Skip to content

Commit

Permalink
Version 5.6.0 (#524)
Browse files Browse the repository at this point in the history
* Adding Passes option for bitrate mode in x265 and x264 (thanks to Chriss)
* Fixing VVC encode options (thanks to Chriss)
* Fixing #532 Trying to crop spams crop error (gendalv)
* Removing distutils in favor of packaging
* Removing #525 invalid 12 bit options for x264 (thanks to Chriss)
* Removing #497 #519 advanced checks for hardware encoders, due to them not always being detected (thanks to CptnFluffy)
cdgriffith authored Nov 5, 2023

Verified

This commit was signed with the committer’s verified signature.
snyk-bot Snyk bot
1 parent 80cca41 commit 8523fcf
Showing 13 changed files with 410 additions and 136 deletions.
8 changes: 8 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## Version 5.6.0

* Adding Passes option for bitrate mode in x265 and x264 (thanks to Chriss)
* Fixing VVC encode options (thanks to Chriss)
* Removing distutils in favor of packaging
* Removing #525 invalid 12 bit options for x264 (thanks to Chriss)
* Removing #497 #519 advanced checks for hardware encoders, due to them not always being detected (thanks to CptnFluffy)

## Version 5.5.7

* Fixing #503 missing CRF mode for SVT-AV1 (thanks to ignace72)
38 changes: 19 additions & 19 deletions fastflix/application.py
Original file line number Diff line number Diff line change
@@ -115,29 +115,29 @@ def init_encoders(app: FastFlixApp, **_):
encoders.insert(encoders.index(avc_plugin), vceencc_avc_plugin)
else:
if app.fastflix.config.qsvencc:
if "H.265/HEVC" in app.fastflix.config.qsvencc_encoders:
encoders.insert(1, qsvencc_plugin)
if "AV1" in app.fastflix.config.qsvencc_encoders:
encoders.insert(encoders.index(av1_plugin), qsvencc_av1_plugin)
if "H.264/AVC" in app.fastflix.config.qsvencc_encoders:
encoders.insert(encoders.index(avc_plugin), qsvencc_avc_plugin)
# if "H.265/HEVC" in app.fastflix.config.qsvencc_encoders:
encoders.insert(1, qsvencc_plugin)
# if "AV1" in app.fastflix.config.qsvencc_encoders:
encoders.insert(encoders.index(av1_plugin), qsvencc_av1_plugin)
# if "H.264/AVC" in app.fastflix.config.qsvencc_encoders:
encoders.insert(encoders.index(avc_plugin), qsvencc_avc_plugin)

if app.fastflix.config.nvencc:
if "H.265/HEVC" in app.fastflix.config.nvencc_encoders:
encoders.insert(1, nvencc_plugin)
if "AV1" in app.fastflix.config.nvencc_encoders:
encoders.insert(encoders.index(av1_plugin), nvencc_av1_plugin)
if "H.264/AVC" in app.fastflix.config.nvencc_encoders:
encoders.insert(encoders.index(avc_plugin), nvencc_avc_plugin)
# if "H.265/HEVC" in app.fastflix.config.nvencc_encoders:
encoders.insert(1, nvencc_plugin)
# if "AV1" in app.fastflix.config.nvencc_encoders:
encoders.insert(encoders.index(av1_plugin), nvencc_av1_plugin)
# if "H.264/AVC" in app.fastflix.config.nvencc_encoders:
encoders.insert(encoders.index(avc_plugin), nvencc_avc_plugin)

if app.fastflix.config.vceencc:
if reusables.win_based and "H.265/HEVC" in app.fastflix.config.vceencc_encoders:
# HEVC AMF support only works on windows currently
encoders.insert(1, vceencc_hevc_plugin)
if "AV1" in app.fastflix.config.vceencc_encoders:
encoders.insert(encoders.index(av1_plugin), vceencc_av1_plugin)
if "H.264/AVC" in app.fastflix.config.vceencc_encoders:
encoders.insert(encoders.index(avc_plugin), vceencc_avc_plugin)
# if reusables.win_based: # and "H.265/HEVC" in app.fastflix.config.vceencc_encoders:
# HEVC AMF support only works on windows currently
encoders.insert(1, vceencc_hevc_plugin)
# if "AV1" in app.fastflix.config.vceencc_encoders:
encoders.insert(encoders.index(av1_plugin), vceencc_av1_plugin)
# if "H.264/AVC" in app.fastflix.config.vceencc_encoders:
encoders.insert(encoders.index(avc_plugin), vceencc_avc_plugin)

app.fastflix.encoders = {
encoder.name: encoder
363 changes: 289 additions & 74 deletions fastflix/data/languages.yaml

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions fastflix/encoders/avc_x264/command_builder.py
Original file line number Diff line number Diff line change
@@ -20,18 +20,22 @@ def build(fastflix: FastFlix):
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 {output_fps} -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"),
]
if settings.bitrate_passes == 2:
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 {output_fps} -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"),
]
else:
command = f"{beginning} -b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} {ending}"
return [Command(command=command, name="Single pass bitrate", exe="ffmpeg")]

