예제 #1
0
    def get_norm_volume(self, filename):
        """ Gets the volume correction of a movie using ffmpeg and sox. 
            Returns without error:              
                        norm_vol, None
                    with error:
                        1.0, error_message """

        try:
            process1 = subprocess.Popen([
                path.get_tools_path('intern-ffmpeg'), '-loglevel', 'quiet',
                '-i', filename, '-f', 'sox', '-'
            ],
                                        stdout=subprocess.PIPE)
        except OSError:
            return "1.0", "FFMPEG wurde nicht gefunden!"

        try:
            process2 = subprocess.Popen([
                path.get_tools_path('intern-sox'), '-p', '--null', 'stat', '-v'
            ],
                                        stdin=process1.stdout,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.STDOUT)
        except OSError:
            return "1.0", "SOX wurde nicht gefunden!"

        log = process2.communicate()[0]

        for line in log.split('\n'):
            try:
                return line, None
            except:
                return "1.0", "Volume konnte nicht bestimmt werden " + line

        return None, "Volume konnte nicht bestimmt werden."
예제 #2
0
    def get_norm_volume(self, filename):
        """ Gets the volume correction of a movie using ffmpeg and sox. 
            Returns without error:              
                        norm_vol, None
                    with error:
                        1.0, error_message """

        try:
            process1 = subprocess.Popen(
                [path.get_tools_path("intern-ffmpeg"), "-loglevel", "quiet", "-i", filename, "-f", "sox", "-"],
                stdout=subprocess.PIPE,
            )
        except OSError:
            return "1.0", "FFMPEG wurde nicht gefunden!"

        try:
            process2 = subprocess.Popen(
                [path.get_tools_path("intern-sox"), "-p", "--null", "stat", "-v"],
                stdin=process1.stdout,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
            )
        except OSError:
            return "1.0", "SOX wurde nicht gefunden!"

        log = process2.communicate()[0]

        for line in log.split("\n"):
            try:
                return line, None
            except:
                return "1.0", "Volume konnte nicht bestimmt werden " + line

        return None, "Volume konnte nicht bestimmt werden."
예제 #3
0
 def get_norm_volume(self, filename):
     """ Gets the volume correction of a movie using ffmpeg and sox. 
         Returns without error:              
                     norm_vol, None
                 with error:
                     1.0, error_message """
         
     try:
         process1 = subprocess.Popen([path.get_tools_path('intern-ffmpeg'), '-loglevel', 'quiet', '-i', filename, '-f', 'sox', '-'], stdout=subprocess.PIPE)       
     except OSError:
         return "1.0", "FFMPEG wurde nicht gefunden!"            
 
     try:
         process2 = subprocess.Popen([path.get_tools_path('intern-sox'), '-p', '--null', 'stat', '-v'], stdin=process1.stdout,stdout=subprocess.PIPE, stderr=subprocess.STDOUT)       
     except OSError:
         return "1.0", "SOX wurde nicht gefunden!"            
         
     log = process2.communicate()[0]
         
     for line in log.split('\n'):
             try:
                 return line, None
             except:
                 return "1.0", "Volume konnte nicht bestimmt werden " + line
       
     return None, "Volume konnte nicht bestimmt werden."
예제 #4
0
    def get_norm_volume(self, filename, stream):
        """ Gets the volume correction of a movie using ffprobe. 
            Returns without error:              
                        norm_vol, None
                    with error:
                        1.0, error_message """

        global adjust
        self.gui.main_window.set_tasks_text('Berechne den Normalisierungswert')
        self.gui.main_window.set_tasks_progress(0)
        try:
            process1 = subprocess.Popen([
                path.get_tools_path('intern-ffprobe'), '-v', 'error', '-of',
                'compact=p=0:nk=1', '-drc_scale', '1.0', '-show_entries',
                'frame_tags=lavfi.r128.I', '-f', 'lavfi',
                'amovie=' + filename + ':si=' + stream + ',ebur128=metadata=1'
            ],
                                        stdout=subprocess.PIPE)
        except OSError:
            return "1.0", "FFMPEG wurde nicht gefunden!"

        log = process1.communicate()[0]

        loudness = ref = -23
        for line in log.splitlines():
            sline = line.rstrip()
            if sline:
                loudness = sline
                adjust = ref - float(loudness)
        self.gui.main_window.set_tasks_progress(100)
        if adjust:
            return str(adjust) + 'dB', None
        else:
            return "1.0", "Volume konnte nicht bestimmt werden."
예제 #5
0
 def get_norm_volume(self, filename, stream):
     """ Gets the volume correction of a movie using ffprobe. 
         Returns without error:              
                     norm_vol, None
                 with error:
                     1.0, error_message """
         
     self.gui.main_window.set_tasks_text('Berechne den Normalisierungswert')
     self.gui.main_window.set_tasks_progress(0)
     try:
         process1 = subprocess.Popen([path.get_tools_path('intern-ffprobe'), '-v',  'error','-of','compact=p=0:nk=1','-drc_scale','1.0','-show_entries','frame_tags=lavfi.r128.I','-f','lavfi','amovie='+filename+':si='+stream+',ebur128=metadata=1'], stdout=subprocess.PIPE)       
     except OSError:
         return "1.0", "FFMPEG wurde nicht gefunden!"            
             
     log = process1.communicate()[0]
         
 
     loudness = ref = -23
     for line in log.splitlines():
         sline = line.rstrip()
         if sline:
             loudness = sline
             adjust = ref - float(loudness)
     self.gui.main_window.set_tasks_progress(100)
     if adjust:
         return str(adjust)+'dB',  None
     else:
         return "1.0", "Volume konnte nicht bestimmt werden."
