// D.1.1 SEI buffering period syntax static void read_sei_type_0(h264_stream_t* h, sei_t* s) { int sched_sel_idx; bs_t bs; sps_t *sps = h->sps; sei_type_0 *bp = malloc(sizeof(sei_type_0)); bs_init(&bs, s->payload, s->payloadSize); bp->seq_parameter_set_id = bs_read_ue(&bs); if(sps->vui.nal_hrd_parameters_present_flag) { for (sched_sel_idx = 0; sched_sel_idx < sps->hrd.cpb_cnt_minus1 + 1; sched_sel_idx++) { bp->initial_cbp_removal_delay[sched_sel_idx] = bs_read_u(&bs, sps->hrd.initial_cpb_removal_delay_length_minus1 + 1); bp->initial_cbp_removal_delay_offset[sched_sel_idx] = bs_read_u(&bs, sps->hrd.initial_cpb_removal_delay_length_minus1 + 1); } } if (sps->vui.vcl_hrd_parameters_present_flag) { for (sched_sel_idx = 0; sched_sel_idx < sps->hrd.cpb_cnt_minus1 + 1; sched_sel_idx++) { bp->initial_cbp_removal_delay[sched_sel_idx] = bs_read_u(&bs, sps->hrd.initial_cpb_removal_delay_length_minus1 + 1); bp->initial_cbp_removal_delay_offset[sched_sel_idx] = bs_read_u(&bs, sps->hrd.initial_cpb_removal_delay_length_minus1 + 1); } } s->sei_type_struct = bp; }
int es_info_read(elementary_stream_info_t *es, bs_t *b) { int es_info_start = bs_pos(b); es->stream_type = bs_read_u8(b); bs_skip_u(b, 3); es->elementary_PID = bs_read_u(b, 13); bs_skip_u(b, 4); es->ES_info_length = bs_read_u(b, 12); LOG_DEBUG_ARGS ("es_info_read: es_info_start = %d, bs_pos(b) = %d, b->end = %d", es_info_start, bs_pos(b), b->end - b->start); LOG_DEBUG_ARGS ("es_info_read pre-return %d", bs_pos(b) - es_info_start); LOG_DEBUG_ARGS ("es_info_read: PID = %d, streamType = 0x%x, ES_info_length = %d. Calling read_descriptor_loop", es->elementary_PID, es->stream_type, es->ES_info_length); read_descriptor_loop(es->descriptors, b, es->ES_info_length); if (es->ES_info_length > MAX_ES_INFO_LEN) { LOG_ERROR_ARGS("ES info length is 0x%02X, larger than maximum allowed 0x%02X", es->ES_info_length, MAX_ES_INFO_LEN); reportAddErrorLogArgs("ES info length is 0x%02X, larger than maximum allowed 0x%02X", es->ES_info_length, MAX_ES_INFO_LEN); SAFE_REPORT_TS_ERR(-60); return 0; } LOG_DEBUG_ARGS ("es_info_read returning %d", bs_pos(b) - es_info_start); return bs_pos(b) - es_info_start; }
static void read_user_data_unregistered(h264_stream_t* h, bs_t* b, int payloadSize) { sei_t* s = h->sei; s->payload = (uint8_t*)malloc(payloadSize); int i; // uuid_iso_iec_11578 todo... for (i = 0; i < 16; i++) s->payload[i] = bs_read_u(b, 8); for (i = 16; i < payloadSize; i++) s->payload[i] = bs_read_u(b, 8); }
// D.1 SEI payload syntax void read_sei_payload( h264_stream_t* h, bs_t* b, int payloadType, int payloadSize) { sei_t* s = h->sei; s->payload = malloc(payloadSize); int i; for( i = 0; i < payloadSize; i++ ) { s->payload[i] = bs_read_u(b, 8); } switch (payloadType) { case SEI_TYPE_BUFFERING_PERIOD: read_sei_type_0(h, s); break; case SEI_TYPE_PIC_TIMING: read_sei_type_1(h, s); break; default: //Not implemented break; } }
void find_nal_unit_type(unsigned char *buf, int *nal_start) { int j; bs_t* b = bs_new(buf, h264buffersize); j = bs_read_u(b,5); printf("%d \n \n ",j); return; }
static inline uint32_t section_header_read(section_header_t *sh, bs_t *b) { sh->table_id = bs_read_u8(b); sh->section_syntax_indicator = bs_read_u1(b); sh->private_indicator = bs_read_u1(b); bs_skip_u(b,2); sh->section_length = bs_read_u(b,12); return sh->table_id; }
int es_info_read(elementary_stream_info_t *es, bs_t *b) { int es_info_start = bs_pos(b); es->stream_type = bs_read_u8(b); bs_skip_u(b, 3); es->elementary_PID = bs_read_u(b, 13); bs_skip_u(b, 4); es->ES_info_length = bs_read_u(b, 12); read_descriptor_loop(es->descriptors, b, es->ES_info_length); if (es->ES_info_length > MAX_ES_INFO_LEN) { LOG_ERROR_ARGS("ES info length is 0x%02X, larger than maximum allowed 0x%02X", es->ES_info_length, MAX_ES_INFO_LEN); SAFE_REPORT_TS_ERR(-60); return 0; } return bs_pos(b) - es_info_start; }
// D.1 SEI payload syntax void read_sei_payload( h264_stream_t* h, bs_t* b, int payloadType, int payloadSize) { int i; sei_t* s = h->sei; s->payload = realloc(s->payload, payloadSize); for( i = 0; i < payloadSize; i++ ) { s->payload[i] = bs_read_u(b, 8); } }
uint32_t bs_read_ue(bs_t* b) { int32_t r = 0; int i = 0; while( bs_read_u1(b) == 0 && i < 32 && !bs_eof(b) ) { i++; } r = bs_read_u(b, i); r += (1 << i) - 1; return r; }
/** Read only the NAL headers (enough to determine unit type) from a byte buffer. @return unit type if read successfully, or -1 if this doesn't look like a nal */ int peek_nal_unit(h264_stream_t* h, uint8_t* buf, int size) { nal_t* nal = h->nal; bs_t* b = bs_new(buf, size); nal->forbidden_zero_bit = bs_read_f(b,1); nal->nal_ref_idc = bs_read_u(b,2); nal->nal_unit_type = bs_read_u(b,5); bs_free(b); // basic verification, per 7.4.1 if ( nal->forbidden_zero_bit ) { return -1; } if ( nal->nal_unit_type <= 0 || nal->nal_unit_type > 20 ) { return -1; } if ( nal->nal_unit_type > 15 && nal->nal_unit_type < 19 ) { return -1; } if ( nal->nal_ref_idc == 0 ) { if ( nal->nal_unit_type == NAL_UNIT_TYPE_CODED_SLICE_IDR ) { return -1; } } else { if ( nal->nal_unit_type == NAL_UNIT_TYPE_SEI || nal->nal_unit_type == NAL_UNIT_TYPE_AUD || nal->nal_unit_type == NAL_UNIT_TYPE_END_OF_SEQUENCE || nal->nal_unit_type == NAL_UNIT_TYPE_END_OF_STREAM || nal->nal_unit_type == NAL_UNIT_TYPE_FILLER ) { return -1; } } return nal->nal_unit_type; }
int read_avcc(avcc_t* avcc, h264_stream_t* h, bs_t* b) { avcc->configurationVersion = bs_read_u8(b); avcc->AVCProfileIndication = bs_read_u8(b); avcc->profile_compatibility = bs_read_u8(b); avcc->AVCLevelIndication = bs_read_u8(b); /* int reserved = */ bs_read_u(b, 6); // '111111'b; avcc->lengthSizeMinusOne = bs_read_u(b, 2); /* int reserved = */ bs_read_u(b, 3); // '111'b; avcc->numOfSequenceParameterSets = bs_read_u(b, 5); avcc->sps_table = (sps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(sps_t*)); int i; for (i = 0; i < avcc->numOfSequenceParameterSets; i++) { int sequenceParameterSetLength = bs_read_u(b, 16); int len = sequenceParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = bs_read_bytes(b, buf, len); int rc = read_nal_unit(h, buf, len); free(buf); if (h->nal->nal_unit_type != NAL_UNIT_TYPE_SPS) { continue; } // TODO report errors if (rc < 0) { continue; } avcc->sps_table[i] = h->sps; // TODO copy data? } avcc->numOfPictureParameterSets = bs_read_u(b, 8); avcc->pps_table = (pps_t**)calloc(avcc->numOfSequenceParameterSets, sizeof(pps_t*)); for (i = 0; i < avcc->numOfPictureParameterSets; i++) { int pictureParameterSetLength = bs_read_u(b, 16); int len = pictureParameterSetLength; uint8_t* buf = (uint8_t*)malloc(len); len = bs_read_bytes(b, buf, len); int rc = read_nal_unit(h, buf, len); free(buf); if (h->nal->nal_unit_type != NAL_UNIT_TYPE_PPS) { continue; } // TODO report errors if (rc < 0) { continue; } avcc->pps_table[i] = h->pps; // TODO copy data? } if (bs_overrun(b)) { return -1; } return bs_pos(b); }
//Appendix E.1.2 HRD parameters syntax void read_hrd_parameters(sps_t* sps, bs_t* b) { int SchedSelIdx; sps->hrd.cpb_cnt_minus1 = bs_read_ue(b); sps->hrd.bit_rate_scale = bs_read_u(b,4); sps->hrd.cpb_size_scale = bs_read_u(b,4); for( SchedSelIdx = 0; SchedSelIdx <= sps->hrd.cpb_cnt_minus1; SchedSelIdx++ ) { sps->hrd.bit_rate_value_minus1[ SchedSelIdx ] = bs_read_ue(b); sps->hrd.cpb_size_value_minus1[ SchedSelIdx ] = bs_read_ue(b); sps->hrd.cbr_flag[ SchedSelIdx ] = bs_read_u1(b); } sps->hrd.initial_cpb_removal_delay_length_minus1 = bs_read_u(b,5); sps->hrd.cpb_removal_delay_length_minus1 = bs_read_u(b,5); sps->hrd.dpb_output_delay_length_minus1 = bs_read_u(b,5); sps->hrd.time_offset_length = bs_read_u(b,5); }
int pes_read_header(pes_header_t *ph, bs_t *b) { int PES_packet_start = bs_pos(b); // we *really* care about bytes 0..19, as we can cheat and manipulate PTS/DTS this way if (bs_bytes_left(b) < 20) return 0; // bytes 0..2 uint32_t pes_packet_start_code = bs_read_u24(b); if (pes_packet_start_code != PES_PACKET_START_CODE_PREFIX) { int actually_read = bs_pos(b) - PES_packet_start; b->p -= actually_read; // undo the read LOG_WARN_ARGS("PES packet starts with 0x%06X instead of expected start code 0x%06X, skipping it", pes_packet_start_code, PES_PACKET_START_CODE_PREFIX); return 0; // bail out! something is fishy! } // bytes 3..5 ph->stream_id = bs_read_u8(b); ph->PES_packet_length = bs_read_u16(b); if (HAS_PES_HEADER(ph->stream_id)) { // byte 6 bs_skip_u(b, 2); ph->PES_scrambling_control = bs_read_u(b, 2); ph->PES_priority = bs_read_u1(b); ph->data_alignment_indicator = bs_read_u1(b); ph->copyright = bs_read_u1(b); ph->original_or_copy = bs_read_u1(b); // byte 7 ph->PTS_DTS_flags = bs_read_u(b, 2); ph->ESCR_flag = bs_read_u1(b); ph->ES_rate_flag = bs_read_u1(b); ph->DSM_trick_mode_flag = bs_read_u1(b); ph->additional_copy_info_flag = bs_read_u1(b); ph->PES_CRC_flag = bs_read_u1(b); ph->PES_extension_flag = bs_read_u1(b); // byte 8 ph->PES_header_data_length = bs_read_u8(b); int PES_packet_optional_start = bs_pos(b); // byte 9..14 if (ph->PTS_DTS_flags & PES_PTS_FLAG) { bs_skip_u(b, 4); ph->PTS = bs_read_90khz_timestamp(b); } // byte 15..19 if (ph->PTS_DTS_flags & PES_DTS_FLAG) { bs_skip_u(b, 4); ph->DTS = bs_read_90khz_timestamp(b); } if (ph->ESCR_flag) { bs_skip_u(b, 2); ph->ESCR_base = bs_read_90khz_timestamp(b); ph->ESCR_extension = bs_read_u(b, 9); bs_skip_u1(b); } if (ph->ES_rate_flag) { bs_skip_u1(b); ph->ES_rate = bs_read_u(b, 22); bs_skip_u1(b); } if (ph->DSM_trick_mode_flag) { ph->trick_mode_control = bs_read_u(b, 3); switch (ph->trick_mode_control) { case PES_DSM_TRICK_MODE_CTL_FAST_FORWARD: case PES_DSM_TRICK_MODE_CTL_FAST_REVERSE: ph->field_id = bs_read_u(b, 2); ph->intra_slice_refresh = bs_read_u1(b); ph->frequency_truncation = bs_read_u(b, 2); break; case PES_DSM_TRICK_MODE_CTL_SLOW_MOTION: case PES_DSM_TRICK_MODE_CTL_SLOW_REVERSE: ph->rep_cntrl = bs_read_u(b, 5); break; case PES_DSM_TRICK_MODE_CTL_FREEZE_FRAME: ph->field_id = bs_read_u(b, 2); bs_skip_u(b, 3); break; default: bs_skip_u(b, 5); break; } } if (ph->additional_copy_info_flag) { bs_skip_u1(b); ph->additional_copy_info = bs_read_u(b, 7); } if (ph->PES_CRC_flag) { ph->previous_PES_packet_CRC = bs_read_u16(b); } if (ph->PES_extension_flag) { ph->PES_private_data_flag = bs_read_u1(b); ph->pack_header_field_flag = bs_read_u1(b); ph->program_packet_sequence_counter_flag = bs_read_u1(b); ph->PSTD_buffer_flag = bs_read_u1(b); bs_skip_u(b, 3); ph->PES_extension_flag_2 = bs_read_u1(b); if (ph->PES_private_data_flag) bs_read_bytes(b, ph->PES_private_data, 16); if (ph->pack_header_field_flag) { // whoever discovers the need for pack_header() is welcome to implement it. // I haven't. ph->pack_field_length = bs_read_u8(b); bs_skip_bytes(b, ph->pack_field_length); } if (ph->program_packet_sequence_counter_flag) { bs_skip_u1(b); ph->program_packet_sequence_counter = bs_read_u(b, 7); bs_skip_u1(b); ph->MPEG1_MPEG2_identifier = bs_read_u1(b); ph->original_stuff_length = bs_read_u(b, 6); } if (ph->PSTD_buffer_flag) { bs_skip_u(b, 2); ph->PSTD_buffer_scale = bs_read_u1(b); ph->PSTD_buffer_size = bs_read_u(b, 13); } if (ph->PES_extension_flag_2) { int PES_extension_field_start = bs_pos(b); bs_skip_u1(b); ph->PES_extension_field_length = bs_read_u(b, 7); ph->stream_id_extension_flag = bs_read_u1(b); if (!ph->stream_id_extension_flag) { ph->stream_id_extension = bs_read_u(b, 7); } else { bs_skip_u(b, 6); ph->tref_extension_flag = bs_read_u1(b); if (ph->tref_extension_flag) { bs_skip_u(b, 4); ph->TREF = bs_read_90khz_timestamp(b); } } int PES_extension_bytes_left = bs_pos(b) - PES_extension_field_start; if (PES_extension_bytes_left > 0) bs_skip_bytes(b, PES_extension_bytes_left); } } int PES_optional_bytes_read = bs_pos(b) - PES_packet_optional_start; int stuffing_bytes_len = ph->PES_header_data_length - PES_optional_bytes_read; // if any if (stuffing_bytes_len > 0) bs_skip_bytes(b, stuffing_bytes_len); } return (bs_pos(b) - PES_packet_start); }
int program_association_section_read(program_association_section_t *pas, uint8_t *buf, size_t buf_len, uint32_t payload_unit_start_indicator, psi_table_buffer_t *patBuffer) { vqarray_t *programs; int num_programs = 0; if (pas == NULL || buf == NULL) { SAFE_REPORT_TS_ERR(-1); return 0; } bs_t *b = NULL; if (!payload_unit_start_indicator && patBuffer->buffer == NULL) { // this TS packet is not start of table, and we have no cached table data LOG_WARN ("program_association_section_read: payload_unit_start_indicator not set and no cached data"); return 0; } if (payload_unit_start_indicator) { uint8_t payloadStartPtr = buf[0]; buf += (payloadStartPtr + 1); buf_len -= (payloadStartPtr + 1); LOG_DEBUG_ARGS ("program_association_section_read: payloadStartPtr = %d", payloadStartPtr); } // check for pat spanning multiple TS packets if (patBuffer->buffer != NULL) { LOG_DEBUG_ARGS ("program_association_section_read: patBuffer detected: patBufferAllocSz = %d, patBufferUsedSz = %d", patBuffer->bufferAllocSz, patBuffer->bufferUsedSz); size_t numBytesToCopy = buf_len; if (buf_len > (patBuffer->bufferAllocSz - patBuffer->bufferUsedSz)) { numBytesToCopy = patBuffer->bufferAllocSz - patBuffer->bufferUsedSz; } LOG_DEBUG_ARGS ("program_association_section_read: copying %d bytes to patBuffer", numBytesToCopy); memcpy (patBuffer->buffer + patBuffer->bufferUsedSz, buf, numBytesToCopy); patBuffer->bufferUsedSz += numBytesToCopy; if (patBuffer->bufferUsedSz < patBuffer->bufferAllocSz) { LOG_DEBUG ("program_association_section_read: patBuffer not yet full -- returning"); return 0; } b = bs_new(patBuffer->buffer, patBuffer->bufferUsedSz); } else { b = bs_new(buf, buf_len); } pas->table_id = bs_read_u8(b); if (pas->table_id != program_association_section) { LOG_ERROR_ARGS("Table ID in PAT is 0x%02X instead of expected 0x%02X", pas->table_id, program_association_section); reportAddErrorLogArgs("Table ID in PAT is 0x%02X instead of expected 0x%02X", pas->table_id, program_association_section); SAFE_REPORT_TS_ERR(-30); resetPSITableBuffer(patBuffer); bs_free (b); return 0; } // read byte 0 pas->section_syntax_indicator = bs_read_u1(b); if (!pas->section_syntax_indicator) { LOG_ERROR("section_syntax_indicator not set in PAT"); reportAddErrorLog("section_syntax_indicator not set in PAT"); SAFE_REPORT_TS_ERR(-31); resetPSITableBuffer(patBuffer); bs_free (b); return 0; } bs_skip_u(b, 3); // TODO read the zero bit, check it to be zero pas->section_length = bs_read_u(b, 12); if (pas->section_length > MAX_SECTION_LEN) { LOG_ERROR_ARGS("PAT section length is 0x%02X, larger than maximum allowed 0x%02X", pas->section_length, MAX_SECTION_LEN); reportAddErrorLogArgs("PAT section length is 0x%02X, larger than maximum allowed 0x%02X", pas->section_length, MAX_SECTION_LEN); SAFE_REPORT_TS_ERR(-32); resetPSITableBuffer(patBuffer); bs_free (b); return 0; } if (pas->section_length > bs_bytes_left(b)) { LOG_DEBUG ("program_association_section_read: Detected section spans more than one TS packet -- allocating buffer"); if (patBuffer->buffer != NULL) { // should never get here LOG_ERROR ("program_association_section_read: unexpected patBufffer"); reportAddErrorLog ("program_association_section_read: unexpected patBufffer"); resetPSITableBuffer(patBuffer); } patBuffer->bufferAllocSz = pas->section_length + 3; patBuffer->buffer = (uint8_t *)calloc (pas->section_length + 3, 1); memcpy (patBuffer->buffer, buf, buf_len); patBuffer->bufferUsedSz = buf_len; bs_free (b); return 0; } // read bytes 1,2 pas->transport_stream_id = bs_read_u16(b); // read bytes 3,4 bs_skip_u(b, 2); pas->version_number = bs_read_u(b, 5); pas->current_next_indicator = bs_read_u1(b); if (!pas->current_next_indicator) LOG_WARN("This PAT is not yet applicable/n"); // read byte 5 pas->section_number = bs_read_u8(b); pas->last_section_number = bs_read_u8(b); if (pas->section_number != 0 || pas->last_section_number != 0) LOG_WARN("Multi-section PAT is not supported yet/n"); // read bytes 6,7 num_programs = (pas->section_length - 5 - 4) / 4; // Programs listed in the PAT // explanation: section_length gives us the length from the end of section_length // we used 5 bytes for the mandatory section fields, and will use another 4 bytes for CRC // the remaining bytes contain program information, which is 4 bytes per iteration // It's much shorter in C :-) // Read the program loop, but ignore the NIT PID "program" programs = vqarray_new(); for (uint32_t i = 0; i < num_programs; i++) { program_info_t *prog = malloc(sizeof(program_info_t)); prog->program_number = bs_read_u16(b); if (prog->program_number == 0) { // Skip the NIT PID program (not a real program) free(prog); bs_skip_u(b, 16); continue; } bs_skip_u(b, 3); prog->program_map_PID = bs_read_u(b, 13); vqarray_add(programs, (vqarray_elem_t*)prog); } // This is our true number of programs pas->_num_programs = vqarray_length(programs); if (pas->_num_programs > 1) LOG_WARN_ARGS("%zd programs found, but only SPTS is fully supported. Patches are welcome.", pas->_num_programs); // Copy form our vqarray into the native array pas->programs = malloc(pas->_num_programs * sizeof(program_info_t)); for (uint32_t i = 0; i < pas->_num_programs; i++) { program_info_t* prog = (program_info_t*)vqarray_pop(programs); pas->programs[i] = *prog; free(prog); } vqarray_free(programs); pas->CRC_32 = bs_read_u32(b); // check CRC crc_t pas_crc = crc_init(); pas_crc = crc_update(pas_crc, buf, bs_pos(b) - 4); pas_crc = crc_finalize(pas_crc); if (pas_crc != pas->CRC_32) { LOG_ERROR_ARGS("PAT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pas->CRC_32, pas_crc); reportAddErrorLogArgs("PAT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pas->CRC_32, pas_crc); SAFE_REPORT_TS_ERR(-33); resetPSITableBuffer(patBuffer); bs_free (b); return 0; } else { // LOG_DEBUG("PAT CRC_32 checked successfully"); // don't enable unless you want to see this every ~100ms } bs_free(b); resetPSITableBuffer(patBuffer); return 1; }
//Appendix E.1.1 VUI parameters syntax void read_vui_parameters(sps_t* sps, bs_t* b) { sps->vui.aspect_ratio_info_present_flag = bs_read_u1(b); if( sps->vui.aspect_ratio_info_present_flag ) { sps->vui.aspect_ratio_idc = bs_read_u8(b); if( sps->vui.aspect_ratio_idc == SAR_Extended ) { sps->vui.sar_width = bs_read_u(b,16); sps->vui.sar_height = bs_read_u(b,16); } } sps->vui.overscan_info_present_flag = bs_read_u1(b); if( sps->vui.overscan_info_present_flag ) { sps->vui.overscan_appropriate_flag = bs_read_u1(b); } sps->vui.video_signal_type_present_flag = bs_read_u1(b); if( sps->vui.video_signal_type_present_flag ) { sps->vui.video_format = bs_read_u(b,3); sps->vui.video_full_range_flag = bs_read_u1(b); sps->vui.colour_description_present_flag = bs_read_u1(b); if( sps->vui.colour_description_present_flag ) { sps->vui.colour_primaries = bs_read_u8(b); sps->vui.transfer_characteristics = bs_read_u8(b); sps->vui.matrix_coefficients = bs_read_u8(b); } } sps->vui.chroma_loc_info_present_flag = bs_read_u1(b); if( sps->vui.chroma_loc_info_present_flag ) { sps->vui.chroma_sample_loc_type_top_field = bs_read_ue(b); sps->vui.chroma_sample_loc_type_bottom_field = bs_read_ue(b); } sps->vui.timing_info_present_flag = bs_read_u1(b); if( sps->vui.timing_info_present_flag ) { sps->vui.num_units_in_tick = bs_read_u(b,32); sps->vui.time_scale = bs_read_u(b,32); sps->vui.fixed_frame_rate_flag = bs_read_u1(b); } sps->vui.nal_hrd_parameters_present_flag = bs_read_u1(b); if( sps->vui.nal_hrd_parameters_present_flag ) { read_hrd_parameters(sps, b); } sps->vui.vcl_hrd_parameters_present_flag = bs_read_u1(b); if( sps->vui.vcl_hrd_parameters_present_flag ) { read_hrd_parameters(sps, b); } if( sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag ) { sps->vui.low_delay_hrd_flag = bs_read_u1(b); } sps->vui.pic_struct_present_flag = bs_read_u1(b); sps->vui.bitstream_restriction_flag = bs_read_u1(b); if( sps->vui.bitstream_restriction_flag ) { sps->vui.motion_vectors_over_pic_boundaries_flag = bs_read_u1(b); sps->vui.max_bytes_per_pic_denom = bs_read_ue(b); sps->vui.max_bits_per_mb_denom = bs_read_ue(b); sps->vui.log2_max_mv_length_horizontal = bs_read_ue(b); sps->vui.log2_max_mv_length_vertical = bs_read_ue(b); sps->vui.num_reorder_frames = bs_read_ue(b); sps->vui.max_dec_frame_buffering = bs_read_ue(b); } }
uint32_t bs_read_u8(bs_t* b) { return bs_read_u(b, 8); }
uint32_t bs_read_f(bs_t* b, int n) { return bs_read_u(b, n); }
//7.3.2.1 Sequence parameter set RBSP syntax int read_seq_parameter_set_rbsp(sps_t* sps, bs_t* b) { int i; memset(sps, 0, sizeof(sps_t)); sps->profile_idc = bs_read_u8(b); sps->constraint_set0_flag = bs_read_u1(b); sps->constraint_set1_flag = bs_read_u1(b); sps->constraint_set2_flag = bs_read_u1(b); sps->constraint_set3_flag = bs_read_u1(b); sps->constraint_set4_flag = bs_read_u1(b); sps->constraint_set5_flag = bs_read_u1(b); sps->reserved_zero_2bits = bs_read_u(b,2); /* all 0's */ sps->level_idc = bs_read_u8(b); sps->seq_parameter_set_id = bs_read_ue(b); sps->chroma_format_idc = 1; if( sps->profile_idc == 100 || sps->profile_idc == 110 || sps->profile_idc == 122 || sps->profile_idc == 144 ) { sps->chroma_format_idc = bs_read_ue(b); if( sps->chroma_format_idc == 3 ) { sps->residual_colour_transform_flag = bs_read_u1(b); } sps->bit_depth_luma_minus8 = bs_read_ue(b); sps->bit_depth_chroma_minus8 = bs_read_ue(b); sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b); sps->seq_scaling_matrix_present_flag = bs_read_u1(b); if( sps->seq_scaling_matrix_present_flag ) { for( i = 0; i < 8; i++ ) { sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b); if( sps->seq_scaling_list_present_flag[ i ] ) { if( i < 6 ) { read_scaling_list( b, sps->ScalingList4x4[ i ], 16, sps->UseDefaultScalingMatrix4x4Flag[ i ]); } else { read_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64, sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ); } } } } } sps->log2_max_frame_num_minus4 = bs_read_ue(b); sps->pic_order_cnt_type = bs_read_ue(b); if( sps->pic_order_cnt_type == 0 ) { sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b); } else if( sps->pic_order_cnt_type == 1 ) { sps->delta_pic_order_always_zero_flag = bs_read_u1(b); sps->offset_for_non_ref_pic = bs_read_se(b); sps->offset_for_top_to_bottom_field = bs_read_se(b); sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b); for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ) { sps->offset_for_ref_frame[ i ] = bs_read_se(b); } } sps->num_ref_frames = bs_read_ue(b); sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b); sps->pic_width_in_mbs_minus1 = bs_read_ue(b); sps->pic_height_in_map_units_minus1 = bs_read_ue(b); sps->frame_mbs_only_flag = bs_read_u1(b); if( !sps->frame_mbs_only_flag ) { sps->mb_adaptive_frame_field_flag = bs_read_u1(b); } sps->direct_8x8_inference_flag = bs_read_u1(b); sps->frame_cropping_flag = bs_read_u1(b); if( sps->frame_cropping_flag ) { sps->frame_crop_left_offset = bs_read_ue(b); sps->frame_crop_right_offset = bs_read_ue(b); sps->frame_crop_top_offset = bs_read_ue(b); sps->frame_crop_bottom_offset = bs_read_ue(b); } sps->vui_parameters_present_flag = bs_read_u1(b); if( sps->vui_parameters_present_flag ) { read_vui_parameters(sps, b); } read_rbsp_trailing_bits(b); return 0; }
int program_map_section_read(program_map_section_t *pms, uint8_t *buf, size_t buf_size) { if (pms == NULL || buf == NULL) { SAFE_REPORT_TS_ERR(-1); return 0; } bs_t *b = bs_new(buf, buf_size); pms->table_id = bs_read_u8(b); if (pms->table_id != TS_program_map_section) { LOG_ERROR_ARGS("Table ID in PMT is 0x%02X instead of expected 0x%02X", pms->table_id, TS_program_map_section); SAFE_REPORT_TS_ERR(-40); return 0; } pms->section_syntax_indicator = bs_read_u1(b); if (!pms->section_syntax_indicator) { LOG_ERROR("section_syntax_indicator not set in PMT"); SAFE_REPORT_TS_ERR(-41); return 0; } bs_skip_u(b, 3); pms->section_length = bs_read_u(b, 12); if (pms->section_length > MAX_SECTION_LEN) { LOG_ERROR_ARGS("PMT section length is 0x%02X, larger than maximum allowed 0x%02X", pms->section_length, MAX_SECTION_LEN); SAFE_REPORT_TS_ERR(-42); return 0; } int section_start = bs_pos(b); // bytes 0,1 pms->program_number = bs_read_u16(b); // byte 2; bs_skip_u(b, 2); pms->version_number = bs_read_u(b, 5); pms->current_next_indicator = bs_read_u1(b); if (!pms->current_next_indicator) LOG_WARN("This PMT is not yet applicable/n"); // bytes 3,4 pms->section_number = bs_read_u8(b); pms->last_section_number = bs_read_u8(b); if (pms->section_number != 0 || pms->last_section_number != 0) { LOG_ERROR("Multi-section PMT is not allowed/n"); SAFE_REPORT_TS_ERR(-43); return 0; } bs_skip_u(b, 3); pms->PCR_PID = bs_read_u(b, 13); if (pms->PCR_PID < GENERAL_PURPOSE_PID_MIN || pms->PCR_PID > GENERAL_PURPOSE_PID_MAX) { LOG_ERROR_ARGS("PCR PID has invalid value 0x%02X", pms->PCR_PID); SAFE_REPORT_TS_ERR(-44); return 0; } bs_skip_u(b, 4); pms->program_info_length = bs_read_u(b, 12); if (pms->program_info_length > MAX_PROGRAM_INFO_LEN) { LOG_ERROR_ARGS("PMT program info length is 0x%02X, larger than maximum allowed 0x%02X", pms->program_info_length, MAX_PROGRAM_INFO_LEN); SAFE_REPORT_TS_ERR(-45); return 0; } read_descriptor_loop(pms->descriptors, b, pms->program_info_length); while (pms->section_length - (bs_pos(b) - section_start) > 4) { // account for CRC elementary_stream_info_t *es = es_info_new(); es_info_read(es, b); vqarray_add(pms->es_info, es); } pms->CRC_32 = bs_read_u32(b); // check CRC crc_t pas_crc = crc_init(); pas_crc = crc_update(pas_crc, buf, bs_pos(b) - 4); pas_crc = crc_finalize(pas_crc); if (pas_crc != pms->CRC_32) { LOG_ERROR_ARGS("PMT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pms->CRC_32, pas_crc); SAFE_REPORT_TS_ERR(-46); return 0; } else { LOG_DEBUG("PMT CRC_32 checked successfully"); } int bytes_read = bs_pos(b); bs_free(b); return bytes_read; }
// Appendix G.13.1.1 Scalability information SEI message syntax void read_sei_scalability_info( h264_stream_t* h, bs_t* b ) { sei_scalability_info_t* sei_svc = h->sei->sei_svc; sei_svc->temporal_id_nesting_flag = bs_read_u1(b); sei_svc->priority_layer_info_present_flag = bs_read_u1(b); sei_svc->priority_id_setting_flag = bs_read_u1(b); sei_svc->num_layers_minus1 = bs_read_ue(b); for( int i = 0; i <= sei_svc->num_layers_minus1; i++ ) { sei_svc->layers[i].layer_id = bs_read_ue(b); sei_svc->layers[i].priority_id = bs_read_u(b, 6); sei_svc->layers[i].discardable_flag = bs_read_u1(b); sei_svc->layers[i].dependency_id = bs_read_u(b, 3); sei_svc->layers[i].quality_id = bs_read_u(b, 4); sei_svc->layers[i].temporal_id = bs_read_u(b, 3); sei_svc->layers[i].sub_pic_layer_flag = bs_read_u1(b); sei_svc->layers[i].sub_region_layer_flag = bs_read_u1(b); sei_svc->layers[i].iroi_division_info_present_flag = bs_read_u1(b); sei_svc->layers[i].profile_level_info_present_flag = bs_read_u1(b); sei_svc->layers[i].bitrate_info_present_flag = bs_read_u1(b); sei_svc->layers[i].frm_rate_info_present_flag = bs_read_u1(b); sei_svc->layers[i].frm_size_info_present_flag = bs_read_u1(b); sei_svc->layers[i].layer_dependency_info_present_flag = bs_read_u1(b); sei_svc->layers[i].parameter_sets_info_present_flag = bs_read_u1(b); sei_svc->layers[i].bitstream_restriction_info_present_flag = bs_read_u1(b); sei_svc->layers[i].exact_inter_layer_pred_flag = bs_read_u1(b); if( sei_svc->layers[i].sub_pic_layer_flag || sei_svc->layers[i].iroi_division_info_present_flag ) { sei_svc->layers[i].exact_sample_value_match_flag = bs_read_u1(b); } sei_svc->layers[i].layer_conversion_flag = bs_read_u1(b); sei_svc->layers[i].layer_output_flag = bs_read_u1(b); if( sei_svc->layers[i].profile_level_info_present_flag ) { sei_svc->layers[i].layer_profile_level_idc = bs_read_u(b, 24); } if( sei_svc->layers[i].bitrate_info_present_flag ) { sei_svc->layers[i].avg_bitrate = bs_read_u(b, 16); sei_svc->layers[i].max_bitrate_layer = bs_read_u(b, 16); sei_svc->layers[i].max_bitrate_layer_representation = bs_read_u(b, 16); sei_svc->layers[i].max_bitrate_calc_window = bs_read_u(b, 16); } if( sei_svc->layers[i].frm_rate_info_present_flag ) { sei_svc->layers[i].constant_frm_rate_idc = bs_read_u(b, 2); sei_svc->layers[i].avg_frm_rate = bs_read_u(b, 16); } if( sei_svc->layers[i].frm_size_info_present_flag || sei_svc->layers[i].iroi_division_info_present_flag ) { sei_svc->layers[i].frm_width_in_mbs_minus1 = bs_read_ue(b); sei_svc->layers[i].frm_height_in_mbs_minus1 = bs_read_ue(b); } if( sei_svc->layers[i].sub_region_layer_flag ) { sei_svc->layers[i].base_region_layer_id = bs_read_ue(b); sei_svc->layers[i].dynamic_rect_flag = bs_read_u1(b); if( sei_svc->layers[i].dynamic_rect_flag ) { sei_svc->layers[i].horizontal_offset = bs_read_u(b, 16); sei_svc->layers[i].vertical_offset = bs_read_u(b, 16); sei_svc->layers[i].region_width = bs_read_u(b, 16); sei_svc->layers[i].region_height = bs_read_u(b, 16); } } if( sei_svc->layers[i].sub_pic_layer_flag ) { sei_svc->layers[i].roi_id = bs_read_ue(b); } if( sei_svc->layers[i].iroi_division_info_present_flag ) { sei_svc->layers[i].iroi_grid_flag = bs_read_u1(b); if( sei_svc->layers[i].iroi_grid_flag ) { sei_svc->layers[i].grid_width_in_mbs_minus1 = bs_read_ue(b); sei_svc->layers[i].grid_height_in_mbs_minus1 = bs_read_ue(b); } else { sei_svc->layers[i].num_rois_minus1 = bs_read_ue(b); for( int j = 0; j <= sei_svc->layers[i].num_rois_minus1; j++ ) { sei_svc->layers[i].roi[j].first_mb_in_roi = bs_read_ue(b); sei_svc->layers[i].roi[j].roi_width_in_mbs_minus1 = bs_read_ue(b); sei_svc->layers[i].roi[j].roi_height_in_mbs_minus1 = bs_read_ue(b); } } } if( sei_svc->layers[i].layer_dependency_info_present_flag ) { sei_svc->layers[i].num_directly_dependent_layers = bs_read_ue(b); for( int j = 0; j < sei_svc->layers[i].num_directly_dependent_layers; j++ ) { sei_svc->layers[i].directly_dependent_layer_id_delta_minus1[j] = bs_read_ue(b); } } else { sei_svc->layers[i].layer_dependency_info_src_layer_id_delta = bs_read_ue(b); } if( sei_svc->layers[i].parameter_sets_info_present_flag ) { sei_svc->layers[i].num_seq_parameter_sets = bs_read_ue(b); for( int j = 0; j < sei_svc->layers[i].num_seq_parameter_sets; j++ ) { sei_svc->layers[i].seq_parameter_set_id_delta[j] = bs_read_ue(b); } sei_svc->layers[i].num_subset_seq_parameter_sets = bs_read_ue(b); for( int j = 0; j < sei_svc->layers[i].num_subset_seq_parameter_sets; j++ ) { sei_svc->layers[i].subset_seq_parameter_set_id_delta[j] = bs_read_ue(b); } sei_svc->layers[i].num_pic_parameter_sets_minus1 = bs_read_ue(b); for( int j = 0; j < sei_svc->layers[i].num_pic_parameter_sets_minus1; j++ ) { sei_svc->layers[i].pic_parameter_set_id_delta[j] = bs_read_ue(b); } } else { sei_svc->layers[i].parameter_sets_info_src_layer_id_delta = bs_read_ue(b); } if( sei_svc->layers[i].bitstream_restriction_info_present_flag ) { sei_svc->layers[i].motion_vectors_over_pic_boundaries_flag = bs_read_u1(b); sei_svc->layers[i].max_bytes_per_pic_denom = bs_read_ue(b); sei_svc->layers[i].max_bits_per_mb_denom = bs_read_ue(b); sei_svc->layers[i].log2_max_mv_length_horizontal = bs_read_ue(b); sei_svc->layers[i].log2_max_mv_length_vertical = bs_read_ue(b); sei_svc->layers[i].max_num_reorder_frames = bs_read_ue(b); sei_svc->layers[i].max_dec_frame_buffering = bs_read_ue(b); } if( sei_svc->layers[i].layer_conversion_flag ) { sei_svc->layers[i].conversion_type_idc = bs_read_ue(b); for( int j = 0; j < 2; j++ ) { sei_svc->layers[i].rewriting_info_flag[j] = bs_read_u(b, 1); if( sei_svc->layers[i].rewriting_info_flag[j] ) { sei_svc->layers[i].rewriting_profile_level_idc[j] = bs_read_u(b, 24); sei_svc->layers[i].rewriting_avg_bitrate[j] = bs_read_u(b, 16); sei_svc->layers[i].rewriting_max_bitrate[j] = bs_read_u(b, 16); } } } } if( sei_svc->priority_layer_info_present_flag ) { sei_svc->pr_num_dIds_minus1 = bs_read_ue(b); for( int i = 0; i <= sei_svc->pr_num_dIds_minus1; i++ ) { sei_svc->pr[i].pr_dependency_id = bs_read_u(b, 3); sei_svc->pr[i].pr_num_minus1 = bs_read_ue(b); for( int j = 0; j <= sei_svc->pr[i].pr_num_minus1; j++ ) { sei_svc->pr[i].pr_info[j].pr_id = bs_read_ue(b); sei_svc->pr[i].pr_info[j].pr_profile_level_idc = bs_read_u(b, 24); sei_svc->pr[i].pr_info[j].pr_avg_bitrate = bs_read_u(b, 16); sei_svc->pr[i].pr_info[j].pr_max_bitrate = bs_read_u(b, 16); } } } }
// D.1.2 SEI picture timing syntax static void read_sei_type_1(h264_stream_t* h, sei_t* s) { bs_t bs; sps_t *sps = h->sps; uint32_t pict_struct, num_clock_ticks; bs_init(&bs, s->payload, s->payloadSize); sei_type_1 *pt_struct = NULL; if(sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag) { pt_struct = calloc(sizeof(sei_type_1), 1); pt_struct->cpb_removal_delay = bs_read_u(&bs, sps->hrd.cpb_removal_delay_length_minus1 + 1); pt_struct->dpb_output_delay = bs_read_u(&bs, sps->hrd.dpb_output_delay_length_minus1 + 1); } if (sps->vui.pic_struct_present_flag) { pict_struct = bs_read_u(&bs, 4); if (pict_struct > SEI_PIC_STRUCT_FRAME_TRIPLING) { return; } num_clock_ticks = sei_num_clock_ts_table[pict_struct]; pt_struct->timings = calloc(sizeof(sei_type_1_pic_timing) * num_clock_ticks, 1); pt_struct->NumClockTS = num_clock_ticks; pt_struct->pic_struct = pict_struct; for (int i = 0; i < num_clock_ticks; i++) { sei_type_1_pic_timing *pt = &pt_struct->timings[i]; pt->clock_timestamp_flag = bs_read_u(&bs, 1); if (pt->clock_timestamp_flag) { pt->ct_type = bs_read_u(&bs, 2); pt->nuit_field_based_flag = bs_read_u(&bs, 1); pt->counting_type = bs_read_u(&bs, 5); pt->full_timestamp_flag = bs_read_u(&bs, 1); pt->discontinuity_flag = bs_read_u(&bs, 1); pt->cnt_dropped_flag = bs_read_u(&bs, 1); pt->n_frames = bs_read_u(&bs, 8); if (pt->full_timestamp_flag) { pt->seconds_value = bs_read_u(&bs, 6); pt->minutes_value = bs_read_u(&bs, 6); pt->hours_value = bs_read_u(&bs, 5); }else { pt->seconds_flag = bs_read_u(&bs, 1); if (pt->seconds_flag) { pt->seconds_value = bs_read_u(&bs, 6); pt->minutes_flag = bs_read_u(&bs, 1); if(pt->minutes_flag) { pt->minutes_value = bs_read_u(&bs, 6); pt->hours_flag = bs_read_u(&bs, 1); if (pt->hours_flag) { pt->hours_value = bs_read_u(&bs, 5); } } } } if (sps->hrd.time_offset_length > 0) { pt->time_offset = bs_read_u(&bs, sps->hrd.time_offset_length); } } } } s->sei_type_struct = pt_struct; }
int program_map_section_read(program_map_section_t *pms, uint8_t *buf, size_t buf_size, uint32_t payload_unit_start_indicator, psi_table_buffer_t *pmtBuffer) { LOG_DEBUG ("program_map_section_read -- entering"); if (pms == NULL || buf == NULL) { SAFE_REPORT_TS_ERR(-1); return 0; } bs_t *b = NULL; if (!payload_unit_start_indicator && pmtBuffer->buffer == NULL) { // this TS packet is not start of table, and we have no cached table data LOG_WARN ("program_map_section_read: payload_unit_start_indicator not set and no cached data"); return 0; } if (payload_unit_start_indicator) { uint8_t payloadStartPtr = buf[0]; buf += (payloadStartPtr + 1); buf_size -= (payloadStartPtr + 1); LOG_DEBUG_ARGS ("program_map_section_read: payloadStartPtr = %d", payloadStartPtr); } // check for pmt spanning multiple TS packets if (pmtBuffer->buffer != NULL) { LOG_DEBUG_ARGS ("program_map_section_read: pmtBuffer detected: pmtBufferAllocSz = %d, pmtBufferUsedSz = %d", pmtBuffer->bufferAllocSz, pmtBuffer->bufferUsedSz); size_t numBytesToCopy = buf_size; if (buf_size > (pmtBuffer->bufferAllocSz - pmtBuffer->bufferUsedSz)) { numBytesToCopy = pmtBuffer->bufferAllocSz - pmtBuffer->bufferUsedSz; } LOG_DEBUG_ARGS ("program_map_section_read: copying %d bytes to pmtBuffer", numBytesToCopy); memcpy (pmtBuffer->buffer + pmtBuffer->bufferUsedSz, buf, numBytesToCopy); pmtBuffer->bufferUsedSz += numBytesToCopy; if (pmtBuffer->bufferUsedSz < pmtBuffer->bufferAllocSz) { LOG_DEBUG ("program_map_section_read: pmtBuffer not yet full -- returning"); return 0; } b = bs_new(pmtBuffer->buffer, pmtBuffer->bufferUsedSz); } else { b = bs_new(buf, buf_size); } pms->table_id = bs_read_u8(b); if (pms->table_id != TS_program_map_section) { LOG_ERROR_ARGS("Table ID in PMT is 0x%02X instead of expected 0x%02X", pms->table_id, TS_program_map_section); reportAddErrorLogArgs("Table ID in PMT is 0x%02X instead of expected 0x%02X", pms->table_id, TS_program_map_section); SAFE_REPORT_TS_ERR(-40); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } pms->section_syntax_indicator = bs_read_u1(b); if (!pms->section_syntax_indicator) { LOG_ERROR("section_syntax_indicator not set in PMT"); reportAddErrorLog("section_syntax_indicator not set in PMT"); SAFE_REPORT_TS_ERR(-41); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } bs_skip_u(b, 3); pms->section_length = bs_read_u(b, 12); if (pms->section_length > MAX_SECTION_LEN) { LOG_ERROR_ARGS("PMT section length is 0x%02X, larger than maximum allowed 0x%02X", pms->section_length, MAX_SECTION_LEN); reportAddErrorLogArgs("PMT section length is 0x%02X, larger than maximum allowed 0x%02X", pms->section_length, MAX_SECTION_LEN); SAFE_REPORT_TS_ERR(-42); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } if (pms->section_length > bs_bytes_left(b)) { LOG_DEBUG ("program_map_section_read: Detected section spans more than one TS packet -- allocating buffer"); if (pmtBuffer->buffer != NULL) { // should never get here LOG_ERROR ("program_map_section_read: unexpected pmtBufffer"); reportAddErrorLog ("program_map_section_read: unexpected pmtBufffer"); resetPSITableBuffer(pmtBuffer); } pmtBuffer->bufferAllocSz = pms->section_length + 3; pmtBuffer->buffer = (uint8_t *)calloc (pms->section_length + 3, 1); memcpy (pmtBuffer->buffer, buf, buf_size); pmtBuffer->bufferUsedSz = buf_size; bs_free (b); return 0; } int section_start = bs_pos(b); // bytes 0,1 pms->program_number = bs_read_u16(b); // byte 2; bs_skip_u(b, 2); pms->version_number = bs_read_u(b, 5); pms->current_next_indicator = bs_read_u1(b); if (!pms->current_next_indicator) LOG_WARN("This PMT is not yet applicable/n"); // bytes 3,4 pms->section_number = bs_read_u8(b); pms->last_section_number = bs_read_u8(b); if (pms->section_number != 0 || pms->last_section_number != 0) { LOG_ERROR("Multi-section PMT is not allowed/n"); reportAddErrorLog("Multi-section PMT is not allowed/n"); SAFE_REPORT_TS_ERR(-43); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } bs_skip_u(b, 3); pms->PCR_PID = bs_read_u(b, 13); if (pms->PCR_PID < GENERAL_PURPOSE_PID_MIN || pms->PCR_PID > GENERAL_PURPOSE_PID_MAX) { LOG_ERROR_ARGS("PCR PID has invalid value 0x%02X", pms->PCR_PID); reportAddErrorLogArgs("PCR PID has invalid value 0x%02X", pms->PCR_PID); SAFE_REPORT_TS_ERR(-44); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } // printf ("PCR PID = %d\n", pms->PCR_PID); bs_skip_u(b, 4); pms->program_info_length = bs_read_u(b, 12); if (pms->program_info_length > MAX_PROGRAM_INFO_LEN) { LOG_ERROR_ARGS("PMT program info length is 0x%02X, larger than maximum allowed 0x%02X", pms->program_info_length, MAX_PROGRAM_INFO_LEN); reportAddErrorLogArgs("PMT program info length is 0x%02X, larger than maximum allowed 0x%02X", pms->program_info_length, MAX_PROGRAM_INFO_LEN); SAFE_REPORT_TS_ERR(-45); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } read_descriptor_loop(pms->descriptors, b, pms->program_info_length); while (!bs_eof(b) && pms->section_length - (bs_pos(b) - section_start) > 4) // account for CRC { elementary_stream_info_t *es = es_info_new(); es_info_read(es, b); vqarray_add(pms->es_info, es); } pms->CRC_32 = bs_read_u32(b); // check CRC crc_t pas_crc = crc_init(); pas_crc = crc_update(pas_crc, b->start, bs_pos(b) - 4); pas_crc = crc_finalize(pas_crc); if (pas_crc != pms->CRC_32) { LOG_ERROR_ARGS("PMT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pms->CRC_32, pas_crc); reportAddErrorLogArgs("PMT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pms->CRC_32, pas_crc); SAFE_REPORT_TS_ERR(-46); resetPSITableBuffer(pmtBuffer); bs_free (b); return 0; } else { // LOG_DEBUG("PMT CRC_32 checked successfully"); } int bytes_read = bs_pos(b); bs_free(b); resetPSITableBuffer(pmtBuffer); return bytes_read; }
int conditional_access_section_read(conditional_access_section_t *cas, uint8_t *buf, size_t buf_len, uint32_t payload_unit_start_indicator, psi_table_buffer_t *catBuffer) { if (cas == NULL || buf == NULL) { SAFE_REPORT_TS_ERR(-1); return 0; } bs_t *b = NULL; if (!payload_unit_start_indicator && catBuffer->buffer == NULL) { // this TS packet is not start of table, and we have no cached table data LOG_WARN ("conditional_access_section_read: payload_unit_start_indicator not set and no cached data"); return 0; } if (payload_unit_start_indicator) { uint8_t payloadStartPtr = buf[0]; buf += (payloadStartPtr + 1); buf_len -= (payloadStartPtr + 1); LOG_DEBUG_ARGS ("conditional_access_section_read: payloadStartPtr = %d", payloadStartPtr); } // check for pat spanning multiple TS packets if (catBuffer->buffer != NULL) { LOG_DEBUG_ARGS ("conditional_access_section_read: catBuffer detected: catBufferAllocSz = %d, catBufferUsedSz = %d", catBuffer->bufferAllocSz, catBuffer->bufferUsedSz); size_t numBytesToCopy = buf_len; if (buf_len > (catBuffer->bufferAllocSz - catBuffer->bufferUsedSz)) { numBytesToCopy = catBuffer->bufferAllocSz - catBuffer->bufferUsedSz; } LOG_DEBUG_ARGS ("conditional_access_section_read: copying %d bytes to catBuffer", numBytesToCopy); memcpy (catBuffer->buffer + catBuffer->bufferUsedSz, buf, numBytesToCopy); catBuffer->bufferUsedSz += numBytesToCopy; if (catBuffer->bufferUsedSz < catBuffer->bufferAllocSz) { LOG_DEBUG ("conditional_access_section_read: catBuffer not yet full -- returning"); return 0; } b = bs_new(catBuffer->buffer, catBuffer->bufferUsedSz); } else { b = bs_new(buf, buf_len); } cas->table_id = bs_read_u8(b); if (cas->table_id != conditional_access_section) { LOG_ERROR_ARGS("Table ID in CAT is 0x%02X instead of expected 0x%02X", cas->table_id, conditional_access_section); reportAddErrorLogArgs("Table ID in CAT is 0x%02X instead of expected 0x%02X", cas->table_id, conditional_access_section); SAFE_REPORT_TS_ERR(-30); resetPSITableBuffer(catBuffer); bs_free (b); return 0; } // read byte 0 cas->section_syntax_indicator = bs_read_u1(b); if (!cas->section_syntax_indicator) { LOG_ERROR("section_syntax_indicator not set in CAT"); reportAddErrorLog("section_syntax_indicator not set in CAT"); SAFE_REPORT_TS_ERR(-31); resetPSITableBuffer(catBuffer); bs_free (b); return 0; } bs_skip_u(b, 3); // TODO read the zero bit, check it to be zero cas->section_length = bs_read_u(b, 12); if (cas->section_length > 1021) // max CAT length { LOG_ERROR_ARGS("CAT section length is 0x%02X, larger than maximum allowed 0x%02X", cas->section_length, MAX_SECTION_LEN); reportAddErrorLogArgs("CAT section length is 0x%02X, larger than maximum allowed 0x%02X", cas->section_length, MAX_SECTION_LEN); SAFE_REPORT_TS_ERR(-32); resetPSITableBuffer(catBuffer); bs_free (b); return 0; } if (cas->section_length > bs_bytes_left(b)) { LOG_DEBUG ("conditional_access_section_read: Detected section spans more than one TS packet -- allocating buffer"); if (catBuffer->buffer != NULL) { // should never get here LOG_ERROR ("conditional_access_section_read: unexpected catBufffer"); reportAddErrorLog ("conditional_access_section_read: unexpected catBufffer"); resetPSITableBuffer(catBuffer); } catBuffer->bufferAllocSz = cas->section_length + 3; catBuffer->buffer = (uint8_t *)calloc (cas->section_length + 3, 1); memcpy (catBuffer->buffer, buf, buf_len); catBuffer->bufferUsedSz = buf_len; bs_free (b); return 0; } // read bytes 1-2 bs_read_u16(b); // read bytes 3,4 bs_skip_u(b, 2); cas->version_number = bs_read_u(b, 5); cas->current_next_indicator = bs_read_u1(b); if (!cas->current_next_indicator) LOG_WARN("This CAT is not yet applicable/n"); // read byte 5 cas->section_number = bs_read_u8(b); cas->last_section_number = bs_read_u8(b); if (cas->section_number != 0 || cas->last_section_number != 0) LOG_WARN("Multi-section CAT is not supported yet/n"); // read bytes 6,7 read_descriptor_loop(cas->descriptors, b, cas->section_length - 5 - 4 ); // explanation: section_length gives us the length from the end of section_length // we used 5 bytes for the mandatory section fields, and will use another 4 bytes for CRC // the remaining bytes contain descriptors, most probably only one // again, it's much shorter in C :-) cas->CRC_32 = bs_read_u32(b); // check CRC crc_t cas_crc = crc_init(); cas_crc = crc_update(cas_crc, buf, bs_pos(b) - 4); cas_crc = crc_finalize(cas_crc); if (cas_crc != cas->CRC_32) { LOG_ERROR_ARGS("CAT CRC_32 specified as 0x%08X, but calculated as 0x%08X", cas->CRC_32, cas_crc); reportAddErrorLogArgs("CAT CRC_32 specified as 0x%08X, but calculated as 0x%08X", cas->CRC_32, cas_crc); SAFE_REPORT_TS_ERR(-33); resetPSITableBuffer(catBuffer); bs_free (b); return 0; } bs_free(b); resetPSITableBuffer(catBuffer); return 1; }
int program_association_section_read(program_association_section_t *pas, uint8_t *buf, size_t buf_len) { if (pas == NULL || buf == NULL) { SAFE_REPORT_TS_ERR(-1); return 0; } bs_t *b = bs_new(buf, buf_len); pas->table_id = bs_read_u8(b); if (pas->table_id != program_association_section) { LOG_ERROR_ARGS("Table ID in PAT is 0x%02X instead of expected 0x%02X", pas->table_id, program_association_section); SAFE_REPORT_TS_ERR(-30); return 0; } // read byte 0 pas->section_syntax_indicator = bs_read_u1(b); if (!pas->section_syntax_indicator) { LOG_ERROR("section_syntax_indicator not set in PAT"); SAFE_REPORT_TS_ERR(-31); return 0; } bs_skip_u(b, 3); // TODO read the zero bit, check it to be zero pas->section_length = bs_read_u(b, 12); if (pas->section_length > MAX_SECTION_LEN) { LOG_ERROR_ARGS("PAT section length is 0x%02X, larger than maximum allowed 0x%02X", pas->section_length, MAX_SECTION_LEN); SAFE_REPORT_TS_ERR(-32); return 0; } // read bytes 1,2 pas->transport_stream_id = bs_read_u16(b); // read bytes 3,4 bs_skip_u(b, 2); pas->version_number = bs_read_u(b, 5); pas->current_next_indicator = bs_read_u1(b); if (!pas->current_next_indicator) LOG_WARN("This PAT is not yet applicable/n"); // read byte 5 pas->section_number = bs_read_u8(b); pas->last_section_number = bs_read_u8(b); if (pas->section_number != 0 || pas->last_section_number != 0) LOG_WARN("Multi-section PAT is not supported yet/n"); // read bytes 6,7 pas->_num_programs = (pas->section_length - 5 - 4) / 4; // explanation: section_length gives us the length from the end of section_length // we used 5 bytes for the mandatory section fields, and will use another 4 bytes for CRC // the remaining bytes contain program information, which is 4 bytes per iteration // It's much shorter in C :-) if (pas->_num_programs > 1) LOG_WARN_ARGS("%zd programs found, but only SPTS is fully supported. Patches are welcome.", pas->_num_programs); pas->programs = malloc(pas->_num_programs * sizeof(program_info_t)); for (uint32_t i = 0; i < pas->_num_programs; i++) { pas->programs[i].program_number = bs_read_u16(b); bs_skip_u(b, 3); pas->programs[i].program_map_PID = bs_read_u(b, 13); } pas->CRC_32 = bs_read_u32(b); // check CRC crc_t pas_crc = crc_init(); pas_crc = crc_update(pas_crc, buf, bs_pos(b) - 4); pas_crc = crc_finalize(pas_crc); if (pas_crc != pas->CRC_32) { LOG_ERROR_ARGS("PAT CRC_32 specified as 0x%08X, but calculated as 0x%08X", pas->CRC_32, pas_crc); SAFE_REPORT_TS_ERR(-33); return 0; } else { LOG_DEBUG("PAT CRC_32 checked successfully"); } bs_free(b); return 1; }