[PR #1915] [MERGED] fix(mp4): Fix 200ms timing offset for MOV/MP4 caption extraction #2707

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

📋 Pull Request Information

Original PR: https://github.com/CCExtractor/ccextractor/pull/1915
Author: @cfsmp3
Created: 12/27/2025
Status: Merged
Merged: 12/28/2025
Merged by: @cfsmp3

Base: masterHead: fix/mp4-mov-200ms-timing-offset


📝 Commits (1)

  • c061026 fix(mp4): Fix 200ms timing offset for MOV/MP4 caption extraction

📊 Changes

1 file changed (+19 additions, -0 deletions)

View changed files

📝 src/lib_ccx/mp4.c (+19 -0)

📄 Description

Summary

This PR fixes a 200ms timing offset that was affecting caption extraction from MOV/MP4 files, causing sample platform tests 226-230 to fail.

Before fix:

  • FFmpeg first caption: 13,847ms
  • CCExtractor first caption: 14,047ms
  • Offset: 200ms late

After fix:

  • FFmpeg first caption: 13,847ms
  • CCExtractor first caption: 13,847ms
  • Offset: 0ms (exact match)

Root Cause Analysis

The Bug

The in_bufferdatatype variable was never set in mp4.c for MP4/MOV container tracks. It remained at its default value CCX_UNKNOWN, which caused incorrect behavior in the caption processing pipeline.

How in_bufferdatatype Affects Timing

In src/lib_ccx/ccx_decoders_common.c, the do_cb() function has a check (lines 150-154):

// For container formats (H.264, MPEG-2 PES), don't increment cb_field
// because the frame PTS already represents the correct timestamp.
// The cb_field offset is only meaningful for raw/elementary streams.
if (ctx->in_bufferdatatype != CCX_H264 && ctx->in_bufferdatatype != CCX_PES)
    cb_field1++;

This check is designed to skip cb_field counter increments for container formats. However, with in_bufferdatatype == CCX_UNKNOWN, this condition evaluated to true, causing cb_field1 to be incremented for every CEA-608 caption block.

The Timing Math

When get_fts() is called to timestamp captions, it calculates:

fts_now + fts_global + cb_field1 * 1001 / 30

The cb_field1 * 1001/30 term adds ~33.37ms per caption block. With a typical roll-up caption having ~6 blocks per frame:

6 blocks × 33.37ms/block ≈ 200ms offset

This explains the consistent 200ms timing offset observed in MOV/MP4 files.

Why Container Formats Don't Need cb_field

For container formats (MP4, MOV, MKV, TS with PES), all caption data for a video frame is bundled together and associated with the frame's PTS. The caption blocks within a frame don't have sub-frame timing - they all belong to the same presentation timestamp.

In contrast, raw/elementary streams may have caption data arriving at field rate (59.94 Hz for NTSC), where each CEA-608 byte pair has its own timing. The cb_field offset accounts for this sub-frame timing.

The Fix

Set in_bufferdatatype correctly in the three MP4 track processing functions:

Function Track Type Setting
process_avc_track() H.264/AVC CCX_H264
process_hevc_track() H.265/HEVC CCX_H264
process_xdvb_track() MPEG-2 CCX_PES

Verification

Test Sample

/home/cfsmp3/media_samples/completed/1974a299f0502fc8199dabcaadb20e422e79df45972e554d58d1d025ef7d0686.mov

Before Fix (ttxt output)

00:00:14,047|00:00:14,547|RU2|>> WHICH OF THESE STORIES WILL
00:00:14,547|00:00:15,948|RU2|YOU BE TALKING ABOUT TOMORROW?

After Fix (ttxt output)

00:00:13,847|00:00:14,547|RU2|>> WHICH OF THESE STORIES WILL
00:00:14,547|00:00:15,248|RU2|YOU BE TALKING ABOUT TOMORROW?

FFmpeg Reference

1
00:00:13,847 --> 00:00:14,548
>> WHICH OF THESE STORIES WILL

The fix aligns CCExtractor's output exactly with FFmpeg's authoritative timing.

Regression Check

Verified that TS files still work correctly with the same timing (no regressions introduced).

Test Plan

  • Verify MOV file timing matches FFmpeg (13,847ms)
  • Verify TS files still work correctly (no regressions)
  • Run sample platform regression tests for tests 226-230
  • Verify HEVC MP4 files (if samples available)

Files Changed

  • src/lib_ccx/mp4.c - Set in_bufferdatatype in 3 track processing functions

🤖 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/1915 **Author:** [@cfsmp3](https://github.com/cfsmp3) **Created:** 12/27/2025 **Status:** ✅ Merged **Merged:** 12/28/2025 **Merged by:** [@cfsmp3](https://github.com/cfsmp3) **Base:** `master` ← **Head:** `fix/mp4-mov-200ms-timing-offset` --- ### 📝 Commits (1) - [`c061026`](https://github.com/CCExtractor/ccextractor/commit/c06102678e9ed24b319e51bea766e83536ed0329) fix(mp4): Fix 200ms timing offset for MOV/MP4 caption extraction ### 📊 Changes **1 file changed** (+19 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `src/lib_ccx/mp4.c` (+19 -0) </details> ### 📄 Description ## Summary This PR fixes a 200ms timing offset that was affecting caption extraction from MOV/MP4 files, causing sample platform tests 226-230 to fail. **Before fix:** - FFmpeg first caption: 13,847ms - CCExtractor first caption: 14,047ms - **Offset: 200ms late** **After fix:** - FFmpeg first caption: 13,847ms - CCExtractor first caption: 13,847ms - **Offset: 0ms (exact match)** ## Root Cause Analysis ### The Bug The `in_bufferdatatype` variable was never set in `mp4.c` for MP4/MOV container tracks. It remained at its default value `CCX_UNKNOWN`, which caused incorrect behavior in the caption processing pipeline. ### How `in_bufferdatatype` Affects Timing In `src/lib_ccx/ccx_decoders_common.c`, the `do_cb()` function has a check (lines 150-154): ```c // For container formats (H.264, MPEG-2 PES), don't increment cb_field // because the frame PTS already represents the correct timestamp. // The cb_field offset is only meaningful for raw/elementary streams. if (ctx->in_bufferdatatype != CCX_H264 && ctx->in_bufferdatatype != CCX_PES) cb_field1++; ``` This check is designed to skip `cb_field` counter increments for container formats. However, with `in_bufferdatatype == CCX_UNKNOWN`, this condition evaluated to `true`, causing `cb_field1` to be incremented for every CEA-608 caption block. ### The Timing Math When `get_fts()` is called to timestamp captions, it calculates: ```c fts_now + fts_global + cb_field1 * 1001 / 30 ``` The `cb_field1 * 1001/30` term adds ~33.37ms per caption block. With a typical roll-up caption having ~6 blocks per frame: ``` 6 blocks × 33.37ms/block ≈ 200ms offset ``` This explains the consistent 200ms timing offset observed in MOV/MP4 files. ### Why Container Formats Don't Need cb_field For container formats (MP4, MOV, MKV, TS with PES), all caption data for a video frame is bundled together and associated with the frame's PTS. The caption blocks within a frame don't have sub-frame timing - they all belong to the same presentation timestamp. In contrast, raw/elementary streams may have caption data arriving at field rate (59.94 Hz for NTSC), where each CEA-608 byte pair has its own timing. The `cb_field` offset accounts for this sub-frame timing. ## The Fix Set `in_bufferdatatype` correctly in the three MP4 track processing functions: | Function | Track Type | Setting | |----------|------------|---------| | `process_avc_track()` | H.264/AVC | `CCX_H264` | | `process_hevc_track()` | H.265/HEVC | `CCX_H264` | | `process_xdvb_track()` | MPEG-2 | `CCX_PES` | ## Verification ### Test Sample `/home/cfsmp3/media_samples/completed/1974a299f0502fc8199dabcaadb20e422e79df45972e554d58d1d025ef7d0686.mov` ### Before Fix (ttxt output) ``` 00:00:14,047|00:00:14,547|RU2|>> WHICH OF THESE STORIES WILL 00:00:14,547|00:00:15,948|RU2|YOU BE TALKING ABOUT TOMORROW? ``` ### After Fix (ttxt output) ``` 00:00:13,847|00:00:14,547|RU2|>> WHICH OF THESE STORIES WILL 00:00:14,547|00:00:15,248|RU2|YOU BE TALKING ABOUT TOMORROW? ``` ### FFmpeg Reference ``` 1 00:00:13,847 --> 00:00:14,548 >> WHICH OF THESE STORIES WILL ``` The fix aligns CCExtractor's output exactly with FFmpeg's authoritative timing. ### Regression Check Verified that TS files still work correctly with the same timing (no regressions introduced). ## Test Plan - [x] Verify MOV file timing matches FFmpeg (13,847ms) - [x] Verify TS files still work correctly (no regressions) - [ ] Run sample platform regression tests for tests 226-230 - [ ] Verify HEVC MP4 files (if samples available) ## Files Changed - `src/lib_ccx/mp4.c` - Set `in_bufferdatatype` in 3 track processing functions 🤖 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:32 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/ccextractor#2707