예제 #6
0
        def mp4():
            # env
            my_env = os.environ.copy()
            my_env["LANG"] = "C"

            for count, filename in enumerate(filenames):
                # analyse file
                cutter = Cut(self.app, self.gui)
                fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile(filename)
                if fps == None:
                    self.errors[filename] = error
                    continue

                # mkvmerge pass
                yield 0, count
                self.progress = 0

                if os.path.splitext(filename)[1] != ".mkv":

                    mkvpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + "_remux.mkv")
                    try:
                        p = subprocess.Popen(
                            [
                                self.app.config.get_program("mkvmerge"),
                                "--ui-language",
                                "en_US",
                                "-o",
                                mkvpass_file,
                                filename,
                            ],
                            stdout=subprocess.PIPE,
                            env=my_env,
                        )
                    except OSError:
                        self.errors[filename] = "MKVmerge wurde nicht gefunden!"
                        continue

                    p.stdout.readline()
                    line = ""

                    while p.poll() == None:
                        # read progress from stdout
                        char = p.stdout.read(1)
                        line += char
                        progress = ""
                        if char == ":":
                            if "Error" in line or "Warning" in line:
                                break

                            while char != "%":
                                char = p.stdout.read(1)
                                progress += char

                            try:
                                self.progress = int(progress.strip(" %"))
                                yield 4, self.progress
                            except ValueError:
                                pass

                    exit_code = p.poll()

                    if exit_code == 0 or exit_code == 1:
                        pass
                    else:
                        error = p.stdout.readline()
                        if os.path.exists(mkvpass_file):
                            fileoperations.remove_file(mkvpass_file)
                        try:
                            error = error.split(":")[1]
                        except IndexError:
                            pass

                        if "unknown type" in error:
                            error = "Datei konnte nicht gelesen werden."
                        self.errors[filename] = error
                        continue
                else:
                    mkvpass_file = filename

                # norm volume ausrechnen
                yield 5, count
                if self.Config["NormalizeAudio"] and self.Config["EncodeAudioToAAC"]:
                    vol, error = self.get_norm_volume(filename)
                else:
                    vol = 1.0

                # ffmpeg pass
                yield 1, count
                self.progress = 0
                ffmpegpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + "_remux.mp4")

                if self.Config["EncodeAudioToAAC"]:
                    if self.Config["EncodeOnlyFirstAudioToAAC"]:
                        aacaudiostreams = "-c:a:0"
                    else:
                        aacaudiostreams = "-c:a"

                    # convert first audio stream to aac
                    ffmpeg = self.app.config.get_program("ffmpeg")
                    if "nonfree" in ffmpeg:
                        # nonfree ffmpeg version with fdk support available
                        audiocodec = [
                            "-c:a",
                            "copy",
                            aacaudiostreams,
                            "libfdk_aac",
                            "-flags",
                            "+qscale",
                            "-profile:a:0",
                            "aac_low",
                            "-global_quality",
                            "5",
                            "-afterburner",
                            "1",
                        ]
                    else:
                        # only gpl version of ffmpeg available -> use standard aac codec
                        audiocodec = [
                            "-c:a",
                            "copy",
                            aacaudiostreams,
                            "aac",
                            "-strict",
                            "-2",
                            "-profile:a:0",
                            "aac_low",
                            "-ab",
                            "192k",
                            "-cutoff",
                            "18000",
                        ]
                else:
                    # only copy audio
                    ffmpeg = path.get_tools_path("intern-ffmpeg")
                    audiocodec = ["-c:a", "copy"]

                if self.Config["DownMixStereo"] and self.Config["EncodeAudioToAAC"]:
                    audiocodec.extend(["-ac:0", "2"])

                if ac3_stream == None:
                    # no ac3 stream found - all streams are muxed
                    map = ["-map", "0"]
                else:
                    if self.Config["RemoveOtherAudioStreamsThanAC3"]:
                        # mux only video and ac3 stream
                        map = ["-map", "0:v", "-map", ac3_stream]
                    else:
                        map = ["-map", "0"]

                args = [
                    ffmpeg,
                    "-loglevel",
                    "info",
                    "-y",
                    "-drc_scale",
                    "1.0",
                    "-i",
                    mkvpass_file,
                    "-vcodec",
                    "copy",
                    "-af",
                    "volume=volume=" + str(vol),
                    "-vsync",
                    "1",
                    "-async",
                    "1000",
                    "-dts_delta_threshold",
                    "100",
                    "-vf",
                    "fps=" + str(fps),
                    ffmpegpass_file,
                ]
                map.extend(audiocodec)
                args[8:8] = map

                try:
                    p = subprocess.Popen(args, stderr=subprocess.PIPE, universal_newlines=True)
                except OSError:
                    self.errors[filename] = "FFMPEG (intern) wurde nicht gefunden!"
                    if os.path.exists(mkvpass_file) and filename != mkvpass_file:
                        fileoperations.remove_file(mkvpass_file)
                    continue

                yield 4, 0
                line = ""
                infos_match = re.compile(r"frame=\ {0,1}(\d{1,})")

                while p.poll() == None:
                    line = p.stderr.readline()
                    m = re.search(infos_match, line)
                    if m and max_frames != 0:
                        next = float(float(m.group(1)) / float(max_frames)) * 100
                        if next > self.progress:
                            self.progress = next
                            yield 4, self.progress
                    else:
                        pass

                exit_code = p.poll()
                if os.path.exists(mkvpass_file) and filename != mkvpass_file:
                    fileoperations.remove_file(mkvpass_file)

                if exit_code == 0:
                    if self.Config["DumpAVIs"]:
                        yield 3, self.success
                        new_filename = os.path.join(
                            self.app.config.get("general", "folder_trash_avis"), os.path.basename(filename)
                        )
                        if os.path.exists(new_filename):
                            fileoperations.remove_file(new_filename)
                        fileoperations.move_file(filename, self.app.config.get("general", "folder_trash_avis"))
                else:
                    self.errors[filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG"
                    if os.path.exists(ffmpegpass_file):
                        fileoperations.remove_file(ffmpegpass_file)
                    continue

                # mp4box - last turn
                self.progress = 0
                mp4boxpass_file = fileoperations.make_unique_filename(os.path.splitext(filename)[0] + ".mp4")

                if self.Config["DontOptimizeMP4"]:
                    os.rename(ffmpegpass_file, mp4boxpass_file)
                    self.success += 1
                    continue

                yield 2, count
                try:
                    p = subprocess.Popen(
                        [
                            self.app.config.get_program("mp4box"),
                            "-keep-all",
                            "-new",
                            "-packed",
                            "-fps",
                            str(fps),
                            "-add",
                            ffmpegpass_file,
                            mp4boxpass_file,
                        ],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                    )
                except OSError:
                    self.errors[filename] = "MP4Box (intern) wurde nicht gefunden!"
                    if os.path.exists(ffmpegpass_file):
                        fileoperations.remove_file(ffmpegpass_file)
                    continue

                yield 4, 0
                infos_match = re.compile(r".*\((\d{2,})\/\d{2,}\).*")

                while p.poll() == None:
                    line = p.stdout.read(60)
                    m = re.search(infos_match, line)
                    if m:
                        self.progress = int(m.group(1))
                        yield 4, self.progress

                        if "Importing" in line:
                            yield 2, count
                        elif "Writing" in line:
                            yield 6, count
                    else:
                        pass

                exit_code = p.poll()
                if os.path.exists(ffmpegpass_file):
                    fileoperations.remove_file(ffmpegpass_file)

                if exit_code == 0:
                    self.success += 1
                else:
                    self.errors[filename] = "Fehler beim Erzeugen der MP4 Datei durch MP4Box"
예제 #7
0
    def cut_file_by_cutlist(self, filename, cutlist=None, program_config_value=None):
        """ Cuts a otr file with x264 and mkvmerge frame accurate. 
            returns: name of cut video, error_message """
        # configuration
        videolist = []                                              # result list for smart rendering simulation
        audio_import_files = [filename]                 # otr files which have audio streams  and needs to be cutted (e.g. OTR avi and ac3) 
        process_list = []                                        # list of started processes
        mkvmerge_list = []                                     # list of started mkvmerge processes
        video_splitframes = ''                               # mkvmerge split string for cutting the video at keyframes 
        audio_timecodes = ''                                # mkvmerge split timecodes for cutting the audio
        ac3_file = None                                         # AC3 source file
        mkvmerge =  self.config.get_program('mkvmerge')
        x264 = self.config.get_program('x264')
        # env
        my_env = os.environ.copy()
        my_env["LANG"] = "C"
        my_env["LC_COLLATE"] = "C"

        # x264 option string
        format, ac3_file = self.get_format(filename)
        if format == Format.HQ:
            x264_opts,  x264_core = self.complete_x264_opts(self.config.get('smartmkvmerge', 'x264_hq_string').split(' '),  filename)
        elif format == Format.HD:
            x264_opts,  x264_core = self.complete_x264_opts(self.config.get('smartmkvmerge', 'x264_hd_string').split(' '),  filename)
        elif format == Format.MP4:
            x264_opts,  x264_core = self.complete_x264_opts(self.config.get('smartmkvmerge', 'x264_mp4_string').split(' '),  filename)
        else:
            return None, "Format nicht unterstützt (Nur MP4 H264, HQ H264 und HD H264 sind möglich)."
        logging.debug(x264_opts)
        
        if x264_core < 122:
            return None,  "Alte HQ Kodierung entdeckt. Diese Datei bitte mit intern-Virtualdub und Codec ffdshow schneiden."
        
        # test workingdir
        if os.access(self.config.get('smartmkvmerge', 'workingdir').rstrip('/'),  os.W_OK):
            self.workingdir = os.path.abspath(self.config.get('smartmkvmerge', 'workingdir')).rstrip('/')
        else:
            return None, "Ungültiges Temp Verzeichnis. Schreiben nicht möglich."
            
        # audio part 1 - cut audio 
        if ac3_file:
            audio_import_files.append(ac3_file)

        audio_timecodes = (',+'.join([self.get_timecode(start) + '-' + self.get_timecode(start+duration) for start, duration in cutlist.cuts_seconds]))        
        audio_timecodes = audio_timecodes.lstrip(',+')
        
        command = [mkvmerge, '--ui-language',  'en_US',  '-D',  '--split',  'parts:'+audio_timecodes,  '-o',  self.workingdir + '/audio_copy.mkv'] + audio_import_files
        logging.debug(command)
        try:
            blocking_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True,  env=my_env)
        except OSError as e:
            return None,  e.strerror + ": " + mkvmerge
        
        mkvmerge_list.append(blocking_process)

        # video part 1 - read keyframes
        keyframes, error = self.get_keyframes_from_file(filename)
        if keyframes == None:
            return None,  "Keyframes konnten nicht ausgelesen werden."
        logging.debug(keyframes)

        # video part 2 - simulate smart rendering process
        for frame_start, frames_duration in cutlist.cuts_frames:
            result = self.__simulate_smart_mkvmerge(int(frame_start), int(frames_duration), keyframes)
            if result != None:
                videolist += result
            else:
                return None,  'Cutlist oder zu schneidende Datei passen nicht zusammen oder sind fehlerhaft.'
        logging.debug(videolist)
    
        # video part 3 - encode small parts - smart rendering part (1/2) 
        for encode, start,  duration,  video_part_filename in videolist:
            self.video_files.append('+'+ self.workingdir +'/' + video_part_filename)
            command = [x264] + x264_opts + ['--demuxer','ffms','--index', self.workingdir + '/x264.index','--seek',  str(start),'--frames',  str(duration),  '--output',  self.workingdir + '/' + video_part_filename,  filename ]
            logging.debug(command)
            if encode:
                try:
                    non_blocking_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
                except OSError as e:
                    return None, e.strerror + ": " + x264
                process_list.append(non_blocking_process)
            else:
                video_splitframes += ','+str(start)+'-'+str(duration)

        self.video_files[0]=self.video_files[0].lstrip('+')
        video_splitframes = video_splitframes.lstrip(',')
        
        # video part 4 - cut the big parts out the file (keyframe accurate) - smart rendering part (2/2)
        command = [mkvmerge,  '--ui-language',  'en_US','-A',  '--split',  'parts-frames:'+video_splitframes,  '-o',  self.workingdir + '/video_copy.mkv', filename ]
        logging.debug(command)
        try:
            non_blocking_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, env=my_env)
        except OSError as e:
            return None, e.strerror + ": " + mkvmerge
        mkvmerge_list.append(non_blocking_process)

        # audio part 2 - encode audio to AAC
        if 'MP3 Spur kopieren' in self.config.get('smartmkvmerge', 'first_audio_stream') and 'AC3 Spur kopieren' in self.config.get('smartmkvmerge', 'second_audio_stream'):
            self.audio_files.append(self.workingdir + '/audio_copy.mkv')
        else:
                blocking_process.wait()
                self.show_progress(blocking_process)
                ffmpeginput_file = self.workingdir + '/audio_copy.mkv'
                ffmpegoutput_file = self.workingdir + '/audio_encode.mkv'
                
                audiofilter = ['-af',  'anull']
                # convert first audio stream to aac
                if 'AAC' in self.config.get('smartmkvmerge', 'first_audio_stream') and 'AAC' in self.config.get('smartmkvmerge', 'second_audio_stream'):
                    aacaudiostreams = '-c:a'
                    if self.config.get('smartmkvmerge', 'normalize_audio'):
                        vol0,  error = self.get_norm_volume(ffmpeginput_file, '0')
                        vol1,  error = self.get_norm_volume(ffmpeginput_file, '1')
                        audiofilter = ['-af:0', 'volume=volume=' + vol0,  '-af:1', 'volume=volume=' + vol1]
                elif 'AAC' in self.config.get('smartmkvmerge', 'second_audio_stream') and 'MP3' in self.config.get('smartmkvmerge', 'first_audio_stream'):
                    aacaudiostreams = '-c:a:1'
                    if self.config.get('smartmkvmerge', 'normalize_audio'):
                        vol,  error = self.get_norm_volume(ffmpeginput_file, '1')
                        audiofilter = ['-af:1', 'volume=volume=' + vol]
                elif 'AAC' in self.config.get('smartmkvmerge', 'first_audio_stream'):
                    aacaudiostreams = '-c:a:0'
                    if self.config.get('smartmkvmerge', 'normalize_audio'):
                        vol,  error = self.get_norm_volume(ffmpeginput_file, '0')
                        audiofilter = ['-af:0', 'volume=volume=' + vol]
                else:
                    aacaudiostreams = '-c:a:2'
                    
                ffmpeg = self.config.get_program('ffmpeg')
                if 'nonfree' in ffmpeg:
                    # nonfree ffmpeg version with fdk support available
                    audiocodec = ['-c:a',  'copy',  aacaudiostreams,  'libfdk_aac',  '-flags',  '+qscale',  '-profile:a',  'aac_low',  '-global_quality',  '5' ,'-afterburner',  '1']
                else:
                    # only gpl version of ffmpeg available -> use standard aac codec
                    audiocodec = ['-c:a',  'copy',  aacaudiostreams,  'aac', '-strict', '-2','-profile:a',  'aac_low',  '-ab' ,'192k',  '-cutoff',  '18000']
                    
                if '2-Kanal' in self.config.get('smartmkvmerge', 'first_audio_stream'):
                    audiocodec.extend(['-ac:0',  '2'])

                if ac3_file == None:
                    # no ac3 stream found - all streams are muxed 
                    map = ['-map',  '0']
                else:
                    if 'AC3' in self.config.get('smartmkvmerge', 'first_audio_stream') :
                        map = ['-map',  '0:a:1']
                    else:
                        map = ['-map',  '0:a:0']
                    if not 'AC3 Spur entfernen' in self.config.get('smartmkvmerge', 'second_audio_stream') :
                        map.extend(['-map',  '0:a:1'])
                    
                args = [ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i", ffmpeginput_file, "-vn", "-vsync", "1", '-async',  '200000',  "-dts_delta_threshold", "100", '-threads',  '0',    ffmpegoutput_file]
                map.extend(audiocodec)
                map.extend(audiofilter)
                args[8:8] = map
                logging.debug(args)
                try:
                    non_blocking_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
                except OSError as e:
                    return None, e.strerror + ": " + ffmpeg
                process_list.append(non_blocking_process)
                self.audio_files.append(self.workingdir + '/audio_encode.mkv')

        # wait until all threads are terminated
        for blocking_process in mkvmerge_list + process_list:
            self.show_progress(blocking_process)

        # check all processes
        for blocking_process in mkvmerge_list:
            returncode = blocking_process.wait()
            if returncode != 0 and returncode != 1:
                return None,  'beim Schneiden der Originaldatei...'
        for blocking_process in process_list:
            returncode = blocking_process.wait()
            if returncode != 0:
                return None,  'beim Kodieren ...'

        # clean up
        if os.path.isfile (self.workingdir + '/video_copy.mkv'):
            os.rename(self.workingdir + '/video_copy.mkv', self.workingdir + '/video_copy-001.mkv')
        if vars().has_key('ffmpeginput_file'):
            if os.path.isfile (ffmpeginput_file):
                os.remove(ffmpeginput_file)        
            
        # mux all together
        if self.config.get('smartmkvmerge', 'remux_to_mp4'):
            cut_video = self.workingdir + '/' + os.path.basename(os.path.splitext(self.generate_filename((filename),1))[0] + ".mkv")
        else:
            cut_video = os.path.splitext(self.generate_filename(filename,1))[0] + ".mkv"
        command = [mkvmerge,  '--engage', 'no_cue_duration', '--engage',  'no_cue_relative_position',  '--ui-language',  'en_US',  '-o',  cut_video] + self.video_files + self.audio_files
        logging.debug(command)
        try:
            blocking_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, env=my_env)
        except OSError:
            return None, "MKVMerge konnte nicht aufgerufen werden oder zu alt (6.5.0 benötigt)"
        self.show_progress(blocking_process)
        
        returncode = blocking_process.wait()
        if returncode != 0 and returncode != 1:
            return None,  'beim Schreiben des geschnittenen MKVs...'

        # remove all temporary files
        for n in self.video_files + self.audio_files:
            if os.path.isfile(n.lstrip('+')):
                os.remove(n.lstrip('+'))

        # mux to mp4 
        if self.config.get('smartmkvmerge', 'remux_to_mp4'):
            # split files with eac3to
            with ChangeDir(self.workingdir):
                stdout_encoding = sys.stdout.encoding or sys.getfilesystemencoding()
                command = ['wine', path.get_tools_path('intern-eac3to/eac3to.exe'), os.path.basename(cut_video),  '-demux',  '-silence',  '-keepDialnorm']
                logging.debug(command)
                try:
                    blocking_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
                except OSError:
                    return None, 'Eac3to konnte nicht aufgerufen werden'
                
                file_match = re.compile(r".*\"(.* - (\d{1,}) - .*)\".*")
                self.gui.main_window.set_tasks_text('Extrahiere Streams')
                self.gui.main_window.set_tasks_progress(50)
                while events_pending():
                    main_iteration(False)

                while blocking_process.poll() == None:
                    line = blocking_process.stdout.readline().strip()
                    if 'Creating file' in line:
                        m = re.search(file_match,line)
                        if m:
                            self.rawstreams[m.group(2)] = m.group(1).decode("iso-8859-1").encode("utf-8")
                        else:
                            pass
                            
                returncode = blocking_process.wait()
                if returncode != 0:
                    if os.path.isfile(cut_video):
                        os.remove(cut_video)
                    return None,  'Fehler beim Extrahieren der Streams mit Eac3to'
                
                # remove mkv + log file
                if os.path.isfile(cut_video):
                    os.remove(cut_video)
                if os.path.isfile(os.path.splitext(cut_video)[0]+ ' - Log.txt'):
                    os.remove(os.path.splitext(cut_video)[0]+ ' - Log.txt')

                args = [self.config.get_program('mp4box'), '-new',  '-keep-all']
                
                for index in sorted(self.rawstreams.keys()):
                    args.append('-add')
                    args.append(self.rawstreams[index])

                cut_video = os.path.splitext(self.generate_filename(filename,1))[0] + ".mp4"
                args.append(cut_video)
                
                # mux to mp4 (mp4box) 
                logging.debug(args)
                try:
                    blocking_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
                except OSError:
                    return None, 'MP4Box konnte nicht aufgerufen werden'
                    
                self.gui.main_window.set_tasks_text('Muxe MP4')                    
                self.show_progress(blocking_process)
                returncode = blocking_process.wait()
                if returncode != 0:
                    return None,  'Fehler beim Erstellen der MP4'
                    
        return cut_video, None
