save_sub_track() was missing two things:
1. No check on the return value of open(). If open() failed,
desc would be -1, and the subsequent write_wrapped() calls
would trigger a fatal error with a confusing message.
2. The file descriptor was never closed at the end of the function,
leaking it on every call. The neighboring save_vobsub_track()
already handles both correctly — this brings save_sub_track()
in line with it.
In save_sub_track(), the length argument for writing timestamp_end
was incorrectly using strlen(timestamp_start) instead of
strlen(timestamp_end). This affected WebVTT, SRT, and ASS/SSA
output paths for Matroska subtitle extraction.
The --mkvlang option previously only supported single ISO 639-2 codes
due to using a Language enum with a fixed list of variants. Extended
codes (like "fre-ca") and multiple codes (like "eng,chi") would panic.
This change introduces MkvLangFilter, a proper type for language
filtering that:
- Validates language codes per BCP 47 specification
- Supports ISO 639-2 (3-letter codes like "eng")
- Supports BCP 47 tags (like "en-US", "zh-Hans-CN")
- Supports comma-separated multiple codes
- Provides clean error messages for invalid input
- Includes comprehensive unit tests
The C code continues to receive the raw string for strstr() matching,
maintaining backward compatibility.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update version number across all packaging and build files for the
0.96.5 release.
Files updated:
- docs/CHANGES.TXT - Added changelog entry
- src/lib_ccx/lib_ccx.h - VERSION define
- linux/configure.ac - AC_INIT version
- mac/configure.ac - AC_INIT version
- OpenBSD/Makefile - V variable
- package_creators/PKGBUILD - pkgver
- package_creators/ccextractor.spec - Version
- package_creators/debian.sh - VERSION
- packaging/chocolatey/ccextractor.nuspec - version
- packaging/chocolatey/tools/chocolateyInstall.ps1 - URL
- packaging/winget/*.yaml - PackageVersion and URLs
Note: SHA256 checksums in chocolatey and winget files will need to be
updated after the MSI is built.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document all changes since 0.96.2 including:
- VOBSUB subtitle extraction for MP4 and MKV files
- Native SCC input file support
- SCC output improvements (frame rate, styled PAC codes)
- Various bug fixes for timing, builds, and OCR
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add docs/VOBSUB.md explaining the VOBSUB extraction workflow
- Add tools/vobsubocr/Dockerfile for building subtile-ocr OCR tool
- Document how to convert VOBSUB (.idx/.sub) to SRT using OCR
The Dockerfile uses subtile-ocr (https://github.com/gwen-lg/subtile-ocr),
an actively maintained fork of vobsubocr with better accuracy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Start new changelog section for unreleased changes. First entry is
the multi-page teletext extraction feature (#665) which allows
extracting multiple teletext pages simultaneously with separate
output files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move all changes made after the 0.95 version bump (commit ee232b5)
to a new 0.96 section marked as "Unreleased".
This separates the released 0.95 content from ongoing development
work that will be included in the next release.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes#1173 - Error in ./configure enabling hardsubx on Mac
Fixes#1306 - Add HARDSUBX compilation docs for macOS
The configure.ac script failed on macOS with "binary operator expected"
because pkg-config output was unquoted. When pkg-config returns multiple
libraries (e.g., "-ltesseract -lcurl"), the unquoted expansion caused
`test ! -z` to receive multiple arguments instead of a single string.
Changes:
- Quote pkg-config output in TESSERACT_PRESENT conditional (mac & linux)
- Add macOS section to docs/HARDSUBX.txt with all build methods
- Add GitHub Actions jobs to test HARDSUBX builds on macOS:
- build_shell_hardsubx: Tests ./build.command -hardsubx
- build_autoconf_hardsubx: Tests ./configure --enable-hardsubx
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a new --list-tracks (-L) option that lists all tracks found in
media files without processing them. This is useful for exploring
media files before caption extraction.
Supports:
- Matroska (MKV/WebM) files
- MP4/MOV files
- MPEG Transport Stream files
The feature is implemented entirely in Rust with native parsers for
each format, avoiding dependency on external libraries.
Closes#1669🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add changelog entries for recent merged PRs:
- Fix: Garbled captions from HDHomeRun and I/P-only H.264 streams (#1109)
- Fix: Enable stdout output for CEA-708 captions on Windows (#1693)
- Fix: McPoodle DVD raw format read/write (#1524)
- Fix: Variable shadowing in general_loop
- Fix: Double-free crash in teletext cleanup
- Fix: Uninitialized memory and memory leaks (Valgrind)
- Fix: Dangling pointers in Rust FFI
- New: Teletext subtitle pages in -out=report (#1034)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(dvb): Multiple fixes for DVB subtitle extraction from Chinese broadcasts (#224)
This commit addresses multiple issues with DVB subtitle extraction reported in #224:
1. **PMT parsing crash fix** (ts_tables.c):
- Added minimum length check (16 bytes) to prevent out-of-bounds access
- Added bounds check before memcpy to prevent buffer overflow when section > 1021 bytes
2. **Negative subtitle timing fix** (general_loop.c):
- For DVB subtitle streams, properly initialize min_pts from audio/subtitle PTS
- This fixes the issue where all timestamps were negative (~95000 seconds off)
3. **OCR improvements** (ocr.c):
- Fixed ignore_alpha_at_edge() which could create invalid crop windows
- Added image inversion for DVB subtitles (light text on dark background)
to improve Tesseract OCR accuracy
- Added contrast normalization to further improve character recognition
- Fixed nofontcolor check to respect --no-fontcolor parameter
- Added iteration safety limit in color detection loop
4. **--ocrlang parameter fix** (Rust files):
- Changed ocrlang from Language enum to String to accept Tesseract language
names directly (e.g., "chi_tra", "chi_sim", "eng")
- Added case-insensitive matching for --dvblang parameter
- Added better error messages for invalid language codes
Tested with 12GB Chinese DVB broadcast file:
- Timing: All timestamps now positive (0.235s, 2.594s, etc.)
- OCR: ~80-90% accuracy with chi_tra traineddata (improved from ~70%)
- No crashes during full file processing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ocr): Fix crashes in DVB subtitle color detection
Two issues fixed in the OCR color detection code:
1. Tesseract crash during iteration:
- The color detection pass used raw color images without preprocessing
- Tesseract expects dark text on light background, but DVB subtitles
have light text on dark background
- Added grayscale conversion, inversion, and contrast enhancement
(same preprocessing as the main OCR pass)
2. Heap corruption in histogram calculation:
- The histogram loop had no bounds checking on array accesses
- Tesseract could return invalid bounding boxes causing buffer overflows
- Added validation of bounding box coordinates before processing
- Added safe index checking for copy->data and histogram arrays
Also added skip_color_detection label for clean error handling and
proper cleanup of the preprocessed image.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(dvb): Fix zero-duration subtitles and overlaps during PTS jumps
Add start_pts field to cc_subtitle struct to track raw PTS values
independent of FTS timeline resets. Modify end_time calculation in
dvbsub_handle_display_segment() to cap duration at 4 seconds when
PTS jumps cause timeline discontinuities, preventing zero-duration
and overlapping subtitles.
Also update .gitignore to exclude plans/ directory and temp files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>