Skip to content

Commit 3094a1e

Browse files
committed
transcode - enabled mimo
1 parent 1cda97a commit 3094a1e

3 files changed

Lines changed: 50 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
55

66
## [Unreleased]
77

8+
### Changed
9+
10+
- `transcode()` allowed to take multiple inputs or outputs
11+
812
## [0.5.0] - 2022-04-03
913

1014
### Added

src/ffmpegio/transcode.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from collections.abc import Sequence
2-
from . import ffmpegprocess, configure, utils, FFmpegError
1+
from . import ffmpegprocess as fp, configure, utils, FFmpegError
32

43
__all__ = ["transcode"]
54

@@ -13,13 +12,13 @@ def transcode(
1312
two_pass=False,
1413
pass1_omits=None,
1514
pass1_extras=None,
16-
**options
15+
**options,
1716
):
1817
"""Transcode media files to another format/encoding
1918
2019
:param inputs: url/path of the input media file or a sequence of tuples, each
2120
containing an input url and its options dict
22-
:type inputs: str or sequence of (str,dict)
21+
:type inputs: str or a list of str or a sequence of (str,dict)
2322
:param outputs: url/path of the output media file or a sequence of tuples, each
2423
containing an output url and its options dict
2524
:type outputs: str or sequence of (str, dict)
@@ -34,24 +33,24 @@ def transcode(
3433
:type show_log: bool, optional
3534
:param two_pass: True to encode in 2-pass
3635
:param pass1_omits: list of output arguments to ignore in pass 1, defaults to
37-
None (removes 'c:a' or 'acodec')
38-
:type pass1_omits: seq(str), optional
36+
None (removes 'c:a' or 'acodec'). For multiple outputs,
37+
specify use list of the list of arguments, matching the
38+
length of outputs, for per-output omission.
39+
:type pass1_omits: seq(str), or seq(seq(str)) optional
3940
:param pass1_extras: list of additional output arguments to include in pass 1,
4041
defaults to None (add 'an' if `pass1_omits` also None)
4142
:type pass1_extras: dict(int:dict(str)), optional
4243
:param \\**options: FFmpeg options. For output and global options, use FFmpeg
43-
option names as is. For input options, prepend "input\_" to
44-
the option name. For example, input_r=2000 to force the
45-
input frame rate to 2000 frames/s (see :doc:`options`).
44+
option names as is. For input options, append "_in" to the
45+
option name. For example, r_in=2000 to force the input frame
46+
rate to 2000 frames/s (see :doc:`options`).
4647
4748
If multiple inputs or outputs are specified, these input
4849
or output options specified here are treated as common
4950
options, and the url-specific duplicate options in the
5051
``inputs`` or ``outputs`` sequence will overwrite those
5152
specified here.
5253
:type \\**options: dict, optional
53-
:return: returncode of FFmpeg subprocess
54-
:rtype: int
5554
5655
5756
"""
@@ -60,38 +59,49 @@ def transcode(
6059
input_options = utils.pop_extra_options(options, "_in")
6160
global_options = utils.pop_global_options(options)
6261

63-
# detect single input/output argument
64-
if isinstance(inputs, str) or not isinstance(inputs, Sequence):
65-
inputs = [(inputs, None)]
66-
if isinstance(outputs, str) or not isinstance(outputs, Sequence):
67-
outputs = [(outputs, None)]
62+
def format_arg(arg, defopts):
63+
def test(a, is_list):
64+
try:
65+
assert len(a) == 2
66+
assert isinstance(a[1], dict)
67+
return (a[0], {**defopts, **a[1]})
68+
except:
69+
if is_list:
70+
return (a, defopts)
71+
raise
72+
73+
# special case: a list of inputs w/out options
74+
if type(arg) == list:
75+
return [test(a, True) for a in arg]
76+
77+
# attempt to map url-options pairs
78+
try:
79+
return [test(a, False) for a in arg]
80+
except:
81+
return [(arg, defopts)]
82+
83+
inputs = format_arg(inputs, input_options)
84+
outputs = format_arg(outputs, options)
6885

6986
# initialize FFmpeg argument dict
7087
args = configure.empty(global_options)
7188

7289
for url, opts in inputs:
73-
opts = {**input_options, **(opts or {})}
7490
input_url, stdin, input = configure.check_url(url, False, opts.get("f", None))
7591
configure.add_url(args, "input", input_url, opts)
7692

7793
for url, opts in outputs:
78-
opts = {**options, **(opts or {})}
7994
output_url, stdout, _ = configure.check_url(url, True)
8095
i, _ = configure.add_url(args, "output", output_url, opts)
8196

8297
# convert basic VF options to vf option
8398
configure.build_basic_vf(args, None, i)
8499

85100
kwargs = (
86-
{
87-
"pass1_omits": None if pass1_omits is None else [pass1_omits],
88-
"pass1_extras": None if pass1_extras is None else [pass1_extras],
89-
}
90-
if two_pass
91-
else {}
101+
{"pass1_omits": pass1_omits, "pass1_extras": pass1_extras} if two_pass else {}
92102
)
93103

94-
pout = (ffmpegprocess.run_two_pass if two_pass else ffmpegprocess.run)(
104+
pout = (fp.run_two_pass if two_pass else fp.run)(
95105
args,
96106
progress=progress,
97107
overwrite=overwrite,

tests/test_transcode.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from os import path
44
import pytest
55

6+
67
def test_transcode():
78
url = "tests/assets/testmulti-1m.mp4"
89
outext = ".flac"
@@ -20,6 +21,16 @@ def test_transcode():
2021
transcode(url, out_url, overwrite=False)
2122
transcode(url, out_url, overwrite=True, show_log=True, progress=progress)
2223

24+
# test mimo
25+
url1 = "tests/assets/testvideo-1m.mp4"
26+
out_url1 = path.join(tmpdirname, "vid1.mp4")
27+
out_url2 = path.join(tmpdirname, "vid2.mp4")
28+
transcode(
29+
[url, url1],
30+
[(out_url1, {"map": "1:v:0"}), (out_url2, {"map": "0:v:0"})],
31+
vframes=10,
32+
)
33+
2334

2435
def test_transcode_from_filter():
2536
with tempfile.TemporaryDirectory() as tmpdirname:

0 commit comments

Comments
 (0)