Skip to content

Commit 556d4f1

Browse files
cfsmp3claude
andcommitted
feat(c): Use Rust CEA-708 decoder in C code (Phase 3)
- init_cc_decode(): Initialize dtvcc_rust via ccxr_dtvcc_init() - dinit_cc_decode(): Free dtvcc_rust via ccxr_dtvcc_free() - flush_cc_decode(): Flush via ccxr_flush_active_decoders() - general_loop.c: Set encoder via ccxr_dtvcc_set_encoder() (3 locations) - mp4.c: Use ccxr_dtvcc_set_encoder() and ccxr_dtvcc_process_data() - Add ccxr_dtvcc_is_active() declaration to ccx_dtvcc.h - Fix clippy warnings in tv_screen.rs (unused assignments) - All changes guarded with #ifndef DISABLE_RUST - Update implementation plan to mark Phase 3 complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent cf328cc commit 556d4f1

File tree

6 files changed

+53
-15
lines changed

6 files changed

+53
-15
lines changed

PLAN_PR1618_REIMPLEMENTATION.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
|-------|--------|--------|-----|
77
| Phase 1: Rust Core | ✅ COMPLETE | `fix/1499-dtvcc-persistent-state` | #1782 |
88
| Phase 2: C Headers | ✅ COMPLETE | `fix/1499-dtvcc-persistent-state` | #1782 |
9-
| Phase 3: C Implementation | 🔲 NOT STARTED | - | - |
9+
| Phase 3: C Implementation | ✅ COMPLETE | `fix/1499-dtvcc-persistent-state` | #1782 |
1010
| Phase 4: Testing | 🔲 NOT STARTED | - | - |
1111

1212
---
@@ -303,20 +303,20 @@ Also modifies `ccxr_process_cc_data` to not create new Dtvcc.
303303
- File: `src/lib_ccx/ccx_decoders_common.h`
304304
- Added extern declaration for `ccxr_flush_active_decoders`
305305

306-
### Phase 3: C Implementation Changes
306+
### Phase 3: C Implementation Changes ✅ COMPLETE
307307

308-
**Step 3.1: Update decoder initialization/destruction**
308+
**Step 3.1: Update decoder initialization/destruction**
309309
- File: `src/lib_ccx/ccx_decoders_common.c`
310310
- In `init_cc_decode()`: Use `ccxr_dtvcc_init()` when Rust enabled
311311
- In `dinit_cc_decode()`: Use `ccxr_dtvcc_free()` when Rust enabled
312312
- In `flush_cc_decode()`: Use `ccxr_flush_active_decoders()` when Rust enabled
313-
- Remove old `ccxr_flush_decoder` extern declaration
313+
- Added `ccxr_dtvcc_is_active()` declaration to `ccx_dtvcc.h`
314314

315-
**Step 3.2: Update encoder assignment points**
315+
**Step 3.2: Update encoder assignment points**
316316
- File: `src/lib_ccx/general_loop.c`
317-
- Three locations need `ccxr_dtvcc_set_encoder()` calls
317+
- Three locations updated with `ccxr_dtvcc_set_encoder()` calls
318318
- File: `src/lib_ccx/mp4.c`
319-
- Use `ccxr_dtvcc_set_encoder()` and `ccxr_dtvcc_process_data()`
319+
- Updated with `ccxr_dtvcc_set_encoder()` and `ccxr_dtvcc_process_data()`
320320

321321
### Phase 4: Testing
322322

@@ -364,21 +364,22 @@ Also modifies `ccxr_process_cc_data` to not create new Dtvcc.
364364
| `src/lib_ccx/lib_ccx.h` | C Header || Added `ccxr_dtvcc_set_encoder` declaration |
365365
| `src/lib_ccx/ccx_decoders_common.h` | C Header || Added `ccxr_flush_active_decoders` declaration |
366366

367-
### Phase 3 (Pending)
367+
### Phase 3 (Complete)
368368

369369
| File | Type | Status | Changes |
370370
|------|------|--------|---------|
371-
| `src/lib_ccx/ccx_decoders_common.c` | C | 🔲 | Use Rust init/free/flush |
372-
| `src/lib_ccx/general_loop.c` | C | 🔲 | Set encoder via Rust function |
373-
| `src/lib_ccx/mp4.c` | C | 🔲 | Use Rust processing for MP4 |
371+
| `src/lib_ccx/ccx_decoders_common.c` | C || Use Rust init/free/flush with `#ifndef DISABLE_RUST` guards |
372+
| `src/lib_ccx/general_loop.c` | C || Set encoder via `ccxr_dtvcc_set_encoder()` at 3 locations |
373+
| `src/lib_ccx/mp4.c` | C || Use `ccxr_dtvcc_set_encoder()` and `ccxr_dtvcc_process_data()` |
374+
| `src/lib_ccx/ccx_dtvcc.h` | C Header || Added `ccxr_dtvcc_is_active()` declaration |
374375

