void sei_dump_messages(sei_message_t* head, double timestamp) { cea708_t cea708; sei_message_t* msg; cea708_init(&cea708, timestamp); for (msg = head; msg; msg = sei_message_next(msg)) { uint8_t* data = sei_message_data(msg); size_t size = sei_message_size(msg); fprintf(stderr, "-- Message %p\n-- Message Type: %d\n-- Message Size: %d\n", data, sei_message_type(msg), (int)size); while (size) { fprintf(stderr, "%02X ", *data); ++data; --size; } fprintf(stderr, "\n"); if (sei_type_user_data_registered_itu_t_t35 == sei_message_type(msg)) { if (LIBCAPTION_OK != cea708_parse_h262(sei_message_data(msg), sei_message_size(msg), &cea708)) { fprintf(stderr, "cea708_parse error\n"); } else { cea708_dump(&cea708); } } } }
void sei_dump_messages (sei_message_t* head) { cea708_t cea708; sei_message_t* msg; cea708_init (&cea708); for (msg = head ; msg ; msg = sei_message_next (msg)) { uint8_t* data = sei_message_data (msg); size_t size = sei_message_size (msg); fprintf (stderr,"-- Message %p\n-- Message Type: %d\n-- Message Size: %d\n", data, sei_message_type (msg), (int) size); while (size) { fprintf (stderr,"%02X ", *data); ++data; --size; } fprintf (stderr,"\n"); if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) { cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708); cea708_dump (&cea708); } } }
size_t mpeg_bitstream_parse(mpeg_bitstream_t* packet, caption_frame_t* frame, const uint8_t* data, size_t size, unsigned stream_type, double dts, double cts) { if (MAX_NALU_SIZE <= packet->size) { packet->status = LIBCAPTION_ERROR; // fprintf(stderr, "LIBCAPTION_ERROR\n"); return 0; } // consume upto MAX_NALU_SIZE bytes if (MAX_NALU_SIZE <= packet->size + size) { size = MAX_NALU_SIZE - packet->size; } sei_t sei; size_t header_size, scpos; packet->status = LIBCAPTION_OK; memcpy(&packet->data[packet->size], data, size); packet->size += size; while (packet->status == LIBCAPTION_OK && 0 < (scpos = find_start_code(&packet->data[0], packet->size))) { switch (mpeg_bitstream_packet_type(packet, stream_type)) { default: break; case H262_SEI_PACKET: header_size = 4; if (STREAM_TYPE_H262 == stream_type && scpos > header_size) { cea708_t* cea708 = _mpeg_bitstream_cea708_emplace_back(packet, dts + cts); packet->status = libcaption_status_update(packet->status, cea708_parse_h262(&packet->data[header_size], scpos - header_size, cea708)); _mpeg_bitstream_cea708_sort_flush(packet, frame, dts); } break; case H264_SEI_PACKET: case H265_SEI_PACKET: header_size = STREAM_TYPE_H264 == stream_type ? 4 : STREAM_TYPE_H265 == stream_type ? 5 : 0; if (header_size && scpos > header_size) { packet->status = libcaption_status_update(packet->status, sei_parse(&sei, &packet->data[header_size], scpos - header_size, dts + cts)); for (sei_message_t* msg = sei_message_head(&sei); msg; msg = sei_message_next(msg)) { if (sei_type_user_data_registered_itu_t_t35 == sei_message_type(msg)) { cea708_t* cea708 = _mpeg_bitstream_cea708_emplace_back(packet, dts + cts); packet->status = libcaption_status_update(packet->status, cea708_parse_h264(sei_message_data(msg), sei_message_size(msg), cea708)); _mpeg_bitstream_cea708_sort_flush(packet, frame, dts); } } sei_free(&sei); } break; } packet->size -= scpos; memmove(&packet->data[0], &packet->data[scpos], packet->size); } return size; }
void sei_cat(sei_t* to, sei_t* from, int itu_t_t35) { if (!to || !from) { return; } sei_message_t* msg = NULL; for (msg = sei_message_head(from); msg; msg = sei_message_next(msg)) { if (itu_t_t35 || sei_type_user_data_registered_itu_t_t35 != msg->type) { sei_message_append(to, sei_message_copy(msg)); } } }
size_t sei_render_size (sei_t* sei) { size_t size = 2; // nalu_type + stop bit sei_message_t* msg; for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) { size += 1 + (msg->type / 255); size += 1 + (msg->size / 255); size += 1 + (msg->size * 4/3); } return size; }
// we can safely assume sei_render_size() bytes have been allocated for data size_t sei_render(sei_t* sei, uint8_t* data) { if (!sei || !sei->head) { return 0; } size_t escaped_size, size = 2; // nalu_type + stop bit sei_message_t* msg; (*data) = 6; ++data; for (msg = sei_message_head(sei); msg; msg = sei_message_next(msg)) { int payloadType = sei_message_type(msg); int payloadSize = (int)sei_message_size(msg); uint8_t* payloadData = sei_message_data(msg); while (255 <= payloadType) { (*data) = 255; ++data; ++size; payloadType -= 255; } (*data) = payloadType; ++data; ++size; while (255 <= payloadSize) { (*data) = 255; ++data; ++size; payloadSize -= 255; } (*data) = payloadSize; ++data; ++size; if (0 >= (escaped_size = _copy_from_rbsp(data, payloadData, payloadSize))) { return 0; } data += escaped_size; size += escaped_size; } // write stop bit and return (*data) = 0x80; return size; }
libcaption_stauts_t sei_to_caption_frame(sei_t* sei, caption_frame_t* frame) { cea708_t cea708; sei_message_t* msg; libcaption_stauts_t status = LIBCAPTION_OK; cea708_init(&cea708, frame->timestamp); for (msg = sei_message_head(sei); msg; msg = sei_message_next(msg)) { if (sei_type_user_data_registered_itu_t_t35 == sei_message_type(msg)) { cea708_parse_h264(sei_message_data(msg), sei_message_size(msg), &cea708); status = libcaption_status_update(status, cea708_to_caption_frame(frame, &cea708)); } } if (LIBCAPTION_READY == status) { frame->timestamp = sei->timestamp; } return status; }