trying to fix export issue and waveform load
This commit is contained in:
@ -13,6 +13,24 @@ from typing import List
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _input_has_video_stream(ffmpeg_cmd: str, input_path: str) -> bool:
|
||||
"""Return True if the input contains at least one video stream."""
|
||||
ffprobe = ffmpeg_cmd.replace("ffmpeg", "ffprobe")
|
||||
cmd = [
|
||||
ffprobe,
|
||||
"-v", "error",
|
||||
"-select_streams", "v:0",
|
||||
"-show_entries", "stream=index",
|
||||
"-of", "csv=p=0",
|
||||
str(input_path),
|
||||
]
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return result.returncode == 0 and bool(result.stdout.strip())
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _clamp_speed(speed: float) -> float:
|
||||
return max(0.25, min(4.0, float(speed)))
|
||||
|
||||
@ -120,6 +138,10 @@ def export_stream_copy(
|
||||
# Mute ranges require audio filtering, so fall back to re-encoding
|
||||
return export_reencode(input_path, output_path, keep_segments, "1080p", "mp4", mute_ranges)
|
||||
ffmpeg = _find_ffmpeg()
|
||||
if not _input_has_video_stream(ffmpeg, input_path):
|
||||
# Audio-only inputs cannot use TS segment stream-copy concat reliably.
|
||||
return export_reencode(input_path, output_path, keep_segments)
|
||||
|
||||
input_path = str(Path(input_path).resolve())
|
||||
output_path = str(Path(output_path).resolve())
|
||||
|
||||
@ -222,10 +244,66 @@ def export_reencode(
|
||||
return ",".join(filters) if filters else "anull"
|
||||
|
||||
has_audio_filters = bool(mute_ranges) or bool(gain_ranges) or abs(float(global_gain_db)) > 1e-6
|
||||
has_video = _input_has_video_stream(ffmpeg, input_path)
|
||||
|
||||
speed_segments = _split_keep_segments_by_speed(keep_segments, speed_ranges)
|
||||
has_speed = any(abs(seg.get("speed", 1.0) - 1.0) > 1e-6 for seg in speed_segments)
|
||||
|
||||
if not has_video:
|
||||
if not keep_segments:
|
||||
raise ValueError("No segments to export")
|
||||
|
||||
segments_for_concat = speed_segments if speed_segments else _split_keep_segments_by_speed(keep_segments, None)
|
||||
if not segments_for_concat:
|
||||
raise ValueError("No segments to export")
|
||||
|
||||
filter_parts = []
|
||||
for i, seg in enumerate(segments_for_concat):
|
||||
speed = _clamp_speed(seg.get("speed", 1.0))
|
||||
a_chain = f"atrim=start={seg['start']}:end={seg['end']},asetpts=PTS-STARTPTS"
|
||||
if abs(speed - 1.0) > 1e-6:
|
||||
a_chain += f",{_build_atempo_chain(speed)}"
|
||||
filter_parts.append(f"[0:a]{a_chain}[a{i}];")
|
||||
|
||||
n = len(segments_for_concat)
|
||||
concat_inputs = "".join(f"[a{i}]" for i in range(n))
|
||||
filter_parts.append(f"{concat_inputs}concat=n={n}:v=0:a=1[outa_raw]")
|
||||
|
||||
audio_filter = build_audio_filter()
|
||||
if audio_filter != "anull":
|
||||
filter_parts.append(f";[outa_raw]{audio_filter}[outa]")
|
||||
audio_map = "[outa]"
|
||||
else:
|
||||
audio_map = "[outa_raw]"
|
||||
|
||||
filter_complex = "".join(filter_parts)
|
||||
|
||||
audio_codec_args = ["-c:a", "aac", "-b:a", "192k"]
|
||||
if format_hint == "webm":
|
||||
audio_codec_args = ["-c:a", "libopus", "-b:a", "160k"]
|
||||
|
||||
cmd = [
|
||||
ffmpeg, "-y",
|
||||
"-i", input_path,
|
||||
"-filter_complex", filter_complex,
|
||||
"-map", audio_map,
|
||||
*audio_codec_args,
|
||||
output_path,
|
||||
]
|
||||
|
||||
logger.info(
|
||||
"Re-encoding audio-only input (%s segments, speed-adjusted=%s) -> %s",
|
||||
n,
|
||||
has_speed,
|
||||
output_path,
|
||||
)
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"FFmpeg audio-only export failed: {result.stderr[-500:]}")
|
||||
|
||||
return output_path
|
||||
|
||||
# Handle filtered full-timeline audio case (mute/gain/global gain) when no speed warping is needed
|
||||
if has_audio_filters and not has_speed:
|
||||
audio_filter = build_audio_filter()
|
||||
@ -344,6 +422,9 @@ def export_reencode_with_subs(
|
||||
If mute_ranges are provided, applies audio muting instead of cutting.
|
||||
"""
|
||||
ffmpeg = _find_ffmpeg()
|
||||
if not _input_has_video_stream(ffmpeg, input_path):
|
||||
raise ValueError("Burn-in captions require a video track")
|
||||
|
||||
input_path = str(Path(input_path).resolve())
|
||||
output_path = str(Path(output_path).resolve())
|
||||
subtitle_path = str(Path(subtitle_path).resolve())
|
||||
|
||||
Reference in New Issue
Block a user