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