/***************************************************************************** * dvbpsi_pat_detach ***************************************************************************** * Close a PAT decoder. The handle isn't valid any more. *****************************************************************************/ void dvbpsi_pat_detach(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { assert(p_dvbpsi); dvbpsi_pat_decoder_t *p_pat_decoder = (dvbpsi_pat_decoder_t*) dvbpsi_decoder_chain_get(p_dvbpsi, i_table_id, i_extension); if (!p_pat_decoder) { dvbpsi_error(p_dvbpsi, "PAT Decoder", "No such PAT decoder (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return; } /* Remove table decoder from chain */ if (!dvbpsi_decoder_chain_remove(p_dvbpsi, DVBPSI_DECODER(p_pat_decoder))) { dvbpsi_error(p_dvbpsi, "PAT Decoder", "Failed to remove" "extension == 0x%02x)", i_table_id, i_extension); return; } if (p_pat_decoder->p_building_pat) dvbpsi_pat_delete(p_pat_decoder->p_building_pat); p_pat_decoder->p_building_pat = NULL; dvbpsi_decoder_delete(DVBPSI_DECODER(p_pat_decoder)); p_pat_decoder = NULL; }
static bool dvbpsi_CheckNIT(dvbpsi_t *p_dvbpsi, dvbpsi_nit_decoder_t *p_nit_decoder, dvbpsi_psi_section_t *p_section) { assert(p_dvbpsi); assert(p_nit_decoder); bool b_reinit = false; if (p_nit_decoder->p_building_nit->i_version != p_section->i_version) { /* version_number */ dvbpsi_error(p_dvbpsi, "NIT decoder", "'version_number' differs" " whereas no discontinuity has occurred"); b_reinit = true; } else if (p_nit_decoder->i_last_section_number != p_section->i_last_number) { /* last_section_number */ dvbpsi_error(p_dvbpsi, "NIT decoder", "'last_section_number' differs" " whereas no discontinuity has occurred"); b_reinit = true; } return b_reinit; }
static bool dvbpsi_CheckTOT(dvbpsi_t *p_dvbpsi, dvbpsi_tot_decoder_t *p_tot_decoder, dvbpsi_psi_section_t *p_section) { bool b_reinit = false; assert(p_dvbpsi); assert(p_tot_decoder); if (p_tot_decoder->p_building_tot->i_extension != p_section->i_extension) { /* transport_stream_id */ dvbpsi_error(p_dvbpsi, "TDT/TOT decoder", "'transport_stream_id' differs" " whereas no TS discontinuity has occured"); b_reinit = true; } else if (p_tot_decoder->p_building_tot->i_version != p_section->i_version) { /* version_number */ dvbpsi_error(p_dvbpsi, "TDT/TOT decoder", "'version_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } else if (p_tot_decoder->i_last_section_number != p_section->i_last_number) { /* last_section_number */ dvbpsi_error(p_dvbpsi, "TDT/TOT decoder", "'last_section_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } return b_reinit; }
static bool dvbpsi_CheckPMT( dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t *p_section ) { bool b_reinit = false; assert( p_dvbpsi->p_decoder ); dvbpsi_pmt_decoder_t* p_pmt_decoder; p_pmt_decoder = (dvbpsi_pmt_decoder_t *) p_dvbpsi->p_decoder; if ( p_pmt_decoder->p_building_pmt->i_version != p_section->i_version ) { /* version_number */ dvbpsi_error( p_dvbpsi, "PMT decoder", "'version_number' differs" " whereas no discontinuity has occured" ); b_reinit = true; }else if ( p_pmt_decoder->i_last_section_number != p_section->i_last_number ) { /* last_section_number */ dvbpsi_error( p_dvbpsi, "PMT decoder", "'last_section_number' differs" " whereas no discontinuity has occured" ); b_reinit = true; } return(b_reinit); }
static bool dvbpsi_CheckPAT( dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t *p_section ) { bool b_reinit = false; assert( p_dvbpsi->p_decoder ); dvbpsi_pat_decoder_t* p_pat_decoder; p_pat_decoder = (dvbpsi_pat_decoder_t *) p_dvbpsi->p_decoder; /* Perform a few sanity checks */ if ( p_pat_decoder->p_building_pat->i_ts_id != p_section->i_extension ) { /* transport_stream_id */ dvbpsi_error( p_dvbpsi, "PAT decoder", "'transport_stream_id' differs" " whereas no TS discontinuity has occured" ); b_reinit = true; }else if ( p_pat_decoder->p_building_pat->i_version != p_section->i_version ) { /* version_number */ dvbpsi_error( p_dvbpsi, "PAT decoder", "'version_number' differs" " whereas no discontinuity has occured" ); b_reinit = true; }else if ( p_pat_decoder->i_last_section_number != p_section->i_last_number ) { /* last_section_number */ dvbpsi_error( p_dvbpsi, "PAT decoder", "'last_section_number' differs" " whereas no discontinuity has occured" ); b_reinit = true; } return(b_reinit); }
/***************************************************************************** * dvbpsi_nit_detach ***************************************************************************** * Close a NIT decoder. *****************************************************************************/ void dvbpsi_nit_detach(dvbpsi_t * p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_decoder; dvbpsi_demux_subdec_t* p_subdec; p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension); if (p_subdec == NULL) { dvbpsi_error(p_dvbpsi, "NIT Decoder", "No such NIT decoder (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return; } dvbpsi_nit_decoder_t* p_nit_decoder; p_nit_decoder = (dvbpsi_nit_decoder_t*)p_subdec->p_decoder; if (p_nit_decoder->p_building_nit) dvbpsi_nit_delete(p_nit_decoder->p_building_nit); p_nit_decoder->p_building_nit = NULL; /* Free demux sub table decoder */ dvbpsi_DetachDemuxSubDecoder(p_demux, p_subdec); dvbpsi_DeleteDemuxSubDecoder(p_subdec); }
/***************************************************************************** * dvbpsi_tot_detach ***************************************************************************** * Close a TDT/TOT decoder. *****************************************************************************/ void dvbpsi_tot_detach(dvbpsi_t* p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *)p_dvbpsi->p_decoder; dvbpsi_demux_subdec_t* p_subdec; i_extension = 0; /* NOTE: force to 0 when handling TDT/TOT */ p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension); if (p_demux == NULL) { dvbpsi_error(p_dvbpsi, "TDT/TOT Decoder", "No such TDT/TOT decoder (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return; } assert(p_subdec->p_decoder); dvbpsi_tot_decoder_t* p_tot_decoder; p_tot_decoder = (dvbpsi_tot_decoder_t*)p_subdec->p_decoder; if (p_tot_decoder->p_building_tot) dvbpsi_tot_delete(p_tot_decoder->p_building_tot); p_tot_decoder->p_building_tot = NULL; dvbpsi_DetachDemuxSubDecoder(p_demux, p_subdec); dvbpsi_DeleteDemuxSubDecoder(p_subdec); }
/***************************************************************************** * dvbpsi_atsc_DetachETT ***************************************************************************** * Close a ETT decoder. The handle isn't valid any more. *****************************************************************************/ void dvbpsi_atsc_DetachETT(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_decoder; dvbpsi_demux_subdec_t* p_subdec; p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension); if (p_subdec == NULL) { dvbpsi_error(p_dvbpsi, "ATSC ETT Decoder", "No such ETT decoder (table_id == 0x%02x," "extension == 0x%04x)", i_table_id, i_extension); return; } dvbpsi_atsc_ett_decoder_t* p_ett_decoder; p_ett_decoder = (dvbpsi_atsc_ett_decoder_t*)p_subdec->p_decoder; if (!p_ett_decoder) return; if (p_ett_decoder->p_building_ett) dvbpsi_atsc_DeleteETT(p_ett_decoder->p_building_ett); p_ett_decoder->p_building_ett = NULL; dvbpsi_DetachDemuxSubDecoder(p_demux, p_subdec); dvbpsi_DeleteDemuxSubDecoder(p_subdec); }
/***************************************************************************** * dvbpsi_sis_detach ***************************************************************************** * Close a SIS decoder. *****************************************************************************/ void dvbpsi_sis_detach(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_decoder; i_extension = 0; dvbpsi_demux_subdec_t* p_subdec; p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension); if (p_demux == NULL) { dvbpsi_error(p_dvbpsi, "SIS Decoder", "No such SIS decoder (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return; } assert(p_subdec->p_decoder); dvbpsi_sis_decoder_t* p_sis_decoder; p_sis_decoder = (dvbpsi_sis_decoder_t*)p_subdec->p_decoder; if (p_sis_decoder->p_building_sis) dvbpsi_sis_delete(p_sis_decoder->p_building_sis); p_sis_decoder->p_building_sis = NULL; dvbpsi_DetachDemuxSubDecoder(p_demux, p_subdec); dvbpsi_DeleteDemuxSubDecoder(p_subdec); }
static bool dvbpsi_CheckSIS(dvbpsi_t *p_dvbpsi, dvbpsi_sis_decoder_t* p_sis_decoder, dvbpsi_psi_section_t *p_section) { bool b_reinit = false; assert(p_dvbpsi); assert(p_sis_decoder); if (p_sis_decoder->p_building_sis->i_protocol_version != 0) { dvbpsi_error(p_dvbpsi, "SIS decoder", "'protocol_version' differs" " while no discontinuity has occured"); b_reinit = true; } else if (p_sis_decoder->p_building_sis->i_extension != p_section->i_extension) { dvbpsi_error(p_dvbpsi, "SIS decoder", "'transport_stream_id' differs" " whereas no discontinuity has occured"); b_reinit = true; } else if (p_sis_decoder->p_building_sis->i_version != p_section->i_version) { /* version_number */ dvbpsi_error(p_dvbpsi, "SIS decoder", "'version_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } else if (p_sis_decoder->i_last_section_number != p_section->i_last_number) { /* last_section_number */ dvbpsi_error(p_dvbpsi, "SIS decoder", "'last_section_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } return b_reinit; }
/***************************************************************************** * dvbpsi_AttachVCT ***************************************************************************** * Initialize a VCT subtable decoder. *****************************************************************************/ bool dvbpsi_AttachVCT(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension, dvbpsi_vct_callback pf_callback, void* p_cb_data) { assert(p_dvbpsi); assert(p_dvbpsi->p_private); dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_dvbpsi->p_private; dvbpsi_demux_subdec_t* p_subdec; dvbpsi_vct_decoder_t* p_vct_decoder; if (dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension)) { dvbpsi_error(p_dvbpsi, "VCT decoder", "Already a decoder for (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return false; } p_subdec = (dvbpsi_demux_subdec_t*)calloc(1, sizeof(dvbpsi_demux_subdec_t)); if(p_subdec == NULL) return false; p_vct_decoder = (dvbpsi_vct_decoder_t*)calloc(1, sizeof(dvbpsi_vct_decoder_t)); if (p_vct_decoder == NULL) { free(p_subdec); return false; } /* subtable decoder configuration */ p_subdec->pf_callback = &dvbpsi_GatherVCTSections; p_subdec->p_cb_data = p_vct_decoder; p_subdec->i_id = (uint32_t)i_table_id << 16 | (uint32_t)i_extension; p_subdec->pf_detach = &dvbpsi_DetachVCT; /* Attach the subtable decoder to the demux */ p_subdec->p_next = p_demux->p_first_subdec; p_demux->p_first_subdec = p_subdec; /* vct decoder information */ p_vct_decoder->pf_vct_callback = pf_callback; p_vct_decoder->p_cb_data = p_cb_data; /* vct decoder initial state */ p_vct_decoder->b_current_valid = false; p_vct_decoder->p_building_vct = NULL; for (unsigned int i = 0; i <= 255; i++) p_vct_decoder->ap_sections[i] = NULL; return true; }
/***************************************************************************** * dvbpsi_nit_attach ***************************************************************************** * Initialize a NIT subtable decoder. *****************************************************************************/ bool dvbpsi_nit_attach(dvbpsi_t* p_dvbpsi, uint8_t i_table_id, uint16_t i_extension, dvbpsi_nit_callback pf_callback, void* p_cb_data) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_dvbpsi->p_decoder; if (dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension)) { dvbpsi_error(p_dvbpsi, "NIT decoder", "Already a decoder for (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return false; } dvbpsi_nit_decoder_t* p_nit_decoder; p_nit_decoder = (dvbpsi_nit_decoder_t*) dvbpsi_decoder_new(NULL, 0, true, sizeof(dvbpsi_nit_decoder_t)); if (p_nit_decoder == NULL) return false; /* subtable decoder configuration */ dvbpsi_demux_subdec_t* p_subdec; p_subdec = dvbpsi_NewDemuxSubDecoder(i_table_id, i_extension, dvbpsi_nit_detach, dvbpsi_nit_sections_gather, DVBPSI_DECODER(p_nit_decoder)); if (p_subdec == NULL) { dvbpsi_decoder_delete(DVBPSI_DECODER(p_nit_decoder)); return false; } /* Attach the subtable decoder to the demux */ dvbpsi_AttachDemuxSubDecoder(p_demux, p_subdec); /* NIT decoder information */ p_nit_decoder->i_network_id = i_extension; p_nit_decoder->pf_nit_callback = pf_callback; p_nit_decoder->p_cb_data = p_cb_data; p_nit_decoder->p_building_nit = NULL; return true; }
/***************************************************************************** * dvbpsi_tot_section_valid ***************************************************************************** * Check the CRC_32 if the section has b_syntax_indicator set. *****************************************************************************/ static bool dvbpsi_tot_section_valid(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t* p_section) { /* TDT table */ if (p_section->i_table_id == 0x70) { /* A TDT (table_id 0x70) always has a length of 5 bytes (which is only the UTC time) */ if (p_section->i_length != 5) { dvbpsi_error(p_dvbpsi, "TDT decoder", "TDT has an invalid payload size (%d bytes) !!!", p_section->i_length); return false; } } /* CRC32 has already been checked by dvbpsi_packet_push() * and by dvbpsi_BuildPSISection(). */ return true; }
/***************************************************************************** * dvbpsi_atsc_AttachETT ***************************************************************************** * Initialize a ETT decoder and return a handle on it. *****************************************************************************/ bool dvbpsi_atsc_AttachETT(dvbpsi_t * p_dvbpsi, uint8_t i_table_id, uint16_t i_extension, dvbpsi_atsc_ett_callback pf_callback, void* p_cb_data) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_dvbpsi->p_decoder; if (dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension)) { dvbpsi_error(p_dvbpsi, "ATSC ETT decoder", "Already a decoder for (table_id == 0x%02x extension == 0x%04x)", i_table_id, i_extension); return false; } dvbpsi_atsc_ett_decoder_t* p_ett_decoder; p_ett_decoder = (dvbpsi_atsc_ett_decoder_t*) dvbpsi_decoder_new(NULL, 0, true, sizeof(dvbpsi_atsc_ett_decoder_t)); if (p_ett_decoder == NULL) return false; /* PSI decoder configuration */ dvbpsi_demux_subdec_t* p_subdec; p_subdec = dvbpsi_NewDemuxSubDecoder(i_table_id, i_extension, dvbpsi_atsc_DetachETT, dvbpsi_atsc_GatherETTSections, DVBPSI_DECODER(p_ett_decoder)); if (p_subdec == NULL) { dvbpsi_decoder_delete(DVBPSI_DECODER(p_ett_decoder)); return false; } /* Attach the subtable decoder to the demux */ dvbpsi_AttachDemuxSubDecoder(p_demux, p_subdec); /* ETT decoder information */ p_ett_decoder->pf_ett_callback = pf_callback; p_ett_decoder->p_cb_data = p_cb_data; p_ett_decoder->p_building_ett = NULL; return true; }
/***************************************************************************** * dvbpsi_DetachVCT ***************************************************************************** * Close a VCT decoder. The handle isn't valid any more. *****************************************************************************/ void dvbpsi_DetachVCT(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension) { assert(p_dvbpsi); assert(p_dvbpsi->p_private); dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_private; dvbpsi_demux_subdec_t* p_subdec; dvbpsi_demux_subdec_t** pp_prev_subdec; dvbpsi_vct_decoder_t* p_vct_decoder; p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension); if (p_subdec == NULL) { dvbpsi_error(p_dvbpsi, "VCT Decoder", "No such VCT decoder (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return; } p_vct_decoder = (dvbpsi_vct_decoder_t*)p_subdec->p_cb_data; free(p_vct_decoder->p_building_vct); for (unsigned int i = 0; i <= 255; i++) { if (p_vct_decoder->ap_sections[i]) { dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[i]); p_vct_decoder->ap_sections[i] = NULL; } } free(p_subdec->p_cb_data); pp_prev_subdec = &p_demux->p_first_subdec; while(*pp_prev_subdec != p_subdec) pp_prev_subdec = &(*pp_prev_subdec)->p_next; *pp_prev_subdec = p_subdec->p_next; free(p_subdec); p_subdec = NULL; }
/***************************************************************************** * dvbpsi_pat_attach ***************************************************************************** * Initialize a PAT decoder and return a handle on it. *****************************************************************************/ bool dvbpsi_pat_attach(dvbpsi_t *p_dvbpsi, uint8_t i_table_id, uint16_t i_extension, dvbpsi_pat_callback pf_callback, void* p_priv) { assert(p_dvbpsi); /* PSI decoder configuration and initial state */ dvbpsi_decoder_t* p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, i_table_id, i_extension); if (p_dec != NULL) { dvbpsi_error(p_dvbpsi, "PAT decoder", "Already a decoder for (table_id == 0x%02x," "extension == 0x%02x)", i_table_id, i_extension); return false; } dvbpsi_pat_decoder_t *p_pat_decoder; p_pat_decoder = (dvbpsi_pat_decoder_t*) dvbpsi_decoder_new(&dvbpsi_pat_sections_gather, 1024, true, sizeof(dvbpsi_pat_decoder_t)); if (p_pat_decoder == NULL) return false; /* PAT decoder information */ p_pat_decoder->pf_pat_callback = pf_callback; p_pat_decoder->p_priv = p_priv; p_pat_decoder->p_building_pat = NULL; p_pat_decoder->i_table_id = i_table_id; p_pat_decoder->i_extension = i_extension; /* Add pat decoder to decoder chain */ if (!dvbpsi_decoder_chain_add(p_dvbpsi, DVBPSI_DECODER(p_pat_decoder))) { dvbpsi_decoder_delete(DVBPSI_DECODER(p_pat_decoder)); return false; } return true; }
/***************************************************************************** * dvbpsi_cat_sections_gather ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ void dvbpsi_cat_sections_gather(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t* p_section) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x01, "CAT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* */ dvbpsi_cat_decoder_t* p_cat_decoder = (dvbpsi_cat_decoder_t*)p_dvbpsi->p_decoder; /* TS discontinuity check */ if (p_cat_decoder->b_discontinuity) { dvbpsi_ReInitCAT(p_cat_decoder, true); p_cat_decoder->b_discontinuity = false; } else { /* Perform some few sanity checks */ if (p_cat_decoder->p_building_cat) { if (dvbpsi_CheckCAT(p_dvbpsi, p_section)) dvbpsi_ReInitCAT(p_cat_decoder, true); } else { if ( (p_cat_decoder->b_current_valid) && (p_cat_decoder->current_cat.i_version == p_section->i_version) && (p_cat_decoder->current_cat.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "CAT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } } } /* Add section to CAT */ if (!dvbpsi_AddSectionCAT(p_dvbpsi, p_cat_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "CAT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_cat_decoder))) { assert(p_cat_decoder->pf_cat_callback); /* Save the current information */ p_cat_decoder->current_cat = *p_cat_decoder->p_building_cat; p_cat_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_cat_sections_decode(p_cat_decoder->p_building_cat, p_cat_decoder->p_sections); /* signal the new CAT */ p_cat_decoder->pf_cat_callback(p_cat_decoder->p_cb_data, p_cat_decoder->p_building_cat); /* Delete sections and Reinitialize the structures */ dvbpsi_ReInitCAT(p_cat_decoder, false); assert(p_cat_decoder->p_sections == NULL); } }
/***************************************************************************** * dvbpsi_packet_push ***************************************************************************** * Injection of a TS packet into a PSI decoder. *****************************************************************************/ bool dvbpsi_packet_push(dvbpsi_t *p_dvbpsi, uint8_t* p_data) { uint8_t i_expected_counter; /* Expected continuity counter */ dvbpsi_psi_section_t* p_section; /* Current section */ uint8_t* p_payload_pos; /* Where in the TS packet */ uint8_t* p_new_pos = NULL; /* Beginning of the new section, updated to NULL when the new section is handled */ int i_available; /* Byte count available in the packet */ dvbpsi_decoder_t *p_decoder = p_dvbpsi->p_decoder; assert(p_decoder); /* TS start code */ if (p_data[0] != 0x47) { dvbpsi_error(p_dvbpsi, "PSI decoder", "not a TS packet"); return false; } /* Continuity check */ bool b_first = (p_decoder->i_continuity_counter == DVBPSI_INVALID_CC); if (b_first) p_decoder->i_continuity_counter = p_data[3] & 0xf; else { i_expected_counter = (p_decoder->i_continuity_counter + 1) & 0xf; p_decoder->i_continuity_counter = p_data[3] & 0xf; if (i_expected_counter == ((p_decoder->i_continuity_counter + 1) & 0xf) && !p_decoder->b_discontinuity) { dvbpsi_error(p_dvbpsi, "PSI decoder", "TS duplicate (received %d, expected %d) for PID %d", p_decoder->i_continuity_counter, i_expected_counter, ((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); return false; } if (i_expected_counter != p_decoder->i_continuity_counter) { dvbpsi_error(p_dvbpsi, "PSI decoder", "TS discontinuity (received %d, expected %d) for PID %d", p_decoder->i_continuity_counter, i_expected_counter, ((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); p_decoder->b_discontinuity = true; if (p_decoder->p_current_section) { dvbpsi_DeletePSISections(p_decoder->p_current_section); p_decoder->p_current_section = NULL; } } } /* Return if no payload in the TS packet */ if (!(p_data[3] & 0x10)) return false; /* Skip the adaptation_field if present */ if (p_data[3] & 0x20) p_payload_pos = p_data + 5 + p_data[4]; else p_payload_pos = p_data + 4; /* Unit start -> skip the pointer_field and a new section begins */ if (p_data[1] & 0x40) { p_new_pos = p_payload_pos + *p_payload_pos + 1; p_payload_pos += 1; } p_section = p_decoder->p_current_section; /* If the psi decoder needs a beginning of a section and a new section begins in the packet then initialize the dvbpsi_psi_section_t structure */ if (p_section == NULL) { if (p_new_pos) { /* Allocation of the structure */ p_decoder->p_current_section = p_section = dvbpsi_NewPSISection(p_decoder->i_section_max_size); if (!p_section) return false; /* Update the position in the packet */ p_payload_pos = p_new_pos; /* New section is being handled */ p_new_pos = NULL; /* Just need the header to know how long is the section */ p_decoder->i_need = 3; p_decoder->b_complete_header = false; } else { /* No new section => return */ return false; } } /* Remaining bytes in the payload */ i_available = 188 + p_data - p_payload_pos; while (i_available > 0) { if (i_available >= p_decoder->i_need) { /* There are enough bytes in this packet to complete the header/section */ memcpy(p_section->p_payload_end, p_payload_pos, p_decoder->i_need); p_payload_pos += p_decoder->i_need; p_section->p_payload_end += p_decoder->i_need; i_available -= p_decoder->i_need; if (!p_decoder->b_complete_header) { /* Header is complete */ p_decoder->b_complete_header = true; /* Compute p_section->i_length and update p_decoder->i_need */ p_decoder->i_need = p_section->i_length = ((uint16_t)(p_section->p_data[1] & 0xf)) << 8 | p_section->p_data[2]; /* Check that the section isn't too long */ if (p_decoder->i_need > p_decoder->i_section_max_size - 3) { dvbpsi_error(p_dvbpsi, "PSI decoder", "PSI section too long"); dvbpsi_DeletePSISections(p_section); p_decoder->p_current_section = NULL; /* If there is a new section not being handled then go forward in the packet */ if (p_new_pos) { p_decoder->p_current_section = p_section = dvbpsi_NewPSISection(p_decoder->i_section_max_size); if (!p_section) return false; p_payload_pos = p_new_pos; p_new_pos = NULL; p_decoder->i_need = 3; p_decoder->b_complete_header = false; i_available = 188 + p_data - p_payload_pos; } else { i_available = 0; } } } else { bool b_valid_crc32 = false; bool has_crc32; /* PSI section is complete */ p_section->i_table_id = p_section->p_data[0]; p_section->b_syntax_indicator = p_section->p_data[1] & 0x80; p_section->b_private_indicator = p_section->p_data[1] & 0x40; /* Update the end of the payload if CRC_32 is present */ has_crc32 = dvbpsi_has_CRC32(p_section); if (p_section->b_syntax_indicator || has_crc32) p_section->p_payload_end -= 4; /* Check CRC32 if present */ if (has_crc32) b_valid_crc32 = dvbpsi_ValidPSISection(p_section); if (!has_crc32 || b_valid_crc32) { /* PSI section is valid */ if (p_section->b_syntax_indicator) { p_section->i_extension = (p_section->p_data[3] << 8) | p_section->p_data[4]; p_section->i_version = (p_section->p_data[5] & 0x3e) >> 1; p_section->b_current_next = p_section->p_data[5] & 0x1; p_section->i_number = p_section->p_data[6]; p_section->i_last_number = p_section->p_data[7]; p_section->p_payload_start = p_section->p_data + 8; } else { p_section->i_extension = 0; p_section->i_version = 0; p_section->b_current_next = true; p_section->i_number = 0; p_section->i_last_number = 0; p_section->p_payload_start = p_section->p_data + 3; } if (p_decoder->pf_gather) p_decoder->pf_gather(p_dvbpsi, p_section); p_decoder->p_current_section = NULL; } else { if (has_crc32 && !dvbpsi_ValidPSISection(p_section))
/***************************************************************************** * dvbpsi_pat_sections_generate ***************************************************************************** * Generate PAT sections based on the dvbpsi_pat_t structure. The third * argument is used to limit the number of program in each section (max: 253). *****************************************************************************/ dvbpsi_psi_section_t* dvbpsi_pat_sections_generate( dvbpsi_t *p_dvbpsi, dvbpsi_pat_t* p_pat, int i_max_pps ) { dvbpsi_psi_section_t * p_result = dvbpsi_NewPSISection( 1024 ); dvbpsi_psi_section_t * p_current = p_result; dvbpsi_psi_section_t * p_prev; dvbpsi_pat_program_t * p_program = p_pat->p_first_program; int i_count = 0; if ( p_current == NULL ) { dvbpsi_error( p_dvbpsi, "PAT encoder", "failed to allocate new PSI section" ); return(NULL); } /* A PAT section can carry up to 253 programs */ if ( (i_max_pps <= 0) || (i_max_pps > 253) ) i_max_pps = 253; p_current->i_table_id = 0; p_current->b_syntax_indicator = true; p_current->b_private_indicator = false; p_current->i_length = 9; /* header + CRC_32 */ p_current->i_extension = p_pat->i_ts_id; p_current->i_version = p_pat->i_version; p_current->b_current_next = p_pat->b_current_next; p_current->i_number = 0; p_current->p_payload_end += 8; /* just after the header */ p_current->p_payload_start = p_current->p_payload_end; /* PAT programs */ while ( p_program != NULL ) { /* New section if needed */ if ( ++i_count > i_max_pps ) { p_prev = p_current; p_current = dvbpsi_NewPSISection( 1024 ); if ( p_current == NULL ) { dvbpsi_error( p_dvbpsi, "PAT encoder", "failed to allocate new PSI section" ); goto error; } p_prev->p_next = p_current; i_count = 1; p_current->i_table_id = 0; p_current->b_syntax_indicator = true; p_current->b_private_indicator = false; p_current->i_length = 9; /* header + CRC_32 */ p_current->i_extension = p_pat->i_ts_id; p_current->i_version = p_pat->i_version; p_current->b_current_next = p_pat->b_current_next; p_current->i_number = p_prev->i_number + 1; p_current->p_payload_end += 8; /* just after the header */ p_current->p_payload_start = p_current->p_payload_end; } /* p_payload_end is where the program begins */ p_current->p_payload_end[0] = p_program->i_number >> 8; p_current->p_payload_end[1] = p_program->i_number; p_current->p_payload_end[2] = (p_program->i_pid >> 8) | 0xe0; p_current->p_payload_end[3] = p_program->i_pid; /* Increase length by 4 */ p_current->p_payload_end += 4; p_current->i_length += 4; p_program = p_program->p_next; } /* Finalization */ p_prev = p_result; while ( p_prev != NULL ) { p_prev->i_last_number = p_current->i_number; dvbpsi_BuildPSISection( p_dvbpsi, p_prev ); p_prev = p_prev->p_next; } return(p_result); error: /* Cleanup on error */ p_prev = p_result; dvbpsi_DeletePSISections( p_prev ); return(NULL); }
/***************************************************************************** * dvbpsi_sis_sections_decode ***************************************************************************** * SIS decoder. *****************************************************************************/ void dvbpsi_sis_sections_decode(dvbpsi_t* p_dvbpsi, dvbpsi_sis_t* p_sis, dvbpsi_psi_section_t* p_section) { uint8_t *p_byte, *p_end; while (p_section) { for (p_byte = p_section->p_payload_start + 3; p_byte < p_section->p_payload_end; ) { p_sis->i_protocol_version = p_byte[3]; p_sis->b_encrypted_packet = ((p_byte[4] & 0x80)>>8); /* NOTE: cannot handle encrypted packet */ assert(p_sis->b_encrypted_packet); p_sis->i_encryption_algorithm = ((p_byte[4] & 0x7E) >> 1); p_sis->i_pts_adjustment = ((((uint64_t)p_byte[4] & 0x01) << 32) | ((uint64_t)p_byte[5] << 24) | ((uint64_t)p_byte[6] << 16) | ((uint64_t)p_byte[7] << 8) | (uint64_t)p_byte[8]); p_sis->cw_index = p_byte[9]; p_sis->i_splice_command_length = ((p_byte[11] & 0x0F) << 8) | p_byte[12]; p_sis->i_splice_command_type = p_byte[13]; uint32_t i_splice_command_length = p_sis->i_splice_command_length; if (p_sis->i_splice_command_length == 0xfff) { /* FIXME: size 0xfff of splice_command_section is undefined */ assert(p_sis->i_splice_command_length != 0xfff); } /* FIXME: handle splice_command_sections */ switch(p_sis->i_splice_command_type) { case 0x00: /* splice_null */ case 0x04: /* splice_schedule */ case 0x05: /* splice_insert */ case 0x06: /* time_signal */ case 0x07: /* bandwidth_reservation */ break; default: dvbpsi_error(p_dvbpsi, "SIS decoder", "invalid SIS Command found"); break; } /* Service descriptors */ uint8_t *p_desc = p_byte + 13 + i_splice_command_length; p_sis->i_descriptors_length = (p_desc[0] << 8) | p_desc[1]; p_desc += 1; p_end = p_desc + p_sis->i_descriptors_length; if (p_end > p_section->p_payload_end) break; while (p_desc + 2 <= p_end) { uint8_t i_tag = p_desc[0]; uint8_t i_length = p_desc[1]; if ((i_length <= 254) && (i_length + 2 <= p_end - p_desc)) dvbpsi_sis_descriptor_add(p_sis, i_tag, i_length, p_desc + 2); p_desc += 2 + i_length; } if (p_sis->b_encrypted_packet) { /* FIXME: Currently ignored */ /* Calculate crc32 over decoded * p_sis->i_splice_command_type till p_sis->i_ecrc, * the result should be exactly p_sis->i_ecrc and indicates * a successfull decryption. */ p_desc += 4; /* E CRC 32 */ } /* point to next section */ p_byte = p_desc + 4 /* CRC 32 */; } p_section = p_section->p_next; } }
void dvbpsi_pmt_sections_gather( dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t* p_section ) { assert( p_dvbpsi ); assert( p_dvbpsi->p_decoder ); /* ¼ì²étable_id */ if ( !dvbpsi_CheckPSISection( p_dvbpsi, p_section, 0x02, "PMT decoder" ) ) { dvbpsi_DeletePSISections( p_section ); return; } /* */ dvbpsi_pmt_decoder_t* p_pmt_decoder = (dvbpsi_pmt_decoder_t *) p_dvbpsi->p_decoder; assert( p_pmt_decoder ); /* We have a valid PMT section */ /* ½ÚÄ¿ºÅ¼ì²é*/ if ( p_pmt_decoder->i_program_number != p_section->i_extension ) { /* Invalid program_number */ dvbpsi_debug( p_dvbpsi, "PMT decoder", "ignoring section %d not belonging to 'program_number' %d", p_section->i_extension, p_pmt_decoder->i_program_number ); dvbpsi_DeletePSISections( p_section ); return; } /* TS discontinuity check */ if ( p_pmt_decoder->b_discontinuity ) { dvbpsi_ReInitPMT( p_pmt_decoder, true ); p_pmt_decoder->b_discontinuity = false; }else { /* Perform some few sanity checks */ if ( p_pmt_decoder->p_building_pmt ) { if ( dvbpsi_CheckPMT( p_dvbpsi, p_section ) ) dvbpsi_ReInitPMT( p_pmt_decoder, true ); }else { if ( (p_pmt_decoder->b_current_valid) && (p_pmt_decoder->current_pmt.i_version == p_section->i_version) && (p_pmt_decoder->current_pmt.b_current_next == p_section->b_current_next) ) { /* Don't decode since this version is already decoded */ dvbpsi_debug( p_dvbpsi, "PMT decoder", "ignoring already decoded section %d", p_section->i_number ); dvbpsi_DeletePSISections( p_section ); return; } } } /* Add section to PMT */ if ( !dvbpsi_AddSectionPMT( p_dvbpsi, p_pmt_decoder, p_section ) ) { dvbpsi_error( p_dvbpsi, "PMT decoder", "failed decoding section %d", p_section->i_number ); dvbpsi_DeletePSISections( p_section ); return; } if ( dvbpsi_decoder_psi_sections_completed( DVBPSI_DECODER( p_pmt_decoder ) ) ) { assert( p_pmt_decoder->pf_pmt_callback ); /* Save the current information */ p_pmt_decoder->current_pmt = *p_pmt_decoder->p_building_pmt; p_pmt_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_pmt_sections_decode( p_pmt_decoder->p_building_pmt, p_pmt_decoder->p_sections ); /* signal the new PMT */ p_pmt_decoder->pf_pmt_callback( p_pmt_decoder->p_cb_data, p_pmt_decoder->p_building_pmt ); /* Delete sections and Reinitialize the structures */ dvbpsi_ReInitPMT( p_pmt_decoder, false ); assert( p_pmt_decoder->p_sections == NULL ); } }
/***************************************************************************** * dvbpsi_GatherBATSections ***************************************************************************** * Callback for the subtable demultiplexor. *****************************************************************************/ void dvbpsi_GatherBATSections(dvbpsi_t *p_dvbpsi, void * p_private_decoder, dvbpsi_psi_section_t * p_section) { dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_private; dvbpsi_bat_decoder_t * p_bat_decoder = (dvbpsi_bat_decoder_t*)p_private_decoder; bool b_reinit = false; assert(p_dvbpsi); assert(p_dvbpsi->p_private); if (!p_section->b_syntax_indicator) { /* Invalid section_syntax_indicator */ dvbpsi_error(p_dvbpsi, "BAT decoder", "invalid section (section_syntax_indicator == 0)"); dvbpsi_DeletePSISections(p_section); return; } dvbpsi_debug(p_dvbpsi, "BAT decoder", "Table version %2d, " "i_table_id %2d, " "i_extension %5d, " "section %3d up to %3d, " "current %1d", p_section->i_version, p_section->i_table_id, p_section->i_extension, p_section->i_number, p_section->i_last_number, p_section->b_current_next); /* We have a valid BAT section */ /* TS discontinuity check */ if (p_demux->b_discontinuity) { b_reinit = true; p_demux->b_discontinuity = false; } else { /* Perform a few sanity checks */ if (p_bat_decoder->p_building_bat) { if (p_bat_decoder->p_building_bat->i_bouquet_id != p_section->i_extension) { /* bouquet_id */ dvbpsi_error(p_dvbpsi, "BAT decoder", "'bouquet_id' differs" " whereas no TS discontinuity has occured"); b_reinit = true; } else if (p_bat_decoder->p_building_bat->i_version != p_section->i_version) { /* version_number */ dvbpsi_error(p_dvbpsi, "BAT decoder", "'version_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } else if (p_bat_decoder->i_last_section_number != p_section->i_last_number) { /* last_section_number */ dvbpsi_error(p_dvbpsi, "BAT decoder", "'last_section_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } } else { if ( (p_bat_decoder->b_current_valid) && (p_bat_decoder->current_bat.i_version == p_section->i_version) && (p_bat_decoder->current_bat.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "BAT decoder", "ignoring already decoded section %d", p_section->i_number); } else if ( (!p_bat_decoder->current_bat.b_current_next) && (p_section->b_current_next)) { /* Signal a new BAT if the previous one wasn't active */ dvbpsi_bat_t *p_bat = (dvbpsi_bat_t*)malloc(sizeof(dvbpsi_bat_t)); if (p_bat) { p_bat_decoder->current_bat.b_current_next = true; memcpy(p_bat, &p_bat_decoder->current_bat, sizeof(dvbpsi_bat_t)); p_bat_decoder->pf_bat_callback(p_bat_decoder->p_cb_data, p_bat); } else dvbpsi_error(p_dvbpsi, "BAT decoder", "Could not signal new BAT."); } dvbpsi_DeletePSISections(p_section); return; } } /* Reinit the decoder if wanted */ if (b_reinit) { /* Force redecoding */ p_bat_decoder->b_current_valid = false; /* Free structures */ if (p_bat_decoder->p_building_bat) { free(p_bat_decoder->p_building_bat); p_bat_decoder->p_building_bat = NULL; } /* Clear the section array */ for (unsigned int i = 0; i < 256; i++) { if (p_bat_decoder->ap_sections[i] != NULL) { dvbpsi_DeletePSISections(p_bat_decoder->ap_sections[i]); p_bat_decoder->ap_sections[i] = NULL; } } } /* Append the section to the list if wanted */ bool b_complete = false; /* Initialize the structures if it's the first section received */ if (!p_bat_decoder->p_building_bat) { p_bat_decoder->p_building_bat = (dvbpsi_bat_t*)malloc(sizeof(dvbpsi_bat_t)); if (p_bat_decoder->p_building_bat) dvbpsi_InitBAT(p_bat_decoder->p_building_bat, p_section->i_extension, p_section->i_version, p_section->b_current_next); else dvbpsi_error(p_dvbpsi, "BAT decoder", "failed decoding BAT section"); p_bat_decoder->i_last_section_number = p_section->i_last_number; } /* Fill the section array */ if (p_bat_decoder->ap_sections[p_section->i_number] != NULL) { dvbpsi_debug(p_dvbpsi, "BAT decoder", "overwrite section number %d", p_section->i_number); dvbpsi_DeletePSISections(p_bat_decoder->ap_sections[p_section->i_number]); } p_bat_decoder->ap_sections[p_section->i_number] = p_section; /* Check if we have all the sections */ for (unsigned int i = 0; i <= p_bat_decoder->i_last_section_number; i++) { if (!p_bat_decoder->ap_sections[i]) break; if (i == p_bat_decoder->i_last_section_number) b_complete = true; } if (b_complete) { /* Save the current information */ p_bat_decoder->current_bat = *p_bat_decoder->p_building_bat; p_bat_decoder->b_current_valid = true; /* Chain the sections */ if (p_bat_decoder->i_last_section_number) { for (int j = 0; j <= p_bat_decoder->i_last_section_number - 1; j++) p_bat_decoder->ap_sections[j]->p_next = p_bat_decoder->ap_sections[j + 1]; } /* Decode the sections */ dvbpsi_DecodeBATSections(p_bat_decoder->p_building_bat, p_bat_decoder->ap_sections[0]); /* Delete the sections */ dvbpsi_DeletePSISections(p_bat_decoder->ap_sections[0]); /* signal the new BAT */ p_bat_decoder->pf_bat_callback(p_bat_decoder->p_cb_data, p_bat_decoder->p_building_bat); /* Reinitialize the structures */ p_bat_decoder->p_building_bat = NULL; for (unsigned int i = 0; i <= p_bat_decoder->i_last_section_number; i++) p_bat_decoder->ap_sections[i] = NULL; } }
/***************************************************************************** * dvbpsi_GenBATSections ***************************************************************************** * Generate BAT sections based on the dvbpsi_bat_t structure. * similar to dvbpsi_GenNITSections *****************************************************************************/ dvbpsi_psi_section_t* dvbpsi_GenBATSections(dvbpsi_t *p_dvbpsi, dvbpsi_bat_t* p_bat) { dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024); dvbpsi_psi_section_t* p_current = p_result; dvbpsi_psi_section_t* p_prev; dvbpsi_descriptor_t* p_descriptor = p_bat->p_first_descriptor; dvbpsi_bat_ts_t* p_ts = p_bat->p_first_ts; uint16_t i_bouquet_descriptors_length, i_transport_stream_loop_length; uint8_t * p_transport_stream_loop_length; if (p_current == NULL) { dvbpsi_error(p_dvbpsi, "BAT encoder", "failed to allocate new PSI section"); return NULL; } p_current->i_table_id = 0x4a; p_current->b_syntax_indicator = true; p_current->b_private_indicator = true; p_current->i_length = 13; /* including CRC_32 */ p_current->i_extension = p_bat->i_bouquet_id; p_current->i_version = p_bat->i_version; p_current->b_current_next = p_bat->b_current_next; p_current->i_number = 0; p_current->p_payload_end += 10; p_current->p_payload_start = p_current->p_data + 8; /* first loop descriptors */ while (p_descriptor != NULL) { /* New section if needed */ /* written_data_length + descriptor_length + 2 > 1024 - CRC_32_length */ if( (p_current->p_payload_end - p_current->p_data) + p_descriptor->i_length > 1018) { /* bouquet_descriptors_length */ i_bouquet_descriptors_length = (p_current->p_payload_end - p_current->p_payload_start) - 2; p_current->p_data[8] = (i_bouquet_descriptors_length >> 8) | 0xf0; p_current->p_data[9] = i_bouquet_descriptors_length; /* transport_stream_loop_length */ p_current->p_payload_end[0] = 0; p_current->p_payload_end[1] = 0; p_current->p_payload_end += 2; p_prev = p_current; p_current = dvbpsi_NewPSISection(1024); if (p_current == NULL) { dvbpsi_error(p_dvbpsi, "BAT encoder", "failed to allocate new PSI section"); goto error; } p_prev->p_next = p_current; p_current->i_table_id = 0x4a; p_current->b_syntax_indicator = true; p_current->b_private_indicator = true; p_current->i_length = 13; /* including CRC_32 */ p_current->i_extension = p_bat->i_bouquet_id; p_current->i_version = p_bat->i_version; p_current->b_current_next = p_bat->b_current_next; p_current->i_number = p_prev->i_number + 1; p_current->p_payload_end += 10; p_current->p_payload_start = p_current->p_data + 8; } /* p_payload_end is where the descriptor begins */ p_current->p_payload_end[0] = p_descriptor->i_tag; p_current->p_payload_end[1] = p_descriptor->i_length; memcpy(p_current->p_payload_end + 2, p_descriptor->p_data, p_descriptor->i_length); /* Increase length by descriptor_length + 2 */ p_current->p_payload_end += p_descriptor->i_length + 2; p_current->i_length += p_descriptor->i_length + 2; p_descriptor = p_descriptor->p_next; }
/***************************************************************************** * dvbpsi_pat_sections_gather ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ void dvbpsi_pat_sections_gather(dvbpsi_t* p_dvbpsi, dvbpsi_psi_section_t* p_section) { assert(p_dvbpsi); if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x00, "PAT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* Now we have a valid PAT section */ dvbpsi_decoder_t *p_dec = dvbpsi_decoder_chain_get(p_dvbpsi, p_section->i_table_id, p_section->i_extension); if (!p_dec) { dvbpsi_DeletePSISections(p_section); return; } /* TS discontinuity check */ dvbpsi_pat_decoder_t *p_pat_decoder = (dvbpsi_pat_decoder_t *)p_dec; if (p_pat_decoder->b_discontinuity) { dvbpsi_ReInitPAT(p_pat_decoder, true); p_pat_decoder->b_discontinuity = false; } else { if (p_pat_decoder->p_building_pat) { if (dvbpsi_CheckPAT(p_dvbpsi, p_pat_decoder, p_section)) dvbpsi_ReInitPAT(p_pat_decoder, true); } else { if( (p_pat_decoder->b_current_valid) && (p_pat_decoder->current_pat.i_version == p_section->i_version) && (p_pat_decoder->current_pat.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "PAT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } } } /* Add section to PAT */ if (!dvbpsi_AddSectionPAT(p_dvbpsi, p_pat_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "PAT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_pat_decoder))) { assert(p_pat_decoder->pf_pat_callback); /* Save the current information */ p_pat_decoder->current_pat = *p_pat_decoder->p_building_pat; /* Decode the sections */ if (dvbpsi_pat_sections_decode(p_pat_decoder->p_building_pat, p_pat_decoder->p_sections)) p_pat_decoder->b_current_valid = true; /* signal the new PAT */ if (p_pat_decoder->b_current_valid) p_pat_decoder->pf_pat_callback(p_pat_decoder->p_priv, p_pat_decoder->p_building_pat); /* Delete sectioins and Reinitialize the structures */ dvbpsi_ReInitPAT(p_pat_decoder, !p_pat_decoder->b_current_valid); assert(p_pat_decoder->p_sections == NULL); } }
/***************************************************************************** * dvbpsi_tot_sections_generate ***************************************************************************** * Generate TDT/TOT sections based on the dvbpsi_tot_t structure. *****************************************************************************/ dvbpsi_psi_section_t* dvbpsi_tot_sections_generate(dvbpsi_t *p_dvbpsi, dvbpsi_tot_t* p_tot) { dvbpsi_psi_section_t* p_result; dvbpsi_descriptor_t* p_descriptor = p_tot->p_first_descriptor; /* If it has descriptors, it must be a TOT, otherwise a TDT */ p_result = dvbpsi_NewPSISection((p_descriptor != NULL) ? 4096 : 8); p_result->i_table_id = (p_descriptor != NULL) ? 0x73 : 0x70; p_result->b_syntax_indicator = false; p_result->b_private_indicator = false; p_result->i_length = 5; p_result->p_payload_start = p_result->p_data + 3; p_result->p_payload_end = p_result->p_data + 8; p_result->p_data[3] = (p_tot->i_utc_time >> 32) & 0xff; p_result->p_data[4] = (p_tot->i_utc_time >> 24) & 0xff; p_result->p_data[5] = (p_tot->i_utc_time >> 16) & 0xff; p_result->p_data[6] = (p_tot->i_utc_time >> 8) & 0xff; p_result->p_data[7] = p_tot->i_utc_time & 0xff; if (p_result->i_table_id == 0x73) { /* Special handling for TOT only (A TDT doesn't have descriptors!) */ /* Reserve two bytes for descriptors_loop_length */ p_result->p_payload_end += 2; p_result->i_length += 2; /* TOT descriptors */ while (p_descriptor != NULL) { /* A TOT cannot have multiple sections! */ if( (p_result->p_payload_end - p_result->p_data) + p_descriptor->i_length > 4090) { dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "TOT does not fit into one section as it ought to be !!!"); break; } /* p_payload_end is where the descriptor begins */ p_result->p_payload_end[0] = p_descriptor->i_tag; p_result->p_payload_end[1] = p_descriptor->i_length; memcpy(p_result->p_payload_end + 2, p_descriptor->p_data, p_descriptor->i_length); /* Increase length by descriptor_length + 2 */ p_result->p_payload_end += p_descriptor->i_length + 2; p_result->i_length += p_descriptor->i_length + 2; p_descriptor = p_descriptor->p_next; } /* descriptors_loop_length */ p_result->p_payload_start[5] = ((p_result->i_length - 7) << 8) | 0xf0; p_result->p_payload_start[6] = (p_result->i_length - 7) & 0xff; } /* Build the PSI section including the CRC32 on the playload. * NOTE: The p_payload_end pointer should point to the last byte * of the payload without the CRC32 field. */ dvbpsi_BuildPSISection(p_dvbpsi, p_result); if (p_result->i_table_id == 0x73) { /* A TOT has a CRC_32 although it's a private section, but the CRC_32 is part of the payload! */ p_result->p_payload_end += 4; p_result->i_length += 4; } if (!dvbpsi_tot_section_valid(p_dvbpsi, p_result)) { dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "********************************************"); dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "* Generated TDT/TOT section is invalid. *"); dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "* THIS IS A BUG, PLEASE REPORT TO THE LIST *"); dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "* --- [email protected] --- *"); dvbpsi_error(p_dvbpsi, "TDT/TOT generator", "********************************************"); } return p_result; }
/***************************************************************************** * dvbpsi_atsc_GatherEITSections ***************************************************************************** * Callback for the subtable demultiplexor. *****************************************************************************/ static void dvbpsi_atsc_GatherEITSections(dvbpsi_t * p_dvbpsi, dvbpsi_decoder_t *p_decoder, dvbpsi_psi_section_t * p_section) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0xCB, "ATSC EIT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* We have a valid EIT section */ dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_decoder; dvbpsi_atsc_eit_decoder_t *p_eit_decoder = (dvbpsi_atsc_eit_decoder_t*)p_decoder; if (!p_eit_decoder) { dvbpsi_error(p_dvbpsi, "ATSC EIT decoder", "No decoder specified"); dvbpsi_DeletePSISections(p_section); return; } /* TS discontinuity check */ if (p_demux->b_discontinuity) { dvbpsi_ReInitEIT(p_eit_decoder, true); p_eit_decoder->b_discontinuity = false; p_demux->b_discontinuity = false; } else { /* Perform a few sanity checks */ if (p_eit_decoder->p_building_eit) { if (dvbpsi_CheckEIT(p_dvbpsi, p_eit_decoder, p_section)) dvbpsi_ReInitEIT(p_eit_decoder, true); } else { if ( (p_eit_decoder->b_current_valid) && (p_eit_decoder->current_eit.i_version == p_section->i_version) && (p_eit_decoder->current_eit.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "ATSC EIT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } #if 0 if ((p_eit_decoder->b_current_valid) && (p_eit_decoder->current_eit.i_version == p_section->i_version)) { /* Signal a new EIT if the previous one wasn't active */ if ((!p_eit_decoder->current_eit.b_current_next) && (p_section->b_current_next)) { dvbpsi_atsc_eit_t * p_eit = (dvbpsi_atsc_eit_t*)malloc(sizeof(dvbpsi_atsc_eit_t)); if (p_eit) { p_eit_decoder->current_eit.b_current_next = true; *p_eit = p_eit_decoder->current_eit; p_eit_decoder->pf_eit_callback(p_eit_decoder->p_cb_data, p_eit); } else dvbpsi_error(p_dvbpsi, "ATSC EIT decoder", "Could not signal new ATSC EIT."); } } dvbpsi_DeletePSISections(p_section); return; #endif } } /* Add section to EIT */ if (!dvbpsi_AddSectionEIT(p_dvbpsi, p_eit_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "ATSC EIT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_eit_decoder))) { assert(p_eit_decoder->pf_eit_callback); /* Save the current information */ p_eit_decoder->current_eit = *p_eit_decoder->p_building_eit; p_eit_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_atsc_DecodeEITSections(p_eit_decoder->p_building_eit, p_eit_decoder->p_sections); /* Delete the sections */ dvbpsi_DeletePSISections(p_eit_decoder->p_sections); p_eit_decoder->p_sections = NULL; /* signal the new EIT */ p_eit_decoder->pf_eit_callback(p_eit_decoder->p_cb_data, p_eit_decoder->p_building_eit); /* Reinitialize the structures */ dvbpsi_ReInitEIT(p_eit_decoder, false); } }
/***************************************************************************** * dvbpsi_tot_sections_gather ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ void dvbpsi_tot_sections_gather(dvbpsi_t* p_dvbpsi, dvbpsi_decoder_t* p_decoder, dvbpsi_psi_section_t* p_section) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); const uint8_t i_table_id = ((p_section->i_table_id == 0x70 || /* TDT */ p_section->i_table_id == 0x73)) ? /* TOT */ p_section->i_table_id : 0x70; if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, i_table_id, "TDT/TOT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* Valid TDT/TOT section */ dvbpsi_tot_decoder_t* p_tot_decoder = (dvbpsi_tot_decoder_t*)p_decoder; /* TS discontinuity check */ if (p_tot_decoder->b_discontinuity) { /* We don't care about discontinuities with the TDT/TOT as it only consists of one section anyway */ //dvbpsi_ReInitTOT(p_tot_decoder, true); p_tot_decoder->b_discontinuity = false; } else { /* Perform a few sanity checks */ if (p_tot_decoder->p_building_tot) { if (dvbpsi_CheckTOT(p_dvbpsi, p_tot_decoder, p_section)) dvbpsi_ReInitTOT(p_tot_decoder, true); } #if 0 /* FIXME: Check TDT/TOT table definition for how the version numbering works for this table */ else { if( (p_tot_decoder->b_current_valid) && (p_tot_decoder->current_tot.i_version == p_section->i_version) && (p_tot_decoder->current_tot.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "TOT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } } #endif } /* Add section to TOT */ if (!dvbpsi_AddSectionTOT(p_dvbpsi, p_tot_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "TOT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_tot_decoder))) { assert(p_tot_decoder->pf_tot_callback); /* Save the current information */ p_tot_decoder->current_tot = *p_tot_decoder->p_building_tot; p_tot_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_tot_sections_decode(p_dvbpsi, p_tot_decoder->p_building_tot, p_tot_decoder->p_sections); /* Delete the sections */ dvbpsi_DeletePSISections(p_tot_decoder->p_sections); p_tot_decoder->p_sections = NULL; /* signal the new TOT */ p_tot_decoder->pf_tot_callback(p_tot_decoder->p_cb_data, p_tot_decoder->p_building_tot); /* Reinitialize the structures */ dvbpsi_ReInitTOT(p_tot_decoder, false); } }
/***************************************************************************** * dvbpsi_GatherVCTSections ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ void dvbpsi_GatherVCTSections(dvbpsi_t *p_dvbpsi, void * p_private_decoder, dvbpsi_psi_section_t * p_section) { assert(p_dvbpsi); assert(p_dvbpsi->p_private); dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *)p_dvbpsi->p_private; dvbpsi_vct_decoder_t *p_vct_decoder = (dvbpsi_vct_decoder_t*)p_private_decoder; dvbpsi_debug(p_dvbpsi, "VCT decoder", "Table version %2d, " "i_table_id %2d, " "i_extension %5d, " "section %3d up to %3d, " "current %1d", p_section->i_version, p_section->i_table_id, p_section->i_extension, p_section->i_number, p_section->i_last_number, p_section->b_current_next); if (!p_section->b_syntax_indicator) { /* Invalid section_syntax_indicator */ dvbpsi_error(p_dvbpsi, "VCT decoder", "invalid section (section_syntax_indicator == 0)"); dvbpsi_DeletePSISections(p_section); return; } bool b_reinit = false; /* TS discontinuity check */ if (p_demux->b_discontinuity) { b_reinit = true; p_demux->b_discontinuity = false; } else { /* Perform a few sanity checks */ if (p_vct_decoder->p_building_vct) { if (p_vct_decoder->p_building_vct->i_ts_id != p_section->i_extension) { /* transport_stream_id */ dvbpsi_error(p_dvbpsi, "VCT decoder", "'transport_stream_id' differs" " whereas no TS discontinuity has occured"); b_reinit = true; } else if (p_vct_decoder->p_building_vct->i_version != p_section->i_version) { /* version_number */ dvbpsi_error(p_dvbpsi, "VCT decoder", "'version_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } else if (p_vct_decoder->i_last_section_number != p_section->i_last_number) { /* last_section_number */ dvbpsi_error(p_dvbpsi, "VCT decoder", "'last_section_number' differs" " whereas no discontinuity has occured"); b_reinit = true; } } else { if( (p_vct_decoder->b_current_valid) && (p_vct_decoder->current_vct.i_version == p_section->i_version) && (p_vct_decoder->current_vct.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_DeletePSISections(p_section); return; } } } /* Reinit the decoder if wanted */ if (b_reinit) { /* Force redecoding */ p_vct_decoder->b_current_valid = false; /* Free structures */ if (p_vct_decoder->p_building_vct) { free(p_vct_decoder->p_building_vct); p_vct_decoder->p_building_vct = NULL; } /* Clear the section array */ for (unsigned int i = 0; i <= 255; i++) { if (p_vct_decoder->ap_sections[i] != NULL) { dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[i]); p_vct_decoder->ap_sections[i] = NULL; } } } /* Initialize the structures if it's the first section received */ if (!p_vct_decoder->p_building_vct) { p_vct_decoder->p_building_vct = (dvbpsi_vct_t*)calloc(1, sizeof(dvbpsi_vct_t)); if (p_vct_decoder->p_building_vct) { dvbpsi_InitVCT(p_vct_decoder->p_building_vct, p_section->i_extension, p_section->i_version, p_section->b_current_next, p_section->i_table_id); p_vct_decoder->i_last_section_number = p_section->i_last_number; } else dvbpsi_debug(p_dvbpsi, "VCT decoder", "failed decoding section"); } /* Fill the section array */ if (p_vct_decoder->ap_sections[p_section->i_number] != NULL) { dvbpsi_debug(p_dvbpsi, "VCT decoder", "overwrite section number %d", p_section->i_number); dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[p_section->i_number]); } p_vct_decoder->ap_sections[p_section->i_number] = p_section; /* Check if we have all the sections */ bool b_complete = false; for (unsigned int i = 0; i <= p_vct_decoder->i_last_section_number; i++) { if (!p_vct_decoder->ap_sections[i]) break; if (i == p_vct_decoder->i_last_section_number) b_complete = true; } if (b_complete) { /* Save the current information */ p_vct_decoder->current_vct = *p_vct_decoder->p_building_vct; p_vct_decoder->b_current_valid = true; /* Chain the sections */ if (p_vct_decoder->i_last_section_number) { for (unsigned int i = 0; (int)i <= p_vct_decoder->i_last_section_number - 1; i++) p_vct_decoder->ap_sections[i]->p_next = p_vct_decoder->ap_sections[i + 1]; } /* Decode the sections */ dvbpsi_DecodeVCTSections(p_vct_decoder->p_building_vct, p_vct_decoder->ap_sections[0]); /* Delete the sections */ dvbpsi_DeletePSISections(p_vct_decoder->ap_sections[0]); p_vct_decoder->ap_sections[0] = NULL; /* signal the new VCT */ p_vct_decoder->pf_vct_callback(p_vct_decoder->p_cb_data, p_vct_decoder->p_building_vct); /* Reinitialize the structures */ p_vct_decoder->p_building_vct = NULL; for (unsigned int i = 0; i <= p_vct_decoder->i_last_section_number; i++) p_vct_decoder->ap_sections[i] = NULL; } }
/***************************************************************************** * dvbpsi_nit_sections_gather ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ void dvbpsi_nit_sections_gather(dvbpsi_t *p_dvbpsi, dvbpsi_decoder_t *p_private_decoder, dvbpsi_psi_section_t *p_section) { assert(p_dvbpsi); const uint8_t i_table_id = ((p_section->i_table_id == 0x40) || (p_section->i_table_id == 0x41)) ? p_section->i_table_id : 0x40; if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, i_table_id, "NIT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* */ dvbpsi_nit_decoder_t* p_nit_decoder = (dvbpsi_nit_decoder_t*)p_private_decoder; /* We have a valid NIT section */ if (p_nit_decoder->i_network_id != p_section->i_extension) { /* Invalid program_number */ dvbpsi_error(p_dvbpsi, "NIT decoder", "'network_id' don't match"); dvbpsi_DeletePSISections(p_section); return; } /* TS discontinuity check */ if (p_nit_decoder->b_discontinuity) { dvbpsi_ReInitNIT(p_nit_decoder, true); p_nit_decoder->b_discontinuity = false; } else { /* Perform some few sanity checks */ if (p_nit_decoder->p_building_nit) { if (dvbpsi_CheckNIT(p_dvbpsi, p_nit_decoder, p_section)) dvbpsi_ReInitNIT(p_nit_decoder, true); } else { if ( (p_nit_decoder->b_current_valid) && (p_nit_decoder->current_nit.i_version == p_section->i_version) && (p_nit_decoder->current_nit.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "NIT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return;; } } } /* Add section to NIT */ if (!dvbpsi_AddSectionNIT(p_dvbpsi, p_nit_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "NIT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_nit_decoder))) { assert(p_nit_decoder->pf_nit_callback); /* Save the current information */ p_nit_decoder->current_nit = *p_nit_decoder->p_building_nit; p_nit_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_nit_sections_decode(p_nit_decoder->p_building_nit, p_nit_decoder->p_sections); /* signal the new NIT */ p_nit_decoder->pf_nit_callback(p_nit_decoder->p_cb_data, p_nit_decoder->p_building_nit); /* Delete sections and Reinitialize the structures */ dvbpsi_ReInitNIT(p_nit_decoder, false); assert(p_nit_decoder->p_sections == NULL); } }
/***************************************************************************** * dvbpsi_atsc_GatherETTSections ***************************************************************************** * Callback for the PSI decoder. *****************************************************************************/ static void dvbpsi_atsc_GatherETTSections(dvbpsi_t* p_dvbpsi, dvbpsi_decoder_t *p_decoder, dvbpsi_psi_section_t* p_section) { assert(p_dvbpsi); assert(p_dvbpsi->p_decoder); if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0xCC, "ATSC ETT decoder")) { dvbpsi_DeletePSISections(p_section); return; } /* We have a valid ETT section */ dvbpsi_demux_t *p_demux = (dvbpsi_demux_t *) p_dvbpsi->p_decoder; dvbpsi_atsc_ett_decoder_t* p_ett_decoder = (dvbpsi_atsc_ett_decoder_t*)p_decoder; if (!p_ett_decoder) { dvbpsi_error(p_dvbpsi, "ATSC ETT decoder", "No decoder specified"); dvbpsi_DeletePSISections(p_section); return; } /* TS discontinuity check */ if (p_demux->b_discontinuity) { dvbpsi_ReInitETT(p_ett_decoder, true); p_ett_decoder->b_discontinuity = false; p_demux->b_discontinuity = false; } else { /* Perform a few sanity checks */ if (p_ett_decoder->p_building_ett) { if (dvbpsi_CheckETT(p_dvbpsi, p_ett_decoder, p_section)) dvbpsi_ReInitETT(p_ett_decoder, true); } else { if ( (p_ett_decoder->b_current_valid) && (p_ett_decoder->current_ett.i_version == p_section->i_version) && (p_ett_decoder->current_ett.b_current_next == p_section->b_current_next)) { /* Don't decode since this version is already decoded */ dvbpsi_debug(p_dvbpsi, "ATSC ETT decoder", "ignoring already decoded section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } } } /* Add section to ETT */ if (!dvbpsi_AddSectionETT(p_dvbpsi, p_ett_decoder, p_section)) { dvbpsi_error(p_dvbpsi, "ATSC ETT decoder", "failed decoding section %d", p_section->i_number); dvbpsi_DeletePSISections(p_section); return; } /* Check if we have all the sections */ if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_ett_decoder))) { assert(p_ett_decoder->pf_ett_callback); /* Save the current information */ p_ett_decoder->current_ett = *p_ett_decoder->p_building_ett; p_ett_decoder->b_current_valid = true; /* Decode the sections */ dvbpsi_atsc_DecodeETTSections(p_ett_decoder->p_building_ett, p_ett_decoder->p_sections); /* signal the new ETT */ p_ett_decoder->pf_ett_callback(p_ett_decoder->p_cb_data, p_ett_decoder->p_building_ett); /* Delete sections and Reinitialize the structures */ dvbpsi_ReInitETT(p_ett_decoder, false); assert(p_ett_decoder->p_sections == NULL); } }