Skip to content

Commit 8a6fcb7

Browse files
committed
fix: add video duration safety buffer
1 parent 18d577f commit 8a6fcb7

2 files changed

Lines changed: 37 additions & 12 deletions

File tree

app/services/video.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,19 @@ def _format_ffmpeg_concat_path(file_path: str) -> str:
314314

315315

316316
def concat_video_clips_with_ffmpeg(
317-
clip_files: List[str], output_file: str, threads: int, output_dir: str
317+
clip_files: List[str],
318+
output_file: str,
319+
threads: int,
320+
output_dir: str,
321+
max_duration: float | None = None,
318322
):
319323
concat_list_file = os.path.join(output_dir, "ffmpeg-concat-list.txt")
320324
with open(concat_list_file, "w", encoding="utf-8") as fp:
321325
for clip_file in clip_files:
322326
fp.write(f"file '{_format_ffmpeg_concat_path(clip_file)}'\n")
323327

324328
def build_command(codec: str) -> list[str]:
325-
return [
329+
command = [
326330
utils.get_ffmpeg_binary(),
327331
"-y",
328332
"-f",
@@ -337,8 +341,11 @@ def build_command(codec: str) -> list[str]:
337341
str(threads or 2),
338342
"-pix_fmt",
339343
"yuv420p",
340-
output_file,
341344
]
345+
if max_duration is not None and max_duration > 0:
346+
command.extend(["-t", f"{max_duration:.3f}"])
347+
command.append(output_file)
348+
return command
342349

343350
def run_concat(codec: str):
344351
command = build_command(codec)
@@ -719,21 +726,14 @@ def combine_videos(
719726
logger.warning("no clips available for merging")
720727
return combined_video_path
721728

722-
# if there is only one clip, use it directly
723-
if len(processed_clips) == 1:
724-
logger.info("using single clip directly")
725-
shutil.copy(processed_clips[0].file_path, combined_video_path)
726-
delete_files([processed_clips[0].file_path])
727-
logger.info("video combining completed")
728-
return combined_video_path
729-
730729
clip_files = [clip.file_path for clip in processed_clips]
731730
logger.info(f"concatenating {len(clip_files)} clips with ffmpeg")
732731
concat_video_clips_with_ffmpeg(
733732
clip_files=clip_files,
734733
output_file=combined_video_path,
735734
threads=threads,
736735
output_dir=output_dir,
736+
max_duration=audio_duration,
737737
)
738738

739739
# clean temp files

test/services/test_video.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ def _open_fake_video_clip(video_path):
485485
with patch.object(
486486
vd, "_write_videofile_with_codec_fallback"
487487
) as write_mock:
488-
with patch.object(vd, "concat_video_clips_with_ffmpeg"):
488+
with patch.object(vd, "concat_video_clips_with_ffmpeg") as concat_mock:
489489
with patch.object(vd, "delete_files"):
490490
result = vd.combine_videos(
491491
combined_video_path=combined_video_path,
@@ -499,6 +499,31 @@ def _open_fake_video_clip(video_path):
499499

500500
self.assertEqual(result, combined_video_path)
501501
self.assertEqual(write_mock.call_count, 4)
502+
self.assertEqual(concat_mock.call_args.kwargs["max_duration"], 10.0)
503+
504+
def test_concat_video_clips_limits_output_to_audio_duration(self):
505+
"""最终拼接时应裁到音频时长,避免安全余量带来明显静音尾巴。"""
506+
507+
def fake_run(command, capture_output, text, check):
508+
return types.SimpleNamespace(returncode=0, stdout="", stderr="")
509+
510+
with tempfile.TemporaryDirectory() as temp_dir:
511+
clip_file = os.path.join(temp_dir, "clip.mp4")
512+
output_file = os.path.join(temp_dir, "combined.mp4")
513+
Path(clip_file).write_bytes(b"fake")
514+
515+
with patch.object(vd.subprocess, "run", side_effect=fake_run) as run:
516+
vd.concat_video_clips_with_ffmpeg(
517+
clip_files=[clip_file],
518+
output_file=output_file,
519+
threads=1,
520+
output_dir=temp_dir,
521+
max_duration=10.0,
522+
)
523+
524+
command = run.call_args.args[0]
525+
self.assertEqual(command[command.index("-t") + 1], "10.000")
526+
self.assertLess(command.index("-t"), command.index(output_file))
502527

503528
def test_prioritize_unique_source_clips_uses_each_source_before_reuse(self):
504529
"""

0 commit comments

Comments
 (0)