ffmpeg-python icon indicating copy to clipboard operation
ffmpeg-python copied to clipboard

Please add support to repeating FFmpeg parameters (such as -metadata)

Open avibrazil opened this issue 4 years ago • 3 comments

FFmpeg has parameters that can have duplicates. For example:

ffmpeg  -i input.mov -i subtitles.srt -map 0 -map 1 \
-acodec copy -vcodec copy \
-metadata:s:s:0 title="Wall clock" \
-metadata:s:s:0 language=eng \
-movflags faststart+use_metadata_tags \
-scodec mov_text \
-tag:s:s:0 tx3g \
output.mov

The -metadata:s:s:0 parameter appears twice on this command, but python-ffmpeg semantics won't allow this.

So maybe this would be a solution:

ffmpeg.output(
                        input,
                        subtitles,
                        acodec='copy',
                        vcodec='copy',
                        scodec='mov_text',
                        tag=':s:s:0 tx3g',
                        metadata=[':s:s:0 title="Wall clock"',':s:s:0 language=eng'],
                        movflags='faststart+use_metadata_tags'
                    )

So I passed a list to the metadata parameters. This obviously doesn't work today.

Please add support for repeating parameters.

Thank you in advance.

avibrazil avatar Nov 24 '20 22:11 avibrazil

Similarily I need something like:

-map 0 -map -0:s - Will select all streams from input index #0 (the 1st input) except subtitles. The - indicates negative mapping.

varnav avatar Jan 01 '21 20:01 varnav

I've been digging around, and the weird thing is that with the current code on Github, giving a list to the metadata like in your example wiill work. However, at least in my install of ffmpeg-python, what was installed from pip does not reflect the newest code in the repository.

In the current source, the function that converts the kwargs dictionary to a list of args for the command line will account for keywords that have iterables (from __utils.py):

def convert_kwargs_to_cmd_line_args(kwargs):
    """Helper function to build command line arguments out of dict."""
    args = []
    for k in sorted(kwargs.keys()):
        v = kwargs[k]
        if isinstance(v, collections.Iterable) and not isinstance(v, str):
            for value in v:
                args.append('-{}'.format(k))
                if value is not None:
                    args.append('{}'.format(value))
            continue
        args.append('-{}'.format(k))
        if v is not None:
            args.append('{}'.format(v))
    return args

The function from the pip install does not include the code block that accounts for iterables. If you compile from the source instead of pip install then your proposed solution will work. Otherwise just take that code block and copy it into the utils script in your local ffmpeg-python package.

kevlu93 avatar Jan 03 '21 13:01 kevlu93

From what I tried, it adds global metadata. What would be useful is an example for adding multiple metadata for a stream

cmd = ffmpeg.output( input_file, output_file, acodec='copy', vcodec='copy', metadata=[':s:a:0 title="Audio Metadata"',':s:a:0 language=eng'] )

Produces [ 'ffmpeg', '-i', 'testfile.mkv', '-acodec', 'copy', '-metadata', ':s:a:0 title="Audio Metadata"', '-metadata', ':s:a:0 language=eng', '-vcodec', 'copy', 'testfile-out.mkv']

What did work was:

cmd = ffmpeg.output(
                        input_file,
                        output_file,
                        acodec='copy',
                        **{'metadata:s:a:0': ['title="Audio Metadata"', 'lang=eng']}
                    )

osmano807 avatar Jul 16 '22 14:07 osmano807