elif settings.crf:
command = f"{beginning} -crf:v {settings.crf} " f"-preset:v {settings.preset} {settings.extra} {ending}"
6 changes: 2 additions & 4 deletions fastflix/encoders/avc_x264/settings_panel.py
Original file line number Diff line number Diff line change
@@ -51,13 +51,10 @@
pix_fmts = [
"8-bit: yuv420p",
"10-bit: yuv420p10le",
"12-bit: yuv420p12le",
"8-bit 422: yuv422p",
"8-bit 444: yuv444p",
"10-bit 422: yuv422p10le",
"10-bit 444: yuv444p10le",
"12-bit 422: yuv422p12le",
"12-bit 444: yuv444p12le",
]


@@ -154,7 +151,7 @@ def init_pix_fmt(self):
)

def init_modes(self):
return self._add_modes(recommended_bitrates, recommended_crfs, qp_name="crf")
return self._add_modes(recommended_bitrates, recommended_crfs, qp_name="crf", show_bitrate_passes=True)

def mode_update(self):
self.widgets.custom_crf.setDisabled(self.widgets.crf.currentText() != "Custom")
@@ -181,6 +178,7 @@ def update_video_encoder_settings(self):
extra=self.ffmpeg_extras,
tune=tune if tune.lower() != "default" else None,
extra_both_passes=self.widgets.extra_both_passes.isChecked(),
bitrate_passes=int(self.widgets.bitrate_passes.currentText()),
)
encode_type, q_value = self.get_mode_settings()
settings.crf = q_value if encode_type == "qp" else None
19 changes: 17 additions & 2 deletions fastflix/encoders/common/setting_panel.py
Original file line number Diff line number Diff line change
@@ -332,7 +332,15 @@ def dhdr10_update(self):
self.widgets.hdr10plus_metadata.setText(filename[0])
self.main.page_update()

