Skip to content

Commit d881887

Browse files
authored
Version 6.2.1 (#735)
* Fixing #529 window geometry and menu anchoring issues when displays are powered off/on or reconfigured during use (thanks to wiznillyp) * Fixing #734 startup crash when FFmpeg/FFprobe exits with non-zero code despite producing valid output (e.g. custom builds that crash during cleanup) (thanks to kliffgomel) * Fixing #727 post-encode FFprobe failure when FFprobe crashes on cleanup but produces valid probe data (thanks to danycat201489-a11y) * Fixing return from queue bug with FFmpeg nvenc av1
1 parent 9f035e8 commit d881887

9 files changed

Lines changed: 69 additions & 12 deletions

File tree

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@
113113
"Bash(ffprobe:*)",
114114
"Bash(gh api:*)",
115115
"Bash(git:*)",
116-
"WebFetch(domain:docs.nvidia.com)"
116+
"WebFetch(domain:docs.nvidia.com)",
117+
"Bash(gh discussion:*)"
117118
]
118119
}
119120
}

CHANGES

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
# Changelog
22

3+
## Version 6.2.1
4+
5+
* Fixing #529 window geometry and menu anchoring issues when displays are powered off/on or reconfigured during use (thanks to wiznillyp)
6+
* Fixing #734 startup crash when FFmpeg/FFprobe exits with non-zero code despite producing valid output (e.g. custom builds that crash during cleanup) (thanks to kliffgomel)
7+
* Fixing #727 post-encode FFprobe failure when FFprobe crashes on cleanup but produces valid probe data (thanks to danycat201489-a11y)
8+
* Fixing return from queue bug with FFmpeg nvenc av1
9+
310
## Version 6.2.0
411

512
* Adding AV1 (NVENC) encoder for FFmpeg-based AV1 hardware encoding on NVIDIA GPUs (RTX 4000+) with quality-focused defaults including spatial/temporal AQ, lookahead, and multipass support
613
* Adding #724 "exit" option to the After Conversion dropdown, which closes FastFlix after all queue items complete (thanks to jrff123)
714
* Adding #731 OpenCL Support setting (Auto/Disable) with re-detection button in Application Locations settings (thanks to sks2012)
815
* Adding favicon to root of repo so it shows up on fastflix.org (thanks to Balthazar)
9-
* Adding encoding history feature with browsable history window, "Apply Last Used Settings" menu action, and startup opt-in prompt
16+
* Adding #689 encoding history feature with browsable history window, "Apply Last Used Settings" menu action, and startup opt-in prompt (thanks to Augusto7743)
1017
* Adding FFmpeg 8.0+ version check on startup with option to download latest FFmpeg on Windows
1118
* Adding "Keep source format" option to Audio Normalize, which detects and uses the same audio codec and bitrate as the source video
1219
* Adding Audio Encoders tab in Settings to view and select which FFmpeg audio encoders appear in audio codec dropdowns

fastflix/encoders/avc_x264/settings_panel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ def update_video_encoder_settings(self):
267267
extra=self.ffmpeg_extras,
268268
tune=tune if tune.lower() != "default" else None,
269269
extra_both_passes=self.widgets.extra_both_passes.isChecked(),
270-
bitrate_passes=int(self.widgets.bitrate_passes.currentText()),
270+
bitrate_passes=int(self.widgets.bitrate_passes.currentText() or 1),
271271
aq_mode=self.widgets.aq_mode.currentText(),
272272
psy_rd=psy_rd_text if psy_rd_text else None,
273273
level=self.widgets.level.currentText(),

fastflix/encoders/ffmpeg_av1_nvenc/settings_panel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ def update_video_encoder_settings(self):
302302
level=self.widgets.level.currentText() if self.widgets.level.currentIndex() != 0 else None,
303303
gpu=int(self.widgets.gpu.currentText() or -1) if self.widgets.gpu.currentIndex() != 0 else -1,
304304
b_ref_mode=self.widgets.b_ref_mode.currentText(),
305-
aq_strength=int(self.widgets.aq_strength.currentText()),
305+
aq_strength=int(self.widgets.aq_strength.currentText() or 8),
306306
tier=self.widgets.tier.currentText(),
307307
hw_accel=self.widgets.hw_accel.isChecked(),
308308
)

fastflix/encoders/hevc_x265/settings_panel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ def update_video_encoder_settings(self):
700700
lossless=self.widgets.lossless.isChecked(),
701701
extra=self.ffmpeg_extras,
702702
extra_both_passes=self.widgets.extra_both_passes.isChecked(),
703-
bitrate_passes=int(self.widgets.bitrate_passes.currentText()),
703+
bitrate_passes=int(self.widgets.bitrate_passes.currentText() or 1),
704704
# gop_size=int(self.widgets.gop_size.currentText()) if self.widgets.gop_size.currentIndex() > 0 else 0,
705705
)
706706

