def test_replace_streams_command_validates_stream_type(self): with self.assertRaises(exceptions.InvalidArgument): commands.replace_streams_command( get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), "v:1", {}, )
def test_replace_streams_command_does_not_accept_video_parameters(self): with self.assertRaises(exceptions.InvalidArgument): commands.replace_streams_command( get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), "v", { 'video': { 'codec': 'h264', 'bitrate': '1000k', }, })
def test_generate_sample_video_command_should_support_multiple_streams_with_same_codec( self): output_path = os.path.join(self.tmp_dir, 'output.mp4') requested_streams_with_types = [ ('subtitle', 'mov_text'), ('video', 'h264'), ('video', 'h264'), ('subtitle', 'mov_text'), ] requested_streams = [ codec_name for codec_type, codec_name in requested_streams_with_types ] expected_command = [ commands.FFMPEG_COMMAND, "-nostdin", "-i", get_absolute_resource_path('sample.srt'), "-i", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), "-map", "0:0", "-codec:0", "mov_text", "-map", "1:0", "-codec:1", "h264", "-map", "1:0", "-codec:2", "h264", "-map", "0:0", "-codec:3", "mov_text", "-f", "mp4", output_path, ] command = generate_sample_video_command( requested_streams, output_path, container='mp4', ) self.assertEqual(command, expected_command)
def test_extract_split_transcoding_merge_replace(self): input_path = get_absolute_resource_path( "ForBiggerBlazes-[codec=h264].mp4") input_metadata = commands.get_metadata_json(input_path) validation.validate_video(input_metadata) transcode_step_targs = { 'container': formats.Container.c_MATROSKA.value, 'frame_rate': '25/1', 'video': { 'codec': codecs.VideoCodec.VP8.value, 'bitrate': '1000k', }, 'resolution': [160, 90], 'scaling_alg': 'neighbor', } replace_step_targs = { 'audio': { 'codec': codecs.AudioCodec.MP3.value, 'bitrate': '128k', }, } validation.validate_transcoding_params( { **transcode_step_targs, **replace_step_targs }, input_metadata, commands.query_muxer_info(transcode_step_targs['container']), commands.query_encoder_info(codecs.VideoCodec.VP8.get_encoder()), ) self.run_extract_split_transcoding_merge_replace_test( num_segments=3, input_path=input_path, extract_step_output_path=os.path.join( self.work_dirs['extract'], "ForBiggerBlazes-[codec=h264][video-only].mp4"), split_step_basename_template= "ForBiggerBlazes-[codec=h264][video-only]_{}.mp4", transcode_step_basename_template= "ForBiggerBlazes-[codec=h264][video-only]_{}_TC.mkv", merge_step_output_path=os.path.join( self.work_dirs['merge'], "ForBiggerBlazes-[codec=h264][video-only]_TC.mkv"), replace_step_output_path=os.path.join( self.work_dirs['replace'], "ForBiggerBlazes-[codec=h264]_TC.mkv"), ffconcat_list_path=os.path.join(self.work_dirs['transcode'], "merge-input.ffconcat"), transcode_step_targs=transcode_step_targs, replace_step_targs=replace_step_targs, )
def test_replace_streams_converts_subtitles(self): input_path = os.path.join(self.tmp_dir, 'input.mkv') replacement_path = get_absolute_resource_path( "ForBiggerBlazes-[codec=h264].mp4") output_path = os.path.join(self.tmp_dir, 'output.mp4') generate_sample_video([ codecs.SubtitleCodec.ASS.value, codecs.VideoCodec.MJPEG.value, codecs.AudioCodec.MP3.value, codecs.SubtitleCodec.SUBRIP.value, codecs.VideoCodec.FLV1.value, codecs.AudioCodec.AAC.value, codecs.SubtitleCodec.WEBVTT.value, ], input_path, container=formats.Container.c_MATROSKA.value) assert os.path.isfile(input_path) assert not os.path.isfile(output_path) commands.replace_streams( input_path, replacement_path, output_path, stream_type='v', targs={}, container=formats.Container.c_MP4.value, strip_unsupported_data_streams=True, strip_unsupported_subtitle_streams=True, ) self.assertTrue(os.path.isfile(output_path)) metadata = meta.get_metadata(output_path) self.assertEqual(meta.get_format(metadata), formats.Container.c_QUICK_TIME_DEMUXER.value) self.assertIn('streams', metadata) expected_streams = [ ('video', codecs.VideoCodec.H_264.value), ('subtitle', codecs.SubtitleCodec.MOV_TEXT.value), ('audio', codecs.AudioCodec.AAC.value), ('subtitle', codecs.SubtitleCodec.MOV_TEXT.value), ('audio', codecs.AudioCodec.AAC.value), ('subtitle', codecs.SubtitleCodec.MOV_TEXT.value), ] streams = [(stream_metadata.get('codec_type'), stream_metadata.get('codec_name')) for stream_metadata in metadata['streams']] self.assertEqual(streams, expected_streams)
def test_transcoding(self): params = meta.create_params("mp4", [1280, 800], "h265") input_video = get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264].mp4') output_video = os.path.join(tempfile.gettempdir(), "ForBiggerBlazes-[codec=h265].mp4") if os.path.exists(output_video): os.remove(output_video) commands.transcode_video(input_video, params, output_video) assert os.path.exists(output_video)
def test_replace_streams_command_removes_streams_not_in_whitelist_if_asked_to( self, _mock_find_unsupported_subtitle_streams, _mock_find_unsupported_data_streams, _mock_get_metadata_json, ): command = commands.replace_streams_command( get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), "v", {}, strip_unsupported_data_streams=True, strip_unsupported_subtitle_streams=True) expected_command = [ "ffmpeg", "-nostdin", "-i", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), "-i", get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), "-map", "1:v", "-map", "0", "-map", "-0:v", '-map', '-0:2', '-map', '-0:3', "-copy_unknown", "-c:v", "copy", "-c:d", "copy", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), ] self.assertEqual(command, expected_command)
def test_replace_streams_command(self, _mock_get_metadata_json): command = commands.replace_streams_command( get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), "v", {'audio': { 'codec': 'mp3', 'bitrate': '128k', }}, ) expected_command = [ "ffmpeg", "-nostdin", "-i", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), "-i", get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264][video-only].mkv'), "-map", "1:v", "-map", "0", "-map", "-0:v", "-copy_unknown", "-c:v", "copy", "-c:d", "copy", "-c:a", codecs.AudioCodec.get_encoder(codecs.AudioCodec.MP3), "-b:a", "128k", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mkv'), ] self.assertEqual(command, expected_command)
def test_generate_sample_video_command(self): output_path = os.path.join(self.tmp_dir, 'output.mkv') requested_streams = [ codec_name for codec_type, codec_name in self.ALMOST_ALL_STREAMS ] expected_command = [ commands.FFMPEG_COMMAND, "-nostdin", "-i", get_absolute_resource_path('ForBiggerBlazes-[codec=h264].mp4'), "-i", get_absolute_resource_path('sample.srt'), "-map", "0:0", "-codec:0", "h264", "-map", "0:0", "-codec:1", "mjpeg", "-map", "0:0", "-codec:2", "flv1", "-map", "0:0", "-codec:3", "vp8", "-map", "0:1", "-codec:4", "aac", "-map", "0:1", "-codec:5", "mp3", "-map", "1:0", "-codec:6", "subrip", "-map", "1:0", "-codec:7", "ass", "-map", "1:0", "-codec:8", "webvtt", "-f", "matroska", output_path, ] command = generate_sample_video_command( requested_streams, output_path, container='matroska', ) self.assertEqual(command, expected_command)
def test_get_video_length(self): input_video = get_absolute_resource_path( 'ForBiggerBlazes-[codec=h264].mp4') length = commands.get_video_len(input_video) assert length == 15.021667