mirror of
https://github.com/kkroening/ffmpeg-python.git
synced 2025-04-06 04:15:44 +08:00
Merge pull request #97 from kkroening/concat-av
Support `concat` a/v params
This commit is contained in:
commit
7c872c56b9
@ -57,6 +57,21 @@ out, _ = (ffmpeg
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Process audio and video simultaneously
|
||||||
|
```python
|
||||||
|
in1 = ffmpeg.input('in1.mp4')
|
||||||
|
in2 = ffmpeg.input('in2.mp4')
|
||||||
|
v1 = in1['v'].hflip()
|
||||||
|
a1 = in1['a']
|
||||||
|
v2 = in2['v'].filter_('reverse').filter_('hue', s=0)
|
||||||
|
a2 = in2['a'].filter_('areverse').filter_('aphaser')
|
||||||
|
joined = ffmpeg.concat(v1, a1, v2, a2, v=1, a=1).node
|
||||||
|
v3 = joined[0]
|
||||||
|
a3 = joined[1].filter_('volume', 0.8)
|
||||||
|
out = ffmpeg.output(v3, a3, 'out.mp4')
|
||||||
|
out.run()
|
||||||
|
```
|
||||||
|
|
||||||
## [Jupyter Frame Viewer](https://github.com/kkroening/ffmpeg-python/blob/master/examples/ffmpeg-numpy.ipynb)
|
## [Jupyter Frame Viewer](https://github.com/kkroening/ffmpeg-python/blob/master/examples/ffmpeg-numpy.ipynb)
|
||||||
|
|
||||||
<img src="https://raw.githubusercontent.com/kkroening/ffmpeg-python/master/doc/jupyter-screenshot.png" alt="jupyter screenshot" width="75%" />
|
<img src="https://raw.githubusercontent.com/kkroening/ffmpeg-python/master/doc/jupyter-screenshot.png" alt="jupyter screenshot" width="75%" />
|
||||||
|
@ -372,7 +372,14 @@ def concat(*streams, **kwargs):
|
|||||||
|
|
||||||
Official documentation: `concat <https://ffmpeg.org/ffmpeg-filters.html#concat>`__
|
Official documentation: `concat <https://ffmpeg.org/ffmpeg-filters.html#concat>`__
|
||||||
"""
|
"""
|
||||||
kwargs['n'] = len(streams)
|
video_stream_count = kwargs.get('v', 1)
|
||||||
|
audio_stream_count = kwargs.get('a', 0)
|
||||||
|
stream_count = video_stream_count + audio_stream_count
|
||||||
|
if len(streams) % stream_count != 0:
|
||||||
|
raise ValueError(
|
||||||
|
'Expected concat input streams to have length multiple of {} (v={}, a={}); got {}'
|
||||||
|
.format(stream_count, video_stream_count, audio_stream_count, len(streams)))
|
||||||
|
kwargs['n'] = int(len(streams) / stream_count)
|
||||||
return FilterNode(streams, concat.__name__, kwargs=kwargs, max_inputs=None).stream()
|
return FilterNode(streams, concat.__name__, kwargs=kwargs, max_inputs=None).stream()
|
||||||
|
|
||||||
|
|
||||||
|
@ -221,6 +221,83 @@ def _get_complex_filter_asplit_example():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_concat__video_only():
|
||||||
|
in1 = ffmpeg.input('in1.mp4')
|
||||||
|
in2 = ffmpeg.input('in2.mp4')
|
||||||
|
args = (
|
||||||
|
ffmpeg
|
||||||
|
.concat(in1, in2)
|
||||||
|
.output('out.mp4')
|
||||||
|
.get_args()
|
||||||
|
)
|
||||||
|
assert args == [
|
||||||
|
'-i',
|
||||||
|
'in1.mp4',
|
||||||
|
'-i',
|
||||||
|
'in2.mp4',
|
||||||
|
'-filter_complex',
|
||||||
|
'[0][1]concat=n=2[s0]',
|
||||||
|
'-map',
|
||||||
|
'[s0]',
|
||||||
|
'out.mp4',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_concat__audio_only():
|
||||||
|
in1 = ffmpeg.input('in1.mp4')
|
||||||
|
in2 = ffmpeg.input('in2.mp4')
|
||||||
|
args = (
|
||||||
|
ffmpeg
|
||||||
|
.concat(in1, in2, v=0, a=1)
|
||||||
|
.output('out.mp4')
|
||||||
|
.get_args()
|
||||||
|
)
|
||||||
|
assert args == [
|
||||||
|
'-i',
|
||||||
|
'in1.mp4',
|
||||||
|
'-i',
|
||||||
|
'in2.mp4',
|
||||||
|
'-filter_complex',
|
||||||
|
'[0][1]concat=a=1:n=2:v=0[s0]',
|
||||||
|
'-map',
|
||||||
|
'[s0]',
|
||||||
|
'out.mp4'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_concat__audio_video():
|
||||||
|
in1 = ffmpeg.input('in1.mp4')
|
||||||
|
in2 = ffmpeg.input('in2.mp4')
|
||||||
|
joined = ffmpeg.concat(in1['v'], in1['a'], in2.hflip(), in2['a'], v=1, a=1).node
|
||||||
|
args = (
|
||||||
|
ffmpeg
|
||||||
|
.output(joined[0], joined[1], 'out.mp4')
|
||||||
|
.get_args()
|
||||||
|
)
|
||||||
|
assert args == [
|
||||||
|
'-i',
|
||||||
|
'in1.mp4',
|
||||||
|
'-i',
|
||||||
|
'in2.mp4',
|
||||||
|
'-filter_complex',
|
||||||
|
'[1]hflip[s0];[0:v][0:a][s0][1:a]concat=a=1:n=2:v=1[s1][s2]',
|
||||||
|
'-map',
|
||||||
|
'[s1]',
|
||||||
|
'-map',
|
||||||
|
'[s2]',
|
||||||
|
'out.mp4',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_concat__wrong_stream_count():
|
||||||
|
in1 = ffmpeg.input('in1.mp4')
|
||||||
|
in2 = ffmpeg.input('in2.mp4')
|
||||||
|
with pytest.raises(ValueError) as excinfo:
|
||||||
|
ffmpeg.concat(in1['v'], in1['a'], in2.hflip(), v=1, a=1).node
|
||||||
|
assert str(excinfo.value) == \
|
||||||
|
'Expected concat input streams to have length multiple of 2 (v=1, a=1); got 3'
|
||||||
|
|
||||||
|
|
||||||
def test_filter_asplit():
|
def test_filter_asplit():
|
||||||
out = _get_complex_filter_asplit_example()
|
out = _get_complex_filter_asplit_example()
|
||||||
args = out.get_args()
|
args = out.get_args()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user