Skip to content

Commit e160a53

Browse files
authored
fix: McPoodle DVD raw format read/write (Issue #1524)
2 parents 083c126 + 88fbe91 commit e160a53

File tree

11 files changed

+697
-47
lines changed

11 files changed

+697
-47
lines changed

src/lib_ccx/ccx_common_constants.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ const unsigned char UTF8_BOM[] = {0xef, 0xbb, 0xbf};
1717
const unsigned char DVD_HEADER[8] = {0x00, 0x00, 0x01, 0xb2, 0x43, 0x43, 0x01, 0xf8};
1818
const unsigned char lc1[1] = {0x8a};
1919
const unsigned char lc2[1] = {0x8f};
20-
const unsigned char lc3[2] = {0x16, 0xfe};
21-
const unsigned char lc4[2] = {0x1e, 0xfe};
20+
const unsigned char lc3[1] = {0x16}; // McPoodle uses single-byte loop markers
21+
const unsigned char lc4[1] = {0x1e};
2222
const unsigned char lc5[1] = {0xff};
2323
const unsigned char lc6[1] = {0xfe};
2424

src/lib_ccx/ccx_common_constants.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ extern const unsigned char UTF8_BOM[3];
2222
extern const unsigned char DVD_HEADER[8];
2323
extern const unsigned char lc1[1];
2424
extern const unsigned char lc2[1];
25-
extern const unsigned char lc3[2];
26-
extern const unsigned char lc4[2];
25+
extern const unsigned char lc3[1];
26+
extern const unsigned char lc4[1];
2727
extern const unsigned char lc5[1];
2828
extern const unsigned char lc6[1];
2929

src/lib_ccx/general_loop.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ int raw_loop(struct lib_ccx_ctx *ctx)
529529
struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
530530
struct lib_cc_decode *dec_ctx = NULL;
531531
int caps = 0;
532+
int is_dvdraw = 0; // Flag to track if this is DVD raw format
532533

533534
dec_ctx = update_decoder_list(ctx);
534535
dec_sub = &dec_ctx->dec_sub;
@@ -545,18 +546,33 @@ int raw_loop(struct lib_ccx_ctx *ctx)
545546
if (ret == CCX_EOF)
546547
break;
547548

548-
ret = process_raw(dec_ctx, dec_sub, data->buffer, data->len);
549+
// Check if this is DVD raw format using Rust detection
550+
if (!is_dvdraw && ccxr_is_dvdraw_header(data->buffer, (unsigned int)data->len))
551+
{
552+
is_dvdraw = 1;
553+
mprint("Detected McPoodle's DVD raw format\n");
554+
}
555+
556+
if (is_dvdraw)
557+
{
558+
// Use Rust implementation - handles timing internally
559+
ret = ccxr_process_dvdraw(dec_ctx, dec_sub, data->buffer, (unsigned int)data->len);
560+
}
561+
else
562+
{
563+
ret = process_raw(dec_ctx, dec_sub, data->buffer, data->len);
564+
// For regular raw format, advance timing based on field 1 blocks
565+
add_current_pts(dec_ctx->timing, cb_field1 * 1001 / 30 * (MPEG_CLOCK_FREQ / 1000));
566+
set_fts(dec_ctx->timing);
567+
}
568+
549569
if (dec_sub->got_output)
550570
{
551571
caps = 1;
552572
encode_sub(enc_ctx, dec_sub);
553573
dec_sub->got_output = 0;
554574
}
555575

556-
// int ccblocks = cb_field1;
557-
add_current_pts(dec_ctx->timing, cb_field1 * 1001 / 30 * (MPEG_CLOCK_FREQ / 1000));
558-
set_fts(dec_ctx->timing); // Now set the FTS related variables including fts_max
559-
560576
} while (data->len);
561577
free(data);
562578
return caps;
@@ -618,6 +634,11 @@ size_t process_raw(struct lib_cc_decode *ctx, struct cc_subtitle *sub, unsigned
618634
return len;
619635
}
620636

