Version 1 OneShot
This commit is contained in:
108
README.md
108
README.md
@@ -0,0 +1,108 @@
|
||||
# FFmpeg Wrapper
|
||||
|
||||
A desktop GUI for common ffmpeg jobs: remuxing MKV files to Jellyfin-friendly MP4s, choosing which
|
||||
audio tracks to keep, stripping audio, re-encoding, and scaling. Works on single files or whole batches.
|
||||
It's a single executable for Windows and Linux, built with Python, Qt (PySide6) and PyInstaller.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- **Single file or batch.** Use *Add Files*, *Add Folder* (recursive), or drag and drop. Files are
|
||||
probed in the background and shown with duration, video info, and audio and subtitle counts.
|
||||
- **Target container.** MP4, MKV, MOV, M4V, WebM, AVI or MPEG-TS. The encoder lists only show codecs
|
||||
the chosen container can hold.
|
||||
- **Audio track picker.** Every audio track in the selected file is listed with its language, codec,
|
||||
channels and title. Tick the tracks you want and drag them into order. The first ticked track
|
||||
becomes the default. **Apply to All Files** copies your choice to the rest of the queue,
|
||||
matching tracks by language, codec and layout, so a season of episodes takes one click.
|
||||
- **Strip audio.** Set Audio mode to *Strip audio*.
|
||||
- **Keep streams unaltered.** *Copy* mode remuxes video and/or audio without re-encoding. *Auto*
|
||||
copies whatever the container supports and re-encodes only what it can't hold (for example
|
||||
DTS/TrueHD to AAC for MP4).
|
||||
- **Up/downscale video.** Pick 360p up to 8K, or a custom WxH, with aspect ratio kept and Lanczos
|
||||
scaling. Portrait and rotated phone videos are handled. You can also change the frame rate.
|
||||
Encoders: H.264, HEVC, AV1, VP9, MPEG-4, plus NVENC, QuickSync and AMF if your ffmpeg has them.
|
||||
There are CRF quality and speed preset controls.
|
||||
- **Up/downmix audio.** Change channels (mono, stereo, 5.1, 7.1), sample rate, bitrate, and codec
|
||||
(AAC, AC-3, E-AC-3, Opus, MP3, Vorbis, FLAC, ALAC, PCM).
|
||||
- **Output folder.** Save next to the source or in a chosen folder. You can add a filename suffix
|
||||
and choose what happens when the output file already exists (keep both, overwrite, or skip).
|
||||
The source file is never overwritten.
|
||||
- **Subtitles** are kept where possible. MP4 and MOV turn text subs into `mov_text`, and image subs
|
||||
(PGS) are dropped with a note in the log. MKV keeps everything, including font attachments.
|
||||
- MP4/MOV outputs get `+faststart`, and HEVC is tagged `hvc1` for Apple and TV compatibility.
|
||||
- The window shows per-file and overall progress, has a **Stop** button, and keeps a full log.
|
||||
**Show Command** prints the exact ffmpeg command so you can copy it.
|
||||
- ffmpeg writes to `name.part.ext` and the file is renamed only on success, so a failed or
|
||||
cancelled job never leaves a half-written file.
|
||||
|
||||
## Getting ffmpeg
|
||||
|
||||
The app looks for `ffmpeg` and `ffprobe` in this order:
|
||||
|
||||
1. The folder set in **Settings > Set FFmpeg Location...**
|
||||
2. Next to the executable (or in `ffmpeg/`, `ffmpeg/bin/` or `bin/` beside it)
|
||||
3. Your `PATH`
|
||||
|
||||
The release archives (`FFmpegWrapper-<version>-windows-x64.zip` / `-linux-x64.tar.gz`) already
|
||||
include ffmpeg and ffprobe next to the executable. If you use the bare executable, install ffmpeg
|
||||
(`sudo apt install ffmpeg`, `winget install ffmpeg`, ...) or point the app at it.
|
||||
|
||||
## Running from source
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
.venv/bin/pip install -r requirements-dev.txt # Windows: .venv\Scripts\pip ...
|
||||
python scripts/fetch_ffmpeg.py # optional: downloads ffmpeg into ./ffmpeg/bin
|
||||
python run.py
|
||||
```
|
||||
|
||||
Tests: `python -m pytest`. The integration tests run real conversions when ffmpeg is found, either
|
||||
on `PATH` or through `FFWRAP_FFMPEG_DIR=ffmpeg/bin`.
|
||||
|
||||
## Building the executables
|
||||
|
||||
PyInstaller does not cross-compile. Build the Windows `.exe` on Windows and the Linux binary on Linux.
|
||||
|
||||
```bash
|
||||
pip install -r requirements-dev.txt
|
||||
python build.py # -> dist/FFmpegWrapper or dist/FFmpegWrapper.exe
|
||||
python build.py --ffmpeg-dir ffmpeg/bin # also bundles ffmpeg + ffprobe into a .zip / .tar.gz
|
||||
python scripts/smoke_test.py dist/FFmpegWrapper # optional: headless start-up check
|
||||
```
|
||||
|
||||
`--onedir` builds a folder instead of a single file. It starts faster because nothing has to be
|
||||
unpacked on launch.
|
||||
|
||||
**CI:** [.github/workflows/build.yml](.github/workflows/build.yml) builds, tests and smoke-tests both
|
||||
platforms on every `v*` tag (or a manual run) and attaches the archives to the release. Gitea and
|
||||
Forgejo Actions can run it too, but they need a Windows runner registered.
|
||||
|
||||
### Notes
|
||||
|
||||
- **Linux:** the binary needs glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+,
|
||||
Mint 21+). It bundles the Qt XCB libraries, but uses the system's OpenGL/EGL driver libraries.
|
||||
To get a menu entry, copy `assets/icon.png` and write a `.desktop` file that points at the binary.
|
||||
- **PySide6 is pinned below 6.12.** PySide6 6.12.0 mis-counts references to Python's `None`
|
||||
(in `QComboBox.clear()`/`currentData()`), which crashes the app on Python 3.11. Python 3.12+ is
|
||||
not affected, but keep the pin until a fixed PySide6 ships.
|
||||
- **Licensing:** the bundled ffmpeg builds come from
|
||||
[BtbN/FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds) and are GPL. Keep that in mind if you
|
||||
redistribute the archives.
|
||||
- Settings (last options, window size, ffmpeg location) are saved per user through Qt's QSettings:
|
||||
the registry on Windows, `~/.config/ffwrap/FFmpegWrapper.conf` on Linux.
|
||||
|
||||
## Project layout
|
||||
|
||||
```
|
||||
ffwrap/
|
||||
formats.py container/encoder tables and compatibility rules (no Qt)
|
||||
probe.py ffprobe -> MediaInfo/Stream dataclasses
|
||||
command.py Options -> ffmpeg arguments, output naming, audio-track matching (no Qt)
|
||||
tools.py locating ffmpeg/ffprobe, encoder detection
|
||||
gui/ main window, queue model, QProcess batch runner
|
||||
build.py PyInstaller build + packaging
|
||||
scripts/ fetch_ffmpeg.py, smoke_test.py, make_icon.py
|
||||
tests/ unit tests + real-ffmpeg integration tests
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user