fastflix/flix.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,15 @@ def ffmpeg_configuration(app, config: Config, **_):
158158
"""Extract the version and libraries available from the specified version of FFmpeg"""
159159
res = execute([f"{config.ffmpeg}", "-version"])
160160
if res.returncode != 0:
161-
logger.error(f"{config.ffmpeg} command stdout: {res.stdout}")
162-
logger.error(f"{config.ffmpeg} command stderr: {res.stderr}")
163-
raise FlixError(f'"{config.ffmpeg}" file not found or errored while executing. Return code {res.returncode}')
161+
if not res.stdout or "ffmpeg version" not in res.stdout:
162+
logger.error(f"{config.ffmpeg} command stdout: {res.stdout}")
163+
logger.error(f"{config.ffmpeg} command stderr: {res.stderr}")
164+
raise FlixError(
165+
f'"{config.ffmpeg}" file not found or errored while executing. Return code {res.returncode}'
166+
)
167+
logger.warning(
168+
f"{config.ffmpeg} returned non-zero exit code {res.returncode} but produced valid output, continuing"
169+
)
164170
config = []
165171
try:
166172
version = res.stdout.split(" ", 4)[2]
@@ -187,7 +193,11 @@ def ffprobe_configuration(app, config: Config, **_):
187193
"""Extract the version of ffprobe"""
188194
res = execute([f"{config.ffprobe}", "-version"])
189195
if res.returncode != 0:
190-
raise FlixError(f'"{config.ffprobe}" file not found')
196+
if not res.stdout or "ffprobe version" not in res.stdout:
197+
raise FlixError(f'"{config.ffprobe}" file not found')
198+
logger.warning(
199+
f"{config.ffprobe} returned non-zero exit code {res.returncode} but produced valid output, continuing"
200+
)
191201
try:
192202
version = res.stdout.split(" ", 4)[2]
193203
except (ValueError, IndexError):
@@ -214,7 +224,9 @@ def probe(app: FastFlixApp, file: Path) -> Box:
214224
]
215225
result = execute(command)
216226
if result.returncode != 0:
217-
raise FlixError(f"Error code returned running FFprobe: {result.stdout} - {result.stderr}")
227+
if not result.stdout or not result.stdout.strip().startswith("{"):
228+
raise FlixError(f"Error code returned running FFprobe: {result.stdout} - {result.stderr}")
229+
logger.warning(f"FFprobe returned non-zero exit code {result.returncode} but produced output, continuing")
218230

219231
if result.stdout.strip() == "{}":
220232
raise FlixError(f"No output from FFprobe, not a known video type. stderr: {result.stderr}")

fastflix/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
3-
__version__ = "6.2.0"
3+
__version__ = "6.2.1"
44
__author__ = "Chris Griffith"

fastflix/widgets/container.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,43 @@ def __init__(self, app: FastFlixApp, **kwargs):
122122
# self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint)
123123
self.moveFlag = False
124124

125+
# Listen for display topology changes (monitors added/removed/reconfigured)
126+
gui_app = QtGui.QGuiApplication.instance()
127+
gui_app.screenAdded.connect(self._on_screen_change)
128+
gui_app.screenRemoved.connect(self._on_screen_change)
129+
gui_app.primaryScreenChanged.connect(self._on_screen_change)
130+
# Track geometry/DPI changes on all current screens
131+
for screen in gui_app.screens():
132+
self._connect_screen_signals(screen)
133+
gui_app.screenAdded.connect(self._connect_screen_signals)
134+
135+
def _connect_screen_signals(self, screen: QtGui.QScreen) -> None:
136+
"""Connect geometry/DPI change signals for a screen."""
137+
screen.geometryChanged.connect(self._on_screen_change)
138+
screen.availableGeometryChanged.connect(self._on_screen_change)
139+
screen.logicalDotsPerInchChanged.connect(self._on_screen_change)
140+
141+
def _on_screen_change(self, *_args) -> None:
142+
"""Handle display topology or geometry changes by re-validating window bounds."""
143+
logger.debug("Screen change detected, re-validating window geometry")
144+
# Use a short timer to coalesce rapid successive signals
145+
if not hasattr(self, "_screen_change_timer"):
146+
self._screen_change_timer = QtCore.QTimer(self)
147+
self._screen_change_timer.setSingleShot(True)
148+
self._screen_change_timer.setInterval(500)
149+
self._screen_change_timer.timeout.connect(self._apply_screen_change)
150+
self._screen_change_timer.start()
151+
152+
def _apply_screen_change(self) -> None:
153+
"""Apply window adjustments after a screen change."""
154+
screen = self._current_screen()
155+
if screen is None:
156+
return
157+
# Recalculate scale factors based on current window size
158+
scaler.calculate_factors(self.width(), self.height())
159+
self._update_scaled_styles()
160+
self.ensure_window_in_bounds()
161+
125162
def _current_screen(self) -> QtGui.QScreen:
126163
"""Return the screen the window center is on, falling back to primary."""
127164
screen = QtGui.QGuiApplication.screenAt(self.geometry().center())

fastflix/widgets/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,7 @@ def generate_output_filename(self):
16101610
video_settings = None
16111611
if video:
16121612
video_settings = video.video_settings
1613-
encoder_settings = video.video_settings.video_encoder_settings
1613+
encoder_settings = getattr(video_settings, "video_encoder_settings", None)
16141614

16151615
name = resolve_pre_encode_variables(
16161616
gen_string,

0 commit comments

Comments
 (0)