637+
/* NOTE: process_dvdraw() has been migrated to Rust.
638+
* The implementation is now in src/rust/src/demuxer/dvdraw.rs
639+
* and exported via ccxr_process_dvdraw() in src/rust/src/libccxr_exports/demuxer.rs
640+
*/
641+
621642
void delete_datalist(struct demuxer_data *list)
622643
{
623644
struct demuxer_data *slist = list;

src/lib_ccx/lib_ccx.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ int ps_get_more_data(struct lib_ccx_ctx *ctx, struct demuxer_data **ppdata);
172172
int general_get_more_data(struct lib_ccx_ctx *ctx, struct demuxer_data **data);
173173
int raw_loop(struct lib_ccx_ctx *ctx);
174174
size_t process_raw(struct lib_cc_decode *ctx, struct cc_subtitle *sub, unsigned char *buffer, size_t len);
175+
176+
// Rust FFI: McPoodle DVD raw format processing (see src/rust/src/demuxer/dvdraw.rs)
177+
unsigned int ccxr_process_dvdraw(struct lib_cc_decode *ctx, struct cc_subtitle *sub, const unsigned char *buffer, unsigned int len);
178+
int ccxr_is_dvdraw_header(const unsigned char *buffer, unsigned int len);
179+
175180
int general_loop(struct lib_ccx_ctx *ctx);
176181
void process_hex(struct lib_ccx_ctx *ctx, char *filename);
177182
int rcwt_loop(struct lib_ccx_ctx *ctx);

src/lib_ccx/output.c

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -119,51 +119,87 @@ void writeDVDraw(const unsigned char *data1, int length1,
119119
struct cc_subtitle *sub)
120120
{
121121
/* these are only used by DVD raw mode: */
122-
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
123-
loop 3: 11 elements, rest: 15 elements */
124-
static int datacount = 0; /* counts within loop */
122+
static int loopcount = 1; /* loop 1: 5 elements, loop 2: 8 elements,
123+
loop 3: 11 elements, rest: 15 elements */
124+
static int datacount = 0; /* counts within loop */
125+
static int waiting_for_field2 = 0; /* track if we're waiting for field 2 data */
125126

126-
if (datacount == 0)
127+
/* printdata() is called separately for field 1 and field 2 data.
128+
* Field 1: data1 set, data2 NULL
129+
* Field 2: data1 NULL, data2 set
130+
* We need to combine them into the DVD raw format: ff [d1] fe [d2]
131+
*/
132+
133+
/* If we have data1 only (field 1), write ff + data1 and wait for field 2 */
134+
if (data1 && length1 && (!data2 || !length2))
127135
{
128-
writeraw(DVD_HEADER, sizeof(DVD_HEADER), NULL, sub);
129-
if (loopcount == 1)
130-
writeraw(lc1, sizeof(lc1), NULL, sub);
131-
if (loopcount == 2)
132-
writeraw(lc2, sizeof(lc2), NULL, sub);
133-
if (loopcount == 3)
134-
{
135-
writeraw(lc3, sizeof(lc3), NULL, sub);
136-
if (data2 && length2)
137-
writeraw(data2, length2, NULL, sub);
138-
}
139-
if (loopcount > 3)
136+
if (datacount == 0)
140137
{
141-
writeraw(lc4, sizeof(lc4), NULL, sub);
142-
if (data2 && length2)
143-
writeraw(data2, length2, NULL, sub);
138+
writeraw(DVD_HEADER, sizeof(DVD_HEADER), NULL, sub);
139+
if (loopcount == 1)
140+
writeraw(lc1, sizeof(lc1), NULL, sub);
141+
else if (loopcount == 2)
142+
writeraw(lc2, sizeof(lc2), NULL, sub);
143+
else if (loopcount == 3)
144+
writeraw(lc3, sizeof(lc3), NULL, sub);
145+
else
146+
writeraw(lc4, sizeof(lc4), NULL, sub);
144147
}
145-
}
146-
datacount++;
147-
writeraw(lc5, sizeof(lc5), NULL, sub);
148-
if (data1 && length1)
148+
writeraw(lc5, sizeof(lc5), NULL, sub); /* ff */
149149
writeraw(data1, length1, NULL, sub);
150-
if (((loopcount == 1) && (datacount < 5)) || ((loopcount == 2) && (datacount < 8)) || ((loopcount == 3) && (datacount < 11)) ||
151-
((loopcount > 3) && (datacount < 15)))
150+
waiting_for_field2 = 1;
151+
return;
152+
}
153+
154+
/* If we have data2 only (field 2), write fe + data2 */
155+
if ((!data1 || !length1) && data2 && length2)
152156
{
153-
writeraw(lc6, sizeof(lc6), NULL, sub);
154-
if (data2 && length2)
155-
writeraw(data2, length2, NULL, sub);
157+
writeraw(lc6, sizeof(lc6), NULL, sub); /* fe */
158+
writeraw(data2, length2, NULL, sub);
159+
waiting_for_field2 = 0;
160+
datacount++;
161+
162+
/* Check if we've completed a loop */
163+
int max_count = (loopcount == 1) ? 5 : (loopcount == 2) ? 8
164+
: (loopcount == 3) ? 11
165+
: 15;
166+
if (datacount >= max_count)
167+
{
168+
loopcount++;
169+
datacount = 0;
170+
}
171+
return;
156172
}
157-
else
173+
174+
/* If we have both data1 and data2 (legacy behavior, just in case) */
175+
if (data1 && length1 && data2 && length2)
158176
{
159-
if (loopcount == 1)
177+
if (datacount == 0)
178+
{
179+
writeraw(DVD_HEADER, sizeof(DVD_HEADER), NULL, sub);
180+
if (loopcount == 1)
181+
writeraw(lc1, sizeof(lc1), NULL, sub);
182+
else if (loopcount == 2)
183+
writeraw(lc2, sizeof(lc2), NULL, sub);
184+
else if (loopcount == 3)
185+
writeraw(lc3, sizeof(lc3), NULL, sub);
186+
else
187+
writeraw(lc4, sizeof(lc4), NULL, sub);
188+
}
189+
writeraw(lc5, sizeof(lc5), NULL, sub); /* ff */
190+
writeraw(data1, length1, NULL, sub);
191+
writeraw(lc6, sizeof(lc6), NULL, sub); /* fe */
192+
writeraw(data2, length2, NULL, sub);
193+
datacount++;
194+
195+
int max_count = (loopcount == 1) ? 5 : (loopcount == 2) ? 8
196+
: (loopcount == 3) ? 11
197+
: 15;
198+
if (datacount >= max_count)
160199
{
161-
writeraw(lc6, sizeof(lc6), NULL, sub);
162-
if (data2 && length2)
163-
writeraw(data2, length2, NULL, sub);
200+
loopcount++;
201+
datacount = 0;
164202
}
165-
loopcount++;
166-
datacount = 0;
167203
}
168204
}
169205

