fix (core): main fixes of codec/container/file_extension inconsistency #11
@@ -194,6 +194,9 @@ def split_audio(input_file: str, output_directory: str, tracks: List[Dict[str, A
|
|||||||
subtitle_codec=args.subtitle_codec,
|
subtitle_codec=args.subtitle_codec,
|
||||||
metadata=metadata,
|
metadata=metadata,
|
||||||
cover_image_path=cover_image_path,
|
cover_image_path=cover_image_path,
|
||||||
|
video_quality=getattr(args, 'video_quality', None),
|
||||||
|
drop_video=args.drop_video,
|
||||||
|
drop_subs=args.drop_subs,
|
||||||
)
|
)
|
||||||
|
|
||||||
print(cmd)
|
print(cmd)
|
||||||
|
|||||||
+43
-14
@@ -281,30 +281,49 @@ def build_ffmpeg_command(
|
|||||||
subtitle_codec: Optional[str] = 'copy',
|
subtitle_codec: Optional[str] = 'copy',
|
||||||
metadata: Optional[Dict] = None,
|
metadata: Optional[Dict] = None,
|
||||||
cover_image_path: Optional[str] = None,
|
cover_image_path: Optional[str] = None,
|
||||||
|
video_quality: Optional[int] = None,
|
||||||
|
drop_video: bool = False,
|
||||||
|
drop_subs: bool = False,
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""
|
"""
|
||||||
Construct the FFmpeg command line.
|
Construct the FFmpeg command line as a list of arguments.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
audio_codec: 'copy' or encoder name (e.g., 'libopus')
|
input_file: Path to the input media file.
|
||||||
video_codec: 'copy' or encoder name (e.g., 'libx264')
|
start_seconds: Start time for the segment (in seconds).
|
||||||
subtitle_codec: 'copy' or encoder name (e.g., 'srt')
|
duration_seconds: Duration of the segment (in seconds).
|
||||||
|
output_path: Destination path for the output file.
|
||||||
|
stream_info: Dictionary from get_stream_info().
|
||||||
|
format_opt: Output container format (e.g., 'mp3', 'mkv').
|
||||||
|
audio_codec: Audio codec to use ('copy' or encoder name like 'libopus').
|
||||||
|
video_codec: Video codec to use ('copy' or encoder name).
|
||||||
|
subtitle_codec: Subtitle codec to use ('copy' or encoder name).
|
||||||
|
metadata: Optional dict of metadata key/value pairs to write.
|
||||||
|
cover_image_path: Path to extracted cover image (if any).
|
||||||
|
video_quality: Quality value for video encoder (e.g., 1-31, lower=better).
|
||||||
|
drop_video: If True, remove video streams.
|
||||||
|
drop_subs: If True, remove subtitle streams.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of command‑line arguments suitable for subprocess.run().
|
||||||
"""
|
"""
|
||||||
cmd = ['ffmpeg']
|
cmd = ['ffmpeg']
|
||||||
|
|
||||||
# Add cover image if provided
|
# Add cover image as first input if provided
|
||||||
if cover_image_path:
|
if cover_image_path:
|
||||||
cmd.extend(['-i', cover_image_path])
|
cmd.extend(['-i', cover_image_path])
|
||||||
|
|
||||||
|
# Add main input file
|
||||||
cmd.extend(['-i', input_file])
|
cmd.extend(['-i', input_file])
|
||||||
|
|
||||||
# Time options
|
# Time options
|
||||||
cmd.extend(['-ss', format_time(start_seconds), '-t', format_time(duration_seconds)])
|
cmd.extend(['-ss', format_time(start_seconds), '-t', format_time(duration_seconds)])
|
||||||
|
|
||||||
# Clear metadata
|
# Clear all original metadata.
|
||||||
cmd.append('-map_metadata')
|
cmd.append('-map_metadata')
|
||||||
cmd.append('-1')
|
cmd.append('-1')
|
||||||
|
|
||||||
# Apply custom metadata
|
# Apply custom metadata.
|
||||||
if metadata:
|
if metadata:
|
||||||
for key, value in metadata.items():
|
for key, value in metadata.items():
|
||||||
if value is not None and value != '':
|
if value is not None and value != '':
|
||||||
@@ -328,15 +347,22 @@ def build_ffmpeg_command(
|
|||||||
else:
|
else:
|
||||||
cmd.extend(['-c:a', 'copy'])
|
cmd.extend(['-c:a', 'copy'])
|
||||||
|
|
||||||
# Subtitle: none (we don't copy from original when using cover image)
|
# Subtitle: we don't copy subtitles when using cover image (they would be from main input)
|
||||||
cmd.append('-sn')
|
cmd.append('-sn')
|
||||||
|
|
||||||
|
# Video quality if specified
|
||||||
|
if video_quality is not None:
|
||||||
|
cmd.extend(['-q:v', str(video_quality)])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Standard mapping: copy all streams by default, then filter based on options
|
# Standard mapping (no cover image)
|
||||||
if not stream_info.get('has_video') or drop_video:
|
if drop_video and drop_subs:
|
||||||
cmd.extend(['-map', '0:a:0'])
|
cmd.extend(['-map', '0:a:0'])
|
||||||
|
elif drop_video:
|
||||||
|
cmd.extend(['-map', '0:a:0', '-map', '0:s?'])
|
||||||
|
elif drop_subs:
|
||||||
|
cmd.extend(['-map', '0:a:0', '-map', '0:v:0'])
|
||||||
else:
|
else:
|
||||||
# Map all streams
|
|
||||||
cmd.extend(['-map', '0'])
|
cmd.extend(['-map', '0'])
|
||||||
|
|
||||||
# Audio codec
|
# Audio codec
|
||||||
@@ -345,17 +371,20 @@ def build_ffmpeg_command(
|
|||||||
else:
|
else:
|
||||||
cmd.extend(['-c:a', 'copy'])
|
cmd.extend(['-c:a', 'copy'])
|
||||||
|
|
||||||
# Video codec (if video present and not dropped)
|
# Video codec
|
||||||
if stream_info.get('has_video') and not drop_video:
|
if not drop_video and stream_info.get('has_video'):
|
||||||
if video_codec and video_codec != 'copy':
|
if video_codec and video_codec != 'copy':
|
||||||
cmd.extend(['-c:v', video_codec])
|
cmd.extend(['-c:v', video_codec])
|
||||||
|
# Add video quality if specified (only when re-encoding)
|
||||||
|
if video_quality is not None:
|
||||||
|
cmd.extend(['-q:v', str(video_quality)])
|
||||||
else:
|
else:
|
||||||
cmd.extend(['-c:v', 'copy'])
|
cmd.extend(['-c:v', 'copy'])
|
||||||
else:
|
else:
|
||||||
cmd.append('-vn')
|
cmd.append('-vn')
|
||||||
|
|
||||||
# Subtitle codec
|
# Subtitle codec
|
||||||
if stream_info.get('has_subtitle') and not drop_subs:
|
if not drop_subs and stream_info.get('has_subtitle'):
|
||||||
if subtitle_codec and subtitle_codec != 'copy':
|
if subtitle_codec and subtitle_codec != 'copy':
|
||||||
cmd.extend(['-c:s', subtitle_codec])
|
cmd.extend(['-c:s', subtitle_codec])
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ def main():
|
|||||||
help="Drop video streams")
|
help="Drop video streams")
|
||||||
parser.add_argument('--drop-subs', action='store_true', default=DEFAULT_DROP_SUBS,
|
parser.add_argument('--drop-subs', action='store_true', default=DEFAULT_DROP_SUBS,
|
||||||
help="Drop subtitle streams")
|
help="Drop subtitle streams")
|
||||||
|
parser.add_argument(
|
||||||
|
'--video-quality', '-vq',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help="Video quality (integer, encoder-specific; usually 1-31, lower=better). "
|
||||||
|
"If omitted, FFmpeg default is used."
|
||||||
|
)
|
||||||
|
|
||||||
# Filename options
|
# Filename options
|
||||||
parser.add_argument('--number-tracks', action='store_true', default=DEFAULT_NUMBER_TRACKS,
|
parser.add_argument('--number-tracks', action='store_true', default=DEFAULT_NUMBER_TRACKS,
|
||||||
|
|||||||
Reference in New Issue
Block a user