def build(fastflix: FastFlix): settings: x264Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libx264") beginning += f'{f"-tune:v {settings.tune}" if settings.tune else ""} {generate_color_details(fastflix)} ' if settings.profile and settings.profile != "default": beginning += f"-profile:v {settings.profile} " pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" if settings.bitrate: command_1 = ( f"{beginning} -pass 1 " f'-passlogfile "{pass_log_file}" -b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra if settings.extra_both_passes else ""} -an -sn -dn -f mp4 {null}' ) command_2 = ( f'{beginning} -pass 2 -passlogfile "{pass_log_file}" ' f"-b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} " ) + ending return [ Command(command=command_1, name="First pass bitrate", exe="ffmpeg"), Command(command=command_2, name="Second pass bitrate", exe="ffmpeg"), ] elif settings.crf: command = f"{beginning} -crf:v {settings.crf} " f"-preset:v {settings.preset} {settings.extra} {ending}" return [Command(command=command, name="Single pass CRF", exe="ffmpeg")] else: return []
def build(fastflix: FastFlix): settings: AOMAV1Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libaom-av1") beginning += ("-strict experimental " f"-cpu-used {settings.cpu_used} " f"-tile-rows {settings.tile_rows} " f"-tile-columns {settings.tile_columns} " f"-usage {settings.usage} " f"{generate_color_details(fastflix)} ") if settings.row_mt.lower() == "enabled": beginning += f"-row-mt 1 " if settings.bitrate: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" command_1 = f'{beginning} -passlogfile "{pass_log_file}" -b:v {settings.bitrate} -pass 1 {settings.extra if settings.extra_both_passes else ""} -an -f matroska {null}' command_2 = ( f'{beginning} -passlogfile "{pass_log_file}" -b:v {settings.bitrate} -pass 2 {settings.extra} {ending}' ) return [ Command(command=command_1, name="First Pass bitrate"), Command(command=command_2, name="Second Pass bitrate"), ] elif settings.crf: command_1 = f"{beginning} -b:v 0 -crf {settings.crf} {settings.extra} {ending}" return [Command(command=command_1, name="Single Pass CRF")]
def build(fastflix: FastFlix): settings: FFmpegNVENCSettings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "hevc_nvenc") beginning += f'{f"-tune:v {settings.tune}" if settings.tune else ""} {generate_color_details(fastflix)} -spatial_aq:v {settings.spatial_aq} -tier:v {settings.tier} -rc-lookahead:v {settings.rc_lookahead} -gpu {settings.gpu} -b_ref_mode {settings.b_ref_mode} ' if settings.profile: beginning += f"-profile:v {settings.profile} " if settings.rc: beginning += f"-rc:v {settings.rc} " if settings.level: beginning += f"-level:v {settings.level} " pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" command_1 = ( f"{beginning} -pass 1 " f'-passlogfile "{pass_log_file}" -b:v {settings.bitrate} -preset:v {settings.preset} -2pass 1 ' f'{settings.extra if settings.extra_both_passes else ""} -an -sn -dn -f mp4 {null}' ) command_2 = ( f'{beginning} -pass 2 -passlogfile "{pass_log_file}" -2pass 1 ' f"-b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} " ) + ending return [ Command(command=command_1, name="First pass bitrate", exe="ffmpeg"), Command(command=command_2, name="Second pass bitrate", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: AOMAV1Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libaom-av1") beginning += ("-strict experimental " f"-cpu-used {settings.cpu_used} " f"-tile-rows {settings.tile_rows} " f"-tile-columns {settings.tile_columns} " f"-usage {settings.usage} " f"{generate_color_details(fastflix)} ") if settings.row_mt.lower() == "enabled": beginning += f"-row-mt 1 " beginning = re.sub("[ ]+", " ", beginning) if settings.bitrate: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}.log" command_1 = f'{beginning} -passlogfile "{pass_log_file}" -b:v {settings.bitrate} -pass 1 -an -f matroska {null}' command_2 = f'{beginning} -passlogfile "{pass_log_file}" -b:v {settings.bitrate} -pass 2' + ending return [ Command(command_1, ["ffmpeg", "output"], False, name="First Pass bitrate"), Command(command_2, ["ffmpeg", "output"], False, name="Second Pass bitrate"), ] elif settings.crf: command_1 = f"{beginning} -b:v 0 -crf {settings.crf}" + ending return [ Command(command_1, ["ffmpeg", "output"], False, name="Single Pass CRF") ]
def build(fastflix: FastFlix): settings: rav1eSettings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "librav1e") beginning += ("-strict experimental " f"-speed {settings.speed} " f"-tile-columns {settings.tile_columns} " f"-tile-rows {settings.tile_rows} " f"-tiles {settings.tiles} " f"{generate_color_details(fastflix)} ") # if not fastflix.current_video.video_settings.remove_hdr: # Currently unsupported https://github.com/xiph/rav1e/issues/2554 # rav1e_options = [] # if side_data.master_display: # rav1e_options.append( # "mastering-display=" # f"G{side_data.master_display.green}" # f"B{side_data.master_display.blue}" # f"R{side_data.master_display.red}" # f"WP{side_data.master_display.white}" # f"L{side_data.master_display.luminance}" # ) # # if side_data.cll: # rav1e_options.append(f"content-light={side_data.cll}") # if rav1e_options: # opts = ":".join(rav1e_options) # beginning += f'-rav1e-params "{opts}"' beginning = re.sub("[ ]+", " ", beginning) if not settings.single_pass: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" beginning += f'-passlogfile "{pass_log_file}" ' pass_type = "bitrate" if settings.bitrate else "QP" if not settings.bitrate: command_1 = f"{beginning} -qp {settings.qp} {settings.extra} {ending}" return [Command(command=command_1, name=f"{pass_type}", exe="ffmpeg")] if settings.single_pass: command_1 = f"{beginning} -b:v {settings.bitrate} {settings.extra} {ending}" return [Command(command=command_1, name=f"{pass_type}", exe="ffmpeg")] else: command_1 = f"{beginning} -b:v {settings.bitrate} -pass 1 {settings.extra if settings.extra_both_passes else ''} -an -f matroska {null}" command_2 = f"{beginning} -b:v {settings.bitrate} -pass 2 {settings.extra} {ending}" return [ Command(command=command_1, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command=command_2, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: VP9Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libvpx-vp9") beginning += f'{"-row-mt 1" if settings.row_mt else ""} ' f"{generate_color_details(fastflix)} " if not settings.single_pass: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" beginning += f'-passlogfile "{pass_log_file}" ' # TODO color_range 1 # if not fastflix.current_video.video_settings.remove_hdr and settings.pix_fmt in ("yuv420p10le", "yuv420p12le"): # if fastflix.current_video.color_space.startswith("bt2020"): # beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc -color_range 1" details = f"-quality:v {settings.quality} -profile:v {settings.profile} -tile-columns:v {settings.tile_columns} -tile-rows:v {settings.tile_rows} " if settings.bitrate: if settings.quality == "realtime": return [ Command( command= f"{beginning} -speed:v {settings.speed} -b:v {settings.bitrate} {details} {settings.extra} {ending} ", name="Single pass realtime bitrate", exe="ffmpeg", ) ] command_1 = f"{beginning} -speed:v {'4' if settings.fast_first_pass else settings.speed} -b:v {settings.bitrate} {details} -pass 1 {settings.extra if settings.extra_both_passes else ''} -an -f webm {null}" command_2 = ( f"{beginning} -speed:v {settings.speed} -b:v {settings.bitrate} {details} -pass 2 {settings.extra} {ending}" ) elif settings.crf: command_1 = f"{beginning} -b:v 0 -crf:v {settings.crf} {details} -pass 1 {settings.extra if settings.extra_both_passes else ''} -an -f webm {null}" command_2 = ( f"{beginning} -b:v 0 -crf:v {settings.crf} {details} " f'{"-pass 2" if not settings.single_pass else ""} {settings.extra} {ending}' ) else: return [] if settings.crf and settings.single_pass: return [ Command(command=command_2, name="Single pass CRF", exe="ffmpeg") ] pass_type = "bitrate" if settings.bitrate else "CRF" return [ Command(command=command_1, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command=command_2, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: SVTAV1Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libsvtav1") beginning += (f"-strict experimental " f"-preset {settings.speed} " f"-tile_columns {settings.tile_columns} " f"-tile_rows {settings.tile_rows} " f"-tier {settings.tier} " f"{generate_color_details(fastflix)} ") beginning = re.sub("[ ]+", " ", beginning) if not settings.single_pass: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}.log" beginning += f'-passlogfile "{pass_log_file}" ' pass_type = "bitrate" if settings.bitrate else "QP" if settings.single_pass: if settings.bitrate: command_1 = f"{beginning} -b:v {settings.bitrate} -rc 1" + ending elif settings.qp is not None: command_1 = f"{beginning} -qp {settings.qp} -rc 0" + ending else: return [] return [ Command(command_1, ["ffmpeg", "output"], False, name=f"{pass_type}", exe="ffmpeg") ] else: if settings.bitrate: command_1 = f"{beginning} -b:v {settings.bitrate} -rc 1 -pass 1 -an -f matroska {null}" command_2 = f"{beginning} -b:v {settings.bitrate} -rc 1 -pass 2" + ending elif settings.qp is not None: command_1 = f"{beginning} -qp {settings.qp} -rc 0 -pass 1 -an -f matroska {null}" command_2 = f"{beginning} -qp {settings.qp} -rc 0 -pass 2" + ending else: return [] return [ Command(command_1, ["ffmpeg", "output"], False, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command_2, ["ffmpeg", "output"], False, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build( source, video_track, ffmpeg, temp_dir, output_video, fps=15, dither="sierra2_4a", extra="", start_time=0, end_time=None, **kwargs, ): palletgen_filters = generate_filters(video_track=video_track, custom_filters="palettegen", **kwargs) filters = generate_filters(video_track=video_track, custom_filters=f"fps={fps:.2f}", raw_filters=True, **kwargs) output_video = output_video.replace("\\", "/") beginning = (f'"{ffmpeg}" -y ' f'{f"-ss {start_time}" if start_time else ""} ' f'{f"-to {end_time}" if end_time else ""} ' f'-i "{source}" ') if extra: beginning += f" {extra} " temp_palette = Path(temp_dir) / f"temp_palette_{secrets.token_hex(10)}.png" command_1 = f'{beginning} {palletgen_filters} -y "{temp_palette}"' gif_filters = f"fps={fps:.2f}" if filters: gif_filters += f",{filters}" command_2 = ( f'{beginning} -i "{temp_palette}" ' f'-filter_complex "{filters};[v][1:v]paletteuse=dither={dither}[o]" -map "[o]" -y "{output_video}" ' ) return [ Command(command_1, ["ffmpeg", "pallet_file", "output"], False, name="Pallet generation", exe="ffmpeg"), Command(command_2, ["ffmpeg", "pallet_file", "output"], False, name="GIF creation", exe="ffmpeg"), ]
def build( source, video_track, ffmpeg, temp_dir, output_video, fps=15, dither="sierra2_4a", extra="", start_time=0, end_time=None, **kwargs, ): filters = generate_filters(**kwargs) beginning = (f'"{ffmpeg}" -y ' f'{f"-ss {start_time}" if start_time else ""} ' f'{f"-to {end_time}" if end_time else ""} ' f'-i "{source}" ') if extra: beginning += f" {extra} " temp_palette = Path(temp_dir) / f"temp_palette_{secrets.token_hex(10)}.png" command_1 = ( f"{beginning} -map 0:{video_track} " f'-vf "{f"{filters}," if filters else ""}palettegen" -y "{temp_palette}"' ) gif_filters = f"fps={fps:.2f}" if filters: gif_filters += f",{filters}" command_2 = ( f'{beginning} -i "{temp_palette}" -map 0:{video_track} ' f'-lavfi "{gif_filters} [x]; [x][1:v] paletteuse=dither={dither}" -y "{output_video}" ' ) return [ Command(command_1, ["ffmpeg", "pallet_file", "output"], False, name="Pallet generation", exe="ffmpeg"), Command(command_2, ["ffmpeg", "pallet_file", "output"], False, name="GIF creation", exe="ffmpeg"), ]
def build( source, video_track, ffmpeg, temp_dir, output_video, lossless=True, compression=6, extra="", preset="default", start_time=0, qscale="75", **kwargs, ): filters = generate_filters(video_track=video_track, **kwargs) beginning = generate_ffmpeg_start(source, ffmpeg, encoder="libwebp", video_track=video_track, start_time=start_time, filters=filters, **kwargs) ending = generate_ending("", "", "", output_video=output_video, **kwargs) return [ Command( f"{beginning} -lossless {lossless} -compression_level {compression} " f"-qscale {qscale} -preset {preset} {extra} {ending}", ["ffmpeg", "output"], False, name="WebP", exe="ffmpeg", ), ]
def build(fastflix: FastFlix): settings: GIFSettings = fastflix.current_video.video_settings.video_encoder_settings args = f"=stats_mode={settings.stats_mode}" if settings.max_colors != "256": args += f":max_colors={settings.max_colors}" palletgen_filters = generate_filters( custom_filters=f"palettegen{args}", **fastflix.current_video.video_settings.dict() ) filters = generate_filters( custom_filters=f"fps={settings.fps:.2f}", raw_filters=True, **fastflix.current_video.video_settings.dict() ) output_video = clean_file_string(fastflix.current_video.video_settings.output_path) beginning = ( f'"{fastflix.config.ffmpeg}" -y ' f'{f"-ss {fastflix.current_video.video_settings.start_time}" if fastflix.current_video.video_settings.start_time else ""} ' f'{f"-to {fastflix.current_video.video_settings.end_time}" if fastflix.current_video.video_settings.end_time else ""} ' f'{f"-r {fastflix.current_video.video_settings.source_fps } " if fastflix.current_video.video_settings.source_fps else ""}' f' -i "{fastflix.current_video.source}" ' ) if settings.extra: beginning += f" " temp_palette = fastflix.current_video.work_path / f"temp_palette_{secrets.token_hex(10)}.png" command_1 = ( f'{beginning} {palletgen_filters} {settings.extra if settings.extra_both_passes else ""} -y "{temp_palette}"' ) gif_filters = f"fps={settings.fps:.2f}" if filters: gif_filters += f",{filters}" command_2 = ( f'{beginning} -i "{temp_palette}" ' f'-filter_complex "{filters};[v][1:v]paletteuse=dither={settings.dither}[o]" -map "[o]" {settings.extra} -y "{output_video}" ' ) return [ Command(command=command_1, name="Pallet generation", exe="ffmpeg"), Command(command=command_2, name="GIF creation", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: GIFSettings = fastflix.current_video.video_settings.video_encoder_settings palletgen_filters = generate_filters( custom_filters="palettegen", **asdict(fastflix.current_video.video_settings)) filters = generate_filters(custom_filters=f"fps={settings.fps:.2f}", raw_filters=True, **asdict(fastflix.current_video.video_settings)) output_video = str( fastflix.current_video.video_settings.output_path).replace("\\", "/") beginning = ( f'"{fastflix.config.ffmpeg}" -y ' f'{f"-ss {fastflix.current_video.video_settings.start_time}" if fastflix.current_video.video_settings.start_time else ""} ' f'{f"-to {fastflix.current_video.video_settings.end_time}" if fastflix.current_video.video_settings.end_time else ""} ' f'-i "{fastflix.current_video.source}" ') if settings.extra: beginning += f" {settings.extra} " temp_palette = fastflix.current_video.work_path / f"temp_palette_{secrets.token_hex(10)}.png" command_1 = f'{beginning} {palletgen_filters} -y "{temp_palette}"' gif_filters = f"fps={settings.fps:.2f}" if filters: gif_filters += f",{filters}" command_2 = ( f'{beginning} -i "{temp_palette}" ' f'-filter_complex "{filters};[v][1:v]paletteuse=dither={settings.dither}[o]" -map "[o]" -y "{output_video}" ' ) return [ Command(command_1, ["ffmpeg", "pallet_file", "output"], False, name="Pallet generation", exe="ffmpeg"), Command(command_2, ["ffmpeg", "pallet_file", "output"], False, name="GIF creation", exe="ffmpeg"), ]
def build(fastflix: FastFlix): beginning, ending = generate_all(fastflix, "copy", disable_filters=True) return [ Command( command= f"{beginning} {fastflix.current_video.video_settings.video_encoder_settings.extra} {ending}", name="No Video Encoding", exe="ffmpeg", ) ]
def build(fastflix: FastFlix): beginning, ending = generate_all(fastflix, "copy", disable_filters=True) return [ Command( re.sub("[ ]+", " ", f"{beginning} {ending}"), ["ffmpeg", "output"], False, name="No Video Encoding", exe="ffmpeg", ) ]
def build(fastflix: FastFlix): settings: HEVCVideoToolboxSettings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "hevc_videotoolbox") beginning += generate_color_details(fastflix) def clean_bool(item): return "true" if item else "false" details = (f"-profile:v {settings.profile} " f"-allow_sw {clean_bool(settings.allow_sw)} " f"-require_sw {clean_bool(settings.require_sw)} " f"-realtime {clean_bool(settings.realtime)} " f"-frames_before {clean_bool(settings.frames_before)} " f"-frames_after {clean_bool(settings.frames_after)} ") if settings.bitrate: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" beginning += f" " command_1 = f"{beginning} -b:v {settings.bitrate} {details} -pass 1 -passlogfile \"{pass_log_file}\" {settings.extra if settings.extra_both_passes else ''} -an -f mp4 {null}" command_2 = f'{beginning} -b:v {settings.bitrate} {details} -pass 2 -passlogfile "{pass_log_file}" {settings.extra} {ending}' return [ Command(command=command_1, name=f"First pass bitrate", exe="ffmpeg"), Command(command=command_2, name=f"Second pass bitrate", exe="ffmpeg"), ] command_1 = f"{beginning} -q:v {settings.q} {details} {settings.extra} {ending}" return [ Command(command=command_1, name=f"Single pass constant quality", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: x264Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libx264") beginning += f'{f"-tune {settings.tune}" if settings.tune else ""} ' f"{generate_color_details(fastflix)} " if settings.profile and settings.profile != "default": beginning += f"-profile {settings.profile} " pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}.log" if settings.bitrate: command_1 = ( f"{beginning} -pass 1 " f'-passlogfile "{pass_log_file}" -b:v {settings.bitrate} -preset {settings.preset} -an -sn -dn -f mp4 {null}' ) command_2 = ( f'{beginning} -pass 2 -passlogfile "{pass_log_file}" ' f"-b:v {settings.bitrate} -preset {settings.preset}" ) + ending return [ Command( re.sub("[ ]+", " ", command_1), ["ffmpeg", "output"], False, name="First pass bitrate", exe="ffmpeg" ), Command( re.sub("[ ]+", " ", command_2), ["ffmpeg", "output"], False, name="Second pass bitrate", exe="ffmpeg" ), ] elif settings.crf: command = (f"{beginning} -crf {settings.crf} " f"-preset {settings.preset} ") + ending return [ Command(re.sub("[ ]+", " ", command), ["ffmpeg", "output"], False, name="Single pass CRF", exe="ffmpeg") ] else: return []
def build(fastflix: FastFlix): settings: WebPSettings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libwebp", audio=False, subs=False) return [ Command( command= f"{beginning} -lossless {settings.lossless} -compression_level {settings.compression} " f"-qscale {settings.qscale} -preset {settings.preset} {settings.extra} {ending}", name="WebP", exe="ffmpeg", ), ]
def build( source, video_track, ffmpeg, temp_dir, output_video, bitrate=None, crf=None, subtitle_tracks=(), single_pass=False, quality="good", audio_tracks=(), speed=1, row_mt=0, pix_fmt="yuv420p10le", attachments="", disable_hdr=False, side_data=None, **kwargs, ): filters = generate_filters(disable_hdr=disable_hdr, **kwargs) audio = build_audio(audio_tracks) subtitles = build_subtitle(subtitle_tracks) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="libvpx-vp9", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += f'{"-row-mt 1" if row_mt else ""} ' if not single_pass: pass_log_file = Path( temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" beginning += f'-passlogfile "{pass_log_file}" ' if not disable_hdr and pix_fmt == "yuv420p10le": if side_data and side_data.get("color_primaries") == "bt2020": beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc" beginning = re.sub("[ ]+", " ", beginning) if bitrate: command_1 = f"{beginning} -b:v {bitrate} -quality good -pass 1 -an -f webm {null}" command_2 = f"{beginning} -b:v {bitrate} -quality {quality} -speed {speed} -pass 2" + ending elif crf: command_1 = f"{beginning} -b:v 0 -crf {crf} -quality good -pass 1 -an -f webm {null}" command_2 = ( f"{beginning} -b:v 0 -crf {crf} -quality {quality} -speed {speed} " f'{"-pass 2" if not single_pass else ""}') + ending else: return [] if crf and single_pass: return [ Command(command_2, ["ffmpeg", "output"], False, name="Single pass CRF", exe="ffmpeg") ] pass_type = "bitrate" if bitrate else "CRF" return [ Command(command_1, ["ffmpeg", "output"], False, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command_2, ["ffmpeg", "output"], False, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build( source, video_track, ffmpeg, temp_dir, output_video, streams, stream_track, bitrate=None, crf=None, audio_tracks=(), subtitle_tracks=(), disable_hdr=False, side_data=None, row_mt=None, cpu_used="1", tile_columns="-1", tile_rows="-1", attachments="", pix_fmt="yuv420p10le", usage="good", **kwargs, ): audio = build_audio(audio_tracks) subtitles, burn_in_track = build_subtitle(subtitle_tracks) filters = generate_filters(video_track=video_track, disable_hdr=disable_hdr, burn_in_track=burn_in_track, **kwargs) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="libaom-av1", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += ( "-strict experimental " f"-cpu-used {cpu_used} " f"-tile-rows {tile_rows} " f"-tile-columns {tile_columns} " f"-usage {usage} " ) if row_mt is not None: beginning += f"-row-mt {row_mt} " if not disable_hdr and pix_fmt in ("yuv420p10le", "yuv420p12le"): if streams.video[stream_track].get("color_primaries") == "bt2020" or ( side_data and side_data.get("color_primaries") == "bt2020" ): beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc" beginning = re.sub("[ ]+", " ", beginning) if bitrate: pass_log_file = Path(temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" command_1 = f'{beginning} -passlogfile "{pass_log_file}" -b:v {bitrate} -pass 1 -an -f matroska {null}' command_2 = f'{beginning} -passlogfile "{pass_log_file}" -b:v {bitrate} -pass 2' + ending return [ Command(command_1, ["ffmpeg", "output"], False, name="First Pass bitrate"), Command(command_2, ["ffmpeg", "output"], False, name="Second Pass bitrate"), ] elif crf: command_1 = f"{beginning} -b:v 0 -crf {crf}" + ending return [Command(command_1, ["ffmpeg", "output"], False, name="Single Pass CRF")]
def build( source, video_track, ffmpeg, temp_dir, output_video, bitrate=None, crf=None, preset="fast", audio_tracks=(), subtitle_tracks=(), disable_hdr=False, side_data=None, pix_fmt="yuv420p", tune=None, profile="default", attachments="", **kwargs, ): filters = generate_filters(disable_hdr=disable_hdr, **kwargs) audio = build_audio(audio_tracks) subtitles = build_subtitle(subtitle_tracks) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) if not side_data: side_data = Box(default_box=True) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="libx264", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += f'{f"-tune {tune}" if tune else ""} ' if profile and profile != "default": beginning += f"-profile {profile} " if not disable_hdr and pix_fmt == "yuv420p10le": if side_data and side_data.get("color_primaries") == "bt2020": beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc" if side_data.cll: pass extra_data = "-map_chapters 0 " # -map_metadata 0 # safe to do for rotation? pass_log_file = Path( temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" if bitrate: command_1 = ( f"{beginning} -pass 1 " f'-passlogfile "{pass_log_file}" -b:v {bitrate} -preset {preset} -an -sn -dn -f mp4 {null}' ) command_2 = (f'{beginning} -pass 2 -passlogfile "{pass_log_file}" ' f"-b:v {bitrate} -preset {preset} {extra_data}") + ending return [ Command(re.sub("[ ]+", " ", command_1), ["ffmpeg", "output"], False, name="First pass bitrate", exe="ffmpeg"), Command(re.sub("[ ]+", " ", command_2), ["ffmpeg", "output"], False, name="Second pass bitrate", exe="ffmpeg"), ] elif crf: command = (f"{beginning} -crf {crf} " f"-preset {preset} {extra_data}") + ending return [ Command(re.sub("[ ]+", " ", command), ["ffmpeg", "output"], False, name="Single pass CRF", exe="ffmpeg") ] else: return []
def build( source, video_track, ffmpeg, temp_dir, output_video, streams, stream_track, bitrate=None, crf=None, preset="fast", audio_tracks=(), subtitle_tracks=(), disable_hdr=False, side_data=None, x265_params=None, intra_encoding=False, pix_fmt="yuv420p10le", tune=None, profile="default", attachments="", hdr10=False, hdr10_opt=False, repeat_headers=False, hdr10plus_metadata="", aq_mode=2, **kwargs, ): audio = build_audio(audio_tracks) subtitles, burn_in_track = build_subtitle(subtitle_tracks) filters = generate_filters(video_track=video_track, disable_hdr=disable_hdr, burn_in_track=burn_in_track, **kwargs) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) if not side_data: side_data = Box(default_box=True) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="libx265", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += f'{f"-tune {tune}" if tune else ""} ' if profile and profile != "default": beginning += f"-profile {profile} " if not x265_params: x265_params = [] x265_params.append(f"aq-mode={aq_mode}") x265_params.append(f"repeat-headers={'1' if repeat_headers else '0'}") if not disable_hdr and pix_fmt in ("yuv420p10le", "yuv420p12le"): x265_params.append(f"hdr10_opt={'1' if hdr10_opt else '0'}") if streams.video[stream_track].get("color_primaries") == "bt2020" or ( side_data and side_data.get("color_primaries") == "bt2020" ): x265_params.extend( [ "colorprim=bt2020", "transfer=smpte2084", "colormatrix=bt2020nc", ] ) if side_data.master_display: hdr10 = True x265_params.append( "master-display=" f"G{side_data.master_display.green}" f"B{side_data.master_display.blue}" f"R{side_data.master_display.red}" f"WP{side_data.master_display.white}" f"L{side_data.master_display.luminance}" ) if side_data.cll: hdr10 = True x265_params.append(f"max-cll={side_data.cll}") x265_params.append(f"hdr10={'1' if hdr10 else '0'}") if hdr10plus_metadata: x265_params.append(f"dhdr10-info='{hdr10plus_metadata}'") if intra_encoding: x265_params.append("keyint=1") if side_data.cll: pass pass_log_file = Path(temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" def get_x265_params(params=()): if not isinstance(params, (list, tuple)): params = [params] all_params = x265_params + list(params) return '-x265-params "{}" '.format(":".join(all_params)) if all_params else "" if bitrate: command_1 = ( f'{beginning} {get_x265_params(["pass=1", "no-slow-firstpass=1"])} ' f'-passlogfile "{pass_log_file}" -b:v {bitrate} -preset {preset} -an -sn -dn -f mp4 {null}' ) command_2 = ( f'{beginning} {get_x265_params(["pass=2"])} -passlogfile "{pass_log_file}" ' f"-b:v {bitrate} -preset {preset} " ) + ending return [ Command( re.sub("[ ]+", " ", command_1), ["ffmpeg", "output"], False, name="First pass bitrate", exe="ffmpeg" ), Command( re.sub("[ ]+", " ", command_2), ["ffmpeg", "output"], False, name="Second pass bitrate", exe="ffmpeg" ), ] elif crf: command = (f"{beginning} {get_x265_params()} -crf {crf} " f"-preset {preset} ") + ending return [ Command(re.sub("[ ]+", " ", command), ["ffmpeg", "output"], False, name="Single pass CRF", exe="ffmpeg") ] else: return []
def build(fastflix: FastFlix): video: Video = fastflix.current_video settings: VCEEncCSettings = fastflix.current_video.video_settings.video_encoder_settings master_display = None if fastflix.current_video.master_display: master_display = ( f'--master-display "G{fastflix.current_video.master_display.green}' f"B{fastflix.current_video.master_display.blue}" f"R{fastflix.current_video.master_display.red}" f"WP{fastflix.current_video.master_display.white}" f'L{fastflix.current_video.master_display.luminance}"' ) max_cll = None if fastflix.current_video.cll: max_cll = f'--max-cll "{fastflix.current_video.cll}"' dhdr = None if settings.hdr10plus_metadata: dhdr = f'--dhdr10-info "{settings.hdr10plus_metadata}"' trim = "" try: if "/" in video.frame_rate: over, under = [int(x) for x in video.frame_rate.split("/")] rate = over / under else: rate = float(video.frame_rate) except Exception: logger.exception("Could not get framerate of this movie!") else: if video.video_settings.end_time: end_frame = int(video.video_settings.end_time * rate) start_frame = 0 if video.video_settings.start_time: start_frame = int(video.video_settings.start_time * rate) trim = f"--trim {start_frame}:{end_frame}" elif video.video_settings.start_time: trim = f"--seek {video.video_settings.start_time}" if (video.frame_rate != video.average_frame_rate) and trim: logger.warning("Cannot use 'trim' when working with variable frame rate videos") trim = "" transform = "" if video.video_settings.vertical_flip or video.video_settings.horizontal_flip: transform = f"--vpp-transform flip_x={'true' if video.video_settings.horizontal_flip else 'false'},flip_y={'true' if video.video_settings.vertical_flip else 'false'}" remove_hdr = "" if video.video_settings.remove_hdr: remove_type = ( video.video_settings.tone_map if video.video_settings.tone_map in ("mobius", "hable", "reinhard") else "mobius" ) remove_hdr = f"--vpp-colorspace hdr2sdr={remove_type}" if video.video_settings.remove_hdr else "" crop = "" if video.video_settings.crop: crop = f"--crop {video.video_settings.crop.left},{video.video_settings.crop.top},{video.video_settings.crop.right},{video.video_settings.crop.bottom}" vbv = "" if video.video_settings.maxrate: vbv = f"--max-bitrate {video.video_settings.maxrate} --vbv-bufsize {video.video_settings.bufsize}" try: stream_id = int(video.current_video_stream["id"], 16) except Exception: if len(video.streams.video) > 1: logger.warning("Could not get stream ID from source, the proper video track may not be selected!") stream_id = None vsync_setting = "cfr" if video.frame_rate == video.average_frame_rate else "vfr" if video.video_settings.vsync == "cfr": vsync_setting = "forcecfr" elif video.video_settings.vsync == "vfr": vsync_setting = "vfr" command = [ f'"{clean_file_string(fastflix.config.vceencc)}"', ("--avhw" if settings.decoder == "Hardware" else "--avsw"), "-i", f'"{clean_file_string(video.source)}"', (f"--video-streamid {stream_id}" if stream_id else ""), trim, (f"--vpp-rotate {video.video_settings.rotate * 90}" if video.video_settings.rotate else ""), transform, (f'--output-res {video.video_settings.scale.replace(":", "x")}' if video.video_settings.scale else ""), crop, ( f"--video-metadata clear --metadata clear" if video.video_settings.remove_metadata else "--video-metadata copy --metadata copy" ), (f'--video-metadata title="{video.video_settings.video_title}"' if video.video_settings.video_title else ""), ("--chapter-copy" if video.video_settings.copy_chapters else ""), "-c", "hevc", (f"--vbr {settings.bitrate.rstrip('k')}" if settings.bitrate else f"--cqp {settings.cqp}"), vbv, (f"--qp-min {settings.min_q}" if settings.min_q and settings.bitrate else ""), (f"--qp-max {settings.max_q}" if settings.max_q and settings.bitrate else ""), (f"--ref {settings.ref}" if settings.ref else ""), "--preset", settings.preset, "--tier", settings.tier, "--level", (settings.level or "auto"), "--colormatrix", (video.video_settings.color_space or "auto"), "--transfer", (video.video_settings.color_transfer or "auto"), "--colorprim", (video.video_settings.color_primaries or "auto"), (master_display if master_display else ""), (max_cll if max_cll else ""), (dhdr if dhdr else ""), "--output-depth", ("10" if video.current_video_stream.bit_depth > 8 and not video.video_settings.remove_hdr else "8"), "--motion-est", settings.mv_precision, ("--vbaq" if settings.vbaq else ""), ("--pe" if settings.pre_encode else ""), ("--pa" if settings.pre_analysis else ""), "--chromaloc", "auto", "--colorrange", "auto", f"--avsync {vsync_setting}", (f"--interlace {video.interlaced}" if video.interlaced and video.interlaced != "False" else ""), ("--vpp-nnedi" if video.video_settings.deinterlace else ""), (f"--vpp-colorspace hdr2sdr=mobius" if video.video_settings.remove_hdr else ""), remove_hdr, "--psnr --ssim" if settings.metrics else "", build_audio(video.video_settings.audio_tracks, video.streams.audio), build_subtitle(video.video_settings.subtitle_tracks, video.streams.subtitle), settings.extra, "-o", f'"{clean_file_string(video.video_settings.output_path)}"', ] return [Command(command=" ".join(x for x in command if x), name="NVEncC Encode", exe="NVEncE")]
def build(fastflix: FastFlix): video: Video = fastflix.current_video settings: NVEncCAVCSettings = fastflix.current_video.video_settings.video_encoder_settings trim = "" try: if "/" in video.frame_rate: over, under = [int(x) for x in video.frame_rate.split("/")] rate = over / under else: rate = float(video.frame_rate) except Exception: logger.exception("Could not get framerate of this movie!") else: if video.video_settings.end_time: end_frame = int(video.video_settings.end_time * rate) start_frame = 0 if video.video_settings.start_time: start_frame = int(video.video_settings.start_time * rate) trim = f"--trim {start_frame}:{end_frame}" elif video.video_settings.start_time: trim = f"--seek {video.video_settings.start_time}" if (video.frame_rate != video.average_frame_rate) and trim: logger.warning("Cannot use 'trim' when working with variable frame rate videos") trim = "" transform = "" if video.video_settings.vertical_flip or video.video_settings.horizontal_flip: transform = f"--vpp-transform flip_x={'true' if video.video_settings.horizontal_flip else 'false'},flip_y={'true' if video.video_settings.vertical_flip else 'false'}" remove_hdr = "" if video.video_settings.remove_hdr: remove_type = ( video.video_settings.tone_map if video.video_settings.tone_map in ("mobius", "hable", "reinhard") else "mobius" ) remove_hdr = f"--vpp-colorspace hdr2sdr={remove_type}" if video.video_settings.remove_hdr else "" crop = "" if video.video_settings.crop: crop = f"--crop {video.video_settings.crop.left},{video.video_settings.crop.top},{video.video_settings.crop.right},{video.video_settings.crop.bottom}" vbv = "" if video.video_settings.maxrate: vbv = f"--max-bitrate {video.video_settings.maxrate} --vbv-bufsize {video.video_settings.bufsize}" init_q = settings.init_q_i if settings.init_q_i and settings.init_q_p and settings.init_q_b: init_q = f"{settings.init_q_i}:{settings.init_q_p}:{settings.init_q_b}" min_q = settings.min_q_i if settings.min_q_i and settings.min_q_p and settings.min_q_b: min_q = f"{settings.min_q_i}:{settings.min_q_p}:{settings.min_q_b}" max_q = settings.max_q_i if settings.max_q_i and settings.max_q_p and settings.max_q_b: max_q = f"{settings.max_q_i}:{settings.max_q_p}:{settings.max_q_b}" try: stream_id = int(video.current_video_stream["id"], 16) except Exception: if len(video.streams.video) > 1: logger.warning("Could not get stream ID from source, the proper video track may not be selected!") stream_id = None aq = "--no-aq" if settings.aq.lower() == "spatial": aq = f"--aq --aq-strength {settings.aq_strength}" elif settings.aq.lower() == "temporal": aq = f"--aq-temporal --aq-strength {settings.aq_strength}" vsync_setting = "cfr" if video.frame_rate == video.average_frame_rate else "vfr" if video.video_settings.vsync == "cfr": vsync_setting = "forcecfr" elif video.video_settings.vsync == "vfr": vsync_setting = "vfr" command = [ f'"{clean_file_string(fastflix.config.nvencc)}"', "-i", f'"{clean_file_string(video.source)}"', (f"--video-streamid {stream_id}" if stream_id else ""), trim, (f"--vpp-rotate {video.video_settings.rotate * 90}" if video.video_settings.rotate else ""), transform, (f'--output-res {video.video_settings.scale.replace(":", "x")}' if video.video_settings.scale else ""), crop, ( f"--video-metadata clear --metadata clear" if video.video_settings.remove_metadata else "--video-metadata copy --metadata copy" ), (f'--video-metadata title="{video.video_settings.video_title}"' if video.video_settings.video_title else ""), ("--chapter-copy" if video.video_settings.copy_chapters else ""), "-c", "avc", (f"--vbr {settings.bitrate.rstrip('k')}" if settings.bitrate else f"--cqp {settings.cqp}"), vbv, (f"--vbr-quality {settings.vbr_target}" if settings.vbr_target is not None and settings.bitrate else ""), (f"--qp-init {init_q}" if init_q and settings.bitrate else ""), (f"--qp-min {min_q}" if min_q and settings.bitrate else ""), (f"--qp-max {max_q}" if max_q and settings.bitrate else ""), (f"--bframes {settings.b_frames}" if settings.b_frames else ""), (f"--ref {settings.ref}" if settings.ref else ""), f"--bref-mode {settings.b_ref_mode}", "--preset", settings.preset, (f"--lookahead {settings.lookahead}" if settings.lookahead else ""), aq, "--level", (settings.level or "auto"), "--colormatrix", (video.video_settings.color_space or "auto"), "--transfer", (video.video_settings.color_transfer or "auto"), "--colorprim", (video.video_settings.color_primaries or "auto"), "--multipass", settings.multipass, "--mv-precision", settings.mv_precision, "--chromaloc", "auto", "--colorrange", "auto", f"--avsync {vsync_setting}", (f"--interlace {video.interlaced}" if video.interlaced and video.interlaced != "False" else ""), ("--vpp-yadif" if video.video_settings.deinterlace else ""), (f"--vpp-colorspace hdr2sdr=mobius" if video.video_settings.remove_hdr else ""), remove_hdr, "--psnr --ssim" if settings.metrics else "", build_audio(video.video_settings.audio_tracks, video.streams.audio), build_subtitle(video.video_settings.subtitle_tracks, video.streams.subtitle), settings.extra, "-o", f'"{clean_file_string(video.video_settings.output_path)}"', ] return [Command(command=" ".join(x for x in command if x), name="NVEncC Encode", exe="NVEncE")]
def build( source, video_track, ffmpeg, temp_dir, output_video, streams, stream_track, tiles=0, tile_columns=0, tile_rows=0, speed=7, qp=-1, pix_fmt="yuv420p10le", bitrate=None, audio_tracks=(), subtitle_tracks=(), disable_hdr=False, side_data=None, single_pass=False, attachments="", **kwargs, ): audio = build_audio(audio_tracks) subtitles, burn_in_track = build_subtitle(subtitle_tracks) filters = generate_filters(video_track=video_track, disable_hdr=disable_hdr, burn_in_track=burn_in_track, **kwargs) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="librav1e", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += ("-strict experimental " f"-speed {speed} " f"-tile-columns {tile_columns} " f"-tile-rows {tile_rows} " f"-tiles {tiles} ") if not single_pass: pass_log_file = Path( temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" beginning += f'-passlogfile "{pass_log_file}" ' if not disable_hdr and pix_fmt in ("yuv420p10le", "yuv420p12le"): if streams.video[stream_track].get("color_primaries") == "bt2020" or ( side_data and side_data.get("color_primaries") == "bt2020"): beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc" # Currently unsupported https://github.com/xiph/rav1e/issues/2554 # rav1e_options = [] # if side_data.master_display: # rav1e_options.append( # "mastering-display=" # f"G{side_data.master_display.green}" # f"B{side_data.master_display.blue}" # f"R{side_data.master_display.red}" # f"WP{side_data.master_display.white}" # f"L{side_data.master_display.luminance}" # ) # # if side_data.cll: # rav1e_options.append(f"content-light={side_data.cll}") # if rav1e_options: # opts = ":".join(rav1e_options) # beginning += f'-rav1e-params "{opts}"' beginning = re.sub("[ ]+", " ", beginning) pass_type = "bitrate" if bitrate else "QP" if not bitrate: command_1 = f"{beginning} -qp {qp}" + ending return [ Command(command_1, ["ffmpeg", "output"], False, name=f"{pass_type}", exe="ffmpeg") ] if single_pass: command_1 = f'{beginning} -b:v {bitrate} {audio} {subtitles} {attachments} "{output_video}"' return [ Command(command_1, ["ffmpeg", "output"], False, name=f"{pass_type}", exe="ffmpeg") ] else: command_1 = f"{beginning} -b:v {bitrate} -pass 1 -an -f matroska {null}" command_2 = f"{beginning} -b:v {bitrate} -pass 2" + ending return [ Command(command_1, ["ffmpeg", "output"], False, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command_2, ["ffmpeg", "output"], False, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: SVTAV1Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libsvtav1") beginning += ( f"-strict experimental " f"-preset {settings.speed} " f"-tile_columns {settings.tile_columns} " f"-tile_rows {settings.tile_rows} " f"-tier {settings.tier} " f"-sc_detection {'true' if settings.scene_detection else 'false'} " f"{generate_color_details(fastflix)} ") svtav1_params = settings.svtav1_params.copy() if not fastflix.current_video.video_settings.remove_hdr: if (fastflix.current_video.video_settings.color_primaries == "bt2020" or fastflix.current_video.color_primaries == "bt2020"): svtav1_params.append(f"color-primaries=9") if (fastflix.current_video.video_settings.color_transfer == "smpte2084" or fastflix.current_video.color_transfer == "smpte2084"): svtav1_params.append(f"transfer-characteristics=16") if (fastflix.current_video.video_settings.color_space and "bt2020" in fastflix.current_video.video_settings.color_space) or ( fastflix.current_video.color_space and "bt2020" in fastflix.current_video.color_space): svtav1_params.append(f"matrix-coefficients=9") enable_hdr = False if settings.pix_fmt in ("yuv420p10le", "yuv420p12le"): def convert_me(two_numbers, conversion_rate=50_000) -> str: num_one, num_two = map(int, two_numbers.strip("()").split(",")) return f"{num_one / conversion_rate:0.4f},{num_two / conversion_rate:0.4f}" if fastflix.current_video.master_display: svtav1_params.append( "mastering-display=" f"G({convert_me(fastflix.current_video.master_display.green)})" f"B({convert_me(fastflix.current_video.master_display.blue)})" f"R({convert_me(fastflix.current_video.master_display.red)})" f"WP({convert_me(fastflix.current_video.master_display.white)})" f"L({convert_me(fastflix.current_video.master_display.luminance, 10_000)})" ) enable_hdr = True if fastflix.current_video.cll: svtav1_params.append( f"content-light={fastflix.current_video.cll}") enable_hdr = True if enable_hdr: svtav1_params.append("enable-hdr=1") if svtav1_params: beginning += f" -svtav1-params \"{':'.join(svtav1_params)}\" " if not settings.single_pass: pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" beginning += f'-passlogfile "{pass_log_file}" ' pass_type = "bitrate" if settings.bitrate else "QP" if settings.single_pass: if settings.bitrate: command_1 = f"{beginning} -b:v {settings.bitrate} {settings.extra} {ending}" elif settings.qp is not None: command_1 = f"{beginning} -{settings.qp_mode} {settings.qp} {settings.extra} {ending}" else: return [] return [Command(command=command_1, name=f"{pass_type}", exe="ffmpeg")] else: if settings.bitrate: command_1 = f"{beginning} -b:v {settings.bitrate} -pass 1 {settings.extra if settings.extra_both_passes else ''} -an -f matroska {null}" command_2 = f"{beginning} -b:v {settings.bitrate} -pass 2 {settings.extra} {ending}" elif settings.qp is not None: command_1 = f"{beginning} -qp {settings.qp} -pass 1 {settings.extra if settings.extra_both_passes else ''} -an -f matroska {null}" command_2 = f"{beginning} -qp {settings.qp} -pass 2 {settings.extra} {ending}" else: return [] return [ Command(command=command_1, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command=command_2, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]
def build(fastflix: FastFlix): settings: x265Settings = fastflix.current_video.video_settings.video_encoder_settings beginning, ending = generate_all(fastflix, "libx265") if settings.tune and settings.tune != "default": beginning += f"-tune:v {settings.tune} " if settings.profile and settings.profile != "default": beginning += f"-profile:v {settings.profile} " x265_params = settings.x265_params.copy() or [] x265_params.append(f"aq-mode={settings.aq_mode}") x265_params.append( f"repeat-headers={'1' if settings.repeat_headers else '0'}") x265_params.append( f"{'' if settings.intra_smoothing else 'no-'}strong-intra-smoothing=1") x265_params.append(f"bframes={settings.bframes}") x265_params.append(f"b-adapt={settings.b_adapt}") x265_params.append(f"frame-threads={settings.frame_threads}") if not fastflix.current_video.video_settings.remove_hdr: if fastflix.current_video.video_settings.color_primaries: x265_params.append( f"colorprim={fastflix.current_video.video_settings.color_primaries}" ) elif fastflix.current_video.color_primaries: if fastflix.current_video.color_primaries in x265_valid_color_primaries: x265_params.append( f"colorprim={fastflix.current_video.color_primaries}") elif fastflix.current_video.color_primaries in color_primaries_mapping: x265_params.append( f"colorprim={color_primaries_mapping[fastflix.current_video.color_primaries]}" ) if fastflix.current_video.video_settings.color_transfer: x265_params.append( f"transfer={fastflix.current_video.video_settings.color_transfer}" ) elif fastflix.current_video.color_transfer: if fastflix.current_video.color_transfer in x265_valid_color_transfers: x265_params.append( f"transfer={fastflix.current_video.color_transfer}") elif fastflix.current_video.color_transfer in color_transfer_mapping: x265_params.append( f"transfer={color_transfer_mapping[fastflix.current_video.color_transfer]}" ) if fastflix.current_video.video_settings.color_space: x265_params.append( f"colormatrix={fastflix.current_video.video_settings.color_space}" ) elif fastflix.current_video.color_space: if fastflix.current_video.color_space in x265_valid_color_matrix: x265_params.append( f"colormatrix={fastflix.current_video.color_space}") elif fastflix.current_video.color_space in color_matrix_mapping: x265_params.append( f"colormatrix={color_matrix_mapping[fastflix.current_video.color_space]}" ) if settings.pix_fmt in ("yuv420p10le", "yuv420p12le"): x265_params.append( f"hdr10_opt={'1' if settings.hdr10_opt else '0'}") if fastflix.current_video.master_display: settings.hdr10 = True x265_params.append( "master-display=" f"G{fastflix.current_video.master_display.green}" f"B{fastflix.current_video.master_display.blue}" f"R{fastflix.current_video.master_display.red}" f"WP{fastflix.current_video.master_display.white}" f"L{fastflix.current_video.master_display.luminance}") if fastflix.current_video.cll: settings.hdr10 = True x265_params.append(f"max-cll={fastflix.current_video.cll}") x265_params.append(f"hdr10={'1' if settings.hdr10 else '0'}") current_chroma_loc = fastflix.current_video.current_video_stream.get( "chroma_location") if current_chroma_loc in chromaloc_mapping: x265_params.append( f"chromaloc={chromaloc_mapping[current_chroma_loc]}") if settings.hdr10plus_metadata: x265_params.append(f"dhdr10-info='{settings.hdr10plus_metadata}'") if settings.intra_encoding: x265_params.append("keyint=1") if settings.intra_refresh: x265_params.append("intra-refresh=1") if settings.lossless: x265_params.append("lossless=1") if fastflix.current_video.video_settings.maxrate: x265_params.append( f"vbv-maxrate={fastflix.current_video.video_settings.maxrate}") x265_params.append( f"vbv-bufsize={fastflix.current_video.video_settings.bufsize}") if fastflix.current_video.cll: pass pass_log_file = fastflix.current_video.work_path / f"pass_log_file_{secrets.token_hex(10)}" def get_x265_params(params=()): if not isinstance(params, (list, tuple)): params = [params] all_params = x265_params + list(params) return '-x265-params "{}" '.format( ":".join(all_params)) if all_params else "" if settings.bitrate: command_1 = ( f'{beginning} {get_x265_params(["pass=1", "no-slow-firstpass=1"])} ' f'-passlogfile "{pass_log_file}" -b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra if settings.extra_both_passes else ""} ' f" -an -sn -dn -f mp4 {null}") command_2 = ( f'{beginning} {get_x265_params(["pass=2"])} -passlogfile "{pass_log_file}" ' f"-b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} {ending}" ) return [ Command(command=command_1, name="First pass bitrate", exe="ffmpeg"), Command(command=command_2, name="Second pass bitrate", exe="ffmpeg"), ] elif settings.crf: command = (f"{beginning} {get_x265_params()} -crf:v {settings.crf} " f"-preset:v {settings.preset} {settings.extra} {ending}") return [Command(command=command, name="Single pass CRF", exe="ffmpeg")] else: return []
def build( source, video_track, ffmpeg, temp_dir, output_video, streams, stream_track, tier="main", tile_columns=0, tile_rows=0, speed=7, qp=25, sc_detection=0, disable_hdr=False, pix_fmt="yuv420p10le", bitrate=None, audio_tracks=(), subtitle_tracks=(), side_data=None, single_pass=False, attachments="", **kwargs, ): audio = build_audio(audio_tracks) subtitles, burn_in_track = build_subtitle(subtitle_tracks) filters = generate_filters(video_track=video_track, disable_hdr=disable_hdr, burn_in_track=burn_in_track, **kwargs) ending = generate_ending(audio=audio, subtitles=subtitles, cover=attachments, output_video=output_video, **kwargs) beginning = generate_ffmpeg_start( source=source, ffmpeg=ffmpeg, encoder="libsvtav1", video_track=video_track, filters=filters, pix_fmt=pix_fmt, **kwargs, ) beginning += (f"-strict experimental " f"-preset {speed} " f"-tile_columns {tile_columns} " f"-tile_rows {tile_rows} " f"-tier {tier} " f"-sc_detection {sc_detection} ") if not single_pass: pass_log_file = Path( temp_dir) / f"pass_log_file_{secrets.token_hex(10)}.log" beginning += f'-passlogfile "{pass_log_file}" ' if not disable_hdr and pix_fmt in ("yuv420p10le", "yuv420p12le"): if streams.video[stream_track].get("color_primaries") == "bt2020" or ( side_data and side_data.get("color_primaries") == "bt2020"): beginning += "-color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc" beginning = re.sub("[ ]+", " ", beginning) pass_type = "bitrate" if bitrate else "QP" if single_pass: if bitrate: command_1 = f"{beginning} -b:v {bitrate} -rc 1" + ending elif qp is not None: command_1 = f"{beginning} -qp {qp} -rc 0" + ending else: return [] return [ Command(command_1, ["ffmpeg", "output"], False, name=f"{pass_type}", exe="ffmpeg") ] else: if bitrate: command_1 = f"{beginning} -b:v {bitrate} -rc 1 -pass 1 -an -f matroska {null}" command_2 = f"{beginning} -b:v {bitrate} -rc 1 -pass 2" + ending elif qp is not None: command_1 = f"{beginning} -qp {qp} -rc 0 -pass 1 -an -f matroska {null}" command_2 = f"{beginning} -qp {qp} -rc 0 -pass 2" + ending else: return [] return [ Command(command_1, ["ffmpeg", "output"], False, name=f"First pass {pass_type}", exe="ffmpeg"), Command(command_2, ["ffmpeg", "output"], False, name=f"Second pass {pass_type} ", exe="ffmpeg"), ]