Skip to content

Commit 03ad9e8

Browse files
authored
[FEATURE] Allow output \0 terminated frames (for WebSocket streaming support) (#2105)
* [feat] Allow output \0 terminated frames * Fix rust `FromCType` * use encoded_end_frame for text-based captions * add changelog entry * fix CEA-708 Rust decoder * fix Rust formating * remove unused `crlf` field - satisfy clippy function argument limit * silence clippy function argument limit in `Writer` * Fix writing frame end with multiline captions * fix formatting errors
1 parent 9f250b1 commit 03ad9e8

15 files changed

Lines changed: 88 additions & 16 deletions

docs/CHANGES.TXT

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
0.96.7 (unreleased)
22
-------------------
3+
- New: Allow output \0 terminated frames via --null-terminated
34
- New: Added ASS/SSA \pos-based positioning for CEA-608 captions when layout is simple (1–2 rows) (#1726)
45
- Fix: Remove strdup() memory leaks in WebVTT styling encoder, fix invalid CSS rgba(0,256,0) green value, fix missing free(unescaped) on write-error path (#2154)
56
- Fix: Prevent crash in Rust timing module when logging out-of-range PTS/FTS timestamps from malformed streams.

src/lib_ccx/ccx_common_option.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ void init_options(struct ccx_s_options *options)
134134
options->enc_cfg.trim_subs = 0; // " Remove spaces at sides? "
135135
options->enc_cfg.in_format = 1;
136136
options->enc_cfg.line_terminator_lf = 0; // 0 = CRLF
137+
options->enc_cfg.frame_terminator_0 = 0; // 0 = frames terminated by line_terminator_lf
137138
options->enc_cfg.start_credits_text = NULL;
138139
options->enc_cfg.end_credits_text = NULL;
139140
options->enc_cfg.encoding = CCX_ENC_UTF_8;

src/lib_ccx/ccx_common_option.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct encoder_cfg
6767
int no_type_setting;
6868
int cc_to_stdout; // If this is set to 1, the stdout will be flushed when data was written to the screen during a process_608 call.
6969
int line_terminator_lf; // 0 = CRLF, 1=LF
70+
int frame_terminator_0; // 0 = frames terminated by line_terminator_lf, 1 = frames terminated by \0
7071
LLONG subs_delay; // ms to delay (or advance) subs
7172
int program_number;
7273
unsigned char in_format;

src/lib_ccx/ccx_encoders_common.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,17 @@ struct encoder_ctx *init_encoder(struct encoder_cfg *opt)
843843

844844
ctx->encoded_br_length = encode_line(ctx, ctx->encoded_br, (unsigned char *)"<br>");
845845

846+
if (opt->frame_terminator_0)
847+
{
848+
ctx->encoded_end_frame[0] = '\0';
849+
ctx->encoded_end_frame_length = 1;
850+
}
851+
else
852+
{
853+
memcpy(ctx->encoded_end_frame, ctx->encoded_crlf, ctx->encoded_crlf_length + 1);
854+
ctx->encoded_end_frame_length = ctx->encoded_crlf_length;
855+
}
856+
846857
for (i = 0; i < ctx->nb_out; i++)
847858
write_subtitle_file_header(ctx, ctx->out + i);
848859

src/lib_ccx/ccx_encoders_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ struct encoder_ctx
146146
unsigned int encoded_crlf_length;
147147
unsigned char encoded_br[16];
148148
unsigned int encoded_br_length;
149+
unsigned char encoded_end_frame[16];
150+
unsigned int encoded_end_frame_length;
149151

150152
// MCC File
151153
int header_printed_flag;

src/lib_ccx/ccx_encoders_transcript.c

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *c
9292
}
9393
}
9494

95-
write_wrapped(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
95+
write_wrapped(context->out->fh, context->encoded_end_frame, context->encoded_end_frame_length);
9696
}
9797
}
9898
#endif
@@ -134,6 +134,7 @@ int write_cc_subtitle_as_transcript(struct cc_subtitle *sub, struct encoder_ctx
134134

135135
str = sub->data;
136136

137+
int wrote_something = 0;
137138
str = strtok_r(str, "\r\n", &save_str);
138139
do
139140
{
@@ -143,6 +144,15 @@ int write_cc_subtitle_as_transcript(struct cc_subtitle *sub, struct encoder_ctx
143144
continue;
144145
}
145146

147+
if (wrote_something)
148+
{
149+
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
150+
if (ret < context->encoded_crlf_length)
151+
{
152+
mprint("Warning:Loss of data\n");
153+
}
154+
}
155+
146156
if (context->transcript_settings->showStartTime)
147157
{
148158
char buf[80];
@@ -200,14 +210,16 @@ int write_cc_subtitle_as_transcript(struct cc_subtitle *sub, struct encoder_ctx
200210
mprint("Warning:Loss of data\n");
201211
}
202212

203-
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
204-
if (ret < context->encoded_crlf_length)
205-
{
206-
mprint("Warning:Loss of data\n");
207-
}
213+
wrote_something = 1;
208214

209215
} while ((str = strtok_r(NULL, "\r\n", &save_str)));
210216

217+
ret = write(context->out->fh, context->encoded_end_frame, context->encoded_end_frame_length);
218+
if (ret < context->encoded_end_frame_length)
219+
{
220+
mprint("Warning:Loss of data\n");
221+
}
222+
211223
freep(&sub->data);
212224
lsub = sub;
213225
sub = sub->next;
@@ -321,29 +333,43 @@ void write_cc_line_as_transcript2(struct eia608_screen *data, struct encoder_ctx
321333
{
322334
mprint("Warning:Loss of data\n");
323335
}
324-
325-
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
326-
if (ret < context->encoded_crlf_length)
327-
{
328-
mprint("Warning:Loss of data\n");
329-
}
330336
}
331337
// fprintf (wb->fh,encoded_crlf);
332338
}
333339

334340
int write_cc_buffer_as_transcript2(struct eia608_screen *data, struct encoder_ctx *context)
335341
{
342+
int ret;
336343
int wrote_something = 0;
337344
dbg_print(CCX_DMT_DECODER_608, "\n- - - TRANSCRIPT caption - - -\n");
338345

339346
for (int i = 0; i < 15; i++)
340347
{
341348
if (data->row_used[i])
342349
{
350+
if (wrote_something)
351+
{
352+
ret = write(context->out->fh, context->encoded_crlf, context->encoded_crlf_length);
353+
if (ret < context->encoded_crlf_length)
354+
{
355+
mprint("Warning:Loss of data\n");
356+
}
357+
}
358+
343359
write_cc_line_as_transcript2(data, context, i);
360+
wrote_something = 1;
344361
}
345-
wrote_something = 1;
346362
}
363+
364+
if (wrote_something)
365+
{
366+
ret = write(context->out->fh, context->encoded_end_frame, context->encoded_end_frame_length);
367+
if (ret < context->encoded_end_frame_length)
368+
{
369+
mprint("Warning:Loss of data\n");
370+
}
371+
}
372+
347373
dbg_print(CCX_DMT_DECODER_608, "- - - - - - - - - - - -\r\n");
348374
return wrote_something;
349375
}

src/lib_ccx/params.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ void print_usage(void)
347347
mprint(" to the output file.\n");
348348
mprint(" --lf: Use LF (UNIX) instead of CRLF (DOS, Windows) as line\n");
349349
mprint(" terminator.\n");
350+
mprint(" --null-terminated: Use \\0 instead of CRLF or LF for frame termination (see '--lf').\n");
351+
mprint(" e.g use '--txt --stdout --null-terminated' when piping to\n");
352+
mprint(" 'websocat -0' (https://github.com/vi/websocat)\n");
350353
mprint(" --df: For MCC Files, force dropframe frame count.\n");
351354
mprint(" --autodash: Based on position on screen, attempt to determine\n");
352355
mprint(" the different speakers and a dash (-) when each\n");

src/rust/lib_ccxr/src/common/options.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ impl Default for EncoderConfig {
248248
no_type_setting: false,
249249
cc_to_stdout: false,
250250
line_terminator_lf: false,
251+
frame_terminator_0: false,
251252
subs_delay: Timestamp::default(),
252253
program_number: 0,
253254
in_format: 1,
@@ -324,6 +325,8 @@ pub struct EncoderConfig {
324325
pub cc_to_stdout: bool,
325326
/// false = CRLF, true = LF
326327
pub line_terminator_lf: bool,
328+
/// false = frames terminated by line_terminator_lf, true = frames terminated by \0
329+
pub frame_terminator_0: bool,
327330
/// ms to delay (or advance) subs
328331
pub subs_delay: Timestamp,
329332
pub program_number: u32,

src/rust/src/args.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,9 @@ pub struct Args {
565565
/// terminator.
566566
#[arg(long, verbatim_doc_comment, help_heading=OUTPUT_AFFECTING_OUTPUT_FILES)]
567567
pub lf: bool,
568+
/// Use \0 instead of CRLF or LF for frame termination (see '--lf')
569+
#[arg(long, verbatim_doc_comment, help_heading=OUTPUT_AFFECTING_OUTPUT_FILES)]
570+
pub null_terminated: bool,
568571
/// For MCC Files, force dropframe frame count.
569572
#[arg(long, verbatim_doc_comment, help_heading=OUTPUT_AFFECTING_OUTPUT_FILES)]
570573
pub df: bool,

src/rust/src/common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ impl CType<encoder_cfg> for EncoderConfig {
960960
no_type_setting: self.no_type_setting as _,
961961
cc_to_stdout: self.cc_to_stdout as _,
962962
line_terminator_lf: self.line_terminator_lf as _,
963+
frame_terminator_0: self.frame_terminator_0 as _,
963964
subs_delay: self.subs_delay.millis(),
964965
program_number: self.program_number as _,
965966
in_format: self.in_format,

0 commit comments

Comments
 (0)