| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -104,10 +104,10 @@ With additional filtering: | |||
| 104 | 104 | ```python | |
| 105 | 105 | in1 = ffmpeg.input('in1.mp4') | |
| 106 | 106 | in2 = ffmpeg.input('in2.mp4') | |
| 107 | - v1 = in1['v'].hflip() | ||
| 108 | - a1 = in1['a'] | ||
| 109 | - v2 = in2['v'].filter('reverse').filter('hue', s=0) | ||
| 110 | - a2 = in2['a'].filter('areverse').filter('aphaser') | ||
| 107 | + v1 = in1.video.hflip() | ||
| 108 | + a1 = in1.audio | ||
| 109 | + v2 = in2.video.filter('reverse').filter('hue', s=0) | ||
| 110 | + a2 = in2.audio.filter('areverse').filter('aphaser') | ||
| 111 | 111 | joined = ffmpeg.concat(v1, a1, v2, a2, v=1, a=1).node | |
| 112 | 112 | v3 = joined[0] | |
| 113 | 113 | a3 = joined[1].filter('volume', 0.8) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -53,8 +53,8 @@ def __getitem__(self, index): | |||
| 53 | 53 | Process the audio and video portions of a stream independently:: | |
| 54 | 54 | ||
| 55 | 55 | input = ffmpeg.input('in.mp4') | |
| 56 | - audio = input[:'a'].filter("aecho", 0.8, 0.9, 1000, 0.3) | ||
| 57 | - video = input[:'v'].hflip() | ||
| 56 | + audio = input['a'].filter("aecho", 0.8, 0.9, 1000, 0.3) | ||
| 57 | + video = input['v'].hflip() | ||
| 58 | 58 | out = ffmpeg.output(audio, video, 'out.mp4') | |
| 59 | 59 | """ | |
| 60 | 60 | if self.selector is not None: | |
@@ -63,6 +63,56 @@ def __getitem__(self, index): | |||
| 63 | 63 | raise TypeError("Expected string index (e.g. 'a'); got {!r}".format(index)) | |
| 64 | 64 | return self.node.stream(label=self.label, selector=index) | |
| 65 | 65 | ||
| 66 | + @property | ||
| 67 | + def audio(self): | ||
| 68 | + """Select the audio-portion of a stream. | ||
| 69 | + | ||
| 70 | + Some ffmpeg filters drop audio streams, and care must be taken | ||
| 71 | + to preserve the audio in the final output. The ``.audio`` and | ||
| 72 | + ``.video`` operators can be used to reference the audio/video | ||
| 73 | + portions of a stream so that they can be processed separately | ||
| 74 | + and then re-combined later in the pipeline. This dilemma is | ||
| 75 | + intrinsic to ffmpeg, and ffmpeg-python tries to stay out of the | ||
| 76 | + way while users may refer to the official ffmpeg documentation | ||
| 77 | + as to why certain filters drop audio. | ||
| 78 | + | ||
| 79 | + ``stream.audio`` is a shorthand for ``stream['a']``. | ||
| 80 | + | ||
| 81 | + Example: | ||
| 82 | + Process the audio and video portions of a stream independently:: | ||
| 83 | + | ||
| 84 | + input = ffmpeg.input('in.mp4') | ||
| 85 | + audio = input.audio.filter("aecho", 0.8, 0.9, 1000, 0.3) | ||
| 86 | + video = input.video.hflip() | ||
| 87 | + out = ffmpeg.output(audio, video, 'out.mp4') | ||
| 88 | + """ | ||
| 89 | + return self['a'] | ||
| 90 | + | ||
| 91 | + @property | ||
| 92 | + def video(self): | ||
| 93 | + """Select the video-portion of a stream. | ||
| 94 | + | ||
| 95 | + Some ffmpeg filters drop audio streams, and care must be taken | ||
| 96 | + to preserve the audio in the final output. The ``.audio`` and | ||
| 97 | + ``.video`` operators can be used to reference the audio/video | ||
| 98 | + portions of a stream so that they can be processed separately | ||
| 99 | + and then re-combined later in the pipeline. This dilemma is | ||
| 100 | + intrinsic to ffmpeg, and ffmpeg-python tries to stay out of the | ||
| 101 | + way while users may refer to the official ffmpeg documentation | ||
| 102 | + as to why certain filters drop audio. | ||
| 103 | + | ||
| 104 | + ``stream.video`` is a shorthand for ``stream['v']``. | ||
| 105 | + | ||
| 106 | + Example: | ||
| 107 | + Process the audio and video portions of a stream independently:: | ||
| 108 | + | ||
| 109 | + input = ffmpeg.input('in.mp4') | ||
| 110 | + audio = input.audio.filter("aecho", 0.8, 0.9, 1000, 0.3) | ||
| 111 | + video = input.video.hflip() | ||
| 112 | + out = ffmpeg.output(audio, video, 'out.mp4') | ||
| 113 | + """ | ||
| 114 | + return self['v'] | ||
| 115 | + | ||
| 66 | 116 | ||
| 67 | 117 | def get_stream_map(stream_spec): | |
| 68 | 118 | if stream_spec is None: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -175,10 +175,15 @@ def test_combined_output(): | |||
| 175 | 175 | ] | |
| 176 | 176 | ||
| 177 | 177 | ||
| 178 | - def test_filter_with_selector(): | ||
| 178 | + @pytest.mark.parametrize('use_shorthand', [True, False]) | ||
| 179 | + def test_filter_with_selector(use_shorthand): | ||
| 179 | 180 | i = ffmpeg.input(TEST_INPUT_FILE1) | |
| 180 | - v1 = i['v'].hflip() | ||
| 181 | - a1 = i['a'].filter('aecho', 0.8, 0.9, 1000, 0.3) | ||
| 181 | + if use_shorthand: | ||
| 182 | + v1 = i.video.hflip() | ||
| 183 | + a1 = i.audio.filter('aecho', 0.8, 0.9, 1000, 0.3) | ||
| 184 | + else: | ||
| 185 | + v1 = i['v'].hflip() | ||
| 186 | + a1 = i['a'].filter('aecho', 0.8, 0.9, 1000, 0.3) | ||
| 182 | 187 | out = ffmpeg.output(a1, v1, TEST_OUTPUT_FILE1) | |
| 183 | 188 | assert out.get_args() == [ | |
| 184 | 189 | '-i', TEST_INPUT_FILE1, | |
@@ -273,7 +278,7 @@ def test_filter_concat__audio_only(): | |||
| 273 | 278 | def test_filter_concat__audio_video(): | |
| 274 | 279 | in1 = ffmpeg.input('in1.mp4') | |
| 275 | 280 | in2 = ffmpeg.input('in2.mp4') | |
| 276 | - joined = ffmpeg.concat(in1['v'], in1['a'], in2.hflip(), in2['a'], v=1, a=1).node | ||
| 281 | + joined = ffmpeg.concat(in1.video, in1.audio, in2.hflip(), in2['a'], v=1, a=1).node | ||
| 277 | 282 | args = ( | |
| 278 | 283 | ffmpeg | |
| 279 | 284 | .output(joined[0], joined[1], 'out.mp4') | |
@@ -298,7 +303,7 @@ def test_filter_concat__wrong_stream_count(): | |||
| 298 | 303 | in1 = ffmpeg.input('in1.mp4') | |
| 299 | 304 | in2 = ffmpeg.input('in2.mp4') | |
| 300 | 305 | with pytest.raises(ValueError) as excinfo: | |
| 301 | - ffmpeg.concat(in1['v'], in1['a'], in2.hflip(), v=1, a=1).node | ||
| 306 | + ffmpeg.concat(in1.video, in1.audio, in2.hflip(), v=1, a=1).node | ||
| 302 | 307 | assert str(excinfo.value) == \ | |
| 303 | 308 | 'Expected concat input streams to have length multiple of 2 (v=1, a=1); got 3' | |
| 304 | 309 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -67,6 +67,13 @@ | |||
| 67 | 67 | keywords=keywords, | |
| 68 | 68 | long_description=long_description, | |
| 69 | 69 | install_requires=['future'], | |
| 70 | + extras_require={ | ||
| 71 | + 'dev': [ | ||
| 72 | + 'future', | ||
| 73 | + 'pytest', | ||
| 74 | + 'pytest-mock', | ||
| 75 | + ], | ||
| 76 | + }, | ||
| 70 | 77 | classifiers=[ | |
| 71 | 78 | 'Intended Audience :: Developers', | |
| 72 | 79 | 'License :: OSI Approved :: Apache Software License', | |
| Back | FazBrowse Home | New Git URL |
0 commit comments