feat: mpv Wayland embedding, timeline redesign, UX polish
mpv embedding: - Replace wid/QOpenGLWidget with QOffscreenSurface + QOpenGLFramebufferObject + QPainter readback — works on Wayland/KDE without sub-surface compositing - Force desktop OpenGL 3.3 core profile before QApplication (fixes black output on GLES) - Timer-based render polling (16 ms) replaces signal-flood from mpv C thread; fixes playback animation and scrubbing preview - Fix AB-loop: set ab-loop-a/b to "no" on stop (0 means infinite in mpv) Timeline: - Full redesign: time ruler with adaptive major/minor ticks, playhead triangle handle, selection region with edge lines, numbered marker badges - Height 160 px; layout collapsed from 4 rows to 2 below timeline - Markers appear immediately on export (optimistic update before ffmpeg finishes) - Right-click marker → context menu to delete from DB Hotkeys: - Replace keyPressEvent with QShortcut(ApplicationShortcut) so keys work regardless of focused widget; MpvWidget gets NoFocus policy Export: - WebP: switch lossless→lossy quality 85, compression_level 1 (~10x faster) - Add -threads 0 for full CPU utilisation during decode/filter - Remember last export folder across sessions via QSettings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# 8-cut Design
|
||||
|
||||
## Overview
|
||||
|
||||
A Linux desktop tool for dropping a video clip, setting a start point on a timeline, and exporting exactly 8 seconds to a numbered output file.
|
||||
|
||||
## Stack
|
||||
|
||||
- **Python + PyQt6** — native desktop window, drag & drop, custom timeline widget
|
||||
- **python-mpv** — embedded video playback with audio, frame-accurate seeking, AB loop for 8s preview
|
||||
- **ffmpeg** — export via subprocess, always re-encodes to guarantee exactly 8s with no freeze frames
|
||||
|
||||
## Layout
|
||||
|
||||
Single window, top to bottom:
|
||||
|
||||
1. Drop zone / loaded file path display
|
||||
2. mpv video embed (preview)
|
||||
3. Custom timeline widget with draggable cursor
|
||||
4. Playback controls + cursor position display
|
||||
5. Export controls: base name input, folder picker, next filename preview, Export button
|
||||
|
||||
## Behavior
|
||||
|
||||
- **Drag & drop** a video file onto the window to load it
|
||||
- **Timeline**: click or drag to reposition cursor; shows current frame when paused
|
||||
- **Play 8s**: mpv seeks to cursor position, plays 8 seconds, loops back using mpv AB-loop (`ab-loop-a` = cursor, `ab-loop-b` = cursor + 8s)
|
||||
- **Pause**: shows current frame at cursor position
|
||||
- **Export**: runs ffmpeg in a QThread (non-blocking UI)
|
||||
- Command: `ffmpeg -ss {start} -i {input} -t 8 -c:v libx264 -c:a aac {output}`
|
||||
- Output: `{folder}/{basename}_{NNN:03d}.mp4`
|
||||
- Counter auto-increments after each successful export
|
||||
- Counter resets if base name or folder changes
|
||||
|
||||
## Architecture
|
||||
|
||||
Single file `main.py` (~300-400 lines):
|
||||
|
||||
- `MainWindow(QMainWindow)` — owns all state: file path, cursor (seconds), base name, output folder, export counter
|
||||
- `TimelineWidget(QWidget)` — custom `paintEvent` draws bar + cursor line; `mousePressEvent`/`mouseMoveEvent` for scrubbing
|
||||
- `MpvWidget(QWidget)` — embeds mpv using window ID (`wid`), exposes `load(path)`, `seek(t)`, `play_loop(a, b)`, `pause()`
|
||||
- `ExportWorker(QThread)` — runs ffmpeg subprocess, emits `finished(path)` or `error(msg)` signal
|
||||
|
||||
## Export guarantees
|
||||
|
||||
Always re-encode (never stream copy) to avoid freeze frames caused by keyframe misalignment at the cut point. Output is always exactly 8.000 seconds.
|
||||
Reference in New Issue
Block a user