fix: transcode video for QMediaPlayer and force xcb platform
This commit is contained in:
1 parent
8c9270c432
commit
99bbc3e126
2 files changed
+65
-2
No files matched your search
@@ -84,7 +84,7 @@ sync:
|
||||
@if [ -x $(PY) ]; then $(PY) apply_sync.py --config $(CONFIG) --lag $(LAG); else python3 apply_sync.py --config $(CONFIG) --lag $(LAG); fi
|
||||
|
||||
verify:
|
||||
@if [ -x $(PY) ]; then QT_QPA_PLATFORM=xcb QT_STYLE_OVERRIDE=Fusion $(PY) verify_sync.py --config $(CONFIG) --lag $(LAG); else QT_QPA_PLATFORM=xcb QT_STYLE_OVERRIDE=Fusion python3 verify_sync.py --config $(CONFIG) --lag $(LAG); fi
|
||||
@if [ -x $(PY) ]; then QT_QPA_PLATFORM=xcb QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi QT_XCB_GL_INTEGRATION=xcb_egl QT_STYLE_OVERRIDE=Fusion $(PY) verify_sync.py --config $(CONFIG) --lag $(LAG); else QT_QPA_PLATFORM=xcb QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi QT_XCB_GL_INTEGRATION=xcb_egl QT_STYLE_OVERRIDE=Fusion python3 verify_sync.py --config $(CONFIG) --lag $(LAG); fi
|
||||
|
||||
ast:
|
||||
@AUDIO_A=$$(python3 -c "import tomllib; c=tomllib.load(open('config.toml','rb')); print(c['extract'].get('file_a',''))" 2>/dev/null); \
|
||||
@@ -100,7 +100,7 @@ ast:
|
||||
else \
|
||||
echo "=> extracted wavs exist ($$OUT/$${STEM_A}_audio.wav, $$OUT/$${STEM_B}_audio.wav), skipping extract"; \
|
||||
fi
|
||||
@if [ -x $(PY) ]; then QT_STYLE_OVERRIDE=Fusion $(PY) sync_audio_test.py --config $(CONFIG); else QT_STYLE_OVERRIDE=Fusion python3 sync_audio_test.py --config $(CONFIG); fi
|
||||
@if [ -x $(PY) ]; then QT_QPA_PLATFORM=xcb QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi QT_XCB_GL_INTEGRATION=xcb_egl QT_STYLE_OVERRIDE=Fusion $(PY) sync_audio_test.py --config $(CONFIG); else QT_QPA_PLATFORM=xcb QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi QT_XCB_GL_INTEGRATION=xcb_egl QT_STYLE_OVERRIDE=Fusion python3 sync_audio_test.py --config $(CONFIG); fi
|
||||
|
||||
clean:
|
||||
rm -rf $(VENV) __pycache__ .pytest_cache
|
||||
@@ -27,6 +27,13 @@ import numpy as np
|
||||
|
||||
warnings.filterwarnings("ignore", category=RuntimeWarning, module="pyqtgraph")
|
||||
|
||||
# Force X11/xcb on Wayland without EGL — QVideoWidget can't render without it
|
||||
for k, v in {"QT_QPA_PLATFORM": "xcb",
|
||||
"QT_STYLE_OVERRIDE": "Fusion",
|
||||
"QT_FFMPEG_DECODING_HW_DEVICE_TYPES": "vaapi",
|
||||
"QT_XCB_GL_INTEGRATION": "xcb_egl"}.items():
|
||||
os.environ.setdefault(k, v)
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ModuleNotFoundError:
|
||||
@@ -108,6 +115,28 @@ def extract_audio_from_mkv(mkv_path: str, stream_index: int, out_wav: str, sr: i
|
||||
return False
|
||||
|
||||
|
||||
def transcode_to_h264_sdr(src: str, dst: str, duration: float = 0) -> bool:
|
||||
"""Transcode video to H.264 SDR MP4 for QMediaPlayer compatibility.
|
||||
If duration > 0, only transcode that many seconds."""
|
||||
cmd = ["ffmpeg", "-y", "-i", src]
|
||||
if duration > 0:
|
||||
cmd += ["-t", f"{duration:.3f}"]
|
||||
cmd += [
|
||||
"-map", "0:v:0",
|
||||
"-an",
|
||||
"-c:v", "libx264", "-preset", "ultrafast", "-crf", "20",
|
||||
"-pix_fmt", "yuv420p",
|
||||
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
|
||||
"-movflags", "+faststart",
|
||||
dst,
|
||||
]
|
||||
try:
|
||||
r = subprocess.run(cmd, capture_output=True, timeout=600)
|
||||
return r.returncode == 0 and os.path.exists(dst)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def apply_lag(a: np.ndarray, b: np.ndarray, lag_samples: int) -> tuple[np.ndarray, np.ndarray]:
|
||||
if lag_samples >= 0:
|
||||
a_out = a[lag_samples:]
|
||||
@@ -621,6 +650,15 @@ def main():
|
||||
print(f"ERROR: wav B not found: {wav_b}", file=sys.stderr); sys.exit(1)
|
||||
|
||||
video_path = video_a
|
||||
# In short mode, use the extracted FFV1 video instead of the original HEVC source
|
||||
if args.mode == "short":
|
||||
stem = os.path.splitext(os.path.basename(video_a))[0]
|
||||
extracted_video = os.path.join(out_dir_extract, f"{stem}_video.mkv")
|
||||
if os.path.exists(extracted_video):
|
||||
video_path = extracted_video
|
||||
print(f"Using extracted video: {video_path}")
|
||||
else:
|
||||
print(f"WARNING: extracted video not found ({extracted_video}), using original", file=sys.stderr)
|
||||
temp_dir = None
|
||||
|
||||
print(f"Mode: {args.mode}")
|
||||
@@ -632,6 +670,31 @@ def main():
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
apply_dark_theme(app)
|
||||
|
||||
# Check if QMediaPlayer supports the video codec; only transcode if needed
|
||||
probe = QtMultimedia.QMediaPlayer()
|
||||
probe.setSource(QtCore.QUrl.fromLocalFile(os.path.abspath(video_path)))
|
||||
support = probe.support()
|
||||
del probe
|
||||
|
||||
if support != QtMultimedia.QMediaPlayer.Support.Supported:
|
||||
if not temp_dir:
|
||||
temp_dir = tempfile.mkdtemp(prefix="verify_sync_")
|
||||
preview_path = os.path.join(temp_dir, "preview.mp4")
|
||||
if not os.path.exists(preview_path):
|
||||
transcode_dur = 30.0 if args.mode == "short" else 0
|
||||
print(f"Codec not supported by QMediaPlayer (support={support.name}), "
|
||||
f"transcoding to H.264 SDR ({'%.1fs' % transcode_dur if transcode_dur else 'full'})...")
|
||||
if not transcode_to_h264_sdr(video_path, preview_path, transcode_dur):
|
||||
print(f"WARNING: transcode failed, using original video (may show black)", file=sys.stderr)
|
||||
else:
|
||||
video_path = preview_path
|
||||
print(f"Preview ready: {preview_path}")
|
||||
else:
|
||||
video_path = preview_path
|
||||
print(f"Using cached preview: {preview_path}")
|
||||
else:
|
||||
print(f"Codec supported by QMediaPlayer, using directly")
|
||||
|
||||
w = VerifyWindow(video_path, wav_a, wav_b, sr=sr, lag_sec=lag_sec,
|
||||
mode=args.mode, out_dir=out_dir, temp_dir=temp_dir,
|
||||
volume=volume)
|
||||
|
||||
Reference in new issue
Block a user