Skip to content

[FIX] --out report: probe both EIA-608 fields so CC3/CC4 are reported accurately (#2177)#2298

Open
x15sr71 wants to merge 2 commits into
CCExtractor:masterfrom
x15sr71:fix/2177-report-both-fields
Open

[FIX] --out report: probe both EIA-608 fields so CC3/CC4 are reported accurately (#2177)#2298
x15sr71 wants to merge 2 commits into
CCExtractor:masterfrom
x15sr71:fix/2177-report-both-fields

Conversation

@x15sr71

@x15sr71 x15sr71 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

In raising this pull request, I confirm the following (please check boxes):

Reason for this PR:

  • This PR adds new functionality.
  • This PR fixes a bug that I have personally experienced or that a real user has reported and for which a sample exists.
  • This PR is porting code from C to Rust.

Sanity check:

  • I have read and understood the contributors guide.
  • I have checked that another pull request for this purpose does not exist.
  • If the PR adds new functionality, I've added it to the changelog. If it's just a bug fix, I have NOT added it to the changelog.
  • I am NOT adding new C code unless it's to fix an existing, reproducible bug.

Repro instructions:

ffmpeg -i "https://weather.horse/samples/cc3.mkv" -c copy cc3.ts -y
ccextractor --out report cc3.ts

Before / After

Sample cc3.ts (captions on field 2):

Before:

EIA-608: Yes
CC1: No
CC2: No
CC3: No      <-- wrong, CC3 is present
CC4: No

After:

EIA-608: Yes
CC1: No
CC2: No
CC3: Yes     <-- correct
CC4: No

Issue

Fixes #2177.

--out report reports CC3 / CC4 as No even when the stream carries captions on EIA-608 field 2 (CC3/CC4 live on field 2). The report is therefore inaccurate for any field-2-only source.

Root cause

The report path never asked the decoder to look at field 2.

options->extract defaults to 1 (field 1 only) — src/lib_ccx/ccx_common_option.c:28. The --out report arm never changed it, so the decoder's field gate (src/lib_ccx/ccx_decoders_608.c:1185-1193, which only processes field 2 when extract == 2 || extract == 12) skipped field 2 entirely. CC3/CC4 presence was never probed, so it was always reported as No.

Fix

Set extract = 12 (both fields) in the OutFormat::Report arm (src/rust/src/parser.rs:202-209).

Two supporting details keep this scoped:

  1. Explicit --output-field still wins. The Report arm runs during set_output_format (parser.rs:783); --output-field is parsed afterwards (parser.rs:988) and overwrites extract. Order of CLI flags is irrelevant because processing order in parse_parameters is fixed.
  2. The "both fields to stdout" guard is bypassed for report mode only. Because report now carries extract == 12, --out report --stdout would otherwise trip the broadcast-mode guard (parser.rs:1575-1585). The guard now has && !self.print_file_reports, so it is relaxed only for report mode. Report writes write_format = Null (no caption stream to stdout), so the guard is meaningless there; normal extraction is unaffected.

The change is 13 lines, Rust-only, entirely inside the report arm + that one guard. It does not alter extract for any non-report invocation.

Testing

Built from this branch (binary reports Git commit 0d968cde). All behaviours verified against cc3.ts:

Command Result
--out report CC3 Yes, exit 10 (normal report exit), no files
--out report --output-field 1 CC3 No (explicit override wins)
--out report --output-field both CC3 Yes
--out report --stdout report printed, no fatal, no files
--out report --output-field both --stdout report printed, no fatal
--output-field both --stdout (normal) still rejected: "You can't extract both fields to stdout…" (exit 4)
--output-field 1 --out report vs --out report --output-field 1 identical (CC3 No) — flag order irrelevant
normal extraction, --output-field 1, --output-field 2, --output-field both unchanged (exit 0, expected output files)

Regression scope verified: the only new extract write is inside the report arm, and the stdout-guard edit is a no-op when print_file_reports == false, so non-report behaviour cannot change. The C-side extract == 12 encoder branches (ccx_encoders_common.c:583/605/643/920) are inert in report mode because generates_file = 0 for CCX_OF_NULL (verified: --out report -o out.srt creates no files) and encode_sub has no CCX_OF_NULL case.

Unit tests: src/rustparser:: module 204/204 pass, including:

  • test_out_report_enables_file_reports (now asserts extract == 12)
  • test_out_report_explicit_field_overrides_both

x15sr71 added 2 commits July 25, 2026 02:46
… reported accurately (CCExtractor#2177)

Issue:
`--out report` reported CC3/CC4 as "No" even when the stream carried captions
on EIA-608 field 2 (CC3/CC4 live on field 2), so the report was inaccurate for
field-2 sources.

Root cause:
options->extract defaults to 1 (field 1 only, ccx_common_option.c:28). The
report path never changed it, so the decoder's field gate (ccx_decoders_608.c,
field 2 processed only when extract == 2 || extract == 12) skipped field 2 and
CC3/CC4 presence was never probed.

Fix:
Set extract = 12 (both fields) in the OutFormat::Report arm (parser.rs). Kept
scoped by two details:
- Explicit --output-field still wins: the report arm runs during
  set_output_format, and --output-field is parsed afterwards and overwrites
  extract, so field selection is honoured regardless of CLI flag order.
- The "both fields to stdout" broadcast-mode guard is bypassed only for report
  mode (added `&& !print_file_reports`). Report uses write_format = Null, so
  there is no real caption stream to stdout; normal extraction is unaffected.

13 lines, Rust-only (src/rust/src/parser.rs). extract is not changed for any
non-report invocation.

Before (cc3.ts): CC3: No   ->   After: CC3: Yes  (CC1/CC2/CC4 unchanged)

Reproduce:
  ffmpeg -i "https://weather.horse/samples/cc3.mkv" -c copy cc3.ts -y
  ccextractor --out report cc3.ts

Testing:
- report -> CC3 Yes; --output-field 1 override -> CC3 No; both -> Yes.
- --out report --stdout and --out report --output-field both --stdout: report
  printed, no fatal. Normal --output-field both --stdout still rejected (exit 4).
- Flag order irrelevant (`-1 --out report` == `--out report -1`).
- Normal / -1 / -2 / both extraction unchanged (exit 0, expected output files).
- C-side extract==12 encoder branches are inert in report mode: generates_file=0
  for CCX_OF_NULL (verified: `--out report -o out.srt` creates no files) and
  encode_sub has no CCX_OF_NULL case.
- parser:: unit tests 204/204, incl. test_out_report_enables_file_reports
  (asserts extract == 12) and test_out_report_explicit_field_overrides_both.
@ccextractor-bot

Copy link
Copy Markdown
Collaborator
CCExtractor CI platform finished running the test files on windows. Below is a summary of the test results, when compared to test for commit 2feb09a...:
Report Name Tests Passed
Broken 9/13
CEA-708 2/14
DVB 2/7
DVD 3/3
DVR-MS 2/2
General 24/27
Hardsubx 1/1
Hauppage 3/3
MP4 3/3
NoCC 10/10
Options 74/86
Teletext 20/21
WTV 12/13
XDS 31/34

Your PR breaks these cases:

  • ccextractor --out=srt --latin1 611b4a9235...
  • ccextractor --autoprogram --out=ttxt --latin1 1020459a86...
  • ccextractor --autoprogram --out=ttxt --latin1 132d7df7e9...
  • ccextractor --autoprogram --out=ttxt --latin1 99e5eaafdc...
  • ccextractor --autoprogram --out=ttxt --latin1 01509e4d27...
  • ccextractor --dru c83f765c66...
  • ccextractor --startat 4 --endat 7 c83f765c66...
  • ccextractor --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9...
  • ccextractor --startcreditsnotbefore 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9...
  • ccextractor --startcreditsnotafter 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9...
  • ccextractor --startcreditsforatleast 1 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9...
  • ccextractor --startcreditsforatmost 2 --startcreditstext "CCextractor Start crdit Testing" c4dd893cb9...
  • ccextractor --out=srt --latin1 f23a544ba8...
  • ccextractor --autoprogram --out=srt --latin1 --ucla d037c7509e...
  • ccextractor --autoprogram --out=srt --latin1 --ucla 7d3f25c32c...
  • ccextractor --autoprogram --out=ttxt --latin1 --ucla --xds 7f41299cc7...

NOTE: The following tests have been failing on the master branch as well as the PR:

Congratulations: Merging this PR would fix the following tests:

  • ccextractor --service 1 --out=ttxt da904de35d..., Last passed: Never
  • ccextractor --autoprogram --out=srt --latin1 --quant 0 85271be4d2..., Last passed: Never
  • ccextractor --autoprogram --out=ttxt --latin1 --ucla dab1c1bd65..., Last passed: Never
  • ccextractor --out=srt --latin1 --autoprogram 29e5ffd34b..., Last passed: Never
  • ccextractor --out=spupng c83f765c66..., Last passed: Never

It seems that not all tests were passed completely. This is an indication that the output of some files is not as expected (but might be according to you).

Check the result page for more info.

@x15sr71

x15sr71 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@bbgdzxng1 @Varadraj75 Tagging you both since this implements the approach discussed in #2177. Tested it with the weather.horse sample from the issue and it seems to behave as expected. If you get a chance, I'd appreciate any feedback.

@cfsmp3

cfsmp3 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Claude review (with human verification!)

Verified the fix on real samples — --out report goes from CC3: No to
CC3: Yes on field-2 sources, and --out report --output-field 1 still
correctly reports CC3: No, so the explicit override wins as you described. The
parse-order argument holds: set_output_format runs at parser.rs:780 and
--output-field is handled at parser.rs:985, so flag order is irrelevant.

On the sample-platform failures: they're noise, not your PR. None of the 16
flagged cases use report mode, so I built master and this branch and ran all 16
commands against the actual samples. Output is byte-identical and exit codes
match in all 16. Nothing to fix here.

Nice side effect you didn't mention: XDS also goes from No to Yes.
XDS only exists in field 2, so probing it fixes XDS reporting too. Worth adding
to the description.

One thing worth knowing — not a blocker, and not caused by this PR. I ran
--out report across 58 local samples; 30 changed, all in the No → Yes
direction. Spot-checking eight of them against ground truth (extracting field 2
directly), only three actually have any CC3 text, and both samples reporting
CC4: Yes produce zero CC4 output:

sample report actual CC3/CC4 bytes
e274a73653 CC3 Yes CC4 Yes 0 / 0
7d2730d38e CC3 Yes CC4 Yes 0 / 0
b22260d065 CC3 Yes CC4 Yes 985 / 0
5d3a29f9f8 CC3 Yes 233118
d037c7509e CC3 Yes 0

The cause is in ccx_decoders_608.c:1222: a channel is marked present on any
control code in 0x10–0x1E, whether or not a character is ever written to the
screen buffer. On field 1 that happens to coincide with reality (in every sample
I checked, CC1: Yes had real text and CC2 was correctly No). On field 2 it
doesn't — field 2 routinely carries control codes with no displayable text.

To be clear, this is pre-existing behaviour, not something you introduced:
master --out report --output-field both already reports CC3: Yes CC4: Yes on
e274a73653 today. Your change just promotes it to the default, which means the
report will now say CC3: Yes on a lot of ordinary field-1-only streams that
have no CC3 captions at all.

I also checked whether XDS data bytes were being misattributed to CC3/CC4 —
patched in a !in_xds_mode guard and rebuilt, and only one of the eight samples
changed. So that's a minor contributor at most, not the explanation.

Given that, I'm inclined to take this as-is and open a separate follow-up to
tighten the cc_channels marking so a channel is only flagged once the decoder
actually writes a character (wrote_to_screen is already tracked in that loop).
That's a decoder change touching field 1 as well, so it doesn't belong in this
PR. Let me know if you'd rather take it on yourself.

Last thing: the stream_functions.rs:395 clippy fix is unrelated to report mode,
but it's welcome — that's the byte_char_slices error currently failing
format_rust on #2294 and #2295, so merging this unblocks both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PROPOSAL] Display both EIA-608 fields in --out report by default

3 participants