예제 #1
0
 def test_ensure_throws_exception_for_absent_audio_codec_args(self):
     with pytest.raises(ImportError) as excinfo:
         # Fetch a list of args from the unffmpeg audio codec handler
         audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mkv.mkv_stereo_aac_audio_ffprobe)
         # Set the audio codec to something that does not exist
         audio_codec_handle.enable_audio_stream_stereo_cloning = True
         audio_codec_handle.set_audio_codec_with_default_encoder_cloning('non_existent_codec')
예제 #2
0
 def test_ensure_we_can_generate_audio_codec_stereo_clone_args(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mkv.mkv_multiple_subtitles_ffprobe)
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
예제 #3
0
 def test_ensure_we_can_generate_copy_current_audio_codec_args(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mkv.mkv_multiple_subtitles_ffprobe)
     # Just copy the current codec (do not re-encode)
     audio_codec_handle.disable_audio_encoding = True
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
     # Assert the streams to encode array is set to copy
     assert audio_codec_args['streams_to_encode'][1] == 'copy'
예제 #4
0
 def test_ensure_args_of_audio_stream_transcode_is_copy_if_src_codec_matches_dest_codec(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mkv.mkv_stereo_aac_audio_ffprobe)
     audio_codec_handle.enable_audio_stream_transcoding = True
     audio_codec_handle.set_audio_codec_with_default_encoder_transcoding(
         'aac')  # Src is aac and dest is aac. Audio stream should just copy
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
     # Assert the streams to encode array is set to copy
     assert audio_codec_args['streams_to_encode'][1] == 'copy'
예제 #5
0
 def test_ensure_we_can_generate_audio_codec_transcode_args(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mp4.mp4_dd_plus_audio_ffprobe)
     audio_codec_handle.enable_audio_stream_transcoding = True
     audio_codec_handle.set_audio_codec_with_default_encoder_transcoding('ac3')
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
     # Assert the first streams to encode array item is set to ac3
     assert audio_codec_args['streams_to_encode'][1] == 'ac3'
     # Assert no clone stream args are created (the streams_to_encode array is only a length of 2)
     assert len(audio_codec_args['streams_to_encode']) == 2
예제 #6
0
 def test_ensure_we_can_set_the_bitrate_of_a_stereo_audio_codec_stream(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mp4.mp4_dd_plus_audio_ffprobe)
     # Set the audio codec to aac
     audio_codec_handle.enable_audio_stream_stereo_cloning = True
     audio_codec_handle.set_audio_codec_with_default_encoder_cloning('aac')
     audio_codec_handle.audio_stereo_stream_bitrate = 'TEST_BITRATE'
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
     # Assert the second streams to encode array item has a bitrate set of 'TEST_BITRATE'
     assert audio_codec_args['streams_to_encode'][5] == 'TEST_BITRATE'
예제 #7
0
 def test_ensure_we_can_generate_a_cloned_stereo_aac_audio_codec_stream_from_ss_audio_stream_args(self):
     # Fetch a list of args from the unffmpeg audio codec handler
     audio_codec_handle = unffmpeg.AudioCodecHandle(ffprobe_mp4.mp4_dd_plus_audio_ffprobe)
     # Set the audio codec to aac
     audio_codec_handle.enable_audio_stream_stereo_cloning = True
     audio_codec_handle.set_audio_codec_with_default_encoder_cloning('aac')
     audio_codec_args = audio_codec_handle.args()
     # Assert the streams to map array is not empty
     assert audio_codec_args['streams_to_map']
     # Assert the streams to encode array is not empty
     assert audio_codec_args['streams_to_encode']
     # Assert the first streams to encode array item is set to copy (copies the DD Plus stream)
     assert audio_codec_args['streams_to_encode'][1] == 'copy'
     # Assert the second streams to encode array item is set to aac (clones the DD Plus stream to a stereo aac)
     assert audio_codec_args['streams_to_encode'][3] == 'aac'
