void sei_free(sei_t* sei) { sei_message_t* tail; while (sei->head) { tail = sei->head->next; free(sei->head); sei->head = tail; } sei_init(sei, 0); }
libcaption_stauts_t sei_parse(sei_t* sei, const uint8_t* data, size_t size, double timestamp) { sei_init(sei, timestamp); int ret = 0; // SEI may contain more than one payload while (1 < size) { size_t payloadType = 0; size_t payloadSize = 0; while (0 < size && 255 == (*data)) { payloadType += 255; ++data, --size; } if (0 == size) { return LIBCAPTION_ERROR; } payloadType += (*data); ++data, --size; while (0 < size && 255 == (*data)) { payloadSize += 255; ++data, --size; } if (0 == size) { return LIBCAPTION_ERROR; } payloadSize += (*data); ++data, --size; if (payloadSize) { sei_message_t* msg = sei_message_new((sei_msgtype_t)payloadType, 0, payloadSize); uint8_t* payloadData = sei_message_data(msg); size_t bytes = _copy_to_rbsp(payloadData, payloadSize, data, size); sei_message_append(sei, msg); if (bytes < payloadSize) { return LIBCAPTION_ERROR; } data += bytes; size -= bytes; ++ret; } } // There should be one trailing byte, 0x80. But really, we can just ignore that fact. return LIBCAPTION_OK; }
//////////////////////////////////////////////////////////////////////////////// // TODO move this out of sei libcaption_stauts_t sei_from_caption_frame(sei_t* sei, caption_frame_t* frame) { int r, c; int unl, prev_unl; cea708_t cea708; const char* data; uint16_t prev_cc_data; eia608_style_t styl, prev_styl; sei_init(sei, frame->timestamp); cea708_init(&cea708, frame->timestamp); // set up a new popon frame cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_erase_non_displayed_memory, DEFAULT_CHANNEL)); cea708_add_cc_data(&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command(eia608_control_resume_caption_loading, DEFAULT_CHANNEL)); for (r = 0; r < SCREEN_ROWS; ++r) { prev_unl = 0, prev_styl = eia608_style_white; // Calculate preamble for (c = 0; c < SCREEN_COLS && 0 == *caption_frame_read_char(frame, r, c, &styl, &unl); ++c) { } // This row is blank if (SCREEN_COLS == c) { continue; } // Write preamble if (0 < c || (0 == unl && eia608_style_white == styl)) { int tab = c % 4; sei_encode_eia608(sei, &cea708, eia608_row_column_pramble(r, c, DEFAULT_CHANNEL, 0)); if (tab) { sei_encode_eia608(sei, &cea708, eia608_tab(tab, DEFAULT_CHANNEL)); } } else { sei_encode_eia608(sei, &cea708, eia608_row_style_pramble(r, DEFAULT_CHANNEL, styl, unl)); prev_unl = unl, prev_styl = styl; } // Write the row for (prev_cc_data = 0, data = caption_frame_read_char(frame, r, c, 0, 0); (*data) && c < SCREEN_COLS; ++c, data = caption_frame_read_char(frame, r, c, &styl, &unl)) { uint16_t cc_data = eia608_from_utf8_1(data, DEFAULT_CHANNEL); if (unl != prev_unl || styl != prev_styl) { sei_encode_eia608(sei, &cea708, eia608_midrow_change(DEFAULT_CHANNEL, styl, unl)); prev_unl = unl, prev_styl = styl; } if (!cc_data) { // We do't want to write bad data, so just ignore it. } else if (eia608_is_basicna(prev_cc_data)) { if (eia608_is_basicna(cc_data)) { // previous and current chars are both basicna, combine them into current sei_encode_eia608(sei, &cea708, eia608_from_basicna(prev_cc_data, cc_data)); } else if (eia608_is_westeu(cc_data)) { // extended charcters overwrite the previous charcter, so insert a dummy char thren write the extended char sei_encode_eia608(sei, &cea708, eia608_from_basicna(prev_cc_data, eia608_from_utf8_1(EIA608_CHAR_SPACE, DEFAULT_CHANNEL))); sei_encode_eia608(sei, &cea708, cc_data); } else { // previous was basic na, but current isnt; write previous and current sei_encode_eia608(sei, &cea708, prev_cc_data); sei_encode_eia608(sei, &cea708, cc_data); } prev_cc_data = 0; // previous is handled, we can forget it now } else if (eia608_is_westeu(cc_data)) { // extended chars overwrite the previous chars, so insert a dummy char // TODO create a map of alternamt chars for eia608_is_westeu instead of using space sei_encode_eia608(sei, &cea708, eia608_from_utf8_1(EIA608_CHAR_SPACE, DEFAULT_CHANNEL)); sei_encode_eia608(sei, &cea708, cc_data); } else if (eia608_is_basicna(cc_data)) { prev_cc_data = cc_data; } else { sei_encode_eia608(sei, &cea708, cc_data); } if (eia608_is_specialna(cc_data)) { // specialna are treated as control charcters. Duplicated control charcters are discarded // So we write a resume after a specialna as a noop to break repetition detection // TODO only do this if the same charcter is repeated sei_encode_eia608(sei, &cea708, eia608_control_command(eia608_control_resume_caption_loading, DEFAULT_CHANNEL)); } } if (0 != prev_cc_data) { sei_encode_eia608(sei, &cea708, prev_cc_data); } } sei_encode_eia608(sei, &cea708, 0); // flush sei->timestamp = frame->timestamp; // assumes in order frames // sei_dump (sei); return LIBCAPTION_OK; }
int sei_parse_nalu (sei_t* sei, const uint8_t* data, size_t size, double dts, double cts) { assert (0<=cts); // cant present before decode sei->dts = dts; sei->cts = cts; int ret = 0; if (0 == data || 0 == size) { return 0; } uint8_t nal_unit_type = (*data) & 0x1F; ++data; --size; if (6 != nal_unit_type) { return 0; } // SEI may contain more than one payload while (1<size) { int payloadType = 0; int payloadSize = 0; while (0 < size && 255 == (*data)) { payloadType += 255; ++data; --size; } if (0 == size) { goto error; } payloadType += (*data); ++data; --size; while (0 < size && 255 == (*data)) { payloadSize += 255; ++data; --size; } if (0 == size) { goto error; } payloadSize += (*data); ++data; --size; if (payloadSize) { sei_message_t* msg = sei_message_new ( (sei_msgtype_t) payloadType, 0, payloadSize); uint8_t* payloadData = sei_message_data (msg); size_t bytes = _copy_to_rbsp (payloadData, payloadSize, data, size); sei_message_append (sei, msg); if ( (int) bytes < payloadSize) { goto error; } data += bytes; size -= bytes; ++ret; } } // There should be one trailing byte, 0x80. But really, we can just ignore that fact. return ret; error: sei_init (sei); return 0; }