def test_concat(self): """ Concat source files.""" ff = self.ffmpeg ff < self.preroll ff < self.source preroll_ready = ff.video | filters.Scale(640, 480) | SetSAR(1) concat = filters.Concat(VIDEO) preroll_ready | concat ff.video | concat concat > self.video_codec aconcat = filters.Concat(AUDIO) ff.audio | aconcat ff.audio | aconcat aconcat > self.audio_codec ff > self.output self.assert_ffmpeg_args( '-i', 'preroll.mp4', '-i', 'source.mp4', '-filter_complex', "[0:v]scale=w=640:h=480[v:scale0];" "[v:scale0]setsar=1[v:setsar0];" "[v:setsar0][1:v]concat[vout0];" "[0:a][1:a]concat=v=0:a=1:n=2[aout0]", '-map', '[vout0]', '-c:v', 'libx264', '-b:v', '3600000', '-map', '[aout0]', '-c:a', 'aac', '-b:a', '192000', 'output.mp4')
def test_detect_concat_buffering(self): """ When single source is used for multiple outputs, and one of outputs has a preroll, buffering occurs, because to output first frame for a non-preroll output, we need to buffer all preroll frames. """ cases = [ (False, True, True), # preroll + source / preroll + source (False, True, False), # preroll + source / preroll (True, False, True), # preroll + source / source ] for case in cases: with self.subTest(case): raises, split_pre, split_src = case ff = FFMPEG() v1 = inputs.Stream(VIDEO, self.preroll.streams[0].meta) a1 = inputs.Stream(AUDIO, self.preroll.streams[1].meta) v2 = inputs.Stream(VIDEO, self.source.streams[0].meta) a2 = inputs.Stream(AUDIO, self.source.streams[1].meta) ff < inputs.input_file('preroll.mp4', v1, a1) ff < inputs.input_file('source.mp4', v2, a2) vf1 = v1 | filters.Split(VIDEO, output_count=int(split_pre) + 1) vf2 = v2 | filters.Split(VIDEO, output_count=int(split_src) + 1) af1 = a1 | filters.Split(AUDIO, output_count=int(split_pre) + 1) af2 = a2 | filters.Split(AUDIO, output_count=int(split_src) + 1) vc1 = vf1 | filters.Concat(VIDEO, input_count=2) vf2 | vc1 ac1 = af1 | filters.Concat(AUDIO, input_count=2) af2 | ac1 vc2 = filters.Concat(VIDEO, int(split_pre) + int(split_src)) if split_pre: vf1 | vc2 if split_src: vf2 | vc2 ac2 = filters.Concat(AUDIO, int(split_pre) + int(split_src)) if split_pre: af1 | ac2 if split_src: af2 | ac2 o1 = outputs.output_file("o1.mp4", X264(), AAC()) o2 = outputs.output_file("o2.mp4", X264(), AAC()) vc1 > o1 ac1 > o1 vc2 > o2 ac2 > o2 ff > o1 ff > o2 try: ff.check_buffering() except BufferError as e: self.assertTrue(raises, e) else: self.assertFalse(raises)
def test_fix_preroll_buffering_with_trim(self): """ We can fix buffering occurred from preroll by using trim filter. """ ff = self.ffmpeg ff < self.preroll ff < self.source output = outputs.output_file('original.mp4', codecs.VideoCodec("libx264")) original = outputs.output_file('original.mp4', codecs.VideoCodec("libx264")) preroll_stream = self.preroll.streams[0] source_stream = self.source.streams[0] concat = preroll_stream | filters.Concat(VIDEO) source_stream | concat split = concat | filters.Split(VIDEO) split > output pd = preroll_stream.meta.duration sd = source_stream.meta.duration trim = split | filters.Trim(VIDEO, start=pd, end=pd + sd) trim | filters.SetPTS(VIDEO) > original ff > original ff > output ff.check_buffering()
def test_detect_trim_buffering(self): """ When trim and concat filters are used for editing timeline, buffering may occur if order of scenes in output file does not match order of same scenes in input file. """ cases = [ (False, [1.0, 2.0], [2.0, 3.0]), (True, [2.0, 3.0], [1.0, 2.0]), (True, [2.0, 3.0], [2.0, 4.0]), ] for case in cases: with self.subTest(case): raises, first, second = case ff = FFMPEG() s1 = inputs.Stream(VIDEO, self.source.streams[0].meta) s2 = inputs.Stream(VIDEO, self.source.streams[1].meta) ff < inputs.input_file('input.mp4', s1, s2) split = ff.video | filters.Split(VIDEO) t1 = split | filters.Trim(VIDEO, *first) p1 = t1 | filters.SetPTS(VIDEO) t2 = split | filters.Trim(VIDEO, *second) p2 = t2 | filters.SetPTS(VIDEO) concat = p1 | filters.Concat(VIDEO) output = outputs.output_file('output.mp4', codecs.VideoCodec('libx264')) p2 | concat > output ff > output try: ff.check_buffering() except BufferError as e: self.assertTrue(raises, e) else: self.assertFalse(raises)
def test_fix_trim_buffering(self): """ Trim buffering could be fixed with multiple source file deconding. """ ff = FFMPEG() v1 = inputs.Stream(VIDEO, self.source.streams[0].meta) a1 = inputs.Stream(AUDIO, self.source.streams[1].meta) v2 = inputs.Stream(VIDEO, self.source.streams[0].meta) a2 = inputs.Stream(AUDIO, self.source.streams[1].meta) in1 = ff < inputs.input_file('input.mp4', v1, a1) in2 = ff < inputs.input_file('input.mp4', v2, a2) p1 = in1.video | filters.Trim(VIDEO, 2.0, 3.0) | filters.SetPTS(VIDEO) p2 = in2.video | filters.Trim(VIDEO, 1.0, 2.0) | filters.SetPTS(VIDEO) output = outputs.output_file('output.mp4', codecs.VideoCodec('libx264')) concat = p1 | filters.Concat(VIDEO) p2 | concat > output ff > output ff.check_buffering()