예제 #8
0
    def generate_ffmpeg_args(self,):
        # ffmpeg -i /library/XXXXX.mkv \
        #     -c:v libx265 \
        #     -map 0:0 -map 0:1 -map 0:1 \
        #     -c:a:0 copy \
        #     -c:a:1 libmp3lame -b:a:0 192k -ac 2 \
        #     -y /cache/XXXXX.mkv
        #

        # Read video information for the input file
        file_probe = self.file_in['file_probe']
        if not file_probe:
            return False

        # current_container = unffmpeg.containers.grab_module(self.settings.OUT_CONTAINER)
        destination_container = unffmpeg.containers.grab_module(self.settings.OUT_CONTAINER)

        # Suppress printing banner. (-hide_banner)
        # Set loglevel to info ("-loglevel", "info")
        # Allow experimental encoder config ("-strict", "-2")
        #
        command = ["-hide_banner", "-loglevel", "info", "-strict", "-2", "-max_muxing_queue_size", "512"]

        # Read stream data
        streams_to_map = []
        streams_to_encode = []

        # Set video encoding args
        video_codec_handle = unffmpeg.VideoCodecHandle(file_probe)
        if not self.settings.ENABLE_VIDEO_ENCODING:
            video_codec_handle.disable_video_encoding = True
        # Set video codec and encoder
        video_codec_handle.video_codec = self.settings.VIDEO_CODEC
        video_codec_handle.video_encoder = self.settings.VIDEO_STREAM_ENCODER
        video_codec_args = video_codec_handle.args()
        streams_to_map = streams_to_map + video_codec_args['streams_to_map']
        streams_to_encode = streams_to_encode + video_codec_args['streams_to_encode']

        # Set audio encoding args
        audio_codec_handle = unffmpeg.AudioCodecHandle(file_probe)
        if not self.settings.ENABLE_AUDIO_ENCODING:
            audio_codec_handle.disable_audio_encoding = True
        # Are we transcoding audio streams to a configured codec?
        audio_codec_handle.enable_audio_stream_transcoding = self.settings.ENABLE_AUDIO_STREAM_TRANSCODING
        audio_codec_handle.audio_codec_transcoding = self.settings.AUDIO_CODEC
        audio_codec_handle.audio_encoder_transcoding = self.settings.AUDIO_STREAM_ENCODER
        # Are we cloning audio streams to stereo streams?
        audio_codec_handle.enable_audio_stream_stereo_cloning = self.settings.ENABLE_AUDIO_STREAM_STEREO_CLONING
        audio_codec_handle.set_audio_codec_with_default_encoder_cloning(self.settings.AUDIO_CODEC_CLONING)
        audio_codec_handle.audio_stereo_stream_bitrate = self.settings.AUDIO_STEREO_STREAM_BITRATE
        # Fetch args
        audio_codec_args = audio_codec_handle.args()
        streams_to_map = streams_to_map + audio_codec_args['streams_to_map']
        streams_to_encode = streams_to_encode + audio_codec_args['streams_to_encode']

        # Set subtitle encoding args
        subtitle_handle = unffmpeg.SubtitleHandle(file_probe, destination_container)
        if self.settings.REMOVE_SUBTITLE_STREAMS:
            subtitle_handle.remove_subtitle_streams = True
        subtitle_args = subtitle_handle.args()
        streams_to_map = streams_to_map + subtitle_args['streams_to_map']
        streams_to_encode = streams_to_encode + subtitle_args['streams_to_encode']

        # Map streams
        command = command + streams_to_map

        # Add arguments for creating streams
        command = command + streams_to_encode

        self._log(" ".join(command), level='debug')

        return command
