Skip to content

Commit

Permalink
caption_frame_decode: rework API
Browse files Browse the repository at this point in the history
Fixes szatmary#59

* pop_on mode requires incrementing the frame timestamp until
  end_of_caption is encountered.

* caption_frame_decode now always updates the timestamp of the
  frame when the timestamp parameter != -1. This requires that callers
  only pass a valid timestamp when a new one is encountered, for
  example with SCC the timestamp at the start of the cue, then -1
  until the next new timestamp.

* A new enum member is added for the return value, LIBCAPTION_CLEAR.
  It allows the caller to determine that closed captions should not
  be displayed anymore, in order to finish the previous cue earlier
  than the start of the next cue.
  • Loading branch information
MathieuDuponchelle committed Mar 18, 2020
1 parent e8b6261 commit 359d568
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 13 deletions.
3 changes: 2 additions & 1 deletion caption/caption.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ typedef signed int ssize_t;
typedef enum {
LIBCAPTION_ERROR = 0,
LIBCAPTION_OK = 1,
LIBCAPTION_READY = 2
LIBCAPTION_READY = 2,
LIBCAPTION_CLEAR = 3,
} libcaption_stauts_t;

static inline libcaption_stauts_t libcaption_status_update(libcaption_stauts_t old_stat, libcaption_stauts_t new_stat)
Expand Down
2 changes: 2 additions & 0 deletions caption/srt.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ static inline utf8_char_t* srt_cue_data(srt_cue_t* cue) { return vtt_block_data(
*/
static inline srt_cue_t* srt_cue_from_caption_frame(caption_frame_t* frame, srt_t* srt) { return vtt_cue_from_caption_frame(frame, srt); };

static inline void srt_cue_finish(caption_frame_t* frame, srt_t* srt) { return vtt_cue_finish(frame, srt); };

/*! \brief
\param
*/
Expand Down
4 changes: 4 additions & 0 deletions caption/vtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ int vtt_cue_to_caption_frame(vtt_block_t* cue, caption_frame_t* frame);
\param
*/
vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t* vtt);

// finishes the last cue
void vtt_cue_finish(caption_frame_t* frame, vtt_t* vtt);

/*! \brief
\param
*/
Expand Down
14 changes: 13 additions & 1 deletion examples/scc2srt.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,23 @@ int main(int argc, char** argv)
scc_data += scc_to_608(&scc, scc_data);

while (scc->cc_size) {
double timestamp = scc->timestamp;

for (i = 0; i < scc->cc_size; ++i) {
// eia608_dump (scc->cc_data[i]);
if (LIBCAPTION_READY == caption_frame_decode(&frame, scc->cc_data[i], scc->timestamp)) {

switch (caption_frame_decode(&frame, scc->cc_data[i], timestamp)) {
case LIBCAPTION_READY:
srt_cue_from_caption_frame(&frame, srt);
break;
case LIBCAPTION_CLEAR:
srt_cue_finish(&frame, srt);
break;
default:
break;
}

timestamp = -1;
}

scc_data += scc_to_608(&scc, scc_data);
Expand Down
14 changes: 13 additions & 1 deletion examples/scc2vtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,22 @@ int main(int argc, char** argv)
scc_data += scc_to_608(&scc, scc_data);

while (scc->cc_size) {
double timestamp = scc->timestamp;

for (i = 0; i < scc->cc_size; ++i) {
if (LIBCAPTION_READY == caption_frame_decode(&frame, scc->cc_data[i], scc->timestamp)) {

switch (caption_frame_decode(&frame, scc->cc_data[i], timestamp)) {
case LIBCAPTION_READY:
vtt_cue_from_caption_frame(&frame, vtt);
break;
case LIBCAPTION_CLEAR:
vtt_cue_finish(&frame, vtt);
break;
default:
break;
}

timestamp = -1;
}

scc_data += scc_to_608(&scc, scc_data);
Expand Down
12 changes: 10 additions & 2 deletions examples/sccdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,21 @@ int main(int argc, char** argv)
scc_data += scc_to_608(&scc, scc_data);

while (scc->cc_size) {
fprintf(stderr, "Timestamp: %f\n", scc->timestamp);
double timestamp = scc->timestamp;

fprintf(stderr, "Timestamp: %f\n", timestamp);

for (i = 0; i < scc->cc_size; ++i) {
eia608_dump(scc->cc_data[i]);
if (LIBCAPTION_READY == caption_frame_decode(&frame, scc->cc_data[i], scc->timestamp)) {
switch (caption_frame_decode(&frame, scc->cc_data[i], timestamp)) {
case LIBCAPTION_READY:
caption_frame_dump(&frame);
break;
default:
break;
}

timestamp = -1;
}

scc_data += scc_to_608(&scc, scc_data);
Expand Down
18 changes: 11 additions & 7 deletions src/caption.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ libcaption_stauts_t caption_frame_decode_control(caption_frame_t* frame, uint16_

case eia608_control_erase_display_memory:
caption_frame_buffer_clear(&frame->front);
return LIBCAPTION_READY;
return LIBCAPTION_CLEAR;

// ROLL-UP
case eia608_control_roll_up_2:
Expand Down Expand Up @@ -306,17 +306,21 @@ libcaption_stauts_t caption_frame_decode(caption_frame_t* frame, uint16_t cc_dat
return frame->status;
}

if (0 > frame->timestamp || frame->timestamp == timestamp || LIBCAPTION_READY == frame->status) {
frame->timestamp = timestamp;
frame->status = LIBCAPTION_OK;
}

// skip duplicate controll commands. We also skip duplicate specialna to match the behaviour of iOS/vlc
if ((eia608_is_specialna(cc_data) || eia608_is_control(cc_data)) && cc_data == frame->state.cc_data) {
if (caption_frame_popon (frame))
frame->timestamp += (1 / 29.97);
return LIBCAPTION_OK;
}

if (timestamp >= 0) {
frame->timestamp = timestamp;
frame->status = LIBCAPTION_OK;
return frame->status;
}

if (caption_frame_popon (frame))
frame->timestamp += (1 / 29.97);

frame->state.cc_data = cc_data;

if (frame->xds.state) {
Expand Down
5 changes: 4 additions & 1 deletion src/cea708.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,13 +268,16 @@ libcaption_stauts_t cea708_to_caption_frame(caption_frame_t* frame, cea708_t* ce
libcaption_stauts_t status = LIBCAPTION_OK;

if (GA94 == cea708->user_identifier) {
float timestamp = cea708->timestamp;

for (i = 0; i < count; ++i) {
int valid;
cea708_cc_type_t type;
uint16_t cc_data = cea708_cc_data(&cea708->user_data, i, &valid, &type);

if (valid && cc_type_ntsc_cc_field_1 == type) {
status = libcaption_status_update(status, caption_frame_decode(frame, cc_data, cea708->timestamp));
status = libcaption_status_update(status, caption_frame_decode(frame, cc_data, timestamp));
timestamp = -1;
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/vtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,13 @@ vtt_block_t* vtt_cue_from_caption_frame(caption_frame_t* frame, vtt_t* vtt)
return cue;
}

void vtt_cue_finish(caption_frame_t* frame, vtt_t* vtt)
{
if (vtt->cue_tail && 0 >= vtt->cue_tail->duration) {
vtt->cue_tail->duration = frame->timestamp - vtt->cue_tail->timestamp;
}
}

static void _dump(vtt_t* vtt)
{
vtt_block_t* block;
Expand Down

0 comments on commit 359d568

Please sign in to comment.