def _copy(self, src, dst, overwrite=False): if self.dry_run: print('Copy: {}=>{}'.format(src, dst)) else: if not overwrite and check_exists(dst, log=self.dry_run): return False create_dirs(dst) shutil.copy(src, dst) return True
def cut(input, output, start=None, end=None): if check_exists(output): return -1 create_dirs(output) args = [ffmpeg(), '-i', input] args.extend(['-c:v', 'copy']) args.extend(['-c:a', 'copy']) args.extend(['-c:s', 'copy']) args.extend(['-map', '0']) if start: args.extend(['-ss', str(start)]) if end: args.extend(['-to', str(end)]) args.append(output) return execute(args)
def combine(video, srt, output, lang=None, overwrite=False, convert=False, crf=DEFAULT_CRF, preset=DEFAULT_PRESET, skip_eia_608=True): if not overwrite and check_exists(output): return -1 if srt.endswith('.ttml') or srt.endswith('.xml'): logger.debug('Converting ttml/xml to srt') name, _ = os.path.splitext(srt) srt_out = name + '.srt' convert_to_srt(srt, srt_out) srt = srt_out create_dirs(output) args = [ffmpeg(), '-i', video] if overwrite: args.append('-y') args.extend(['-i', srt]) args.extend(['-map', '0:v', '-map', '0:a']) if skip_eia_608: metadata = extract_metadata(video) for i in (s.index for s in metadata.subtitle_streams if s.codec != 'eia_608'): args.extend(['-map', '0:{}'.format(i)]) else: args.extend(['-map', '0:s?']) args.extend(['-map', '1:0']) if convert: args.extend(['-c:v', 'libx264', '-crf', str(crf), '-preset', preset]) args.extend(['-c:a', 'aac']) else: args.extend(['-c:v', 'copy']) args.extend(['-c:a', 'copy']) args.extend(['-c:s', 'copy']) # -metadata:s:s:0 language=eng if lang: args.extend(['-metadata:s:s:0', 'language=' + lang]) args.append(output) return execute(args)
def create_remux_args(input_files: List[str], output_file: str, mappings: List, overwrite=False, metadata={}): """ :param input_files: :param output_file: :param mappings: :param overwrite: :param metadata: {'s:0': {'language':'eng'}, '': {'title': 'A Great Movie'}} :return: """ if not overwrite and check_exists(output_file): return -1 args = [ffmpeg()] if overwrite: args.append('-y') for input_file in input_files: args.extend(['-i', input_file]) args.extend(['-c', 'copy']) for m in mappings: if type(m) == int: args.extend(['-map', '0:{}'.format(m)]) else: args.extend(['-map', m]) for key, value in metadata.items(): if key: key = ':s:' + key for meta_key, meta_val in value.items(): args.append('-metadata{}'.format(key)) args.append('{}={}'.format(meta_key, meta_val)) args.append(output_file) return args
def convert_with_config(input, output, config: ConvertConfig, print_output=True, overwrite=False, metadata=None, mappings=None, use_nice=True): """ :param input: :param output: :param config: :param print_output: :param overwrite: :param metadata: :param mappings: List of mappings (for example ['0:0', '0:1']) :return: """ if not overwrite and check_exists(output): return -1 if print_output: print('Converting {} -> {}'.format(input, output)) print('Using config: {}'.format(config)) if not metadata: metadata = create_metadata_extractor().extract( input, detect_interlace=config.deinterlace) elif config.deinterlace and not metadata.interlace_report: raise Exception( 'Metadata provided without interlace report, but convert requires deinterlace checks' ) if metadata.resolution not in (Resolution.LOW_DEF, Resolution.STANDARD_DEF, Resolution.MEDIUM_DEF, Resolution.HIGH_DEF) and not config.scale: print('{}: Resolution not supported for conversion: {}'.format( input, metadata.resolution)) # TODO Handle converting 4k content in H.265/HVEC return -2 if use_nice and nice_exe: args = [nice_exe, ffmpeg()] else: args = [ffmpeg()] if overwrite: args.append('-y') args.extend(['-i', input]) if config.scale: args.extend(['-vf', 'scale=-1:{}'.format(config.scale)]) args.extend(['-c:v', config.video_codec]) crf = config.crf bitrate = config.bitrate if VideoCodec.H264.equals( config.video_codec ) and config.bitrate is not None and config.bitrate != 'disabled': crf = 1 # -x264-params vbv-maxrate=1666:vbv-bufsize=3332:crf-max=22:qpmax=34 if config.bitrate == 'auto': bitrate = auto_bitrate_from_config(metadata.resolution, config) params = 'vbv-maxrate={}:vbv-bufsize={}:crf-max=25:qpmax=34'.format( str(bitrate), str(bitrate * 2)) args.extend(['-x264-params', params]) elif VideoCodec.H265.equals( config.video_codec ) and config.bitrate is not None and config.bitrate != 'disabled': raise Exception('Avg Bitrate not supported for H265') args.extend(['-crf', str(crf), '-preset', config.preset]) if config.deinterlace: is_interlaced = metadata.interlace_report.is_interlaced( config.deinterlace_threshold) if print_output: print('{} - Interlaced: {}'.format(metadata.interlace_report, is_interlaced)) if is_interlaced: # Video is interlaced, so add the deinterlace filter args.extend(['-vf', 'yadif']) args.extend(['-c:a', config.audio_codec]) index = 0 for audio in metadata.audio_streams: if audio.channels == 7: # 6.1 sound, so mix it up to 7.1 args.extend(['-ac:a:{}'.format(index), '8']) index += 1 if config.include_subtitles: args.extend(['-c:s', 'copy']) if not mappings: args.extend(['-map', '0']) else: for m in mappings: if type(m) == int: args.extend(['-map', '0:{}'.format(m)]) else: args.extend(['-map', m]) if config.include_meta: args.extend(['-metadata', 'ripped=true']) args.extend(['-metadata:s:v:0', 'ripped=true']) args.append(output) return execute(args, print_output)