def _add_modes(self, recommended_bitrates, recommended_qps, qp_name="crf", add_qp=True, disable_custom_qp=False):
def _add_modes(
self,
recommended_bitrates,
recommended_qps,
qp_name="crf",
add_qp=True,
disable_custom_qp=False,
show_bitrate_passes=False,
):
self.recommended_bitrates = recommended_bitrates
self.recommended_qps = recommended_qps
self.qp_name = qp_name
@@ -352,6 +360,10 @@ def _add_modes(self, recommended_bitrates, recommended_qps, qp_name="crf", add_q
self.widgets.bitrate = QtWidgets.QComboBox()
# self.widgets.bitrate.setFixedWidth(250)
self.widgets.bitrate.addItems(recommended_bitrates)
self.widgets.bitrate_passes = QtWidgets.QComboBox()
self.widgets.bitrate_passes.addItems(["1", "2"])
self.widgets.bitrate_passes.setCurrentIndex(1)
self.widgets.bitrate_passes.currentIndexChanged.connect(lambda: self.mode_update())
config_opt = self.app.fastflix.config.encoder_opt(self.profile_name, "bitrate")
custom_bitrate = False
try:
@@ -372,8 +384,11 @@ def _add_modes(self, recommended_bitrates, recommended_qps, qp_name="crf", add_q
bitrate_box_layout.addWidget(self.bitrate_radio)
bitrate_box_layout.addWidget(self.widgets.bitrate, 1)
bitrate_box_layout.addStretch(1)
if show_bitrate_passes:
bitrate_box_layout.addWidget(QtWidgets.QLabel(t("Passes") + ":"))
bitrate_box_layout.addWidget(self.widgets.bitrate_passes)
bitrate_box_layout.addStretch(1)
bitrate_box_layout.addWidget(QtWidgets.QLabel("Custom:"))
bitrate_box_layout.addWidget(QtWidgets.QLabel(t("Custom") + ":"))
bitrate_box_layout.addWidget(self.widgets.custom_bitrate)
bitrate_box_layout.addWidget(QtWidgets.QLabel("k"))

30 changes: 17 additions & 13 deletions fastflix/encoders/hevc_x265/command_builder.py
Original file line number Diff line number Diff line change
@@ -179,19 +179,23 @@ def get_x265_params(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 {output_fps} -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"),
]
if settings.bitrate_passes == 2:
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 {output_fps} -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"),
]
else:
command = f"{beginning} {get_x265_params()} -b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} {ending}"
return [Command(command=command, name="Single pass bitrate", exe="ffmpeg")]

elif settings.crf:
command = (
3 changes: 2 additions & 1 deletion fastflix/encoders/hevc_x265/settings_panel.py
Original file line number Diff line number Diff line change
@@ -563,7 +563,7 @@ def init_gop(self):
)

def init_modes(self):
return self._add_modes(recommended_bitrates, recommended_crfs, qp_name="crf")
return self._add_modes(recommended_bitrates, recommended_crfs, qp_name="crf", show_bitrate_passes=True)

def mode_update(self):
self.widgets.custom_crf.setDisabled(self.widgets.crf.currentText() != "Custom")
@@ -697,6 +697,7 @@ def update_video_encoder_settings(self):
lossless=self.widgets.lossless.isChecked(),
extra=self.ffmpeg_extras,
extra_both_passes=self.widgets.extra_both_passes.isChecked(),
bitrate_passes=int(self.widgets.bitrate_passes.currentText()),
# gop_size=int(self.widgets.gop_size.currentText()) if self.widgets.gop_size.currentIndex() > 0 else 0,
)

12 changes: 8 additions & 4 deletions fastflix/encoders/vvc/command_builder.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
from fastflix.encoders.common.helpers import Command, generate_all, null
from fastflix.models.encode import VVCSettings
from fastflix.models.fastflix import FastFlix
from fastflix.shared import clean_file_string, quoted_path

