def test_clone_inputs_for_destination_filter(self): """ If source vector has different streams, next filter must be cloned with all connected inputs. """ v = self.simd.video | Vector((SomeFilter(), AnotherFilter())) # noinspection PyTypeChecker some, other = cast(Tuple[VideoFilter, VideoFilter], v) v1 = Vector(some).connect(Scale, params=[(1280, 720), (640, 360)]) overlay = other | Overlay(0, 0) v2 = v1.connect(overlay) v2 > self.simd self.assert_simd_args( '-i', 'input.mp4', '-filter_complex', '[0:v]split[v:split0][v:split1];' '[v:split0]some[v:some0];' '[v:split1]another[v:another0];' '[v:some0]split[v:split2][v:split3];' '[v:split2]scale=w=1280:h=720[v:scale0];' '[v:split3]scale=w=640:h=360[v:scale1];' '[v:another0]split[v:split4][v:split5];' '[v:split4][v:scale0]overlay[vout0];' '[v:split5][v:scale1]overlay[vout1]', '-map', '[vout0]', '-c:v', 'libx264', '-map', '0:a', '-c:a', 'aac', '-b:a', '64000', 'output1.mp4', '-map', '[vout1]', '-c:v', 'libx265', '-map', '0:a', '-c:a', 'libfdk_aac', 'output2.mp5')
def test_filter_graph_pass_through(self): """ Empty graph is removed from output arguments.""" Vector(self.source.video) > self.simd Vector(self.source.audio) > self.simd self.assert_simd_args('-i', 'input.mp4', '-map', '0:v', '-c:v', 'libx264', '-map', '0:a', '-c:a', 'aac', '-b:a', '64000', 'output1.mp4', '-map', '0:v', '-c:v', 'libx265', '-map', '0:a', '-c:a', 'libfdk_aac', 'output2.mp5')
def test_vector_metadata_for_multiple_streams(self): """ Checks that vector does not return metadata if it contains multiple streams. """ v = Vector([VideoFilter(), VideoFilter()]) self.assertRaises(RuntimeError, getattr, v, 'meta')
def test_vector_kind(self): """ Checks that vector does not return kind if it contains audio and video streams. """ v = Vector([VideoFilter(), AudioFilter()]) self.assertRaises(RuntimeError, getattr, v, 'kind')
def test_single_quality_copy_pass_through(self): """ Copy codec is connected directly to input with vectorized filters. """ self.output2.codecs[0] = codecs.Copy(kind=VIDEO) src = Vector(self.source.video) params = [(1920, 1080), None] scaled = src.connect(Scale, params=params, mask=[True, False]) scaled > self.simd Vector(self.source.audio) > self.simd self.assert_simd_args('-i', 'input.mp4', '-filter_complex', '[0:v]scale=w=1920:h=1080[vout0]', '-map', '[vout0]', '-c:v', 'libx264', '-map', '0:a', '-c:a', 'aac', '-b:a', '64000', 'output1.mp4', '-map', '0:v', '-c:v', 'copy', '-map', '0:a', '-c:a', 'libfdk_aac', 'output2.mp5')
def test_vector_dimensions(self): """ Vector to vector connection must be one of 1:N, M:1, K:K. """ with self.subTest("1:N"): v1 = Vector(self.source.video) v2 = Vector([VideoFilter(), VideoFilter()]) self.assertTrue(v1 | v2) with self.subTest("M:1"): a1 = Vector([self.source.audio, self.source.audio]) # type: ignore a2 = Vector([Concat(AUDIO)]) self.assertTrue(a1 | a2) with self.subTest("K:K"): v1 = Vector([self.source.video, self.source.video]) # type: ignore v2 = Vector([VideoFilter(), VideoFilter()]) self.assertTrue(v1 | v2) with self.subTest("M:N"): v1 = Vector([self.source.video, self.source.video]) # type: ignore v2 = Vector([VideoFilter(), VideoFilter(), VideoFilter()]) with self.assertRaises(RuntimeError): self.assertTrue(v1 | v2)
# cut same parts from input audio stream for p in trim: p['kind'] = AUDIO audio = simd.audio.connect(Trim, params=trim) | SetPTS(AUDIO) audio_concat = Concat(AUDIO, input_count=len(audio)) for stream in audio: stream | audio_concat # add a logo to an edited video stream with_logo = concat | Overlay(x=100, y=100) logo | with_logo # now we need to vectorize video stream again to perform # scaling to multiple sizes cursor = Vector(with_logo) sizes = [(640, 360), (960, 540), (1280, 720), (1920, 1080)] cursor = cursor.connect(Scale, params=sizes) # finalize video processing cursor > simd # finalize audio processing audio_concat > simd simd.ffmpeg.overwrite = True print(simd.ffmpeg.get_cmd())