[patch] 1/2: Add NIT support
Johann Hanne <[email protected]>
| Newsgroups | gmane.comp.video.videolan.libdvbpsi.devel |
|---|---|
| Message-ID | <200804241820.40975.jhml__27701.6015527353$1211432161$gmane$org@gmx.net> |
Hi, the attached patch adds support for the NIT table. Please apply. Cheers, Johann _______________________________________________ libdvbpsi-devel mailing list [email protected] http://mailman.videolan.org/listinfo/libdvbpsi-devel
add_nit_support.diff
(text/x-diff, 41 KB)
diff -uNr libdvbpsi-trunk/src/Makefile.am libdvbpsi-trunk+nit/src/Makefile.am
--- libdvbpsi-trunk/src/Makefile.am 2008-04-23 18:45:32.000000000 +0200
+++ libdvbpsi-trunk+nit/src/Makefile.am 2008-04-24 18:01:07.000000000 +0200
@@ -15,7 +15,7 @@
pkginclude_HEADERS = dvbpsi.h psi.h descriptor.h demux.h \
tables/pat.h tables/pmt.h tables/sdt.h tables/eit.h \
- tables/cat.h \
+ tables/cat.h tables/nit.h \
descriptors/dr_02.h \
descriptors/dr_03.h \
descriptors/dr_04.h \
@@ -73,5 +73,6 @@
tables/pmt.c tables/pmt_private.h \
tables/sdt.c tables/sdt_private.h \
tables/eit.c tables/eit_private.h \
- tables/cat.c tables/cat_private.h
+ tables/cat.c tables/cat_private.h \
+ tables/nit.c tables/nit_private.h
diff -uNr libdvbpsi-trunk/src/tables/nit.c libdvbpsi-trunk+nit/src/tables/nit.c
--- libdvbpsi-trunk/src/tables/nit.c 1970-01-01 01:00:00.000000000 +0100
+++ libdvbpsi-trunk+nit/src/tables/nit.c 2008-04-24 18:00:00.000000000 +0200
@@ -0,0 +1,751 @@
+/*****************************************************************************
+ * nit.c: NIT decoder/generator
+ *----------------------------------------------------------------------------
+ * (c)2001-2008 VideoLAN
+ * $Id: $
+ *
+ * Authors: Johann Hanne
+ * heavily based on pmt.c which was written by
+ * Arnaud de Bossoreille de Ribou <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *----------------------------------------------------------------------------
+ *
+ *****************************************************************************/
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+#include <stdint.h>
+#endif
+
+#include "../dvbpsi.h"
+#include "../dvbpsi_private.h"
+#include "../psi.h"
+#include "../descriptor.h"
+#include "../demux.h"
+#include "nit.h"
+#include "nit_private.h"
+
+
+/*****************************************************************************
+ * dvbpsi_AttachNIT
+ *****************************************************************************
+ * Initialize a NIT subtable decoder.
+ *****************************************************************************/
+int dvbpsi_AttachNIT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
+ uint16_t i_extension, dvbpsi_nit_callback pf_callback,
+ void* p_cb_data)
+{
+ dvbpsi_demux_t* p_demux = (dvbpsi_demux_t*)p_psi_decoder->p_private_decoder;
+ dvbpsi_demux_subdec_t* p_subdec;
+ dvbpsi_nit_decoder_t* p_nit_decoder;
+ unsigned int i;
+
+ if(dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension))
+ {
+ DVBPSI_ERROR_ARG("NIT decoder",
+ "Already a decoder for (table_id == 0x%02x,"
+ "extension == 0x%02x)",
+ i_table_id, i_extension);
+
+ return 1;
+ }
+
+ p_subdec = (dvbpsi_demux_subdec_t*)malloc(sizeof(dvbpsi_demux_subdec_t));
+ if(p_subdec == NULL)
+ {
+ return 1;
+ }
+
+ p_nit_decoder = (dvbpsi_nit_decoder_t*)malloc(sizeof(dvbpsi_nit_decoder_t));
+
+ if(p_nit_decoder == NULL)
+ {
+ free(p_subdec);
+ return 1;
+ }
+
+ /* subtable decoder configuration */
+ p_subdec->pf_callback = &dvbpsi_GatherNITSections;
+ p_subdec->p_cb_data = p_nit_decoder;
+ p_subdec->i_id = (uint32_t)i_table_id << 16 | (uint32_t)i_extension;
+ p_subdec->pf_detach = dvbpsi_DetachNIT;
+
+ /* Attach the subtable decoder to the demux */
+ p_subdec->p_next = p_demux->p_first_subdec;
+ p_demux->p_first_subdec = p_subdec;
+
+ /* NIT decoder information */
+ p_nit_decoder->i_network_id = i_extension;
+ p_nit_decoder->pf_callback = pf_callback;
+ p_nit_decoder->p_cb_data = p_cb_data;
+ /* NIT decoder initial state */
+ p_nit_decoder->b_current_valid = 0;
+ p_nit_decoder->p_building_nit = NULL;
+ for(i = 0; i <= 255; i++)
+ p_nit_decoder->ap_sections[i] = NULL;
+
+ return 0;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_DetachNIT
+ *****************************************************************************
+ * Close a NIT decoder.
+ *****************************************************************************/
+void dvbpsi_DetachNIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
+ uint16_t i_extension)
+{
+ dvbpsi_demux_subdec_t* p_subdec;
+ dvbpsi_demux_subdec_t** pp_prev_subdec;
+ dvbpsi_nit_decoder_t* p_nit_decoder;
+
+ unsigned int i;
+
+ p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension);
+
+ if(p_demux == NULL)
+ {
+ DVBPSI_ERROR_ARG("NIT Decoder",
+ "No such NIT decoder (table_id == 0x%02x,"
+ "extension == 0x%02x)",
+ i_table_id, i_extension);
+ return;
+ }
+
+ p_nit_decoder = (dvbpsi_nit_decoder_t*)p_subdec->p_cb_data;
+
+ free(p_nit_decoder->p_building_nit);
+
+ for(i = 0; i <= 255; i++)
+ {
+ if(p_nit_decoder->ap_sections[i])
+ dvbpsi_DeletePSISections(p_nit_decoder->ap_sections[i]);
+ }
+
+ 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);
+}
+
+
+/*****************************************************************************
+ * dvbpsi_InitNIT
+ *****************************************************************************
+ * Initialize a pre-allocated dvbpsi_nit_t structure.
+ *****************************************************************************/
+void dvbpsi_InitNIT(dvbpsi_nit_t* p_nit, uint16_t i_network_id,
+ uint8_t i_version, int b_current_next)
+{
+ p_nit->i_network_id = i_network_id;
+ p_nit->i_version = i_version;
+ p_nit->b_current_next = b_current_next;
+ p_nit->p_first_descriptor = NULL;
+ p_nit->p_first_ts = NULL;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_EmptyNIT
+ *****************************************************************************
+ * Clean a dvbpsi_nit_t structure.
+ *****************************************************************************/
+void dvbpsi_EmptyNIT(dvbpsi_nit_t* p_nit)
+{
+ dvbpsi_nit_ts_t* p_ts = p_nit->p_first_ts;
+
+ dvbpsi_DeleteDescriptors(p_nit->p_first_descriptor);
+
+ while(p_ts != NULL)
+ {
+ dvbpsi_nit_ts_t* p_tmp = p_ts->p_next;
+ dvbpsi_DeleteDescriptors(p_ts->p_first_descriptor);
+ free(p_ts);
+ p_ts = p_tmp;
+ }
+
+ p_nit->p_first_descriptor = NULL;
+ p_nit->p_first_ts = NULL;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_NITAddDescriptor
+ *****************************************************************************
+ * Add a descriptor in the NIT.
+ *****************************************************************************/
+dvbpsi_descriptor_t* dvbpsi_NITAddDescriptor(dvbpsi_nit_t* p_nit,
+ uint8_t i_tag, uint8_t i_length,
+ uint8_t* p_data)
+{
+ dvbpsi_descriptor_t* p_descriptor
+ = dvbpsi_NewDescriptor(i_tag, i_length, p_data);
+
+ if(p_descriptor)
+ {
+ if(p_nit->p_first_descriptor == NULL)
+ {
+ p_nit->p_first_descriptor = p_descriptor;
+ }
+ else
+ {
+ dvbpsi_descriptor_t* p_last_descriptor = p_nit->p_first_descriptor;
+ while(p_last_descriptor->p_next != NULL)
+ p_last_descriptor = p_last_descriptor->p_next;
+ p_last_descriptor->p_next = p_descriptor;
+ }
+ }
+
+ return p_descriptor;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_NITAddTS
+ *****************************************************************************
+ * Add an TS in the NIT.
+ *****************************************************************************/
+dvbpsi_nit_ts_t* dvbpsi_NITAddTS(dvbpsi_nit_t* p_nit,
+ uint16_t i_ts_id, uint16_t i_orig_network_id)
+{
+ dvbpsi_nit_ts_t* p_ts = (dvbpsi_nit_ts_t*)malloc(sizeof(dvbpsi_nit_ts_t));
+
+ if(p_ts)
+ {
+ p_ts->i_ts_id = i_ts_id;
+ p_ts->i_orig_network_id = i_orig_network_id;
+ p_ts->p_first_descriptor = NULL;
+ p_ts->p_next = NULL;
+
+ if(p_nit->p_first_ts == NULL)
+ {
+ p_nit->p_first_ts = p_ts;
+ }
+ else
+ {
+ dvbpsi_nit_ts_t* p_last_ts = p_nit->p_first_ts;
+ while(p_last_ts->p_next != NULL)
+ p_last_ts = p_last_ts->p_next;
+ p_last_ts->p_next = p_ts;
+ }
+ }
+
+ return p_ts;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_NITTSAddDescriptor
+ *****************************************************************************
+ * Add a descriptor in the NIT TS.
+ *****************************************************************************/
+dvbpsi_descriptor_t* dvbpsi_NITTSAddDescriptor(dvbpsi_nit_ts_t* p_ts,
+ uint8_t i_tag, uint8_t i_length,
+ uint8_t* p_data)
+{
+ dvbpsi_descriptor_t* p_descriptor
+ = dvbpsi_NewDescriptor(i_tag, i_length, p_data);
+
+ if(p_descriptor)
+ {
+ if(p_ts->p_first_descriptor == NULL)
+ {
+ p_ts->p_first_descriptor = p_descriptor;
+ }
+ else
+ {
+ dvbpsi_descriptor_t* p_last_descriptor = p_ts->p_first_descriptor;
+ while(p_last_descriptor->p_next != NULL)
+ p_last_descriptor = p_last_descriptor->p_next;
+ p_last_descriptor->p_next = p_descriptor;
+ }
+ }
+
+ return p_descriptor;
+}
+
+
+/*****************************************************************************
+ * dvbpsi_GatherNITSections
+ *****************************************************************************
+ * Callback for the PSI decoder.
+ *****************************************************************************/
+void dvbpsi_GatherNITSections(dvbpsi_decoder_t * p_decoder,
+ void * p_private_decoder,
+ dvbpsi_psi_section_t * p_section)
+{
+ dvbpsi_nit_decoder_t* p_nit_decoder
+ = (dvbpsi_nit_decoder_t*)p_private_decoder;
+ int b_append = 1;
+ int b_reinit = 0;
+ unsigned int i;
+
+ DVBPSI_DEBUG_ARG("NIT decoder",
+ "Table version %2d, " "i_extension %5d, "
+ "section %3d up to %3d, " "current %1d",
+ p_section->i_version, p_section->i_extension,
+ p_section->i_number, p_section->i_last_number,
+ p_section->b_current_next);
+
+ if(p_section->i_table_id != 0x40 && p_section->i_table_id != 0x41)
+ {
+ /* Invalid table_id value */
+ DVBPSI_ERROR_ARG("NIT decoder",
+ "invalid section (table_id == 0x%02x)",
+ p_section->i_table_id);
+ b_append = 0;
+ }
+
+ if(b_append && !p_section->b_syntax_indicator)
+ {
+ /* Invalid section_syntax_indicator */
+ DVBPSI_ERROR("NIT decoder",
+ "invalid section (section_syntax_indicator == 0)");
+ b_append = 0;
+ }
+
+ /* Now if b_append is true then we have a valid NIT section */
+ if(b_append && (p_nit_decoder->i_network_id != p_section->i_extension))
+ {
+ /* Invalid program_number */
+#if 0
+ DVBPSI_ERROR("NIT decoder", "'network_id' don't match");
+#endif
+ b_append = 0;
+ }
+
+ if(b_append)
+ {
+ /* TS discontinuity check */
+ if(p_decoder->b_discontinuity)
+ {
+ b_reinit = 1;
+ p_decoder->b_discontinuity = 0;
+ }
+ else
+ {
+ /* Perform some few sanity checks */
+ if(p_nit_decoder->p_building_nit)
+ {
+ if(p_nit_decoder->p_building_nit->i_version != p_section->i_version)
+ {
+ /* version_number */
+ DVBPSI_ERROR("NIT decoder",
+ "'version_number' differs"
+ " whereas no discontinuity has occured");
+ b_reinit = 1;
+ }
+ else if(p_nit_decoder->i_last_section_number
+ != p_section->i_last_number)
+ {
+ /* last_section_number */
+ DVBPSI_ERROR("NIT decoder",
+ "'last_section_number' differs"
+ " whereas no discontinuity has occured");
+ b_reinit = 1;
+ }
+ }
+ else
+ {
+ if( (p_nit_decoder->b_current_valid)
+ && (p_nit_decoder->current_nit.i_version == p_section->i_version))
+ {
+ /* Signal a new NIT if the previous one wasn't active */
+ if( (!p_nit_decoder->current_nit.b_current_next)
+ && (p_section->b_current_next))
+ {
+ dvbpsi_nit_t* p_nit = (dvbpsi_nit_t*)malloc(sizeof(dvbpsi_nit_t));
+
+ p_nit_decoder->current_nit.b_current_next = 1;
+ *p_nit = p_nit_decoder->current_nit;
+ p_nit_decoder->pf_callback(p_nit_decoder->p_cb_data, p_nit);
+ }
+
+ /* Don't decode since this version is already decoded */
+ b_append = 0;
+ }
+ }
+ }
+ }
+
+ /* Reinit the decoder if wanted */
+ if(b_reinit)
+ {
+ /* Force redecoding */
+ p_nit_decoder->b_current_valid = 0;
+ /* Free structures */
+ if(p_nit_decoder->p_building_nit)
+ {
+ free(p_nit_decoder->p_building_nit);
+ p_nit_decoder->p_building_nit = NULL;
+ }
+ /* Clear the section array */
+ for(i = 0; i <= 255; i++)
+ {
+ if(p_nit_decoder->ap_sections[i] != NULL)
+ {
+ dvbpsi_DeletePSISections(p_nit_decoder->ap_sections[i]);
+ p_nit_decoder->ap_sections[i] = NULL;
+ }
+ }
+ }
+
+ /* Append the section to the list if wanted */
+ if(b_append)
+ {
+ int b_complete;
+
+ /* Initialize the structures if it's the first section received */
+ if(!p_nit_decoder->p_building_nit)
+ {
+ p_nit_decoder->p_building_nit =
+ (dvbpsi_nit_t*)malloc(sizeof(dvbpsi_nit_t));
+ dvbpsi_InitNIT(p_nit_decoder->p_building_nit,
+ p_nit_decoder->i_network_id,
+ p_section->i_version,
+ p_section->b_current_next);
+ p_nit_decoder->i_last_section_number = p_section->i_last_number;
+ }
+
+ /* Fill the section array */
+ if(p_nit_decoder->ap_sections[p_section->i_number] != NULL)
+ {
+ DVBPSI_DEBUG_ARG("NIT decoder", "overwrite section number %d",
+ p_section->i_number);
+ dvbpsi_DeletePSISections(p_nit_decoder->ap_sections[p_section->i_number]);
+ }
+ p_nit_decoder->ap_sections[p_section->i_number] = p_section;
+
+ /* Check if we have all the sections */
+ b_complete = 0;
+ for(i = 0; i <= p_nit_decoder->i_last_section_number; i++)
+ {
+ if(!p_nit_decoder->ap_sections[i])
+ break;
+
+ if(i == p_nit_decoder->i_last_section_number)
+ b_complete = 1;
+ }
+
+ if(b_complete)
+ {
+ /* Save the current information */
+ p_nit_decoder->current_nit = *p_nit_decoder->p_building_nit;
+ p_nit_decoder->b_current_valid = 1;
+ /* Chain the sections */
+ if(p_nit_decoder->i_last_section_number)
+ {
+ for(i = 0; i <= p_nit_decoder->i_last_section_number - 1; i++)
+ p_nit_decoder->ap_sections[i]->p_next =
+ p_nit_decoder->ap_sections[i + 1];
+ }
+ /* Decode the sections */
+ dvbpsi_DecodeNITSections(p_nit_decoder->p_building_nit,
+ p_nit_decoder->ap_sections[0]);
+ /* Delete the sections */
+ dvbpsi_DeletePSISections(p_nit_decoder->ap_sections[0]);
+ /* signal the new NIT */
+ p_nit_decoder->pf_callback(p_nit_decoder->p_cb_data,
+ p_nit_decoder->p_building_nit);
+ /* Reinitialize the structures */
+ p_nit_decoder->p_building_nit = NULL;
+ for(i = 0; i <= p_nit_decoder->i_last_section_number; i++)
+ p_nit_decoder->ap_sections[i] = NULL;
+ }
+ }
+ else
+ {
+ dvbpsi_DeletePSISections(p_section);
+ }
+}
+
+
+/*****************************************************************************
+ * dvbpsi_DecodeNITSections
+ *****************************************************************************
+ * NIT decoder.
+ *****************************************************************************/
+void dvbpsi_DecodeNITSections(dvbpsi_nit_t* p_nit,
+ dvbpsi_psi_section_t* p_section)
+{
+ uint8_t* p_byte, * p_end, * p_end2;
+
+ while(p_section)
+ {
+ /* - NIT descriptors */
+ p_byte = p_section->p_payload_start + 2;
+ p_end = p_byte + ( ((uint16_t)(p_section->p_payload_start[0] & 0x0f) << 8)
+ | p_section->p_payload_start[1]);
+
+ while(p_byte + 2 <= p_end)
+ {
+ uint8_t i_tag = p_byte[0];
+ uint8_t i_length = p_byte[1];
+ if(i_length + 2 <= p_end - p_byte)
+ dvbpsi_NITAddDescriptor(p_nit, i_tag, i_length, p_byte + 2);
+ p_byte += 2 + i_length;
+ }
+
+ p_end = p_byte + ( ((uint16_t)(p_byte[0] & 0x0f) << 8)
+ | p_byte[1]);
+ if(p_end > p_section->p_payload_end)
+ {
+ p_end = p_section->p_payload_end;
+ }
+ p_byte += 2;
+
+ /* - TSs */
+ for(; p_byte + 6 <= p_end;)
+ {
+ uint16_t i_ts_id = ((uint16_t)p_byte[0] << 8) | p_byte[1];
+ uint16_t i_orig_network_id = ((uint16_t)p_byte[2] << 8) | p_byte[3];
+ uint16_t i_length = ((uint16_t)(p_byte[4] & 0x0f) << 8) | p_byte[5];
+ dvbpsi_nit_ts_t* p_ts = dvbpsi_NITAddTS(p_nit, i_ts_id, i_orig_network_id);
+ /* - TS descriptors */
+ p_byte += 6;
+ p_end2 = p_byte + i_length;
+ if( p_end2 > p_section->p_payload_end )
+ {
+ p_end2 = p_section->p_payload_end;
+ }
+ while(p_byte + 2 <= p_end2)
+ {
+ uint8_t i_tag = p_byte[0];
+ uint8_t i_length = p_byte[1];
+ if(i_length + 2 <= p_end2 - p_byte)
+ dvbpsi_NITTSAddDescriptor(p_ts, i_tag, i_length, p_byte + 2);
+ p_byte += 2 + i_length;
+ }
+ }
+
+ p_section = p_section->p_next;
+ }
+}
+
+
+/*****************************************************************************
+ * dvbpsi_GenNITSections
+ *****************************************************************************
+ * Generate NIT sections based on the dvbpsi_nit_t structure.
+ *****************************************************************************/
+dvbpsi_psi_section_t* dvbpsi_GenNITSections(dvbpsi_nit_t* p_nit,
+ uint8_t i_table_id)
+{
+ 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_nit->p_first_descriptor;
+ dvbpsi_nit_ts_t* p_ts = p_nit->p_first_ts;
+ uint16_t i_network_descriptors_length, i_transport_stream_loop_length;
+ uint8_t * p_transport_stream_loop_length;
+
+ p_current->i_table_id = i_table_id;
+ p_current->b_syntax_indicator = 1;
+ p_current->b_private_indicator = 0;
+ p_current->i_length = 13; /* including CRC_32 */
+ p_current->i_extension = p_nit->i_network_id;
+ p_current->i_version = p_nit->i_version;
+ p_current->b_current_next = p_nit->b_current_next;
+ p_current->i_number = 0;
+ p_current->p_payload_end += 10;
+ p_current->p_payload_start = p_current->p_data + 8;
+
+ /* NIT 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)
+ {
+ /* network_descriptors_length */
+ i_network_descriptors_length = (p_current->p_payload_end - p_current->p_payload_start) - 2;
+ p_current->p_data[8] = (i_network_descriptors_length >> 8) | 0xf0;
+ p_current->p_data[9] = i_network_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);
+ p_prev->p_next = p_current;
+
+ p_current->i_table_id = i_table_id;
+ p_current->b_syntax_indicator = 1;
+ p_current->b_private_indicator = 0;
+ p_current->i_length = 13; /* including CRC_32 */
+ p_current->i_extension = p_nit->i_network_id;
+ p_current->i_version = p_nit->i_version;
+ p_current->b_current_next = p_nit->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;
+ }
+
+ /* network_descriptors_length */
+ i_network_descriptors_length = (p_current->p_payload_end - p_current->p_payload_start) - 2;
+ p_current->p_data[8] = (i_network_descriptors_length >> 8) | 0xf0;
+ p_current->p_data[9] = i_network_descriptors_length;
+
+ /* Store the position of the transport_stream_loop_length field
+ and reserve two bytes for it */
+ p_transport_stream_loop_length = p_current->p_payload_end;
+ p_current->p_payload_end += 2;
+
+ /* NIT TSs */
+ while(p_ts != NULL)
+ {
+ uint8_t* p_ts_start = p_current->p_payload_end;
+ uint16_t i_ts_length = 5;
+
+ /* Can the current section carry all the descriptors ? */
+ p_descriptor = p_ts->p_first_descriptor;
+ while( (p_descriptor != NULL)
+ && ((p_ts_start - p_current->p_data) + i_ts_length <= 1020))
+ {
+ i_ts_length += p_descriptor->i_length + 2;
+ p_descriptor = p_descriptor->p_next;
+ }
+
+ /* If _no_ and the current section isn't empty and an empty section
+ may carry one more descriptor
+ then create a new section */
+ if( (p_descriptor != NULL)
+ && (p_ts_start - p_current->p_data != 12)
+ && (i_ts_length <= 1008))
+ {
+ /* transport_stream_loop_length */
+ i_transport_stream_loop_length = (p_current->p_payload_end - p_transport_stream_loop_length) - 2;
+ p_transport_stream_loop_length[0] = (i_transport_stream_loop_length >> 8) | 0xf0;
+ p_transport_stream_loop_length[1] = i_transport_stream_loop_length;
+
+ /* will put more descriptors in an empty section */
+ DVBPSI_DEBUG("NIT generator",
+ "create a new section to carry more TS descriptors");
+ p_prev = p_current;
+ p_current = dvbpsi_NewPSISection(1024);
+ p_prev->p_next = p_current;
+
+ p_current->i_table_id = i_table_id;
+ p_current->b_syntax_indicator = 1;
+ p_current->b_private_indicator = 0;
+ p_current->i_length = 13; /* including CRC_32 */
+ p_current->i_extension = p_nit->i_network_id;
+ p_current->i_version = p_nit->i_version;
+ p_current->b_current_next = p_nit->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;
+
+ /* network_descriptors_length = 0 */
+ p_current->p_data[8] = 0xf0;
+ p_current->p_data[9] = 0x00;
+
+ /* Store the position of the transport_stream_loop_length field
+ and reserve two bytes for it */
+ p_transport_stream_loop_length = p_current->p_payload_end;
+ p_current->p_payload_end += 2;
+
+ p_ts_start = p_current->p_payload_end;
+ }
+
+ /* p_ts_start is where the TS begins */
+ p_ts_start[0] = p_ts->i_ts_id >> 8;
+ p_ts_start[1] = p_ts->i_ts_id & 0xff;
+ p_ts_start[2] = p_ts->i_orig_network_id >> 8;
+ p_ts_start[3] = p_ts->i_orig_network_id & 0xff;
+
+ /* Increase the length by 6 */
+ p_current->p_payload_end += 6;
+ p_current->i_length += 6;
+
+ /* TS descriptors */
+ p_descriptor = p_ts->p_first_descriptor;
+ while( (p_descriptor != NULL)
+ && ( (p_current->p_payload_end - p_current->p_data)
+ + p_descriptor->i_length <= 1018))
+ {
+ /* 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;
+ }
+
+ if(p_descriptor != NULL)
+ DVBPSI_ERROR("NIT generator", "unable to carry all the TS descriptors");
+
+ /* TS_info_length */
+ i_ts_length = p_current->p_payload_end - p_ts_start - 5;
+ p_ts_start[4] = (i_ts_length >> 8) | 0xf0;
+ p_ts_start[5] = i_ts_length;
+
+ p_ts = p_ts->p_next;
+ }
+
+ /* transport_stream_loop_length */
+ i_transport_stream_loop_length = (p_current->p_payload_end - p_transport_stream_loop_length) - 2;
+ p_transport_stream_loop_length[0] = (i_transport_stream_loop_length >> 8) | 0xf0;
+ p_transport_stream_loop_length[1] = i_transport_stream_loop_length;
+
+ /* Finalization */
+ p_prev = p_result;
+ while(p_prev != NULL)
+ {
+ p_prev->i_last_number = p_current->i_number;
+ dvbpsi_BuildPSISection(p_prev);
+ p_prev = p_prev->p_next;
+ }
+
+ return p_result;
+}
diff -uNr libdvbpsi-trunk/src/tables/nit.h libdvbpsi-trunk+nit/src/tables/nit.h
--- libdvbpsi-trunk/src/tables/nit.h 1970-01-01 01:00:00.000000000 +0100
+++ libdvbpsi-trunk+nit/src/tables/nit.h 2008-04-24 18:00:00.000000000 +0200
@@ -0,0 +1,287 @@
+/*****************************************************************************
+ * nit.h
+ * (c)2001-2008 VideoLAN
+ * $Id: $
+ *
+ * Authors: Johann Hanne
+ * heavily based on pmt.c which was written by
+ * Arnaud de Bossoreille de Ribou <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************/
+
+/*!
+ * \file <nit.h>
+ * \author Johann Hanne
+ * \brief Application interface for the NIT decoder and the NIT generator.
+ *
+ * Application interface for the NIT decoder and the NIT generator. New
+ * decoded NIT tables are sent by callback to the application. If a table
+ * wasn't active (b_current_next == 0) and the next is the same but active
+ * (b_current_next == 1) then the two lists are empty and should be
+ * caught from the previous structure.
+ */
+
+#ifndef _DVBPSI_NIT_H_
+#define _DVBPSI_NIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*****************************************************************************
+ * dvbpsi_nit_ts_t
+ *****************************************************************************/
+/*!
+ * \struct dvbpsi_nit_ts_s
+ * \brief NIT TS structure.
+ *
+ * This structure is used to store a decoded TS description.
+ * (ETSI EN 300 468 section 5.2.1).
+ */
+/*!
+ * \typedef struct dvbpsi_nit_ts_s dvbpsi_nit_ts_t
+ * \brief dvbpsi_nit_ts_t type definition.
+ */
+typedef struct dvbpsi_nit_ts_s
+{
+ uint16_t i_ts_id; /*!< transport stream id */
+ uint16_t i_orig_network_id; /*!< original network id */
+
+ dvbpsi_descriptor_t * p_first_descriptor; /*!< descriptor list */
+
+ struct dvbpsi_nit_ts_s * p_next; /*!< next element of
+ the list */
+
+} dvbpsi_nit_ts_t;
+
+
+/*****************************************************************************
+ * dvbpsi_nit_t
+ *****************************************************************************/
+/*!
+ * \struct dvbpsi_nit_s
+ * \brief NIT structure.
+ *
+ * This structure is used to store a decoded NIT.
+ * (ETSI EN 300 468 section 5.2.1).
+ */
+/*!
+ * \typedef struct dvbpsi_nit_s dvbpsi_nit_t
+ * \brief dvbpsi_nit_t type definition.
+ */
+typedef struct dvbpsi_nit_s
+{
+ uint16_t i_network_id; /*!< network_id */
+ uint8_t i_version; /*!< version_number */
+ int b_current_next; /*!< current_next_indicator */
+
+ dvbpsi_descriptor_t * p_first_descriptor; /*!< descriptor list */
+
+ dvbpsi_nit_ts_t * p_first_ts; /*!< TS list */
+
+} dvbpsi_nit_t;
+
+
+/*****************************************************************************
+ * dvbpsi_nit_callback
+ *****************************************************************************/
+/*!
+ * \typedef void (* dvbpsi_nit_callback)(void* p_cb_data,
+ dvbpsi_nit_t* p_new_nit)
+ * \brief Callback type definition.
+ */
+typedef void (* dvbpsi_nit_callback)(void* p_cb_data, dvbpsi_nit_t* p_new_nit);
+
+
+/*****************************************************************************
+ * dvbpsi_AttachNIT
+ *****************************************************************************/
+/*!
+ * \fn void dvbpsi_AttachNIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
+ uint16_t i_extension, dvbpsi_nit_callback pf_callback,
+ void* p_cb_data)
+ * \brief Creation and initialization of a NIT decoder.
+ * \param p_demux Subtable demultiplexor to which the decoder is attached.
+ * \param i_table_id Table ID, 0x4E, 0x4F, or 0x50-0x6F.
+ * \param i_extension Table ID extension, here service ID.
+ * \param pf_callback function to call back on new NIT.
+ * \param p_cb_data private data given in argument to the callback.
+ * \return 0 if everything went ok.
+ */
+int dvbpsi_AttachNIT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
+ uint16_t i_extension, dvbpsi_nit_callback pf_callback,
+ void* p_cb_data);
+
+
+/*****************************************************************************
+ * dvbpsi_DetachNIT
+ *****************************************************************************/
+/*!
+ * \fn void dvbpsi_DetachNIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
+ uint16_t i_extension)
+ * \brief Destroy a NIT decoder.
+ * \param p_demux Subtable demultiplexor to which the decoder is attached.
+ * \param i_table_id Table ID, 0x4E, 0x4F, or 0x50-0x6F.
+ * \param i_extension Table ID extension, here service ID.
+ * \return nothing.
+ */
+void dvbpsi_DetachNIT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
+ uint16_t i_extension);
+
+
+/*****************************************************************************
+ * dvbpsi_InitNIT/dvbpsi_NewNIT
+ *****************************************************************************/
+/*!
+ * \fn void dvbpsi_InitNIT(dvbpsi_nit_t* p_nit, uint16_t i_network_id,
+ uint8_t i_version, int b_current_next)
+ * \brief Initialize a user-allocated dvbpsi_nit_t structure.
+ * \param p_nit pointer to the NIT structure
+ * \param i_network_id network id
+ * \param i_version NIT version
+ * \param b_current_next current next indicator
+ * \return nothing.
+ */
+void dvbpsi_InitNIT(dvbpsi_nit_t* p_nit, uint16_t i_network_id,
+ uint8_t i_version, int b_current_next);
+
+/*!
+ * \def dvbpsi_NewNIT(p_nit, i_network_id,
+ i_version, b_current_next)
+ * \brief Allocate and initialize a new dvbpsi_nit_t structure.
+ * \param p_nit pointer to the NIT structure
+ * \param i_network_id network id
+ * \param i_version NIT version
+ * \param b_current_next current next indicator
+ * \param i_pcr_pid PCR_PID
+ * \return nothing.
+ */
+#define dvbpsi_NewNIT(p_nit, i_network_id, \
+ i_version, b_current_next) \
+do { \
+ p_nit = (dvbpsi_nit_t*)malloc(sizeof(dvbpsi_nit_t)); \
+ if(p_nit != NULL) \
+ dvbpsi_InitNIT(p_nit, i_network_id, i_version, b_current_next); \
+} while(0);
+
+
+/*****************************************************************************
+ * dvbpsi_EmptyNIT/dvbpsi_DeleteNIT
+ *****************************************************************************/
+/*!
+ * \fn void dvbpsi_EmptyNIT(dvbpsi_nit_t* p_nit)
+ * \brief Clean a dvbpsi_nit_t structure.
+ * \param p_nit pointer to the NIT structure
+ * \return nothing.
+ */
+void dvbpsi_EmptyNIT(dvbpsi_nit_t* p_nit);
+
+/*!
+ * \def dvbpsi_DeleteNIT(p_nit)
+ * \brief Clean and free a dvbpsi_nit_t structure.
+ * \param p_nit pointer to the NIT structure
+ * \return nothing.
+ */
+#define dvbpsi_DeleteNIT(p_nit) \
+do { \
+ dvbpsi_EmptyNIT(p_nit); \
+ free(p_nit); \
+} while(0);
+
+
+/*****************************************************************************
+ * dvbpsi_NITAddDescriptor
+ *****************************************************************************/
+/*!
+ * \fn dvbpsi_descriptor_t* dvbpsi_NITAddDescriptor(dvbpsi_nit_t* p_nit,
+ uint8_t i_tag,
+ uint8_t i_length,
+ uint8_t* p_data)
+ * \brief Add a descriptor in the NIT.
+ * \param p_nit pointer to the NIT structure
+ * \param i_tag descriptor's tag
+ * \param i_length descriptor's length
+ * \param p_data descriptor's data
+ * \return a pointer to the added descriptor.
+ */
+dvbpsi_descriptor_t* dvbpsi_NITAddDescriptor(dvbpsi_nit_t* p_nit,
+ uint8_t i_tag, uint8_t i_length,
+ uint8_t* p_data);
+
+
+/*****************************************************************************
+ * dvbpsi_NITAddTS
+ *****************************************************************************/
+/*!
+ * \fn dvbpsi_nit_ts_t* dvbpsi_NITAddTS(dvbpsi_nit_t* p_nit,
+ uint8_t i_type, uint16_t i_pid)
+ * \brief Add an TS in the NIT.
+ * \param p_nit pointer to the NIT structure
+ * \param i_type type of TS
+ * \param i_pid PID of the TS
+ * \return a pointer to the added TS.
+ */
+dvbpsi_nit_ts_t* dvbpsi_NITAddTS(dvbpsi_nit_t* p_nit,
+ uint16_t i_ts_id, uint16_t i_orig_network_id);
+
+
+/*****************************************************************************
+ * dvbpsi_NITTSAddDescriptor
+ *****************************************************************************/
+/*!
+ * \fn dvbpsi_descriptor_t* dvbpsi_NITTSAddDescriptor(dvbpsi_nit_ts_t* p_ts,
+ uint8_t i_tag,
+ uint8_t i_length,
+ uint8_t* p_data)
+ * \brief Add a descriptor in the NIT TS.
+ * \param p_ts pointer to the TS structure
+ * \param i_tag descriptor's tag
+ * \param i_length descriptor's length
+ * \param p_data descriptor's data
+ * \return a pointer to the added descriptor.
+ */
+dvbpsi_descriptor_t* dvbpsi_NITTSAddDescriptor(dvbpsi_nit_ts_t* p_ts,
+ uint8_t i_tag, uint8_t i_length,
+ uint8_t* p_data);
+
+
+/*****************************************************************************
+ * dvbpsi_GenNITSections
+ *****************************************************************************/
+/*!
+ * \fn dvbpsi_psi_section_t* dvbpsi_GenNITSections(dvbpsi_nit_t* p_nit,
+ uint8_t i_table_id)
+ * \brief NIT generator
+ * \param p_nit NIT structure
+ * \param i_table_id table id, 0x40 = actual network / 0x41 = other network
+ * \return a pointer to the list of generated PSI sections.
+ *
+ * Generate NIT sections based on the dvbpsi_nit_t structure.
+ */
+dvbpsi_psi_section_t* dvbpsi_GenNITSections(dvbpsi_nit_t* p_nit,
+ uint8_t i_table_id);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#else
+#error "Multiple inclusions of nit.h"
+#endif
+
diff -uNr libdvbpsi-trunk/src/tables/nit_private.h libdvbpsi-trunk+nit/src/tables/nit_private.h
--- libdvbpsi-trunk/src/tables/nit_private.h 1970-01-01 01:00:00.000000000 +0100
+++ libdvbpsi-trunk+nit/src/tables/nit_private.h 2008-04-24 18:02:34.000000000 +0200
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * nit_private.h: private NIT structures
+ *----------------------------------------------------------------------------
+ * (c)2001-2002 VideoLAN
+ * $Id: $
+ *
+ * Authors: Johann Hanne
+ * heavily based on pmt.c which was written by
+ * Arnaud de Bossoreille de Ribou <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *----------------------------------------------------------------------------
+ *
+ *****************************************************************************/
+
+#ifndef _DVBPSI_NIT_PRIVATE_H_
+#define _DVBPSI_NIT_PRIVATE_H_
+
+/*****************************************************************************
+ * dvbpsi_nit_decoder_t
+ *****************************************************************************
+ * NIT decoder.
+ *****************************************************************************/
+typedef struct dvbpsi_nit_decoder_s
+{
+ uint16_t i_network_id;
+
+ dvbpsi_nit_callback pf_callback;
+ void * p_cb_data;
+
+ dvbpsi_nit_t current_nit;
+ dvbpsi_nit_t * p_building_nit;
+
+ int b_current_valid;
+
+ uint8_t i_last_section_number;
+ dvbpsi_psi_section_t * ap_sections [256];
+
+} dvbpsi_nit_decoder_t;
+
+
+/*****************************************************************************
+ * dvbpsi_GatherNITSections
+ *****************************************************************************
+ * Callback for the PSI decoder.
+ *****************************************************************************/
+void dvbpsi_GatherNITSections(dvbpsi_decoder_t* p_psi_decoder,
+ void* p_private_decoder,
+ dvbpsi_psi_section_t* p_section);
+
+
+/*****************************************************************************
+ * dvbpsi_DecodeNITSections
+ *****************************************************************************
+ * NIT decoder.
+ *****************************************************************************/
+void dvbpsi_DecodeNITSections(dvbpsi_nit_t* p_nit,
+ dvbpsi_psi_section_t* p_section);
+
+
+#else
+#error "Multiple inclusions of nit_private.h"
+#endif
+