pmt.c   pmt.c 
/************************************************************************** *** /************************************************************************** ***
* pmt.c: PMT decoder/generator * pmt.c: PMT decoder/generator
*------------------------------------------------------------------------- --- *------------------------------------------------------------------------- ---
* Copyright (C) 2001-2010 VideoLAN * Copyright (C) 2001-2011 VideoLAN
* $Id$ * $Id$
* *
* Authors: Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr> * Authors: Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>
* Jean-Paul Saman <jpsaman@videolan.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
skipping to change at line 31 skipping to change at line 32
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130 1 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130 1 USA
* *
*------------------------------------------------------------------------- --- *------------------------------------------------------------------------- ---
* *
************************************************************************** ***/ ************************************************************************** ***/
#include "config.h" #include "config.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#if defined(HAVE_INTTYPES_H) #if defined(HAVE_INTTYPES_H)
#include <inttypes.h> #include <inttypes.h>
#elif defined(HAVE_STDINT_H) #elif defined(HAVE_STDINT_H)
#include <stdint.h> #include <stdint.h>
#endif #endif
#include <assert.h>
#include "../dvbpsi.h" #include "../dvbpsi.h"
#include "../dvbpsi_private.h" #include "../dvbpsi_private.h"
#include "../psi.h" #include "../psi.h"
#include "../descriptor.h" #include "../descriptor.h"
#include "pmt.h" #include "pmt.h"
#include "pmt_private.h" #include "pmt_private.h"
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_AttachPMT * dvbpsi_pmt_attach
************************************************************************** *** ************************************************************************** ***
* Initialize a PMT decoder and return a handle on it. * Initialize a PMT decoder and return a handle on it.
************************************************************************** ***/ ************************************************************************** ***/
dvbpsi_handle dvbpsi_AttachPMT(uint16_t i_program_number, bool dvbpsi_pmt_attach(dvbpsi_t *p_dvbpsi, uint16_t i_program_number,
dvbpsi_pmt_callback pf_callback, dvbpsi_pmt_callback pf_callback, void* p_cb_data)
void* p_cb_data) {
{ assert(p_dvbpsi);
dvbpsi_handle h_dvbpsi = (dvbpsi_decoder_t*)malloc(sizeof(dvbpsi_decoder_ assert(p_dvbpsi->p_decoder == NULL);
t));
dvbpsi_pmt_decoder_t* p_pmt_decoder;
if(h_dvbpsi == NULL)
return NULL;
p_pmt_decoder = (dvbpsi_pmt_decoder_t*)malloc(sizeof(dvbpsi_pmt_decoder_t
));
if(p_pmt_decoder == NULL)
{
free(h_dvbpsi);
return NULL;
}
/* PSI decoder configuration */
h_dvbpsi->pf_callback = &dvbpsi_GatherPMTSections;
h_dvbpsi->p_private_decoder = p_pmt_decoder;
h_dvbpsi->i_section_max_size = 1024;
/* PSI decoder initial state */
h_dvbpsi->i_continuity_counter = 31;
h_dvbpsi->b_discontinuity = 1;
h_dvbpsi->p_current_section = NULL;
/* PMT decoder configuration */
p_pmt_decoder->i_program_number = i_program_number;
p_pmt_decoder->pf_callback = pf_callback;
p_pmt_decoder->p_cb_data = p_cb_data;
/* PMT decoder initial state */
p_pmt_decoder->b_current_valid = 0;
p_pmt_decoder->p_building_pmt = NULL;
for(unsigned int i = 0; i <= 255; i++)
p_pmt_decoder->ap_sections[i] = NULL;
return h_dvbpsi; dvbpsi_pmt_decoder_t* p_pmt_decoder;
p_pmt_decoder = (dvbpsi_pmt_decoder_t*) dvbpsi_decoder_new(&dvbpsi_pmt_
sections_gather,
1024, true, sizeof(dvbpsi_pmt_d
ecoder_t));
if (p_pmt_decoder == NULL)
return false;
p_dvbpsi->p_decoder = DVBPSI_DECODER(p_pmt_decoder);
/* PMT decoder configuration */
p_pmt_decoder->i_program_number = i_program_number;
p_pmt_decoder->pf_pmt_callback = pf_callback;
p_pmt_decoder->p_cb_data = p_cb_data;
p_pmt_decoder->p_building_pmt = NULL;
return true;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_DetachPMT * dvbpsi_pmt_detach
************************************************************************** *** ************************************************************************** ***
* Close a PMT decoder. The handle isn't valid any more. * Close a PMT decoder. The handle isn't valid any more.
************************************************************************** ***/ ************************************************************************** ***/
void dvbpsi_DetachPMT(dvbpsi_handle h_dvbpsi) void dvbpsi_pmt_detach(dvbpsi_t *p_dvbpsi)
{ {
dvbpsi_pmt_decoder_t* p_pmt_decoder assert(p_dvbpsi);
= (dvbpsi_pmt_decoder_t*)h_dvbpsi->p_private_decode assert(p_dvbpsi->p_decoder);
r;
free(p_pmt_decoder->p_building_pmt);
for(unsigned int i = 0; i <= 255; i++) dvbpsi_pmt_decoder_t* p_pmt_decoder;
{ p_pmt_decoder = (dvbpsi_pmt_decoder_t*)p_dvbpsi->p_decoder;
if(p_pmt_decoder->ap_sections[i]) if (p_pmt_decoder->p_building_pmt)
free(p_pmt_decoder->ap_sections[i]); dvbpsi_pmt_delete(p_pmt_decoder->p_building_pmt);
} p_pmt_decoder->p_building_pmt = NULL;
free(h_dvbpsi->p_private_decoder); dvbpsi_decoder_delete(p_dvbpsi->p_decoder);
if(h_dvbpsi->p_current_section) p_dvbpsi->p_decoder = NULL;
dvbpsi_DeletePSISections(h_dvbpsi->p_current_section);
free(h_dvbpsi);
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_InitPMT * dvbpsi_pmt_init
************************************************************************** *** ************************************************************************** ***
* Initialize a pre-allocated dvbpsi_pmt_t structure. * Initialize a pre-allocated dvbpsi_pmt_t structure.
************************************************************************** ***/ ************************************************************************** ***/
void dvbpsi_InitPMT(dvbpsi_pmt_t* p_pmt, uint16_t i_program_number, void dvbpsi_pmt_init(dvbpsi_pmt_t* p_pmt, uint16_t i_program_number,
uint8_t i_version, int b_current_next, uint16_t i_pcr_p uint8_t i_version, bool b_current_next, uint16_t i_pcr_
id) pid)
{ {
p_pmt->i_program_number = i_program_number; assert(p_pmt);
p_pmt->i_version = i_version;
p_pmt->b_current_next = b_current_next; p_pmt->i_program_number = i_program_number;
p_pmt->i_pcr_pid = i_pcr_pid; p_pmt->i_version = i_version;
p_pmt->p_first_descriptor = NULL; p_pmt->b_current_next = b_current_next;
p_pmt->p_first_es = NULL; p_pmt->i_pcr_pid = i_pcr_pid;
p_pmt->p_first_descriptor = NULL;
p_pmt->p_first_es = NULL;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_EmptyPMT * dvbpsi_pmt_new
**************************************************************************
***
* Allocate and Initialize a new dvbpsi_pmt_t structure.
**************************************************************************
***/
dvbpsi_pmt_t* dvbpsi_pmt_new(uint16_t i_program_number, uint8_t i_version,
bool b_current_next, uint16_t i_pcr_pid)
{
dvbpsi_pmt_t *p_pmt = (dvbpsi_pmt_t*)malloc(sizeof(dvbpsi_pmt_t));
if(p_pmt != NULL)
dvbpsi_pmt_init(p_pmt, i_program_number, i_version,
b_current_next, i_pcr_pid);
return p_pmt;
}
/**************************************************************************
***
* dvbpsi_pmt_empty
************************************************************************** *** ************************************************************************** ***
* Clean a dvbpsi_pmt_t structure. * Clean a dvbpsi_pmt_t structure.
************************************************************************** ***/ ************************************************************************** ***/
void dvbpsi_EmptyPMT(dvbpsi_pmt_t* p_pmt) void dvbpsi_pmt_empty(dvbpsi_pmt_t* p_pmt)
{ {
dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es; dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es;
dvbpsi_DeleteDescriptors(p_pmt->p_first_descriptor); dvbpsi_DeleteDescriptors(p_pmt->p_first_descriptor);
while(p_es != NULL) while(p_es != NULL)
{ {
dvbpsi_pmt_es_t* p_tmp = p_es->p_next; dvbpsi_pmt_es_t* p_tmp = p_es->p_next;
dvbpsi_DeleteDescriptors(p_es->p_first_descriptor); dvbpsi_DeleteDescriptors(p_es->p_first_descriptor);
free(p_es); free(p_es);
p_es = p_tmp; p_es = p_tmp;
} }
p_pmt->p_first_descriptor = NULL; p_pmt->p_first_descriptor = NULL;
p_pmt->p_first_es = NULL; p_pmt->p_first_es = NULL;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_PMTAddDescriptor * dvbpsi_pmt_delete
**************************************************************************
***
* Clean a dvbpsi_pmt_t structure.
**************************************************************************
***/
void dvbpsi_pmt_delete(dvbpsi_pmt_t* p_pmt)
{
if (p_pmt)
dvbpsi_pmt_empty(p_pmt);
free(p_pmt);
}
/**************************************************************************
***
* dvbpsi_pmt_descriptor_add
************************************************************************** *** ************************************************************************** ***
* Add a descriptor in the PMT. * Add a descriptor in the PMT.
************************************************************************** ***/ ************************************************************************** ***/
dvbpsi_descriptor_t* dvbpsi_PMTAddDescriptor(dvbpsi_pmt_t* p_pmt, dvbpsi_descriptor_t* dvbpsi_pmt_descriptor_add(dvbpsi_pmt_t* p_pmt,
uint8_t i_tag, uint8_t i_lengt uint8_t i_tag, uint8_t i_len
h, gth,
uint8_t* p_data) uint8_t* p_data)
{ {
dvbpsi_descriptor_t* p_descriptor dvbpsi_descriptor_t* p_descriptor;
= dvbpsi_NewDescriptor(i_tag, i_length, p_data); p_descriptor = dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if (p_descriptor == NULL)
if(p_descriptor) return NULL;
{
if(p_pmt->p_first_descriptor == NULL) p_pmt->p_first_descriptor = dvbpsi_AddDescriptor(p_pmt->p_first_descrip
{ tor,
p_pmt->p_first_descriptor = p_descriptor; p_descriptor);
} assert(p_pmt->p_first_descriptor);
else if (p_pmt->p_first_descriptor == NULL)
{ return NULL;
dvbpsi_descriptor_t* p_last_descriptor = p_pmt->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; return p_descriptor;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_PMTAddES * dvbpsi_pmt_es_add
************************************************************************** *** ************************************************************************** ***
* Add an ES in the PMT. * Add an ES in the PMT.
************************************************************************** ***/ ************************************************************************** ***/
dvbpsi_pmt_es_t* dvbpsi_PMTAddES(dvbpsi_pmt_t* p_pmt, dvbpsi_pmt_es_t* dvbpsi_pmt_es_add(dvbpsi_pmt_t* p_pmt,
uint8_t i_type, uint16_t i_pid) uint8_t i_type, uint16_t i_pid)
{ {
dvbpsi_pmt_es_t* p_es = (dvbpsi_pmt_es_t*)malloc(sizeof(dvbpsi_pmt_es_t)) dvbpsi_pmt_es_t* p_es = (dvbpsi_pmt_es_t*)malloc(sizeof(dvbpsi_pmt_es_t
; ));
if (p_es == NULL)
return NULL;
if(p_es)
{
p_es->i_type = i_type; p_es->i_type = i_type;
p_es->i_pid = i_pid; p_es->i_pid = i_pid;
p_es->p_first_descriptor = NULL; p_es->p_first_descriptor = NULL;
p_es->p_next = NULL; p_es->p_next = NULL;
if(p_pmt->p_first_es == NULL) if (p_pmt->p_first_es == NULL)
{ p_pmt->p_first_es = p_es;
p_pmt->p_first_es = p_es;
}
else else
{ {
dvbpsi_pmt_es_t* p_last_es = p_pmt->p_first_es; dvbpsi_pmt_es_t* p_last_es = p_pmt->p_first_es;
while(p_last_es->p_next != NULL) while (p_last_es->p_next != NULL)
p_last_es = p_last_es->p_next; p_last_es = p_last_es->p_next;
p_last_es->p_next = p_es; p_last_es->p_next = p_es;
} }
} return p_es;
return p_es;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_PMTESAddDescriptor * dvbpsi_pmt_es_descriptor_add
************************************************************************** *** ************************************************************************** ***
* Add a descriptor in the PMT ES. * Add a descriptor in the PMT ES.
************************************************************************** ***/ ************************************************************************** ***/
dvbpsi_descriptor_t* dvbpsi_PMTESAddDescriptor(dvbpsi_pmt_es_t* p_es, dvbpsi_descriptor_t* dvbpsi_pmt_es_descriptor_add(dvbpsi_pmt_es_t* p_es,
uint8_t i_tag, uint8_t i_len gth, uint8_t i_tag, uint8_t i_len gth,
uint8_t* p_data) uint8_t* p_data)
{ {
dvbpsi_descriptor_t* p_descriptor dvbpsi_descriptor_t* p_descriptor;
= dvbpsi_NewDescriptor(i_tag, i_length, p_data); p_descriptor = dvbpsi_NewDescriptor(i_tag, i_length, p_data);
if (p_descriptor == NULL)
return NULL;
if(p_descriptor) if (p_es->p_first_descriptor == NULL)
{ p_es->p_first_descriptor = p_descriptor;
if(p_es->p_first_descriptor == NULL) else
{ {
p_es->p_first_descriptor = p_descriptor; dvbpsi_descriptor_t* p_last_descriptor = p_es->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;
} }
else return p_descriptor;
}
/* */
static void dvbpsi_ReInitPMT(dvbpsi_pmt_decoder_t* p_decoder, const bool b_
force)
{
assert(p_decoder);
dvbpsi_decoder_reset(DVBPSI_DECODER(p_decoder), b_force);
/* Force redecoding */
if (b_force)
{
/* Free structures */
if (p_decoder->p_building_pmt)
dvbpsi_pmt_delete(p_decoder->p_building_pmt);
}
p_decoder->p_building_pmt = NULL;
}
static bool dvbpsi_CheckPMT(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t *p_sec
tion)
{
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_numb
er)
{ {
dvbpsi_descriptor_t* p_last_descriptor = p_es->p_first_descriptor; /* last_section_number */
while(p_last_descriptor->p_next != NULL) dvbpsi_error(p_dvbpsi, "PMT decoder",
p_last_descriptor = p_last_descriptor->p_next; "'last_section_number' differs"
p_last_descriptor->p_next = p_descriptor; " whereas no discontinuity has occured");
b_reinit = true;
} }
}
return p_descriptor; return b_reinit;
}
static bool dvbpsi_AddSectionPMT(dvbpsi_t *p_dvbpsi, dvbpsi_pmt_decoder_t *
p_pmt_decoder,
dvbpsi_psi_section_t* p_section)
{
assert(p_dvbpsi);
assert(p_pmt_decoder);
assert(p_section);
/* Initialize the structures if it's the first section received */
if (p_pmt_decoder->p_building_pmt == NULL)
{
p_pmt_decoder->p_building_pmt = dvbpsi_pmt_new(p_pmt_decoder->i_pro
gram_number,
p_section->i_version, p_section->b_current_ne
xt,
((uint16_t)(p_section->p_payload_start[0] & 0
x1f) << 8)
| p_section->p_payload_start[1]);
if (p_pmt_decoder->p_building_pmt == NULL)
return false;
p_pmt_decoder->i_last_section_number = p_section->i_last_number;
}
/* Add to linked list of sections */
if (dvbpsi_decoder_psi_section_add(DVBPSI_DECODER(p_pmt_decoder), p_sec
tion))
dvbpsi_debug(p_dvbpsi, "PMT decoder", "overwrite section number %d"
,
p_section->i_number);
return true;
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_GatherPMTSections * dvbpsi_GatherPMTSections
************************************************************************** *** ************************************************************************** ***
* Callback for the PSI decoder. * Callback for the PSI decoder.
************************************************************************** ***/ ************************************************************************** ***/
void dvbpsi_GatherPMTSections(dvbpsi_decoder_t* p_decoder, void dvbpsi_pmt_sections_gather(dvbpsi_t *p_dvbpsi, dvbpsi_psi_section_t* p
dvbpsi_psi_section_t* p_section) _section)
{ {
dvbpsi_pmt_decoder_t* p_pmt_decoder assert(p_dvbpsi);
= (dvbpsi_pmt_decoder_t*)p_decoder->p_private_decod assert(p_dvbpsi->p_decoder);
er;
int b_append = 1; if (!dvbpsi_CheckPSISection(p_dvbpsi, p_section, 0x02, "PMT decoder"))
int b_reinit = 0; {
dvbpsi_DeletePSISections(p_section);
DVBPSI_DEBUG_ARG("PMT decoder", return;
"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, dvbpsi_pmt_decoder_t* p_pmt_decoder = (dvbpsi_pmt_decoder_t*)p_dvbpsi->
p_section->b_current_next); p_decoder;
assert(p_pmt_decoder);
if(p_section->i_table_id != 0x02)
{ /* We have a valid PMT section */
/* Invalid table_id value */ if (p_pmt_decoder->i_program_number != p_section->i_extension)
DVBPSI_ERROR_ARG("PMT decoder", {
"invalid section (table_id == 0x%02x)", /* Invalid program_number */
p_section->i_table_id); dvbpsi_error(p_dvbpsi, "PMT decoder", "'program_number' don't match
b_append = 0; ");
} dvbpsi_DeletePSISections(p_section);
return;
if(b_append && !p_section->b_syntax_indicator) }
{
/* Invalid section_syntax_indicator */
DVBPSI_ERROR("PMT decoder",
"invalid section (section_syntax_indicator == 0)");
b_append = 0;
}
/* Now if b_append is true then we have a valid PMT section */
if(b_append && (p_pmt_decoder->i_program_number != p_section->i_extension
))
{
/* Invalid program_number */
#if 0
DVBPSI_ERROR("PMT decoder", \
"'program_number' don't match");
#endif
b_append = 0;
}
if(b_append)
{
/* TS discontinuity check */ /* TS discontinuity check */
if(p_decoder->b_discontinuity) if (p_pmt_decoder->b_discontinuity)
{ {
b_reinit = 1; dvbpsi_ReInitPMT(p_pmt_decoder, true);
p_decoder->b_discontinuity = 0; p_pmt_decoder->b_discontinuity = false;
} }
else else
{ {
/* Perform some few sanity checks */ /* Perform some few sanity checks */
if(p_pmt_decoder->p_building_pmt) if (p_pmt_decoder->p_building_pmt)
{
if(p_pmt_decoder->p_building_pmt->i_version != p_section->i_version
)
{ {
/* version_number */ if (dvbpsi_CheckPMT(p_dvbpsi, p_section))
DVBPSI_ERROR("PMT decoder", dvbpsi_ReInitPMT(p_pmt_decoder, true);
"'version_number' differs"
" whereas no discontinuity has occured");
b_reinit = 1;
} }
else if(p_pmt_decoder->i_last_section_number else
!= p_section->i_last_number
)
{ {
/* last_section_number */ if( (p_pmt_decoder->b_current_valid)
DVBPSI_ERROR("PMT decoder", && (p_pmt_decoder->current_pmt.i_version == p_section->i_ve
"'last_section_number' differs" rsion)
" whereas no discontinuity has occured"); && (p_pmt_decoder->current_pmt.b_current_next ==
b_reinit = 1; 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;
}
} }
}
else
{
if( (p_pmt_decoder->b_current_valid)
&& (p_pmt_decoder->current_pmt.i_version == p_section->i_versio
n)
&& (p_pmt_decoder->current_pmt.b_current_next ==
p_section->b_current_next))
{
/* Don't decode since this version is already decoded */
b_append = 0;
}
}
} }
}
/* Reinit the decoder if wanted */
if(b_reinit)
{
/* Force redecoding */
p_pmt_decoder->b_current_valid = 0;
/* Free structures */
if(p_pmt_decoder->p_building_pmt)
{
free(p_pmt_decoder->p_building_pmt);
p_pmt_decoder->p_building_pmt = NULL;
}
/* Clear the section array */
for(unsigned int i = 0; i <= 255; i++)
{
if(p_pmt_decoder->ap_sections[i] != NULL)
{
dvbpsi_DeletePSISections(p_pmt_decoder->ap_sections[i]);
p_pmt_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 */ /* Add section to PMT */
if(!p_pmt_decoder->p_building_pmt) if (!dvbpsi_AddSectionPMT(p_dvbpsi, p_pmt_decoder, p_section))
{ {
p_pmt_decoder->p_building_pmt = dvbpsi_error(p_dvbpsi, "PMT decoder", "failed decoding section %d",
(dvbpsi_pmt_t*)malloc(sizeof(dvbpsi_pmt_t)) p_section->i_number);
; dvbpsi_DeletePSISections(p_section);
dvbpsi_InitPMT(p_pmt_decoder->p_building_pmt, return;
p_pmt_decoder->i_program_number, }
p_section->i_version,
p_section->b_current_next, if (dvbpsi_decoder_psi_sections_completed(DVBPSI_DECODER(p_pmt_decoder)
((uint16_t)(p_section->p_payload_start[0] & 0x1f) << ))
8) {
| p_section->p_payload_start[1]); assert(p_pmt_decoder->pf_pmt_callback);
p_pmt_decoder->i_last_section_number = p_section->i_last_number;
} /* Save the current information */
p_pmt_decoder->current_pmt = *p_pmt_decoder->p_building_pmt;
/* Fill the section array */ p_pmt_decoder->b_current_valid = true;
if(p_pmt_decoder->ap_sections[p_section->i_number] != NULL) /* Decode the sections */
{ dvbpsi_pmt_sections_decode(p_pmt_decoder->p_building_pmt,
DVBPSI_DEBUG_ARG("PMT decoder", "overwrite section number %d", p_pmt_decoder->p_sections);
p_section->i_number); /* Delete the sections */
dvbpsi_DeletePSISections(p_pmt_decoder->ap_sections[p_section->i_numb dvbpsi_DeletePSISections(p_pmt_decoder->p_sections);
er]); p_pmt_decoder->p_sections = NULL;
} /* signal the new PMT */
p_pmt_decoder->ap_sections[p_section->i_number] = p_section; p_pmt_decoder->pf_pmt_callback(p_pmt_decoder->p_cb_data,
p_pmt_decoder->p_building_pmt);
/* Check if we have all the sections */ /* Reinitialize the structures */
b_complete = 0; dvbpsi_ReInitPMT(p_pmt_decoder, false);
for(unsigned int i = 0; i <= p_pmt_decoder->i_last_section_number; i++) }
{
if(!p_pmt_decoder->ap_sections[i])
break;
if(i == p_pmt_decoder->i_last_section_number)
b_complete = 1;
}
if(b_complete)
{
/* Save the current information */
p_pmt_decoder->current_pmt = *p_pmt_decoder->p_building_pmt;
p_pmt_decoder->b_current_valid = 1;
/* Chain the sections */
if(p_pmt_decoder->i_last_section_number)
{
for(unsigned int i = 0; (int)i <= p_pmt_decoder->i_last_section_num
ber - 1; i++)
p_pmt_decoder->ap_sections[i]->p_next =
p_pmt_decoder->ap_sections[i + 1];
}
/* Decode the sections */
dvbpsi_DecodePMTSections(p_pmt_decoder->p_building_pmt,
p_pmt_decoder->ap_sections[0]);
/* Delete the sections */
dvbpsi_DeletePSISections(p_pmt_decoder->ap_sections[0]);
/* signal the new PMT */
p_pmt_decoder->pf_callback(p_pmt_decoder->p_cb_data,
p_pmt_decoder->p_building_pmt);
/* Reinitialize the structures */
p_pmt_decoder->p_building_pmt = NULL;
for(unsigned int i = 0; i <= p_pmt_decoder->i_last_section_number; i+
+)
p_pmt_decoder->ap_sections[i] = NULL;
}
}
else
{
dvbpsi_DeletePSISections(p_section);
}
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_DecodePMTSections * dvbpsi_pmt_sections_decode
************************************************************************** *** ************************************************************************** ***
* PMT decoder. * PMT decoder.
************************************************************************** ***/ ************************************************************************** ***/
void dvbpsi_DecodePMTSections(dvbpsi_pmt_t* p_pmt, void dvbpsi_pmt_sections_decode(dvbpsi_pmt_t* p_pmt,
dvbpsi_psi_section_t* p_section) dvbpsi_psi_section_t* p_section)
{ {
uint8_t* p_byte, * p_end; uint8_t* p_byte, * p_end;
while(p_section) while (p_section)
{ {
/* - PMT descriptors */ /* - PMT descriptors */
p_byte = p_section->p_payload_start + 4; p_byte = p_section->p_payload_start + 4;
p_end = p_byte + ( ((uint16_t)(p_section->p_payload_start[2] & 0x0f) p_end = p_byte + ( ((uint16_t)(p_section->p_payload_start[2] & 0x
<< 8) 0f) << 8)
| p_section->p_payload_start[3]); | p_section->p_payload_start[3]);
while(p_byte + 2 <= p_end) while (p_byte + 2 <= p_end)
{ {
uint8_t i_tag = p_byte[0]; uint8_t i_tag = p_byte[0];
uint8_t i_length = p_byte[1]; uint8_t i_length = p_byte[1];
if(i_length + 2 <= p_end - p_byte) if (i_length + 2 <= p_end - p_byte)
dvbpsi_PMTAddDescriptor(p_pmt, i_tag, i_length, p_byte + 2); dvbpsi_pmt_descriptor_add(p_pmt, i_tag, i_length, p_byte +
p_byte += 2 + i_length; 2);
} p_byte += 2 + i_length;
}
/* - ESs */
for(p_byte = p_end; p_byte + 5 <= p_section->p_payload_end;)
{
uint8_t i_type = p_byte[0];
uint16_t i_pid = ((uint16_t)(p_byte[1] & 0x1f) << 8) | p_byte[2];
uint16_t i_es_length = ((uint16_t)(p_byte[3] & 0x0f) << 8) | p_byte[4
];
dvbpsi_pmt_es_t* p_es = dvbpsi_PMTAddES(p_pmt, i_type, i_pid);
/* - ES descriptors */
p_byte += 5;
p_end = p_byte + i_es_length;
if( p_end > p_section->p_payload_end )
{
p_end = p_section->p_payload_end;
}
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_PMTESAddDescriptor(p_es, i_tag, i_length, p_byte + 2);
p_byte += 2 + i_length;
}
}
p_section = p_section->p_next; /* - ESs */
} for (p_byte = p_end; p_byte + 5 <= p_section->p_payload_end;)
{
uint8_t i_type = p_byte[0];
uint16_t i_pid = ((uint16_t)(p_byte[1] & 0x1f) << 8) | p_byte[2
];
uint16_t i_es_length = ((uint16_t)(p_byte[3] & 0x0f) << 8) | p_
byte[4];
dvbpsi_pmt_es_t* p_es = dvbpsi_pmt_es_add(p_pmt, i_type, i_pid)
;
/* - ES descriptors */
p_byte += 5;
p_end = p_byte + i_es_length;
if (p_end > p_section->p_payload_end)
{
p_end = p_section->p_payload_end;
}
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_pmt_es_descriptor_add(p_es, i_tag, i_length, p_b
yte + 2);
p_byte += 2 + i_length;
}
}
p_section = p_section->p_next;
}
} }
/************************************************************************** *** /************************************************************************** ***
* dvbpsi_GenPMTSections * dvbpsi_pmt_sections_generate
************************************************************************** *** ************************************************************************** ***
* Generate PMT sections based on the dvbpsi_pmt_t structure. * Generate PMT sections based on the dvbpsi_pmt_t structure.
************************************************************************** ***/ ************************************************************************** ***/
dvbpsi_psi_section_t* dvbpsi_GenPMTSections(dvbpsi_pmt_t* p_pmt) dvbpsi_psi_section_t* dvbpsi_pmt_sections_generate(dvbpsi_t *p_dvbpsi, dvbp si_pmt_t* p_pmt)
{ {
dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024); dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024);
dvbpsi_psi_section_t* p_current = p_result; dvbpsi_psi_section_t* p_current = p_result;
dvbpsi_psi_section_t* p_prev; dvbpsi_psi_section_t* p_prev;
dvbpsi_descriptor_t* p_descriptor = p_pmt->p_first_descriptor; dvbpsi_descriptor_t* p_descriptor = p_pmt->p_first_descriptor;
dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es; dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es;
uint16_t i_info_length; uint16_t i_info_length;
p_current->i_table_id = 0x02; p_current->i_table_id = 0x02;
p_current->b_syntax_indicator = 1; p_current->b_syntax_indicator = true;
p_current->b_private_indicator = 0; p_current->b_private_indicator = false;
p_current->i_length = 13; /* header + CRC_32 */ p_current->i_length = 13; /* header + CRC_32 */
p_current->i_extension = p_pmt->i_program_number; p_current->i_extension = p_pmt->i_program_number;
p_current->i_version = p_pmt->i_version; p_current->i_version = p_pmt->i_version;
p_current->b_current_next = p_pmt->b_current_next; p_current->b_current_next = p_pmt->b_current_next;
p_current->i_number = 0; p_current->i_number = 0;
p_current->p_payload_end += 12; /* just after the header */ p_current->p_payload_end += 12; /* just after the header
p_current->p_payload_start = p_current->p_data + 8; */
p_current->p_payload_start = p_current->p_data + 8;
/* PCR_PID */
p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0; /* PCR_PID */
p_current->p_data[9] = p_pmt->i_pcr_pid; p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0;
p_current->p_data[9] = p_pmt->i_pcr_pid;
/* PMT descriptors */
while(p_descriptor != NULL) /* PMT descriptors */
{ while (p_descriptor != NULL)
/* New section if needed */ {
/* written_data_length + descriptor_length + 2 > 1024 - CRC_32_length * /* New section if needed */
/ /* written_data_length + descriptor_length + 2 > 1024 - CRC_32_leng
if( (p_current->p_payload_end - p_current->p_data) th */
+ p_descriptor->i_length > 1018) if ((p_current->p_payload_end - p_current->p_data)
{ + p_descriptor->i_length > 1018)
/* program_info_length */ {
i_info_length = (p_current->p_payload_end - p_current->p_data) - 12; /* program_info_length */
p_current->p_data[10] = (i_info_length >> 8) | 0xf0; i_info_length = (p_current->p_payload_end - p_current->p_data)
p_current->p_data[11] = i_info_length; - 12;
p_current->p_data[10] = (i_info_length >> 8) | 0xf0;
p_prev = p_current; p_current->p_data[11] = i_info_length;
p_current = dvbpsi_NewPSISection(1024);
p_prev->p_next = p_current; p_prev = p_current;
p_current = dvbpsi_NewPSISection(1024);
p_current->i_table_id = 0x02; p_prev->p_next = p_current;
p_current->b_syntax_indicator = 1;
p_current->b_private_indicator = 0; p_current->i_table_id = 0x02;
p_current->i_length = 13; /* header + CRC_32 */ p_current->b_syntax_indicator = true;
p_current->i_extension = p_pmt->i_program_number; p_current->b_private_indicator = false;
p_current->i_version = p_pmt->i_version; p_current->i_length = 13; /* header + CRC_32 */
p_current->b_current_next = p_pmt->b_current_next; p_current->i_extension = p_pmt->i_program_number;
p_current->i_number = p_prev->i_number + 1; p_current->i_version = p_pmt->i_version;
p_current->p_payload_end += 12; /* just after the header */ p_current->b_current_next = p_pmt->b_current_next;
p_current->p_payload_start = p_current->p_data + 8; p_current->i_number = p_prev->i_number + 1;
p_current->p_payload_end += 12; /* just after the hea
/* PCR_PID */ der */
p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0; p_current->p_payload_start = p_current->p_data + 8;
p_current->p_data[9] = p_pmt->i_pcr_pid;
} /* PCR_PID */
p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0;
/* p_payload_end is where the descriptor begins */ p_current->p_data[9] = p_pmt->i_pcr_pid;
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_payload_end is where the descriptor begins */
p_descriptor->p_data, p_current->p_payload_end[0] = p_descriptor->i_tag;
p_descriptor->i_length); p_current->p_payload_end[1] = p_descriptor->i_length;
memcpy(p_current->p_payload_end + 2,
/* Increase length by descriptor_length + 2 */ p_descriptor->p_data,
p_current->p_payload_end += p_descriptor->i_length + 2; p_descriptor->i_length);
p_current->i_length += p_descriptor->i_length + 2;
/* Increase length by descriptor_length + 2 */
p_descriptor = p_descriptor->p_next; p_current->p_payload_end += p_descriptor->i_length + 2;
} p_current->i_length += p_descriptor->i_length + 2;
/* program_info_length */ p_descriptor = p_descriptor->p_next;
i_info_length = (p_current->p_payload_end - p_current->p_data) - 12; }
p_current->p_data[10] = (i_info_length >> 8) | 0xf0;
p_current->p_data[11] = i_info_length; /* program_info_length */
i_info_length = (p_current->p_payload_end - p_current->p_data) - 12;
/* PMT ESs */ p_current->p_data[10] = (i_info_length >> 8) | 0xf0;
while(p_es != NULL) p_current->p_data[11] = i_info_length;
{
uint8_t* p_es_start = p_current->p_payload_end; /* PMT ESs */
uint16_t i_es_length = 5; while (p_es != NULL)
{
/* Can the current section carry all the descriptors ? */ uint8_t* p_es_start = p_current->p_payload_end;
p_descriptor = p_es->p_first_descriptor; uint16_t i_es_length = 5;
while( (p_descriptor != NULL)
&& ((p_es_start - p_current->p_data) + i_es_length <= 1020)) /* Can the current section carry all the descriptors ? */
{ p_descriptor = p_es->p_first_descriptor;
i_es_length += p_descriptor->i_length + 2; while( (p_descriptor != NULL)
p_descriptor = p_descriptor->p_next; && ((p_es_start - p_current->p_data) + i_es_length <= 1020))
} {
i_es_length += p_descriptor->i_length + 2;
/* If _no_ and the current section isn't empty and an empty section p_descriptor = p_descriptor->p_next;
may carry one more descriptor }
then create a new section */
if( (p_descriptor != NULL) /* If _no_ and the current section isn't empty and an empty section
&& (p_es_start - p_current->p_data != 12) may carry one more descriptor
&& (i_es_length <= 1008)) then create a new section */
{ if( (p_descriptor != NULL)
/* will put more descriptors in an empty section */ && (p_es_start - p_current->p_data != 12)
DVBPSI_DEBUG("PMT generator", && (i_es_length <= 1008))
"create a new section to carry more ES descriptors"); {
p_prev = p_current; /* will put more descriptors in an empty section */
p_current = dvbpsi_NewPSISection(1024); dvbpsi_debug(p_dvbpsi, "PMT generator",
p_prev->p_next = p_current; "create a new section to carry more ES descriptors
");
p_current->i_table_id = 0x02;
p_current->b_syntax_indicator = 1; p_prev = p_current;
p_current->b_private_indicator = 0; p_current = dvbpsi_NewPSISection(1024);
p_current->i_length = 13; /* header + CRC_32 */ p_prev->p_next = p_current;
p_current->i_extension = p_pmt->i_program_number;
p_current->i_version = p_pmt->i_version; p_current->i_table_id = 0x02;
p_current->b_current_next = p_pmt->b_current_next; p_current->b_syntax_indicator = true;
p_current->i_number = p_prev->i_number + 1; p_current->b_private_indicator = false;
p_current->p_payload_end += 12; /* just after the header */ p_current->i_length = 13; /* header + CRC_32 */
p_current->p_payload_start = p_current->p_data + 8; p_current->i_extension = p_pmt->i_program_number;
p_current->i_version = p_pmt->i_version;
/* PCR_PID */ p_current->b_current_next = p_pmt->b_current_next;
p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0; p_current->i_number = p_prev->i_number + 1;
p_current->p_data[9] = p_pmt->i_pcr_pid; p_current->p_payload_end += 12; /* just after the hea
der */
/* program_info_length */ p_current->p_payload_start = p_current->p_data + 8;
i_info_length = 0;
p_current->p_data[10] = 0xf0; /* PCR_PID */
p_current->p_data[11] = 0x00; p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0;
p_current->p_data[9] = p_pmt->i_pcr_pid;
p_es_start = p_current->p_payload_end;
} /* program_info_length */
i_info_length = 0;
/* p_es_start is where the ES begins */ p_current->p_data[10] = 0xf0;
p_es_start[0] = p_es->i_type; p_current->p_data[11] = 0x00;
p_es_start[1] = (p_es->i_pid >> 8) | 0xe0;
p_es_start[2] = p_es->i_pid; p_es_start = p_current->p_payload_end;
}
/* Increase the length by 5 */
p_current->p_payload_end += 5; /* p_es_start is where the ES begins */
p_current->i_length += 5; p_es_start[0] = p_es->i_type;
p_es_start[1] = (p_es->i_pid >> 8) | 0xe0;
/* ES descriptors */ p_es_start[2] = p_es->i_pid;
p_descriptor = p_es->p_first_descriptor;
while( (p_descriptor != NULL) /* Increase the length by 5 */
&& ( (p_current->p_payload_end - p_current->p_data) p_current->p_payload_end += 5;
+ p_descriptor->i_length <= 1018)) p_current->i_length += 5;
{
/* p_payload_end is where the descriptor begins */ /* ES descriptors */
p_current->p_payload_end[0] = p_descriptor->i_tag; p_descriptor = p_es->p_first_descriptor;
p_current->p_payload_end[1] = p_descriptor->i_length; while( (p_descriptor != NULL)
memcpy(p_current->p_payload_end + 2, && ( (p_current->p_payload_end - p_current->p_data)
p_descriptor->p_data, + p_descriptor->i_length <= 1018))
p_descriptor->i_length); {
/* p_payload_end is where the descriptor begins */
/* Increase length by descriptor_length + 2 */ p_current->p_payload_end[0] = p_descriptor->i_tag;
p_current->p_payload_end += p_descriptor->i_length + 2; p_current->p_payload_end[1] = p_descriptor->i_length;
p_current->i_length += p_descriptor->i_length + 2; memcpy(p_current->p_payload_end + 2,
p_descriptor->p_data,
p_descriptor = p_descriptor->p_next; p_descriptor->i_length);
}
/* Increase length by descriptor_length + 2 */
if(p_descriptor != NULL) p_current->p_payload_end += p_descriptor->i_length + 2;
DVBPSI_ERROR("PMT generator", "unable to carry all the ES descriptors p_current->i_length += p_descriptor->i_length + 2;
");
p_descriptor = p_descriptor->p_next;
/* ES_info_length */ }
i_es_length = p_current->p_payload_end - p_es_start - 5;
p_es_start[3] = (i_es_length >> 8) | 0xf0; if (p_descriptor != NULL)
p_es_start[4] = i_es_length; dvbpsi_error(p_dvbpsi, "PMT generator", "unable to carry all th
e ES descriptors");
p_es = p_es->p_next;
} /* ES_info_length */
i_es_length = p_current->p_payload_end - p_es_start - 5;
/* Finalization */ p_es_start[3] = (i_es_length >> 8) | 0xf0;
p_prev = p_result; p_es_start[4] = i_es_length;
while(p_prev != NULL)
{ p_es = p_es->p_next;
p_prev->i_last_number = p_current->i_number; }
dvbpsi_BuildPSISection(p_prev);
p_prev = p_prev->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; return p_result;
} }
 End of changes. 62 change blocks. 
537 lines changed or deleted 530 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/