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)
  • Loading branch information
cdgriffith committed Nov 5, 2023
1 parent 80cca41 commit 8523fcf
Show file tree
Hide file tree
Showing 13 changed files with 410 additions and 136 deletions.
8 changes: 8 additions & 0 deletions CHANGES
@@ -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)
Expand Down
38 changes: 19 additions & 19 deletions fastflix/application.py
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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}"
Expand Down
6 changes: 2 additions & 4 deletions fastflix/encoders/avc_x264/settings_panel.py
Expand Up @@ -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",
]


Expand Down Expand Up @@ -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")
Expand All @@ -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
Expand Down
19 changes: 17 additions & 2 deletions fastflix/encoders/common/setting_panel.py
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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"))

Expand Down
30 changes: 17 additions & 13 deletions fastflix/encoders/hevc_x265/command_builder.py
Expand Up @@ -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 = (
Expand Down
3 changes: 2 additions & 1 deletion fastflix/encoders/hevc_x265/settings_panel.py
Expand Up @@ -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")
Expand Down Expand Up @@ -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,
)

Expand Down
12 changes: 8 additions & 4 deletions fastflix/encoders/vvc/command_builder.py
Expand Up @@ -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",
Expand Down Expand Up @@ -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 [
Expand All @@ -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")]
Expand Down
2 changes: 2 additions & 0 deletions fastflix/models/encode.py
Expand Up @@ -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):
Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions fastflix/shared.py
Expand Up @@ -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
Expand Down Expand Up @@ -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"):
Expand Down
2 changes: 1 addition & 1 deletion fastflix/version.py
@@ -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
Expand Up @@ -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):
Expand Down

0 comments on commit 8523fcf

Please sign in to comment.