src/lib_ccx/stream_functions.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ void detect_stream_type(struct ccx_demuxer *ctx)
6565
ctx->startbytes[3] == 0x20)
6666
ctx->stream_mode = CCX_SM_WTV;
6767
}
68+
// Check for McPoodle DVD raw format: 00 00 01 B2 43 43 ("CC") 01 F8
69+
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 8)
70+
{
71+
if (ctx->startbytes[0] == 0x00 &&
72+
ctx->startbytes[1] == 0x00 &&
73+
ctx->startbytes[2] == 0x01 &&
74+
ctx->startbytes[3] == 0xb2 &&
75+
ctx->startbytes[4] == 0x43 && // 'C'
76+
ctx->startbytes[5] == 0x43 && // 'C'
77+
ctx->startbytes[6] == 0x01 &&
78+
ctx->startbytes[7] == 0xf8)
79+
ctx->stream_mode = CCX_SM_MCPOODLESRAW;
80+
}
6881
#ifdef WTV_DEBUG
6982
if (ctx->stream_mode == CCX_SM_ELEMENTARY_OR_NOT_FOUND && ctx->startbytes_avail >= 6)
7083
{

src/rust/lib_ccxr/src/common/constants.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ pub const UTF8_BOM: [u8; 3] = [0xef, 0xbb, 0xbf];
6666
pub const DVD_HEADER: [u8; 8] = [0x00, 0x00, 0x01, 0xb2, 0x43, 0x43, 0x01, 0xf8];
6767
pub const LC1: [u8; 1] = [0x8a];
6868
pub const LC2: [u8; 1] = [0x8f];
69-
pub const LC3: [u8; 2] = [0x16, 0xfe];
70-
pub const LC4: [u8; 2] = [0x1e, 0xfe];
69+
pub const LC3: [u8; 1] = [0x16]; // McPoodle uses single-byte loop markers
70+
pub const LC4: [u8; 1] = [0x1e];
7171
pub const LC5: [u8; 1] = [0xff];
7272
pub const LC6: [u8; 1] = [0xfe];
7373

0 commit comments

Comments
 (0)