mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-10 01:02:13 +01:00
[ffmpeg] Allow passing custom arguments before -i
:ci skip dl
This commit is contained in:
parent
e409895f13
commit
5b1ecbb327
7 changed files with 42 additions and 34 deletions
16
README.md
16
README.md
|
@ -611,13 +611,17 @@ ## Post-Processing Options:
|
||||||
SubtitlesConvertor and EmbedThumbnail. The
|
SubtitlesConvertor and EmbedThumbnail. The
|
||||||
supported executables are: SponSkrub,
|
supported executables are: SponSkrub,
|
||||||
FFmpeg, FFprobe, and AtomicParsley. You can
|
FFmpeg, FFprobe, and AtomicParsley. You can
|
||||||
use this option multiple times to give
|
also specify "PP+EXE:ARGS" to give the
|
||||||
|
arguments to the specified executable only
|
||||||
|
when being used by the specified
|
||||||
|
postprocessor. Additionally, for
|
||||||
|
ffmpeg/ffprobe, a number can be appended to
|
||||||
|
the exe name seperated by "_i" to pass the
|
||||||
|
argument before the specified input file.
|
||||||
|
Eg: --ppa "Merger+ffmpeg_i1:-v quiet". You
|
||||||
|
can use this option multiple times to give
|
||||||
different arguments to different
|
different arguments to different
|
||||||
postprocessors. You can also specify
|
postprocessors. (Alias: --ppa)
|
||||||
"PP+EXE:ARGS" to give the arguments to the
|
|
||||||
specified executable only when being used
|
|
||||||
by the specified postprocessor. You can use
|
|
||||||
this option multiple times (Alias: --ppa)
|
|
||||||
-k, --keep-video Keep the intermediate video file on disk
|
-k, --keep-video Keep the intermediate video file on disk
|
||||||
after post-processing
|
after post-processing
|
||||||
--no-keep-video Delete the intermediate video file after
|
--no-keep-video Delete the intermediate video file after
|
||||||
|
|
|
@ -105,9 +105,10 @@ def _bool_option(self, command_option, param, true_value='true', false_value='fa
|
||||||
def _valueless_option(self, command_option, param, expected_value=True):
|
def _valueless_option(self, command_option, param, expected_value=True):
|
||||||
return cli_valueless_option(self.params, command_option, param, expected_value)
|
return cli_valueless_option(self.params, command_option, param, expected_value)
|
||||||
|
|
||||||
def _configuration_args(self, default=[]):
|
def _configuration_args(self, *args, **kwargs):
|
||||||
return cli_configuration_args(
|
return cli_configuration_args(
|
||||||
self.params, 'external_downloader_args', self.get_basename(), default)[0]
|
self.params.get('external_downloader_args'),
|
||||||
|
self.get_basename(), *args, **kwargs)
|
||||||
|
|
||||||
def _call_downloader(self, tmpfilename, info_dict):
|
def _call_downloader(self, tmpfilename, info_dict):
|
||||||
""" Either overwrite this or implement _make_cmd """
|
""" Either overwrite this or implement _make_cmd """
|
||||||
|
|
|
@ -1071,10 +1071,12 @@ def _dict_from_multiple_values_options_callback(
|
||||||
'SponSkrub, ExtractAudio, VideoRemuxer, VideoConvertor, EmbedSubtitle, Metadata, Merger, '
|
'SponSkrub, ExtractAudio, VideoRemuxer, VideoConvertor, EmbedSubtitle, Metadata, Merger, '
|
||||||
'FixupStretched, FixupM4a, FixupM3u8, SubtitlesConvertor and EmbedThumbnail. '
|
'FixupStretched, FixupM4a, FixupM3u8, SubtitlesConvertor and EmbedThumbnail. '
|
||||||
'The supported executables are: SponSkrub, FFmpeg, FFprobe, and AtomicParsley. '
|
'The supported executables are: SponSkrub, FFmpeg, FFprobe, and AtomicParsley. '
|
||||||
'You can use this option multiple times to give different arguments to different postprocessors. '
|
|
||||||
'You can also specify "PP+EXE:ARGS" to give the arguments to the specified executable '
|
'You can also specify "PP+EXE:ARGS" to give the arguments to the specified executable '
|
||||||
'only when being used by the specified postprocessor. '
|
'only when being used by the specified postprocessor. Additionally, for ffmpeg/ffprobe, '
|
||||||
'You can use this option multiple times (Alias: --ppa)'))
|
'a number can be appended to the exe name seperated by "_i" to pass the argument '
|
||||||
|
'before the specified input file. Eg: --ppa "Merger+ffmpeg_i1:-v quiet". '
|
||||||
|
'You can use this option multiple times to give different arguments to different '
|
||||||
|
'postprocessors. (Alias: --ppa)'))
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'-k', '--keep-video',
|
'-k', '--keep-video',
|
||||||
action='store_true', dest='keepvideo', default=False,
|
action='store_true', dest='keepvideo', default=False,
|
||||||
|
|
|
@ -91,11 +91,10 @@ def try_utime(self, path, atime, mtime, errnote='Cannot update utime of file'):
|
||||||
except Exception:
|
except Exception:
|
||||||
self.report_warning(errnote)
|
self.report_warning(errnote)
|
||||||
|
|
||||||
def _configuration_args(self, default=[], exe=None):
|
def _configuration_args(self, *args, **kwargs):
|
||||||
key = self.pp_key().lower()
|
return cli_configuration_args(
|
||||||
args, is_compat = cli_configuration_args(
|
self._downloader.params.get('postprocessor_args'),
|
||||||
self._downloader.params, 'postprocessor_args', key, default, exe)
|
self.pp_key().lower(), *args, **kwargs)
|
||||||
return args if not is_compat or key != 'sponskrub' else default
|
|
||||||
|
|
||||||
|
|
||||||
class AudioConversionError(PostProcessingError):
|
class AudioConversionError(PostProcessingError):
|
||||||
|
|
|
@ -239,21 +239,20 @@ def run_ffmpeg_multiple_files(self, input_paths, out_path, opts):
|
||||||
oldest_mtime = min(
|
oldest_mtime = min(
|
||||||
os.stat(encodeFilename(path)).st_mtime for path in input_paths)
|
os.stat(encodeFilename(path)).st_mtime for path in input_paths)
|
||||||
|
|
||||||
opts += self._configuration_args(exe=self.basename)
|
|
||||||
|
|
||||||
files_cmd = []
|
|
||||||
for path in input_paths:
|
|
||||||
files_cmd.extend([
|
|
||||||
encodeArgument('-i'),
|
|
||||||
encodeFilename(self._ffmpeg_filename_argument(path), True)
|
|
||||||
])
|
|
||||||
cmd = [encodeFilename(self.executable, True), encodeArgument('-y')]
|
cmd = [encodeFilename(self.executable, True), encodeArgument('-y')]
|
||||||
# avconv does not have repeat option
|
# avconv does not have repeat option
|
||||||
if self.basename == 'ffmpeg':
|
if self.basename == 'ffmpeg':
|
||||||
cmd += [encodeArgument('-loglevel'), encodeArgument('repeat+info')]
|
cmd += [encodeArgument('-loglevel'), encodeArgument('repeat+info')]
|
||||||
cmd += (files_cmd
|
|
||||||
+ [encodeArgument(o) for o in opts]
|
def make_args(file, pre=[], post=[], *args, **kwargs):
|
||||||
+ [encodeFilename(self._ffmpeg_filename_argument(out_path), True)])
|
args = pre + self._configuration_args(*args, **kwargs) + post
|
||||||
|
return (
|
||||||
|
[encodeArgument(o) for o in args]
|
||||||
|
+ [encodeFilename(self._ffmpeg_filename_argument(file), True)])
|
||||||
|
|
||||||
|
for i, path in enumerate(input_paths):
|
||||||
|
cmd += make_args(path, post=['-i'], exe='%s_i%d' % (self.basename, i+1), use_default_arg=False)
|
||||||
|
cmd += make_args(out_path, pre=opts, exe=self.basename)
|
||||||
|
|
||||||
self.write_debug('ffmpeg command line: %s' % shell_quote(cmd))
|
self.write_debug('ffmpeg command line: %s' % shell_quote(cmd))
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||||
|
|
|
@ -71,7 +71,7 @@ def run(self, information):
|
||||||
if not self.cutout:
|
if not self.cutout:
|
||||||
cmd += ['-chapter']
|
cmd += ['-chapter']
|
||||||
cmd += compat_shlex_split(self.args) # For backward compatibility
|
cmd += compat_shlex_split(self.args) # For backward compatibility
|
||||||
cmd += self._configuration_args(exe=self._exe_name)
|
cmd += self._configuration_args(exe=self._exe_name, use_default_arg='no_compat')
|
||||||
cmd += ['--', information['id'], filename, temp_filename]
|
cmd += ['--', information['id'], filename, temp_filename]
|
||||||
cmd = [encodeArgument(i) for i in cmd]
|
cmd = [encodeArgument(i) for i in cmd]
|
||||||
|
|
||||||
|
|
|
@ -4689,13 +4689,16 @@ def cli_valueless_option(params, command_option, param, expected_value=True):
|
||||||
return [command_option] if param == expected_value else []
|
return [command_option] if param == expected_value else []
|
||||||
|
|
||||||
|
|
||||||
def cli_configuration_args(params, arg_name, key, default=[], exe=None): # returns arg, for_compat
|
def cli_configuration_args(argdict, key, default=[], exe=None, use_default_arg=True):
|
||||||
argdict = params.get(arg_name, {})
|
# use_default_arg can be True, False, or 'no_compat'
|
||||||
if isinstance(argdict, (list, tuple)): # for backward compatibility
|
if isinstance(argdict, (list, tuple)): # for backward compatibility
|
||||||
return argdict, True
|
if use_default_arg == True:
|
||||||
|
return argdict
|
||||||
|
else:
|
||||||
|
argdict = None
|
||||||
|
|
||||||
if argdict is None:
|
if argdict is None:
|
||||||
return default, False
|
return default
|
||||||
assert isinstance(argdict, dict)
|
assert isinstance(argdict, dict)
|
||||||
|
|
||||||
key = key.lower()
|
key = key.lower()
|
||||||
|
@ -4710,12 +4713,12 @@ def cli_configuration_args(params, arg_name, key, default=[], exe=None): # retu
|
||||||
if args is None:
|
if args is None:
|
||||||
args = argdict.get(key) if key != exe else None
|
args = argdict.get(key) if key != exe else None
|
||||||
if args is None and exe_args is None:
|
if args is None and exe_args is None:
|
||||||
args = argdict.get('default', default)
|
args = argdict.get('default', default) if use_default_arg else default
|
||||||
|
|
||||||
args, exe_args = args or [], exe_args or []
|
args, exe_args = args or [], exe_args or []
|
||||||
assert isinstance(args, (list, tuple))
|
assert isinstance(args, (list, tuple))
|
||||||
assert isinstance(exe_args, (list, tuple))
|
assert isinstance(exe_args, (list, tuple))
|
||||||
return args + exe_args, False
|
return args + exe_args
|
||||||
|
|
||||||
|
|
||||||
class ISO639Utils(object):
|
class ISO639Utils(object):
|
||||||
|
|
Loading…
Reference in a new issue