Commit 968b0ea0 authored by Christophe Massiot's avatar Christophe Massiot

* Initial import.

parents
# Contributors to biTStream
# $Id$
#
# The format of this file was inspired by the Linux kernel CREDITS file.
# Authors are listed alphabetically.
#
# The fields are: name (N), email (E), web-address (W), CVS account login (C),
# PGP key ID and fingerprint (P), description (D), and snail-mail address (S).
N: Christophe Massiot
E: massiot AT via DOT ecp DOT fr
C: massiot
D: All of the code
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
$Id$
Installing biTStream
====================
No Makefile yet... Just create a /usr/include/bitstream or
/usr/local/include/bitstream directory, and copy all top-level directories
there.
$Id$
1.0 (?? Aug 2010)
=================
- Initial public release
$Id$
Welcome to biTStream!
=====================
biTStream is a set of C headers allowing a simpler access to binary
structures such as specified by MPEG, DVB, IETF, etc.
biTStream vs. libdvbpsi
=======================
libdvbpsi converts binary structures to C structures. Lists are implemented
with chained lists of C structures.
biTStream is lower level, and more efficient: fewer memory allocations,
fewer memory copies. It also features a better separation between layers
and specifications.
Extending biTStream
===================
A lot of MPEG and DVB tables and descriptors are not implemented yet, or
are incomplete. Patches are very welcome.
Though biTStream is originally targeted at video applications in general
and MPEG-2 transport stream in particular, the same principle can be
followed with other binary data types, and patches are welcome here too.
Just try to follow a coherent directory naming.
My coding style is Linux kernel + Hungarian conventions. Really, I do not
care about the coding style of new files; do (WTF) you want. However, for
existing files, please try to follow the original conventions.
biTStream is released under the WTF public license because since it is a
direct application of standards, there is no added value. The WTF license
doesn't require you to contribute back your changes, and you can use
biTStream in proprietary applications. However, if you add new structures,
or fix bugs in current structures, you'd be very nice to contribute them
(again, there is no point in concealing this). Thanks.
/*****************************************************************************
* ci.h: ETSI EN 50 221 Common Interface Specification
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ETSI EN 50 221 (1997) (Common Interface Specification)
*/
#ifndef __BITSTREAM_DVB_CI_H__
#define __BITSTREAM_DVB_CI_H__
#include <bitstream/mpeg/psi.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Conditional Access Program Map Table
*****************************************************************************
* Implementation note: the first field here is ca_pmt_list_management,
* since the previous length field is variable size and is generally put
* afterwards.
*****************************************************************************/
#define CAPMT_HEADER_SIZE 6
#define CAPMT_ES_SIZE 5
#define CAPMTI_HEADER_SIZE 3
/* Max theoritical size is PSI_MAX_SIZE + ~100 */
#define CAPMT_DECLARE PSI_PRIVATE_DECLARE
#define capmt_allocate psi_private_allocate
static inline void capmt_init(uint8_t *p_capmt)
{
p_capmt[3] = 0xc1;
p_capmt[4] = 0xf0;
}
static inline void capmt_set_listmanagement(uint8_t *p_capmt, uint8_t i_mgt)
{
p_capmt[0] = i_mgt;
}
static inline void capmt_set_program(uint8_t *p_capmt, uint16_t i_program)
{
p_capmt[1] = i_program >> 8;
p_capmt[2] = i_program & 0xff;
}
static inline void capmt_set_version(uint8_t *p_capmt, uint8_t i_version)
{
p_capmt[3] &= ~0x3e;
p_capmt[3] |= i_version << 1;
}
static inline uint8_t *capmt_get_infos(uint8_t *p_capmt)
{
return &p_capmt[4];
}
static inline uint16_t capmt_get_infoslength(const uint8_t *p_capmt)
{
return ((p_capmt[4] & 0xf) << 8) | p_capmt[5];
}
static inline void capmtn_init(uint8_t *p_capmt_n)
{
p_capmt_n[1] = 0xe0;
}
static inline void capmtn_set_streamtype(uint8_t *p_capmt_n,
uint8_t i_stream_type)
{
p_capmt_n[0] = i_stream_type;
}
static inline void capmtn_set_pid(uint8_t *p_capmt_n, uint16_t i_pid)
{
p_capmt_n[1] &= ~0x1f;
p_capmt_n[1] |= i_pid >> 8;
p_capmt_n[2] = i_pid & 0xff;
}
static inline uint16_t capmtn_get_infoslength(const uint8_t *p_capmt_n)
{
return ((p_capmt_n[3] & 0xf) << 8) | p_capmt_n[4];
}
static inline uint8_t *capmtn_get_infos(uint8_t *p_capmt_n)
{
return &p_capmt_n[3];
}
static inline uint8_t *capmt_get_es(uint8_t *p_capmt, uint8_t n)
{
uint8_t *p_capmt_n = p_capmt + CAPMT_HEADER_SIZE
+ capmt_get_infoslength(p_capmt);
while (n) {
p_capmt_n += CAPMT_ES_SIZE + capmtn_get_infoslength(p_capmt_n);
n--;
}
return p_capmt_n;
}
static inline void capmti_init(uint8_t *p_infos)
{
p_infos[0] = 0xf0;
}
static inline void capmti_set_length(uint8_t *p_infos, uint16_t i_length)
{
p_infos[0] &= ~0xf;
p_infos[0] |= i_length >> 8;
p_infos[1] = i_length & 0xff;
}
static inline uint16_t capmti_get_length(const uint8_t *p_infos)
{
return ((p_infos[0] & 0xf) << 8) | p_infos[1];
}
static inline void capmti_set_cmd(uint8_t *p_infos, uint8_t i_cmd)
{
p_infos[2] = i_cmd;
}
static inline uint8_t *capmti_get_info(uint8_t *p_infos, uint16_t n)
{
uint8_t *p_info = p_infos + CAPMTI_HEADER_SIZE;
uint16_t i_infos_size = capmti_get_length(p_infos) + DESCS_HEADER_SIZE;
while (n) {
if (p_info + DESC_HEADER_SIZE - p_infos > i_infos_size) return NULL;
p_info += DESC_HEADER_SIZE + desc_get_length(p_info);
n--;
}
if (p_info - p_infos >= i_infos_size) return NULL;
return p_info;
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* si.h: ETSI EN 300 468 Service Information
*****************************************************************************
* Copyright (C) 2009-2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ISO/IEC 13818-1:2007(E) (MPEG-2 Systems)
* - ETSI EN 300 468 V1.11.1 (2010-04) (SI in DVB systems)
*/
#ifndef __BITSTREAM_DVB_SI_H__
#define __BITSTREAM_DVB_SI_H__
#include <bitstream/mpeg/psi.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Descriptor 0x40: Network name descriptor
*****************************************************************************/
#define DESC40_HEADER_SIZE DESC_HEADER_SIZE
static inline void desc40_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x40);
}
static inline void desc40_set_networkname(uint8_t *p_desc,
const char *psz_network_name)
{
uint8_t i_length = strlen(psz_network_name);
desc_set_length(p_desc, i_length);
memcpy(p_desc + 2, psz_network_name, i_length);
}
static inline void desc40_get_networkname(const uint8_t *p_desc,
char *psz_network_name)
{
uint8_t i_length = desc_get_length(p_desc);
memcpy(psz_network_name, p_desc + 2, i_length);
psz_network_name[i_length] = '\0';
}
/*****************************************************************************
* Descriptor 0x48: Service descriptor
*****************************************************************************/
#define DESC48_HEADER_SIZE 3
static inline uint8_t desc48_get_type(const uint8_t *p_desc)
{
return p_desc[2];
}
static inline void desc48_get_provider(const uint8_t *p_desc,
char *psz_provider)
{
const uint8_t *p = p_desc + 3;
memcpy(psz_provider, p + 1, *p);
psz_provider[*p] = '\0';
}
static inline void desc48_get_service(const uint8_t *p_desc,
char *psz_service)
{
const uint8_t *p = p_desc + 4 + p_desc[3];
memcpy(psz_service, p + 1, *p);
psz_service[*p] = '\0';
}
/*****************************************************************************
* Descriptor 0x56: Teletext descriptor
*****************************************************************************/
#define DESC56_HEADER_SIZE DESC_HEADER_SIZE
#define DESC56_LANGUAGE_SIZE 5
static inline void desc56_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x56);
}
static inline uint8_t *desc56_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC56_HEADER_SIZE + n * DESC56_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC56_HEADER_SIZE)
return NULL;
return p_desc_n;
}
#define desc56n_set_code desc0an_set_code
static inline void desc56n_set_teletexttype(uint8_t *p_desc_n, uint8_t i_type)
{
p_desc_n[3] &= ~0xfc;
p_desc_n[3] |= (i_type << 3) & 0xfc;
}
static inline void desc56n_set_teletextmagazine(uint8_t *p_desc_n,
uint8_t i_magazine)
{
p_desc_n[3] &= ~0x3;
p_desc_n[3] |= (i_magazine & 0x3);
}
static inline void desc56n_set_teletextpage(uint8_t *p_desc_n, uint8_t i_page)
{
p_desc_n[4] = i_page;
}
/*****************************************************************************
* Descriptor 0x59: Subtitling descriptor
*****************************************************************************/
#define DESC59_HEADER_SIZE DESC_HEADER_SIZE
#define DESC59_LANGUAGE_SIZE 8
static inline void desc59_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x59);
}
static inline uint8_t *desc59_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC59_HEADER_SIZE + n * DESC59_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC59_HEADER_SIZE)
return NULL;
return p_desc_n;
}
#define desc59n_set_code desc0an_set_code
static inline void desc59n_set_subtitlingtype(uint8_t *p_desc_n, uint8_t i_type)
{
p_desc_n[3] = i_type;
}
static inline void desc59n_set_compositionpage(uint8_t *p_desc_n,
uint16_t i_page)
{
p_desc_n[4] = i_page >> 8;
p_desc_n[5] = i_page & 0xff;
}
static inline void desc59n_set_ancillarypage(uint8_t *p_desc_n, uint16_t i_page)
{
p_desc_n[6] = i_page >> 8;
p_desc_n[7] = i_page & 0xff;
}
/*****************************************************************************
* Descriptor 0x6a: AC-3 descriptor
*****************************************************************************/
#define DESC6A_HEADER_SIZE 3
static inline void desc6a_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x6a);
}
static inline void desc6a_clear_flags(uint8_t *p_desc)
{
p_desc[2] = 0;
}
/*****************************************************************************
* Network Information Table
*****************************************************************************/
#define NIT_PID 0x10
#define NIT_TABLE_ID_ACTUAL 0x40
#define NIT_TABLE_ID_OTHER 0x41
#define NIT_HEADER_SIZE (PSI_HEADER_SIZE_SYNTAX1 + 2)
#define NIT_HEADER2_SIZE 2
#define NIT_TS_SIZE 6
#define nit_set_nid psi_set_tableidext
#define nit_get_nid psi_get_tableidext
static inline void nit_init(uint8_t *p_nit, bool b_actual)
{
psi_init(p_nit, true);
psi_set_tableid(p_nit, b_actual ? NIT_TABLE_ID_ACTUAL : NIT_TABLE_ID_OTHER);
p_nit[8] = 0xf0;
}
static inline void nit_set_length(uint8_t *p_nit, uint16_t i_nit_length)
{
psi_set_length(p_nit, NIT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+ i_nit_length);
}
static inline void nit_set_desclength(uint8_t *p_nit, uint16_t i_length)
{
p_nit[8] &= ~0xf;
p_nit[8] |= i_length >> 8;
p_nit[9] = i_length & 0xff;
}
static inline uint16_t nit_get_desclength(const uint8_t *p_nit)
{
return ((p_nit[8] & 0xf) << 8) | p_nit[9];
}
static inline uint8_t *nit_get_descs(uint8_t *p_nit)
{
return &p_nit[8];
}
static inline void nith_init(uint8_t *p_nit_h)
{
p_nit_h[0] = 0xf0;
}
static inline void nith_set_tslength(uint8_t *p_nit_h, uint16_t i_length)
{
p_nit_h[0] &= ~0xf;
p_nit_h[0] |= i_length >> 8;
p_nit_h[1] = i_length & 0xff;
}
static inline uint16_t nith_get_tslength(const uint8_t *p_nit_h)
{
return ((p_nit_h[0] & 0xf) << 8) | p_nit_h[1];
}
static inline void nitn_init(uint8_t *p_nit_n)
{
p_nit_n[4] = 0xf0;
}
static inline void nitn_set_tsid(uint8_t *p_nit_n, uint16_t i_tsid)
{
p_nit_n[0] = i_tsid >> 8;
p_nit_n[1] = i_tsid & 0xff;
}
static inline uint8_t nitn_get_tsid(const uint8_t *p_nit_n)
{
return (p_nit_n[0] << 8) | p_nit_n[1];
}
static inline void nitn_set_onid(uint8_t *p_nit_n, uint16_t i_onid)
{
p_nit_n[2] = i_onid >> 8;
p_nit_n[3] = i_onid & 0xff;
}
static inline uint8_t nitn_get_onid(const uint8_t *p_nit_n)
{
return (p_nit_n[2] << 8) | p_nit_n[3];
}
static inline void nitn_set_desclength(uint8_t *p_nit_n, uint16_t i_length)
{
p_nit_n[4] &= ~0xf;
p_nit_n[4] |= i_length >> 8;
p_nit_n[5] = i_length & 0xff;
}
static inline uint16_t nitn_get_desclength(const uint8_t *p_nit_n)
{
return ((p_nit_n[4] & 0xf) << 8) | p_nit_n[5];
}
static inline uint8_t *nitn_get_descs(uint8_t *p_nit_n)
{
return &p_nit_n[4];
}
static inline uint8_t *nit_get_header2(uint8_t *p_nit)
{
return p_nit + NIT_HEADER_SIZE + nit_get_desclength(p_nit);
}
static inline uint8_t *nit_get_ts(uint8_t *p_nit, uint8_t n)
{
uint16_t i_section_size = psi_get_length(p_nit) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
uint8_t *p_nit_n = p_nit + NIT_HEADER_SIZE + nit_get_desclength(p_nit)
+ NIT_HEADER2_SIZE;
if (p_nit_n - p_nit > i_section_size) return NULL;
while (n) {
if (p_nit_n + NIT_TS_SIZE - p_nit > i_section_size) return NULL;
p_nit_n += NIT_TS_SIZE + nitn_get_desclength(p_nit_n);
n--;
}
if (p_nit_n - p_nit >= i_section_size) return NULL;
return p_nit_n;
}
static inline bool nit_validate(const uint8_t *p_nit)
{
uint16_t i_section_size = psi_get_length(p_nit) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
const uint8_t *p_nit_n;
if (!psi_get_syntax(p_nit)
|| (psi_get_tableid(p_nit) != NIT_TABLE_ID_ACTUAL
&& psi_get_tableid(p_nit) != NIT_TABLE_ID_OTHER))
return false;
if (i_section_size < NIT_HEADER_SIZE
|| i_section_size < NIT_HEADER_SIZE + nit_get_desclength(p_nit))
return false;
if (!descs_validate(p_nit + 8))
return false;
p_nit_n = p_nit + NIT_HEADER_SIZE + nit_get_desclength(p_nit);
if (nith_get_tslength(p_nit_n) != p_nit + i_section_size - p_nit_n
- NIT_HEADER2_SIZE)
return false;
p_nit_n += NIT_HEADER2_SIZE;
while (p_nit_n + NIT_TS_SIZE - p_nit <= i_section_size
&& p_nit_n + NIT_TS_SIZE + nitn_get_desclength(p_nit_n) - p_nit
<= i_section_size) {
if (!descs_validate(p_nit_n + 4))
return false;
p_nit_n += NIT_TS_SIZE + nitn_get_desclength(p_nit_n);
}
return (p_nit_n - p_nit == i_section_size);
}
/*****************************************************************************
* Service Description Table
*****************************************************************************/
#define SDT_PID 0x11
#define SDT_TABLE_ID_ACTUAL 0x42
#define SDT_TABLE_ID_OTHER 0x46
#define SDT_HEADER_SIZE (PSI_HEADER_SIZE_SYNTAX1 + 3)
#define SDT_SERVICE_SIZE 5
#define sdt_set_tsid psi_set_tableidext
#define sdt_get_tsid psi_get_tableidext
static inline void sdt_init(uint8_t *p_sdt, bool b_actual)
{
psi_init(p_sdt, true);
psi_set_tableid(p_sdt, b_actual ? SDT_TABLE_ID_ACTUAL : SDT_TABLE_ID_OTHER);
p_sdt[10] = 0xff;
}
static inline void sdt_set_length(uint8_t *p_sdt, uint16_t i_sdt_length)
{
psi_set_length(p_sdt, SDT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+ i_sdt_length);
}
static inline void sdt_set_onid(uint8_t *p_sdt, uint16_t i_onid)
{
p_sdt[8] = i_onid >> 8;
p_sdt[9] = i_onid & 0xff;
}
static inline uint16_t sdt_get_onid(const uint8_t *p_sdt)
{
return (p_sdt[8] << 8) | p_sdt[9];
}
static inline void sdtn_init(uint8_t *p_sdt_n)
{
p_sdt_n[2] = 0xfc;
}
static inline void sdtn_set_sid(uint8_t *p_sdt_n, uint16_t i_sid)
{
p_sdt_n[0] = i_sid >> 8;
p_sdt_n[1] = i_sid & 0xff;
}
static inline uint16_t sdtn_get_sid(const uint8_t *p_sdt_n)
{
return (p_sdt_n[0] << 8) | p_sdt_n[1];
}
static inline void sdtn_set_eitschedule(uint8_t *p_sdt_n)
{
p_sdt_n[2] |= 0x2;
}
static inline bool sdtn_get_eitschedule(const uint8_t *p_sdt_n)
{
return p_sdt_n[2] & 0x2;
}
static inline void sdtn_set_eitpresent(uint8_t *p_sdt_n)
{
p_sdt_n[2] |= 0x1;
}
static inline bool sdtn_get_eitpresent(const uint8_t *p_sdt_n)
{
return p_sdt_n[2] & 0x1;
}
static inline void sdtn_set_running(uint8_t *p_sdt_n, uint8_t i_running)
{
p_sdt_n[3] &= 0x1f;
p_sdt_n[3] |= i_running << 5;
}
static inline uint8_t sdtn_get_running(const uint8_t *p_sdt_n)
{
return p_sdt_n[3] >> 5;
}
static inline void sdtn_set_ca(uint8_t *p_sdt_n)
{
p_sdt_n[3] |= 0x10;
}
static inline bool sdtn_get_ca(const uint8_t *p_sdt_n)
{
return p_sdt_n[3] & 0x10;
}
static inline void sdtn_set_desclength(uint8_t *p_sdt_n, uint16_t i_length)
{
p_sdt_n[3] &= ~0xf;
p_sdt_n[3] |= (i_length >> 8) & 0xf;
p_sdt_n[4] = i_length & 0xff;
}
static inline uint16_t sdtn_get_desclength(const uint8_t *p_sdt_n)
{
return ((p_sdt_n[3] & 0xf) << 8) | p_sdt_n[4];
}
static inline uint8_t *sdtn_get_descs(uint8_t *p_sdt_n)
{
return &p_sdt_n[3];
}
static inline uint8_t *sdt_get_service(uint8_t *p_sdt, uint8_t n)
{
uint16_t i_section_size = psi_get_length(p_sdt) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
uint8_t *p_sdt_n = p_sdt + SDT_HEADER_SIZE;
while (n) {
if (p_sdt_n + SDT_SERVICE_SIZE - p_sdt > i_section_size) return NULL;
p_sdt_n += SDT_SERVICE_SIZE + sdtn_get_desclength(p_sdt_n);
n--;
}
if (p_sdt_n - p_sdt >= i_section_size) return NULL;
return p_sdt_n;
}
static inline bool sdt_validate(const uint8_t *p_sdt)
{
uint16_t i_section_size = psi_get_length(p_sdt) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
const uint8_t *p_sdt_n;
if (!psi_get_syntax(p_sdt)
|| (psi_get_tableid(p_sdt) != SDT_TABLE_ID_ACTUAL
&& psi_get_tableid(p_sdt) != SDT_TABLE_ID_OTHER))
return false;
p_sdt_n = p_sdt + SDT_HEADER_SIZE;
while (p_sdt_n + SDT_SERVICE_SIZE - p_sdt <= i_section_size
&& p_sdt_n + SDT_SERVICE_SIZE + sdtn_get_desclength(p_sdt_n) - p_sdt
<= i_section_size) {
if (!descs_validate(p_sdt_n + 3))
return false;
p_sdt_n += SDT_SERVICE_SIZE + sdtn_get_desclength(p_sdt_n);
}
return (p_sdt_n - p_sdt == i_section_size);
}
static inline uint8_t *sdt_table_find_service(uint8_t **pp_sections,
uint16_t i_sid)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_service;
int j = 0;
while ((p_service = sdt_get_service(p_section, j)) != NULL) {
if (sdtn_get_sid(p_service) == i_sid)
return p_service;
j++;
}
}
return NULL;
}
/*****************************************************************************
* Event Information Table
*****************************************************************************/
#define EIT_PID 0x12
#define EIT_TABLE_ID_PF_ACTUAL 0x4e
#define EIT_TABLE_ID_PF_OTHER 0x4f
#define EIT_TABLE_ID_SCHED_ACTUAL_FIRST 0x50
#define EIT_TABLE_ID_SCHED_ACTUAL_LAST 0x5f
#define EIT_TABLE_ID_SCHED_OTHER_FIRST 0x60
#define EIT_TABLE_ID_SCHED_OTHER_LAST 0x6f
#define EIT_HEADER_SIZE (PSI_HEADER_SIZE_SYNTAX1 + 6)
#define EIT_EVENT_SIZE 12
#define eit_set_sid psi_set_tableidext
#define eit_get_sid psi_get_tableidext
static inline void eit_init(uint8_t *p_eit, bool b_actual)
{
psi_init(p_eit, true);
psi_set_tableid(p_eit, b_actual ? EIT_TABLE_ID_PF_ACTUAL :
EIT_TABLE_ID_PF_OTHER);
}
static inline void eit_set_length(uint8_t *p_eit, uint16_t i_eit_length)
{
psi_set_length(p_eit, EIT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+ i_eit_length);
}
static inline void eit_set_tsid(uint8_t *p_eit, uint16_t i_tsid)
{
p_eit[8] = i_tsid >> 8;
p_eit[9] = i_tsid & 0xff;
}
static inline uint16_t eit_get_tsid(const uint8_t *p_eit)
{
return (p_eit[8] << 8) | p_eit[9];
}
static inline uint16_t eitn_get_desclength(const uint8_t *p_eit_n)
{
return ((p_eit_n[10] & 0xf) << 8) | p_eit_n[11];
}
static inline bool eit_validate(const uint8_t *p_eit)
{
uint16_t i_section_size = psi_get_length(p_eit) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
uint8_t i_tid = psi_get_tableid(p_eit);
const uint8_t *p_eit_n;
if (!psi_get_syntax(p_eit)
|| (i_tid != EIT_TABLE_ID_PF_ACTUAL
&& i_tid != EIT_TABLE_ID_PF_OTHER
&& !(i_tid >= EIT_TABLE_ID_SCHED_ACTUAL_FIRST
&& i_tid <= EIT_TABLE_ID_SCHED_ACTUAL_LAST)
&& !(i_tid >= EIT_TABLE_ID_SCHED_OTHER_FIRST
&& i_tid <= EIT_TABLE_ID_SCHED_OTHER_LAST)))
return false;
p_eit_n = p_eit + EIT_HEADER_SIZE;
while (p_eit_n + EIT_EVENT_SIZE - p_eit <= i_section_size
&& p_eit_n + EIT_EVENT_SIZE + eitn_get_desclength(p_eit_n) - p_eit
<= i_section_size) {
if (!descs_validate(p_eit_n + 10))
return false;
p_eit_n += EIT_EVENT_SIZE + eitn_get_desclength(p_eit_n);
}
return (p_eit_n - p_eit == i_section_size);
}
/* TODO: unfinished support */
/*****************************************************************************
* Running Status Table
*****************************************************************************/
#define RST_PID 0x13
#define RST_TABLE_ID 0x71
#define RST_HEADER_SIZE PSI_HEADER_SIZE
#define RST_EVENT_SIZE 9
/* TODO: unfinished support */
/*****************************************************************************
* Time and Date Table
*****************************************************************************/
#define TDT_PID 0x14
#define TDT_TABLE_ID 0x70
#define TDT_HEADER_SIZE (PSI_HEADER_SIZE + 5)
static inline void tdt_init(uint8_t *p_tdt)
{
psi_init(p_tdt, false);
psi_set_tableid(p_tdt, TDT_TABLE_ID);
psi_set_length(p_tdt, TDT_HEADER_SIZE - PSI_HEADER_SIZE);
}
static inline void tdt_set_utc(uint8_t *p_tdt, uint64_t i_utc)
{
p_tdt[3] = (i_utc >> 32) & 0xff;
p_tdt[4] = (i_utc >> 24) & 0xff;
p_tdt[5] = (i_utc >> 16) & 0xff;
p_tdt[6] = (i_utc >> 8) & 0xff;
p_tdt[7] = i_utc & 0xff;
}
static inline uint64_t tdt_get_utc(const uint8_t *p_tdt)
{
return ((uint64_t)p_tdt[3] << 32) | (p_tdt[4] << 24) | (p_tdt[5] << 16)
| (p_tdt[6] << 8) | p_tdt[7];
}
static inline bool tdt_validate(const uint8_t *p_tdt)
{
uint16_t i_section_size = psi_get_length(p_tdt) + PSI_HEADER_SIZE;
uint8_t i_tid = psi_get_tableid(p_tdt);
if (psi_get_syntax(p_tdt) || i_tid != TDT_TABLE_ID
|| i_section_size < TDT_HEADER_SIZE)
return false;
return true;
}
/*****************************************************************************
* Time Offset Table
*****************************************************************************/
#define TOT_PID 0x14
#define TOT_TABLE_ID 0x73
#define TOT_HEADER_SIZE (PSI_HEADER_SIZE + 7)
#define tot_set_utc tdt_set_utc
#define tot_get_utc tdt_get_utc
static inline void tot_init(uint8_t *p_tot)
{
psi_init(p_tot, false);
psi_set_tableid(p_tot, TOT_TABLE_ID);
p_tot[8] = 0xf0;
}
static inline void tot_set_desclength(uint8_t *p_tot, uint16_t i_length)
{
p_tot[8] &= ~0xf;
p_tot[8] |= i_length >> 8;
p_tot[9] = i_length & 0xff;
}
static inline uint16_t tot_get_desclength(const uint8_t *p_tot)
{
return ((p_tot[8] & 0xf) << 8) | p_tot[9];
}
static inline bool tot_validate(const uint8_t *p_tot)
{
uint16_t i_section_size = psi_get_length(p_tot) + PSI_HEADER_SIZE;
uint8_t i_tid = psi_get_tableid(p_tot);
if (psi_get_syntax(p_tot) || i_tid != TOT_TABLE_ID
|| i_section_size < TOT_HEADER_SIZE + PSI_CRC_SIZE)
return false;
/* TOT is a syntax0 table with CRC */
if (!psi_check_crc(p_tot))
return false;
if (i_section_size < TOT_HEADER_SIZE
|| i_section_size < TOT_HEADER_SIZE + tot_get_desclength(p_tot))
return false;
if (!descs_validate(p_tot + 8))
return false;
return true;
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* rtp.h: Real-Time Protocol
*****************************************************************************
* Copyright (C) 2009 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - IETF RFC 3550 Real-Time Protocol (July 2003)
*/
#ifndef __BITSTREAM_IETF_RTP_H__
#define __BITSTREAM_IETF_RTP_H__
#ifdef __cplusplus
extern "C"
{
#endif
#define RTP_HEADER_SIZE 12
#define RTP_TYPE_TS 33
/*
* Reminder : RTP header
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static inline void rtp_set_hdr(uint8_t *p_rtp)
{
p_rtp[0] = 0x80;
}
static inline bool rtp_check_hdr(const uint8_t *p_rtp)
{
return (p_rtp[0] & 0xc0) == 0x80;
}
static inline void rtp_set_type(uint8_t *p_rtp, uint8_t i_type)
{
p_rtp[1] = i_type;
}
static inline uint8_t rtp_get_type(const uint8_t *p_rtp)
{
return p_rtp[1] & 0x7f;
}
static inline void rtp_set_cc(uint8_t *p_rtp, uint16_t i_rtp_cc)
{
p_rtp[2] = i_rtp_cc >> 8;
p_rtp[3] = i_rtp_cc & 0xff;
}
static inline uint16_t rtp_get_cc(uint8_t *p_rtp)
{
return (p_rtp[2] << 8) | p_rtp[3];
}
static inline void rtp_set_timestamp(uint8_t *p_rtp, uint32_t i_timestamp)
{
p_rtp[4] = (i_timestamp >> 24) & 0xff;
p_rtp[5] = (i_timestamp >> 16) & 0xff;
p_rtp[6] = (i_timestamp >> 8) & 0xff;
p_rtp[7] = i_timestamp & 0xff;
}
static inline uint32_t rtp_get_timestamp(uint8_t *p_rtp)
{
return (p_rtp[4] << 24) | (p_rtp[5] << 16) | (p_rtp[6] << 8) | p_rtp[7];
}
static inline void rtp_set_ssrc(uint8_t *p_rtp, const uint8_t pi_ssrc[4])
{
p_rtp[8] = pi_ssrc[0];
p_rtp[9] = pi_ssrc[1];
p_rtp[10] = pi_ssrc[2];
p_rtp[11] = pi_ssrc[3];
}
static inline void rtp_get_ssrc(uint8_t *p_rtp, uint8_t pi_ssrc[4])
{
pi_ssrc[0] = p_rtp[8];
pi_ssrc[1] = p_rtp[9];
pi_ssrc[2] = p_rtp[10];
pi_ssrc[3] = p_rtp[11];
}
static inline uint8_t *rtp_payload(uint8_t *p_rtp)
{
unsigned int i_size = RTP_HEADER_SIZE;
i_size += 4 * (p_rtp[0] & 0xf);
if (p_rtp[0] & 0x10) /* header extension */
i_size += 4 + (p_rtp[i_size + 2] << 8) + p_rtp[i_size + 3];
return p_rtp + i_size;
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* aac.h: ISO/IEC 14496-3 Advanced Audio Coding
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ISO/IEC 14496-3 Subpart 4:1998(E)
* (Advanced Audio Coding, Time/Frequency Coding)
*/
#ifndef __BITSTREAM_MPEG_AAC_H__
#define __BITSTREAM_MPEG_AAC_H__
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* ADTS header
*****************************************************************************/
#define ADTS_HEADER_SIZE 7
/* fixed header */
static inline void adts_set_sync(uint8_t *p_adts)
{
p_adts[0] = 0xff;
p_adts[1] = 0xf9; /* protection absent */
p_adts[2] = 0x0;
p_adts[3] = 0x0;
p_adts[4] = 0x0;
p_adts[5] = 0x0;
p_adts[6] = 0x0;
}
static inline void adts_set_profile(uint8_t *p_adts, uint8_t i_profile)
{
p_adts[2] &= ~0xc0;
p_adts[2] |= i_profile << 6;
}
static inline void adts_set_index(uint8_t *p_adts, uint8_t i_index)
{
p_adts[2] &= ~0x3c;
p_adts[2] |= (i_index & 0xf) << 2;
}
static inline void adts_set_channels(uint8_t *p_adts, uint8_t i_channels)
{
p_adts[2] &= ~0x03; /* also clear out the private bit */
p_adts[2] |= (i_channels & 0x7) >> 2;
p_adts[3] &= ~0xc0;
p_adts[3] |= (i_channels & 0x7) << 6;
}
static inline void adts_set_copy(uint8_t *p_adts, bool b_copy)
{
if (!b_copy)
p_adts[3] &= ~0x20;
else
p_adts[3] |= 0x20;
}
static inline void adts_set_home(uint8_t *p_adts, bool b_home)
{
if (!b_home)
p_adts[3] &= ~0x10;
else
p_adts[3] |= 0x10;
}
/* variable header */
static inline void adts_set_cp_id(uint8_t *p_adts, bool b_bit, bool b_start)
{
p_adts[3] &= ~0x0c;
if (b_bit)
p_adts[3] |= 0x08;
if (b_start)
p_adts[3] |= 0x04;
}
static inline void adts_set_length(uint8_t *p_adts, uint16_t i_length)
{
p_adts[3] &= ~0x03;
p_adts[3] |= (i_length >> 11) & 0x03;
p_adts[4] = i_length >> 3;
p_adts[5] &= ~0xe0;
p_adts[5] |= (i_length << 5) & 0xe0;
}
static inline void adts_set_fullness(uint8_t *p_adts, uint16_t i_fullness)
{
p_adts[5] &= ~0x1f;
p_adts[5] |= (i_fullness >> 6) & 0x1f;
p_adts[6] &= ~0xfc;
p_adts[6] |= (i_fullness << 2) & 0xfc;
}
/* i_blocks == number of blocks - 1 */
static inline void adts_set_num_blocks(uint8_t *p_adts, uint8_t i_blocks)
{
p_adts[6] &= ~0x03;
p_adts[6] |= i_blocks & 0x03;
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* pes.h: ISO/IEC 13818-1 Packetized Elementary Stream
*****************************************************************************
* Copyright (C) 2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ISO/IEC 13818-1:2007(E) (MPEG-2 systems)
*/
#ifndef __BITSTREAM_MPEG_PES_H__
#define __BITSTREAM_MPEG_PES_H__
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* PES header
*****************************************************************************/
#define PES_HEADER_SIZE 6
#define PES_HEADER_SIZE_NOPTS 9
#define PES_HEADER_SIZE_PTS 14
#define PES_HEADER_SIZE_PTSDTS 19
#define PES_STREAM_ID_MIN 0xbc
#define PES_STREAM_ID_PRIVATE_1 0xbd
#define PES_STREAM_ID_PRIVATE_2 0xbf
#define PES_STREAM_ID_AUDIO_MPEG 0xc0
#define PES_STREAM_ID_VIDEO_MPEG 0xe0
static inline void pes_init(uint8_t *p_pes)
{
p_pes[0] = 0x0;
p_pes[1] = 0x0;
p_pes[2] = 0x1;
p_pes[6] = 0x80;
p_pes[7] = 0x0;
p_pes[8] = 0x0;
}
static inline void pes_set_streamid(uint8_t *p_pes, uint8_t i_stream_id)
{
p_pes[3] = i_stream_id;
}
static inline void pes_set_length(uint8_t *p_pes, uint16_t i_length)
{
p_pes[4] = i_length >> 8;
p_pes[5] = i_length & 0xff;
}
static inline void pes_set_headerlength(uint8_t *p_pes, uint8_t i_length)
{
p_pes[6] = 0x80;
p_pes[7] = 0x0;
p_pes[8] = i_length;
if ( i_length > 0 )
memset( &p_pes[9], 0xff, i_length ); /* stuffing */
}
static inline uint8_t pes_get_headerlength(const uint8_t *p_pes)
{
return p_pes[8];
}
static inline void pes_set_dataalignment(uint8_t *p_pes)
{
p_pes[6] |= 0x4;
}
static inline void pes_set_pts(uint8_t *p_pes, uint64_t i_pts)
{
p_pes[7] |= 0x80;
if (p_pes[8] < 5)
p_pes[8] = 5;
p_pes[9] = 0x21 | ((i_pts >> 29) & 0xe);
p_pes[10] = (i_pts >> 22) & 0xff;
p_pes[11] = 0x1 | ((i_pts >> 14) & 0xfe);
p_pes[12] = (i_pts >> 7) & 0xff;
p_pes[13] = 0x1 | ((i_pts << 1) & 0xfe);
}
static inline void pes_set_dts(uint8_t *p_pes, uint64_t i_dts)
{
p_pes[7] |= 0x40;
if (p_pes[8] < 10)
p_pes[8] = 10;
p_pes[14] = 0x11 | ((i_dts >> 29) & 0xe);
p_pes[15] = (i_dts >> 22) & 0xff;
p_pes[16] = 0x1 | ((i_dts >> 14) & 0xfe);
p_pes[17] = (i_dts >> 7) & 0xff;
p_pes[18] = 0x1 | ((i_dts << 1) & 0xfe);
}
static inline bool pes_validate(const uint8_t *p_pes)
{
return (p_pes[0] == 0x0 && p_pes[1] == 0x0 && p_pes[2] == 0x1
&& p_pes[3] >= PES_STREAM_ID_MIN);
}
/*****************************************************************************
* PES payload
*****************************************************************************/
static inline uint8_t *pes_payload(uint8_t *p_pes)
{
return p_pes + PES_HEADER_SIZE + pes_get_headerlength(p_pes);
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* psi.h: ISO/IEC 13818-1 Program Stream Information
*****************************************************************************
* Copyright (C) 2009-2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ISO/IEC 13818-1:2007(E) (MPEG-2 Systems)
*/
#ifndef __BITSTREAM_MPEG_PSI_H__
#define __BITSTREAM_MPEG_PSI_H__
#include <bitstream/mpeg/ts.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* Descriptor
*****************************************************************************/
#define DESC_HEADER_SIZE 2
#define DESC_MAX_STRING1 256
#define DESC_DECLARE_STRING1(p_string) \
char p_string[DESC_MAX_STRING1]
static inline void desc_set_tag(uint8_t *p_desc, uint8_t i_tag)
{
p_desc[0] = i_tag;
}
static inline uint8_t desc_get_tag(const uint8_t *p_desc)
{
return p_desc[0];
}
static inline void desc_set_length(uint8_t *p_desc, uint8_t i_length)
{
p_desc[1] = i_length;
}
static inline uint8_t desc_get_length(const uint8_t *p_desc)
{
return p_desc[1];
}
/*****************************************************************************
* Descriptor 0x05: Registration descriptor
*****************************************************************************/
#define DESC05_HEADER_SIZE 6
static inline void desc05_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x05);
desc_set_length(p_desc, DESC05_HEADER_SIZE);
}
static inline void desc05_set_identifier(uint8_t *p_desc, uint8_t p_id[4])
{
p_desc[2] = p_id[0];
p_desc[3] = p_id[1];
p_desc[4] = p_id[2];
p_desc[5] = p_id[3];
}
/*****************************************************************************
* Descriptor 0x09: Conditional access descriptor
*****************************************************************************/
#define DESC09_HEADER_SIZE 6
static inline uint16_t desc09_get_sysid(const uint8_t *p_desc)
{
return (p_desc[2] << 8) | p_desc[3];
}
static inline uint16_t desc09_get_pid(const uint8_t *p_desc)
{
return ((p_desc[4] & 0x1f) << 8) | p_desc[5];
}
/*****************************************************************************
* Descriptor 0x0a: ISO-639 language descriptor
*****************************************************************************/
#define DESC0A_HEADER_SIZE DESC_HEADER_SIZE
#define DESC0A_LANGUAGE_SIZE 4
static inline void desc0a_init(uint8_t *p_desc)
{
desc_set_tag(p_desc, 0x0a);
}
static inline uint8_t *desc0a_get_language(uint8_t *p_desc, uint8_t n)
{
uint8_t *p_desc_n = p_desc + DESC0A_HEADER_SIZE + n * DESC0A_LANGUAGE_SIZE;
if (p_desc_n - p_desc > desc_get_length(p_desc) + DESC0A_HEADER_SIZE)
return NULL;
return p_desc_n;
}
static inline void desc0an_set_code(uint8_t *p_desc_n, const uint8_t p_code[3])
{
p_desc_n[0] = p_code[0];
p_desc_n[1] = p_code[1];
p_desc_n[2] = p_code[2];
}
static inline void desc0an_set_audiotype(uint8_t *p_desc_n, uint8_t i_type)
{
p_desc_n[3] = i_type;
}
/*****************************************************************************
* Descriptors list
*****************************************************************************/
#define DESCS_HEADER_SIZE 2
#define DESCS_MAX_SIZE 4095
static inline void descs_set_length(uint8_t *p_descs, uint16_t i_length)
{
p_descs[0] &= 0xf0;
p_descs[0] |= (i_length >> 8) & 0xf;
p_descs[1] = i_length & 0xff;
}
static inline uint16_t descs_get_length(const uint8_t *p_descs)
{
return ((p_descs[0] & 0xf) << 8) | p_descs[1];
}
static inline uint8_t *descs_get_desc(uint8_t *p_descs, uint16_t n)
{
uint8_t *p_desc = p_descs + DESCS_HEADER_SIZE;
uint16_t i_descs_size = descs_get_length(p_descs) + DESCS_HEADER_SIZE;
while (n) {
if (p_desc + DESC_HEADER_SIZE - p_descs > i_descs_size) return NULL;
p_desc += DESC_HEADER_SIZE + desc_get_length(p_desc);
n--;
}
if (p_desc - p_descs >= i_descs_size) return NULL;
return p_desc;
}
static inline bool descs_validate(const uint8_t *p_descs)
{
const uint8_t *p_desc = p_descs + DESCS_HEADER_SIZE;
uint16_t i_descs_size = descs_get_length(p_descs) + DESCS_HEADER_SIZE;
while (p_desc + DESC_HEADER_SIZE - p_descs <= i_descs_size)
p_desc += DESC_HEADER_SIZE + desc_get_length(p_desc);
return (p_desc - p_descs == i_descs_size);
}
/*****************************************************************************
* s_crc32_table
*****************************************************************************
* 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:
*
* uint32_t table[256];
* uint32_t i, j, k;
*
* for(i = 0; i < 256; i++)
* {
* k = 0;
* for (j = (i << 24) | 0x800000; j != 0x80000000; j <<= 1)
* k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
* table[i] = k;
* }
*
* A CRC is computed like this:
*
* initialization
* --------------
* uint32_t i_crc = 0xffffffff;
*
* for each data byte do
* ---------------------
* i_crc = (i_crc << 8) ^ s_crc32_table[(i_crc >> 24) ^ (data_byte)];
*****************************************************************************/
#define PSI_CRC_TABLE \
{ \
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, \
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, \
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, \
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, \
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, \
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, \
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, \
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, \
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, \
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, \
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, \
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, \
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, \
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, \
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, \
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, \
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, \
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, \
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, \
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, \
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, \
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, \
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, \
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, \
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, \
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, \
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, \
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, \
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, \
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, \
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, \
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, \
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, \
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, \
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, \
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, \
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, \
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, \
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, \
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, \
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, \
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, \
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, \
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, \
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, \
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, \
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, \
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, \
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, \
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, \
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, \
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, \
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, \
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, \
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, \
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, \
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, \
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, \
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, \
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, \
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, \
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, \
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, \
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 \
}
/*****************************************************************************
* PSI section
*****************************************************************************/
#define PSI_HEADER_SIZE 3
#define PSI_HEADER_SIZE_SYNTAX1 8
#define PSI_CRC_SIZE 4
#define PSI_MAX_SIZE 1021
#define PSI_PRIVATE_MAX_SIZE 4093
#define PSI_DECLARE(p_table) \
uint8_t p_table[PSI_MAX_SIZE + PSI_HEADER_SIZE]
#define PSI_PRIVATE_DECLARE(p_table) \
uint8_t p_table[PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE]
static inline uint8_t *psi_allocate(void)
{
return malloc((PSI_MAX_SIZE + PSI_HEADER_SIZE) * sizeof(uint8_t));
}
static inline uint8_t *psi_private_allocate(void)
{
return malloc((PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE) * sizeof(uint8_t));
}
static inline void psi_set_tableid(uint8_t *p_section, uint8_t i_table_id)
{
p_section[0] = i_table_id;
}
static inline uint8_t psi_get_tableid(const uint8_t *p_section)
{
return p_section[0];
}
static inline void psi_set_syntax(uint8_t *p_section)
{
p_section[1] |= 0x80;
}
static inline bool psi_get_syntax(const uint8_t *p_section)
{
return p_section[1] & 0x80;
}
static inline void psi_init(uint8_t *p_section, bool b_syntax)
{
/* set reserved bits */
p_section[1] = 0x70;
if (b_syntax) {
psi_set_syntax(p_section);
p_section[5] = 0xc0;
}
}
static inline void psi_set_length(uint8_t *p_section, uint16_t i_length)
{
p_section[1] &= ~0xf;
p_section[1] |= (i_length >> 8) & 0xf;
p_section[2] = i_length & 0xff;
}
static inline uint16_t psi_get_length(const uint8_t *p_section)
{
return ((p_section[1] & 0xf) << 8) | p_section[2];
}
static inline void psi_set_tableidext(uint8_t *p_section,
uint16_t i_table_id_ext)
{
p_section[3] = i_table_id_ext >> 8;
p_section[4] = i_table_id_ext & 0xff;
}
static inline uint16_t psi_get_tableidext(const uint8_t *p_section)
{
return (p_section[3] << 8) | p_section[4];
}
static inline void psi_set_version(uint8_t *p_section, uint8_t i_version)
{
p_section[5] = i_version << 1;
}
static inline uint8_t psi_get_version(uint8_t *p_section)
{
return (p_section[5] & 0x1e) >> 1;
}
static inline void psi_set_current(uint8_t *p_section)
{
p_section[5] |= 0x1;
}
static inline bool psi_get_current(const uint8_t *p_section)
{
return (p_section[5] & 0x1);
}
static inline void psi_set_section(uint8_t *p_section, uint8_t i_section)
{
p_section[6] = i_section;
}
static inline uint8_t psi_get_section(const uint8_t *p_section)
{
return p_section[6];
}
static inline void psi_set_lastsection(uint8_t *p_section,
uint8_t i_last_section)
{
p_section[7] = i_last_section;
}
static inline uint8_t psi_get_lastsection(const uint8_t *p_section)
{
return p_section[7];
}
/*****************************************************************************
* PSI validation
*****************************************************************************/
static inline void psi_set_crc(uint8_t *p_section)
{
static const uint32_t s_crc32_table[256] = PSI_CRC_TABLE;
uint32_t i_crc = 0xffffffff;
uint16_t i_end = (((p_section[1] & 0xf) << 8) | p_section[2])
+ PSI_HEADER_SIZE - PSI_CRC_SIZE;
uint16_t i;
for (i = 0; i < i_end; i++)
i_crc = (i_crc << 8) ^ s_crc32_table[(i_crc >> 24) ^ (p_section[i])];
p_section[i_end] = i_crc >> 24;
p_section[i_end + 1] = (i_crc >> 16) & 0xff;
p_section[i_end + 2] = (i_crc >> 8) & 0xff;
p_section[i_end + 3] = i_crc & 0xff;
}
static inline bool psi_check_crc(const uint8_t *p_section)
{
static const uint32_t s_crc32_table[256] = PSI_CRC_TABLE;
uint32_t i_crc = 0xffffffff;
uint16_t i_end = (((p_section[1] & 0xf) << 8) | p_section[2])
+ PSI_HEADER_SIZE - PSI_CRC_SIZE;
uint16_t i;
for (i = 0; i < i_end; i++)
i_crc = (i_crc << 8) ^ s_crc32_table[(i_crc >> 24) ^ (p_section[i])];
return p_section[i_end] == (i_crc >> 24)
&& p_section[i_end + 1] == ((i_crc >> 16) & 0xff)
&& p_section[i_end + 2] == ((i_crc >> 8) & 0xff)
&& p_section[i_end + 3] == (i_crc & 0xff);
}
static inline bool psi_validate(const uint8_t *p_section)
{
if (psi_get_syntax(p_section)
&& (psi_get_length(p_section) < PSI_HEADER_SIZE_SYNTAX1
- PSI_HEADER_SIZE + PSI_CRC_SIZE))
return false;
if (psi_get_syntax(p_section) && !psi_check_crc(p_section))
return false;
return true;
}
/*****************************************************************************
* PSI section gathering
*****************************************************************************/
static inline void psi_assemble_init(uint8_t **pp_psi_buffer,
uint16_t *pi_psi_buffer_used)
{
*pp_psi_buffer = NULL;
*pi_psi_buffer_used = 0;
}
static inline void psi_assemble_reset(uint8_t **pp_psi_buffer,
uint16_t *pi_psi_buffer_used)
{
free(*pp_psi_buffer);
psi_assemble_init(pp_psi_buffer, pi_psi_buffer_used);
}
static inline bool psi_assemble_empty(uint8_t **pp_psi_buffer,
uint16_t *pi_psi_buffer_used)
{
return *pp_psi_buffer == NULL;
}
static inline uint8_t *psi_assemble_payload(uint8_t **pp_psi_buffer,
uint16_t *pi_psi_buffer_used,
const uint8_t **pp_payload,
uint8_t *pi_length)
{
uint16_t i_remaining_size = PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE
- *pi_psi_buffer_used;
uint16_t i_copy_size = *pi_length < i_remaining_size ? *pi_length :
i_remaining_size;
uint8_t *p_section = NULL;
if (*pp_psi_buffer == NULL) {
if (**pp_payload == 0xff) {
/* padding table to the end of buffer */
*pi_length = 0;
return NULL;
}
*pp_psi_buffer = psi_private_allocate();
}
memcpy( *pp_psi_buffer + *pi_psi_buffer_used, *pp_payload, i_copy_size );
*pi_psi_buffer_used += i_copy_size;
if (*pi_psi_buffer_used >= PSI_HEADER_SIZE) {
uint16_t i_section_size = psi_get_length(*pp_psi_buffer)
+ PSI_HEADER_SIZE;
if (i_section_size <= *pi_psi_buffer_used) {
p_section = *pp_psi_buffer;
i_copy_size -= (*pi_psi_buffer_used - i_section_size);
*pp_psi_buffer = NULL;
*pi_psi_buffer_used = 0;
}
}
*pp_payload += i_copy_size;
*pi_length -= i_copy_size;
return p_section;
}
/*****************************************************************************
* PSI section splitting
*****************************************************************************/
static inline void psi_split_end(uint8_t *p_ts, uint8_t *pi_ts_offset)
{
if (*pi_ts_offset != TS_SIZE) {
memset(p_ts + *pi_ts_offset, 0xff, TS_SIZE - *pi_ts_offset);
*pi_ts_offset = TS_SIZE;
}
}
static inline void psi_split_section(uint8_t *p_ts, uint8_t *pi_ts_offset,
const uint8_t *p_section,
uint16_t *pi_section_offset)
{
uint16_t i_section_length = psi_get_length(p_section) + PSI_HEADER_SIZE
- *pi_section_offset;
uint8_t i_ts_length, i_copy;
if (!*pi_ts_offset) {
ts_init(p_ts);
ts_set_payload(p_ts);
*pi_ts_offset = ts_payload(p_ts) - p_ts;
}
if (!*pi_section_offset) {
if (TS_SIZE - *pi_ts_offset < 2) {
psi_split_end(p_ts, pi_ts_offset);
return;
}
if (!ts_get_unitstart(p_ts)) {
uint8_t *p_payload = ts_payload(p_ts);
uint8_t i_payload_length = *pi_ts_offset - (p_payload - p_ts);
if (i_payload_length)
memmove(p_payload + 1, p_payload, i_payload_length);
(*pi_ts_offset)++;
*p_payload = i_payload_length; /* pointer_field */
ts_set_unitstart(p_ts);
}
}
i_ts_length = TS_SIZE - *pi_ts_offset;
i_copy = i_ts_length < i_section_length ?
i_ts_length : i_section_length;
memcpy(p_ts + *pi_ts_offset, p_section + *pi_section_offset, i_copy);
*pi_ts_offset += i_copy;
*pi_section_offset += i_copy;
}
/*****************************************************************************
* PSI table gathering
*****************************************************************************/
#define PSI_TABLE_MAX_SECTIONS 256
#define PSI_TABLE_DECLARE(pp_table) \
uint8_t *pp_table[PSI_TABLE_MAX_SECTIONS]
static inline uint8_t **psi_table_allocate(void)
{
return malloc(PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
}
static inline void psi_table_init(uint8_t **pp_sections)
{
int i;
for (i = 0; i < PSI_TABLE_MAX_SECTIONS; i++)
pp_sections[i] = NULL;
}
static inline void psi_table_free(uint8_t **pp_sections)
{
int i;
for (i = 0; i < PSI_TABLE_MAX_SECTIONS; i++)
free(pp_sections[i]);
}
static inline bool psi_table_validate(uint8_t **pp_sections)
{
return pp_sections[0] != NULL;
}
static inline void psi_table_copy(uint8_t **pp_dest, uint8_t **pp_src)
{
memcpy(pp_dest, pp_src, PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
}
static inline uint16_t psi_table_get_tableidext(uint8_t **pp_sections)
{
return psi_get_tableidext(pp_sections[0]);
}
static inline uint8_t psi_table_get_version(uint8_t **pp_sections)
{
return psi_get_version(pp_sections[0]);
}
static inline uint8_t psi_table_get_lastsection(uint8_t **pp_sections)
{
return psi_get_lastsection(pp_sections[0]);
}
static inline bool psi_table_section(uint8_t **pp_sections, uint8_t *p_section)
{
uint8_t i_section = psi_get_section( p_section );
uint8_t i_last_section = psi_get_lastsection( p_section );
uint8_t i_version = psi_get_version( p_section );
uint16_t i_tableidext = psi_get_tableidext( p_section );
int i;
free(pp_sections[i_section]);
pp_sections[i_section] = p_section;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p = pp_sections[i];
if (p == NULL)
return false;
if (psi_get_lastsection(p) != i_last_section
|| psi_get_version(p) != i_version
|| psi_get_tableidext(p) != i_tableidext)
return false;
}
/* free spurious, invalid sections */
for (; i < PSI_TABLE_MAX_SECTIONS; i++)
free(pp_sections[i]);
/* a new, full table is available */
return true;
}
static inline uint8_t *psi_table_get_section(uint8_t **pp_sections, uint8_t n)
{
return pp_sections[n];
}
/*****************************************************************************
* Program Association Table
*****************************************************************************/
#define PAT_PID 0x0
#define PAT_TABLE_ID 0x0
#define PAT_HEADER_SIZE PSI_HEADER_SIZE_SYNTAX1
#define PAT_PROGRAM_SIZE 4
#define pat_set_tsid psi_set_tableidext
#define pat_get_tsid psi_get_tableidext
static inline void pat_init(uint8_t *p_pat)
{
psi_init(p_pat, true);
psi_set_tableid(p_pat, PAT_TABLE_ID);
p_pat[1] &= ~0x40;
}
static inline void pat_set_length(uint8_t *p_pat, uint16_t i_pat_length)
{
psi_set_length(p_pat, PAT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+ i_pat_length);
}
static inline void patn_init(uint8_t *p_pat_n)
{
p_pat_n[2] = 0xe0;
}
static inline void patn_set_program(uint8_t *p_pat_n, uint16_t i_program)
{
p_pat_n[0] = i_program >> 8;
p_pat_n[1] = i_program & 0xff;
}
static inline uint16_t patn_get_program(const uint8_t *p_pat_n)
{
return (p_pat_n[0] << 8) | p_pat_n[1];
}
static inline void patn_set_pid(uint8_t *p_pat_n, uint16_t i_pid)
{
p_pat_n[2] &= ~0x1f;
p_pat_n[2] |= i_pid >> 8;
p_pat_n[3] = i_pid & 0xff;
}
static inline uint16_t patn_get_pid(const uint8_t *p_pat_n)
{
return ((p_pat_n[2] & 0x1f) << 8) | p_pat_n[3];
}
static inline uint8_t *pat_get_program(uint8_t *p_pat, uint8_t n)
{
uint8_t *p_pat_n = p_pat + PAT_HEADER_SIZE + n * PAT_PROGRAM_SIZE;
if (p_pat_n - p_pat > psi_get_length(p_pat) + PSI_HEADER_SIZE - PSI_CRC_SIZE)
return NULL;
return p_pat_n;
}
static inline bool pat_validate(const uint8_t *p_pat)
{
if (!psi_get_syntax(p_pat) || psi_get_tableid(p_pat) != PAT_TABLE_ID)
return false;
if ((psi_get_length(p_pat) - PAT_HEADER_SIZE + PSI_HEADER_SIZE
- PSI_CRC_SIZE) % PAT_PROGRAM_SIZE)
return false;
return true;
}
static inline uint8_t *pat_table_find_program(uint8_t **pp_sections,
uint16_t i_program)
{
uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
uint8_t i;
for (i = 0; i <= i_last_section; i++) {
uint8_t *p_section = psi_table_get_section(pp_sections, i);
uint8_t *p_program;
int j = 0;
while ((p_program = pat_get_program(p_section, j)) != NULL)
{
if (patn_get_program(p_program) == i_program)
return p_program;
j++;
}
}
return NULL;
}
/*****************************************************************************
* Program Map Table
*****************************************************************************/
#define PMT_TABLE_ID 0x2
#define PMT_HEADER_SIZE (PSI_HEADER_SIZE_SYNTAX1 + 4)
#define PMT_ES_SIZE 5
#define pmt_set_program psi_set_tableidext
#define pmt_get_program psi_get_tableidext
static inline void pmt_init(uint8_t *p_pmt)
{
psi_init(p_pmt, true);
psi_set_tableid(p_pmt, PMT_TABLE_ID);
p_pmt[1] &= ~0x40;
psi_set_section(p_pmt, 0);
psi_set_lastsection(p_pmt, 0);
p_pmt[8] = 0xe0;
p_pmt[10] = 0xf0;
}
static inline void pmt_set_length(uint8_t *p_pmt, uint16_t i_pmt_length)
{
psi_set_length(p_pmt, PMT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+ i_pmt_length);
}
static inline void pmt_set_pcrpid(uint8_t *p_pmt, uint16_t i_pcr_pid)
{
p_pmt[8] &= ~0x1f;
p_pmt[8] |= i_pcr_pid >> 8;
p_pmt[9] = i_pcr_pid & 0xff;
}
static inline uint16_t pmt_get_pcrpid(const uint8_t *p_pmt)
{
return ((p_pmt[8] & 0x1f) << 8) | p_pmt[9];
}
static inline void pmt_set_desclength(uint8_t *p_pmt, uint16_t i_length)
{
p_pmt[10] &= ~0xf;
p_pmt[10] |= i_length >> 8;
p_pmt[11] = i_length & 0xff;
}
static inline uint16_t pmt_get_desclength(const uint8_t *p_pmt)
{
return ((p_pmt[10] & 0xf) << 8) | p_pmt[11];
}
static inline uint8_t *pmt_get_descs(uint8_t *p_pmt)
{
return &p_pmt[10];
}
static inline void pmtn_init(uint8_t *p_pmt_n)
{
p_pmt_n[1] = 0xe0;
p_pmt_n[3] = 0xf0;
}
static inline void pmtn_set_streamtype(uint8_t *p_pmt_n, uint8_t i_stream_type)
{
p_pmt_n[0] = i_stream_type;
}
static inline uint8_t pmtn_get_streamtype(const uint8_t *p_pmt_n)
{
return p_pmt_n[0];
}
static inline void pmtn_set_pid(uint8_t *p_pmt_n, uint16_t i_pid)
{
p_pmt_n[1] &= ~0x1f;
p_pmt_n[1] |= i_pid >> 8;
p_pmt_n[2] = i_pid & 0xff;
}
static inline uint16_t pmtn_get_pid(const uint8_t *p_pmt_n)
{
return ((p_pmt_n[1] & 0x1f) << 8) | p_pmt_n[2];
}
static inline void pmtn_set_desclength(uint8_t *p_pmt_n, uint16_t i_length)
{
p_pmt_n[3] &= ~0xf;
p_pmt_n[3] |= i_length >> 8;
p_pmt_n[4] = i_length & 0xff;
}
static inline uint16_t pmtn_get_desclength(const uint8_t *p_pmt_n)
{
return ((p_pmt_n[3] & 0xf) << 8) | p_pmt_n[4];
}
static inline uint8_t *pmtn_get_descs(uint8_t *p_pmt_n)
{
return &p_pmt_n[3];
}
static inline uint8_t *pmt_get_es(uint8_t *p_pmt, uint8_t n)
{
uint16_t i_section_size = psi_get_length(p_pmt) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
uint8_t *p_pmt_n = p_pmt + PMT_HEADER_SIZE + pmt_get_desclength(p_pmt);
if (p_pmt_n - p_pmt > i_section_size) return NULL;
while (n) {
if (p_pmt_n + PMT_ES_SIZE - p_pmt > i_section_size) return NULL;
p_pmt_n += PMT_ES_SIZE + pmtn_get_desclength(p_pmt_n);
n--;
}
if (p_pmt_n - p_pmt >= i_section_size) return NULL;
return p_pmt_n;
}
static inline bool pmt_validate(const uint8_t *p_pmt)
{
uint16_t i_section_size = psi_get_length(p_pmt) + PSI_HEADER_SIZE
- PSI_CRC_SIZE;
const uint8_t *p_pmt_n;
if (!psi_get_syntax(p_pmt) || psi_get_section(p_pmt)
|| psi_get_lastsection(p_pmt)
|| psi_get_tableid(p_pmt) != PMT_TABLE_ID)
return false;
if (i_section_size < PMT_HEADER_SIZE
|| i_section_size < PMT_HEADER_SIZE + pmt_get_desclength(p_pmt))
return false;
if (!descs_validate(p_pmt + 10))
return false;
p_pmt_n = p_pmt + PMT_HEADER_SIZE + pmt_get_desclength(p_pmt);
while (p_pmt_n + PMT_ES_SIZE - p_pmt <= i_section_size
&& p_pmt_n + PMT_ES_SIZE + pmtn_get_desclength(p_pmt_n) - p_pmt
<= i_section_size) {
if (!descs_validate(p_pmt_n + 3))
return false;
p_pmt_n += PMT_ES_SIZE + pmtn_get_desclength(p_pmt_n);
}
return (p_pmt_n - p_pmt == i_section_size);
}
static inline uint8_t *pmt_find_es(uint8_t *p_pmt, uint16_t i_pid)
{
uint8_t *p_es;
uint8_t j = 0;
while ((p_es = pmt_get_es(p_pmt, j)) != NULL) {
j++;
if (pmtn_get_pid(p_es) == i_pid)
return p_es;
}
return NULL;
}
#ifdef __cplusplus
}
#endif
#endif
/*****************************************************************************
* ts.h: ISO/IEC 13818-1 Transport Stream
*****************************************************************************
* Copyright (C) 2009-2010 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*****************************************************************************/
/*
* Normative references:
* - ISO/IEC 13818-1:2007(E) (MPEG-2 systems)
*/
#ifndef __BITSTREAM_MPEG_TS_H__
#define __BITSTREAM_MPEG_TS_H__
#ifdef __cplusplus
extern "C"
{
#endif
/*****************************************************************************
* TS header
*****************************************************************************/
#define TS_SIZE 188
#define TS_HEADER_SIZE 4
#define TS_HEADER_SIZE_AF 6
#define TS_HEADER_SIZE_PCR 12
#define TS_DECLARE(p_ts) \
uint8_t p_ts[TS_SIZE]
static inline uint8_t *ts_allocate(void)
{
return malloc(TS_SIZE * sizeof(uint8_t));
}
static inline void ts_init(uint8_t *p_ts)
{
p_ts[0] = 0x47;
p_ts[1] = 0x0;
p_ts[2] = 0x0;
p_ts[3] = 0x0;
}
static inline bool ts_get_transporterror(const uint8_t *p_ts)
{
return p_ts[1] & 0x80;
}
static inline void ts_set_unitstart(uint8_t *p_ts)
{
p_ts[1] |= 0x40;
}
static inline bool ts_get_unitstart(const uint8_t *p_ts)
{
return p_ts[1] & 0x40;
}
static inline void ts_set_transportpriority(uint8_t *p_ts)
{
p_ts[1] |= 0x20;
}
static inline bool ts_get_transportpriority(const uint8_t *p_ts)
{
return p_ts[1] & 0x20;
}
static inline void ts_set_pid(uint8_t *p_ts, uint16_t i_pid)
{
p_ts[1] &= ~0x1f;
p_ts[1] |= (i_pid >> 8) & 0x1f;
p_ts[2] = i_pid & 0xff;
}
static inline uint16_t ts_get_pid(const uint8_t *p_ts)
{
return ((p_ts[1] & 0x1f) << 8) | p_ts[2];
}
static inline void ts_set_cc(uint8_t *p_ts, uint8_t i_cc)
{
p_ts[3] &= ~0xf;
p_ts[3] |= (i_cc & 0xf);
}
static inline uint8_t ts_get_cc(const uint8_t *p_ts)
{
return p_ts[3] & 0xf;
}
static inline void ts_set_payload(uint8_t *p_ts)
{
p_ts[3] |= 0x10;
}
static inline bool ts_has_payload(const uint8_t *p_ts)
{
return p_ts[3] & 0x10;
}
static inline void ts_set_adaptation(uint8_t *p_ts, uint8_t i_length)
{
p_ts[3] |= 0x20;
p_ts[4] = i_length;
if (i_length)
p_ts[5] = 0x0;
if (i_length > 1)
memset(&p_ts[6], 0xff, i_length - 1); /* stuffing */
}
static inline bool ts_has_adaptation(const uint8_t *p_ts)
{
return (p_ts[3] & 0x20);
}
static inline uint8_t ts_get_adaptation(const uint8_t *p_ts)
{
return p_ts[4];
}
static inline void ts_set_scrambling(uint8_t *p_ts, uint8_t i_scrambling)
{
p_ts[3] &= ~0xc0;
p_ts[3] |= i_scrambling << 6;
}
static inline uint8_t ts_get_scrambling(const uint8_t *p_ts)
{
return (p_ts[3] & 0xc0) >> 6;
}
static inline bool ts_validate(const uint8_t *p_ts)
{
return p_ts[0] == 0x47;
}
/*****************************************************************************
* TS payload
*****************************************************************************/
static inline void ts_pad(uint8_t *p_ts)
{
ts_init(p_ts);
ts_set_pid(p_ts, 0x1fff);
ts_set_cc(p_ts, 0);
ts_set_payload(p_ts);
memset(p_ts + 4, 0xff, TS_SIZE - 4);
}
static inline uint8_t *ts_payload(uint8_t *p_ts)
{
if (!ts_has_payload(p_ts))
return p_ts + TS_SIZE;
if (!ts_has_adaptation(p_ts))
return p_ts + TS_HEADER_SIZE;
return p_ts + TS_HEADER_SIZE + 1 + ts_get_adaptation(p_ts);
}
static inline uint8_t *ts_section(uint8_t *p_ts)
{
uint8_t *p_payload;
if (!ts_get_unitstart(p_ts))
return p_ts + TS_SIZE;
p_payload = ts_payload(p_ts);
if (p_payload >= p_ts + TS_SIZE)
return p_ts + TS_SIZE;
return p_payload + *p_payload + 1; /* pointer_field */
}
/*****************************************************************************
* Adaptation field
*****************************************************************************/
static inline void tsaf_set_discontinuity(uint8_t *p_ts)
{
p_ts[5] |= 0x80;
}
static inline void tsaf_set_randomaccess(uint8_t *p_ts)
{
p_ts[5] |= 0x40;
}
static inline bool tsaf_has_randomaccess(const uint8_t *p_ts)
{
return p_ts[5] & 0x40;
}
static inline void tsaf_set_streampriority(uint8_t *p_ts)
{
p_ts[5] |= 0x20;
}
static inline void tsaf_set_pcr(uint8_t *p_ts, uint64_t i_pcr)
{
p_ts[5] |= 0x10;
p_ts[6] = (i_pcr >> 25) & 0xff;
p_ts[7] = (i_pcr >> 17) & 0xff;
p_ts[8] = (i_pcr >> 9) & 0xff;
p_ts[9] = (i_pcr >> 1) & 0xff;
p_ts[10] = 0x7e | ((i_pcr << 7) & 0x80);
p_ts[11] = 0;
}
static inline void tsaf_set_pcrext(uint8_t *p_ts, uint16_t i_pcr_ext)
{
p_ts[10] |= (i_pcr_ext >> 8) & 0x1;
p_ts[11] = i_pcr_ext & 0xff;
}
static inline bool tsaf_has_pcr(uint8_t *p_ts)
{
return p_ts[5] & 0x10;
}
static inline uint64_t tsaf_get_pcr(const uint8_t *p_ts)
{
return (p_ts[6] << 25) | (p_ts[7] << 17) | (p_ts[8] << 9) | (p_ts[9] << 1) |
(p_ts[10] >> 7);
}
static inline uint64_t tsaf_get_pcrext(const uint8_t *p_ts)
{
return ((p_ts[10] & 1) << 8) | p_ts[11];
}
/*****************************************************************************
* TS payload gathering
*****************************************************************************/
static inline bool ts_check_duplicate(uint8_t i_cc, uint8_t i_last_cc)
{
return i_last_cc == i_cc;
}
static inline bool ts_check_discontinuity(uint8_t i_cc, uint8_t i_last_cc)
{
return (i_last_cc + 17 - i_cc) % 16;
}
#ifdef __cplusplus
}
#endif
#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