예제 #8
0
        def mp4():
            # env
            my_env = os.environ.copy()
            my_env["LANG"] = "C"

            for count, filename in enumerate(filenames):
                # analyse file
                cutter = Cut(self.app, self.gui)
                fps, dar, sar, max_frames, ac3_stream, error = cutter.analyse_mediafile(
                    filename)
                if fps == None:
                    self.errors[filename] = error
                    continue

                # mkvmerge pass
                yield 0, count
                self.progress = 0

                if os.path.splitext(filename)[1] != '.mkv':

                    mkvpass_file = fileoperations.make_unique_filename(
                        os.path.splitext(filename)[0] + "_remux.mkv")
                    try:
                        p = subprocess.Popen([
                            self.app.config.get_program('mkvmerge'),
                            '--ui-language', 'en_US', "-o", mkvpass_file,
                            filename
                        ],
                                             stdout=subprocess.PIPE,
                                             env=my_env)
                    except OSError:
                        self.errors[
                            filename] = "MKVmerge wurde nicht gefunden!"
                        continue

                    p.stdout.readline()
                    line = ""

                    while p.poll() == None:
                        # read progress from stdout
                        char = p.stdout.read(1)
                        line += char.decode('utf-8')
                        progress = ''
                        if char == ':':
                            if "Error" in line or "Warning" in line:
                                break

                            while char != '%':
                                char = p.stdout.read(1)
                                progress += char

                            try:
                                self.progress = int(progress.strip(' %'))
                                yield 4, self.progress
                            except ValueError:
                                pass

                    exit_code = p.poll()

                    if exit_code == 0 or exit_code == 1:
                        pass
                    else:
                        error = p.stdout.readline()
                        if os.path.exists(mkvpass_file):
                            fileoperations.remove_file(mkvpass_file)
                        try:
                            error = error.split(":")[1]
                        except IndexError:
                            pass

                        if "unknown type" in error:
                            error = "Datei konnte nicht gelesen werden."
                        self.errors[filename] = error
                        continue
                else:
                    mkvpass_file = filename

                # norm volume ausrechnen
                yield 5, count
                if self.Config['NormalizeAudio'] and self.Config[
                        'EncodeAudioToAAC']:
                    vol, error = self.get_norm_volume(filename)
                else:
                    vol = 1.0

                # ffmpeg pass
                yield 1, count
                self.progress = 0
                ffmpegpass_file = fileoperations.make_unique_filename(
                    os.path.splitext(filename)[0] + "_remux.mp4")

                if self.Config['EncodeAudioToAAC']:
                    if self.Config['EncodeOnlyFirstAudioToAAC']:
                        aacaudiostreams = '-c:a:0'
                    else:
                        aacaudiostreams = '-c:a'

                    # convert first audio stream to aac
                    ffmpeg = self.app.config.get_program('ffmpeg')
                    if 'nonfree' in ffmpeg:
                        # nonfree ffmpeg version with fdk support available
                        audiocodec = [
                            '-c:a', 'copy', aacaudiostreams, 'libfdk_aac',
                            '-flags', '+qscale', '-profile:a:0', 'aac_low',
                            '-global_quality', '5', '-afterburner', '1'
                        ]
                    else:
                        # only gpl version of ffmpeg available -> use standard aac codec
                        audiocodec = [
                            '-c:a', 'copy', aacaudiostreams, 'aac', '-strict',
                            '-2', '-profile:a:0', 'aac_low', '-ab', '192k',
                            '-cutoff', '18000'
                        ]
                else:
                    # only copy audio
                    ffmpeg = path.get_tools_path('intern-ffmpeg')
                    audiocodec = ['-c:a', 'copy']

                if self.Config['DownMixStereo'] and self.Config[
                        'EncodeAudioToAAC']:
                    audiocodec.extend(['-ac:0', '2'])

                if ac3_stream == None:
                    # no ac3 stream found - all streams are muxed
                    map = ['-map', '0']
                else:
                    if self.Config['RemoveOtherAudioStreamsThanAC3']:
                        # mux only video and ac3 stream
                        map = ['-map', '0:v', '-map', ac3_stream]
                    else:
                        map = ['-map', '0']

                args = [
                    ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0",
                    "-i", mkvpass_file, "-vcodec", "copy", '-af',
                    'volume=volume=' + str(vol), "-vsync", "1", '-async',
                    '1000', "-dts_delta_threshold", "100", "-vf",
                    "fps=" + str(fps), ffmpegpass_file
                ]
                map.extend(audiocodec)
                args[8:8] = map

                try:
                    p = subprocess.Popen(args,
                                         stderr=subprocess.PIPE,
                                         universal_newlines=True)
                except OSError:
                    self.errors[
                        filename] = "FFMPEG (intern) wurde nicht gefunden!"
                    if os.path.exists(
                            mkvpass_file) and filename != mkvpass_file:
                        fileoperations.remove_file(mkvpass_file)
                    continue

                yield 4, 0
                line = ""
                infos_match = re.compile(r"frame=\ {0,1}(\d{1,})")

                while p.poll() == None:
                    line = p.stderr.readline()
                    m = re.search(infos_match, line)
                    if m and max_frames != 0:
                        next = float(
                            float(m.group(1)) / float(max_frames)) * 100
                        if next > self.progress:
                            self.progress = next
                            yield 4, self.progress
                    else:
                        pass

                exit_code = p.poll()
                if os.path.exists(mkvpass_file) and filename != mkvpass_file:
                    fileoperations.remove_file(mkvpass_file)

                if exit_code == 0:
                    if self.Config['DumpAVIs']:
                        yield 3, self.success
                        new_filename = os.path.join(
                            self.app.config.get('general',
                                                'folder_trash_avis'),
                            os.path.basename(filename))
                        if os.path.exists(new_filename):
                            fileoperations.remove_file(new_filename)
                        fileoperations.move_file(
                            filename,
                            self.app.config.get('general',
                                                'folder_trash_avis'))
                else:
                    self.errors[
                        filename] = "Fehler beim Erzeugen der MP4 Datei durch FFMPEG"
                    if os.path.exists(ffmpegpass_file):
                        fileoperations.remove_file(ffmpegpass_file)
                    continue

                # mp4box - last turn
                self.progress = 0
                mp4boxpass_file = fileoperations.make_unique_filename(
                    os.path.splitext(filename)[0] + ".mp4")

                if self.Config['DontOptimizeMP4']:
                    os.rename(ffmpegpass_file, mp4boxpass_file)
                    self.success += 1
                    continue

                yield 2, count
                try:
                    p = subprocess.Popen([
                        self.app.config.get_program('mp4box'), "-keep-all",
                        "-new", "-packed", "-fps",
                        str(fps), "-add", ffmpegpass_file, mp4boxpass_file
                    ],
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.STDOUT)
                except OSError:
                    self.errors[
                        filename] = "MP4Box (intern) wurde nicht gefunden!"
                    if os.path.exists(ffmpegpass_file):
                        fileoperations.remove_file(ffmpegpass_file)
                    continue

                yield 4, 0
                infos_match = re.compile(r".*\((\d{2,})\/\d{2,}\).*")

                while p.poll() == None:
                    line = p.stdout.read(60)
                    line = line.decode('utf-8')
                    m = re.search(infos_match, line)
                    if m:
                        self.progress = int(m.group(1))
                        yield 4, self.progress

                        if 'Importing' in line:
                            yield 2, count
                        elif 'Writing' in line:
                            yield 6, count
                    else:
                        pass

                exit_code = p.poll()
                if os.path.exists(ffmpegpass_file):
                    fileoperations.remove_file(ffmpegpass_file)

                if exit_code == 0:
                    self.success += 1
                else:
                    self.errors[
                        filename] = "Fehler beim Erzeugen der MP4 Datei durch MP4Box"
    def cut_file_by_cutlist(self,
                            filename,
                            cutlist=None,
                            program_config_value=None):
        """ Cuts a otr file with x264 and mkvmerge frame accurate. 
            returns: name of cut video, error_message """
        # configuration
        videolist = []  # result list for smart rendering simulation
        audio_import_files = [
            filename
        ]  # otr files which have audio streams  and needs to be cutted (e.g. OTR avi and ac3)
        process_list = []  # list of started processes
        mkvmerge_list = []  # list of started mkvmerge processes
        video_splitframes = ''  # mkvmerge split string for cutting the video at keyframes
        audio_timecodes = ''  # mkvmerge split timecodes for cutting the audio
        ac3_file = None  # AC3 source file
        warning_msg = None
        mkvmerge = self.config.get_program('mkvmerge')
        x264 = self.config.get_program('x264')
        ffmpeg = self.config.get_program('ffmpeg')
        encoder_engine = self.config.get('smartmkvmerge', 'encoder_engine')
        # env
        my_env = os.environ.copy()
        my_env["LANG"] = "C"
        my_env["LC_COLLATE"] = "C"
        my_env["LC_ALL"] = "C"

        # analyse file
        fps, dar, sar, max_frames, ac3_stream, error = self.analyse_mediafile(
            filename)
        if error:
            return None, "Konnte FPS nicht bestimmen: " + error

        # codec configuration string
        format, ac3_file, bframe_delay = self.get_format(filename)
        if format == Format.HQ:
            if encoder_engine == 'x264':
                codec, codec_core = self.complete_x264_opts(
                    self.config.get('smartmkvmerge',
                                    'x264_hq_string').split(' '), filename)
            elif encoder_engine == 'ffmpeg':
                codec, codec_core = self.__ffmpeg_codec_options(
                    self.config.get('smartmkvmerge',
                                    'ffmpeg_hq_x264_options').split(' '),
                    filename)
        elif format == Format.HD:
            if encoder_engine == 'x264':
                codec, codec_core = self.complete_x264_opts(
                    self.config.get('smartmkvmerge',
                                    'x264_hd_string').split(' '), filename)
            elif encoder_engine == 'ffmpeg':
                codec, codec_core = self.__ffmpeg_codec_options(
                    self.config.get('smartmkvmerge',
                                    'ffmpeg_hd_x264_options').split(' '),
                    filename)
        elif format == Format.MP4:
            if encoder_engine == 'x264':
                codec, codec_core = self.complete_x264_opts(
                    self.config.get('smartmkvmerge',
                                    'x264_mp4_string').split(' '), filename)
            elif encoder_engine == 'ffmpeg':
                codec, codec_core = self.__ffmpeg_codec_options(
                    self.config.get('smartmkvmerge',
                                    'ffmpeg_mp4_x264_options').split(' '),
                    filename)
        elif format == Format.AVI:
            encoder_engine = 'ffmpeg'
            codec = self.config.get('smartmkvmerge',
                                    'ffmpeg_avi_mpeg4_options').split(' ')
            codec_core = 125
        else:
            return None, "Format nicht unterstützt (Nur MP4 H264, HQ H264 und HD H264 sind möglich)."

        self.log.debug("Codec: {}".format(codec))

        if codec_core != 125:
            warning_msg = "Unbekannte Kodierung entdeckt. Diese Datei genau prüfen und notfalls mit intern-Virtualdub und Codec ffdshow schneiden."
            return None, warning_msg

        # test workingdir
        if os.access(
                self.config.get('smartmkvmerge', 'workingdir').rstrip('/'),
                os.W_OK):
            self.workingdir = os.path.abspath(
                self.config.get('smartmkvmerge', 'workingdir')).rstrip('/')
        else:
            return None, "Ungültiges Temp Verzeichnis. Schreiben nicht möglich."

        # threads
        flag_singlethread = self.config.get('smartmkvmerge', 'single_threaded')

        if self.config.get('smartmkvmerge', 'single_threaded_automatic'):
            try:
                memory = self.meminfo()
                if self.available_cpu_count() > 1 and memory['MemFree'] > (
                        os.stat(filename).st_size / 1024):
                    flag_singlethread = True
                else:
                    flag_singlethread = False
            except Exception as e:
                flag_singlethread = self.config.get('smartmkvmerge',
                                                    'single_threaded')

        self.log.debug("flag_singlethread: {}".format(flag_singlethread))

        # audio part 1 - cut audio
        if ac3_file:
            audio_import_files.append(ac3_file)

        audio_timecodes = (',+'.join([
            self.get_timecode(start) + '-' +
            self.get_timecode(start + duration)
            for start, duration in cutlist.cuts_seconds
        ]))
        audio_timecodes = audio_timecodes.lstrip(',+')

        command = [
            mkvmerge, '--ui-language', 'en_US', '-D', '--split', 'parts:' +
            audio_timecodes, '-o', self.workingdir + '/audio_copy.mkv'
        ] + audio_import_files
        self.log.debug("Command: {}".format(command))
        try:
            blocking_process = subprocess.Popen(command,
                                                stdout=subprocess.PIPE,
                                                stderr=subprocess.STDOUT,
                                                universal_newlines=True,
                                                env=my_env)
        except OSError as e:
            return None, e.strerror + ": " + mkvmerge
        mkvmerge_list.append(blocking_process)
        if flag_singlethread:
            self.show_progress(blocking_process)

        # video part 1 - read keyframes
        keyframes, error = self.get_keyframes_from_file(filename)
        if keyframes == None:
            return None, "Keyframes konnten nicht ausgelesen werden."
        # self.log.debug(keyframes)

        # video part 2 - simulate smart rendering process
        for frame_start, frames_duration in cutlist.cuts_frames:
            result = self.__simulate_smart_mkvmerge(int(frame_start),
                                                    int(frames_duration),
                                                    keyframes)
            if result != None:
                videolist += result
            else:
                return None, 'Cutlist oder zu schneidende Datei passen nicht zusammen oder sind fehlerhaft.'
        self.log.debug("Videolist: {}".format(videolist))

        # video part 3 - encode small parts - smart rendering part (1/2)
        for encode, start, duration, video_part_filename in videolist:
            self.video_files.append('+' + self.workingdir + '/' +
                                    video_part_filename)
            if encoder_engine == 'x264':
                command = [x264] + codec + [
                    '--demuxer', 'ffms', '--index',
                    self.workingdir + '/x264.index', '--seek',
                    str(start), '--frames',
                    str(duration), '--output',
                    self.workingdir + '/' + video_part_filename, filename
                ]
            elif encoder_engine == 'ffmpeg':
                command = [
                    ffmpeg, '-ss',
                    str(self.get_timecode((start + bframe_delay) / fps)), '-i',
                    filename, '-vframes',
                    str(duration), '-vf', 'setsar=' + str(sar), '-threads',
                    '0', '-an', '-sn', '-dn', '-y',
                    self.workingdir + '/' + video_part_filename
                ]
                command[5:5] = codec
            else:
                return None, "Keine unterstützte Render-Engine zum Kodieren eingestellt"
            self.log.debug("Command: {}".format(command))
            if encode:
                try:
                    non_blocking_process = subprocess.Popen(
                        command,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                        universal_newlines=True)
                except OSError as e:
                    return None, e.strerror + ": " + 'Render Engine nicht vorhanden'
                process_list.append(non_blocking_process)
                if flag_singlethread:
                    self.show_progress(non_blocking_process)
            else:
                video_splitframes += ',' + str(start) + '-' + str(duration)

        self.video_files[0] = self.video_files[0].lstrip('+')
        video_splitframes = video_splitframes.lstrip(',')

        # video part 4 - cut the big parts out the file (keyframe accurate) - smart rendering part (2/2)
        command = [
            mkvmerge, '--ui-language', 'en_US', '-A', '--split',
            'parts-frames:' + video_splitframes, '-o',
            self.workingdir + '/video_copy.mkv', filename
        ]
        self.log.debug("Command: {}".format(command))
        try:
            non_blocking_process = subprocess.Popen(command,
                                                    stdout=subprocess.PIPE,
                                                    stderr=subprocess.STDOUT,
                                                    universal_newlines=True,
                                                    env=my_env)
        except OSError as e:
            return None, e.strerror + ": " + mkvmerge
        mkvmerge_list.append(non_blocking_process)
        if flag_singlethread:
            self.show_progress(non_blocking_process)

        # audio part 2 - encode audio to AAC
        if 'MP3 Spur kopieren' in self.config.get(
                'smartmkvmerge', 'first_audio_stream'
        ) and 'AC3 Spur kopieren' in self.config.get('smartmkvmerge',
                                                     'second_audio_stream'):
            self.audio_files.append(self.workingdir + '/audio_copy.mkv')
        else:
            self.show_progress(blocking_process)
            blocking_process.wait()
            ffmpeginput_file = self.workingdir + '/audio_copy.mkv'
            ffmpegoutput_file = self.workingdir + '/audio_encode.mkv'

            audiofilter = []
            # convert first audio stream to aac
            if 'AAC' in self.config.get(
                    'smartmkvmerge',
                    'first_audio_stream') and 'AAC' in self.config.get(
                        'smartmkvmerge', 'second_audio_stream'):
                aacaudiostreams = '-c:a'
                if self.config.get('smartmkvmerge', 'normalize_audio'):
                    vol0, error = self.get_norm_volume(ffmpeginput_file, '0')
                    vol1, error = self.get_norm_volume(ffmpeginput_file, '1')
                    audiofilter = [
                        '-af:0', 'volume=volume=' + vol0, '-af:1',
                        'volume=volume=' + vol1
                    ]
            elif 'AAC' in self.config.get(
                    'smartmkvmerge',
                    'second_audio_stream') and 'MP3' in self.config.get(
                        'smartmkvmerge', 'first_audio_stream'):
                aacaudiostreams = '-c:a:1'
                if self.config.get('smartmkvmerge', 'normalize_audio'):
                    vol, error = self.get_norm_volume(ffmpeginput_file, '1')
                    audiofilter = ['-af:1', 'volume=volume=' + vol]
            elif 'AAC' in self.config.get('smartmkvmerge',
                                          'first_audio_stream'):
                aacaudiostreams = '-c:a:0'
                if self.config.get('smartmkvmerge', 'normalize_audio'):
                    vol, error = self.get_norm_volume(ffmpeginput_file, '0')
                    audiofilter = ['-af:0', 'volume=volume=' + vol]
            else:
                aacaudiostreams = '-c:a:2'

            if 'nonfree' in ffmpeg:
                # nonfree ffmpeg version with fdk support available
                audiocodec = [
                    '-c:a', 'copy', aacaudiostreams, 'libfdk_aac', '-flags',
                    '+qscale', '-profile:a', 'aac_low', '-global_quality', '5',
                    '-afterburner', '1'
                ]
            else:
                # only gpl version of ffmpeg available -> use standard aac codec
                audiocodec = [
                    '-c:a', 'copy', aacaudiostreams, 'aac', '-strict', '-2',
                    '-profile:a', 'aac_low', '-ab', '192k', '-cutoff', '18000'
                ]

            if '2-Kanal' in self.config.get('smartmkvmerge',
                                            'first_audio_stream'):
                audiocodec.extend(['-ac:0', '2'])

            if ac3_file == None:
                # no ac3 stream found - all streams are muxed
                map = ['-map', '0']
            else:
                if 'AC3' in self.config.get('smartmkvmerge',
                                            'first_audio_stream'):
                    map = ['-map', '0:a:1']
                else:
                    map = ['-map', '0:a:0']
                if not 'AC3 Spur entfernen' in self.config.get(
                        'smartmkvmerge', 'second_audio_stream'):
                    map.extend(['-map', '0:a:1'])

            args = [
                ffmpeg, "-loglevel", "info", "-y", "-drc_scale", "1.0", "-i",
                ffmpeginput_file, "-vn", "-vsync", "1", '-async', '200000',
                "-dts_delta_threshold", "100", '-threads', '0',
                ffmpegoutput_file
            ]
            map.extend(audiocodec)
            map.extend(audiofilter)
            args[8:8] = map
            self.log.debug("Args: {}".format(args))
            try:
                non_blocking_process = subprocess.Popen(
                    args,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.STDOUT,
                    universal_newlines=True)
            except OSError as e:
                return None, e.strerror + ": " + ffmpeg
            process_list.append(non_blocking_process)
            self.audio_files.append(self.workingdir + '/audio_encode.mkv')
            if flag_singlethread:
                self.show_progress(non_blocking_process)

        # wait until all threads are terminated
        for blocking_process in mkvmerge_list + process_list:
            self.show_progress(blocking_process)

        # check all processes
        for blocking_process in mkvmerge_list:
            returncode = blocking_process.wait()
            if returncode != 0 and returncode != 1:
                return None, 'beim Schneiden der Originaldatei...'
        for blocking_process in process_list:
            returncode = blocking_process.wait()
            if returncode != 0:
                return None, 'beim Kodieren ...'

        # clean up
        if os.path.isfile(self.workingdir + '/video_copy.mkv'):
            os.rename(self.workingdir + '/video_copy.mkv',
                      self.workingdir + '/video_copy-001.mkv')
        if 'ffmpeginput_file' in vars():
            if os.path.isfile(ffmpeginput_file):
                os.remove(ffmpeginput_file)

        # mux all together
        if self.config.get('smartmkvmerge', 'remux_to_mp4'):
            cut_video = self.workingdir + '/' + os.path.basename(
                os.path.splitext(self.generate_filename((filename), 1))[0] +
                ".mkv")
        else:
            cut_video = os.path.splitext(self.generate_filename(filename,
                                                                1))[0] + ".mkv"
        command = [
            mkvmerge, '--engage', 'no_cue_duration', '--engage',
            'no_cue_relative_position', '--ui-language', 'en_US', '-o',
            cut_video
        ] + self.video_files + self.audio_files
        self.log.debug("Command: {}".format(command))
        try:
            blocking_process = subprocess.Popen(command,
                                                stdout=subprocess.PIPE,
                                                stderr=subprocess.STDOUT,
                                                universal_newlines=True,
                                                env=my_env)
        except OSError:
            return None, "MKVMerge konnte nicht aufgerufen werden oder zu alt (6.5.0 benötigt)"
        self.show_progress(blocking_process)

        returncode = blocking_process.wait()
        if returncode != 0 and returncode != 1:
            return None, 'beim Schreiben des geschnittenen MKVs...'

        # remove all temporary files
        for n in self.video_files + self.audio_files:
            if os.path.isfile(n.lstrip('+')):
                os.remove(n.lstrip('+'))

        # mux to mp4
        if self.config.get('smartmkvmerge', 'remux_to_mp4'):
            # split files with eac3to
            with ChangeDir(self.workingdir):
                command = [
                    'wine',
                    path.get_tools_path('intern-eac3to/eac3to.exe'),
                    os.path.basename(cut_video), '-demux', '-silence',
                    '-keepDialnorm'
                ]
                self.log.debug("Command: {}".format(command))
                try:
                    blocking_process = subprocess.Popen(
                        command,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                        universal_newlines=True)
                except OSError:
                    return None, 'Eac3to konnte nicht aufgerufen werden'

                file_match = re.compile(r".*\"(.* - (\d{1,}) - .*)\".*")
                self.gui.main_window.set_tasks_text('Extrahiere Streams')
                self.gui.main_window.set_tasks_progress(50)
                while Gtk.events_pending():
                    Gtk.main_iteration()

                while blocking_process.poll() == None:
                    line = blocking_process.stdout.readline().strip()
                    if 'Creating file' in line:
                        m = re.search(file_match, line)
                        if m:
                            self.rawstreams[m.group(2)] = m.group(1).decode(
                                "iso-8859-1").encode("utf-8")
                        else:
                            pass

                returncode = blocking_process.wait()
                if returncode != 0:
                    if os.path.isfile(cut_video):
                        os.remove(cut_video)
                    return None, 'Fehler beim Extrahieren der Streams mit Eac3to'

                # remove mkv + log file
                if os.path.isfile(cut_video):
                    os.remove(cut_video)
                if os.path.isfile(
                        os.path.splitext(cut_video)[0] + ' - Log.txt'):
                    os.remove(os.path.splitext(cut_video)[0] + ' - Log.txt')

                args = [
                    self.config.get_program('mp4box'), '-new', '-keep-all',
                    '-isma', '-inter', '500'
                ]

                for index in sorted(self.rawstreams.keys()):
                    args.append('-add')
                    if '.dx50' in self.rawstreams[index]:
                        (root_dx50,
                         dx50) = os.path.splitext(self.rawstreams[index])
                        os.rename(self.rawstreams[index], root_dx50 + '.m4v')
                        self.rawstreams[index] = root_dx50 + '.m4v'
                    args.append(self.rawstreams[index])

                cut_video = os.path.splitext(
                    self.generate_filename(filename, 1))[0] + ".mp4"
                args.append(cut_video)

                # mux to mp4 (mp4box)
                self.log.debug("Args: {}".format(args))
                try:
                    blocking_process = subprocess.Popen(
                        args,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT,
                        universal_newlines=True)
                except OSError:
                    return None, 'MP4Box konnte nicht aufgerufen werden'

                self.gui.main_window.set_tasks_text('Muxe MP4')
                self.show_progress(blocking_process)
                returncode = blocking_process.wait()
                if returncode != 0:
                    return None, 'Fehler beim Erstellen der MP4'

        return cut_video, warning_msg