Commit e2393869 authored by Zlu Zu's avatar Zlu Zu Committed by Jean-Paul Saman

BAT decoder and generator

Original patch was modified by Jean-Paul Saman <jpsaman@videolan.org>
- changed license to LGPLv2.1
- general cleanup
- fixed memleaks
- add missing prototypes to bat_private.h
- add static to functions in example/decode_bat.c
parent 897aa49f
......@@ -60,3 +60,7 @@ E: jpsaman@videolan.org
D: VBI Data Descriptor (0x45)
D: CUE Identifier Descriptor (0x8a)
D: Splice Information Table
N: Zlu Zu
E: zluzu@gmail.com
D: BAT decoder and generator
## Process this file with automake to produce Makefile.in
noinst_PROGRAMS = decode_pat decode_pmt get_pcr_pid decode_sdt decode_mpeg
noinst_PROGRAMS = decode_pat decode_pmt get_pcr_pid decode_sdt decode_mpeg decode_bat
decode_pat_SOURCES = decode_pat.c
decode_pat_LDFLAGS = -L../src -ldvbpsi
......@@ -20,3 +20,5 @@ decode_mpeg_SOURCES += connect.c connect.h
endif
decode_mpeg_LDFLAGS = -L../src -ldvbpsi -lm
decode_bat_SOURCES = decode_bat.c
decode_bat_LDFLAGS = -L../src -ldvbpsi
/*****************************************************************************
* decode_bat.c: BAT decoder example
*----------------------------------------------------------------------------
* Copyright (C) 2001-2010 VideoLAN
* $Id: decode_bat.c 01 2010-04-01 17:55:18 zhuzlu $
*
* Authors: Zhu zhenglu <zhuzlu@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*----------------------------------------------------------------------------
*
*****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#elif defined(HAVE_STDINT_H)
#include <stdint.h>
#endif
/* The libdvbpsi distribution defines DVBPSI_DIST */
#ifdef DVBPSI_DIST
#include "../src/dvbpsi.h"
#include "../src/psi.h"
#include "../src/demux.h"
#include "../src/descriptor.h"
#include "../src/tables/bat.h"
#else
#include <dvbpsi/dvbpsi.h>
#include <dvbpsi/psi.h>
#include <dvbpsi/demux.h>
#include <dvbpsi/descriptor.h>
#include <dvbpsi/bat.h>
#endif
/*****************************************************************************
* ReadPacket
*****************************************************************************/
static int ReadPacket(int i_fd, uint8_t* p_dst)
{
int i = 187;
int i_rc = 1;
p_dst[0] = 0;
while((p_dst[0] != 0x47) && (i_rc > 0))
{
i_rc = read(i_fd, p_dst, 1);
}
while((i != 0) && (i_rc > 0))
{
i_rc = read(i_fd, p_dst + 188 - i, i);
if(i_rc >= 0)
i -= i_rc;
}
return (i == 0) ? 1 : 0;
}
/*****************************************************************************
* DumpDescriptors
*****************************************************************************/
static void DumpDescriptors(const char* str, dvbpsi_descriptor_t* p_descriptor)
{
while(p_descriptor)
{
int i;
printf("%s 0x%02x : \"", str, p_descriptor->i_tag);
for(i = 0; i < p_descriptor->i_length; i++)
printf("%.2x", p_descriptor->p_data[i]);
printf("\"\n");
p_descriptor = p_descriptor->p_next;
}
};
/*****************************************************************************
* Print_0xb1
*****************************************************************************/
static void Print_DescTag_0xb1(uint16_t i_ts_id, dvbpsi_descriptor_t* p_descriptor)
{
int i;
uint8_t *pdata;
unsigned int sub_bouquet_id;
int num;
unsigned int formater;
pdata = p_descriptor->p_data;
num=(p_descriptor->i_length-2)/9;
sub_bouquet_id= (((unsigned int)pdata[0]&0xff)<<8)|pdata[1];
if(sub_bouquet_id!=0xffff)
{
printf("sub_bouquet_id!=0xffff\n");
return;
}
if(num*9!=p_descriptor->i_length-2)
{
printf("num of private_services error\n");
return;
}
pdata+=2;
printf("\nts_id: %d, service_num: %d, service_id list: \n",i_ts_id,num);
formater=0;
for(i = 0; i < num; i++)
{
uint16_t service_id=(((uint16_t)pdata[0]&0xff)<<8)|pdata[1];
printf("%.4x ", service_id);
formater++;
if(0 == formater%16)
{
printf("\n");
}
pdata+=9;
}
printf("\r\n");
}
/*****************************************************************************
* DumpDescriptors_verbose
*****************************************************************************/
static void DumpDescriptors_verbose(uint16_t i_ts_id, dvbpsi_descriptor_t* p_descriptor)
{
while(p_descriptor)
{
if(0xb1 == p_descriptor->i_tag)
{
Print_DescTag_0xb1(i_ts_id,p_descriptor);
}
p_descriptor = p_descriptor->p_next;
}
};
/*****************************************************************************
* DumpBAT_verbose
*****************************************************************************/
static void DumpBAT_verbose(void* p_zero, dvbpsi_bat_t* p_bat)
{
dvbpsi_bat_ts_t* p_ts = p_bat->p_first_ts;
while(p_ts)
{
DumpDescriptors_verbose(p_ts->i_ts_id, p_ts->p_first_descriptor);
p_ts = p_ts->p_next;
}
}
/*****************************************************************************
* DumpBAT
*****************************************************************************/
static void DumpBAT(void* p_zero, dvbpsi_bat_t* p_bat)
{
dvbpsi_bat_ts_t* p_ts = p_bat->p_first_ts;
{
printf( "\n");
printf( "New active BAT(binary dumped)\n");
printf( " bouquet_id : %d\n",
p_bat->i_bouquet_id);
printf( " version_number : %d\n",
p_bat->i_version);
printf( " | ts_id \n");
while(p_ts)
{
printf(" | 0x%02x \n",
p_ts->i_ts_id);
DumpDescriptors(" | ]", p_ts->p_first_descriptor);
p_ts = p_ts->p_next;
}
printf( "\n");
printf( "New active BAT(string dumped)\n");
DumpBAT_verbose(p_zero,p_bat);
printf("\n");
}
dvbpsi_DeleteBAT(p_bat);
}
/*****************************************************************************
* NewSubtable
*****************************************************************************/
static void NewSubtableBAT(void * p_zero, dvbpsi_handle h_dvbpsi,
uint8_t i_table_id, uint16_t i_extension)
{
if(i_table_id == 0x4a)
{
dvbpsi_AttachBAT(h_dvbpsi, i_table_id, i_extension, DumpBAT, NULL);
}
}
/*****************************************************************************
* main
*****************************************************************************/
int main(int i_argc, char* pa_argv[])
{
int i_fd;
uint8_t data[188];
dvbpsi_handle h_dvbpsi;
int b_ok;
if(i_argc != 2)
return 1;
i_fd = open(pa_argv[1], 0);
h_dvbpsi = dvbpsi_AttachDemux(NewSubtableBAT, NULL);
b_ok = ReadPacket(i_fd, data);
while(b_ok)
{
uint16_t i_pid = ((uint16_t)(data[1] & 0x1f) << 8) + data[2];
if(i_pid == 0x11)
dvbpsi_PushPacket(h_dvbpsi, data);
b_ok = ReadPacket(i_fd, data);
}
dvbpsi_DetachDemux(h_dvbpsi);
return 0;
}
......@@ -16,6 +16,7 @@ libdvbpsi_la_LDFLAGS = -version-info 7:0:0
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/nit.h tables/tot.h tables/sis.h \
tables/bat.h \
descriptors/dr_02.h \
descriptors/dr_03.h \
descriptors/dr_04.h \
......@@ -84,5 +85,6 @@ tables_src = tables/pat.c tables/pat_private.h \
tables/cat.c tables/cat_private.h \
tables/nit.c tables/nit_private.h \
tables/tot.c tables/tot_private.h \
tables/sis.c tables/sis_private.h
tables/sis.c tables/sis_private.h \
tables/bat.c tables/bat_private.h
/*****************************************************************************
* bat.c: BAT decoder/generator
*----------------------------------------------------------------------------
* Copyright (C) 2001-2010 VideoLAN
* $Id: bat.c 110 2010-04-01 12:52:02Z gbazin $
*
* Authors: Zhu zhenglu <zhuzlu@gmail.com>
* heavily based on nit.c which was written by
* Johann Hanne
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "bat.h"
#include "bat_private.h"
/*****************************************************************************
* dvbpsi_AttachBAT
*****************************************************************************
* Initialize a BAT subtable decoder.
*****************************************************************************/
int dvbpsi_AttachBAT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
uint16_t i_extension, dvbpsi_bat_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_bat_decoder_t* p_bat_decoder;
unsigned int i;
if(dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension))
{
DVBPSI_ERROR_ARG("BAT 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_bat_decoder = (dvbpsi_bat_decoder_t*)malloc(sizeof(dvbpsi_bat_decoder_t));
if(p_bat_decoder == NULL)
{
free(p_subdec);
return 1;
}
/* subtable decoder configuration */
p_subdec->pf_callback = &dvbpsi_GatherBATSections;
p_subdec->p_cb_data = p_bat_decoder;
p_subdec->i_id = (uint32_t)i_table_id << 16 | (uint32_t)i_extension;
p_subdec->pf_detach = dvbpsi_DetachBAT;
/* Attach the subtable decoder to the demux */
p_subdec->p_next = p_demux->p_first_subdec;
p_demux->p_first_subdec = p_subdec;
/* BAT decoder information */
p_bat_decoder->pf_callback = pf_callback;
p_bat_decoder->p_cb_data = p_cb_data;
/* BAT decoder initial state */
p_bat_decoder->b_current_valid = 0;
p_bat_decoder->p_building_bat = NULL;
for(i = 0; i < 256; i++)
p_bat_decoder->ap_sections[i] = NULL;
return 0;
}
/*****************************************************************************
* dvbpsi_DetachBAT
*****************************************************************************
* Close a BAT decoder.
*****************************************************************************/
void dvbpsi_DetachBAT(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_bat_decoder_t* p_bat_decoder;
unsigned int i;
p_subdec = dvbpsi_demuxGetSubDec(p_demux, i_table_id, i_extension);
if(p_subdec == NULL)
{
DVBPSI_ERROR_ARG("BAT Decoder",
"No such BAT decoder (table_id == 0x%02x,"
"extension == 0x%02x)",
i_table_id, i_extension);
return;
}
p_bat_decoder = (dvbpsi_bat_decoder_t*)p_subdec->p_cb_data;
free(p_bat_decoder->p_building_bat);
for(i = 0; i < 256; i++)
{
if(p_bat_decoder->ap_sections[i])
dvbpsi_DeletePSISections(p_bat_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_InitBAT
*****************************************************************************
* Initialize a pre-allocated dvbpsi_bat_t structure.
*****************************************************************************/
void dvbpsi_InitBAT(dvbpsi_bat_t* p_bat, uint16_t i_bouquet_id, uint8_t i_version,
int b_current_next)
{
p_bat->i_bouquet_id = i_bouquet_id;
p_bat->i_version = i_version;
p_bat->b_current_next = b_current_next;
p_bat->p_first_ts = NULL;
p_bat->p_first_descriptor = NULL;
}
/*****************************************************************************
* dvbpsi_EmptyBAT
*****************************************************************************
* Clean a dvbpsi_bat_t structure.
*****************************************************************************/
void dvbpsi_EmptyBAT(dvbpsi_bat_t* p_bat)
{
dvbpsi_bat_ts_t* p_ts = p_bat->p_first_ts;
dvbpsi_DeleteDescriptors(p_bat->p_first_descriptor);
p_bat->p_first_descriptor = NULL;
while(p_ts != NULL)
{
dvbpsi_bat_ts_t* p_tmp = p_ts->p_next;
dvbpsi_DeleteDescriptors(p_ts->p_first_descriptor);
free(p_ts);
p_ts = p_tmp;
}
p_bat->p_first_ts = NULL;
}
/*****************************************************************************
* dvbpsi_BATAddTS
*****************************************************************************
* Add a TS description at the end of the BAT.
*****************************************************************************/
dvbpsi_bat_ts_t *dvbpsi_BATAddTS(dvbpsi_bat_t* p_bat,
uint16_t i_ts_id, uint16_t i_orig_network_id)
{
dvbpsi_bat_ts_t * p_ts
= (dvbpsi_bat_ts_t*)malloc(sizeof(dvbpsi_bat_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_next = NULL;
p_ts->p_first_descriptor = NULL;
if(p_bat->p_first_ts == NULL)
{
p_bat->p_first_ts = p_ts;
}
else
{
dvbpsi_bat_ts_t * p_last_ts = p_bat->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_BATBouquetAddDescriptor
*****************************************************************************
* Add a descriptor in the BAT Bouquet descriptors (the first loop description),
* which is in the first loop of BAT.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_BATBouquetAddDescriptor(
dvbpsi_bat_t *p_bat,
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_bat->p_first_descriptor == NULL)
{
p_bat->p_first_descriptor = p_descriptor;
}
else
{
dvbpsi_descriptor_t * p_last_descriptor = p_bat->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_BATTSAddDescriptor
*****************************************************************************
* Add a descriptor in the BAT TS descriptors, which is in the second loop of BAT.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_BATTSAddDescriptor(
dvbpsi_bat_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_GatherBATSections
*****************************************************************************
* Callback for the subtable demultiplexor.
*****************************************************************************/
void dvbpsi_GatherBATSections(dvbpsi_decoder_t * p_psi_decoder,
void * p_private_decoder,
dvbpsi_psi_section_t * p_section)
{
dvbpsi_bat_decoder_t * p_bat_decoder
= (dvbpsi_bat_decoder_t*)p_private_decoder;
int b_append = 1;
int b_reinit = 0;
unsigned int i;
DVBPSI_DEBUG_ARG("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);
if(!p_section->b_syntax_indicator)
{
/* Invalid section_syntax_indicator */
DVBPSI_ERROR("BAT decoder",
"invalid section (section_syntax_indicator == 0)");
b_append = 0;
}
/* Now if b_append is true then we have a valid BAT section */
if(b_append)
{
/* TS discontinuity check */
if(p_psi_decoder->b_discontinuity)
{
b_reinit = 1;
p_psi_decoder->b_discontinuity = 0;
}
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("BAT decoder",
"'bouquet_id' differs"
" whereas no TS discontinuity has occured");
b_reinit = 1;
}
else if(p_bat_decoder->p_building_bat->i_version
!= p_section->i_version)
{
/* version_number */
DVBPSI_ERROR("BAT decoder",
"'version_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
else if(p_bat_decoder->i_last_section_number !=
p_section->i_last_number)
{
/* last_section_number */
DVBPSI_ERROR("BAT decoder",
"'last_section_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
}
}
else
{
if( (p_bat_decoder->b_current_valid)
&& (p_bat_decoder->current_bat.i_version == p_section->i_version))
{
/* Signal a new BAT if the previous one wasn't active */
if( (!p_bat_decoder->current_bat.b_current_next)
&& (p_section->b_current_next))
{
dvbpsi_bat_t *p_bat = NULL;
p_bat_decoder->current_bat.b_current_next = 1;
*p_bat = p_bat_decoder->current_bat;
p_bat_decoder->pf_callback(p_bat_decoder->p_cb_data, p_bat);
}
/* Don't decode since this version is already decoded */
b_append = 0;
}
}
}
}
/* Reinit the decoder if wanted */
if(b_reinit)
{
/* Force redecoding */
p_bat_decoder->b_current_valid = 0;
/* 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(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 */
if(b_append)
{
int b_complete;
/* 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));
dvbpsi_InitBAT(p_bat_decoder->p_building_bat,
p_section->i_extension,
p_section->i_version,
p_section->b_current_next);
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_ARG("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 */
b_complete = 0;
for(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 = 1;
}
if(b_complete)
{
/* Save the current information */
p_bat_decoder->current_bat = *p_bat_decoder->p_building_bat;
p_bat_decoder->b_current_valid = 1;
/* Chain the sections */
if(p_bat_decoder->i_last_section_number)
{
int j;
for(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_callback(p_bat_decoder->p_cb_data,
p_bat_decoder->p_building_bat);
/* Reinitialize the structures */
p_bat_decoder->p_building_bat = NULL;
for(i = 0; i <= p_bat_decoder->i_last_section_number; i++)
p_bat_decoder->ap_sections[i] = NULL;
}
}
else
{
dvbpsi_DeletePSISections(p_section);
}
}
/*****************************************************************************
* dvbpsi_DecodeBATSection
*****************************************************************************
* BAT decoder.
* p_bat as the output parameter
* p_section as the input parameter
* similar to dvbpsi_DecodeNITSection
*****************************************************************************/
void dvbpsi_DecodeBATSections(dvbpsi_bat_t* p_bat,
dvbpsi_psi_section_t* p_section)
{
uint8_t* p_byte, * p_end, * p_end2;
while(p_section)
{
/* - first loop 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_BATBouquetAddDescriptor(p_bat, 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_transport_descriptors_length = ((uint16_t)(p_byte[4] & 0x0f) << 8) | p_byte[5];
dvbpsi_bat_ts_t* p_ts = dvbpsi_BATAddTS(p_bat, i_ts_id, i_orig_network_id);
/* - TS descriptors */
p_byte += 6;
p_end2 = p_byte + i_transport_descriptors_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_BATTSAddDescriptor(p_ts, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
}
p_section = p_section->p_next;
}
}
/*****************************************************************************
* dvbpsi_GenBATSections
*****************************************************************************
* Generate BAT sections based on the dvbpsi_bat_t structure.
* similar to dvbpsi_GenNITSections
*****************************************************************************/
dvbpsi_psi_section_t* dvbpsi_GenBATSections(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;
p_current->i_table_id = 0x4a;
p_current->b_syntax_indicator = 1;
p_current->b_private_indicator = 1;
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);
p_prev->p_next = p_current;
p_current->i_table_id = 0x4a;
p_current->b_syntax_indicator = 1;
p_current->b_private_indicator = 1;
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;
}
/* 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;
/* 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;
/* second loop: BAT TSs */
while(p_ts != NULL)
{
uint8_t* p_ts_start = p_current->p_payload_end;
uint16_t i_transport_descriptors_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_transport_descriptors_length <= 1020))
{
i_transport_descriptors_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_transport_descriptors_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("BAT 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 = 0x4a;
p_current->b_syntax_indicator = 1;
p_current->b_private_indicator = 1;
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;
/* bouquet_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("BAT generator", "unable to carry all the TS descriptors");
/* transport_descriptors_length */
i_transport_descriptors_length = p_current->p_payload_end - p_ts_start - 5;
p_ts_start[4] = (i_transport_descriptors_length >> 8) | 0xf0;
p_ts_start[5] = i_transport_descriptors_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;
}
/*****************************************************************************
* bat.h
* Copyright (C) 2001-2010 VideoLAN
* $Id: bat.h $
*
* Authors: Zhu zhenglu <zhuzlu@gmail.com>
* heavily based on nit.h which was written by
* Johann Hanne
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
*****************************************************************************/
/*!
* \file bat.h
* \author Zhu zhenglu <zhuzlu@gmail.com>
* \brief Application interface for the BAT decoder.
*
* Application interface for the BAT decoder. New
* decoded BAT 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 service description list is empty and should
* be caught from the previous structure.
* This is a simulation to sdt.h
*/
#ifndef _DVBPSI_BAT_H_
#define _DVBPSI_BAT_H_
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
* dvbpsi_bat_ts_t
*****************************************************************************/
/*!
* \struct dvbpsi_bat_ts_s
* \brief BAT transport stream description structure.
*
* This structure is used to store a decoded BAT service description.
* (ETSI EN 300 468 V1.5.1 section 5.2.2).
*/
/*!
* \typedef struct dvbpsi_bat_ts_s dvbpsi_bat_ts_t
* \brief dvbpsi_bat_ts_t type definition.
*/
typedef struct dvbpsi_bat_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_bat_ts_s * p_next; /*!< next element of
the list */
} dvbpsi_bat_ts_t;
/*****************************************************************************
* dvbpsi_bat_t
*****************************************************************************/
/*!
* \struct dvbpsi_bat_s
* \brief BAT structure.
*
* This structure is used to store a decoded BAT.
* (ETSI EN 300 468 V1.5.1 section 5.2.2).
*/
/*!
* \typedef struct dvbpsi_bat_s dvbpsi_bat_t
* \brief dvbpsi_bat_t type definition.
*/
typedef struct dvbpsi_bat_s
{
uint16_t i_bouquet_id; /*!< bouquet_id */
uint8_t i_version; /*!< version_number */
int b_current_next; /*!< current_next_indicator */
dvbpsi_descriptor_t * p_first_descriptor; /*!< descriptor list */
dvbpsi_bat_ts_t * p_first_ts; /*!< transport stream description
list */
} dvbpsi_bat_t;
/*****************************************************************************
* dvbpsi_bat_callback
*****************************************************************************/
/*!
* \typedef void (* dvbpsi_bat_callback)(void* p_cb_data,
dvbpsi_bat_t* p_new_bat)
* \brief Callback type definition.
*/
typedef void (* dvbpsi_bat_callback)(void* p_cb_data, dvbpsi_bat_t* p_new_bat);
/*****************************************************************************
* dvbpsi_AttachBAT
*****************************************************************************/
/*!
* \fn void dvbpsi_AttachBAT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
uint16_t i_extension, dvbpsi_bat_callback pf_callback,
void* p_cb_data)
* \brief Creation and initialization of a BAT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0x4a.
* \param i_extension Table ID extension, here bouquet ID.
* \param pf_callback function to call back on new BAT.
* \param p_cb_data private data given in argument to the callback.
* \return 0 if everything went ok.
*/
int dvbpsi_AttachBAT(dvbpsi_decoder_t * p_psi_decoder, uint8_t i_table_id,
uint16_t i_extension, dvbpsi_bat_callback pf_callback,
void* p_cb_data);
/*****************************************************************************
* dvbpsi_DetachBAT
*****************************************************************************/
/*!
* \fn void dvbpsi_DetachBAT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
uint16_t i_extension)
* \brief Destroy a BAT decoder.
* \param p_demux Subtable demultiplexor to which the decoder is attached.
* \param i_table_id Table ID, 0x4a.
* \param i_extension Table ID extension, here bouquet ID.
* \return nothing.
*/
void dvbpsi_DetachBAT(dvbpsi_demux_t * p_demux, uint8_t i_table_id,
uint16_t i_extension);
/*****************************************************************************
* dvbpsi_InitBAT/dvbpsi_NewBAT
*****************************************************************************/
/*!
* \fn void dvbpsi_InitBAT(dvbpsi_bat_t *p_bat, uint16_t i_bouquet_id, uint8_t i_version,
int b_current_next)
* \brief Initialize a user-allocated dvbpsi_bat_t structure.
* \param p_bat pointer to the BAT structure
* \param i_bouquet_id bouquet ID
* \param i_version BAT version
* \param b_current_next current next indicator
* \param i_network_id original network id
* \return nothing.
*/
void dvbpsi_InitBAT(dvbpsi_bat_t *p_bat, uint16_t i_bouquet_id, uint8_t i_version,
int b_current_next);
/*!
* \def dvbpsi_NewBAT(p_bat, i_bouquet_id, i_version, b_current_next)
* \brief Allocate and initialize a new dvbpsi_bat_t structure.
* \param p_bat pointer to the BAT structure
* \param i_bouquet_id bouquet ID
* \param i_version BAT version
* \param b_current_next current next indicator
* \param i_network_id original network id
* \return nothing.
*/
#define dvbpsi_NewBAT(p_bat, i_bouquet_id, i_version, b_current_next) \
do { \
p_bat = (dvbpsi_bat_t*)malloc(sizeof(dvbpsi_bat_t)); \
if(p_bat != NULL) \
dvbpsi_InitBAT(p_bat, i_bouquet_id, i_version, b_current_next); \
} while(0);
/*****************************************************************************
* dvbpsi_EmptyBAT/dvbpsi_DeleteBAT
*****************************************************************************/
/*!
* \fn void dvbpsi_EmptyBAT(dvbpsi_bat_t* p_bat)
* \brief Clean a dvbpsi_bat_t structure.
* \param p_bat pointer to the BAT structure
* \return nothing.
*/
void dvbpsi_EmptyBAT(dvbpsi_bat_t *p_bat);
/*!
* \def dvbpsi_DeleteBAT(p_bat)
* \brief Clean and free a dvbpsi_bat_t structure.
* \param p_bat pointer to the BAT structure
* \return nothing.
*/
#define dvbpsi_DeleteBAT(p_bat) \
do { \
dvbpsi_EmptyBAT(p_bat); \
free(p_bat); \
} while(0);
/*****************************************************************************
* dvbpsi_GenBATSections
*****************************************************************************
*!
* \fn dvbpsi_psi_section_t* dvbpsi_GenBATSections(dvbpsi_bat_t* p_bat)
* \brief BAT generator
* \param p_bat BAT structure
* \return a pointer to the list of generated PSI sections.
*
* Generate BAT sections based on the dvbpsi_bat_t structure.
*****************************************************************************/
dvbpsi_psi_section_t *dvbpsi_GenBATSections(dvbpsi_bat_t * p_bat);
#ifdef __cplusplus
};
#endif
#else
#error "Multiple inclusions of bat.h"
#endif
/*****************************************************************************
* bat_private.h: private BAT structures
*----------------------------------------------------------------------------
* Copyright (C) 2001-2010 VideoLAN
* $Id: bat_private.h 88 2004-02-24 14:31:18Z sam $
*
* Authors: Zhu zhenglu <zhuzlu@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
*----------------------------------------------------------------------------
*
*****************************************************************************/
#ifndef _DVBPSI_BAT_PRIVATE_H_
#define _DVBPSI_BAT_PRIVATE_H_
/*****************************************************************************
* dvbpsi_bat_decoder_t
*****************************************************************************
* BAT decoder.
*****************************************************************************/
typedef struct dvbpsi_bat_decoder_s
{
dvbpsi_bat_callback pf_callback;
void * p_cb_data;
dvbpsi_bat_t current_bat;
dvbpsi_bat_t * p_building_bat;
int b_current_valid;
uint8_t i_last_section_number;
dvbpsi_psi_section_t * ap_sections [256];
} dvbpsi_bat_decoder_t;
/*****************************************************************************
* dvbpsi_GatherBATSections
*****************************************************************************
* Callback for the PSI decoder.
*****************************************************************************/
void dvbpsi_GatherBATSections(dvbpsi_decoder_t* p_psi_decoder,
void* p_private_decoder,
dvbpsi_psi_section_t* p_section);
/*****************************************************************************
* dvbpsi_DecodeBATSections
*****************************************************************************
* BAT decoder.
*****************************************************************************/
void dvbpsi_DecodeBATSections(dvbpsi_bat_t* p_bat,
dvbpsi_psi_section_t* p_section);
/*****************************************************************************
* dvbpsi_BATAddTS
*****************************************************************************
* Add a TS description at the end of the BAT.
*****************************************************************************/
dvbpsi_bat_ts_t *dvbpsi_BATAddTS(dvbpsi_bat_t* p_bat,
uint16_t i_ts_id, uint16_t i_orig_network_id);
/*****************************************************************************
* dvbpsi_BATBouquetAddDescriptor
*****************************************************************************
* Add a descriptor in the BAT Bouquet descriptors (the first loop description),
* which is in the first loop of BAT.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_BATBouquetAddDescriptor(
dvbpsi_bat_t *p_bat,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
/*****************************************************************************
* dvbpsi_BATTSAddDescriptor
*****************************************************************************
* Add a descriptor in the BAT TS descriptors, which is in the second loop of BAT.
*****************************************************************************/
dvbpsi_descriptor_t *dvbpsi_BATTSAddDescriptor(
dvbpsi_bat_ts_t *p_ts,
uint8_t i_tag, uint8_t i_length,
uint8_t *p_data);
#else
#error "Multiple inclusions of bat_private.h"
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment