[PR #1852] [MERGED] fix(hevc): Add HEVC/H.265 caption extraction support with B-frame reordering #2614

Open
opened 2026-01-29 17:23:05 +00:00 by claunia · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/CCExtractor/ccextractor/pull/1852
Author: @cfsmp3
Created: 12/19/2025
Status: Merged
Merged: 12/20/2025
Merged by: @cfsmp3

Base: masterHead: fix/issue-1690-hevc-caption-extraction


📝 Commits (5)

  • 0fbbc06 fix(hevc): Add HEVC/H.265 caption extraction support
  • 440cd55 fix(hevc): Fix garbled captions by implementing B-frame reordering
  • 87bc1d9 style: Fix clang-format issue in ts_functions.c
  • 9e970fd style: Run cargo fmt on avc/core.rs
  • 1bdd9ab fix(clippy): Suppress dead_code warnings for unused HEVC NAL constants

📊 Changes

10 files changed (+371 additions, -117 deletions)

View changed files

📝 src/lib_ccx/avc_functions.c (+80 -33)
📝 src/lib_ccx/avc_functions.h (+1 -0)
📝 src/lib_ccx/ccx_common_constants.h (+2 -1)
📝 src/lib_ccx/general_loop.c (+7 -0)
📝 src/lib_ccx/ts_functions.c (+24 -7)
📝 src/lib_ccx/ts_info.c (+3 -1)
📝 src/rust/src/avc/common_types.rs (+2 -0)
📝 src/rust/src/avc/core.rs (+250 -75)
📝 src/rust/src/common.rs (+1 -0)
📝 src/rust/src/ctorust.rs (+1 -0)

📄 Description

Summary

Fixes #1690 - Captions fail to extract on HEVC video stream
Fixes #1639 - CCextractor not finding 608 captions in ATSC3.0 TS (garbled output)

HEVC (H.265) video streams with embedded EIA-608/708 captions weren't being extracted correctly. VLC/MPV could display them, but CCExtractor either failed to find them or produced garbled output.

Root Causes Fixed

  1. HEVC stream type (0x24) wasn't recognized for CC extraction in TS demuxer
  2. HEVC NAL parsing used H.264 format (1-byte header) instead of HEVC format (2-byte header)
  3. HEVC SEI types (39/40) weren't handled - only H.264 SEI type 6 was recognized
  4. CC data accumulation across SEIs caused u8 overflow and garbled output
  5. B-frame reordering not implemented for HEVC - CC data was processed in decode order instead of presentation order, scrambling character pairs

Issue #1639 Deep Dive - B-Frame Reordering

The ATSC 3.0 sample from issue #1639 exposed a critical problem: HEVC uses B-frames extensively, and CC data embedded in SEI NAL units was being processed in decode order instead of presentation order.

Evidence from the sample file:

  • Raw GA94 data (decode order): " BOTH OF MIOEDCRE WNDOHE TRESTH.TCL WWEILATE SEWHNSAP HPE IGAN ME..."
  • Correct text (presentation order): "COME BOTH OF MEDIOCRE DOWN THE STRETCH. WE WILL SEE WHAT HAPPENS IN GAME NUMBER ONE TONIGHT"

The same characters were present but scrambled due to B-frame reordering.

Before fix:

STH.TC
L  WWEILATE SEWHNSAP HPE IGAN ME

After fix:

STRETCH.
WE WILL SEE WHAT HAPPENS IN GAME
NUMBER ONE TONIGHT

Changes

C Code:

  • ts_info.c: Include HEVC (0x24) in video stream detection
  • ts_functions.c: Add CCX_HEVC buffer type handling, HEVC NAL type detection for streams without PAT/PMT (VPS=32, SPS=33, PPS=34, PREFIX_SEI=39, SUFFIX_SEI=40, IDR=19,20, CRA=21)
  • ccx_common_constants.h: Add CCX_HEVC = 11 buffer type
  • general_loop.c: Handle CCX_HEVC and set is_hevc flag
  • avc_functions.h: Add is_hevc field to avc_ctx

Rust Code (src/rust/src/avc/core.rs):

  • HEVC NAL header parsing: 2 bytes, type = (byte[0] >> 1) & 0x3F
  • HEVC SEI types: PREFIX_SEI (39), SUFFIX_SEI (40)
  • HEVC parameter sets (VPS=32, SPS=33, PPS=34) enable SEI processing
  • PTS-based sequence numbering for B-frame reordering (similar to H.264's pts_ordering_mode):
    let pts_diff = current_pts - currefpts;
    let fps_factor = MPEG_CLOCK_FREQ / current_fps;
    let calculated_index = round(2.0 * pts_diff / fps_factor);
    
  • IDR-based flush - only flush CC buffer on IDR frames (NAL types 19, 20) instead of every VCL NAL, allowing proper reordering across GOP
  • Process and flush CC data immediately per SEI for non-B-frame content
  • Reset cc_count to 0 per SEI but preserve cc_data vector length

Test Results

Issue #1690 sample file - now extracts 329 lines of clean, readable captions:

1
00:00:02,620 --> 00:00:04,486
in the blink of an eye!         

2
00:00:04,488 --> 00:00:08,157
       Now that you know,       
 we can use the built-up power. 

Issue #1639 sample file - garbled output now displays correctly:

STRETCH.
WE WILL SEE WHAT HAPPENS IN GAME
NUMBER ONE TONIGHT

Acknowledgments

Thanks to @trufio465-bot for the initial research direction in PR #1735. While that PR was incomplete, it helped identify the key areas that needed modification.

Test plan

  • Tested with sample file from issue #1690 - captions now extract correctly
  • Tested with sample file from issue #1639 - garbled captions now display correctly
  • CI regression tests should pass
  • Manual verification that existing H.264 caption extraction still works

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/CCExtractor/ccextractor/pull/1852 **Author:** [@cfsmp3](https://github.com/cfsmp3) **Created:** 12/19/2025 **Status:** ✅ Merged **Merged:** 12/20/2025 **Merged by:** [@cfsmp3](https://github.com/cfsmp3) **Base:** `master` ← **Head:** `fix/issue-1690-hevc-caption-extraction` --- ### 📝 Commits (5) - [`0fbbc06`](https://github.com/CCExtractor/ccextractor/commit/0fbbc06bcfc3ec1242791ccb0bfafc76c9408ce1) fix(hevc): Add HEVC/H.265 caption extraction support - [`440cd55`](https://github.com/CCExtractor/ccextractor/commit/440cd5527f3bf68248368d511227d609b81a3011) fix(hevc): Fix garbled captions by implementing B-frame reordering - [`87bc1d9`](https://github.com/CCExtractor/ccextractor/commit/87bc1d96132d36fb7c6321e2e6627db307437088) style: Fix clang-format issue in ts_functions.c - [`9e970fd`](https://github.com/CCExtractor/ccextractor/commit/9e970fd788842263f68806b0b6848286b31c5196) style: Run cargo fmt on avc/core.rs - [`1bdd9ab`](https://github.com/CCExtractor/ccextractor/commit/1bdd9abd356f9ae9dcf9c18a52722630580af743) fix(clippy): Suppress dead_code warnings for unused HEVC NAL constants ### 📊 Changes **10 files changed** (+371 additions, -117 deletions) <details> <summary>View changed files</summary> 📝 `src/lib_ccx/avc_functions.c` (+80 -33) 📝 `src/lib_ccx/avc_functions.h` (+1 -0) 📝 `src/lib_ccx/ccx_common_constants.h` (+2 -1) 📝 `src/lib_ccx/general_loop.c` (+7 -0) 📝 `src/lib_ccx/ts_functions.c` (+24 -7) 📝 `src/lib_ccx/ts_info.c` (+3 -1) 📝 `src/rust/src/avc/common_types.rs` (+2 -0) 📝 `src/rust/src/avc/core.rs` (+250 -75) 📝 `src/rust/src/common.rs` (+1 -0) 📝 `src/rust/src/ctorust.rs` (+1 -0) </details> ### 📄 Description ## Summary Fixes #1690 - Captions fail to extract on HEVC video stream Fixes #1639 - CCextractor not finding 608 captions in ATSC3.0 TS (garbled output) HEVC (H.265) video streams with embedded EIA-608/708 captions weren't being extracted correctly. VLC/MPV could display them, but CCExtractor either failed to find them or produced garbled output. ### Root Causes Fixed 1. **HEVC stream type (0x24) wasn't recognized** for CC extraction in TS demuxer 2. **HEVC NAL parsing used H.264 format** (1-byte header) instead of HEVC format (2-byte header) 3. **HEVC SEI types (39/40) weren't handled** - only H.264 SEI type 6 was recognized 4. **CC data accumulation** across SEIs caused u8 overflow and garbled output 5. **B-frame reordering not implemented for HEVC** - CC data was processed in decode order instead of presentation order, scrambling character pairs ### Issue #1639 Deep Dive - B-Frame Reordering The ATSC 3.0 sample from issue #1639 exposed a critical problem: HEVC uses B-frames extensively, and CC data embedded in SEI NAL units was being processed in **decode order** instead of **presentation order**. **Evidence from the sample file:** - Raw GA94 data (decode order): `" BOTH OF MIOEDCRE WNDOHE TRESTH.TCL WWEILATE SEWHNSAP HPE IGAN ME..."` - Correct text (presentation order): `"COME BOTH OF MEDIOCRE DOWN THE STRETCH. WE WILL SEE WHAT HAPPENS IN GAME NUMBER ONE TONIGHT"` The same characters were present but scrambled due to B-frame reordering. **Before fix:** ``` STH.TC L WWEILATE SEWHNSAP HPE IGAN ME ``` **After fix:** ``` STRETCH. WE WILL SEE WHAT HAPPENS IN GAME NUMBER ONE TONIGHT ``` ### Changes **C Code:** - `ts_info.c`: Include HEVC (0x24) in video stream detection - `ts_functions.c`: Add `CCX_HEVC` buffer type handling, HEVC NAL type detection for streams without PAT/PMT (VPS=32, SPS=33, PPS=34, PREFIX_SEI=39, SUFFIX_SEI=40, IDR=19,20, CRA=21) - `ccx_common_constants.h`: Add `CCX_HEVC = 11` buffer type - `general_loop.c`: Handle `CCX_HEVC` and set `is_hevc` flag - `avc_functions.h`: Add `is_hevc` field to `avc_ctx` **Rust Code (`src/rust/src/avc/core.rs`):** - HEVC NAL header parsing: 2 bytes, type = `(byte[0] >> 1) & 0x3F` - HEVC SEI types: PREFIX_SEI (39), SUFFIX_SEI (40) - HEVC parameter sets (VPS=32, SPS=33, PPS=34) enable SEI processing - **PTS-based sequence numbering** for B-frame reordering (similar to H.264's `pts_ordering_mode`): ```rust let pts_diff = current_pts - currefpts; let fps_factor = MPEG_CLOCK_FREQ / current_fps; let calculated_index = round(2.0 * pts_diff / fps_factor); ``` - **IDR-based flush** - only flush CC buffer on IDR frames (NAL types 19, 20) instead of every VCL NAL, allowing proper reordering across GOP - Process and flush CC data immediately per SEI for non-B-frame content - Reset `cc_count` to 0 per SEI but preserve `cc_data` vector length ### Test Results **Issue #1690 sample file** - now extracts 329 lines of clean, readable captions: ``` 1 00:00:02,620 --> 00:00:04,486 in the blink of an eye! 2 00:00:04,488 --> 00:00:08,157 Now that you know, we can use the built-up power. ``` **Issue #1639 sample file** - garbled output now displays correctly: ``` STRETCH. WE WILL SEE WHAT HAPPENS IN GAME NUMBER ONE TONIGHT ``` ## Acknowledgments Thanks to @trufio465-bot for the initial research direction in PR #1735. While that PR was incomplete, it helped identify the key areas that needed modification. ## Test plan - [x] Tested with sample file from issue #1690 - captions now extract correctly - [x] Tested with sample file from issue #1639 - garbled captions now display correctly - [ ] CI regression tests should pass - [ ] Manual verification that existing H.264 caption extraction still works 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
claunia added the pull-request label 2026-01-29 17:23:05 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/ccextractor#2614