dvbpsi.c | dvbpsi.c | |||
---|---|---|---|---|
/************************************************************************** *** | /************************************************************************** *** | |||
* dvbpsi.c: conversion from TS packets to PSI sections | * dvbpsi.c: conversion from TS packets to PSI sections | |||
*------------------------------------------------------------------------- --- | *------------------------------------------------------------------------- --- | |||
* Copyright (C) 2001-2010 VideoLAN | * Copyright (C) 2001-2012 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 <string.h> | #include <string.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdarg.h> | ||||
#include <stdlib.h> | ||||
#include <stdbool.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" | |||
/************************************************************************** *** | /************************************************************************** *** | |||
* dvbpsi_crc32_table | * dvbpsi_crc32_table | |||
************************************************************************** *** | ************************************************************************** *** | |||
* This table is used to compute a PSI CRC byte per byte instead of bit per | * This table is used to compute a PSI CRC byte per byte instead of bit per | |||
* bit. It's been generated by 'gen_crc' in the 'misc' directory: | * bit. It's been generated by 'gen_crc' in the 'misc' directory: | |||
* | * | |||
skipping to change at line 138 | skipping to change at line 144 | |||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, | 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, | |||
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, | 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, | |||
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, | 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, | |||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, | 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, | |||
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, | 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, | |||
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, | 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, | |||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 | 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 | |||
}; | }; | |||
/************************************************************************** *** | /************************************************************************** *** | |||
* dvbpsi_PushPacket | * dvbpsi_new | |||
************************************************************************** | ||||
***/ | ||||
dvbpsi_t *dvbpsi_new(dvbpsi_message_cb callback, enum dvbpsi_msg_level leve | ||||
l) | ||||
{ | ||||
dvbpsi_t *p_dvbpsi = calloc(1, sizeof(dvbpsi_t)); | ||||
if (p_dvbpsi == NULL) | ||||
return NULL; | ||||
p_dvbpsi->p_decoder = NULL; | ||||
p_dvbpsi->pf_message = callback; | ||||
p_dvbpsi->i_msg_level = level; | ||||
return p_dvbpsi; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_delete | ||||
************************************************************************** | ||||
***/ | ||||
void dvbpsi_delete(dvbpsi_t *p_dvbpsi) | ||||
{ | ||||
assert(p_dvbpsi->p_decoder == NULL); | ||||
if (p_dvbpsi) | ||||
p_dvbpsi->pf_message = NULL; | ||||
free(p_dvbpsi); | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_new | ||||
************************************************************************** | ||||
***/ | ||||
#define DVBPSI_INVALID_CC (0xFF) | ||||
void *dvbpsi_decoder_new(dvbpsi_callback_gather_t pf_gather, | ||||
const int i_section_max_size, const bool b_discontinuity, const size_t | ||||
psi_size) | ||||
{ | ||||
assert(psi_size >= sizeof(dvbpsi_decoder_t)); | ||||
dvbpsi_decoder_t *p_decoder = (dvbpsi_decoder_t *) calloc(1, psi_size); | ||||
if (p_decoder == NULL) | ||||
return NULL; | ||||
memcpy(&p_decoder->i_magic[0], "psi", 3); | ||||
p_decoder->pf_gather = pf_gather; | ||||
p_decoder->p_current_section = NULL; | ||||
p_decoder->i_section_max_size = i_section_max_size; | ||||
p_decoder->b_discontinuity = b_discontinuity; | ||||
p_decoder->i_continuity_counter = DVBPSI_INVALID_CC; | ||||
p_decoder->p_current_section = NULL; | ||||
p_decoder->b_current_valid = false; | ||||
p_decoder->i_last_section_number = 0; | ||||
p_decoder->p_sections = NULL; | ||||
p_decoder->b_complete_header = false; | ||||
return p_decoder; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_reset | ||||
************************************************************************** | ||||
***/ | ||||
void dvbpsi_decoder_reset(dvbpsi_decoder_t* p_decoder, const bool b_force) | ||||
{ | ||||
assert(p_decoder); | ||||
/* Force redecoding */ | ||||
if (b_force) | ||||
p_decoder->b_current_valid = false; | ||||
/* Clear the section array */ | ||||
dvbpsi_DeletePSISections(p_decoder->p_sections); | ||||
p_decoder->p_sections = NULL; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_psi_sections_completed | ||||
************************************************************************** | ||||
***/ | ||||
bool dvbpsi_decoder_psi_sections_completed(dvbpsi_decoder_t* p_decoder) | ||||
{ | ||||
assert(p_decoder); | ||||
bool b_complete = false; | ||||
dvbpsi_psi_section_t *p = p_decoder->p_sections; | ||||
unsigned int prev_nr = 0; | ||||
while (p) | ||||
{ | ||||
assert(prev_nr < 256); | ||||
if (prev_nr != p->i_number) | ||||
break; | ||||
if (p_decoder->i_last_section_number == p->i_number) | ||||
b_complete = true; | ||||
p = p->p_next; | ||||
prev_nr++; | ||||
} | ||||
return b_complete; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_psi_section_add | ||||
************************************************************************** | ||||
***/ | ||||
bool dvbpsi_decoder_psi_section_add(dvbpsi_decoder_t *p_decoder, dvbpsi_psi | ||||
_section_t *p_section) | ||||
{ | ||||
assert(p_decoder); | ||||
assert(p_section); | ||||
assert(p_section->p_next == NULL); | ||||
/* Empty list */ | ||||
if (!p_decoder->p_sections) | ||||
{ | ||||
p_decoder->p_sections = p_section; | ||||
p_section->p_next = NULL; | ||||
return false; | ||||
} | ||||
/* Insert in right place */ | ||||
dvbpsi_psi_section_t *p = p_decoder->p_sections; | ||||
dvbpsi_psi_section_t *p_prev = NULL; | ||||
bool b_overwrite = false; | ||||
while (p) | ||||
{ | ||||
if (p->i_number == p_section->i_number) | ||||
{ | ||||
/* Replace */ | ||||
if (p_prev) | ||||
{ | ||||
p_prev->p_next = p_section; | ||||
p_section->p_next = p->p_next; | ||||
p->p_next = NULL; | ||||
dvbpsi_DeletePSISections(p); | ||||
b_overwrite = true; | ||||
} | ||||
else | ||||
{ | ||||
p_section->p_next = p->p_next; | ||||
p->p_next = NULL; | ||||
dvbpsi_DeletePSISections(p); | ||||
p = p_section; | ||||
p_decoder->p_sections = p; | ||||
b_overwrite = true; | ||||
} | ||||
goto out; | ||||
} | ||||
else if (p->i_number > p_section->i_number) | ||||
{ | ||||
/* Insert before p */ | ||||
if (p_prev) | ||||
{ | ||||
p_prev->p_next = p_section; | ||||
p_section->p_next = p; | ||||
} | ||||
else | ||||
{ | ||||
p_section->p_next = p; | ||||
p_decoder->p_sections = p_section; | ||||
} | ||||
goto out; | ||||
} | ||||
p_prev = p; | ||||
p = p->p_next; | ||||
} | ||||
/* Add to end of list */ | ||||
if (p_prev->i_number < p_section->i_number) | ||||
{ | ||||
p_prev->p_next = p_section; | ||||
p_section->p_next = NULL; | ||||
} | ||||
out: | ||||
return b_overwrite; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_delete | ||||
************************************************************************** | ||||
***/ | ||||
void dvbpsi_decoder_delete(dvbpsi_decoder_t *p_decoder) | ||||
{ | ||||
assert(p_decoder); | ||||
if (p_decoder->p_sections) | ||||
{ | ||||
dvbpsi_DeletePSISections(p_decoder->p_sections); | ||||
p_decoder->p_sections = NULL; | ||||
} | ||||
dvbpsi_DeletePSISections(p_decoder->p_current_section); | ||||
free(p_decoder); | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_decoder_present | ||||
************************************************************************** | ||||
***/ | ||||
bool dvbpsi_decoder_present(dvbpsi_t *p_dvbpsi) | ||||
{ | ||||
if (p_dvbpsi && p_dvbpsi->p_decoder) | ||||
return true; | ||||
else | ||||
return false; | ||||
} | ||||
/************************************************************************** | ||||
*** | ||||
* dvbpsi_packet_push | ||||
************************************************************************** *** | ************************************************************************** *** | |||
* Injection of a TS packet into a PSI decoder. | * Injection of a TS packet into a PSI decoder. | |||
************************************************************************** ***/ | ************************************************************************** ***/ | |||
void dvbpsi_PushPacket(dvbpsi_handle h_dvbpsi, uint8_t* p_data) | bool dvbpsi_packet_push(dvbpsi_t *p_dvbpsi, uint8_t* p_data) | |||
{ | { | |||
uint8_t i_expected_counter; /* Expected continuity counter */ | uint8_t i_expected_counter; /* Expected continuity counter */ | |||
dvbpsi_psi_section_t* p_section; /* Current section */ | dvbpsi_psi_section_t* p_section; /* Current section */ | |||
uint8_t* p_payload_pos; /* Where in the TS packet */ | uint8_t* p_payload_pos; /* Where in the TS packet */ | |||
uint8_t* p_new_pos = NULL; /* Beginning of the new section, | uint8_t* p_new_pos = NULL; /* Beginning of the new section, | |||
updated to NULL when the new | updated to NULL when the new | |||
section is handled */ | section is handled */ | |||
int i_available; /* Byte count available in the | int i_available; /* Byte count available in the | |||
packet */ | packet */ | |||
/* TS start code */ | dvbpsi_decoder_t *p_decoder = p_dvbpsi->p_decoder; | |||
if(p_data[0] != 0x47) | assert(p_decoder); | |||
{ | ||||
DVBPSI_ERROR("PSI decoder", "not a TS packet"); | /* TS start code */ | |||
return; | if (p_data[0] != 0x47) | |||
} | { | |||
dvbpsi_error(p_dvbpsi, "PSI decoder", "not a TS packet"); | ||||
/* Continuity check */ | return false; | |||
i_expected_counter = (h_dvbpsi->i_continuity_counter + 1) & 0xf; | } | |||
h_dvbpsi->i_continuity_counter = p_data[3] & 0xf; | ||||
/* Continuity check */ | ||||
if(i_expected_counter == ((h_dvbpsi->i_continuity_counter + 1) & 0xf) | bool b_first = (p_decoder->i_continuity_counter == DVBPSI_INVALID_CC); | |||
&& !h_dvbpsi->b_discontinuity) | if (b_first) | |||
{ | p_decoder->i_continuity_counter = p_data[3] & 0xf; | |||
DVBPSI_ERROR_ARG("PSI decoder", | else | |||
{ | ||||
i_expected_counter = (p_decoder->i_continuity_counter + 1) & 0xf; | ||||
p_decoder->i_continuity_counter = p_data[3] & 0xf; | ||||
if (i_expected_counter == ((p_decoder->i_continuity_counter + 1) & | ||||
0xf) | ||||
&& !p_decoder->b_discontinuity) | ||||
{ | ||||
dvbpsi_error(p_dvbpsi, "PSI decoder", | ||||
"TS duplicate (received %d, expected %d) for PID %d", | "TS duplicate (received %d, expected %d) for PID %d", | |||
h_dvbpsi->i_continuity_counter, i_expected_counter, | p_decoder->i_continuity_counter, i_expected_counter, | |||
((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); | ((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); | |||
return; | return false; | |||
} | } | |||
if(i_expected_counter != h_dvbpsi->i_continuity_counter) | if (i_expected_counter != p_decoder->i_continuity_counter) | |||
{ | { | |||
DVBPSI_ERROR_ARG("PSI decoder", | dvbpsi_error(p_dvbpsi, "PSI decoder", | |||
"TS discontinuity (received %d, expected %d) for PID % d", | "TS discontinuity (received %d, expected %d) for PID % d", | |||
h_dvbpsi->i_continuity_counter, i_expected_counter, | p_decoder->i_continuity_counter, i_expected_counter, | |||
((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); | ((uint16_t)(p_data[1] & 0x1f) << 8) | p_data[2]); | |||
h_dvbpsi->b_discontinuity = 1; | p_decoder->b_discontinuity = true; | |||
if(h_dvbpsi->p_current_section) | if (p_decoder->p_current_section) | |||
{ | { | |||
dvbpsi_DeletePSISections(h_dvbpsi->p_current_section); | dvbpsi_DeletePSISections(p_decoder->p_current_section); | |||
h_dvbpsi->p_current_section = NULL; | p_decoder->p_current_section = NULL; | |||
} | ||||
} | ||||
} | } | |||
} | ||||
/* Return if no payload in the TS packet */ | /* Return if no payload in the TS packet */ | |||
if(!(p_data[3] & 0x10)) | if (!(p_data[3] & 0x10)) | |||
{ | return false; | |||
return; | ||||
} | /* Skip the adaptation_field if present */ | |||
if (p_data[3] & 0x20) | ||||
/* Skip the adaptation_field if present */ | p_payload_pos = p_data + 5 + p_data[4]; | |||
if(p_data[3] & 0x20) | ||||
p_payload_pos = p_data + 5 + p_data[4]; | ||||
else | ||||
p_payload_pos = p_data + 4; | ||||
/* Unit start -> skip the pointer_field and a new section begins */ | ||||
if(p_data[1] & 0x40) | ||||
{ | ||||
p_new_pos = p_payload_pos + *p_payload_pos + 1; | ||||
p_payload_pos += 1; | ||||
} | ||||
p_section = h_dvbpsi->p_current_section; | ||||
/* If the psi decoder needs a begginning of section and a new section | ||||
begins in the packet then initialize the dvbpsi_psi_section_t structur | ||||
e */ | ||||
if(p_section == NULL) | ||||
{ | ||||
if(p_new_pos) | ||||
{ | ||||
/* Allocation of the structure */ | ||||
h_dvbpsi->p_current_section | ||||
= p_section | ||||
= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size | ||||
); | ||||
/* Update the position in the packet */ | ||||
p_payload_pos = p_new_pos; | ||||
/* New section is being handled */ | ||||
p_new_pos = NULL; | ||||
/* Just need the header to know how long is the section */ | ||||
h_dvbpsi->i_need = 3; | ||||
h_dvbpsi->b_complete_header = 0; | ||||
} | ||||
else | else | |||
p_payload_pos = p_data + 4; | ||||
/* Unit start -> skip the pointer_field and a new section begins */ | ||||
if (p_data[1] & 0x40) | ||||
{ | { | |||
/* No new section => return */ | p_new_pos = p_payload_pos + *p_payload_pos + 1; | |||
return; | p_payload_pos += 1; | |||
} | } | |||
} | ||||
/* Remaining bytes in the payload */ | p_section = p_decoder->p_current_section; | |||
i_available = 188 + p_data - p_payload_pos; | ||||
while(i_available > 0) | /* If the psi decoder needs a beginning of a section and a new section | |||
{ | begins in the packet then initialize the dvbpsi_psi_section_t struct | |||
if(i_available >= h_dvbpsi->i_need) | ure */ | |||
{ | if (p_section == NULL) | |||
/* There are enough bytes in this packet to complete the | { | |||
header/section */ | if (p_new_pos) | |||
memcpy(p_section->p_payload_end, p_payload_pos, h_dvbpsi->i_need); | ||||
p_payload_pos += h_dvbpsi->i_need; | ||||
p_section->p_payload_end += h_dvbpsi->i_need; | ||||
i_available -= h_dvbpsi->i_need; | ||||
if(!h_dvbpsi->b_complete_header) | ||||
{ | ||||
/* Header is complete */ | ||||
h_dvbpsi->b_complete_header = 1; | ||||
/* Compute p_section->i_length and update h_dvbpsi->i_need */ | ||||
h_dvbpsi->i_need = p_section->i_length | ||||
= ((uint16_t)(p_section->p_data[1] & 0xf)) << 8 | ||||
| p_section->p_data[2]; | ||||
/* Check that the section isn't too long */ | ||||
if(h_dvbpsi->i_need > h_dvbpsi->i_section_max_size - 3) | ||||
{ | { | |||
DVBPSI_ERROR("PSI decoder", "PSI section too long"); | /* Allocation of the structure */ | |||
dvbpsi_DeletePSISections(p_section); | p_decoder->p_current_section | |||
h_dvbpsi->p_current_section = NULL; | ||||
/* If there is a new section not being handled then go forward | ||||
in the packet */ | ||||
if(p_new_pos) | ||||
{ | ||||
h_dvbpsi->p_current_section | ||||
= p_section | = p_section | |||
= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size | = dvbpsi_NewPSISection(p_decoder->i_section_max_siz | |||
); | e); | |||
if (!p_section) | ||||
return false; | ||||
/* Update the position in the packet */ | ||||
p_payload_pos = p_new_pos; | p_payload_pos = p_new_pos; | |||
/* New section is being handled */ | ||||
p_new_pos = NULL; | p_new_pos = NULL; | |||
h_dvbpsi->i_need = 3; | /* Just need the header to know how long is the section */ | |||
h_dvbpsi->b_complete_header = 0; | p_decoder->i_need = 3; | |||
i_available = 188 + p_data - p_payload_pos; | p_decoder->b_complete_header = false; | |||
} | ||||
else | ||||
{ | ||||
i_available = 0; | ||||
} | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
/* PSI section is complete */ | ||||
p_section->b_syntax_indicator = p_section->p_data[1] & 0x80; | ||||
p_section->b_private_indicator = p_section->p_data[1] & 0x40; | ||||
/* Update the end of the payload if CRC_32 is present */ | ||||
if(p_section->b_syntax_indicator) | ||||
p_section->p_payload_end -= 4; | ||||
if(p_section->p_data[0] != 0x72 && dvbpsi_ValidPSISection(p_section | ||||
)) | ||||
{ | ||||
/* PSI section is valid */ | ||||
p_section->i_table_id = p_section->p_data[0]; | ||||
if(p_section->b_syntax_indicator) | ||||
{ | ||||
p_section->i_extension = (p_section->p_data[3] << 8) | ||||
| p_section->p_data[4]; | ||||
p_section->i_version = (p_section->p_data[5] & 0x3e) >> 1; | ||||
p_section->b_current_next = p_section->p_data[5] & 0x1; | ||||
p_section->i_number = p_section->p_data[6]; | ||||
p_section->i_last_number = p_section->p_data[7]; | ||||
p_section->p_payload_start = p_section->p_data + 8; | ||||
} | ||||
else | ||||
{ | ||||
p_section->i_extension = 0; | ||||
p_section->i_version = 0; | ||||
p_section->b_current_next = 1; | ||||
p_section->i_number = 0; | ||||
p_section->i_last_number = 0; | ||||
p_section->p_payload_start = p_section->p_data + 3; | ||||
} | ||||
h_dvbpsi->pf_callback(h_dvbpsi, p_section); | ||||
h_dvbpsi->p_current_section = NULL; | ||||
} | } | |||
else | else | |||
{ | { | |||
/* PSI section isn't valid => trash it */ | /* No new section => return */ | |||
dvbpsi_DeletePSISections(p_section); | return false; | |||
h_dvbpsi->p_current_section = NULL; | ||||
} | } | |||
} | ||||
/* A TS packet may contain any number of sections, only the first | /* Remaining bytes in the payload */ | |||
* new one is flagged by the pointer_field. If the next payload | i_available = 188 + p_data - p_payload_pos; | |||
* byte isn't 0xff then a new section starts. */ | ||||
if(p_new_pos == NULL && i_available && *p_payload_pos != 0xff) | while (i_available > 0) | |||
p_new_pos = p_payload_pos; | { | |||
if (i_available >= p_decoder->i_need) | ||||
/* If there is a new section not being handled then go forward | ||||
in the packet */ | ||||
if(p_new_pos) | ||||
{ | { | |||
h_dvbpsi->p_current_section | /* There are enough bytes in this packet to complete the | |||
= p_section | header/section */ | |||
= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size | memcpy(p_section->p_payload_end, p_payload_pos, p_decoder->i_ne | |||
); | ed); | |||
p_payload_pos = p_new_pos; | p_payload_pos += p_decoder->i_need; | |||
p_new_pos = NULL; | p_section->p_payload_end += p_decoder->i_need; | |||
h_dvbpsi->i_need = 3; | i_available -= p_decoder->i_need; | |||
h_dvbpsi->b_complete_header = 0; | ||||
i_available = 188 + p_data - p_payload_pos; | if (!p_decoder->b_complete_header) | |||
{ | ||||
/* Header is complete */ | ||||
p_decoder->b_complete_header = true; | ||||
/* Compute p_section->i_length and update p_decoder->i_need | ||||
*/ | ||||
p_decoder->i_need = p_section->i_length | ||||
= ((uint16_t)(p_section->p_data[1] & 0xf) | ||||
) << 8 | ||||
| p_section->p_data[2]; | ||||
/* Check that the section isn't too long */ | ||||
if (p_decoder->i_need > p_decoder->i_section_max_size - 3) | ||||
{ | ||||
dvbpsi_error(p_dvbpsi, "PSI decoder", "PSI section too | ||||
long"); | ||||
dvbpsi_DeletePSISections(p_section); | ||||
p_decoder->p_current_section = NULL; | ||||
/* If there is a new section not being handled then go | ||||
forward | ||||
in the packet */ | ||||
if (p_new_pos) | ||||
{ | ||||
p_decoder->p_current_section | ||||
= p_section | ||||
= dvbpsi_NewPSISection(p_decoder->i_sec | ||||
tion_max_size); | ||||
if (!p_section) | ||||
return false; | ||||
p_payload_pos = p_new_pos; | ||||
p_new_pos = NULL; | ||||
p_decoder->i_need = 3; | ||||
p_decoder->b_complete_header = false; | ||||
i_available = 188 + p_data - p_payload_pos; | ||||
} | ||||
else | ||||
{ | ||||
i_available = 0; | ||||
} | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
/* PSI section is complete */ | ||||
p_section->b_syntax_indicator = p_section->p_data[1] & 0x80 | ||||
; | ||||
p_section->b_private_indicator = p_section->p_data[1] & 0x4 | ||||
0; | ||||
/* Update the end of the payload if CRC_32 is present */ | ||||
if (p_section->b_syntax_indicator) | ||||
p_section->p_payload_end -= 4; | ||||
if ((p_section->p_data[0] == 0x70) /* TDT (has no CRC 32) * | ||||
/ || | ||||
(p_section->p_data[0] == 0x71) /* RST (has no CRC 32) * | ||||
/ || | ||||
(p_section->p_data[0] != 0x72 && dvbpsi_ValidPSISection | ||||
(p_section))) | ||||
{ | ||||
/* PSI section is valid */ | ||||
p_section->i_table_id = p_section->p_data[0]; | ||||
if (p_section->b_syntax_indicator) | ||||
{ | ||||
p_section->i_extension = (p_section->p_data[3] << | ||||
8) | ||||
| p_section->p_data[4]; | ||||
p_section->i_version = (p_section->p_data[5] & 0x3e | ||||
) >> 1; | ||||
p_section->b_current_next = p_section->p_data[5] & | ||||
0x1; | ||||
p_section->i_number = p_section->p_data[6]; | ||||
p_section->i_last_number = p_section->p_data[7]; | ||||
p_section->p_payload_start = p_section->p_data + 8; | ||||
} | ||||
else | ||||
{ | ||||
p_section->i_extension = 0; | ||||
p_section->i_version = 0; | ||||
p_section->b_current_next = true; | ||||
p_section->i_number = 0; | ||||
p_section->i_last_number = 0; | ||||
p_section->p_payload_start = p_section->p_data + 3; | ||||
} | ||||
if (p_decoder->pf_gather) | ||||
p_decoder->pf_gather(p_dvbpsi, p_section); | ||||
p_decoder->p_current_section = NULL; | ||||
} | ||||
else | ||||
{ | ||||
if (!dvbpsi_ValidPSISection(p_section)) | ||||
dvbpsi_error(p_dvbpsi, "misc PSI", "Bad CRC_32 tabl | ||||
e 0x%x !!!", | ||||
p_section->p_data[0]); | ||||
else | ||||
dvbpsi_error(p_dvbpsi, "misc PSI", "table 0x%x", p_ | ||||
section->p_data[0]); | ||||
/* PSI section isn't valid => trash it */ | ||||
dvbpsi_DeletePSISections(p_section); | ||||
p_decoder->p_current_section = NULL; | ||||
} | ||||
/* A TS packet may contain any number of sections, only the | ||||
first | ||||
* new one is flagged by the pointer_field. If the next pay | ||||
load | ||||
* byte isn't 0xff then a new section starts. */ | ||||
if (p_new_pos == NULL && i_available && *p_payload_pos != 0 | ||||
xff) | ||||
p_new_pos = p_payload_pos; | ||||
/* If there is a new section not being handled then go forw | ||||
ard | ||||
in the packet */ | ||||
if (p_new_pos) | ||||
{ | ||||
p_decoder->p_current_section | ||||
= p_section | ||||
= dvbpsi_NewPSISection(p_decoder->i_section_m | ||||
ax_size); | ||||
if (!p_section) | ||||
return false; | ||||
p_payload_pos = p_new_pos; | ||||
p_new_pos = NULL; | ||||
p_decoder->i_need = 3; | ||||
p_decoder->b_complete_header = false; | ||||
i_available = 188 + p_data - p_payload_pos; | ||||
} | ||||
else | ||||
{ | ||||
i_available = 0; | ||||
} | ||||
} | ||||
} | } | |||
else | else | |||
{ | { | |||
i_available = 0; | /* There aren't enough bytes in this packet to complete the | |||
header/section */ | ||||
memcpy(p_section->p_payload_end, p_payload_pos, i_available); | ||||
p_section->p_payload_end += i_available; | ||||
p_decoder->i_need -= i_available; | ||||
i_available = 0; | ||||
} | } | |||
} | ||||
} | } | |||
else | return true; | |||
} | ||||
#undef DVBPSI_INVALID_CC | ||||
/************************************************************************** | ||||
*** | ||||
* Message error level: | ||||
* -1 is disabled, | ||||
* 0 is errors only | ||||
* 1 is warning and errors | ||||
* 2 is debug, warning and errors | ||||
************************************************************************** | ||||
***/ | ||||
#if !defined(_GNU_SOURCE) | ||||
# define DVBPSI_MSG_SIZE 1024 | ||||
#endif | ||||
#define DVBPSI_MSG_FORMAT "libdvbpsi (%s): %s" | ||||
#ifdef HAVE_VARIADIC_MACROS | ||||
void dvbpsi_message(dvbpsi_t *dvbpsi, const dvbpsi_msg_level_t level, const | ||||
char *fmt, ...) | ||||
{ | ||||
if ((dvbpsi->i_msg_level > DVBPSI_MSG_NONE) && | ||||
(level <= dvbpsi->i_msg_level)) | ||||
{ | { | |||
/* There aren't enough bytes in this packet to complete the | va_list ap; | |||
header/section */ | va_start(ap, fmt); | |||
memcpy(p_section->p_payload_end, p_payload_pos, i_available); | char *msg = NULL; | |||
p_section->p_payload_end += i_available; | #if defined(_GNU_SOURCE) | |||
h_dvbpsi->i_need -= i_available; | int err = vasprintf(&msg, fmt, ap); | |||
i_available = 0; | #else | |||
msg = malloc(DVBPSI_MSG_SIZE); | ||||
if (msg == NULL) | ||||
return; | ||||
if (snprintf(&msg, DVBPSI_MSG_SIZE, DVBPSI_MSG_FORMAT, ap) < 0) { | ||||
free(msg); | ||||
return; | ||||
} | ||||
int err = vsnprintf(&msg, DVBPSI_MSG_SIZE, fmt, ap); | ||||
#endif | ||||
va_end(ap); | ||||
if (err > DVBPSI_MSG_NONE) { | ||||
if (dvbpsi->pf_message) | ||||
dvbpsi->pf_message(dvbpsi, level, msg); | ||||
} | ||||
free(msg); | ||||
} | } | |||
} | ||||
} | } | |||
#else | ||||
/* Common code for printing messages */ | ||||
# if defined(_GNU_SOURCE) | ||||
# define DVBPSI_MSG_COMMON(level) \ | ||||
do { \ | ||||
va_list ap; \ | ||||
va_start(ap, fmt); \ | ||||
char *tmp = NULL; \ | ||||
int err = vasprintf(&tmp, fmt, ap); \ | ||||
if (err < 0) \ | ||||
return; \ | ||||
char *msg = NULL; \ | ||||
if (asprintf(&msg, DVBPSI_MSG_FORMAT, src, tmp) < 0) { \ | ||||
free(tmp); \ | ||||
return; \ | ||||
} \ | ||||
free(tmp); \ | ||||
va_end(ap); \ | ||||
if (err > 0) { \ | ||||
if (dvbpsi->pf_message) \ | ||||
dvbpsi->pf_message(dvbpsi, level, msg); \ | ||||
} \ | ||||
free(msg); \ | ||||
} while(0); | ||||
# else | ||||
# define DVBPSI_MSG_COMMON \ | ||||
do { \ | ||||
va_list ap; \ | ||||
va_start(ap, fmt); \ | ||||
char *msg = malloc(DVBPSI_MSG_SIZE); \ | ||||
if (msg == NULL) \ | ||||
return; \ | ||||
if (snprintf(&msg, DVBPSI_MSG_SIZE, DVBPSI_MSG_FORMAT, src) < 0) \ | ||||
return; \ | ||||
int err = vsnprintf(&msg, DVBPSI_MSG_SIZE, fmt, ap); \ | ||||
va_end(ap); \ | ||||
if (err > 0) { \ | ||||
if (dvbpsi->pf_message) \ | ||||
dvbpsi->pf_message(dvbpsi, level, msg); \ | ||||
} \ | ||||
free(msg); \ | ||||
} while(0); | ||||
# endif | ||||
void dvbpsi_error(dvbpsi_t *dvbpsi, const char *src, const char *fmt, ...) | ||||
{ | ||||
if ((dvbpsi->i_msg_level > DVBPSI_MSG_NONE) && | ||||
(DVBPSI_MSG_ERROR <= dvbpsi->i_msg_level)) | ||||
{ | ||||
DVBPSI_MSG_COMMON(DVBPSI_MSG_ERROR) | ||||
} | ||||
} | ||||
void dvbpsi_warning(dvbpsi_t *dvbpsi, const char *src, const char *fmt, ... | ||||
) | ||||
{ | ||||
if ((dvbpsi->i_msg_level > DVBPSI_MSG_NONE) && | ||||
(DVBPSI_MSG_WARN <= dvbpsi->i_msg_level)) | ||||
{ | ||||
DVBPSI_MSG_COMMON(DVBPSI_MSG_WARN) | ||||
} | ||||
} | ||||
void dvbpsi_debug(dvbpsi_t *dvbpsi, const char *src, const char *fmt, ...) | ||||
{ | ||||
if ((dvbpsi->i_msg_level > DVBPSI_MSG_NONE) && | ||||
(DVBPSI_MSG_DEBUG <= dvbpsi->i_msg_level)) | ||||
{ | ||||
DVBPSI_MSG_COMMON(DVBPSI_MSG_DEBUG) | ||||
} | ||||
} | ||||
#endif | ||||
End of changes. 33 change blocks. | ||||
194 lines changed or deleted | 508 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/ |