375376
---
376377

377378
## Estimated Complexity
378379

379380
- **Phase 1 (Rust)**: ✅ COMPLETE - Added new struct alongside existing code
380381
- **Phase 2 (C Headers)**: ✅ COMPLETE - Added field and extern declarations
381-
- **Phase 3 (C Implementation)**: Low-Medium - conditional compilation blocks
382+
- **Phase 3 (C Implementation)**: ✅ COMPLETE - Added conditional compilation blocks
382383
- **Phase 4 (Testing)**: Medium - need to verify state persistence works correctly
383384

384385
**Total estimate**: This is a significant change touching core decoder logic. Recommend implementing in small, testable increments.

src/lib_ccx/ccx_decoders_common.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,12 @@ int do_cb(struct lib_cc_decode *ctx, unsigned char *cc_block, struct cc_subtitle
217217
void dinit_cc_decode(struct lib_cc_decode **ctx)
218218
{
219219
struct lib_cc_decode *lctx = *ctx;
220+
#ifndef DISABLE_RUST
221+
ccxr_dtvcc_free(lctx->dtvcc_rust);
222+
lctx->dtvcc_rust = NULL;
223+
#else
220224
dtvcc_free(&lctx->dtvcc);
225+
#endif
221226
dinit_avc(&lctx->avc_ctx);
222227
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_1);
223228
ccx_decoder_608_dinit_library(&lctx->context_cc608_field_2);
@@ -246,8 +251,14 @@ struct lib_cc_decode *init_cc_decode(struct ccx_decoders_common_settings_t *sett
246251
ctx->no_rollup = setting->no_rollup;
247252
ctx->noscte20 = setting->noscte20;
248253

254+
#ifndef DISABLE_RUST
255+
ctx->dtvcc_rust = ccxr_dtvcc_init(setting->settings_dtvcc);
256+
ctx->dtvcc = NULL; // Not used when Rust is enabled
257+
#else
249258
ctx->dtvcc = dtvcc_init(setting->settings_dtvcc);
250259
ctx->dtvcc->is_active = setting->settings_dtvcc->enabled;
260+
ctx->dtvcc_rust = NULL;
261+
#endif
251262

252263
if (setting->codec == CCX_CODEC_ATSC_CC)
253264
{
@@ -426,6 +437,13 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
426437
}
427438
}
428439
}
440+
#ifndef DISABLE_RUST
441+
if (ccxr_dtvcc_is_active(ctx->dtvcc_rust))
442+
{
443+
ctx->current_field = 3;
444+
ccxr_flush_active_decoders(ctx->dtvcc_rust);
445+
}
446+
#else
429447
if (ctx->dtvcc->is_active)
430448
{
431449
for (int i = 0; i < CCX_DTVCC_MAX_SERVICES; i++)
@@ -440,6 +458,7 @@ void flush_cc_decode(struct lib_cc_decode *ctx, struct cc_subtitle *sub)
440458
}
441459
}
442460
}
461+
#endif
443462
}
444463
struct encoder_ctx *copy_encoder_context(struct encoder_ctx *ctx)
445464
{

src/lib_ccx/ccx_dtvcc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extern void *ccxr_dtvcc_init(struct ccx_decoder_dtvcc_settings *settings_dtvcc);
1616
extern void ccxr_dtvcc_free(void *dtvcc_rust);
1717
extern void ccxr_dtvcc_process_data(void *dtvcc_rust, const unsigned char cc_valid,
1818
const unsigned char cc_type, const unsigned char data1, const unsigned char data2);
19+
extern int ccxr_dtvcc_is_active(void *dtvcc_rust);
1920
#endif
2021

2122
#endif //CCEXTRACTOR_CCX_DTVCC_H

src/lib_ccx/general_loop.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,11 @@ int process_non_multiprogram_general_loop(struct lib_ccx_ctx *ctx,
896896
cinfo = get_cinfo(ctx->demux_ctx, pid);
897897
*enc_ctx = update_encoder_list_cinfo(ctx, cinfo);
898898
*dec_ctx = update_decoder_list_cinfo(ctx, cinfo);
899+
#ifndef DISABLE_RUST
900+
ccxr_dtvcc_set_encoder((*dec_ctx)->dtvcc_rust, *enc_ctx);
901+
#else
899902
(*dec_ctx)->dtvcc->encoder = (void *)(*enc_ctx);
903+
#endif
900904

901905
if ((*dec_ctx)->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program
902906
{
@@ -1093,7 +1097,11 @@ int general_loop(struct lib_ccx_ctx *ctx)
10931097

10941098
enc_ctx = update_encoder_list_cinfo(ctx, cinfo);
10951099
dec_ctx = update_decoder_list_cinfo(ctx, cinfo);
1100+
#ifndef DISABLE_RUST
1101+
ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx);
1102+
#else
10961103
dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work
1104+
#endif
10971105

10981106
if (dec_ctx->timing->min_pts == 0x01FFFFFFFFLL) // if we didn't set the min_pts of the program
10991107
{
@@ -1268,7 +1276,11 @@ int rcwt_loop(struct lib_ccx_ctx *ctx)
12681276
}
12691277

12701278
dec_ctx = update_decoder_list(ctx);
1279+
#ifndef DISABLE_RUST
1280+
ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx);
1281+
#else
12711282
dec_ctx->dtvcc->encoder = (void *)enc_ctx; // WARN: otherwise cea-708 will not work
1283+
#endif
12721284
if (parsebuf[6] == 0 && parsebuf[7] == 2)
12731285
{
12741286
dec_ctx->codec = CCX_CODEC_TELETEXT;

src/lib_ccx/mp4.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,11 @@ static int process_clcp(struct lib_ccx_ctx *ctx, struct encoder_ctx *enc_ctx,
416416
dbg_print(CCX_DMT_PARSE, "MP4-708: atom skipped (cc_type < 2)\n");
417417
continue;
418418
}
419+
#ifndef DISABLE_RUST
420+
ccxr_dtvcc_process_data(dec_ctx->dtvcc_rust, cc_valid, cc_type, temp[2], temp[3]);
421+
#else
419422
dtvcc_process_data(dec_ctx->dtvcc, (unsigned char *)temp);
423+
#endif
420424
cb_708++;
421425
}
422426
if (ctx->write_format == CCX_OF_MCC)
@@ -551,7 +555,11 @@ int processmp4(struct lib_ccx_ctx *ctx, struct ccx_s_mp4Cfg *cfg, char *file)
551555
enc_ctx->timing = dec_ctx->timing;
552556

553557
// WARN: otherwise cea-708 will not work
558+
#ifndef DISABLE_RUST
559+
ccxr_dtvcc_set_encoder(dec_ctx->dtvcc_rust, enc_ctx);
560+
#else
554561
dec_ctx->dtvcc->encoder = (void *)enc_ctx;
562+
#endif
555563

556564
memset(&dec_sub, 0, sizeof(dec_sub));
557565
mprint("Opening \'%s\': ", file);

src/rust/src/decoder/tv_screen.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ impl dtvcc_tv_screen {
454454
// Correct the frame delay
455455
time_show.time_in_ms -= 1000 / 29.97 as i64;
456456
buf.push_str(&(get_scc_time_str(time_show) + "\t942c 942c ").to_owned());
457-
time_show.time_in_ms += 1000 / 29.97 as i64;
458457
// Clear the buffer and start pop on caption
459458
buf.push_str("94ae 94ae 9420 9420");
460459
}
@@ -466,14 +465,12 @@ impl dtvcc_tv_screen {
466465
time_show.time_in_ms -= 1000 / 29.97 as i64;
467466
// Clear the buffer and start pop on caption in new time
468467
buf.push_str(&(get_scc_time_str(time_show) + "\t94ae 94ae 9420 9420").to_owned());
469-
time_show.time_in_ms += 1000 / 29.97 as i64;
470468
}
471469
Ordering::Equal => {
472470
time_show.time_in_ms -= 1000 / 29.97 as i64;
473471
buf.push_str(
474472
&(get_scc_time_str(time_show) + "\t942c 942c 94ae 94ae 9420 9420").to_owned(),
475473
);
476-
time_show.time_in_ms += 1000 / 29.97 as i64;
477474
}
478475
}
479476

0 commit comments

Comments
 (0)