예제 #9
0
    def generate_ffmpeg_args(self, file_probe, in_file, out_file):
        # ffmpeg -i /library/XXXXX.mkv \
        #     -c:v libx265 \
        #     -map 0:0 -map 0:1 -map 0:1 \
        #     -c:a:0 copy \
        #     -c:a:1 libmp3lame -b:a:0 192k -ac 2 \
        #     -y /cache/XXXXX.mkv
        #

        # current_container = unffmpeg.containers.grab_module(self.settings['out_container'])
        destination_container = unffmpeg.containers.grab_module(
            self.settings['out_container'])

        # Suppress printing banner. (-hide_banner)
        # Set loglevel to info ("-loglevel", "info")
        # Allow experimental encoder config ("-strict", "-2")
        # Fix issue - 'Too many packets buffered for output stream 0:1' ("-max_muxing_queue_siz", "2048")
        #       REF: [https://trac.ffmpeg.org/ticket/6375]
        #
        main_options = ["-hide_banner", "-loglevel", "info", "-strict", "-2"]
        # Configure Advanced options: https://ffmpeg.org/ffmpeg.html#Advanced-options
        # These are added after the input file
        advanced_options = ["-max_muxing_queue_size", "2048"]
        command = []

        # Hardware acceleration args
        hardware_acceleration = unffmpeg.HardwareAccelerationHandle(file_probe)
        if self.settings['enable_video_encoding']:
            hardware_acceleration.video_encoder = self.settings[
                'video_stream_encoder']
        # Check if hardware decoding is enabled
        if self.settings['enable_hardware_accelerated_decoding']:
            hardware_acceleration.enable_hardware_accelerated_decoding = True
            # The "Enable HW Decoding" checkbox is selected...
            # Loop over available decoders to select the best match for the current settings...
            for hardware_device in hardware_acceleration.get_hwaccel_devices():
                # TODO: in the future perhaps add a feature to be able to select which decoder to use.

                # First select the first one in the list (if nothing else matches, this one will be used)
                if hardware_acceleration.hardware_device is None:
                    hardware_acceleration.hardware_device = hardware_device

                # If we have enabled a HW accelerated encoder, then attempt to match the decoder with it.
                hwaccel = hardware_acceleration.hardware_device.get('hwaccel')
                if "vaapi" in self.settings[
                        'video_stream_encoder'] and hwaccel == "vaapi":
                    hardware_acceleration.hardware_device = hardware_device
                    break
                elif "nvenc" in self.settings[
                        'video_stream_encoder'] and hwaccel == "cuda":
                    hardware_acceleration.hardware_device = hardware_device
                    break
                continue
        hardware_acceleration.set_hwaccel_args()
        main_options = hardware_acceleration.update_main_options(main_options)
        advanced_options = hardware_acceleration.update_advanced_options(
            advanced_options)

        # Read stream data
        streams_to_map = []
        streams_to_encode = []

        # Set video encoding args
        video_codec_handle = unffmpeg.VideoCodecHandle(file_probe)
        if not self.settings['enable_video_encoding']:
            video_codec_handle.disable_video_encoding = True
        # Set video codec and encoder
        video_codec_handle.video_codec = self.settings['video_codec']
        video_codec_handle.video_encoder = self.settings[
            'video_stream_encoder']
        video_codec_args = video_codec_handle.args()
        streams_to_map = streams_to_map + video_codec_args['streams_to_map']
        streams_to_encode = streams_to_encode + video_codec_args[
            'streams_to_encode']

        # Set audio encoding args
        audio_codec_handle = unffmpeg.AudioCodecHandle(file_probe)
        if not self.settings['enable_audio_encoding']:
            audio_codec_handle.disable_audio_encoding = True
        # Are we transcoding audio streams to a configured codec?
        audio_codec_handle.enable_audio_stream_transcoding = self.settings[
            'enable_audio_stream_transcoding']
        audio_codec_handle.audio_codec_transcoding = self.settings[
            'audio_codec']
        audio_codec_handle.audio_encoder_transcoding = self.settings[
            'audio_stream_encoder']
        # Are we cloning audio streams to stereo streams?
        audio_codec_handle.enable_audio_stream_stereo_cloning = self.settings[
            'enable_audio_stream_stereo_cloning']
        audio_codec_handle.set_audio_codec_with_default_encoder_cloning(
            self.settings['audio_codec_cloning'])
        audio_codec_handle.audio_stereo_stream_bitrate = self.settings[
            'audio_stereo_stream_bitrate']
        # Fetch args
        audio_codec_args = audio_codec_handle.args()
        streams_to_map = streams_to_map + audio_codec_args['streams_to_map']
        streams_to_encode = streams_to_encode + audio_codec_args[
            'streams_to_encode']

        # Set subtitle encoding args
        subtitle_handle = unffmpeg.SubtitleHandle(file_probe,
                                                  destination_container)
        if self.settings['remove_subtitle_streams']:
            subtitle_handle.remove_subtitle_streams = True
        subtitle_args = subtitle_handle.args()
        streams_to_map = streams_to_map + subtitle_args['streams_to_map']
        streams_to_encode = streams_to_encode + subtitle_args[
            'streams_to_encode']

        # Overwrite additional options
        if self.settings['overwrite_additional_ffmpeg_options']:
            advanced_options = self.settings[
                'additional_ffmpeg_options'].split()

        # Add main options to command
        command = command + main_options

        # Add input file
        command = command + ['-i', in_file]

        # Add advanced options to command
        command = command + advanced_options

        # Map streams
        command = command + streams_to_map

        # Add arguments for creating streams
        command = command + streams_to_encode

        # Add output file
        command = command + ['-y', out_file]

        return command