vvc_valid_color_primaries = [
"bt709",
@@ -106,13 +107,16 @@ def get_vvc_params(params=()):
return '-vvenc-params "{}" '.format(":".join(all_params)) if all_params else ""

if settings.bitrate:
params = get_vvc_params(["pass=1", f"rcstatsfile={quoted_path(clean_file_string(pass_log_file))}"])
command_1 = (
f'{beginning} {get_vvc_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"{beginning} {params} "
f'-passlogfile "{pass_log_file}" -b:v {settings.bitrate} '
f'-preset:v {settings.preset} {settings.extra if settings.extra_both_passes else ""} '
f" -an -sn -dn {output_fps} -f mp4 {null}"
)
params2 = get_vvc_params(["pass=2", f"rcstatsfile={quoted_path(clean_file_string(pass_log_file))}"])
command_2 = (
f'{beginning} {get_vvc_params(["pass=2"])} -passlogfile "{pass_log_file}" '
f'{beginning} {params2} -passlogfile "{pass_log_file}" '
f"-b:v {settings.bitrate} -preset:v {settings.preset} {settings.extra} {ending}"
)
return [
@@ -122,7 +126,7 @@ def get_vvc_params(params=()):

elif settings.qp:
command = (
f"{beginning} {get_vvc_params()} -qp:v {settings.qp} "
f"{beginning} {get_vvc_params()} -qp:v {settings.qp} -b:v 0 "
f"-preset:v {settings.preset} {settings.extra} {ending}"
)
return [Command(command=command, name="Single pass CRF", exe="ffmpeg")]
2 changes: 2 additions & 0 deletions fastflix/models/encode.py
Original file line number Diff line number Diff line change
@@ -72,6 +72,7 @@ class x265Settings(EncoderSettings):
intra_smoothing: bool = True
frame_threads: int = 0
# gop_size: int = 0
bitrate_passes: int = 2


class VVCSettings(EncoderSettings):
@@ -94,6 +95,7 @@ class x264Settings(EncoderSettings):
pix_fmt: str = "yuv420p"
crf: Optional[Union[int, float]] = 23
bitrate: Optional[str] = None
bitrate_passes: int = 2


class FFmpegNVENCSettings(EncoderSettings):
4 changes: 2 additions & 2 deletions fastflix/shared.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
import os
import sys
from datetime import datetime, timedelta
from distutils.version import StrictVersion
from packaging import version as packaging_version
from pathlib import Path
from subprocess import run
import platform
@@ -165,7 +165,7 @@ def latest_fastflix(app, show_new_dialog=False):

release = [x for x in data if x["tag_name"] == use_version][0]

if use_version != __version__ and StrictVersion(use_version) > StrictVersion(__version__):
if use_version != __version__ and packaging_version.parse(use_version) > packaging_version.parse(__version__):
portable, installer = None, None
for asset in release["assets"]:
if asset["name"].endswith("win64.zip"):
2 changes: 1 addition & 1 deletion fastflix/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__version__ = "5.5.7"
__version__ = "5.6.0"
__author__ = "Chris Griffith"
31 changes: 27 additions & 4 deletions fastflix/widgets/main.py
Original file line number Diff line number Diff line change
@@ -1294,16 +1294,39 @@ def build_crop(self) -> Union[Crop, None]:
return None
try:
assert crop.top >= 0, t("Top must be positive number")
assert crop.left >= 0, t("Left must be positive number")
assert crop.width > 0, t("Total video width must be greater than 0")
assert crop.height > 0, t("Total video height must be greater than 0")
assert crop.width <= self.app.fastflix.current_video.width, t("Width must be smaller than video width")
assert crop.height <= self.app.fastflix.current_video.height, t(
"Height must be smaller than video height"
)
except AssertionError as err:
error_message(f"{t('Invalid Crop')}: {err}")
logger.warning(f"{t('Invalid Crop')}: {err}")
self.widgets.crop.top.setStyleSheet("color: red")
self.widgets.crop.bottom.setStyleSheet("color: red")
return None
try:
assert crop.left >= 0, t("Left must be positive number")
assert crop.width > 0, t("Total video width must be greater than 0")

assert crop.width <= self.app.fastflix.current_video.width, t("Width must be smaller than video width")

except AssertionError as err:
logger.warning(f"{t('Invalid Crop')}: {err}")
self.widgets.crop.left.setStyleSheet("color: red")
self.widgets.crop.right.setStyleSheet("color: red")
# error_message(f"{t('Invalid Crop')}: {err}")
return None
self.widgets.crop.left.setStyleSheet(
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
)
self.widgets.crop.right.setStyleSheet(
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
)
self.widgets.crop.top.setStyleSheet(
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
)
self.widgets.crop.bottom.setStyleSheet(
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
)
return crop

def disable_all(self):

0 comments on commit 8523fcf

Please sign in to comment.