[SCM] bitstream/master: Imported Upstream version 1.1

sramacher at users.alioth.debian.org sramacher at users.alioth.debian.org
Sun Jan 10 14:16:25 UTC 2016


The following commit has been merged in the master branch:
commit 5e5d6a4e27b427714bc78495f42488845cf23919
Author: Sebastian Ramacher <sebastian at ramacher.at>
Date:   Sun Jan 10 15:01:54 2016 +0100

    Imported Upstream version 1.1

diff --git a/Makefile b/Makefile
index 4d43e77..206861a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 PREFIX ?= /usr/local
 INCLUDE = $(subst //,/,$(DESTDIR)/$(PREFIX)/include/bitstream)
-VERSION = 1.0
+VERSION = 1.1
 
 all:
 	@echo "Run \"make install\" to install biTStream into $(INCLUDE)"
@@ -9,22 +9,28 @@ install:
 	@echo "INSTALL  $(INCLUDE)"
 	@install -d $(INCLUDE)
 	@install -m 644 common.h $(INCLUDE)/
+	@install -d $(INCLUDE)/atsc
+	@install -m 644 atsc/*.h $(INCLUDE)/atsc
 	@install -d $(INCLUDE)/dvb
 	@install -m 644 dvb/*.h $(INCLUDE)/dvb
 	@install -d $(INCLUDE)/dvb/si
 	@install -m 644 dvb/si/*.h $(INCLUDE)/dvb/si
 	@install -d $(INCLUDE)/ietf
 	@install -m 644 ietf/* $(INCLUDE)/ietf
+	@install -d $(INCLUDE)/ieee
+	@install -m 644 ieee/* $(INCLUDE)/ieee
 	@install -d $(INCLUDE)/mpeg
 	@install -m 644 mpeg/*.h $(INCLUDE)/mpeg
 	@install -d $(INCLUDE)/mpeg/psi
 	@install -m 644 mpeg/psi/*.h $(INCLUDE)/mpeg/psi
+	@install -d $(INCLUDE)/scte
+	@install -m 644 scte/*.h $(INCLUDE)/scte
 
 uninstall:
 	@echo "REMOVE   $(INCLUDE)"
 	@rm -rf $(INCLUDE)
 
-distcheck:
+dist:
 	git archive --format=tar --prefix=bitstream-$(VERSION)/ master | bzip2 -9 > bitstream-$(VERSION).tar.bz2
 
 .PHONY: install uninstall distcheck
diff --git a/NEWS b/NEWS
index 5c3754f..9b4dc2d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,20 @@
+1.1 (5 Oct 2015)
+================
+ - Rename fields in BAT, RST and SIT to match those of SDT
+ - Add support for private data specifier 0x233a for descriptor 0x83
+ - Add support for elementary streams MPEG video and audio, AAC, A/52, Opus,
+   H264 and DVB subtitles
+ - Add support for SMPTE 2022-1 Forward Error Correction
+ - Add support for encoder/decoder DVB Simulcrypt EMMG interface
+ - Add support for IEEE 802.3 Ethernet frames
+ - Add support for IP and UDP headers
+ - Add support for IETF RTCP
+ - Add support for SCTE-35 Splice Information Table
+ - Fix parsing of PSI version_number
+ - Fix bug in EIT
+ - Fix bug in PCR writing
+ - Fix retrieval of PES payload offset in case of optional header
+ - Fix incorrect marker bit in PES PTS and DTS syntax
 
 1.0 (15 Dec 2011)
 =================
diff --git a/atsc/a52.h b/atsc/a52.h
new file mode 100644
index 0000000..9a210db
--- /dev/null
+++ b/atsc/a52.h
@@ -0,0 +1,314 @@
+/*****************************************************************************
+ * a52.h: ATSC A/52:2012 Digital Audio Compression Standard
+ *****************************************************************************
+ * Copyright (C) 2013-2014 VideoLAN
+ *
+ * Authors: Benjamin Cohen <bencoh at notk.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ * - ATSC A/52:2012
+ */
+
+#ifndef __BITSTREAM_ATSC_A52_H__
+#define __BITSTREAM_ATSC_A52_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include <string.h>   /* memcmp */
+#include <stdbool.h>  /* bool */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define A52_BSID                8
+#define A52_BSID_ANNEX_D        1
+#define A52_BSID_ANNEX_E        16
+
+#define A52_FSCOD_48KHZ         0
+#define A52_FSCOD_441KHZ        1
+#define A52_FSCOD_32KHZ         2
+#define A52_FSCOD_RESERVED      3
+#define A52_FRAME_SAMPLES       1536
+
+/*****************************************************************************
+ * A/52 syncinfo (A/52:2012 Table 5.1)
+ * - syncword       16
+ * - crc1           16
+ * - fscod          2
+ * - frmsizecod     6
+ *****************************************************************************/
+#define A52_SYNCINFO_SIZE       5
+
+/* A/52 Frame Size Code Table (A/52:2012 Table 5.18) */
+static const uint16_t a52_frame_size_code_tab[38][3] = {
+    { 64,   69,   96   },
+    { 64,   70,   96   },
+    { 80,   87,   120  },
+    { 80,   88,   120  },
+    { 96,   104,  144  },
+    { 96,   105,  144  },
+    { 112,  121,  168  },
+    { 112,  122,  168  },
+    { 128,  139,  192  },
+    { 128,  140,  192  },
+    { 160,  174,  240  },
+    { 160,  175,  240  },
+    { 192,  208,  288  },
+    { 192,  209,  288  },
+    { 224,  243,  336  },
+    { 224,  244,  336  },
+    { 256,  278,  384  },
+    { 256,  279,  384  },
+    { 320,  348,  480  },
+    { 320,  349,  480  },
+    { 384,  417,  576  },
+    { 384,  418,  576  },
+    { 448,  487,  672  },
+    { 448,  488,  672  },
+    { 512,  557,  768  },
+    { 512,  558,  768  },
+    { 640,  696,  960  },
+    { 640,  697,  960  },
+    { 768,  835,  1152 },
+    { 768,  836,  1152 },
+    { 896,  975,  1344 },   
+    { 896,  976,  1344 },
+    { 1024, 1114, 1536 },
+    { 1024, 1115, 1536 },
+    { 1152, 1253, 1728 },
+    { 1152, 1254, 1728 },
+    { 1280, 1393, 1920 },
+    { 1280, 1394, 1920 },
+};
+
+/* A/52 Bitrate Table (A/52:2012 Table 5.18) */
+static const uint16_t a52_bitrate_tab[38] = {
+    64, 64,
+    80, 80,
+    96, 96,
+    112, 112,
+    128, 128,
+    160, 160,
+    192, 192,
+    224, 224,
+    256, 256,
+    320, 320,
+    384, 384,
+    448, 448,
+    512, 512,
+    640, 640,
+    768, 768,
+    896, 896,
+    1024, 1024,
+    1152, 1152,
+    1280, 1280
+};
+
+static inline uint16_t a52_get_sync(const uint8_t *p_a52)
+{
+    return (p_a52[0] << 8 | p_a52[1]);
+}
+
+static inline void a52_set_sync(uint8_t *p_a52)
+{
+    p_a52[0] = 0xb;
+    p_a52[1] = 0x77;
+}
+
+static inline uint16_t a52_get_crc(const uint8_t *p_a52)
+{
+    return (p_a52[2] << 8 | p_a52[3]);
+}
+
+static inline void a52_set_crc(uint8_t *p_a52, uint16_t i_crc)
+{
+    p_a52[2] = i_crc >> 8;
+    p_a52[3] = i_crc & 0xff;
+}
+
+static inline uint8_t a52_get_fscod(const uint8_t *p_a52)
+{
+    return (p_a52[4] & 0xc0) >> 6;
+}
+
+static inline void a52_set_fscod(uint8_t *p_a52, uint8_t i_fscod)
+{
+    p_a52[4] &= ~0xc0;
+    p_a52[4] |= (i_fscod & 0x3) << 6;
+}
+
+static inline uint8_t a52_get_frmsizecod(const uint8_t *p_a52)
+{
+    return p_a52[4] & 0x3f;
+}
+
+static inline void a52_set_frmsizecod(uint8_t *p_a52, uint8_t i_frmsizecod)
+{
+    p_a52[4] &= ~0x3f;
+    p_a52[4] |= i_frmsizecod & 0x3f;
+}
+
+static inline uint16_t a52_get_frame_size(uint8_t i_fscod, uint8_t i_frmsizecod)
+{
+    i_fscod &= 0x3;
+    if ((i_fscod == A52_FSCOD_RESERVED) || (i_frmsizecod > 37)) {
+        return 0;
+    }
+    return a52_frame_size_code_tab[i_frmsizecod][i_fscod] * 2;
+}
+
+static inline bool a52_sync_compare_formats(const uint8_t *p_a521, const uint8_t *p_a522)
+{
+    return p_a521[0] == p_a522[0] && p_a521[1] == p_a522[1] &&
+           p_a521[4] == p_a522[4];
+}
+
+/*****************************************************************************
+ * A/52 bsi (Bit Stream Information)
+ *****************************************************************************/
+
+static inline uint8_t a52_get_bsid(const uint8_t *p_a52)
+{
+    return (p_a52[5] & 0xf8) >> 3;
+}
+
+static inline void a52_set_bsid(uint8_t *p_a52, uint8_t i_bsid)
+{
+    p_a52[5] &= ~0xf8;
+    p_a52[5] |= (i_bsid & 0xf8) << 3;
+}
+
+static inline uint8_t a52_get_bsmod(const uint8_t *p_a52)
+{
+    return (p_a52[5] & 0x7);
+}
+
+static inline void a52_set_bsmod(uint8_t *p_a52, uint8_t i_bsid)
+{
+    p_a52[5] &= ~0x7;
+    p_a52[5] |= i_bsid & 0x7;
+}
+
+static inline uint8_t a52_get_acmod(const uint8_t *p_a52)
+{
+    return (p_a52[6] & 0xe0) >> 5;
+}
+
+static inline void a52_set_acmod(uint8_t *p_a52, uint8_t i_acmod)
+{
+    p_a52[6] &= ~0xe0;
+    p_a52[6] |= (i_acmod & 0x7) << 5;
+}
+
+static inline uint8_t a52_get_cmixlev(const uint8_t *p_a52)
+{
+    return (p_a52[6] & 0x18) >> 3;
+}
+
+static inline void a52_set_cmixlev(uint8_t *p_a52, uint8_t i_cmixlev)
+{
+    p_a52[6] &= ~0x18;
+    p_a52[6] |= (i_cmixlev & 0x3) << 3;
+}
+
+/*****************************************************************************
+ * A/52 Annex E 
+ *****************************************************************************/
+#define A52E_FSCOD2_24KHZ       0
+#define A52E_FSCOD2_2205KHZ     1
+#define A52E_FSCOD2_16KHZ       2
+#define A52E_FSCOD2_RESERVED    3
+
+static inline uint8_t a52e_get_strmtyp(const uint8_t *p_a52)
+{
+    return (p_a52[2] & 0xc0) >> 5;
+}
+
+static inline void a52e_set_strmtyp(uint8_t *p_a52, uint8_t i_strmtyp)
+{
+    p_a52[2] &= ~0xc0;
+    p_a52[2] |= (i_strmtyp & 0x3) << 6;
+}
+
+static inline uint8_t a52e_get_substreamid(const uint8_t *p_a52)
+{
+    return (p_a52[2] & 0x38) >> 3;
+}
+
+static inline void a52e_set_substreamid(uint8_t *p_a52, uint8_t i_substreamid)
+{
+    p_a52[2] &= ~0x38;
+    p_a52[2] |= (i_substreamid & 0x7) << 3;
+}
+
+static inline uint16_t a52e_get_frmsiz(const uint8_t *p_a52)
+{
+    return ((p_a52[2] & 0x7) << 8) | p_a52[3];
+}
+
+static inline void a52e_set_frmsiz(uint8_t *p_a52, uint16_t i_frmsiz)
+{
+    p_a52[2] &= ~0x7;
+    p_a52[2] |= (i_frmsiz >> 8) & 0x7;
+    p_a52[3] = i_frmsiz & 0xff;
+}
+
+static inline uint16_t a52e_get_frame_size(uint16_t i_frmsiz)
+{
+    return (i_frmsiz + 1) * 2;
+}
+
+static inline uint8_t a52e_get_fscod(const uint8_t *p_a52)
+{
+    return (p_a52[4] & 0xc0) >> 6;
+}
+
+static inline void a52e_set_fscod(uint8_t *p_a52, uint8_t i_fscod)
+{
+    p_a52[4] &= ~0xc0;
+    p_a52[4] |= (i_fscod & 0x3) << 6;
+}
+
+static inline uint8_t a52e_get_fscod2(const uint8_t *p_a52)
+{
+    return (p_a52[4] & 0x30) >> 4;
+}
+
+static inline void a52e_set_fscod2(uint8_t *p_a52, uint8_t i_fscod)
+{
+    p_a52[4] &= ~0x30;
+    p_a52[4] |= (i_fscod & 0x3) << 4;
+}
+
+static inline bool a52e_sync_compare_formats(const uint8_t *p_a521, const uint8_t *p_a522)
+{
+    return !memcmp(p_a521, p_a522, A52_SYNCINFO_SIZE);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dvb/ci.h b/dvb/ci.h
index 86e94a7..f7a6868 100644
--- a/dvb/ci.h
+++ b/dvb/ci.h
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * ci.h: ETSI EN 50 221 Common Interface Specification
+ * ci.h: CENELEC EN 50 221 Common Interface Specification
  *****************************************************************************
  * Copyright (C) 2010 VideoLAN
  *
@@ -27,7 +27,7 @@
 
 /*
  * Normative references:
- *  - ETSI EN 50 221 (1997) (Common Interface Specification)
+ *  - CENELEC EN 50 221 (1997) (Common Interface Specification)
  */
 
 #ifndef __BITSTREAM_DVB_CI_H__
diff --git a/dvb/si/bat_print.h b/dvb/si/bat_print.h
index 016c08c..2c7ebcf 100644
--- a/dvb/si/bat_print.h
+++ b/dvb/si/bat_print.h
@@ -52,14 +52,14 @@ static inline void bat_table_print(uint8_t **pp_sections,
 
     switch (i_print_type) {
     case PRINT_XML:
-        pf_print(print_opaque, "<BAT tid=\"%hhu\" networkid=\"%hu\" version=\"%hhu\" current_next=\"%d\">",
+        pf_print(print_opaque, "<BAT tid=\"%hhu\" bouquetid=\"%hu\" version=\"%hhu\" current_next=\"%d\">",
                  psi_table_get_tableid(pp_sections),
                  psi_table_get_tableidext(pp_sections),
                  psi_table_get_version(pp_sections),
                  !psi_table_get_current(pp_sections) ? 0 : 1);
         break;
     default:
-        pf_print(print_opaque, "new BAT networkid=%hu version=%hhu%s",
+        pf_print(print_opaque, "new BAT bouquetid=%hu version=%hhu%s",
                  psi_table_get_tableidext(pp_sections),
                  psi_table_get_version(pp_sections),
                  !psi_table_get_current(pp_sections) ? " (next)" : "");
diff --git a/dvb/si/desc_40.h b/dvb/si/desc_40.h
index ed9c8cd..9dfd5d3 100644
--- a/dvb/si/desc_40.h
+++ b/dvb/si/desc_40.h
@@ -70,6 +70,8 @@ static inline const uint8_t *desc40_get_networkname(const uint8_t *p_desc,
 
 static inline bool desc40_validate(const uint8_t *p_desc)
 {
+    (void) p_desc;
+
     return true;
 }
 
diff --git a/dvb/si/desc_42.h b/dvb/si/desc_42.h
index 813b4fe..dc3b167 100644
--- a/dvb/si/desc_42.h
+++ b/dvb/si/desc_42.h
@@ -53,6 +53,8 @@ static inline void desc42_init(uint8_t *p_desc)
 
 static inline bool desc42_validate(const uint8_t *p_desc)
 {
+    (void) p_desc;
+
     return true;
 }
 
diff --git a/dvb/si/desc_45.h b/dvb/si/desc_45.h
index 9655d93..9c11db9 100644
--- a/dvb/si/desc_45.h
+++ b/dvb/si/desc_45.h
@@ -72,7 +72,7 @@ static inline uint8_t desc45n_get_data_length(const uint8_t *p_desc_n)
     return p_desc_n[1];
 }
 
-static inline char *desc45_get_service_id_txt(uint8_t i_service_id)
+static inline const char *desc45_get_service_id_txt(uint8_t i_service_id)
 {
     return i_service_id == 0x00 ? "reserved" :
            i_service_id == 0x01 ? "EBU teletext" :
diff --git a/dvb/si/desc_46.h b/dvb/si/desc_46.h
index bb50b16..240b129 100644
--- a/dvb/si/desc_46.h
+++ b/dvb/si/desc_46.h
@@ -49,6 +49,12 @@ extern "C"
 #define DESC46_HEADER_SIZE      DESC_HEADER_SIZE
 #define DESC46_LANGUAGE_SIZE    5
 
+#define DESC46_TELETEXTTYPE_INITIAL     1
+#define DESC46_TELETEXTTYPE_SUBTITLE    2
+#define DESC46_TELETEXTTYPE_INFORMATION 3
+#define DESC46_TELETEXTTYPE_SCHEDULE    4
+#define DESC46_TELETEXTTYPE_SUBTITLE_H  5
+
 static inline void desc46_init(uint8_t *p_desc)
 {
     desc_set_tag(p_desc, 0x46);
@@ -77,7 +83,7 @@ static inline uint8_t desc46n_get_teletexttype(const uint8_t *p_desc_n)
     return p_desc_n[3] >> 3;
 }
 
-static inline char *desc46_get_teletexttype_txt(uint8_t i_type)
+static inline const char *desc46_get_teletexttype_txt(uint8_t i_type)
 {
     return i_type == 0x00 ? "Reserved" :
            i_type == 0x01 ? "Initial teletext page" :
diff --git a/dvb/si/desc_51.h b/dvb/si/desc_51.h
index 4be501d..fd812bb 100644
--- a/dvb/si/desc_51.h
+++ b/dvb/si/desc_51.h
@@ -105,7 +105,7 @@ static inline void desc51n_set_logical_cell_presentation_info(uint8_t *p_desc_n,
     p_desc_n[1] = (i_lc_presentation_info & 0x07) | 0xf8;
 }
 
-static inline char *desc51_get_logical_cell_presentation_info_txt(uint8_t i_lcp_info)
+static inline const char *desc51_get_logical_cell_presentation_info_txt(uint8_t i_lcp_info)
 {
     return i_lcp_info == 0x00 ? "undefined" :
            i_lcp_info == 0x01 ? "video" :
@@ -143,7 +143,7 @@ static inline void desc51n_set_cell_linkage_info(uint8_t *p_desc_n, uint8_t i_ce
     p_desc_n[3 + desc51n_get_elementary_cell_field_length(p_desc_n)] = i_cell_linkage_info;
 }
 
-static inline char *desc51_get_cell_linkage_info_txt(uint8_t i_icl_info)
+static inline const char *desc51_get_cell_linkage_info_txt(uint8_t i_icl_info)
 {
     return i_icl_info == 0x00 ? "undefined" :
            i_icl_info == 0x01 ? "bouquet related" :
diff --git a/dvb/si/desc_56.h b/dvb/si/desc_56.h
index ac13ded..bf19b58 100644
--- a/dvb/si/desc_56.h
+++ b/dvb/si/desc_56.h
@@ -48,6 +48,12 @@ extern "C"
 #define DESC56_HEADER_SIZE      DESC46_HEADER_SIZE
 #define DESC56_LANGUAGE_SIZE    DESC46_LANGUAGE_SIZE
 
+#define DESC56_TELETEXTTYPE_INITIAL     DESC46_TELETEXTTYPE_INITIAL
+#define DESC56_TELETEXTTYPE_SUBTITLE    DESC46_TELETEXTTYPE_SUBTITLE
+#define DESC56_TELETEXTTYPE_INFORMATION DESC46_TELETEXTTYPE_INFORMATION
+#define DESC56_TELETEXTTYPE_SCHEDULE    DESC46_TELETEXTTYPE_SCHEDULE
+#define DESC56_TELETEXTTYPE_SUBTITLE_H  DESC46_TELETEXTTYPE_SUBTITLE_H
+
 static inline void desc56_init(uint8_t *p_desc)
 {
     desc_set_tag(p_desc, 0x56);
diff --git a/dvb/si/desc_66.h b/dvb/si/desc_66.h
index f53e215..8873e9c 100644
--- a/dvb/si/desc_66.h
+++ b/dvb/si/desc_66.h
@@ -97,7 +97,7 @@ static inline void desc66_print(const uint8_t *p_desc, f_print pf_print,
 
     for (i = 0; i < i_selector_byte_length; i++) {
         sprintf(psz_selector_byte + 2 * i, "%02x", p_selector_byte[i]);
-        if (p_selector_byte[i] >= 32 && p_selector_byte[i] <= 127 && p_selector_byte[i] != '"')
+        if (p_selector_byte[i] >= 48 && p_selector_byte[i] <= 127 && p_selector_byte[i] != '"')
             psz_selector_byte_txt[i] = p_selector_byte[i];
         else
             psz_selector_byte_txt[i] = '.';
diff --git a/dvb/si/desc_67.h b/dvb/si/desc_67.h
index 319faf3..831e2e3 100644
--- a/dvb/si/desc_67.h
+++ b/dvb/si/desc_67.h
@@ -71,6 +71,8 @@ static inline void desc67_set_bytes(uint8_t *p_desc, const uint8_t *p_bytes, uin
 
 static inline bool desc67_validate(const uint8_t *p_desc)
 {
+  (void) p_desc;
+
     return true;
 }
 
diff --git a/dvb/si/desc_69.h b/dvb/si/desc_69.h
index d83487a..93a868a 100644
--- a/dvb/si/desc_69.h
+++ b/dvb/si/desc_69.h
@@ -67,8 +67,8 @@ static inline void desc69_set_pil(uint8_t *p_desc, uint32_t i_pil)
 
 static inline uint8_t desc69_get_day(const uint8_t *p_desc)
 {
-    uint8_t i_day = ((p_desc[2] & 0x0f) << 1) | ((p_desc[3] & 0x7f) >> 7); // rrrr1111 1xxxxxxx
-    return i_day + 1;
+    uint8_t i_day = ((p_desc[2] & 0x0f) << 1) | ((p_desc[3] & 0x80) >> 7); // rrrr1111 1xxxxxxx
+    return i_day;
 }
 
 static inline void desc69_set_day(uint8_t *p_desc, uint8_t i_day)
diff --git a/dvb/si/desc_7c.h b/dvb/si/desc_7c.h
index 2472d3a..1e7b854 100644
--- a/dvb/si/desc_7c.h
+++ b/dvb/si/desc_7c.h
@@ -83,7 +83,7 @@ static inline void desc7c_set_aac_type_flag(uint8_t *p_desc, bool b_aac_type_fla
         desc_set_length(p_desc, i_desc_len);
     }
     if (i_desc_len > 1)
-        p_desc[3] = b_aac_type_flag ? 0xff : 0x7f;
+        p_desc[3] = b_aac_type_flag ? 0x80 : 0;
 }
 
 static inline uint8_t desc7c_get_aac_type(const uint8_t *p_desc)
diff --git a/dvb/si/desc_83p28.h b/dvb/si/desc_83p28.h
index 7adf7cc..d416b42 100644
--- a/dvb/si/desc_83p28.h
+++ b/dvb/si/desc_83p28.h
@@ -103,7 +103,7 @@ static inline void desc83p28_print(uint8_t *p_desc, f_print pf_print,
             break;
         default:
             pf_print(opaque,
-            "    - desc %hhu lcn sid=%hu%s lcn=%hu", desc_get_tag(p_desc),
+            "    - desc %hhx lcn sid=%hu%s lcn=%hu", desc_get_tag(p_desc),
             desc83p28n_get_sid(p_desc_n),
             desc83p28n_get_visible(p_desc_n) ? " visible" : "",
             desc83p28n_get_lcn(p_desc_n));
diff --git a/dvb/si/dit_print.h b/dvb/si/dit_print.h
index 6a54883..f6991cd 100644
--- a/dvb/si/dit_print.h
+++ b/dvb/si/dit_print.h
@@ -44,6 +44,9 @@ static inline void dit_print(uint8_t *p_dit,
                              f_iconv pf_iconv, void *iconv_opaque,
                              print_type_t i_print_type)
 {
+    (void) pf_iconv;
+    (void) iconv_opaque;
+
     switch (i_print_type) {
     case PRINT_XML:
         pf_print(print_opaque, "<DIT transition_flag=\"%u\"/>",
diff --git a/dvb/si/eit.h b/dvb/si/eit.h
index b7f4253..f529b5d 100644
--- a/dvb/si/eit.h
+++ b/dvb/si/eit.h
@@ -114,6 +114,11 @@ static inline uint8_t eit_get_last_table_id(const uint8_t *p_eit)
     return p_eit[13];
 }
 
+static inline void eitn_init(uint8_t *p_eit_n)
+{
+    p_eit_n[10] = 0;
+}
+
 static inline uint16_t eitn_get_event_id(const uint8_t *p_eit_n)
 {
     return (p_eit_n[0] << 8) | p_eit_n[1];
@@ -152,24 +157,24 @@ static inline void eitn_set_duration_bcd(uint8_t *p_eit_n, uint32_t i_duration_b
     p_eit_n[9] = i_duration_bcd         & 0xff;
 }
 
-static inline uint8_t eitn_get_running_status(const uint8_t *p_eit_n)
+static inline uint8_t eitn_get_running(const uint8_t *p_eit_n)
 {
     return p_eit_n[10] >> 5;
 }
 
-static inline void eitn_set_running_status(uint8_t *p_eit_n, uint8_t i_running_status)
+static inline void eitn_set_running(uint8_t *p_eit_n, uint8_t i_running_status)
 {
     p_eit_n[10] = (p_eit_n[10] & 0x1f) | (i_running_status << 5);
 }
 
-static inline bool eitn_get_free_CA_mode(const uint8_t *p_eit_n)
+static inline bool eitn_get_ca(const uint8_t *p_eit_n)
 {
     return (p_eit_n[10] & 0x10) == 0x10;
 }
 
-static inline void eitn_set_free_CA_mode(uint8_t *p_eit_n, bool b_free_CA_mode)
+static inline void eitn_set_ca(uint8_t *p_eit_n)
 {
-    p_eit_n[10] = b_free_CA_mode ? (p_eit_n[10] | 0x10) : (p_eit_n[10] &~ 0x10);
+    p_eit_n[10] |= 0x10;
 }
 
 static inline uint16_t eitn_get_desclength(const uint8_t *p_eit_n)
diff --git a/dvb/si/eit_print.h b/dvb/si/eit_print.h
index 5adedf8..6c4d53c 100644
--- a/dvb/si/eit_print.h
+++ b/dvb/si/eit_print.h
@@ -50,7 +50,7 @@ static inline void eit_print(uint8_t *p_eit,
     uint8_t *p_event;
     uint8_t j = 0;
     uint8_t i_tid = psi_get_tableid(p_eit);
-    char *psz_tid = "unknown";
+    const char *psz_tid = "unknown";
 
     if (i_tid == EIT_TABLE_ID_PF_ACTUAL)
         psz_tid = "actual_pf";
@@ -64,29 +64,28 @@ static inline void eit_print(uint8_t *p_eit,
     switch (i_print_type) {
     case PRINT_XML:
         pf_print(print_opaque,
-                "<EIT tableid=\"0x%02x\" type=\"%s\" version=\"%u\""
-                " current_next=\"%u\" tsid=\"%u\" onid=\"%u\""
-                " seg_last_sec_number=\"%u\" last_table_id=\"0x%02x\">",
+                "<EIT tableid=\"0x%02x\" type=\"%s\" service_id=\"%u\" version=\"%u\""
+                " current_next=\"%u\" tsid=\"%u\" onid=\"%u\">",
                  i_tid, psz_tid,
+                 eit_get_sid(p_eit),
                  psi_get_version(p_eit),
                  !psi_get_current(p_eit) ? 0 : 1,
                  eit_get_tsid(p_eit),
-                 eit_get_onid(p_eit),
-                 eit_get_segment_last_sec_number(p_eit),
-                 eit_get_last_table_id(p_eit)
+                 eit_get_onid(p_eit)
                 );
         break;
     default:
         pf_print(print_opaque,
-                 "new EIT tableid=0x%02x type=%s version=%u%s tsid=%u"
-                 " onid=%u seg_last_sec_number=%u last_table_id=0x%02x",
+                 "new EIT tableid=0x%02x type=%s service_id=%u version=%u%s section=%u/%u tsid=%u"
+                 " onid=%u",
                  i_tid, psz_tid,
+                 eit_get_sid(p_eit),
                  psi_get_version(p_eit),
                  !psi_get_current(p_eit) ? " (next)" : "",
+                 psi_get_section(p_eit),
+                 psi_get_lastsection(p_eit),
                  eit_get_tsid(p_eit),
-                 eit_get_onid(p_eit),
-                 eit_get_segment_last_sec_number(p_eit),
-                 eit_get_last_table_id(p_eit)
+                 eit_get_onid(p_eit)
                 );
     }
 
@@ -105,21 +104,21 @@ static inline void eit_print(uint8_t *p_eit,
         case PRINT_XML:
             pf_print(print_opaque, "<EVENT id=\"%u\" start_time=\"%ld\" start_time_dec=\"%s\""
                                    " duration=\"%u\" duration_dec=\"%s\""
-                                   " running_status=\"%d\" free_CA_mode=\"%d\">",
+                                   " running=\"%d\" free_CA=\"%d\">",
                      eitn_get_event_id(p_event),
                      start_ts, start_str,
                      duration, duration_str,
-                     eitn_get_running_status(p_event),
-                     eitn_get_free_CA_mode(p_event)
+                     eitn_get_running(p_event),
+                     eitn_get_ca(p_event)
                     );
             break;
         default:
-            pf_print(print_opaque, "  * EVENT id=%u start_time=%ld start_time_dec=\"%s\" duration=%u duration_dec=%s running_status=%d free_CA_mode=%d",
+            pf_print(print_opaque, "  * EVENT id=%u start_time=%ld start_time_dec=\"%s\" duration=%u duration_dec=%s running=%d free_CA=%d",
                      eitn_get_event_id(p_event),
                      start_ts, start_str,
                      duration, duration_str,
-                     eitn_get_running_status(p_event),
-                     eitn_get_free_CA_mode(p_event)
+                     eitn_get_running(p_event),
+                     eitn_get_ca(p_event)
                     );
         }
 
diff --git a/dvb/si/rst.h b/dvb/si/rst.h
index 113c54b..0897815 100644
--- a/dvb/si/rst.h
+++ b/dvb/si/rst.h
@@ -110,12 +110,12 @@ static inline void rstn_set_event_id(uint8_t *p_rst_n, uint16_t i_event_id)
     p_rst_n[7] = i_event_id & 0xff;
 }
 
-static inline uint8_t rstn_get_running_status(const uint8_t *p_rst_n)
+static inline uint8_t rstn_get_running(const uint8_t *p_rst_n)
 {
     return p_rst_n[8] & 0x07;
 }
 
-static inline void rstn_set_running_status(uint8_t *p_rst_n, uint8_t i_running_status)
+static inline void rstn_set_running(uint8_t *p_rst_n, uint8_t i_running_status)
 {
     p_rst_n[8] = 0xf8 | (i_running_status & 0x07);
 }
diff --git a/dvb/si/rst_print.h b/dvb/si/rst_print.h
index 0d859f4..2dd482a 100644
--- a/dvb/si/rst_print.h
+++ b/dvb/si/rst_print.h
@@ -44,6 +44,9 @@ static inline void rst_print(uint8_t *p_rst,
                              f_iconv pf_iconv, void *iconv_opaque,
                              print_type_t i_print_type)
 {
+    (void) pf_iconv;
+    (void) iconv_opaque;
+
     uint8_t j = 0;
     uint8_t *p_rst_n;
 
@@ -60,23 +63,23 @@ static inline void rst_print(uint8_t *p_rst,
         case PRINT_XML:
             pf_print(print_opaque,
                      "<STATUS tsid=\"%hu\" onid=\"%hu\" service_id=\"%hu\""
-                     " event_id=\"%hu\" running_status=\"%hu\"/>",
+                     " event_id=\"%hu\" running=\"%hu\"/>",
                      rstn_get_tsid(p_rst_n),
                      rstn_get_onid(p_rst_n),
                      rstn_get_service_id(p_rst_n),
                      rstn_get_event_id(p_rst_n),
-                     rstn_get_running_status(p_rst_n)
+                     rstn_get_running(p_rst_n)
                     );
             break;
         default:
             pf_print(print_opaque,
                      "  * status tsid=\"%hu\" onid=\"%hu\" service_id=\"%hu\""
-                     " event_id=\"%hu\" running_status=\"%hu\"",
+                     " event_id=\"%hu\" running=\"%hu\"",
                      rstn_get_tsid(p_rst_n),
                      rstn_get_onid(p_rst_n),
                      rstn_get_service_id(p_rst_n),
                      rstn_get_event_id(p_rst_n),
-                     rstn_get_running_status(p_rst_n)
+                     rstn_get_running(p_rst_n)
                     );
         }
     }
diff --git a/dvb/si/sdt.h b/dvb/si/sdt.h
index fea3396..d8170e3 100644
--- a/dvb/si/sdt.h
+++ b/dvb/si/sdt.h
@@ -228,6 +228,7 @@ static inline bool sdt_table_validate(uint8_t **pp_sections)
 {
     uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
     uint8_t i;
+    uint16_t i_onid;
 
     for (i = 0; i <= i_last_section; i++) {
         uint8_t *p_section = psi_table_get_section(pp_sections, i);
@@ -237,6 +238,11 @@ static inline bool sdt_table_validate(uint8_t **pp_sections)
         if (!psi_check_crc(p_section))
             return false;
 
+        if (!j)
+            i_onid = sdt_get_onid(p_section);
+        else if (sdt_get_onid(p_section) != i_onid)
+            return false;
+
         while ((p_service = sdt_get_service(p_section, j)) != NULL) {
             j++;
             /* check that the service is not already in the table */
diff --git a/dvb/si/sit.h b/dvb/si/sit.h
index ae11716..a275569 100644
--- a/dvb/si/sit.h
+++ b/dvb/si/sit.h
@@ -99,12 +99,12 @@ static inline void sitn_set_sid(uint8_t *p_sit_n, uint16_t i_sid)
     p_sit_n[1] =  i_sid       & 0xff;
 }
 
-static inline uint8_t sitn_get_running_status(const uint8_t *p_sit_n)
+static inline uint8_t sitn_get_running(const uint8_t *p_sit_n)
 {
     return (p_sit_n[2] & 0x70) >> 4;
 }
 
-static inline void sitn_set_running_status(uint8_t *p_sit_n, uint8_t i_running_status)
+static inline void sitn_set_running(uint8_t *p_sit_n, uint8_t i_running_status)
 {
     p_sit_n[2] = (p_sit_n[2] &~ 0x70) | ((i_running_status & 0x07) << 4);
 }
diff --git a/dvb/si/sit_print.h b/dvb/si/sit_print.h
index 68a1cb0..107852c 100644
--- a/dvb/si/sit_print.h
+++ b/dvb/si/sit_print.h
@@ -66,15 +66,15 @@ static inline void sit_print(uint8_t *p_sit,
         j++;
         switch (i_print_type) {
         case PRINT_XML:
-            pf_print(print_opaque, "<SERVICE sid=\"%hu\" running_status=\"%u\">",
+            pf_print(print_opaque, "<SERVICE sid=\"%hu\" running=\"%u\">",
                      sitn_get_sid(p_service),
-                     sitn_get_running_status(p_service)
+                     sitn_get_running(p_service)
                     );
             break;
         default:
-            pf_print(print_opaque, "  * SERVICE sid=%hu running_status=%u",
+            pf_print(print_opaque, "  * SERVICE sid=%hu running=%u",
                      sitn_get_sid(p_service),
-                     sitn_get_running_status(p_service)
+                     sitn_get_running(p_service)
                     );
         }
 
diff --git a/dvb/si/strings.h b/dvb/si/strings.h
index 5c30260..c61f477 100644
--- a/dvb/si/strings.h
+++ b/dvb/si/strings.h
@@ -47,19 +47,19 @@ extern "C"
  *****************************************************************************/
 static const char *ppsz_dvb_encodings[] = {
     /* 0x00 - 0x0f */
-    "", "ISO_8859-5", "ISO_8859-6", "ISO_8859-7", "ISO_8859-8",
-    "ISO_8859-9", "ISO_8859-10", "ISO_8859-11", "", "ISO_8859-13",
-    "ISO_8859-14", "ISO_8859-15", "", "", "", "",
+    "", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8",
+    "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "", "ISO-8859-13",
+    "ISO-8859-14", "ISO-8859-15", "", "", "", "",
 
     /* 0x10 - 0x1f */
     "", "UTF-16", "KSC5601-1987", "GB2312", "BIG-5", "UTF-8",
     "", "", "", "", "", "", "", "", "", "", NULL
 };
 static const char *ppsz_dvb_encodings10[] = {
-    "", "ISO_8859-1", "ISO_8859-2", "ISO_8859-3", "ISO_8859-4",
-    "ISO_8859-5", "ISO_8859-6", "ISO_8859-7", "ISO_8859-8", "ISO_8859-9",
-    "ISO_8859-10", "ISO_8859-11", "", "ISO_8859-13", "ISO_8859-14",
-    "ISO_8859-15", NULL
+    "", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4",
+    "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9",
+    "ISO-8859-10", "ISO-8859-11", "", "ISO-8859-13", "ISO-8859-14",
+    "ISO-8859-15", NULL
 };
 
 static inline const char *dvb_string_get_encoding(const uint8_t **pp_string,
@@ -71,7 +71,7 @@ static inline const char *dvb_string_get_encoding(const uint8_t **pp_string,
     i_first = (*pp_string)[0];
 
     if (!i_first) return NULL;
-    if (i_first >= 0x20) return "ISO_8859-1";
+    if (i_first >= 0x20) return "ISO-8859-1";
     (*pp_string)++;
     (*pi_length)--;
 
@@ -102,14 +102,14 @@ static inline uint8_t *dvb_string_set(const uint8_t *p_string, size_t i_length,
 {
     int i;
 
-    if (!strcmp(psz_encoding, "ISO_8859-9")) {
+    if (!strcmp(psz_encoding, "ISO-8859-9")) {
         *pi_out_length = i_length;
         return (uint8_t *)strdup((const char *)p_string);
     }
 
     for (i = 0; ppsz_dvb_encodings[i] != NULL; i++) {
         if (!strcasecmp(psz_encoding, ppsz_dvb_encodings[i])) {
-            uint8_t *p_encoded = malloc(i_length + 1);
+            uint8_t *p_encoded = (uint8_t *)malloc(i_length + 1);
             *pi_out_length = i_length + 1;
             p_encoded[0] = i;
             memcpy(p_encoded + 1, p_string, i_length);
@@ -119,7 +119,7 @@ static inline uint8_t *dvb_string_set(const uint8_t *p_string, size_t i_length,
 
     for (i = 0; ppsz_dvb_encodings10[i] != NULL; i++) {
         if (!strcasecmp(psz_encoding, ppsz_dvb_encodings10[i])) {
-            uint8_t *p_encoded = malloc(i_length + 3);
+            uint8_t *p_encoded = (uint8_t *)malloc(i_length + 3);
             *pi_out_length = i_length + 3;
             p_encoded[0] = 0x10;
             p_encoded[1] = 0x0;
@@ -142,7 +142,7 @@ static inline char *dvb_string_get(const uint8_t *p_string, size_t i_length,
                                                            &i_length);
         if (psz_encoding == NULL || !i_length) {
             /* try one-byte charset */
-            char *psz_string = malloc(i_length + 1);
+            char *psz_string = (char *)malloc(i_length + 1);
             memcpy(psz_string, p_string, i_length);
             psz_string[i_length] = '\0';
             return psz_string;
@@ -180,7 +180,7 @@ static inline char *dvb_string_xml_escape(char *psz_input)
         psz1++;
     }
 
-    psz2 = psz_output = malloc(i_output_size + 1);
+    psz2 = psz_output = (char *)malloc(i_output_size + 1);
     psz1 = psz_input;
     while (*psz1) {
         switch (*psz1) {
diff --git a/dvb/si/tdt_print.h b/dvb/si/tdt_print.h
index 87b0c72..040b7cb 100644
--- a/dvb/si/tdt_print.h
+++ b/dvb/si/tdt_print.h
@@ -45,6 +45,9 @@ static inline void tdt_print(uint8_t *p_tdt,
                              f_iconv pf_iconv, void *iconv_opaque,
                              print_type_t i_print_type)
 {
+    (void) pf_iconv;
+    (void) iconv_opaque;
+
     time_t ts;
     char ts_str[24];
 
diff --git a/dvb/sim.h b/dvb/sim.h
index a68955d..e575411 100644
--- a/dvb/sim.h
+++ b/dvb/sim.h
@@ -449,6 +449,180 @@ static inline bool ecmg_validate(uint8_t *p_tlv)
     return true;
 }
 
+/*****************************************************************************
+ * EMMG
+ *****************************************************************************/
+/* message types */
+#define EMMG_TYPE_CHANNEL_SETUP     0x0011
+#define EMMG_TYPE_CHANNEL_TEST      0x0012
+#define EMMG_TYPE_CHANNEL_STATUS    0x0013
+#define EMMG_TYPE_CHANNEL_CLOSE     0x0014
+#define EMMG_TYPE_CHANNEL_ERROR     0x0015
+#define EMMG_TYPE_STREAM_SETUP      0x0111
+#define EMMG_TYPE_STREAM_TEST       0x0112
+#define EMMG_TYPE_STREAM_STATUS     0x0113
+#define EMMG_TYPE_STREAM_CLOSEREQ   0x0114
+#define EMMG_TYPE_STREAM_CLOSERESP  0x0115
+#define EMMG_TYPE_STREAM_ERROR      0x0116
+#define EMMG_TYPE_BW_REQ            0x0117
+#define EMMG_TYPE_BW_ALLOC          0x0118
+#define EMMG_TYPE_DATA_PROVISION    0x0211
+
+/* parameter types */
+#define EMMG_PARAM_CLIENTID         0x0001
+#define EMMG_PARAM_SECTIONTSPKT     0x0002
+#define EMMG_PARAM_DATACHANNELID    0x0003
+#define EMMG_PARAM_DATASTREAMID     0x0004
+#define EMMG_PARAM_DATAGRAM         0x0005
+#define EMMG_PARAM_BANDWIDTH        0x0006
+#define EMMG_PARAM_DATATYPE         0x0007
+#define EMMG_PARAM_DATAID           0x0008
+#define EMMG_PARAM_ERRORSTATUS      0x7000
+#define EMMG_PARAM_ERRORINFO        0x7001
+
+static inline void emmg_init(uint8_t *p_tlv)
+{
+    tlv_empty(p_tlv);
+}
+
+TLV_DECLARE_PARAM(emmg, clientid, EMMG_PARAM_CLIENTID, uint32_t, uint32_t)
+TLV_DECLARE_PARAM(emmg, sectiontspkt, EMMG_PARAM_SECTIONTSPKT, uint8_t, uint8_t)
+TLV_DECLARE_PARAM(emmg, datachannelid, EMMG_PARAM_DATACHANNELID, uint16_t, int16_t)
+TLV_DECLARE_PARAM(emmg, datastreamid, EMMG_PARAM_DATASTREAMID, uint16_t, int16_t)
+TLV_DECLARE_PARAM(emmg, bandwidth, EMMG_PARAM_BANDWIDTH, uint16_t, int16_t)
+TLV_DECLARE_PARAM(emmg, datatype, EMMG_PARAM_DATATYPE, uint8_t, int8_t)
+TLV_DECLARE_PARAM(emmg, dataid, EMMG_PARAM_DATAID, uint16_t, uint16_t)
+TLV_DECLARE_PARAM(emmg, errorstatus, EMMG_PARAM_ERRORSTATUS, uint16_t, uint16_t)
+
+static inline bool emmg_validate_param(const uint8_t *p_tlv_n)
+{
+    static const uint16_t pi_emmg_params_minlength[] = {
+        0, 4, 1, 2, 2, 1, 2, 1, 2
+    };
+    static const uint16_t pi_emmg_params_manlength[] = {
+        0, 4, 1, 2, 2, 1, 2, 1, 2
+    };
+
+    uint16_t i_type = tlv_get_type(p_tlv_n);
+    uint16_t i_length = tlv_get_length(p_tlv_n);
+
+    if (i_type <= EMMG_PARAM_DATAID && i_type != EMMG_PARAM_DATAGRAM) {
+        if (i_length < pi_emmg_params_minlength[i_type] ||
+            i_length > pi_emmg_params_manlength[i_type])
+          return false;
+
+    } else if (i_type == EMMG_PARAM_ERRORSTATUS) {
+        if (i_length < 2) return false;
+    }
+
+    return true;
+}
+
+static inline bool emmg_validate(uint8_t *p_tlv)
+{
+    static const tlv_param_count_t p_emmg_params_channel_setup[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_SECTIONTSPKT, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_channel_test[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_channel_status[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_SECTIONTSPKT, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_channel_close[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_channel_error[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_ERRORSTATUS, 1, UINT16_MAX}, {0, 0, 0}
+    };
+
+    static const tlv_param_count_t p_emmg_params_stream_setup[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {EMMG_PARAM_DATAID, 1, 1},
+        {EMMG_PARAM_DATATYPE, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_stream_test[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_stream_status[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {EMMG_PARAM_DATAID, 1, 1},
+        {EMMG_PARAM_DATATYPE, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_stream_close[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_stream_error[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {EMMG_PARAM_ERRORSTATUS, 1, UINT16_MAX},
+        {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_bandwidth[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 1, 1},
+        {EMMG_PARAM_DATASTREAMID, 1, 1}, {EMMG_PARAM_BANDWIDTH, 0, 1},
+        {0, 0, 0}
+    };
+    static const tlv_param_count_t p_emmg_params_data_provision[] = {
+        {EMMG_PARAM_CLIENTID, 1, 1}, {EMMG_PARAM_DATACHANNELID, 0, 1},
+        {EMMG_PARAM_DATASTREAMID, 0, 1}, {EMMG_PARAM_DATAID, 1, 1},
+        {EMMG_PARAM_DATAGRAM, 1, UINT16_MAX}, {0, 0, 0}
+    };
+
+    const tlv_param_count_t null_param = {0, 0, 0};
+    const tlv_param_count_t *p_param = &null_param;
+    uint8_t *p_tlv_n;
+    int j = 0;
+
+    switch (tlv_get_type(p_tlv)) {
+        case EMMG_TYPE_CHANNEL_SETUP:
+            p_param = p_emmg_params_channel_setup; break;
+        case EMMG_TYPE_CHANNEL_TEST:
+            p_param = p_emmg_params_channel_test; break;
+        case EMMG_TYPE_CHANNEL_STATUS:
+            p_param = p_emmg_params_channel_status; break;
+        case EMMG_TYPE_CHANNEL_CLOSE:
+            p_param = p_emmg_params_channel_close; break;
+        case EMMG_TYPE_CHANNEL_ERROR:
+            p_param = p_emmg_params_channel_error; break;
+        case EMMG_TYPE_STREAM_SETUP:
+            p_param = p_emmg_params_stream_setup; break;
+        case EMMG_TYPE_STREAM_TEST:
+            p_param = p_emmg_params_stream_test; break;
+        case EMMG_TYPE_STREAM_STATUS:
+            p_param = p_emmg_params_stream_status; break;
+        case EMMG_TYPE_STREAM_CLOSEREQ:
+        case EMMG_TYPE_STREAM_CLOSERESP:
+            p_param = p_emmg_params_stream_close; break;
+        case EMMG_TYPE_STREAM_ERROR:
+            p_param = p_emmg_params_stream_error; break;
+        case EMMG_TYPE_BW_ALLOC:
+        case EMMG_TYPE_BW_REQ:
+            p_param = p_emmg_params_bandwidth; break;
+        case EMMG_TYPE_DATA_PROVISION:
+            p_param = p_emmg_params_data_provision; break;
+        default:
+            break;
+    }
+
+    while (p_param->i_type)
+        if (!tlv_validate_count_param(p_tlv, p_param++))
+            return false;
+
+    while ((p_tlv_n = tlv_get_param(p_tlv, j)) != NULL) {
+        j++;
+        if (!emmg_validate_param(p_tlv_n)) return false;
+    }
+
+    return true;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/dvb/si/desc_56.h b/dvb/sub.h
similarity index 57%
copy from dvb/si/desc_56.h
copy to dvb/sub.h
index ac13ded..0759649 100644
--- a/dvb/si/desc_56.h
+++ b/dvb/sub.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * desc_56.h: ETSI EN 300 468 Descriptor 0x56: Teletext descriptor
+ * sub.h: ETSI EN 300 743 Subtitling Systems
  *****************************************************************************
- * Copyright (C) 2009-2010 VideoLAN
+ * Copyright (C) 2014 VideoLAN
  *
  * Authors: Christophe Massiot <massiot at via.ecp.fr>
  *
@@ -27,15 +27,13 @@
 
 /*
  * Normative references:
- *  - ETSI EN 300 468 V1.11.1 (2010-04) (SI in DVB systems)
+ *  - ETSI EN 300 743 V1.5.1 (2014-01) (Subtitling Systems)
  */
 
-#ifndef __BITSTREAM_DVB_DESC_56_H__
-#define __BITSTREAM_DVB_DESC_56_H__
+#ifndef __BITSTREAM_DVB_SUB_H__
+#define __BITSTREAM_DVB_SUB_H__
 
-#include <bitstream/common.h>
-#include <bitstream/mpeg/psi/descriptors.h>
-#include <bitstream/dvb/si/desc_46.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -43,27 +41,39 @@ extern "C"
 #endif
 
 /*****************************************************************************
- * Descriptor 0x56: Teletext descriptor
+ * PES data field
  *****************************************************************************/
-#define DESC56_HEADER_SIZE      DESC46_HEADER_SIZE
-#define DESC56_LANGUAGE_SIZE    DESC46_LANGUAGE_SIZE
+#define DVBSUB_HEADER_SIZE      2
+#define DVBSUB_DATA_IDENTIFIER  0x20
 
-static inline void desc56_init(uint8_t *p_desc)
+/*****************************************************************************
+ * Subtitling segment
+ *****************************************************************************/
+#define DVBSUBS_HEADER_SIZE     6
+#define DVBSUBS_SYNC            0xf
+
+#define DVBSUBS_PAGE_COMPOSITION        0x10
+#define DVBSUBS_REGION_COMPOSITION      0x11
+#define DVBSUBS_CLUT_DEFINITION         0x12
+#define DVBSUBS_OBJECT_DATA             0x13
+#define DVBSUBS_DISPLAY_DEFINITION      0x14
+#define DVBSUBS_DISPARITY_SIGNALLING    0x15
+#define DVBSUBS_END_OF_DISPLAY_SET      0x80
+
+static inline uint8_t dvbsubs_get_type(const uint8_t *p_dvbsubs)
 {
-    desc_set_tag(p_desc, 0x56);
+    return p_dvbsubs[1];
 }
 
-#define desc56_get_language desc46_get_language
-#define desc56n_set_code desc46n_set_code
-#define desc56n_get_code desc46n_get_code
-#define desc56n_set_teletexttype desc46n_set_teletexttype
-#define desc56n_get_teletexttype desc46n_get_teletexttype
-#define desc56n_set_teletextmagazine desc46n_set_teletextmagazine
-#define desc56n_get_teletextmagazine desc46n_get_teletextmagazine
-#define desc56n_set_teletextpage desc46n_set_teletextpage
-#define desc56n_get_teletextpage desc46n_get_teletextpage
-#define desc56_validate desc46_validate
-#define desc56_print desc46_print
+static inline uint16_t dvbsubs_get_page(const uint8_t *p_dvbsubs)
+{
+    return (p_dvbsubs[2] << 8) | p_dvbsubs[3];
+}
+
+static inline uint16_t dvbsubs_get_length(const uint8_t *p_dvbsubs)
+{
+    return (p_dvbsubs[4] << 8) | p_dvbsubs[5];
+}
 
 #ifdef __cplusplus
 }
diff --git a/examples/Makefile b/examples/Makefile
index 43ebc95..61ac82f 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,7 +1,7 @@
 CFLAGS = -Wall -O2 -g
 CFLAGS_LOCAL = -Wall -O2 -g -I. -I../..
-LDFLAGS = 
-OBJ = dvb_print_si dvb_gen_si dvb_ecmg dvb_ecmg_test mpeg_print_pcr rtp_check_seqnum
+LDFLAGS = -lrt
+OBJ = dvb_print_si dvb_gen_si dvb_ecmg dvb_ecmg_test mpeg_print_pcr rtp_check_seqnum mpeg_restamp
 
 ifeq "$(shell uname -s)" "Darwin"
 LDFLAGS += -liconv
diff --git a/examples/dvb_gen_si.c b/examples/dvb_gen_si.c
index e929cc6..b5e696c 100644
--- a/examples/dvb_gen_si.c
+++ b/examples/dvb_gen_si.c
@@ -2,9 +2,11 @@
  * dvb_gen_si.c: Generate SI tables and descriptors
  *****************************************************************************
  * Copyright (c) 2011 Unix Solutions Ltd.
+ * Copyright (c) 2015 VideoLAN
  *
  * Authors:
  *   Georgi Chorbadzhiyski <gf at unixsol.org>
+ *   Christophe Massiot <massiot at via.ecp.fr>
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -38,6 +40,8 @@
 #include <bitstream/mpeg/psi.h>
 #include <bitstream/dvb/si.h>
 #include <bitstream/dvb/si_print.h>
+#include <bitstream/scte/35.h>
+#include <bitstream/scte/35_print.h>
 
 uint16_t tsid     = 10000;
 uint16_t sid      = 20000;
@@ -45,6 +49,7 @@ uint16_t event_id = 30000;
 uint16_t onid     = 40000;
 
 uint16_t pmt_pid  = 100;
+uint16_t scte35_pid  = 200;
 
 time_t ts_0 = 1234567890;
 time_t ts_1 = 1;
@@ -2359,6 +2364,7 @@ static void generate_eit(void) {
     psi_set_current(eit);
 
     eit_set_length(eit, 0);
+    eit_set_sid(eit, sid);
     eit_set_tsid(eit, tsid);
     eit_set_onid(eit, onid);
     eit_set_segment_last_sec_number(eit, 0);
@@ -2383,8 +2389,7 @@ static void generate_eit(void) {
         eitn_set_event_id(eit_n, event_id);
         eitn_set_start_time(eit_n, dvb_time_encode_UTC(ts_0));
         eitn_set_duration_bcd(eit_n, dvb_time_encode_duration(86399));
-        eitn_set_running_status(eit_n, 2);
-        eitn_set_free_CA_mode(eit_n, false);
+        eitn_set_running(eit_n, 2);
         eitn_set_desclength(eit_n, 0);
         {
             // Add descriptors to transport_stream_n
@@ -2404,8 +2409,7 @@ static void generate_eit(void) {
         eitn_set_event_id(eit_n, event_id + 100);
         eitn_set_start_time(eit_n, dvb_time_encode_UTC(ts_1));
         eitn_set_duration_bcd(eit_n, dvb_time_encode_duration(3600));
-        eitn_set_running_status(eit_n, 1);
-        eitn_set_free_CA_mode(eit_n, false);
+        eitn_set_running(eit_n, 1);
         eitn_set_desclength(eit_n, 0);
         {
             // Add descriptors to transport_stream_n
@@ -2434,8 +2438,7 @@ static void generate_eit(void) {
         eitn_set_event_id(eit_n, event_id + 200);
         eitn_set_start_time(eit_n, dvb_time_encode_UTC(ts_2));
         eitn_set_duration_bcd(eit_n, dvb_time_encode_duration(7200));
-        eitn_set_running_status(eit_n, 0);
-        eitn_set_free_CA_mode(eit_n, false);
+        eitn_set_running(eit_n, 0);
         eitn_set_desclength(eit_n, 0);
         {
             // Add descriptors to transport_stream_n
@@ -2470,8 +2473,8 @@ static void generate_eit(void) {
         eitn_set_event_id(eit_n, event_id + 300);
         eitn_set_start_time(eit_n, dvb_time_encode_UTC(ts_2));
         eitn_set_duration_bcd(eit_n, dvb_time_encode_duration(7200));
-        eitn_set_running_status(eit_n, 4);
-        eitn_set_free_CA_mode(eit_n, true);
+        eitn_set_running(eit_n, 4);
+        eitn_set_ca(eit_n);
         eitn_set_desclength(eit_n, 0);
         {
             // Add descriptors to transport_stream_n
@@ -2601,7 +2604,7 @@ static void generate_rst(void) {
     rstn_set_onid(rst_n, onid);
     rstn_set_service_id(rst_n, sid);
     rstn_set_event_id(rst_n, event_id);
-    rstn_set_running_status(rst_n, 1);
+    rstn_set_running(rst_n, 1);
 
     rst_n = rst_get_status(rst, j++);
     rstn_init(rst_n);
@@ -2609,7 +2612,7 @@ static void generate_rst(void) {
     rstn_set_onid(rst_n, onid + 100);
     rstn_set_service_id(rst_n, sid + 100);
     rstn_set_event_id(rst_n, event_id + 100);
-    rstn_set_running_status(rst_n, 2);
+    rstn_set_running(rst_n, 2);
 
     rst_n = rst_get_status(rst, j++);
     rstn_init(rst_n);
@@ -2617,7 +2620,7 @@ static void generate_rst(void) {
     rstn_set_onid(rst_n, onid + 200);
     rstn_set_service_id(rst_n, sid + 200);
     rstn_set_event_id(rst_n, event_id + 200);
-    rstn_set_running_status(rst_n, 3);
+    rstn_set_running(rst_n, 3);
 
     // Set correct rst length
     rst_n = rst_get_status(rst, j); // Get offset of the end of last status
@@ -2961,6 +2964,12 @@ static void generate_pmt(void) {
             descs_set_length(desc_loop, desc - desc_loop - DESCS_HEADER_SIZE);
         }
 
+        pmt_n = pmt_get_es(pmt, pmt_n_counter++);
+        pmtn_init(pmt_n);
+        pmtn_set_streamtype(pmt_n, PMT_STREAMTYPE_SCTE_35);
+        pmtn_set_pid(pmt_n, scte35_pid);
+        pmtn_set_desclength(pmt_n, 0);
+
         // Set transport_stream_loop length
         pmt_n = pmt_get_es(pmt, pmt_n_counter); // Get last service
         pmt_set_length(pmt, pmt_n - pmt_get_es(pmt, 0) + pmt_get_desclength(pmt));
@@ -3036,7 +3045,7 @@ static void generate_sit(void) {
         sit_n = sit_get_service(sit, sit_n_counter++);
         sitn_init(sit_n);
         sitn_set_sid(sit_n, sid);
-        sitn_set_running_status(sit_n, 1);
+        sitn_set_running(sit_n, 1);
         sitn_set_desclength(sit_n, 0);
         {
             // Add descriptors to transport_stream_n
@@ -3061,7 +3070,7 @@ static void generate_sit(void) {
         sit_n = sit_get_service(sit, sit_n_counter++);
         sitn_init(sit_n);
         sitn_set_sid(sit_n, sid + 1000);
-        sitn_set_running_status(sit_n, 3);
+        sitn_set_running(sit_n, 3);
         sitn_set_desclength(sit_n, 0);
 
         // Set transport_stream_loop length
@@ -3075,6 +3084,58 @@ static void generate_sit(void) {
     free(sit);
 }
 
+/* SCTE 35 Splice Information Table */
+static void generate_scte35(void) {
+    uint8_t *scte35 = psi_allocate();
+
+    // Generate empty section
+    scte35_init(scte35);
+    psi_set_length(scte35, PSI_MAX_SIZE);
+    scte35_set_pts_adjustment(scte35, 0);
+    scte35_null_init(scte35);
+    scte35_set_desclength(scte35, 0);
+    psi_set_length(scte35,
+            scte35_get_descl(scte35) + PSI_CRC_SIZE - scte35 - PSI_HEADER_SIZE);
+    psi_set_crc(scte35);
+    output_psi_section(scte35, scte35_pid, &cc);
+
+    // Generate insert section
+    scte35_init(scte35);
+    psi_set_length(scte35, PSI_MAX_SIZE);
+    scte35_set_pts_adjustment(scte35, 0);
+    scte35_insert_init(scte35,
+            SCTE35_INSERT_HEADER2_SIZE +
+            SCTE35_SPLICE_TIME_HEADER_SIZE + SCTE35_SPLICE_TIME_TIME_SIZE +
+            SCTE35_BREAK_DURATION_HEADER_SIZE + SCTE35_INSERT_FOOTER_SIZE);
+    scte35_insert_set_cancel(scte35, false);
+    scte35_insert_set_event_id(scte35, 4242);
+    scte35_insert_set_out_of_network(scte35, true);
+    scte35_insert_set_program_splice(scte35, true);
+    scte35_insert_set_duration(scte35, true);
+    scte35_insert_set_splice_immediate(scte35, false);
+
+    uint8_t *splice_time = scte35_insert_get_splice_time(scte35);
+    scte35_splice_time_init(splice_time);
+    scte35_splice_time_set_time_specified(splice_time, true);
+    scte35_splice_time_set_pts_time(splice_time, 270000000);
+
+    uint8_t *duration = scte35_insert_get_break_duration(scte35);
+    scte35_break_duration_init(duration);
+    scte35_break_duration_set_auto_return(duration, true);
+    scte35_break_duration_set_duration(duration, 27000000);
+
+    scte35_insert_set_unique_program_id(scte35, 2424);
+    scte35_insert_set_avail_num(scte35, 0);
+    scte35_insert_set_avails_expected(scte35, 0);
+    scte35_set_desclength(scte35, 0);
+    psi_set_length(scte35,
+            scte35_get_descl(scte35) + PSI_CRC_SIZE - scte35 - PSI_HEADER_SIZE);
+    psi_set_crc(scte35);
+    output_psi_section(scte35, scte35_pid, &cc);
+
+    free(scte35);
+}
+
 int main(void)
 {
     generate_pat();
@@ -3090,6 +3151,7 @@ int main(void)
     generate_pmt();
     generate_dit();
     generate_sit();
+    generate_scte35();
 
     return EXIT_SUCCESS;
 }
diff --git a/examples/dvb_print_si.c b/examples/dvb_print_si.c
index 469428d..e7d8e7e 100644
--- a/examples/dvb_print_si.c
+++ b/examples/dvb_print_si.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * dvb_print_si.c: Prints tables from a TS file
  *****************************************************************************
- * Copyright (C) 2010-2011 VideoLAN
+ * Copyright (C) 2010-2015 VideoLAN
  *
  * Authors: Christophe Massiot <massiot at via.ecp.fr>
  *
@@ -41,6 +41,8 @@
 #include <bitstream/dvb/si.h>
 #include <bitstream/dvb/si_print.h>
 #include <bitstream/mpeg/psi_print.h>
+#include <bitstream/scte/35.h>
+#include <bitstream/scte/35_print.h>
 
 /*****************************************************************************
  * Local declarations
@@ -57,15 +59,26 @@ typedef struct ts_pid_t {
     uint16_t i_psi_buffer_used;
 } ts_pid_t;
 
+static ts_pid_t p_pids[MAX_PIDS];
+
 typedef struct sid_t {
     uint16_t i_sid, i_pmt_pid;
     uint8_t *p_current_pmt;
+    PSI_TABLE_DECLARE(pp_eit_sections);
 } sid_t;
 
-ts_pid_t p_pids[MAX_PIDS];
 static sid_t **pp_sids = NULL;
 static int i_nb_sids = 0;
 
+typedef struct bouquet_t {
+    uint16_t i_bouquet;
+    PSI_TABLE_DECLARE(pp_current_bat_sections);
+    PSI_TABLE_DECLARE(pp_next_bat_sections);
+} bouquet_t;
+
+static bouquet_t **pp_bouquets = NULL;
+static int i_nb_bouquets = 0;
+
 static PSI_TABLE_DECLARE(pp_current_pat_sections);
 static PSI_TABLE_DECLARE(pp_next_pat_sections);
 static PSI_TABLE_DECLARE(pp_current_cat_sections);
@@ -74,8 +87,6 @@ static PSI_TABLE_DECLARE(pp_current_tsdt_sections);
 static PSI_TABLE_DECLARE(pp_next_tsdt_sections);
 static PSI_TABLE_DECLARE(pp_current_nit_sections);
 static PSI_TABLE_DECLARE(pp_next_nit_sections);
-static PSI_TABLE_DECLARE(pp_current_bat_sections);
-static PSI_TABLE_DECLARE(pp_next_bat_sections);
 static PSI_TABLE_DECLARE(pp_current_sdt_sections);
 static PSI_TABLE_DECLARE(pp_next_sdt_sections);
 
@@ -99,14 +110,17 @@ enum tables_t {
     TABLE_DIT,
     TABLE_SIT,
     TABLE_PMT,
+    TABLE_SCTE35,
     TABLE_END
 };
 static const char * const ppsz_all_tables[TABLE_END] = {
     "pat", "cat", "tsdt", "nit", "bat", "sdt", "eit", "tot", "tdt", "rst",
-    "dit", "sit", "pmt"
+    "dit", "sit", "pmt", "scte35"
 };
 static bool pb_print_table[TABLE_END];
 
+static void handle_pmt_es(uint8_t *p_pmt, bool b_select);
+
 /*****************************************************************************
  * print_wrapper
  *****************************************************************************/
@@ -118,6 +132,7 @@ static void print_wrapper(void *_unused, const char *psz_format, ...)
     strcpy(psz_fmt, psz_format);
     strcat(psz_fmt, "\n");
     vprintf(psz_fmt, args);
+    va_end(args);
 }
 
 /*****************************************************************************
@@ -153,6 +168,7 @@ static char *iconv_wrapper(void *_unused, const char *psz_encoding,
                 psz_native_encoding);
         return iconv_append_null(p_string, i_length);
     }
+    psz_current_encoding = psz_encoding;
 
     /* converted strings can be up to six times larger */
     i_out_length = i_length * 6;
@@ -246,6 +262,7 @@ static void handle_pat(void)
                     pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
                     pp_sids[i_pmt] = p_sid;
                     p_sid->p_current_pmt = NULL;
+                    psi_table_init(p_sid->pp_eit_sections);
                 }
                 else
                     p_sid = pp_sids[i_pmt];
@@ -276,8 +293,11 @@ static void handle_pat(void)
                     for (i_pmt = 0; i_pmt < i_nb_sids; i_pmt++)
                         if (pp_sids[i_pmt]->i_sid == i_sid) {
                             pp_sids[i_pmt]->i_sid = 0;
+                            handle_pmt_es(pp_sids[i_pmt]->p_current_pmt, false);
                             free(pp_sids[i_pmt]->p_current_pmt);
                             pp_sids[i_pmt]->p_current_pmt = NULL;
+                            psi_table_free(pp_sids[i]->pp_eit_sections);
+                            psi_table_init(pp_sids[i]->pp_eit_sections);
                             break;
                         }
                 }
@@ -437,6 +457,28 @@ static void handle_tsdt_section(uint16_t i_pid, uint8_t *p_section)
 /*****************************************************************************
  * handle_pmt
  *****************************************************************************/
+static void handle_pmt_es(uint8_t *p_pmt, bool b_select)
+{
+    int j = 0;
+    uint8_t *p_es;
+    while ((p_es = pmt_get_es(p_pmt, j)) != NULL) {
+        uint16_t i_pid = pmtn_get_pid(p_es);
+        uint8_t i_type = pmtn_get_streamtype(p_es);
+        j++;
+
+        switch (i_type) {
+            case PMT_STREAMTYPE_SCTE_35:
+                if (b_select)
+                    p_pids[i_pid].i_psi_refcount++;
+                else
+                    p_pids[i_pid].i_psi_refcount--;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
 static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
 {
     uint16_t i_sid = pmt_get_program(p_pmt);
@@ -477,6 +519,7 @@ static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
         p_sid->i_sid = i_sid;
         p_sid->i_pmt_pid = i_pid;
         p_sid->p_current_pmt = NULL;
+        psi_table_init(p_sid->pp_eit_sections);
     } else {
         p_sid = pp_sids[i];
         if (i_pid != p_sid->i_pmt_pid) {
@@ -499,8 +542,12 @@ static void handle_pmt(uint16_t i_pid, uint8_t *p_pmt)
         return;
     }
 
+    if (p_sid->p_current_pmt)
+        handle_pmt_es(p_sid->p_current_pmt, false);
+
     free(p_sid->p_current_pmt);
     p_sid->p_current_pmt = p_pmt;
+    handle_pmt_es(p_pmt, true);
 
     if (pb_print_table[TABLE_PMT])
         pmt_print(p_pmt, print_wrapper, NULL, iconv_wrapper, NULL,
@@ -528,8 +575,8 @@ static void handle_nit(void)
         default:
             printf("invalid NIT received\n");
         }
-        psi_table_free( pp_next_nit_sections );
-        psi_table_init( pp_next_nit_sections );
+        psi_table_free(pp_next_nit_sections);
+        psi_table_init(pp_next_nit_sections);
         return;
     }
 
@@ -567,17 +614,18 @@ static void handle_nit_section(uint16_t i_pid, uint8_t *p_section)
 /*****************************************************************************
  * handle_bat
  *****************************************************************************/
-static void handle_bat(void)
+static void handle_bat(bouquet_t *p_bouquet)
 {
-    if (psi_table_validate(pp_current_bat_sections) &&
-        psi_table_compare(pp_current_bat_sections, pp_next_bat_sections)) {
+    if (psi_table_validate(p_bouquet->pp_current_bat_sections) &&
+        psi_table_compare(p_bouquet->pp_current_bat_sections,
+                          p_bouquet->pp_next_bat_sections)) {
         /* Same version BAT. Shortcut. */
-        psi_table_free(pp_next_bat_sections);
-        psi_table_init(pp_next_bat_sections);
+        psi_table_free(p_bouquet->pp_next_bat_sections);
+        psi_table_init(p_bouquet->pp_next_bat_sections);
         return;
     }
 
-    if (!bat_table_validate(pp_next_bat_sections)) {
+    if (!bat_table_validate(p_bouquet->pp_next_bat_sections)) {
         switch (i_print_type) {
         case PRINT_XML:
             printf("<ERROR type=\"invalid_bat\"/>\n");
@@ -585,23 +633,28 @@ static void handle_bat(void)
         default:
             printf("invalid BAT received\n");
         }
-        psi_table_free( pp_next_bat_sections );
-        psi_table_init( pp_next_bat_sections );
+        psi_table_free(p_bouquet->pp_next_bat_sections);
+        psi_table_init(p_bouquet->pp_next_bat_sections);
         return;
     }
 
     /* Switch tables. */
-    psi_table_free(pp_current_bat_sections);
-    psi_table_copy(pp_current_bat_sections, pp_next_bat_sections);
-    psi_table_init(pp_next_bat_sections);
+    psi_table_free(p_bouquet->pp_current_bat_sections);
+    psi_table_copy(p_bouquet->pp_current_bat_sections,
+                   p_bouquet->pp_next_bat_sections);
+    psi_table_init(p_bouquet->pp_next_bat_sections);
 
     if (pb_print_table[TABLE_BAT])
-        bat_table_print(pp_current_bat_sections, print_wrapper, NULL,
+        bat_table_print(p_bouquet->pp_current_bat_sections, print_wrapper, NULL,
                         iconv_wrapper, NULL, i_print_type);
 }
 
 static void handle_bat_section(uint16_t i_pid, uint8_t *p_section)
 {
+    uint16_t i_bouquet;
+    bouquet_t *p_bouquet;
+    int i;
+
     if (i_pid != BAT_PID || !bat_validate(p_section)) {
         switch (i_print_type) {
         case PRINT_XML:
@@ -615,10 +668,24 @@ static void handle_bat_section(uint16_t i_pid, uint8_t *p_section)
         return;
     }
 
-    if (!psi_table_section(pp_next_bat_sections, p_section))
+    i_bouquet = psi_get_tableidext(p_section);
+    for (i = 0; i < i_nb_bouquets; i++)
+        if (pp_bouquets[i]->i_bouquet && pp_bouquets[i]->i_bouquet == i_bouquet)
+            break;
+    if (i == i_nb_bouquets) {
+        p_bouquet = malloc(sizeof(bouquet_t));
+        pp_bouquets = realloc(pp_bouquets, ++i_nb_bouquets * sizeof(bouquet_t *));
+        pp_bouquets[i] = p_bouquet;
+        p_bouquet->i_bouquet = i_bouquet;
+        psi_table_init(p_bouquet->pp_current_bat_sections);
+        psi_table_init(p_bouquet->pp_next_bat_sections);
+    } else
+        p_bouquet = pp_bouquets[i];
+
+    if (!psi_table_section(p_bouquet->pp_next_bat_sections, p_section))
         return;
 
-    handle_bat();
+    handle_bat(p_bouquet);
 }
 
 /*****************************************************************************
@@ -681,9 +748,14 @@ static void handle_sdt_section(uint16_t i_pid, uint8_t *p_section)
 /*****************************************************************************
  * handle_eit
  *****************************************************************************/
-static void handle_eit_section(uint16_t i_pid, uint8_t *p_eit)
+static void handle_eit_section(uint16_t i_pid, uint8_t *p_section)
 {
-    if (i_pid != EIT_PID || !eit_validate(p_eit)) {
+    uint16_t i_sid;
+    uint8_t i_section;
+    sid_t *p_sid;
+    int i;
+
+    if (i_pid != EIT_PID || !eit_validate(p_section)) {
         switch (i_print_type) {
         case PRINT_XML:
             printf("<ERROR type=\"invalid_eit_section\" pid=\"%hu\"/>\n",
@@ -692,15 +764,49 @@ static void handle_eit_section(uint16_t i_pid, uint8_t *p_eit)
         default:
             printf("invalid EIT section received on PID %hu\n", i_pid);
         }
-        free(p_eit);
+        free(p_section);
+        return;
+    }
+
+    i_sid = psi_get_tableidext(p_section);
+    for (i = 0; i < i_nb_sids; i++)
+        if (pp_sids[i]->i_sid && pp_sids[i]->i_sid == i_sid)
+            break;
+    if (i == i_nb_sids) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"ghost_eit\" sid=\"%hu\"/>\n", i_sid);
+            break;
+        default:
+            printf("ghost EIT for service %hu\n", i_sid);
+        }
+        p_sid = malloc(sizeof(sid_t));
+        pp_sids = realloc(pp_sids, ++i_nb_sids * sizeof(sid_t *));
+        pp_sids[i] = p_sid;
+        p_sid->i_sid = i_sid;
+        p_sid->i_pmt_pid = 0;
+        p_sid->p_current_pmt = NULL;
+        psi_table_init(p_sid->pp_eit_sections);
+    } else
+        p_sid = pp_sids[i];
+
+    /* We do not use psi_table_* primitives as the spec allows for holes in
+     * section numbering, and there is no sure way to know whether you have
+     * gathered all sections. */
+    i_section = psi_get_section(p_section);
+    if (p_sid->pp_eit_sections[i_section] != NULL &&
+        psi_compare(p_sid->pp_eit_sections[i_section], p_section)) {
+        /* Identical section. Shortcut. */
+        free(p_section);
         return;
     }
 
+    free(p_sid->pp_eit_sections[i_section]);
+    p_sid->pp_eit_sections[i_section] = p_section;
+
     if (pb_print_table[TABLE_EIT])
-        eit_print(p_eit, print_wrapper, NULL, iconv_wrapper, NULL,
+        eit_print(p_section, print_wrapper, NULL, iconv_wrapper, NULL,
                   i_print_type);
-
-    free(p_eit);
 }
 
 /*****************************************************************************
@@ -829,6 +935,31 @@ static void handle_sit_section(uint16_t i_pid, uint8_t *p_sit)
 }
 
 /*****************************************************************************
+ * handle_scte35
+ *****************************************************************************/
+static void handle_scte35_section(uint16_t i_pid, uint8_t *p_scte35)
+{
+    if (!scte35_validate(p_scte35)) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"invalid_scte35_section\" pid=\"%hu\"/>\n",
+                   i_pid);
+            break;
+        default:
+            printf("invalid SCTE35 section received on PID %hu\n", i_pid);
+        }
+        free(p_scte35);
+        return;
+    }
+
+    if (pb_print_table[TABLE_SCTE35] &&
+        scte35_get_command_type(p_scte35) != SCTE35_NULL_COMMAND)
+        scte35_print(p_scte35, print_wrapper, NULL, i_print_type);
+
+    free(p_scte35);
+}
+
+/*****************************************************************************
  * handle_section
  *****************************************************************************/
 static void handle_section(uint16_t i_pid, uint8_t *p_section)
@@ -896,14 +1027,15 @@ static void handle_section(uint16_t i_pid, uint8_t *p_section)
         handle_sit_section(i_pid, p_section);
         break;
 
-    default:
-        if (i_table_id == EIT_TABLE_ID_PF_ACTUAL ||
-           (i_table_id >= EIT_TABLE_ID_SCHED_ACTUAL_FIRST &&
-            i_table_id <= EIT_TABLE_ID_SCHED_ACTUAL_LAST)) {
-            handle_eit_section(i_pid, p_section);
-            break;
-        }
+    case EIT_TABLE_ID_PF_ACTUAL:
+        handle_eit_section(i_pid, p_section);
+        break;
+
+    case SCTE35_TABLE_ID:
+        handle_scte35_section(i_pid, p_section);
+        break;
 
+    default:
         free( p_section );
         break;
     }
@@ -1009,8 +1141,8 @@ int main(int i_argc, char **ppsz_argv)
 
     for (i = 0; i < 8192; i++) {
         p_pids[i].i_last_cc = -1;
-        psi_assemble_init( &p_pids[i].p_psi_buffer,
-                           &p_pids[i].i_psi_buffer_used );
+        psi_assemble_init(&p_pids[i].p_psi_buffer,
+                          &p_pids[i].i_psi_buffer_used);
     }
 
     p_pids[PAT_PID].i_psi_refcount++;
@@ -1025,6 +1157,17 @@ int main(int i_argc, char **ppsz_argv)
     p_pids[DIT_PID].i_psi_refcount++;
     p_pids[SIT_PID].i_psi_refcount++;
 
+    psi_table_init(pp_current_pat_sections);
+    psi_table_init(pp_next_pat_sections);
+    psi_table_init(pp_current_cat_sections);
+    psi_table_init(pp_next_cat_sections);
+    psi_table_init(pp_current_tsdt_sections);
+    psi_table_init(pp_next_tsdt_sections);
+    psi_table_init(pp_current_nit_sections);
+    psi_table_init(pp_next_nit_sections);
+    psi_table_init(pp_current_sdt_sections);
+    psi_table_init(pp_next_sdt_sections);
+
     if (psz_tables != NULL) {
         char *psz_table = psz_tables;
         for (i = 0; i < TABLE_END; i++)
@@ -1084,5 +1227,37 @@ int main(int i_argc, char **ppsz_argv)
         break;
     }
 
+    if (iconv_handle != (iconv_t)-1)
+        iconv_close(iconv_handle);
+
+    psi_table_free(pp_current_pat_sections);
+    psi_table_free(pp_next_pat_sections);
+    psi_table_free(pp_current_cat_sections);
+    psi_table_free(pp_next_cat_sections);
+    psi_table_free(pp_current_tsdt_sections);
+    psi_table_free(pp_next_tsdt_sections);
+    psi_table_free(pp_current_nit_sections);
+    psi_table_free(pp_next_nit_sections);
+    psi_table_free(pp_current_sdt_sections);
+    psi_table_free(pp_next_sdt_sections);
+
+    for (i = 0; i < i_nb_bouquets; i++) {
+        psi_table_free(pp_bouquets[i]->pp_current_bat_sections);
+        psi_table_free(pp_bouquets[i]->pp_next_bat_sections);
+        free(pp_bouquets[i]);
+    }
+    free(pp_bouquets);
+
+    for (i = 0; i < i_nb_sids; i++) {
+        psi_table_free(pp_sids[i]->pp_eit_sections);
+        free(pp_sids[i]->p_current_pmt);
+        free(pp_sids[i]);
+    }
+    free(pp_sids);
+
+    for (i = 0; i < 8192; i++)
+        psi_assemble_reset(&p_pids[i].p_psi_buffer,
+                           &p_pids[i].i_psi_buffer_used);
+
     return EXIT_SUCCESS;
 }
diff --git a/examples/dvb_print_si.output.txt b/examples/dvb_print_si.output.txt
index 815f3ea..7b2cd5a 100644
--- a/examples/dvb_print_si.output.txt
+++ b/examples/dvb_print_si.output.txt
@@ -70,9 +70,9 @@ new NIT actual networkid=40000 version=1
         - mobile_handover handover_type=1 origin_type=0 nid=41000 initial_sid=21000
   * ts tsid=10300 onid=40300
 end NIT
-new BAT networkid=40000 version=0
+new BAT bouquetid=40000 version=0
 end BAT
-new BAT networkid=40000 version=1
+new BAT bouquetid=40000 version=1
     - desc 47 bouquetname="Test Bouquet Name"
     - desc 5c multilingual_bouquet_name code="eng" bouquetname="M Bouquet"
     - desc 5c multilingual_bouquet_name code="fre" bouquetname="M Bouquet"
@@ -141,12 +141,12 @@ new SDT actual tsid=10000 version=1 onid=40000
     - desc 4b nvod_reference tsid=10200 onid=40200 sid=20200
     - desc 5f private_data specifier=0xaabbccdd
 end SDT
-new EIT tableid=0x4e type=actual_pf version=0 tsid=10000 onid=40000 seg_last_sec_number=0 last_table_id=0x00
+new EIT tableid=0x4e type=actual_pf service_id=20000 version=0 section=0/0 tsid=10000 onid=40000
 end EIT
-new EIT tableid=0x4e type=actual_pf version=1 tsid=10000 onid=40000 seg_last_sec_number=0 last_table_id=0x00
-  * EVENT id=30000 start_time=1234567890 start_time_dec="2009-02-13 23:31:30 UTC" duration=86399 duration_dec=23:59:59 running_status=2 free_CA_mode=0
+new EIT tableid=0x4e type=actual_pf service_id=20000 version=1 section=0/0 tsid=10000 onid=40000
+  * EVENT id=30000 start_time=1234567890 start_time_dec="2009-02-13 23:31:30 UTC" duration=86399 duration_dec=23:59:59 running=2 free_CA=0
     - desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
-  * EVENT id=30100 start_time=1 start_time_dec="1970-01-01 00:00:01 UTC" duration=3600 duration_dec=01:00:00 running_status=1 free_CA_mode=0
+  * EVENT id=30100 start_time=1 start_time_dec="1970-01-01 00:00:01 UTC" duration=3600 duration_dec=01:00:00 running=1 free_CA=0
     - desc 4a linkage tsid=10700 onid=40700 sid=20700 linkage=0x0d linkage_txt="event linkage"
         - event_linkage target_event_id=31000 target_listed=1 event_simulcast=1
     - desc 4e extended_event desc_number=0 last_desc_number=0 lang=eng text="Wow, what an event!"
@@ -155,7 +155,7 @@ new EIT tableid=0x4e type=actual_pf version=1 tsid=10000 onid=40000 seg_last_sec
        - extended_event_item description="Rating" text="***++"
     - desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
     - desc 61 short_smoothing_buffer sb_size=1 sb_leak_rate=10
-  * EVENT id=30200 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running_status=0 free_CA_mode=0
+  * EVENT id=30200 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running=0 free_CA=0
     - desc 4a linkage tsid=10800 onid=40800 sid=20800 linkage=0x0e linkage_txt="extended event linkage"
         - extended_event_linkage target_event_id=31000 target_listed=0 event_simulcast=1 link_type=1 link_type_txt="HD" target_id_type=3 target_id_type_txt="use user_defined_id" onid_id_flag=1 service_id_flag=1 user_defined_id=7878 target_tsid=0 target_onid=0 target_service_id=0
         - extended_event_linkage target_event_id=32000 target_listed=1 event_simulcast=1 link_type=0 link_type_txt="SD" target_id_type=0 target_id_type_txt="use tsid" onid_id_flag=1 service_id_flag=1 user_defined_id=0 target_tsid=0 target_onid=42000 target_service_id=22000
@@ -172,7 +172,7 @@ new EIT tableid=0x4e type=actual_pf version=1 tsid=10000 onid=40000 seg_last_sec
     - desc 55 parental_rating country_code=BUL rating=24 rating_txt="unknown"
     - desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
     - desc 4f time_shifted_service reference_sid=22000 reference_event_id=32000
-  * EVENT id=30300 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running_status=4 free_CA_mode=1
+  * EVENT id=30300 start_time=999999999 start_time_dec="2001-09-09 01:46:39 UTC" duration=7200 duration_dec=02:00:00 running=4 free_CA=1
     - desc 54 content content_l1=2 content_l2=4 user=78
     - desc 54 content content_l1=6 content_l2=8 user=177
     - desc 4d short_event lang=eng event_name="Major TV event" text="The event of the century!"
@@ -205,9 +205,9 @@ end TOT
 new RST
 end RST
 new RST
-  * status tsid="10000" onid="40000" service_id="20000" event_id="30000" running_status="1"
-  * status tsid="10100" onid="40100" service_id="20100" event_id="30100" running_status="2"
-  * status tsid="10200" onid="40200" service_id="20200" event_id="30200" running_status="3"
+  * status tsid="10000" onid="40000" service_id="20000" event_id="30000" running="1"
+  * status tsid="10100" onid="40100" service_id="20100" event_id="30100" running="2"
+  * status tsid="10200" onid="40200" service_id="20200" event_id="30200" running="3"
 end RST
 new PMT program=20000 version=0 pcrpid=110
 end PMT
@@ -332,6 +332,7 @@ new PMT program=20000 version=1 pcrpid=110
     - desc 42 stuffing length=4
     - desc 2b mpeg2_aac_audio profile=0x12 channel_config=0x05 additional_info=0x00
     - desc 7c aac profile_and_level="0x14" aac_type_flag="1" aac_type="0x1f"
+  * ES pid=200 streamtype=0x86 streamtype_txt="SCTE 35 Splice Information Table"
 end PMT
 new DIT transition_flag=1
 end DIT
@@ -341,9 +342,11 @@ new SIT version=0
 end SIT
 new SIT version=1
     - desc 63 partial_transport_stream peak_rate=5000 min_overall_smoothing_rate=7000 max_overall_smoothing_buffer=1000
-  * SERVICE sid=20000 running_status=1
+  * SERVICE sid=20000 running=1
     - desc 05 registration identifier=TEST
     - desc 05 registration identifier=TEST
     - desc 05 registration identifier=TEST
-  * SERVICE sid=21000 running_status=3
+  * SERVICE sid=21000 running=3
 end SIT
+new SCTE35 command=5 command_str=insert pts_adjustment=0 event_id=4242 cancel=false out_of_network=true program_splice=true splice_time=270000000 auto_return=true duration=27000000 unique_program_id=2424
+end SCTE35
diff --git a/examples/dvb_print_si.output.xml b/examples/dvb_print_si.output.xml
index 955713e..9de4947 100644
--- a/examples/dvb_print_si.output.xml
+++ b/examples/dvb_print_si.output.xml
@@ -120,9 +120,9 @@
 <TS tsid="10300" onid="40300">
 </TS>
 </NIT>
-<BAT tid="74" networkid="40000" version="0" current_next="1">
+<BAT tid="74" bouquetid="40000" version="0" current_next="1">
 </BAT>
-<BAT tid="74" networkid="40000" version="1" current_next="1">
+<BAT tid="74" bouquetid="40000" version="1" current_next="1">
 <DESC id="0x47" length="17" value="5465737420426f7571756574204e616d65">
 <BOUQUET_NAME_DESC bouquetname="Test Bouquet Name"/>
 </DESC>
@@ -248,15 +248,15 @@
 </DESC>
 </SERVICE>
 </SDT>
-<EIT tableid="0x4e" type="actual_pf" version="0" current_next="1" tsid="10000" onid="40000" seg_last_sec_number="0" last_table_id="0x00">
+<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="0" current_next="1" tsid="10000" onid="40000">
 </EIT>
-<EIT tableid="0x4e" type="actual_pf" version="1" current_next="1" tsid="10000" onid="40000" seg_last_sec_number="0" last_table_id="0x00">
-<EVENT id="30000" start_time="1234567890" start_time_dec="2009-02-13 23:31:30 UTC" duration="86399" duration_dec="23:59:59" running_status="2" free_CA_mode="0">
+<EIT tableid="0x4e" type="actual_pf" service_id="20000" version="1" current_next="1" tsid="10000" onid="40000">
+<EVENT id="30000" start_time="1234567890" start_time_dec="2009-02-13 23:31:30 UTC" duration="86399" duration_dec="23:59:59" running="2" free_CA="0">
 <DESC id="0x4d" length="44" value="656e670e4d616a6f72205456206576656e7419546865206576656e74206f66207468652063656e7475727921">
 <SHORT_EVENT_DESC lang="eng" event_name="Major TV event" text="The event of the century!"/>
 </DESC>
 </EVENT>
-<EVENT id="30100" start_time="1" start_time_dec="1970-01-01 00:00:01 UTC" duration="3600" duration_dec="01:00:00" running_status="1" free_CA_mode="0">
+<EVENT id="30100" start_time="1" start_time_dec="1970-01-01 00:00:01 UTC" duration="3600" duration_dec="01:00:00" running="1" free_CA="0">
 <DESC id="0x4a" length="10" value="29cc9efc50dc0d7918ff">
 <LINKAGE_DESC tsid="10700" onid="40700" sid="20700" linkage="0x0d" linkage_txt="event linkage">
 <EVENT_LINKAGE target_event_id="31000" target_listed="1" event_simulcast="1"/>
@@ -276,7 +276,7 @@
 <SHORT_SMOOTHING_BUFFER_DESC sb_size="1" sb_leak_rate="10"/>
 </DESC>
 </EVENT>
-<EVENT id="30200" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running_status="0" free_CA_mode="0">
+<EVENT id="30200" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running="0" free_CA="0">
 <DESC id="0x4a" length="31" value="2a309f6051400e79185f1ec67d00c3a41055f080e8e732c8a7f859d884d000">
 <LINKAGE_DESC tsid="10800" onid="40800" sid="20800" linkage="0x0e" linkage_txt="extended event linkage">
 <EXTENDED_EVENT_LINKAGE target_event_id="31000" target_listed="0" event_simulcast="1" link_type="1" link_type_txt="HD" target_id_type="3" target_id_type_txt="use user_defined_id" onid_id_flag="1" service_id_flag="1" user_defined_id="7878" target_tsid="0" target_onid="0" target_service_id="0"/>
@@ -307,7 +307,7 @@
 <TIME_SHIFTED_EVENT_DESC reference_sid="22000" reference_event_id="32000"/>
 </DESC>
 </EVENT>
-<EVENT id="30300" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running_status="4" free_CA_mode="1">
+<EVENT id="30300" start_time="999999999" start_time_dec="2001-09-09 01:46:39 UTC" duration="7200" duration_dec="02:00:00" running="4" free_CA="1">
 <DESC id="0x54" length="4" value="244e68b1">
 <CONTENT_DESC content_l1="2" content_l2="4" user="78"/>
 <CONTENT_DESC content_l1="6" content_l2="8" user="177"/>
@@ -350,9 +350,9 @@
 <RST>
 </RST>
 <RST>
-<STATUS tsid="10000" onid="40000" service_id="20000" event_id="30000" running_status="1"/>
-<STATUS tsid="10100" onid="40100" service_id="20100" event_id="30100" running_status="2"/>
-<STATUS tsid="10200" onid="40200" service_id="20200" event_id="30200" running_status="3"/>
+<STATUS tsid="10000" onid="40000" service_id="20000" event_id="30000" running="1"/>
+<STATUS tsid="10100" onid="40100" service_id="20100" event_id="30100" running="2"/>
+<STATUS tsid="10200" onid="40200" service_id="20200" event_id="30200" running="3"/>
 </RST>
 <PMT program="20000" version="0" current_next="1" pcrpid="110">
 </PMT>
@@ -412,12 +412,12 @@
 <AUDIO_STREAM_DESC free_format_tag="1" ID="1" layer="2" ID_txt="MPEG Audio" layer_txt="Layer II" vbr_audio_flag="1"/>
 </DESC>
 <DESC id="0x0a" length="24" value="656e6700656e6701656e6702656e670362756c0462756c00">
-<AUDIO_LANGUAGE_DESC language="eng" audiotype="0" autiotype_txt="undefined"/>
-<AUDIO_LANGUAGE_DESC language="eng" audiotype="1" autiotype_txt="clean effects"/>
-<AUDIO_LANGUAGE_DESC language="eng" audiotype="2" autiotype_txt="hearing impaired"/>
-<AUDIO_LANGUAGE_DESC language="eng" audiotype="3" autiotype_txt="visual impaired commentary"/>
-<AUDIO_LANGUAGE_DESC language="bul" audiotype="4" autiotype_txt="reserved"/>
-<AUDIO_LANGUAGE_DESC language="bul" audiotype="0" autiotype_txt="undefined"/>
+<AUDIO_LANGUAGE_DESC language="eng" audiotype="0" audiotype_txt="undefined"/>
+<AUDIO_LANGUAGE_DESC language="eng" audiotype="1" audiotype_txt="clean effects"/>
+<AUDIO_LANGUAGE_DESC language="eng" audiotype="2" audiotype_txt="hearing impaired"/>
+<AUDIO_LANGUAGE_DESC language="eng" audiotype="3" audiotype_txt="visual impaired commentary"/>
+<AUDIO_LANGUAGE_DESC language="bul" audiotype="4" audiotype_txt="reserved"/>
+<AUDIO_LANGUAGE_DESC language="bul" audiotype="0" audiotype_txt="undefined"/>
 </DESC>
 <DESC id="0x52" length="1" value="2e">
 <STREAM_IDENTIFIER_DESC component_tag="46"/>
@@ -603,10 +603,12 @@
 <DESC id="0x2b" length="3" value="120500">
 <MPEG2_AAC_AUDIO_DESC profile="0x12" channel_config="0x05" additional_info="0x00"/>
 </DESC>
-<DESC id="0x7c" length="3" value="14ff1f">
+<DESC id="0x7c" length="3" value="14801f">
 <AAC_DESC profile_and_level="0x14" aac_type_flag="1" aac_type="0x1f"/>
 </DESC>
 </ES>
+<ES pid="200" streamtype="0x86" streamtype_txt="SCTE 35 Splice Information Table">
+</ES>
 </PMT>
 <DIT transition_flag="1"/>
 <DIT transition_flag="0"/>
@@ -616,7 +618,7 @@
 <DESC id="0x63" length="8" value="c01388c01b58c3e8">
 <PARTIAL_TRANSPORT_STREAM_DESC peak_rate="5000" min_overall_smoothing_rate="7000" max_overall_smoothing_buffer="1000"/>
 </DESC>
-<SERVICE sid="20000" running_status="1">
+<SERVICE sid="20000" running="1">
 <DESC id="0x05" length="4" value="54455354">
 <REGISTRATION_DESC identifier="TEST"/>
 </DESC>
@@ -627,7 +629,9 @@
 <REGISTRATION_DESC identifier="TEST"/>
 </DESC>
 </SERVICE>
-<SERVICE sid="21000" running_status="3">
+<SERVICE sid="21000" running="3">
 </SERVICE>
 </SIT>
+<SCTE35 command="5" command_str="insert" pts_adjustment="0" event_id="4242" cancel="0" out_of_network="1" program_splice="1" splice_time="270000000" auto_return="1" duration="27000000" unique_program_id="2424">
+</SCTE35>
 </TS>
diff --git a/examples/mpeg_restamp.c b/examples/mpeg_restamp.c
new file mode 100644
index 0000000..8d226e3
--- /dev/null
+++ b/examples/mpeg_restamp.c
@@ -0,0 +1,191 @@
+/*****************************************************************************
+ * mpeg_restamp.c: Restamps PCR and PTS/DTS to make them appear continuous
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/* Limitation: this supposes the PES header is not fragmented over several
+ * TS packets, and that the stream is not scrambled. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+
+#include <bitstream/mpeg/ts.h>
+#include <bitstream/mpeg/pes.h>
+
+#define UINT33_MAX UINT64_C(8589934592)
+#define TS_CLOCK_MAX UINT33_MAX
+#define CLOCK_FREQ UINT64_C(90000)
+#define MAX_PCR_INTERVAL (CLOCK_FREQ / 10)
+
+/*****************************************************************************
+ * Local declarations
+ *****************************************************************************/
+static uint64_t i_last_pcr_date;
+static uint64_t i_last_pcr = TS_CLOCK_MAX;
+static uint64_t i_pcr_offset = 0;
+
+/*****************************************************************************
+ * get_date:
+ *****************************************************************************/
+static uint64_t get_date(void)
+{
+    struct timespec ts;
+
+    /* Try to use POSIX monotonic clock if available */
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) == EINVAL)
+        /* Run-time fallback to real-time clock (always available) */
+        (void)clock_gettime(CLOCK_REALTIME, &ts);
+
+    return ((uint64_t)ts.tv_sec * CLOCK_FREQ)
+            + ((uint64_t)ts.tv_nsec * (CLOCK_FREQ / 10000) / 100000);
+}
+
+/*****************************************************************************
+ * handle_pcr:
+ *****************************************************************************/
+static void handle_pcr(uint8_t *p_ts, uint64_t i_date)
+{
+    uint64_t i_pcr = tsaf_get_pcr(p_ts);
+    bool b_discontinuity = tsaf_has_discontinuity(p_ts);
+
+    if (i_last_pcr == TS_CLOCK_MAX)
+        i_last_pcr = i_pcr;
+    else {
+        /* handle 2^33 wrap-arounds */
+        uint64_t i_delta =
+            (TS_CLOCK_MAX + i_pcr -
+             (i_last_pcr % TS_CLOCK_MAX)) % TS_CLOCK_MAX;
+        if (i_delta <= MAX_PCR_INTERVAL && !b_discontinuity)
+            i_last_pcr = i_pcr;
+        else {
+            i_last_pcr += i_date - i_last_pcr_date;
+            i_last_pcr %= TS_CLOCK_MAX;
+            i_pcr_offset += TS_CLOCK_MAX + i_last_pcr - i_pcr;
+            i_pcr_offset %= TS_CLOCK_MAX;
+            i_last_pcr = i_pcr;
+        }
+    }
+    i_last_pcr_date = i_date;
+    if (!i_pcr_offset)
+        return;
+
+    i_pcr += i_pcr_offset;
+    i_pcr %= TS_CLOCK_MAX;
+    tsaf_set_pcr(p_ts, i_pcr);
+    tsaf_clear_discontinuity(p_ts);
+}
+
+/*****************************************************************************
+ * handle_ts:
+ *****************************************************************************/
+static uint64_t handle_ts(uint64_t i_ts)
+{
+    i_ts += i_pcr_offset;
+    i_ts %= TS_CLOCK_MAX;
+    return i_ts;
+}
+
+/*****************************************************************************
+ * Main loop
+ *****************************************************************************/
+static void usage(const char *psz)
+{
+    fprintf(stderr, "usage: %s [<mtu>] < <input file> [> <output>]\n", psz);
+    exit(EXIT_FAILURE);
+}
+
+int main(int i_argc, char **ppsz_argv)
+{
+    if (i_argc > 2 || i_argc < 1 ||
+        (!strcmp(ppsz_argv[1], "-h") || !strcmp(ppsz_argv[1], "--help")))
+        usage(ppsz_argv[0]);
+
+    unsigned int i_mtu = TS_SIZE;
+    if (i_argc == 2) {
+        i_mtu = strtoul(ppsz_argv[1], NULL, 0);
+        if (!i_mtu)
+            usage(ppsz_argv[0]);
+    }
+
+    for ( ; ; ) {
+        uint8_t p_buffer[i_mtu];
+        ssize_t i_read = read(STDIN_FILENO, p_buffer, i_mtu);
+        uint64_t date = get_date();
+        if (i_read == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+                continue;
+            exit(EXIT_FAILURE);
+        }
+
+        if (!i_read)
+            exit(EXIT_SUCCESS);
+
+        uint8_t *p_ts = p_buffer;
+        while (p_ts < p_buffer + i_mtu && ts_validate(p_ts)) {
+            if (ts_has_adaptation(p_ts) && ts_get_adaptation(p_ts) &&
+                tsaf_has_pcr(p_ts))
+                handle_pcr(p_ts, date);
+
+            uint16_t header_size = TS_HEADER_SIZE +
+                                   (ts_has_adaptation(p_ts) ? 1 : 0) +
+                                   ts_get_adaptation(p_ts);
+            if (ts_get_unitstart(p_ts) && ts_has_payload(p_ts) &&
+                header_size + PES_HEADER_SIZE_PTS <= TS_SIZE &&
+                pes_validate(p_ts + header_size) &&
+                pes_get_streamid(p_ts + header_size) !=
+                    PES_STREAM_ID_PRIVATE_2 &&
+                pes_validate_header(p_ts + header_size) &&
+                pes_has_pts(p_ts + header_size) &&
+                pes_validate_pts(p_ts + header_size)) {
+                pes_set_pts(p_ts + header_size,
+                            handle_ts(pes_get_pts(p_ts + header_size)));
+
+                if (header_size + PES_HEADER_SIZE_PTSDTS <= TS_SIZE &&
+                    pes_has_dts(p_ts + header_size) &&
+                    pes_validate_dts(p_ts + header_size))
+                    pes_set_dts(p_ts + header_size,
+                                handle_ts(pes_get_dts(p_ts + header_size)));
+            }
+
+            p_ts += TS_SIZE;
+        }
+
+        ssize_t i_written = write(STDOUT_FILENO, p_buffer, i_mtu);
+        if (i_written == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK)
+                continue;
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    return EXIT_FAILURE;
+}
diff --git a/headers_test.sh b/headers_test.sh
index cbd7203..8ee4fdc 100755
--- a/headers_test.sh
+++ b/headers_test.sh
@@ -11,12 +11,23 @@ HEADER_LIST="dvb/sim.h ietf/rtp.h"
 # If you want to test only particular headers comment the line bellow
 HEADER_LIST=$(find * | grep \\.h$ | sort | sed -e 's|^\./||')
 
-for HDR in $HEADER_LIST
+for suffix in "c" "cpp"
 do
-    test_file=$(echo $HDR | sed -e 's|/|_|g;s|\.h$||')
-    echo "Testing: $HDR"
-    printf "#include \"$HDR\"\n\nint main(void) { return 0; }\n" > $test_file.c
-    gcc -I.. -Werror -Wall -Wextra -Wno-unused -Wno-sign-compare -Wformat-security $test_file.c -o $test_file
-    [ $? != 0 ] && exit 1
-    rm $test_file $test_file.c
+    case $suffix in
+        "cpp")
+            compiler="g++"
+            ;;
+        *)
+            compiler="gcc"
+            ;;
+    esac
+    for HDR in $HEADER_LIST
+    do
+        test_file=$(echo $HDR | sed -e 's|/|_|g;s|\.h$||')
+        echo "Testing ($compiler): $HDR"
+        printf "#include \"$HDR\"\n\nint main(void) { return 0; }\n" > $test_file.$suffix
+        $compiler -I.. -Werror -Wall -Wextra -Wno-unused -Wno-sign-compare -Wformat-security $test_file.$suffix -o $test_file
+        [ $? != 0 ] && exit 1
+        rm $test_file $test_file.$suffix
+    done
 done
diff --git a/ieee/ethernet.h b/ieee/ethernet.h
new file mode 100644
index 0000000..e15519f
--- /dev/null
+++ b/ieee/ethernet.h
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ * ethernet.h: Ethernet frames
+ *****************************************************************************
+ * Copyright (C) 2015 VideoLAN
+ *
+ * Authors: Benjamin Cohen <bencoh at notk.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - IEEE Std 802.3-2012 (December 2012)
+ *  - IETF RFC 7042 IANA Considerations and IETF Protocol
+ *    and Documentation Usage for IEEE 802 Parameters (October 2013)
+ */
+
+#ifndef __BITSTREAM_IEEE_ETHERNET_H__
+#define __BITSTREAM_IEEE_ETHERNET_H__
+
+#include <stdint.h>
+#include <string.h> /* memcpy */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define ETHERNET_ADDR_LEN 6
+#define ETHERNET_HEADER_LEN (2*ETHERNET_ADDR_LEN + 2)
+
+#define ETHERNET_TYPE_IP            0x0800
+#define ETHERNET_TYPE_ARP           0x0806
+#define ETHERNET_TYPE_RARP          0x8035
+#define ETHERNET_TYPE_VLAN          0x8100
+#define ETHERNET_TYPE_IPV6          0x86DD
+#define ETHERNET_TYPE_PPP           0x880B
+#define ETHERNET_TYPE_MPLS          0x8847
+#define ETHERNET_TYPE_PPPOE_DISC    0x8863
+#define ETHERNET_TYPE_PPPOE_SESSION 0x8864
+#define ETHERNET_TYPE_LLDP          0x88CC
+
+static inline uint8_t *ethernet_dstaddr(uint8_t *p_ethernet)
+{
+    return p_ethernet;
+}
+
+static inline void ethernet_get_dstaddr(const uint8_t *p_ethernet, uint8_t *p_addr)
+{
+    memcpy(p_addr, p_ethernet, ETHERNET_ADDR_LEN);
+}
+
+static inline void ethernet_set_dstaddr(uint8_t *p_ethernet, const uint8_t *p_addr)
+{
+    memcpy(ethernet_dstaddr(p_ethernet), p_addr, ETHERNET_ADDR_LEN);
+}
+
+static inline uint8_t *ethernet_srcaddr(uint8_t *p_ethernet)
+{
+    return p_ethernet + ETHERNET_ADDR_LEN;
+}
+
+static inline void ethernet_get_srcaddr(const uint8_t *p_ethernet, uint8_t *p_addr)
+{
+    memcpy(p_addr, p_ethernet + ETHERNET_ADDR_LEN, ETHERNET_ADDR_LEN);
+}
+
+static inline void ethernet_set_srcaddr(uint8_t *p_ethernet, const uint8_t *p_addr)
+{
+    memcpy(ethernet_srcaddr(p_ethernet), p_addr, ETHERNET_ADDR_LEN);
+}
+
+static inline uint16_t ethernet_get_lentype(const uint8_t *p_ethernet)
+{
+    return (p_ethernet[12] << 8) | p_ethernet[13];
+}
+
+static inline void ethernet_set_lentype(uint8_t *p_ethernet, uint16_t lentype)
+{
+    p_ethernet[12] = (lentype & 0xff00) >> 8;
+    p_ethernet[13] = (lentype & 0xff);
+}
+
+static inline uint8_t *ethernet_payload(uint8_t *p_ethernet)
+{
+    return p_ethernet + ETHERNET_HEADER_LEN;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ietf/ip.h b/ietf/ip.h
new file mode 100644
index 0000000..6d2702b
--- /dev/null
+++ b/ietf/ip.h
@@ -0,0 +1,245 @@
+/*****************************************************************************
+ * ip.h: Internet Protocol (IP)
+ *****************************************************************************
+ * Copyright (C) 2015 VideoLAN
+ *
+ * Authors: Benjamin Cohen <bencoh at notk.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - IETF RFC 791 INTERNET PROTOCOL (September 1981)
+ *  - IETF RFC 790 ASSIGNED NUMBERS (September 1981)
+ */
+
+#ifndef __BITSTREAM_IETF_IP_H__
+#define __BITSTREAM_IETF_IP_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * Reminder: IP 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 
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |Version|  IHL  |Type of Service|          Total Length         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |         Identification        |Flags|      Fragment Offset    |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |  Time to Live |    Protocol   |         Header Checksum       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                       Source Address                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                    Destination Address                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                    Options                    |    Padding    |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+#define IP_HEADER_MINSIZE   20
+
+#define IP_PROTO_ICMP       1
+#define IP_PROTO_TCP        6
+#define IP_PROTO_UDP        17
+
+static inline void ip_set_version(uint8_t *p_ip, uint8_t version)
+{
+    p_ip[0] &= ~0xf0;
+    p_ip[0] |= (version & 0xf) << 4;
+}
+
+static inline uint8_t ip_get_version(const uint8_t *p_ip)
+{
+    return (p_ip[0] >> 4) & 0xf;
+}
+
+static inline void ip_set_ihl(uint8_t *p_ip, uint8_t ihl)
+{
+    p_ip[0] &= ~0xf;
+    p_ip[0] |= (ihl & 0xf);
+}
+
+static inline uint8_t ip_get_ihl(const uint8_t *p_ip)
+{
+    return p_ip[0] & 0xf;
+}
+
+static inline void ip_set_tos(uint8_t *p_ip, uint8_t tos)
+{
+    p_ip[1] = tos;
+}
+
+static inline uint8_t ip_get_tos(const uint8_t *p_ip)
+{
+    return p_ip[1];
+}
+
+static inline void ip_set_len(uint8_t *p_ip, uint16_t len)
+{
+    p_ip[2] = (len & 0xff00) >> 8;
+    p_ip[3] = (len & 0xff);
+}
+
+static inline uint16_t ip_get_len(const uint8_t *p_ip)
+{
+    return (p_ip[2] << 8) | p_ip[3];
+}
+
+static inline void ip_set_id(uint8_t *p_ip, uint16_t id)
+{
+    
+    p_ip[4] = (id & 0xff00) >> 8;
+    p_ip[5] = (id & 0xff);
+}
+
+static inline uint16_t ip_get_id(const uint8_t *p_ip)
+{
+    return (p_ip[4] << 8) | p_ip[5];
+}
+
+static inline void ip_set_flag_reserved(uint8_t *p_ip, uint8_t flag)
+{
+    p_ip[6] &= ~0x80;
+    p_ip[6] |= (flag & 1) << 7;
+}
+
+static inline uint8_t ip_get_flag_reservered(const uint8_t *p_ip)
+{
+    return (p_ip[6] & 0x80);
+}
+
+static inline void ip_set_flag_df(uint8_t *p_ip, uint8_t flag)
+{
+    p_ip[6] &= ~0x40;
+    p_ip[6] |= (flag & 1) << 6;
+}
+
+static inline uint8_t ip_get_flag_df(const uint8_t *p_ip)
+{
+    return (p_ip[6] & 0x40);
+}
+
+static inline void ip_set_flag_mf(uint8_t *p_ip, uint8_t flag)
+{
+    p_ip[6] &= ~0x20;
+    p_ip[6] |= (flag & 1) << 5;
+}
+
+static inline uint8_t ip_get_flag_mf(const uint8_t *p_ip)
+{
+    return (p_ip[6] & 0x20);
+}
+
+static inline void ip_set_frag_offset(uint8_t *p_ip, uint16_t offset)
+{
+    p_ip[6] &= ~0x1f;
+    p_ip[6] |= (offset & 0x1f00) >> 8;
+    p_ip[7] = (offset & 0xff);
+}
+
+static inline uint8_t ip_get_frag_offset(const uint8_t *p_ip)
+{
+    return ((p_ip[6] & 0x1f) << 8 | p_ip[7]);
+}
+
+static inline void ip_set_ttl(uint8_t *p_ip, uint8_t ttl)
+{
+    p_ip[8] = ttl;
+}
+
+static inline uint8_t ip_get_ttl(const uint8_t *p_ip)
+{
+    return p_ip[8];
+}
+
+static inline void ip_set_proto(uint8_t *p_ip, uint8_t proto)
+{
+    p_ip[9] = proto;
+}
+
+static inline uint8_t ip_get_proto(const uint8_t *p_ip)
+{
+    return p_ip[9];
+}
+
+static inline void ip_set_cksum(uint8_t *p_ip, uint16_t cksum)
+{
+    p_ip[10] = (cksum & 0xff00) >> 8;
+    p_ip[11] = (cksum & 0xff);
+}
+
+static inline uint16_t ip_get_cksum(const uint8_t *p_ip)
+{
+    return (p_ip[10] << 8) | p_ip[11];
+}
+
+static inline void ip_set_srcaddr(uint8_t *p_ip, uint32_t addr)
+{
+    p_ip[12] = (addr & 0xff000000) >> 24;
+    p_ip[13] = (addr & 0x00ff0000) >> 16;
+    p_ip[14] = (addr & 0x0000ff00) >>  8;
+    p_ip[15] = (addr & 0x000000ff);
+}
+
+static inline uint32_t ip_get_srcaddr(const uint8_t *p_ip)
+{
+    return (p_ip[12] << 24) | (p_ip[13] << 16) | (p_ip[14] << 8) | p_ip[15];
+}
+
+static inline uint8_t *ip_srcaddr(uint8_t *p_ip)
+{
+    return p_ip + 12;
+}
+
+static inline void ip_set_dstaddr(uint8_t *p_ip, uint32_t addr)
+{
+    p_ip[16] = (addr & 0xff000000) >> 24;
+    p_ip[17] = (addr & 0x00ff0000) >> 16;
+    p_ip[18] = (addr & 0x0000ff00) >>  8;
+    p_ip[19] = (addr & 0x000000ff);
+}
+
+static inline uint8_t *ip_dstaddr(uint8_t *p_ip)
+{
+    return p_ip + 16;
+}
+
+static inline uint32_t ip_get_dstaddr(const uint8_t *p_ip)
+{
+    return (p_ip[16] << 24) | (p_ip[17] << 16) | (p_ip[18] << 8) | p_ip[19];
+}
+
+static inline uint8_t *ip_payload(uint8_t *p_ip)
+{
+    return p_ip + 4 * ip_get_ihl(p_ip); /* ihl is in 32b words */
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ietf/rtcp.h b/ietf/rtcp.h
new file mode 100644
index 0000000..8ae65e4
--- /dev/null
+++ b/ietf/rtcp.h
@@ -0,0 +1,71 @@
+#ifndef __BITSTREAM_IETF_RTCP_H__
+# define __BITSTREAM_IETF_RTCP_H__
+
+# include <inttypes.h>
+
+# define RTCP_RTP_VERSION       2
+# define RTCP_PT_SR             200
+
+static inline void rtcp_sr_set_rtp_version(uint8_t *p_rtcp_sr)
+{
+    p_rtcp_sr[0] = RTCP_RTP_VERSION << 6;
+}
+
+static inline void rtcp_sr_set_pt(uint8_t *p_rtcp_sr)
+{
+    p_rtcp_sr[1] = RTCP_PT_SR;
+}
+
+static inline void rtcp_sr_set_length(uint8_t *p_rtcp_sr,
+                                      uint16_t length)
+{
+    p_rtcp_sr[2] = length >> 8;
+    p_rtcp_sr[3] = length & 0xff;
+}
+
+static inline void rtcp_sr_set_ntp_time_msw(uint8_t *p_rtcp_sr,
+                                            uint32_t ntp_time_msw)
+{
+    p_rtcp_sr[8] = (ntp_time_msw >> 24) & 0xff;
+    p_rtcp_sr[9] = (ntp_time_msw >> 16) & 0xff;
+    p_rtcp_sr[10] = (ntp_time_msw >> 8) & 0xff;
+    p_rtcp_sr[11] = ntp_time_msw & 0xff;
+}
+
+static inline void rtcp_sr_set_ntp_time_lsw(uint8_t *p_rtcp_sr,
+                                            uint32_t ntp_time_lsw)
+{
+    p_rtcp_sr[12] = (ntp_time_lsw >> 24) & 0xff;
+    p_rtcp_sr[13] = (ntp_time_lsw >> 16) & 0xff;
+    p_rtcp_sr[14] = (ntp_time_lsw >> 8) & 0xff;
+    p_rtcp_sr[15] = ntp_time_lsw & 0xff;
+}
+
+static inline void rtcp_sr_set_rtp_time(uint8_t *p_rtcp_sr,
+                                            uint32_t rtp_time)
+{
+    p_rtcp_sr[16] = (rtp_time >> 24) & 0xff;
+    p_rtcp_sr[17] = (rtp_time >> 16) & 0xff;
+    p_rtcp_sr[18] = (rtp_time >> 8) & 0xff;
+    p_rtcp_sr[19] = rtp_time & 0xff;
+}
+
+static inline void rtcp_sr_set_packet_count(uint8_t *p_rtcp_sr,
+                                            uint32_t packet_count)
+{
+    p_rtcp_sr[20] = (packet_count >> 24) & 0xff;
+    p_rtcp_sr[21] = (packet_count >> 16) & 0xff;
+    p_rtcp_sr[22] = (packet_count >> 8) & 0xff;
+    p_rtcp_sr[23] = packet_count & 0xff;
+}
+
+static inline void rtcp_sr_set_octet_count(uint8_t *p_rtcp_sr,
+                                            uint32_t octet_count)
+{
+    p_rtcp_sr[24] = (octet_count >> 24) & 0xff;
+    p_rtcp_sr[25] = (octet_count >> 16) & 0xff;
+    p_rtcp_sr[26] = (octet_count >> 8) & 0xff;
+    p_rtcp_sr[27] = octet_count & 0xff;
+}
+
+#endif /* !__BITSTREAM_IETF_RTCP_H__ */
diff --git a/ietf/rtp.h b/ietf/rtp.h
index 37419c7..a8a03f6 100644
--- a/ietf/rtp.h
+++ b/ietf/rtp.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * rtp.h: Real-Time Protocol
+ * rtp.h: Real-time Transport Protocol
  *****************************************************************************
- * Copyright (C) 2009 VideoLAN
+ * Copyright (C) 2009, 2014 VideoLAN
  *
  * Authors: Christophe Massiot <massiot at via.ecp.fr>
  *
@@ -42,6 +42,7 @@ extern "C"
 #endif
 
 #define RTP_HEADER_SIZE     12
+#define RTP_EXTENSION_SIZE  4
 #define RTP_TYPE_TS         33
 
 /*
@@ -70,9 +71,45 @@ static inline bool rtp_check_hdr(const uint8_t *p_rtp)
     return (p_rtp[0] & 0xc0) == 0x80;
 }
 
+static inline void rtp_set_extension(uint8_t *p_rtp)
+{
+    p_rtp[0] |= 0x10;
+}
+
+static inline bool rtp_check_extension(const uint8_t *p_rtp)
+{
+    return !!(p_rtp[0] & 0x10);
+}
+
+static inline void rtp_set_cc(uint8_t *p_rtp, uint8_t i_cc)
+{
+    p_rtp[0] &= 0xf0;
+    p_rtp[0] |= i_cc & 0xf;
+}
+
+static inline uint8_t rtp_get_cc(const uint8_t *p_rtp)
+{
+    return p_rtp[0] & 0xf;
+}
+
+static inline void rtp_set_marker(uint8_t *p_rtp)
+{
+    p_rtp[1] |= 0x80;
+}
+
+static inline void rtp_clear_marker(uint8_t *p_rtp)
+{
+    p_rtp[1] &= ~0x80;
+}
+
+static inline bool rtp_check_marker(const uint8_t *p_rtp)
+{
+    return !!(p_rtp[1] & 0x80);
+}
+
 static inline void rtp_set_type(uint8_t *p_rtp, uint8_t i_type)
 {
-    p_rtp[1] = i_type;
+    p_rtp[1] = i_type & 0x7f;
 }
 
 static inline uint8_t rtp_get_type(const uint8_t *p_rtp)
@@ -86,7 +123,7 @@ static inline void rtp_set_seqnum(uint8_t *p_rtp, uint16_t i_seqnum)
     p_rtp[3] = i_seqnum & 0xff;
 }
 
-static inline uint16_t rtp_get_seqnum(uint8_t *p_rtp)
+static inline uint16_t rtp_get_seqnum(const uint8_t *p_rtp)
 {
     return (p_rtp[2] << 8) | p_rtp[3];
 }
@@ -99,7 +136,7 @@ static inline void rtp_set_timestamp(uint8_t *p_rtp, uint32_t i_timestamp)
     p_rtp[7] = i_timestamp & 0xff;
 }
 
-static inline uint32_t rtp_get_timestamp(uint8_t *p_rtp)
+static inline uint32_t rtp_get_timestamp(const uint8_t *p_rtp)
 {
     return (p_rtp[4] << 24) | (p_rtp[5] << 16) | (p_rtp[6] << 8) | p_rtp[7];
 }
@@ -112,7 +149,7 @@ static inline void rtp_set_ssrc(uint8_t *p_rtp, const uint8_t pi_ssrc[4])
     p_rtp[11] = pi_ssrc[3];
 }
 
-static inline void rtp_get_ssrc(uint8_t *p_rtp, uint8_t pi_ssrc[4])
+static inline void rtp_get_ssrc(const uint8_t *p_rtp, uint8_t pi_ssrc[4])
 {
     pi_ssrc[0] = p_rtp[8];
     pi_ssrc[1] = p_rtp[9];
@@ -120,12 +157,39 @@ static inline void rtp_get_ssrc(uint8_t *p_rtp, uint8_t pi_ssrc[4])
     pi_ssrc[3] = p_rtp[11];
 }
 
+static inline uint8_t *rtp_extension(uint8_t *p_rtp)
+{
+    return p_rtp + RTP_HEADER_SIZE + 4 * rtp_get_cc(p_rtp);
+}
+
+static inline void rtpx_set_header(uint8_t *p_rtpx, uint16_t i_header)
+{
+    p_rtpx[0] = (i_header >> 8) & 0xff;
+    p_rtpx[1] = i_header & 0xff;
+}
+
+static inline uint16_t rtpx_get_header(const uint8_t *p_rtpx)
+{
+    return (p_rtpx[0] << 8) | p_rtpx[1];
+}
+
+static inline void rtpx_set_length(uint8_t *p_rtpx, uint16_t i_length)
+{
+    p_rtpx[2] = (i_length >> 8) & 0xff;
+    p_rtpx[3] = i_length & 0xff;
+}
+
+static inline uint16_t rtpx_get_length(const uint8_t *p_rtpx)
+{
+    return (p_rtpx[2] << 8) | p_rtpx[3];
+}
+
 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 * (1 + (p_rtp[i_size + 2] << 8) + p_rtp[i_size + 3]);
+    i_size += 4 * rtp_get_cc(p_rtp);
+    if (rtp_check_extension(p_rtp))
+        i_size += 4 * (1 + rtpx_get_length(rtp_extension(p_rtp)));
     return p_rtp + i_size;
 }
 
diff --git a/ietf/rtp3551.h b/ietf/rtp3551.h
new file mode 100644
index 0000000..1197079
--- /dev/null
+++ b/ietf/rtp3551.h
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * rtp3551.h: RTP Profile for Audio and Video
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN
+ *
+ * Authors: Benjamin Cohen <bencoh at notk.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - IETF RFC 3551 RTP Profile for Audio and Video Conferences
+ *                  with Minimal Control (July 2003)
+ */
+
+#ifndef __BITSTREAM_IETF_RTP3551_H__
+#define __BITSTREAM_IETF_RTP3551_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include "rtp.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define RTP_TYPE_PCMU           0
+/* Reserved                     1 */
+/* Reserved                     2 */
+#define RTP_TYPE_GSM            3
+#define RTP_TYPE_G723           4
+#define RTP_TYPE_DVI4_8000      5
+#define RTP_TYPE_DVI4_16000     6
+#define RTP_TYPE_LPC            7
+#define RTP_TYPE_PCMA           8
+#define RTP_TYPE_G722           9
+#define RTP_TYPE_L16            10
+#define RTP_TYPE_L16MONO        11
+#define RTP_TYPE_QCELP          12
+#define RTP_TYPE_CN             13
+#define RTP_TYPE_MPA            14
+#define RTP_TYPE_G728           15
+#define RTP_TYPE_DVI4_11025     16
+#define RTP_TYPE_DVI4_22050     17
+#define RTP_TYPE_G729           18
+/* Reserved                     19 */
+/* Unassigned                   20 */
+/* Unassigned                   21 */
+/* Unassigned                   22 */
+/* Unassigned                   23 */
+/* Unassigned                   24 */
+#define RTP_TYPE_CELB           25
+#define RTP_TYPE_JPEG           26
+/* Unassigned                   27 */
+#define RTP_TYPE_NV             28
+/* Unassigned                   29 */
+/* Unassigned                   30 */
+#define RTP_TYPE_H261           31
+#define RTP_TYPE_MPV            32
+#define RTP_TYPE_MP2T           33
+#define RTP_TYPE_H263           34
+/* Unassigned                   35-71 */
+/* Reserved                     72-76 */
+/* Unassigned                   77-95 */
+/* Dynamic                      96-127 */
+
+static inline uint32_t rtp_3551_get_clock_rate(uint8_t i_type)
+{
+    switch (i_type) {
+    case RTP_TYPE_PCMU:
+    case RTP_TYPE_GSM:
+    case RTP_TYPE_G723:
+    case RTP_TYPE_DVI4_8000:
+    case RTP_TYPE_LPC:
+    case RTP_TYPE_PCMA:
+    case RTP_TYPE_G722:
+    case RTP_TYPE_QCELP:
+    case RTP_TYPE_CN:
+    case RTP_TYPE_G728:
+    case RTP_TYPE_G729:
+        return 8000;
+
+    case RTP_TYPE_DVI4_16000:
+        return 16000;
+
+    case RTP_TYPE_L16:
+    case RTP_TYPE_L16MONO:
+        return 44100;
+
+    case RTP_TYPE_DVI4_11025:
+        return 11025;
+
+    case RTP_TYPE_DVI4_22050:
+        return 22050;
+
+    case RTP_TYPE_MPA:
+    case RTP_TYPE_CELB:
+    case RTP_TYPE_JPEG:
+    case RTP_TYPE_NV:
+    case RTP_TYPE_H261:
+    case RTP_TYPE_MPV:
+    case RTP_TYPE_MP2T:
+    case RTP_TYPE_H263:
+        return 90000;
+    }
+    return 0; /* invalid clock rate for unknown type */
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ietf/rtp6184.h b/ietf/rtp6184.h
new file mode 100644
index 0000000..c35afb2
--- /dev/null
+++ b/ietf/rtp6184.h
@@ -0,0 +1,9 @@
+/*
+ * RTP Payload Format for H.264 Video
+ */
+#ifndef __BITSTREAM_IETF_RTP6184_H__
+# define __BITSTREAM_IETF_RTP6184_H__
+
+#define RTP_6184_CLOCKRATE       90000
+
+#endif /* !__BITSTREAM_IETF_RTP6184_H__ */
diff --git a/ietf/rtp7587.h b/ietf/rtp7587.h
new file mode 100644
index 0000000..fee9c89
--- /dev/null
+++ b/ietf/rtp7587.h
@@ -0,0 +1,9 @@
+/*
+ * RTP Payload Format for the Opus Speech and Audio Codec
+ */
+#ifndef __BITSTREAM_IETF_RTP7587_H__
+# define __BITSTREAM_IETF_RTP7587_H__
+
+#define RTP_7587_CLOCKRATE       48000
+
+#endif /* !__BITSTREAM_IETF_RTP7587_H__ */
diff --git a/ietf/udp.h b/ietf/udp.h
new file mode 100644
index 0000000..7eefcbb
--- /dev/null
+++ b/ietf/udp.h
@@ -0,0 +1,110 @@
+/*****************************************************************************
+ * udp.h: User Datagram Protocol (UDP)
+ *****************************************************************************
+ * Copyright (C) 2015 VideoLAN
+ *
+ * Authors: Benjamin Cohen <bencoh at notk.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - IETF RFC 768 User Datagram Protocol (August 1980)
+ */
+
+#ifndef __BITSTREAM_IETF_UDP_H__
+#define __BITSTREAM_IETF_UDP_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * Reminder: UDP header
+     0      7 8     15 16    23 24    31  
+    +--------+--------+--------+--------+ 
+    |     Source      |   Destination   | 
+    |      Port       |      Port       | 
+    +--------+--------+--------+--------+ 
+    |                 |                 | 
+    |     Length      |    Checksum     | 
+    +--------+--------+--------+--------+ 
+ */
+
+#define UDP_HEADER_SIZE 8
+
+static inline void udp_set_srcport(uint8_t *p_udp, uint16_t port)
+{
+    p_udp[0] = (port & 0xff00) >> 8;
+    p_udp[1] = (port & 0xff);
+}
+
+static inline uint16_t udp_get_srcport(const uint8_t *p_udp)
+{
+    return (p_udp[0] << 8) | p_udp[1];
+}
+
+static inline void udp_set_dstport(uint8_t *p_udp, uint16_t port)
+{
+    p_udp[2] = (port & 0xff00) >> 8;
+    p_udp[3] = (port & 0xff);
+}
+
+static inline uint16_t udp_get_dstport(const uint8_t *p_udp)
+{
+    return (p_udp[2] << 8) | p_udp[3];
+}
+
+static inline void udp_set_len(uint8_t *p_udp, uint16_t len)
+{
+    p_udp[4] = (len & 0xff00) >> 8;
+    p_udp[5] = (len & 0xff);
+}
+
+static inline uint16_t udp_get_len(const uint8_t *p_udp)
+{
+    return (p_udp[4] << 8) | p_udp[5];
+}
+
+static inline void udp_set_cksum(uint8_t *p_udp, uint16_t cksum)
+{
+    p_udp[6] = (cksum & 0xff00) >> 8;
+    p_udp[7] = (cksum & 0xff);
+}
+
+static inline uint16_t udp_get_cksum(const uint8_t *p_udp)
+{
+    return (p_udp[6] << 8) | p_udp[7];
+}
+
+static inline uint8_t *udp_payload(uint8_t *p_udp)
+{
+    return p_udp + UDP_HEADER_SIZE;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mpeg/aac.h b/mpeg/aac.h
index cb5b59c..767efc7 100644
--- a/mpeg/aac.h
+++ b/mpeg/aac.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * aac.h: ISO/IEC 14496-3 Advanced Audio Coding
  *****************************************************************************
- * Copyright (C) 2010 VideoLAN
+ * Copyright (C) 2010, 2013 VideoLAN
  *
  * Authors: Christophe Massiot <massiot at via.ecp.fr>
  *
@@ -46,6 +46,7 @@ extern "C"
  * ADTS header
  *****************************************************************************/
 #define ADTS_HEADER_SIZE        7
+#define ADTS_SAMPLES_PER_BLOCK  1024
 
 /* fixed header */
 static inline void adts_set_sync(uint8_t *p_adts)
@@ -59,16 +60,41 @@ static inline void adts_set_sync(uint8_t *p_adts)
     p_adts[6] = 0x0;
 }
 
+static inline bool adts_get_protection_absent(const uint8_t *p_adts)
+{
+    return !!(p_adts[1] & 0x01);
+}
+
+static inline void adts_clear_protection_absent(uint8_t *p_adts)
+{
+    p_adts[1] &= ~0x01;
+}
+
+static inline uint8_t adts_get_profile(const uint8_t *p_adts)
+{
+    return p_adts[2] >> 6;
+}
+
 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)
+static inline uint8_t adts_get_sampling_freq(const uint8_t *p_adts)
+{
+    return (p_adts[2] & 0x3c) >> 2;
+}
+
+static inline void adts_set_sampling_freq(uint8_t *p_adts, uint8_t i_freq)
 {
     p_adts[2] &= ~0x3c;
-    p_adts[2] |= (i_index & 0xf) << 2;
+    p_adts[2] |= (i_freq & 0xf) << 2;
+}
+
+static inline uint8_t adts_get_channels(const uint8_t *p_adts)
+{
+    return ((p_adts[2] & 0x01) << 2) | (p_adts[3] >> 6);
 }
 
 static inline void adts_set_channels(uint8_t *p_adts, uint8_t i_channels)
@@ -79,23 +105,33 @@ static inline void adts_set_channels(uint8_t *p_adts, uint8_t i_channels)
     p_adts[3] |= (i_channels & 0x7) << 6;
 }
 
-static inline void adts_set_copy(uint8_t *p_adts, bool b_copy)
+static inline bool adts_get_copy(const uint8_t *p_adts)
 {
-    if (!b_copy)
-        p_adts[3] &= ~0x20;
-    else
-        p_adts[3] |= 0x20;
+    return !!(p_adts[3] & 0x20);
 }
 
-static inline void adts_set_home(uint8_t *p_adts, bool b_home)
+static inline void adts_set_copy(uint8_t *p_adts)
 {
-    if (!b_home)
-        p_adts[3] &= ~0x10;
-    else
-        p_adts[3] |= 0x10;
+    p_adts[3] |= 0x20;
+}
+
+static inline bool adts_get_home(const uint8_t *p_adts)
+{
+    return !!(p_adts[3] & 0x10);
+}
+
+static inline void adts_set_home(uint8_t *p_adts)
+{
+    p_adts[3] |= 0x10;
 }
 
 /* variable header */
+static inline void adts_get_cp_id(const uint8_t *p_adts, bool *pb_bit, bool *pb_start)
+{
+    *pb_bit = !!(p_adts[3] & 0x08);
+    *pb_start = !!(p_adts[3] & 0x04);
+}
+
 static inline void adts_set_cp_id(uint8_t *p_adts, bool b_bit, bool b_start)
 {
     p_adts[3] &= ~0x0c;
@@ -105,6 +141,11 @@ static inline void adts_set_cp_id(uint8_t *p_adts, bool b_bit, bool b_start)
         p_adts[3] |= 0x04;
 }
 
+static inline uint16_t adts_get_length(const uint8_t *p_adts)
+{
+    return ((p_adts[3] & 0x03) << 11) | (p_adts[4] << 3) | (p_adts[5] >> 5);
+}
+
 static inline void adts_set_length(uint8_t *p_adts, uint16_t i_length)
 {
     p_adts[3] &= ~0x03;
@@ -114,6 +155,11 @@ static inline void adts_set_length(uint8_t *p_adts, uint16_t i_length)
     p_adts[5] |= (i_length << 5) & 0xe0;
 }
 
+static inline uint16_t adts_get_fullness(const uint8_t *p_adts)
+{
+    return ((p_adts[5] & 0x1f) << 6) | (p_adts[6] >> 2);
+}
+
 static inline void adts_set_fullness(uint8_t *p_adts, uint16_t i_fullness)
 {
     p_adts[5] &= ~0x1f;
@@ -122,11 +168,33 @@ static inline void adts_set_fullness(uint8_t *p_adts, uint16_t i_fullness)
     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)
+/* blocks == number of blocks - 1 */
+static inline uint8_t adts_get_num_blocks(const uint8_t *p_adts)
+{
+    return (p_adts[6] & 0x03);
+}
+
+static inline void adts_set_num_blocks(uint8_t *p_adts, uint8_t i_blocks_min1)
 {
     p_adts[6] &= ~0x03;
-    p_adts[6] |= i_blocks & 0x03;
+    p_adts[6] |= i_blocks_min1 & 0x03;
+}
+
+static inline bool adts_sync_compare(const uint8_t *p_adts1, const uint8_t *p_adts2)
+{
+    return p_adts1[0] == p_adts2[0] &&
+           p_adts1[1] == p_adts2[1] &&
+           p_adts1[2] == p_adts2[2] &&
+           (p_adts1[3] & 0xfc) == (p_adts2[3] & 0xfc);
+}
+
+/* same but only takes into account meaningful fields */
+static inline bool adts_sync_compare_formats(const uint8_t *p_adts1, const uint8_t *p_adts2)
+{
+    return p_adts1[0] == p_adts2[0] &&
+           (p_adts1[1] & 0xfe) == (p_adts2[1] & 0xfe) &&
+           p_adts1[2] == p_adts2[2] &&
+           (p_adts1[3] & 0xc0) == (p_adts2[3] & 0xc0);
 }
 
 #ifdef __cplusplus
diff --git a/mpeg/h264.h b/mpeg/h264.h
new file mode 100644
index 0000000..b905c0b
--- /dev/null
+++ b/mpeg/h264.h
@@ -0,0 +1,312 @@
+/*****************************************************************************
+ * h264.h: ISO/IEC 14496-10 (video)
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - ISO/IEC 14496-10 (advanced video coding)
+ */
+
+#ifndef __BITSTREAM_MPEG_H264_H__
+#define __BITSTREAM_MPEG_H264_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include <stdbool.h>  /* bool */
+#include <string.h>   /* memset */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * H264 network abstraction layer (annex B)
+ *****************************************************************************/
+#define H264NAL_TYPE_NONIDR             1
+#define H264NAL_TYPE_PARTA              2
+#define H264NAL_TYPE_PARTB              3
+#define H264NAL_TYPE_PARTC              4
+#define H264NAL_TYPE_IDR                5
+#define H264NAL_TYPE_SEI                6
+#define H264NAL_TYPE_SPS                7
+#define H264NAL_TYPE_PPS                8
+#define H264NAL_TYPE_AUD                9
+#define H264NAL_TYPE_ENDSEQ             10
+#define H264NAL_TYPE_ENDSTR             11
+#define H264NAL_TYPE_FILLER             12
+#define H264NAL_TYPE_SPSX               13
+#define H264NAL_TYPE_PFX                14
+#define H264NAL_TYPE_SSPS               15
+
+static inline void h264nal_init(uint8_t *p_h264nal)
+{
+    p_h264nal[0] = 0x0;
+    p_h264nal[1] = 0x0;
+    p_h264nal[2] = 0x1;
+    p_h264nal[3] = 0;
+}
+
+static inline void h264nal_set_ref(uint8_t *p_h264nal, uint8_t ref)
+{
+    p_h264nal[3] &= 0x1f;
+    p_h264nal[3] |= ref << 5;
+}
+
+static inline uint8_t h264nal_get_ref(const uint8_t *p_h264nal)
+{
+    return (p_h264nal[3] & 0x60) >> 5;
+}
+
+static inline void h264nal_set_type(uint8_t *p_h264nal, uint8_t type)
+{
+    p_h264nal[3] &= 0xe0;
+    p_h264nal[3] |= type;
+}
+
+static inline uint8_t h264nal_get_type(const uint8_t *p_h264nal)
+{
+    return p_h264nal[3] & 0x1f;
+}
+
+static inline uint8_t h264nalst_get_ref(uint8_t start)
+{
+    return (start & 0x60) >> 5;
+}
+
+static inline uint8_t h264nalst_get_type(uint8_t start)
+{
+    return start & 0x1f;
+}
+
+/*****************************************************************************
+ * H264 supplemental enhancement information
+ *****************************************************************************/
+#define H264SEI_HEADER_SIZE         4
+
+#define H264SEI_BUFFERING_PERIOD    0
+#define H264SEI_PIC_TIMING          1
+#define H264SEI_PAN_SCAN_RECT       2
+#define H264SEI_FILLER_PAYLOAD      3
+#define H264SEI_USER_T_T35          4
+#define H264SEI_USER_UNREGISTERED   5
+#define H264SEI_RECOVERY_POINT      6
+#define H264SEI_DEC_REF_PIC_MARK_R  7
+#define H264SEI_SPARE_PIC           8
+#define H264SEI_SCENE_INFO          9
+#define H264SEI_SUB_SEQ_INFO        10
+#define H264SEI_SUB_SEQ_LAYER_CHAR  11
+#define H264SEI_SUB_SEQ_CHAR        12
+#define H264SEI_FULL_FRAME_FREEZE   13
+#define H264SEI_FULL_FRAME_FREEZE_R 14
+#define H264SEI_FULL_FRAME_SNAP     15
+#define H264SEI_PROG_REF_SEGMENT_S  16
+#define H264SEI_PROG_REF_SEGMENT_E  17
+#define H264SEI_MOTION_CONS_SGRP_S  18
+#define H264SEI_FILM_GRAIN_CHAR     19
+#define H264SEI_DEBLOCK_DIS_PREF    20
+#define H264SEI_STEREO_VIDEO_INFO   21
+#define H264SEI_POST_FILTER_HINT    22
+#define H264SEI_TONE_MAPPING_INFO   23
+#define H264SEI_SCALABILITY_INFO    24
+#define H264SEI_SUBPIC_SCAL_LAYER   25
+#define H264SEI_NONREQ_LAYER_REP    26
+#define H264SEI_PRIO_LAYER_INFO     27
+#define H264SEI_LAYERS_NOT_PRES     28
+#define H264SEI_LAYER_DEP_CHANGE    29
+#define H264SEI_SCALABLE_NESTING    30
+#define H264SEI_BASE_LAYER_TEMP_HRD 31
+#define H264SEI_QUAL_LAYER_INT_CHK  32
+#define H264SEI_REDUND_PIC_PROP     33
+#define H264SEI_TL0_DEP_REP         34
+#define H264SEI_TL_SWITCHING_POINT  35
+#define H264SEI_PARALLEL_DEC_INFO   36
+#define H264SEI_MVC_SCAL_NESTING    37
+#define H264SEI_VIEW_SCAL_INFO      38
+#define H264SEI_MULTIVIEW_SCN_INFO  39
+#define H264SEI_MULTIVIEW_ACQ_INFO  40
+#define H264SEI_NONREQ_VIEW_COMP    41
+#define H264SEI_VIEW_DEP_CHANGE     42
+#define H264SEI_OP_POINTS_NOT_PRES  43
+#define H264SEI_BASE_VIEW_TEMP_HRD  44
+#define H264SEI_FRAME_PACK_ARRANG   45
+
+#define H264SEI_STRUCT_FRAME        0
+#define H264SEI_STRUCT_TOP          1
+#define H264SEI_STRUCT_BOT          2
+#define H264SEI_STRUCT_TOP_BOT      3
+#define H264SEI_STRUCT_BOT_TOP      4
+#define H264SEI_STRUCT_TOP_BOT_TOP  5
+#define H264SEI_STRUCT_BOT_TOP_BOT  6
+#define H264SEI_STRUCT_DOUBLE       7
+#define H264SEI_STRUCT_TRIPLE       8
+
+static inline void h264sei_init(uint8_t *p_h264sei)
+{
+    h264nal_init(p_h264sei);
+    h264nal_set_type(p_h264sei, H264NAL_TYPE_SEI);
+}
+
+/*****************************************************************************
+ * H264 sequence parameter set
+ *****************************************************************************/
+#define H264SPS_HEADER_SIZE         7
+
+#define H264SPS_ID_MAX              32
+
+#define H264SPS_CHROMA_MONO         0
+#define H264SPS_CHROMA_420          1
+#define H264SPS_CHROMA_422          2
+#define H264SPS_CHROMA_444          3
+
+static inline void h264sps_init(uint8_t *p_h264sps)
+{
+    h264nal_init(p_h264sps);
+    h264nal_set_ref(p_h264sps, 1);
+    h264nal_set_type(p_h264sps, H264NAL_TYPE_SPS);
+    p_h264sps[5] = 0x0;
+}
+
+static inline void h264sps_set_profile(uint8_t *p_h264sps, uint8_t i_profile)
+{
+    p_h264sps[4] = i_profile;
+}
+
+static inline uint8_t h264sps_get_profile(const uint8_t *p_h264sps)
+{
+    return p_h264sps[4];
+}
+
+static inline void h264sps_set_level(uint8_t *p_h264sps, uint8_t i_level)
+{
+    p_h264sps[6] = i_level;
+}
+
+static inline uint8_t h264sps_get_level(const uint8_t *p_h264sps)
+{
+    return p_h264sps[6];
+}
+
+/*****************************************************************************
+ * H264 picture parameter set
+ *****************************************************************************/
+#define H264PPS_HEADER_SIZE         7
+
+#define H264PPS_ID_MAX              256
+
+static inline void h264pps_init(uint8_t *p_h264pps)
+{
+    h264nal_init(p_h264pps);
+    h264nal_set_ref(p_h264pps, 1);
+    h264nal_set_type(p_h264pps, H264NAL_TYPE_PPS);
+}
+
+/*****************************************************************************
+ * H264 access unit delimiter
+ *****************************************************************************/
+#define H264AUD_HEADER_SIZE         5
+
+static inline void h264aud_init(uint8_t *p_h264aud)
+{
+    h264nal_init(p_h264aud);
+    h264nal_set_type(p_h264aud, H264NAL_TYPE_AUD);
+    p_h264aud[4] = 0x10;
+}
+
+static inline void h264aud_set_pic_type(uint8_t *p_h264aud, uint8_t i_type)
+{
+    p_h264aud[4] = i_type << 5;
+}
+
+static inline uint8_t h264aud_get_pic_type(const uint8_t *p_h264aud)
+{
+    return p_h264aud[4] >> 5;
+}
+
+/*****************************************************************************
+ * H264 end sequence
+ *****************************************************************************/
+#define H264ENDSEQ_HEADER_SIZE      4
+
+static inline void h264endseq_init(uint8_t *p_h264endseq)
+{
+    h264nal_init(p_h264endseq);
+    h264nal_set_type(p_h264endseq, H264NAL_TYPE_ENDSEQ);
+}
+
+/*****************************************************************************
+ * H264 end stream
+ *****************************************************************************/
+#define H264ENDSTR_HEADER_SIZE      4
+
+static inline void h264endstr_init(uint8_t *p_h264endstr)
+{
+    h264nal_init(p_h264endstr);
+    h264nal_set_type(p_h264endstr, H264NAL_TYPE_ENDSTR);
+}
+
+/*****************************************************************************
+ * H264 sequence parameter set extension
+ *****************************************************************************/
+#define H264SPSX_HEADER_SIZE        4
+
+static inline void h264spsx_init(uint8_t *p_h264spsx)
+{
+    h264nal_init(p_h264spsx);
+    h264nal_set_ref(p_h264spsx, 1);
+    h264nal_set_type(p_h264spsx, H264NAL_TYPE_SPSX);
+}
+
+/*****************************************************************************
+ * H264 subset sequence parameter set
+ *****************************************************************************/
+#define H264SSPS_HEADER_SIZE        4
+
+static inline void h264ssps_init(uint8_t *p_h264ssps)
+{
+    h264nal_init(p_h264ssps);
+    h264nal_set_ref(p_h264ssps, 1);
+    h264nal_set_type(p_h264ssps, H264NAL_TYPE_SSPS);
+}
+
+/*****************************************************************************
+ * H264 video usability information
+ *****************************************************************************/
+#define H264VUI_AR_EXTENDED         255
+
+/*****************************************************************************
+ * H264 slices
+ *****************************************************************************/
+#define H264SLI_TYPE_P              0
+#define H264SLI_TYPE_B              1
+#define H264SLI_TYPE_I              2
+#define H264SLI_TYPE_SP             3
+#define H264SLI_TYPE_SI             4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mpeg/mp2v.h b/mpeg/mp2v.h
new file mode 100644
index 0000000..e9cb1bd
--- /dev/null
+++ b/mpeg/mp2v.h
@@ -0,0 +1,842 @@
+/*****************************************************************************
+ * mp2v.h: ISO/IEC 13818-2 (video)
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - ISO/IEC 13818-2 (MPEG-2 video)
+ */
+
+#ifndef __BITSTREAM_MPEG_MP2V_H__
+#define __BITSTREAM_MPEG_MP2V_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include <stdbool.h>  /* bool */
+#include <string.h>   /* memset */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * MP2V start code
+ *****************************************************************************/
+static inline void mp2vstart_init(uint8_t *p_mp2vstart, uint8_t startcode)
+{
+    p_mp2vstart[0] = 0x0;
+    p_mp2vstart[1] = 0x0;
+    p_mp2vstart[2] = 0x1;
+    p_mp2vstart[3] = startcode;
+}
+
+/*****************************************************************************
+ * MP2V extension
+ *****************************************************************************/
+#define MP2VX_HEADER_SIZE           4
+#define MP2VX_START_CODE            0xb5
+
+#define MP2VX_ID_SEQX               1
+#define MP2VX_ID_SEQDX              2
+#define MP2VX_ID_QUANTX             3
+#define MP2VX_ID_SEQSCALX           5
+#define MP2VX_ID_PICDX              7
+#define MP2VX_ID_PICX               8
+#define MP2VX_ID_PICSSCALX          9
+#define MP2VX_ID_PICTSCALX          10
+
+static inline uint8_t mp2vx_get_id(const uint8_t *p_mp2vx)
+{
+    return p_mp2vx[4] >> 4;
+}
+
+static inline void mp2vx_set_id(uint8_t *p_mp2vx, uint8_t id)
+{
+    p_mp2vx[4] &= 0xf;
+    p_mp2vx[4] |= id << 4;
+}
+
+static inline uint8_t mp2vxst_get_id(uint8_t start)
+{
+    return start >> 4;
+}
+
+/*****************************************************************************
+ * MP2V user data
+ *****************************************************************************/
+#define MP2VUSR_HEADER_SIZE         4
+#define MP2VUSR_START_CODE          0xb2
+
+/*****************************************************************************
+ * MP2V sequence header
+ *****************************************************************************/
+#define MP2VSEQ_HEADER_SIZE         12
+#define MP2VSEQ_START_CODE          0xb3
+
+#define MP2VSEQ_ASPECT_SQUARE       1
+#define MP2VSEQ_ASPECT_4_3          2
+#define MP2VSEQ_ASPECT_16_9         3
+#define MP2VSEQ_ASPECT_2_21         4
+
+#define MP2VSEQ_FRAMERATE_23_976    1
+#define MP2VSEQ_FRAMERATE_24        2
+#define MP2VSEQ_FRAMERATE_25        3
+#define MP2VSEQ_FRAMERATE_29_97     4
+#define MP2VSEQ_FRAMERATE_30        5
+#define MP2VSEQ_FRAMERATE_50        6
+#define MP2VSEQ_FRAMERATE_59_94     7
+#define MP2VSEQ_FRAMERATE_60        8
+/* unofficial Xing */
+#define MP2VSEQ_FRAMERATE_14_99     9
+/* unofficial libmpeg3 */
+#define MP2VSEQ_FRAMERATE_4_99      10
+#define MP2VSEQ_FRAMERATE_9_99      11
+#define MP2VSEQ_FRAMERATE_12_99     12
+
+#define MP2VSEQ_VBVBUFFER_VBR       0xffff
+
+static inline void mp2vseq_init(uint8_t *p_mp2vseq)
+{
+    mp2vstart_init(p_mp2vseq, MP2VSEQ_START_CODE);
+    p_mp2vseq[10] = 0x20;
+    p_mp2vseq[11] = 0x0;
+}
+
+static inline void mp2vseq_set_horizontal(uint8_t *p_mp2vseq,
+                                          uint16_t i_horizontal)
+{
+    p_mp2vseq[4] = i_horizontal >> 4;
+    p_mp2vseq[5] &= 0xf;
+    p_mp2vseq[5] |= (i_horizontal << 4) & 0xff;
+}
+
+static inline uint16_t mp2vseq_get_horizontal(const uint8_t *p_mp2vseq)
+{
+    return (p_mp2vseq[4] << 4) | (p_mp2vseq[5] >> 4);
+}
+
+static inline void mp2vseq_set_vertical(uint8_t *p_mp2vseq, uint16_t i_vertical)
+{
+    p_mp2vseq[5] &= 0xf0;
+    p_mp2vseq[5] |= (i_vertical >> 8) & 0xf;
+    p_mp2vseq[6] = i_vertical & 0xff;
+}
+
+static inline uint16_t mp2vseq_get_vertical(const uint8_t *p_mp2vseq)
+{
+    return ((p_mp2vseq[5] & 0xf) << 8) | p_mp2vseq[6];
+}
+
+static inline void mp2vseq_set_aspect(uint8_t *p_mp2vseq, uint8_t i_aspect)
+{
+    p_mp2vseq[7] &= 0xf;
+    p_mp2vseq[7] |= (i_aspect << 4) & 0xf0;
+}
+
+static inline uint8_t mp2vseq_get_aspect(const uint8_t *p_mp2vseq)
+{
+    return (p_mp2vseq[7] >> 4);
+}
+
+static inline void mp2vseq_set_framerate(uint8_t *p_mp2vseq,
+                                         uint8_t i_framerate)
+{
+    p_mp2vseq[7] &= 0xf0;
+    p_mp2vseq[7] |= i_framerate & 0xf;
+}
+
+static inline uint8_t mp2vseq_get_framerate(const uint8_t *p_mp2vseq)
+{
+    return (p_mp2vseq[7] & 0xf);
+}
+
+static inline void mp2vseq_set_bitrate(uint8_t *p_mp2vseq, uint32_t i_bitrate)
+{
+    p_mp2vseq[8] = i_bitrate >> 10;
+    p_mp2vseq[9] = (i_bitrate >> 2) & 0xff;
+    p_mp2vseq[10] &= 0x3f;
+    p_mp2vseq[10] |= (i_bitrate << 6) & 0xff;
+}
+
+static inline uint32_t mp2vseq_get_bitrate(const uint8_t *p_mp2vseq)
+{
+    return (p_mp2vseq[8] << 10) | (p_mp2vseq[9] << 2) | (p_mp2vseq[10] >> 6);
+}
+
+static inline void mp2vseq_set_vbvbuffer(uint8_t *p_mp2vseq,
+                                         uint16_t i_vbvbuffer)
+{
+    p_mp2vseq[10] &= 0xe0;
+    p_mp2vseq[10] |= (i_vbvbuffer >> 5) & 0x1f;
+    p_mp2vseq[11] &= 0x7;
+    p_mp2vseq[11] |= (i_vbvbuffer << 3) & 0xf8;
+}
+
+static inline uint16_t mp2vseq_get_vbvbuffer(const uint8_t *p_mp2vseq)
+{
+    return ((p_mp2vseq[10] & 0x1f) << 5) | (p_mp2vseq[11] >> 3);
+}
+
+static inline void mp2vseq_set_constrained(uint8_t *p_mp2vseq)
+{
+    p_mp2vseq[11] |= 0x4;
+}
+
+static inline bool mp2vseq_get_constrained(const uint8_t *p_mp2vseq)
+{
+    return !!(p_mp2vseq[11] & 0x4);
+}
+
+static inline void mp2vseq_set_intramatrix(uint8_t *p_mp2vseq,
+                                           const uint8_t p_matrix[64])
+{
+    p_mp2vseq[11] |= 0x2;
+    if (p_matrix != NULL) {
+        int i;
+        for (i = 0; i < 64; i++) {
+            p_mp2vseq[11 + i] |= p_matrix[i] >> 7;
+            p_mp2vseq[12 + i] = (p_matrix[i] << 1) & 0xfe;
+        }
+    } else
+        memset(p_mp2vseq + 12, 0, 64);
+}
+
+static inline bool mp2vseq_get_intramatrix(const uint8_t *p_mp2vseq,
+                                           uint64_t p_matrix[64])
+{
+    if (!(p_mp2vseq[11] & 0x2))
+        return false;
+    if (p_matrix != NULL) {
+        int i;
+        for (i = 0; i < 64; i++)
+            p_matrix[i] = ((p_mp2vseq[11 + i] << 7) & 0x80) |
+                           (p_mp2vseq[12 + i] >> 1);
+    }
+    return true;
+}
+
+static inline void mp2vseq_set_nonintramatrix(uint8_t *p_mp2vseq,
+                                              const uint8_t p_matrix[64])
+{
+    unsigned int offset = 11;
+    if (p_mp2vseq[11] & 0x2)
+        offset += 64;
+    p_mp2vseq[offset] |= 0x1;
+    if (p_matrix != NULL) {
+        int i;
+        for (i = 0; i < 64; i++) {
+            p_mp2vseq[offset + i] |= p_matrix[i] >> 7;
+            p_mp2vseq[offset + 1 + i] = (p_matrix[i] << 1) & 0xfe;
+        }
+    } else
+        memset(p_mp2vseq + offset + 1, 0, 64);
+}
+
+static inline bool mp2vseq_get_nonintramatrix(const uint8_t *p_mp2vseq,
+                                              uint64_t p_matrix[64])
+{
+    unsigned int offset = 11;
+    if (p_mp2vseq[11] & 0x2)
+        offset += 64;
+    if (!(p_mp2vseq[offset] & 0x1))
+        return false;
+    if (p_matrix != NULL) {
+        int i;
+        for (i = 0; i < 64; i++)
+            p_matrix[i] = ((p_mp2vseq[offset + i] << 7) & 0x80) |
+                           (p_mp2vseq[offset + 1 + i] >> 1);
+    }
+    return true;
+}
+
+/*****************************************************************************
+ * MP2V sequence extension
+ *****************************************************************************/
+#define MP2VSEQX_HEADER_SIZE        10
+
+#define MP2VSEQX_PROFILE_MASK       0x70
+#define MP2VSEQX_PROFILE_SIMPLE     (5 << 4)
+#define MP2VSEQX_PROFILE_MAIN       (4 << 4)
+#define MP2VSEQX_PROFILE_SNR_SCAL   (3 << 4)
+#define MP2VSEQX_PROFILE_SPAT_SCAL  (2 << 4)
+#define MP2VSEQX_PROFILE_HIGH       (1 << 4)
+#define MP2VSEQX_LEVEL_MASK         0xf
+#define MP2VSEQX_LEVEL_LOW          10
+#define MP2VSEQX_LEVEL_MAIN         8
+#define MP2VSEQX_LEVEL_HIGH1440     6
+#define MP2VSEQX_LEVEL_HIGH         4
+
+#define MP2VSEQX_CHROMA_420         1
+#define MP2VSEQX_CHROMA_422         2
+#define MP2VSEQX_CHROMA_444         3
+
+static inline void mp2vseqx_init(uint8_t *p_mp2vseq)
+{
+    mp2vstart_init(p_mp2vseq, MP2VX_START_CODE);
+    p_mp2vseq[4] = (MP2VX_ID_SEQX << 4) & 0xf0;
+    p_mp2vseq[5] = 0;
+    p_mp2vseq[7] = 0x1;
+    p_mp2vseq[9] = 0;
+}
+
+static inline void mp2vseqx_set_profilelevel(uint8_t *p_mp2vseqx,
+                                             uint8_t i_profilelevel)
+{
+    p_mp2vseqx[4] &= 0xf0;
+    p_mp2vseqx[4] |= i_profilelevel >> 4;
+    p_mp2vseqx[5] &= 0x0f;
+    p_mp2vseqx[5] |= (i_profilelevel << 4) & 0xf0;
+}
+
+static inline uint8_t mp2vseqx_get_profilelevel(const uint8_t *p_mp2vseqx)
+{
+    return ((p_mp2vseqx[4] & 0x0f) << 4) | (p_mp2vseqx[5] >> 4);
+}
+
+static inline void mp2vseqx_set_progressive(uint8_t *p_mp2vseqx)
+{
+    p_mp2vseqx[5] |= 0x8;
+}
+
+static inline bool mp2vseqx_get_progressive(const uint8_t *p_mp2vseqx)
+{
+    return !!(p_mp2vseqx[5] & 0x8);
+}
+
+static inline void mp2vseqx_set_chroma(uint8_t *p_mp2vseqx, uint8_t i_chroma)
+{
+    p_mp2vseqx[5] &= 0xf9;
+    p_mp2vseqx[5] |= (i_chroma & 0x3) << 1;
+}
+
+static inline uint8_t mp2vseqx_get_chroma(const uint8_t *p_mp2vseqx)
+{
+    return ((p_mp2vseqx[5] & 0x06) >> 1);
+}
+
+static inline void mp2vseqx_set_horizontal(uint8_t *p_mp2vseqx,
+                                           uint8_t i_horizontal)
+{
+    p_mp2vseqx[5] &= 0xfe;
+    p_mp2vseqx[5] |= (i_horizontal >> 1) & 0x1;
+    p_mp2vseqx[6] &= 0x7f;
+    p_mp2vseqx[6] |= (i_horizontal << 7) & 0x80;
+}
+
+static inline uint8_t mp2vseqx_get_horizontal(const uint8_t *p_mp2vseqx)
+{
+    return ((p_mp2vseqx[5] & 0x1) << 1) | (p_mp2vseqx[6] >> 7);
+}
+
+static inline void mp2vseqx_set_vertical(uint8_t *p_mp2vseqx,
+                                         uint8_t i_vertical)
+{
+    p_mp2vseqx[6] &= 0x9f;
+    p_mp2vseqx[6] |= (i_vertical << 5) & 0x60;
+}
+
+static inline uint8_t mp2vseqx_get_vertical(const uint8_t *p_mp2vseqx)
+{
+    return (p_mp2vseqx[6] & 0x60) >> 5;
+}
+
+static inline void mp2vseqx_set_bitrate(uint8_t *p_mp2vseqx, uint16_t i_bitrate)
+{
+    p_mp2vseqx[6] &= 0xe0;
+    p_mp2vseqx[6] |= (i_bitrate >> 7) & 0x1f;
+    p_mp2vseqx[7] = ((i_bitrate << 1) & 0xfe) | 0x1;
+}
+
+static inline uint16_t mp2vseqx_get_bitrate(const uint8_t *p_mp2vseqx)
+{
+    return ((p_mp2vseqx[6] & 0x1f) << 7) | (p_mp2vseqx[7] >> 1);
+}
+
+static inline void mp2vseqx_set_vbvbuffer(uint8_t *p_mp2vseqx,
+                                          uint8_t i_vbvbuffer)
+{
+    p_mp2vseqx[8] = i_vbvbuffer;
+}
+
+static inline uint8_t mp2vseqx_get_vbvbuffer(const uint8_t *p_mp2vseqx)
+{
+    return p_mp2vseqx[8];
+}
+
+static inline void mp2vseqx_set_lowdelay(uint8_t *p_mp2vseqx)
+{
+    p_mp2vseqx[9] |= 0x8;
+}
+
+static inline bool mp2vseqx_get_lowdelay(const uint8_t *p_mp2vseqx)
+{
+    return !!(p_mp2vseqx[9] & 0x8);
+}
+
+static inline void mp2vseqx_set_frameraten(uint8_t *p_mp2vseqx,
+                                           uint8_t i_frameraten)
+{
+    p_mp2vseqx[9] &= 0x9f;
+    p_mp2vseqx[9] |= (i_frameraten << 5) & 0x60;
+}
+
+static inline uint8_t mp2vseqx_get_frameraten(const uint8_t *p_mp2vseqx)
+{
+    return (p_mp2vseqx[9] & 0x60) >> 5;
+}
+
+static inline void mp2vseqx_set_framerated(uint8_t *p_mp2vseqx,
+                                           uint8_t i_framerated)
+{
+    p_mp2vseqx[9] &= 0xe0;
+    p_mp2vseqx[9] |= i_framerated & 0x1f;
+}
+
+static inline uint8_t mp2vseqx_get_framerated(const uint8_t *p_mp2vseqx)
+{
+    return (p_mp2vseqx[9] & 0x1f);
+}
+
+/*****************************************************************************
+ * MP2V sequence display extension
+ *****************************************************************************/
+#define MP2VSEQDX_HEADER_SIZE        9
+#define MP2VSEQDX_COLOR_SIZE         3
+
+static inline void mp2vseqdx_init(uint8_t *p_mp2vseq)
+{
+    mp2vstart_init(p_mp2vseq, MP2VX_START_CODE);
+    p_mp2vseq[4] = (MP2VX_ID_SEQDX << 4) & 0xf0;
+}
+
+static inline void mp2vseqdx_set_format(uint8_t *p_mp2vseqdx,
+                                        uint8_t i_format)
+{
+    p_mp2vseqdx[4] &= 0xf1;
+    p_mp2vseqdx[4] |= (i_format << 1) & 0xe;
+}
+
+static inline uint8_t mp2vseqdx_get_format(const uint8_t *p_mp2vseqdx)
+{
+    return ((p_mp2vseqdx[4] & 0x0e) >> 1);
+}
+
+static inline void mp2vseqdx_set_color(uint8_t *p_mp2vseqdx)
+{
+    p_mp2vseqdx[4] |= 0x1;
+}
+
+static inline bool mp2vseqdx_get_color(const uint8_t *p_mp2vseqdx)
+{
+    return !!(p_mp2vseqdx[4] & 0x1);
+}
+
+static inline void mp2vseqdx_set_primaries(uint8_t *p_mp2vseqdx,
+                                                 uint8_t i_primaries)
+{
+    mp2vseqdx_set_color(p_mp2vseqdx);
+    p_mp2vseqdx[5] = i_primaries;
+}
+
+static inline uint8_t mp2vseqdx_get_primaries(const uint8_t *p_mp2vseqdx)
+{
+    if (!mp2vseqdx_get_color(p_mp2vseqdx))
+        return 1;
+    return p_mp2vseqdx[5];
+}
+
+static inline void mp2vseqdx_set_transfer(uint8_t *p_mp2vseqdx,
+                                          uint8_t i_transfer)
+{
+    mp2vseqdx_set_color(p_mp2vseqdx);
+    p_mp2vseqdx[6] = i_transfer;
+}
+
+static inline uint8_t mp2vseqdx_get_transfer(const uint8_t *p_mp2vseqdx)
+{
+    if (!mp2vseqdx_get_color(p_mp2vseqdx))
+        return 1;
+    return p_mp2vseqdx[6];
+}
+
+static inline void mp2vseqdx_set_matrixcoeffs(uint8_t *p_mp2vseqdx,
+                                              uint8_t i_matrixcoeffs)
+{
+    mp2vseqdx_set_color(p_mp2vseqdx);
+    p_mp2vseqdx[7] = i_matrixcoeffs;
+}
+
+static inline uint8_t mp2vseqdx_get_matrixcoeffs(const uint8_t *p_mp2vseqdx)
+{
+    if (!mp2vseqdx_get_color(p_mp2vseqdx))
+        return 1;
+    return p_mp2vseqdx[7];
+}
+
+static inline void mp2vseqdx_set_horizontal(uint8_t *p_mp2vseqdx,
+                                            uint16_t i_horizontal)
+{
+    unsigned int base = mp2vseqdx_get_color(p_mp2vseqdx) ? 8 : 5;
+    p_mp2vseqdx[base] &= 0xfe;
+    p_mp2vseqdx[base] = (i_horizontal >> 6) & 0xff;
+    p_mp2vseqdx[base + 1] &= 0x1;
+    p_mp2vseqdx[base + 1] |= ((i_horizontal << 2) & 0xfc) | 0x2;
+}
+
+static inline uint16_t mp2vseqdx_get_horizontal(const uint8_t *p_mp2vseqdx)
+{
+    unsigned int base = mp2vseqdx_get_color(p_mp2vseqdx) ? 8 : 5;
+    return (p_mp2vseqdx[base] << 6) | (p_mp2vseqdx[base + 1] >> 2);
+}
+
+static inline void mp2vseqdx_set_vertical(uint8_t *p_mp2vseqdx,
+                                          uint16_t i_vertical)
+{
+    unsigned int base = mp2vseqdx_get_color(p_mp2vseqdx) ? 8 : 5;
+    p_mp2vseqdx[base + 1] &= 0xfe;
+    p_mp2vseqdx[base + 1] |= (i_vertical >> 13) & 0x1;
+    p_mp2vseqdx[base + 2] = (i_vertical >> 5) & 0xff;
+    p_mp2vseqdx[base + 3] = i_vertical << 3;
+}
+
+static inline uint8_t mp2vseqdx_get_vertical(const uint8_t *p_mp2vseqdx)
+{
+    unsigned int base = mp2vseqdx_get_color(p_mp2vseqdx) ? 8 : 5;
+    return ((p_mp2vseqdx[base + 1] & 0x1) << 13) |
+           (p_mp2vseqdx[base + 2] << 5) | (p_mp2vseqdx[base + 3] >> 3);
+}
+
+/*****************************************************************************
+ * MP2V GOP header
+ *****************************************************************************/
+#define MP2VGOP_HEADER_SIZE         8
+#define MP2VGOP_START_CODE          0xb8
+
+static inline void mp2vgop_init(uint8_t *p_mp2vgop)
+{
+    mp2vstart_init(p_mp2vgop, MP2VGOP_START_CODE);
+    p_mp2vgop[7] = 0x0;
+}
+
+static inline void mp2vgop_set_timecode(uint8_t *p_mp2vgop, uint32_t i_timecode)
+{
+    p_mp2vgop[4] = i_timecode >> 17;
+    p_mp2vgop[5] = (i_timecode >> 9) & 0xff;
+    p_mp2vgop[6] = (i_timecode >> 1) & 0xff;
+    p_mp2vgop[7] &= 0x7f;
+    p_mp2vgop[7] |= (i_timecode << 7) & 0x80;
+}
+
+static inline uint16_t mp2vgop_get_timecode(const uint8_t *p_mp2vgop)
+{
+    return (p_mp2vgop[4] << 17) | (p_mp2vgop[5] << 9) | (p_mp2vgop[6] << 1) |
+           (p_mp2vgop[7] >> 7);
+}
+
+static inline void mp2vgop_set_closedgop(uint8_t *p_mp2vgop)
+{
+    p_mp2vgop[7] |= 0x40;
+}
+
+static inline bool mp2vgop_get_closedgop(const uint8_t *p_mp2vgop)
+{
+    return !!(p_mp2vgop[7] & 0x40);
+}
+
+static inline void mp2vgop_set_brokenlink(uint8_t *p_mp2vgop)
+{
+    p_mp2vgop[7] |= 0x20;
+}
+
+static inline bool mp2vgop_get_brokenlink(const uint8_t *p_mp2vgop)
+{
+    return !!(p_mp2vgop[7] & 0x20);
+}
+
+/*****************************************************************************
+ * MP2V picture header
+ *****************************************************************************/
+#define MP2VPIC_HEADER_SIZE         8
+#define MP2VPIC_START_CODE          0x0
+/* last slice header */
+#define MP2VPIC_LAST_CODE           0xaf
+
+#define MP2VPIC_TYPE_I              1
+#define MP2VPIC_TYPE_P              2
+#define MP2VPIC_TYPE_B              3
+#define MP2VPIC_TYPE_D              4
+
+static inline void mp2vpic_init(uint8_t *p_mp2vpic)
+{
+    mp2vstart_init(p_mp2vpic, MP2VPIC_START_CODE);
+    p_mp2vpic[7] = 0x0;
+}
+
+static inline void mp2vpic_set_temporalreference(uint8_t *p_mp2vpic,
+                                                 uint16_t i_temporalreference)
+{
+    p_mp2vpic[4] = i_temporalreference >> 2;
+    p_mp2vpic[5] &= 0x3f;
+    p_mp2vpic[5] |= (i_temporalreference << 6) & 0xff;
+}
+
+static inline uint16_t mp2vpic_get_temporalreference(const uint8_t *p_mp2vpic)
+{
+    return (p_mp2vpic[4] << 2) | (p_mp2vpic[5] >> 6);
+}
+
+static inline void mp2vpic_set_codingtype(uint8_t *p_mp2vpic,
+                                          uint8_t i_codingtype)
+{
+    p_mp2vpic[5] &= ~0x38;
+    p_mp2vpic[5] |= (i_codingtype << 3) & 0x38;
+}
+
+static inline uint16_t mp2vpic_get_codingtype(const uint8_t *p_mp2vpic)
+{
+    return (p_mp2vpic[5] >> 3) & 0x7;
+}
+
+static inline void mp2vpic_set_vbvdelay(uint8_t *p_mp2vpic, uint16_t i_vbvdelay)
+{
+    p_mp2vpic[5] &= 0xf8;
+    p_mp2vpic[5] |= i_vbvdelay >> 13;
+    p_mp2vpic[6] = (i_vbvdelay >> 5) & 0xff;
+    p_mp2vpic[7] &= 0x7;
+    p_mp2vpic[7] |= (i_vbvdelay << 3) & 0xf8;
+}
+
+static inline uint16_t mp2vpic_get_vbvdelay(const uint8_t *p_mp2vpic)
+{
+    return ((p_mp2vpic[5] & 0x7) << 13) | (p_mp2vpic[6] << 5) |
+           (p_mp2vpic[7] >>3);
+}
+
+/*****************************************************************************
+ * MP2V picture extension
+ *****************************************************************************/
+#define MP2VPICX_HEADER_SIZE        9
+
+#define MP2VPICX_TOP_FIELD          1
+#define MP2VPICX_BOTTOM_FIELD       2
+#define MP2VPICX_FRAME_PICTURE      3
+
+static inline void mp2vpicx_init(uint8_t *p_mp2vpic)
+{
+    mp2vstart_init(p_mp2vpic, MP2VX_START_CODE);
+    p_mp2vpic[4] = (MP2VX_ID_PICX << 4) & 0xf0;
+    p_mp2vpic[7] = 0;
+    p_mp2vpic[8] = 0;
+}
+
+static inline void mp2vpicx_set_fcode00(uint8_t *p_mp2vpicx,
+                                        uint8_t i_fcode00)
+{
+    p_mp2vpicx[4] &= 0xf0;
+    p_mp2vpicx[4] |= i_fcode00 & 0xf;
+}
+
+static inline uint8_t mp2vpicx_get_fcode00(const uint8_t *p_mp2vpicx)
+{
+    return (p_mp2vpicx[4] & 0xf);
+}
+
+static inline void mp2vpicx_set_fcode01(uint8_t *p_mp2vpicx,
+                                        uint8_t i_fcode01)
+{
+    p_mp2vpicx[5] &= 0x0f;
+    p_mp2vpicx[5] |= (i_fcode01 << 4) & 0xf0;
+}
+
+static inline uint8_t mp2vpicx_get_fcode01(const uint8_t *p_mp2vpicx)
+{
+    return (p_mp2vpicx[5] >> 4);
+}
+
+static inline void mp2vpicx_set_fcode10(uint8_t *p_mp2vpicx,
+                                        uint8_t i_fcode10)
+{
+    p_mp2vpicx[5] &= 0xf0;
+    p_mp2vpicx[5] |= i_fcode10 & 0xf;
+}
+
+static inline uint8_t mp2vpicx_get_fcode10(const uint8_t *p_mp2vpicx)
+{
+    return (p_mp2vpicx[5] & 0xf);
+}
+
+static inline void mp2vpicx_set_fcode11(uint8_t *p_mp2vpicx,
+                                        uint8_t i_fcode11)
+{
+    p_mp2vpicx[6] &= 0x0f;
+    p_mp2vpicx[6] |= (i_fcode11 << 4) & 0xf0;
+}
+
+static inline uint8_t mp2vpicx_get_fcode11(const uint8_t *p_mp2vpicx)
+{
+    return (p_mp2vpicx[6] >> 4);
+}
+
+static inline void mp2vpicx_set_intradc(uint8_t *p_mp2vpicx,
+                                        uint8_t i_intradc)
+{
+    p_mp2vpicx[6] &= 0xf3;
+    p_mp2vpicx[6] |= (i_intradc << 2) & 0xc;
+}
+
+static inline uint8_t mp2vpicx_get_intradc(const uint8_t *p_mp2vpicx)
+{
+    return ((p_mp2vpicx[6] & 0x0c) >> 2);
+}
+
+static inline void mp2vpicx_set_structure(uint8_t *p_mp2vpicx,
+                                          uint8_t i_structure)
+{
+    p_mp2vpicx[6] &= 0xfc;
+    p_mp2vpicx[6] |= i_structure & 0x3;
+}
+
+static inline uint8_t mp2vpicx_get_structure(const uint8_t *p_mp2vpicx)
+{
+    return (p_mp2vpicx[6] & 0x3);
+}
+
+static inline void mp2vpicx_set_tff(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x80;
+}
+
+static inline bool mp2vpicx_get_tff(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x80);
+}
+
+static inline void mp2vpicx_set_framepreddct(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x40;
+}
+
+static inline bool mp2vpicx_get_framepreddct(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x40);
+}
+
+static inline void mp2vpicx_set_concealmentmv(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x20;
+}
+
+static inline bool mp2vpicx_get_concealmentmv(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x20);
+}
+
+static inline void mp2vpicx_set_qscale(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x10;
+}
+
+static inline bool mp2vpicx_get_qscale(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x10);
+}
+
+static inline void mp2vpicx_set_intravlc(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x8;
+}
+
+static inline bool mp2vpicx_get_intravlc(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x8);
+}
+
+static inline void mp2vpicx_set_alternatescan(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x4;
+}
+
+static inline bool mp2vpicx_get_alternatescan(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x4);
+}
+
+static inline void mp2vpicx_set_rff(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x2;
+}
+
+static inline bool mp2vpicx_get_rff(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x2);
+}
+
+static inline void mp2vpicx_set_chroma420(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[7] |= 0x1;
+}
+
+static inline bool mp2vpicx_get_chroma420(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[7] & 0x1);
+}
+
+static inline void mp2vpicx_set_progressive(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[8] |= 0x80;
+}
+
+static inline bool mp2vpicx_get_progressive(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[8] & 0x80);
+}
+
+static inline void mp2vpicx_set_compositedisplay(uint8_t *p_mp2vpicx)
+{
+    p_mp2vpicx[8] |= 0x40;
+}
+
+static inline bool mp2vpicx_get_compositedisplay(const uint8_t *p_mp2vpicx)
+{
+    return !!(p_mp2vpicx[8] & 0x40);
+}
+
+/*****************************************************************************
+ * MP2V end sequence
+ *****************************************************************************/
+#define MP2VEND_HEADER_SIZE         4
+#define MP2VEND_START_CODE          0xb7
+
+static inline void mp2vend_init(uint8_t *p_mp2vend)
+{
+    mp2vstart_init(p_mp2vend, MP2VEND_START_CODE);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mpeg/mpga.h b/mpeg/mpga.h
new file mode 100644
index 0000000..0c8ff7b
--- /dev/null
+++ b/mpeg/mpga.h
@@ -0,0 +1,227 @@
+/*****************************************************************************
+ * mpga.h: ISO/IEC 11172-3 and 13818-3 MPEG audio
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - ISO/IEC 11172-3
+ *  - ISO/IEC 13818-3
+ */
+
+#ifndef __BITSTREAM_MPEG_MPGA_H__
+#define __BITSTREAM_MPEG_MPGA_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include <stdbool.h>  /* bool */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * MPEG audio header
+ *****************************************************************************/
+#define MPGA_HEADER_SIZE        4
+
+#define MPGA_ID_1               1
+#define MPGA_ID_2               0
+
+#define MPGA_LAYER_1            3
+#define MPGA_LAYER_2            2
+#define MPGA_LAYER_3            1
+#define MPGA_LAYER_ADTS         0
+
+#define MPGA_BITRATE_INVALID    15
+#define MPGA_SAMPLERATE_INVALID 3
+
+#define MPGA_MODE_STEREO        0
+#define MPGA_MODE_JOINT         1
+#define MPGA_MODE_DUAL_MONO     2
+#define MPGA_MODE_MONO          3
+
+#define MPGA_EMPHASIS_NONE      0
+#define MPGA_EMPHASIS_50_15     1
+#define MPGA_EMPHASIS_INVALID   2
+#define MPGA_EMPHASIS_J_17      3
+
+static inline void mpga_set_sync(uint8_t *p_mpga)
+{
+    p_mpga[0] = 0xff;
+    p_mpga[1] = 0xf9;
+    p_mpga[2] = 0x0;
+    p_mpga[3] = 0x0;
+}
+
+/* unofficial extension */
+static inline bool mpga_get_mpeg25(const uint8_t *p_mpga)
+{
+    return !(p_mpga[1] & 0x10);
+}
+
+static inline void mpga_set_mpeg25(uint8_t *p_mpga)
+{
+    p_mpga[1] &= ~0x10;
+}
+
+static inline bool mpga_get_id(const uint8_t *p_mpga)
+{
+    return !!(p_mpga[1] & 0x08);
+}
+
+static inline void mpga_clear_id(uint8_t *p_mpga)
+{
+    p_mpga[1] &= ~0x08;
+}
+
+static inline uint8_t mpga_get_layer(const uint8_t *p_mpga)
+{
+    return (p_mpga[1] & 0x06) >> 1;
+}
+
+static inline void mpga_set_layer(uint8_t *p_mpga, uint8_t i_layer)
+{
+    p_mpga[1] &= ~0x06;
+    p_mpga[1] |= (i_layer & 0x3) << 1;
+}
+
+static inline bool mpga_get_protection_absent(const uint8_t *p_mpga)
+{
+    return !!(p_mpga[1] & 0x01);
+}
+
+static inline void mpga_clear_protection_absent(uint8_t *p_mpga)
+{
+    p_mpga[1] &= ~0x01;
+}
+
+static inline uint8_t mpga_get_bitrate_index(const uint8_t *p_mpga)
+{
+    return p_mpga[2] >> 4;
+}
+
+static inline void mpga_set_bitrate_index(uint8_t *p_mpga, uint8_t i_index)
+{
+    p_mpga[2] &= ~0xf0;
+    p_mpga[2] |= i_index << 4;
+}
+
+static inline uint8_t mpga_get_sampling_freq(const uint8_t *p_mpga)
+{
+    return (p_mpga[2] & 0xc) >> 2;
+}
+
+static inline void mpga_set_sampling_freq(uint8_t *p_mpga, uint8_t i_freq)
+{
+    p_mpga[2] &= ~0x0c;
+    p_mpga[2] |= (i_freq & 0x3) << 2;
+}
+
+static inline bool mpga_get_padding(const uint8_t *p_mpga)
+{
+    return !!(p_mpga[2] & 0x02);
+}
+
+static inline void mpga_set_padding(uint8_t *p_mpga)
+{
+    p_mpga[2] |= 0x02;
+}
+
+static inline uint8_t mpga_get_mode(const uint8_t *p_mpga)
+{
+    return (p_mpga[3] & 0xc0) >> 6;
+}
+
+static inline void mpga_set_mode(uint8_t *p_mpga, uint8_t i_mode)
+{
+    p_mpga[3] &= ~0xc0;
+    p_mpga[3] |= i_mode << 6;
+}
+
+static inline uint8_t mpga_get_mode_ext(const uint8_t *p_mpga)
+{
+    return (p_mpga[3] & 0x30) >> 4;
+}
+
+static inline void mpga_set_mode_ext(uint8_t *p_mpga, uint8_t i_mode_ext)
+{
+    p_mpga[3] &= ~0x30;
+    p_mpga[3] |= (i_mode_ext & 0x3) << 4;
+}
+
+static inline bool mpga_get_copyright(const uint8_t *p_mpga)
+{
+    return !!(p_mpga[3] & 0x80);
+}
+
+static inline void mpga_set_copyright(uint8_t *p_mpga)
+{
+    p_mpga[3] |= 0x80;
+}
+
+static inline bool mpga_get_original(const uint8_t *p_mpga)
+{
+    return !!(p_mpga[3] & 0x40);
+}
+
+static inline void mpga_set_original(uint8_t *p_mpga)
+{
+    p_mpga[3] |= 0x40;
+}
+
+static inline uint8_t mpga_get_emphasis(const uint8_t *p_mpga)
+{
+    return p_mpga[3] & 0x03;
+}
+
+static inline void mpga_set_emphasis(uint8_t *p_mpga, uint8_t i_emphasis)
+{
+    p_mpga[3] &= ~0x03;
+    p_mpga[3] |= i_emphasis & 0x03;
+}
+
+static inline bool mpga_sync_compare(const uint8_t *p_mpga1, const uint8_t *p_mpga2)
+{
+    return p_mpga1[0] == p_mpga2[0] &&
+           p_mpga1[1] == p_mpga2[1] &&
+           (p_mpga1[2] & 0xfc) == (p_mpga2[2] & 0xfc) &&
+           p_mpga1[3] == p_mpga2[3];
+}
+
+/* same but only takes into account meaningful fields */
+static inline bool mpga_sync_compare_formats(const uint8_t *p_mpga1, const uint8_t *p_mpga2)
+{
+    return p_mpga1[0] == p_mpga2[0] &&
+           (p_mpga1[1] & 0xfe) == (p_mpga2[1] & 0xfe) &&
+           (p_mpga1[2] & 0xfc) == (p_mpga2[2] & 0xfc) &&
+           (p_mpga1[3] & 0xc0) == (p_mpga2[3] & 0xc0);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mpeg/pes.h b/mpeg/pes.h
index 98a45f8..0095c6d 100644
--- a/mpeg/pes.h
+++ b/mpeg/pes.h
@@ -45,25 +45,32 @@ extern "C"
 /*****************************************************************************
  * 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_HEADER_SIZE             6
+#define PES_HEADER_SIZE_NOPTS       9
+#define PES_HEADER_SIZE_PTS         14
+#define PES_HEADER_SIZE_PTSDTS      19
+#define PES_HEADER_OPTIONAL_SIZE    3
+#define PES_HEADER_TS_SIZE          5
 
 #define PES_STREAM_ID_MIN           0xbc
+#define PES_STREAM_ID_PSM           0xbc
 #define PES_STREAM_ID_PRIVATE_1     0xbd
+#define PES_STREAM_ID_PADDING       0xbe
 #define PES_STREAM_ID_PRIVATE_2     0xbf
-#define PES_STREAM_ID_AUDIO_MPEG    0xc0
-#define PES_STREAM_ID_VIDEO_MPEG    0xe0
+#define PES_STREAM_ID_AUDIO_MPEG    0xc0 /* and following */
+#define PES_STREAM_ID_VIDEO_MPEG    0xe0 /* and following */
+#define PES_STREAM_ID_ECM           0xf0
+#define PES_STREAM_ID_EMM           0xf1
+#define PES_STREAM_ID_DSMCC         0xf2
+#define PES_STREAM_ID_MHEG          0xf3
+#define PES_STREAM_ID_H222_1_E      0xf8
+#define PES_STREAM_ID_PSD           0xff
 
 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)
@@ -71,12 +78,22 @@ static inline void pes_set_streamid(uint8_t *p_pes, uint8_t i_stream_id)
     p_pes[3] = i_stream_id;
 }
 
+static inline uint8_t pes_get_streamid(const uint8_t *p_pes)
+{
+    return p_pes[3];
+}
+
 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 uint16_t pes_get_length(const uint8_t *p_pes)
+{
+    return (p_pes[4] << 8) | p_pes[5];
+}
+
 static inline void pes_set_headerlength(uint8_t *p_pes, uint8_t i_length)
 {
     p_pes[6] = 0x80;
@@ -96,23 +113,54 @@ static inline void pes_set_dataalignment(uint8_t *p_pes)
     p_pes[6] |= 0x4;
 }
 
+static inline bool pes_get_dataalignment(const uint8_t *p_pes)
+{
+    return !!(p_pes[6] & 0x4);
+}
+
+static inline bool pes_has_pts(const uint8_t *p_pes)
+{
+    return !!(p_pes[7] & 0x80);
+}
+
+static inline bool pes_has_dts(const uint8_t *p_pes)
+{
+    return (p_pes[7] & 0xc0) == 0xc0;
+}
+
 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);
+    uint8_t marker = pes_has_dts(p_pes) ? 0x30 : 0x20;
+    p_pes[9] = marker | 0x1 | ((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 bool pes_validate_pts(const uint8_t *p_pes)
+{
+    return ((p_pes[9] & 0xe1) == 0x21)
+            && (p_pes[11] & 0x1) && (p_pes[13] & 0x1);
+}
+
+static inline uint64_t pes_get_pts(const uint8_t *p_pes)
+{
+    return (((uint64_t)p_pes[9] & 0xe)) << 29 | (p_pes[10] << 22) |
+           ((p_pes[11] & 0xfe) << 14) | (p_pes[12] << 7) |
+           ((p_pes[13] & 0xfe) >> 1);
+}
+
 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[9] &= 0x0f;
+    p_pes[9] |= 0x30;
     p_pes[14] = 0x11 | ((i_dts >> 29) & 0xe);
     p_pes[15] = (i_dts >> 22) & 0xff;
     p_pes[16] = 0x1 | ((i_dts >> 14) & 0xfe);
@@ -120,18 +168,36 @@ static inline void pes_set_dts(uint8_t *p_pes, uint64_t i_dts)
     p_pes[18] = 0x1 | ((i_dts << 1) & 0xfe);
 }
 
+static inline bool pes_validate_dts(const uint8_t *p_pes)
+{
+    return (p_pes[9] & 0x10) && ((p_pes[14] & 0xf1) == 0x11)
+            && (p_pes[16] & 0x1) && (p_pes[18] & 0x1);
+}
+
+static inline uint64_t pes_get_dts(const uint8_t *p_pes)
+{
+    return (((uint64_t)p_pes[14] & 0xe)) << 29 | (p_pes[15] << 22) |
+           ((p_pes[16] & 0xfe) << 14) | (p_pes[17] << 7) |
+           ((p_pes[18] & 0xfe) >> 1);
+}
+
 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);
 }
 
+static inline bool pes_validate_header(const uint8_t *p_pes)
+{
+    return ((p_pes[6] & 0xc0) == 0x80);
+}
+
 /*****************************************************************************
  * PES payload
  *****************************************************************************/
 static inline uint8_t *pes_payload(uint8_t *p_pes)
 {
-    return p_pes + PES_HEADER_SIZE + pes_get_headerlength(p_pes);
+    return p_pes + PES_HEADER_SIZE + PES_HEADER_OPTIONAL_SIZE + pes_get_headerlength(p_pes);
 }
 
 #ifdef __cplusplus
diff --git a/mpeg/psi/cat_print.h b/mpeg/psi/cat_print.h
index e2e381b..c220da2 100644
--- a/mpeg/psi/cat_print.h
+++ b/mpeg/psi/cat_print.h
@@ -45,7 +45,7 @@ static inline void cat_table_print(uint8_t **pp_sections, f_print pf_print,
 {
     uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
     uint8_t i;
-    char *psz_table_name = "CAT";
+    const char *psz_table_name = "CAT";
 
     if (psi_get_tableid(psi_table_get_section(pp_sections, 0)) == TSDT_TABLE_ID)
         psz_table_name = "TSDT";
diff --git a/mpeg/psi/desc_04.h b/mpeg/psi/desc_04.h
index 14eadfa..c7fe45d 100644
--- a/mpeg/psi/desc_04.h
+++ b/mpeg/psi/desc_04.h
@@ -92,7 +92,7 @@ static inline void desc04_set_channel(uint8_t *p_desc, uint8_t i_channel)
     p_desc[5] = i_channel | 0xc0;
 }
 
-static inline char *desc04_get_type_txt(uint8_t i_type)
+static inline const char *desc04_get_type_txt(uint8_t i_type)
 {
     return i_type == 0 ? "reserved" :
            i_type == 1 ? "Spatial Scalability" :
diff --git a/mpeg/psi/desc_05.h b/mpeg/psi/desc_05.h
index c43b8c8..f993c7e 100644
--- a/mpeg/psi/desc_05.h
+++ b/mpeg/psi/desc_05.h
@@ -52,7 +52,7 @@ static inline void desc05_init(uint8_t *p_desc)
     desc_set_length(p_desc, DESC05_HEADER_SIZE - DESC_HEADER_SIZE);
 }
 
-static inline void desc05_set_identifier(uint8_t *p_desc, uint8_t p_id[4])
+static inline void desc05_set_identifier(uint8_t *p_desc, const uint8_t p_id[4])
 {
     p_desc[2] = p_id[0];
     p_desc[3] = p_id[1];
diff --git a/mpeg/psi/desc_0a.h b/mpeg/psi/desc_0a.h
index fc680a2..5552f09 100644
--- a/mpeg/psi/desc_0a.h
+++ b/mpeg/psi/desc_0a.h
@@ -48,6 +48,11 @@ extern "C"
 #define DESC0A_HEADER_SIZE      DESC_HEADER_SIZE
 #define DESC0A_LANGUAGE_SIZE    4
 
+#define DESC0A_TYPE_UNDEFINED   0x0
+#define DESC0A_TYPE_CLEAN       0x1
+#define DESC0A_TYPE_HEARING_IMP 0x2
+#define DESC0A_TYPE_VISUAL_IMP  0x3
+
 static inline void desc0a_init(uint8_t *p_desc)
 {
     desc_set_tag(p_desc, 0x0a);
@@ -107,7 +112,7 @@ static inline void desc0a_print(uint8_t *p_desc, f_print pf_print,
         j++;
         switch (i_print_type) {
         case PRINT_XML:
-            pf_print(opaque, "<AUDIO_LANGUAGE_DESC language=\"%3.3s\" audiotype=\"%u\" autiotype_txt=\"%s\"/>",
+            pf_print(opaque, "<AUDIO_LANGUAGE_DESC language=\"%3.3s\" audiotype=\"%u\" audiotype_txt=\"%s\"/>",
                      (const char *)desc0an_get_code(p_desc_n),
                      desc0an_get_audiotype(p_desc_n),
                      desc0a_get_audiotype_txt(desc0an_get_audiotype(p_desc_n))
diff --git a/mpeg/psi/desc_24.h b/mpeg/psi/desc_24.h
index 0eae715..6b76590 100644
--- a/mpeg/psi/desc_24.h
+++ b/mpeg/psi/desc_24.h
@@ -310,8 +310,8 @@ static inline void desc24_print(const uint8_t *p_desc, f_print pf_print,
                  " content_reference_id_record_length=\"%u\""
                  " content_reference_id_record=\"%s\""
                  " content_time_base_indicator=\"%u\""
-                 " content_time_base_value=\"%"PRIu64"\""
-                 " metadata_time_base_value=\"%"PRIu64"\""
+                 " content_time_base_value=\"%" PRIu64 "\""
+                 " metadata_time_base_value=\"%" PRIu64 "\""
                  " content_id=\"%u\""
                  " time_base_association_data_length=\"%u\""
                  " time_base_association_data=\"%s\"/>",
@@ -336,8 +336,8 @@ static inline void desc24_print(const uint8_t *p_desc, f_print pf_print,
                  " content_reference_id_record_length=%u"
                  " content_reference_id_record=\"%s\""
                  " content_time_base_indicator=%u"
-                 " content_time_base_value=\"%"PRIu64"\""
-                 " metadata_time_base_value=\"%"PRIu64"\""
+                 " content_time_base_value=\"%" PRIu64 "\""
+                 " metadata_time_base_value=\"%" PRIu64 "\""
                  " content_id=%u"
                  " time_base_association_data_length=%u"
                  " time_base_association_data=\"%s\"",
diff --git a/mpeg/psi/desc_26.h b/mpeg/psi/desc_26.h
index 1efe8ba..940284c 100644
--- a/mpeg/psi/desc_26.h
+++ b/mpeg/psi/desc_26.h
@@ -235,7 +235,7 @@ static inline void desc26_print(const uint8_t *p_desc, f_print pf_print,
     uint8_t i, i_service_identification_record_length;
     const uint8_t *p_service_identification_record = desc26_get_service_identification_record(p_desc, &i_service_identification_record_length);
     char psz_service_identification_record[2 * 256 + 1];
-    char *extra_str = "decoder_config";
+    const char *extra_str = "decoder_config";
     const uint8_t *p_extra = NULL;
     uint8_t i_extra_length = 0;
     char psz_extra[2 * 256 + 1];
diff --git a/mpeg/psi/descriptors.h b/mpeg/psi/descriptors.h
index 688d86a..ff472be 100644
--- a/mpeg/psi/descriptors.h
+++ b/mpeg/psi/descriptors.h
@@ -93,6 +93,8 @@ static inline void desc_print_begin(const uint8_t *p_desc, f_print pf_print,
 static inline void desc_print_end(const uint8_t *p_desc, f_print pf_print,
                                   void *opaque, print_type_t i_print_type)
 {
+    (void) p_desc;
+
     switch (i_print_type) {
     case PRINT_XML:
         pf_print(opaque, "</DESC>");
@@ -187,6 +189,14 @@ static inline uint8_t *descs_get_desc(uint8_t *p_descs, uint16_t n)
                           descs_get_length(p_descs), n);
 }
 
+static inline bool descs_validate_desc(const uint8_t *p_descs,
+                                       const uint8_t *p_desc,
+                                       uint8_t i_desclength)
+{
+    uint16_t i_descs_length = descs_get_length(p_descs);
+    return (p_desc + i_desclength <= p_descs + i_descs_length);
+}
+
 static inline bool descs_validate(const uint8_t *p_descs)
 {
     return descl_validate(p_descs + DESCS_HEADER_SIZE,
diff --git a/mpeg/psi/descs_print.h b/mpeg/psi/descs_print.h
index a568e4e..b8d8e43 100644
--- a/mpeg/psi/descs_print.h
+++ b/mpeg/psi/descs_print.h
@@ -55,8 +55,8 @@ static inline void descl_print(uint8_t *p_descl, uint16_t i_length,
         j++;
 
         desc_print_begin(p_desc, pf_print, print_opaque, i_print_type);
-
-        if (i_private_data_specifier == 0x28) {
+        if (i_private_data_specifier == 0x28 ||
+            i_private_data_specifier == 0x233a) {
             /* EICTA */
             switch (i_tag) {
 #define CASE_DESC(id)                                                       \
diff --git a/mpeg/psi/pmt.h b/mpeg/psi/pmt.h
index 67de337..9926064 100644
--- a/mpeg/psi/pmt.h
+++ b/mpeg/psi/pmt.h
@@ -52,6 +52,38 @@ extern "C"
 #define pmt_set_program psi_set_tableidext
 #define pmt_get_program psi_get_tableidext
 
+#define PMT_STREAMTYPE_VIDEO_MPEG1      0x1
+#define PMT_STREAMTYPE_VIDEO_MPEG2      0x2
+#define PMT_STREAMTYPE_AUDIO_MPEG1      0x3
+#define PMT_STREAMTYPE_AUDIO_MPEG2      0x4
+#define PMT_STREAMTYPE_PRIVATE_PSI      0x5
+#define PMT_STREAMTYPE_PRIVATE_PES      0x6
+#define PMT_STREAMTYPE_MHEG             0x7
+#define PMT_STREAMTYPE_DSM_CC           0x8
+#define PMT_STREAMTYPE_H222_1           0x9
+#define PMT_STREAMTYPE_13818_6_A        0xa
+#define PMT_STREAMTYPE_13818_6_B        0xb
+#define PMT_STREAMTYPE_13818_6_C        0xc
+#define PMT_STREAMTYPE_13818_6_D        0xd
+#define PMT_STREAMTYPE_H222_0_AUX       0xe
+#define PMT_STREAMTYPE_AUDIO_ADTS       0xf
+#define PMT_STREAMTYPE_VIDEO_MPEG4      0x10
+#define PMT_STREAMTYPE_AUDIO_LATM       0x11
+#define PMT_STREAMTYPE_SL_PES           0x12
+#define PMT_STREAMTYPE_SL_14496         0x13
+#define PMT_STREAMTYPE_SDP              0x14
+#define PMT_STREAMTYPE_META_PES         0x15
+#define PMT_STREAMTYPE_META_PSI         0x16
+#define PMT_STREAMTYPE_META_DC          0x17
+#define PMT_STREAMTYPE_META_OC          0x18
+#define PMT_STREAMTYPE_META_SDP         0x19
+#define PMT_STREAMTYPE_IPMP_13818_11    0x1a
+#define PMT_STREAMTYPE_VIDEO_AVC        0x1b
+#define PMT_STREAMTYPE_VIDEO_AVS        0x42
+#define PMT_STREAMTYPE_IPMP             0x7f
+#define PMT_STREAMTYPE_ATSC_A52         0x81
+#define PMT_STREAMTYPE_SCTE_35          0x86
+
 static inline void pmt_init(uint8_t *p_pmt)
 {
     psi_init(p_pmt, true);
@@ -116,7 +148,7 @@ static inline uint8_t pmtn_get_streamtype(const uint8_t *p_pmt_n)
 
 static inline const char *pmt_get_streamtype_txt(uint8_t i_stream_type) {
     /* ISO/IEC 13818-1 | Table 2-36 - Stream type assignments */
-    if (i_stream_type == 0 || (i_stream_type > 0x1c && i_stream_type < 0x7e))
+    if (i_stream_type == 0)
         return "Reserved";
     switch (i_stream_type) {
         case 0x01: return "11172-2 video (MPEG-1)";
@@ -148,6 +180,8 @@ static inline const char *pmt_get_streamtype_txt(uint8_t i_stream_type) {
         case 0x1B: return "H.264/14496-10 video (MPEG-4/AVC)";
         case 0x42: return "AVS Video";
         case 0x7F: return "IPMP stream";
+        case 0x81: return "ATSC A/52";
+        case 0x86: return "SCTE 35 Splice Information Table";
         default  : return "Unknown";
     }
 }
diff --git a/mpeg/psi/psi.h b/mpeg/psi/psi.h
index 7d287b2..9866c7b 100644
--- a/mpeg/psi/psi.h
+++ b/mpeg/psi/psi.h
@@ -151,12 +151,12 @@ static const uint32_t p_psi_crc_table[256] = {
 
 static inline uint8_t *psi_allocate(void)
 {
-    return malloc((PSI_MAX_SIZE + PSI_HEADER_SIZE) * sizeof(uint8_t));
+    return (uint8_t *)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));
+    return (uint8_t *)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)
@@ -220,7 +220,7 @@ static inline void psi_set_version(uint8_t *p_section, uint8_t i_version)
 
 static inline uint8_t psi_get_version(const uint8_t *p_section)
 {
-    return (p_section[5] & 0x1e) >> 1;
+    return (p_section[5] & 0x3e) >> 1;
 }
 
 static inline void psi_set_current(uint8_t *p_section)
@@ -330,6 +330,8 @@ static inline void psi_assemble_reset(uint8_t **pp_psi_buffer,
 static inline bool psi_assemble_empty(uint8_t **pp_psi_buffer,
                                       uint16_t *pi_psi_buffer_used)
 {
+    (void) pi_psi_buffer_used;
+
     return *pp_psi_buffer == NULL;
 }
 
@@ -438,7 +440,7 @@ static inline void psi_split_section(uint8_t *p_ts, uint8_t *pi_ts_offset,
 
 static inline uint8_t **psi_table_allocate(void)
 {
-    return malloc(PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
+    return (uint8_t **)malloc(PSI_TABLE_MAX_SECTIONS * sizeof(uint8_t *));
 }
 
 static inline void psi_table_init(uint8_t **pp_sections)
diff --git a/mpeg/ts.h b/mpeg/ts.h
index 4bcedc5..fba5e13 100644
--- a/mpeg/ts.h
+++ b/mpeg/ts.h
@@ -56,7 +56,7 @@ extern "C"
 
 static inline uint8_t *ts_allocate(void)
 {
-    return malloc(TS_SIZE * sizeof(uint8_t));
+    return (uint8_t *)malloc(TS_SIZE * sizeof(uint8_t));
 }
 
 static inline void ts_init(uint8_t *p_ts)
@@ -67,6 +67,11 @@ static inline void ts_init(uint8_t *p_ts)
     p_ts[3] = 0x0;
 }
 
+static inline void ts_set_transporterror(uint8_t *p_ts)
+{
+    p_ts[1] |= 0x80;
+}
+
 static inline bool ts_get_transporterror(const uint8_t *p_ts)
 {
     return !!(p_ts[1] & 0x80);
@@ -211,6 +216,16 @@ static inline void tsaf_set_discontinuity(uint8_t *p_ts)
     p_ts[5] |= 0x80;
 }
 
+static inline void tsaf_clear_discontinuity(uint8_t *p_ts)
+{
+    p_ts[5] &= ~0x80;
+}
+
+static inline bool tsaf_has_discontinuity(const uint8_t *p_ts)
+{
+    return !!(p_ts[5] & 0x80);
+}
+
 static inline void tsaf_set_randomaccess(uint8_t *p_ts)
 {
     p_ts[5] |= 0x40;
@@ -250,7 +265,7 @@ static inline bool tsaf_has_pcr(const uint8_t *p_ts)
 
 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) |
+    return ((uint64_t) p_ts[6] << 25) | (p_ts[7] << 17) | (p_ts[8] << 9) | (p_ts[9] << 1) |
            (p_ts[10] >> 7);
 }
 
diff --git a/scte/35.h b/scte/35.h
new file mode 100644
index 0000000..2b1ba17
--- /dev/null
+++ b/scte/35.h
@@ -0,0 +1,732 @@
+/*****************************************************************************
+ * 35.h: SCTE 35 Digital Program Insertion Cueing Message for Cable
+ *****************************************************************************
+ * Copyright (C) 2015 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - SCTE 35 2013 (Digital Program Insertion Cueing Message for Cable)
+ */
+
+#ifndef __BITSTREAM_SCTE_35_H__
+#define __BITSTREAM_SCTE_35_H__
+
+#include <bitstream/common.h>
+#include <bitstream/mpeg/psi/psi.h>
+#include <bitstream/mpeg/psi/descriptors.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * Splice Information Table
+ *****************************************************************************/
+#define SCTE35_TABLE_ID                 0xfc
+#define SCTE35_HEADER_SIZE              (PSI_HEADER_SIZE + 11)
+#define SCTE35_HEADER2_SIZE             2
+
+static inline void scte35_init(uint8_t *p_scte35)
+{
+    psi_set_tableid(p_scte35, SCTE35_TABLE_ID);
+    psi_init(p_scte35, false);
+    p_scte35[1] &= ~0x40; /* private indicator */
+    p_scte35[3] = 0;
+    p_scte35[4] = 0;
+    p_scte35[9] = 0;
+    p_scte35[10] = 0xff;
+    p_scte35[11] = 0xf0;
+}
+
+static inline uint8_t scte35_get_protocol(const uint8_t *p_scte35)
+{
+    return p_scte35[3];
+}
+
+static inline void scte35_set_protocol(uint8_t *p_scte35, uint8_t i_version)
+{
+    p_scte35[3] = i_version;
+}
+
+static inline bool scte35_is_encrypted(const uint8_t *p_scte35)
+{
+    return !!(p_scte35[4] & 0x80);
+}
+
+static inline void scte35_set_encrypted(uint8_t *p_scte35, bool b_encrypted)
+{
+    if (b_encrypted)
+        p_scte35[4] |= 0x80;
+    else
+        p_scte35[4] &= ~0x80;
+}
+
+static inline uint64_t scte35_get_pts_adjustment(const uint8_t *p_scte35)
+{
+    return ((uint64_t)(p_scte35[4] & 0x1) << 32) |
+           ((uint64_t)p_scte35[5] << 24) | ((uint64_t)p_scte35[6] << 16) |
+           ((uint64_t)p_scte35[7] << 8) | (uint64_t)p_scte35[8];
+}
+
+static inline void scte35_set_pts_adjustment(uint8_t *p_scte35,
+                                             uint64_t i_adjustment)
+{
+    p_scte35[4] &= ~0x1;
+    p_scte35[4] |= (i_adjustment >> 32) & 0x1;
+    p_scte35[5] = (i_adjustment >> 24) & 0xff;
+    p_scte35[6] = (i_adjustment >> 16) & 0xff;
+    p_scte35[7] = (i_adjustment >> 8) & 0xff;
+    p_scte35[8] = i_adjustment & 0xff;
+}
+
+static inline uint16_t scte35_get_command_length(const uint8_t *p_scte35)
+{
+    return ((p_scte35[11] & 0xf) << 8) | p_scte35[12];
+}
+
+static inline void scte35_set_command_length(uint8_t *p_scte35,
+                                             uint16_t i_length)
+{
+    p_scte35[11] &= ~0xf;
+    p_scte35[11] |= (i_length >> 8) & 0xf;
+    p_scte35[12] = i_length & 0xff;
+}
+
+static inline uint8_t scte35_get_command_type(const uint8_t *p_scte35)
+{
+    return p_scte35[13];
+}
+
+static inline void scte35_set_command_type(uint8_t *p_scte35, uint8_t i_type)
+{
+    p_scte35[13] = i_type;
+}
+
+static inline uint8_t *scte35_get_command(const uint8_t *p_scte35)
+{
+    return (uint8_t *)p_scte35 + SCTE35_HEADER_SIZE;
+}
+
+static inline uint16_t scte35_get_desclength(const uint8_t *p_scte35)
+{
+    uint16_t i_command_length = scte35_get_command_length(p_scte35);
+    if (i_command_length == 0xfff)
+        return 0;
+    const uint8_t *pi_desclength = scte35_get_command(p_scte35) +
+                                   i_command_length;
+    return (pi_desclength[0] << 8) | pi_desclength[1];
+}
+
+static inline void scte35_set_desclength(uint8_t *p_scte35, uint16_t i_length)
+{
+    uint8_t *pi_desclength = scte35_get_command(p_scte35) +
+                             scte35_get_command_length(p_scte35);
+    pi_desclength[0] = (i_length >> 8) & 0xff;
+    pi_desclength[1] = i_length & 0xff;
+}
+
+static inline uint8_t *scte35_get_descl(const uint8_t *p_scte35)
+{
+    uint16_t i_command_length = scte35_get_command_length(p_scte35);
+    if (i_command_length == 0xfff)
+        return NULL;
+    return scte35_get_command(p_scte35) + i_command_length +
+           SCTE35_HEADER2_SIZE;
+}
+
+/*****************************************************************************
+ * Splice Information Table - splice_time structure
+ *****************************************************************************/
+#define SCTE35_SPLICE_TIME_HEADER_SIZE              1
+#define SCTE35_SPLICE_TIME_TIME_SIZE                4
+
+static inline void scte35_splice_time_init(uint8_t *p_splice_time)
+{
+    p_splice_time[0] = 0x7f;
+}
+
+static inline bool scte35_splice_time_has_time_specified(const uint8_t *p_splice_time)
+{
+    return !!(p_splice_time[0] & 0x80);
+}
+
+static inline void scte35_splice_time_set_time_specified(uint8_t *p_splice_time,
+        bool b_time_specified)
+{
+    if (b_time_specified)
+        p_splice_time[0] |= 0x80;
+    else
+        p_splice_time[0] &= ~0x80;
+}
+
+static inline uint64_t scte35_splice_time_get_pts_time(const uint8_t *p_splice_time)
+{
+    return ((uint64_t)(p_splice_time[0] & 0x1) << 32) |
+           ((uint64_t)p_splice_time[1] << 24) |
+           ((uint64_t)p_splice_time[2] << 16) |
+           ((uint64_t)p_splice_time[3] << 8) |
+           (uint64_t)p_splice_time[4];
+}
+
+static inline void scte35_splice_time_set_pts_time(uint8_t *p_splice_time,
+                                                   uint64_t i_pts_time)
+{
+    p_splice_time[0] &= ~0x1;
+    p_splice_time[0] |= (i_pts_time >> 32) & 0x1;
+    p_splice_time[1] = (i_pts_time >> 24) & 0xff;
+    p_splice_time[2] = (i_pts_time >> 16) & 0xff;
+    p_splice_time[3] = (i_pts_time >> 8) & 0xff;
+    p_splice_time[4] = i_pts_time & 0xff;
+}
+
+static inline uint8_t scte35_splice_time_size(const uint8_t *p_splice_time)
+{
+    return SCTE35_SPLICE_TIME_HEADER_SIZE +
+        (scte35_splice_time_has_time_specified(p_splice_time) ?
+         SCTE35_SPLICE_TIME_TIME_SIZE : 0);
+}
+
+/*****************************************************************************
+ * Splice Information Table - break_duration structure
+ *****************************************************************************/
+#define SCTE35_BREAK_DURATION_HEADER_SIZE              5
+
+static inline void scte35_break_duration_init(uint8_t *p_break_duration)
+{
+    p_break_duration[0] = 0xff;
+}
+
+static inline bool scte35_break_duration_has_auto_return(const uint8_t *p_break_duration)
+{
+    return !!(p_break_duration[0] & 0x80);
+}
+
+static inline void scte35_break_duration_set_auto_return(uint8_t *p_break_duration, bool b_auto_return)
+{
+    if (b_auto_return)
+        p_break_duration[0] |= 0x80;
+    else
+        p_break_duration[0] &= ~0x80;
+}
+
+static inline uint64_t scte35_break_duration_get_duration(const uint8_t *p_break_duration)
+{
+    return ((uint64_t)(p_break_duration[0] & 0x1) << 32) |
+           ((uint64_t)p_break_duration[1] << 24) |
+           ((uint64_t)p_break_duration[2] << 16) |
+           ((uint64_t)p_break_duration[3] << 8) |
+           (uint64_t)p_break_duration[4];
+}
+
+static inline void scte35_break_duration_set_duration(uint8_t *p_break_duration,
+                                                      uint64_t i_duration)
+{
+    p_break_duration[0] &= ~0x1;
+    p_break_duration[0] |= (i_duration >> 32) & 0x1;
+    p_break_duration[1] = (i_duration >> 24) & 0xff;
+    p_break_duration[2] = (i_duration >> 16) & 0xff;
+    p_break_duration[3] = (i_duration >> 8) & 0xff;
+    p_break_duration[4] = i_duration & 0xff;
+}
+
+/*****************************************************************************
+ * Splice Information Table - null command
+ *****************************************************************************/
+#define SCTE35_NULL_COMMAND                         0
+#define SCTE35_NULL_HEADER_SIZE                     0
+
+static inline void scte35_null_init(uint8_t *p_scte35)
+{
+    scte35_init(p_scte35);
+    scte35_set_command_type(p_scte35, SCTE35_NULL_COMMAND);
+    scte35_set_command_length(p_scte35, SCTE35_NULL_HEADER_SIZE);
+    scte35_set_desclength(p_scte35, 0);
+}
+
+static inline bool scte35_null_validate(const uint8_t *p_scte35)
+{
+    return true;
+}
+
+/*****************************************************************************
+ * Splice Information Table - schedule command
+ *****************************************************************************/
+#define SCTE35_SCHEDULE_COMMAND                     4
+
+/* TODO Not implemented (useless) */
+
+/*****************************************************************************
+ * Splice Information Table - insert command
+ *****************************************************************************/
+#define SCTE35_INSERT_COMMAND                       5
+#define SCTE35_INSERT_HEADER_SIZE                   5
+#define SCTE35_INSERT_HEADER2_SIZE                  1
+#define SCTE35_INSERT_COMPONENT_COUNT_SIZE          1
+#define SCTE35_INSERT_COMPONENT_HEADER_SIZE         1
+#define SCTE35_INSERT_FOOTER_SIZE                   4
+
+static inline void scte35_insert_init(uint8_t *p_scte35, uint16_t i_length)
+{
+    scte35_init(p_scte35);
+    scte35_set_command_type(p_scte35, SCTE35_INSERT_COMMAND);
+    scte35_set_command_length(p_scte35,
+                              SCTE35_INSERT_HEADER_SIZE + i_length);
+    scte35_set_desclength(p_scte35, 0);
+
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    p_command[4] = 0xff;
+}
+
+static inline uint32_t scte35_insert_get_event_id(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return ((uint32_t)p_command[0] << 24) | (p_command[1] << 16) |
+           (p_command[2] << 8) | p_command[3];
+}
+
+static inline void scte35_insert_set_event_id(uint8_t *p_scte35,
+                                              uint32_t i_event_id)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    p_command[0] = (i_event_id >> 24) & 0xff;
+    p_command[1] = (i_event_id >> 16) & 0xff;
+    p_command[2] = (i_event_id >> 8) & 0xff;
+    p_command[3] = i_event_id & 0xff;
+}
+
+static inline bool scte35_insert_has_cancel(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return !!(p_command[4] & 0x80);
+}
+
+static inline void scte35_insert_set_cancel(const uint8_t *p_scte35,
+                                            bool b_cancel)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    if (b_cancel)
+        p_command[4] |= 0x80;
+    else {
+        p_command[4] &= ~0x80;
+        p_command[5] = 0xff;
+    }
+}
+
+static inline bool scte35_insert_has_out_of_network(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return !!(p_command[5] & 0x80);
+}
+
+static inline void scte35_insert_set_out_of_network(const uint8_t *p_scte35,
+                                                    bool b_out_of_network)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    if (b_out_of_network)
+        p_command[5] |= 0x80;
+    else
+        p_command[5] &= ~0x80;
+}
+
+static inline bool scte35_insert_has_program_splice(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return !!(p_command[5] & 0x40);
+}
+
+static inline void scte35_insert_set_program_splice(const uint8_t *p_scte35,
+                                                    bool b_program_splice)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    if (b_program_splice)
+        p_command[5] |= 0x40;
+    else
+        p_command[5] &= ~0x40;
+}
+
+static inline bool scte35_insert_has_duration(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return !!(p_command[5] & 0x20);
+}
+
+static inline void scte35_insert_set_duration(const uint8_t *p_scte35,
+                                              bool b_duration)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    if (b_duration)
+        p_command[5] |= 0x20;
+    else
+        p_command[5] &= ~0x20;
+}
+
+static inline bool scte35_insert_has_splice_immediate(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return !!(p_command[5] & 0x10);
+}
+
+static inline void scte35_insert_set_splice_immediate(const uint8_t *p_scte35,
+                                                      bool b_splice_immediate)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    if (b_splice_immediate)
+        p_command[5] |= 0x10;
+    else
+        p_command[5] &= ~0x10;
+}
+
+static inline uint8_t *scte35_insert_get_splice_time(const uint8_t *p_scte35)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    return p_command + SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE;
+}
+
+static inline uint8_t scte35_insert_get_component_count(const uint8_t *p_scte35)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    return p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE];
+}
+
+static inline void scte35_insert_set_component_count(uint8_t *p_scte35,
+                                                     uint8_t i_component_count)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    p_command[SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE] =
+        i_component_count;
+}
+
+static inline uint8_t scte35_insert_component_get_component_tag(const uint8_t *p_component)
+{
+    return p_component[0];
+}
+
+static inline void scte35_insert_component_set_component_tag(uint8_t *p_component, uint8_t i_component_tag)
+{
+    p_component[0] = i_component_tag;
+}
+
+static inline uint8_t *scte35_insert_component_get_splice_time(const uint8_t *p_component)
+{
+    return (uint8_t *)p_component + SCTE35_INSERT_COMPONENT_HEADER_SIZE;
+}
+
+static inline uint8_t *scte35_insert_get_component(const uint8_t *p_scte35,
+                                                   uint8_t n)
+{
+    uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
+                               - PSI_CRC_SIZE;
+    bool b_splice_immediate = scte35_insert_has_splice_immediate(p_scte35);
+    uint8_t *p_scte35_n = scte35_get_command(p_scte35) +
+        SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
+        SCTE35_INSERT_COMPONENT_COUNT_SIZE;
+    if (p_scte35_n - p_scte35 > i_section_size)
+        return NULL;
+
+    while (n) {
+        if (p_scte35_n + SCTE35_INSERT_COMPONENT_HEADER_SIZE - p_scte35 >
+                i_section_size)
+            return NULL;
+        p_scte35_n += SCTE35_INSERT_COMPONENT_HEADER_SIZE +
+            (b_splice_immediate ?
+             scte35_splice_time_size(
+                 scte35_insert_component_get_splice_time(p_scte35_n)) :
+             0);
+        n--;
+    }
+    if (p_scte35_n - p_scte35 >= i_section_size) return NULL;
+    return p_scte35_n;
+}
+
+static inline uint8_t *scte35_insert_get_break_duration(const uint8_t *p_scte35)
+{
+    if (!scte35_insert_has_program_splice(p_scte35))
+        return scte35_insert_get_component(p_scte35,
+                scte35_insert_get_component_count(p_scte35) + 1);
+
+    if (scte35_insert_has_splice_immediate(p_scte35))
+        return scte35_get_command(p_scte35) + SCTE35_INSERT_HEADER_SIZE +
+               SCTE35_INSERT_HEADER2_SIZE;
+
+    uint8_t *p_splice_time = scte35_insert_get_splice_time(p_scte35);
+    return p_splice_time + scte35_splice_time_size(p_splice_time);
+}
+
+static inline uint8_t *scte35_insert_get_footer(const uint8_t *p_scte35)
+{
+    return scte35_insert_get_break_duration(p_scte35) +
+        (scte35_insert_has_duration(p_scte35) ?
+         SCTE35_BREAK_DURATION_HEADER_SIZE : 0);
+}
+
+static inline uint16_t scte35_insert_get_unique_program_id(const uint8_t *p_scte35)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    return (p_footer[0] << 8) | p_footer[1];
+}
+
+static inline void scte35_insert_set_unique_program_id(uint8_t *p_scte35,
+        uint16_t i_unique_program_id)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    p_footer[0] = (i_unique_program_id >> 8) & 0xff;
+    p_footer[1] = i_unique_program_id & 0xff;
+}
+
+static inline uint8_t scte35_insert_get_avail_num(const uint8_t *p_scte35)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    return p_footer[2];
+}
+
+static inline void scte35_insert_set_avail_num(uint8_t *p_scte35,
+                                               uint8_t i_avail_num)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    p_footer[2] = i_avail_num;
+}
+
+static inline uint8_t scte35_insert_get_avails_expected(const uint8_t *p_scte35)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    return p_footer[3];
+}
+
+static inline void scte35_insert_set_avails_expected(uint8_t *p_scte35,
+                                                     uint8_t i_avails_expected)
+{
+    uint8_t *p_footer = scte35_insert_get_footer(p_scte35);
+    p_footer[3] = i_avails_expected;
+}
+
+static inline bool scte35_insert_validate(const uint8_t *p_scte35)
+{
+    size_t i_length = scte35_get_command_length(p_scte35);
+    if (i_length < SCTE35_INSERT_HEADER_SIZE)
+        return false;
+
+    if (scte35_insert_has_cancel(p_scte35))
+        return i_length <= SCTE35_INSERT_HEADER_SIZE;
+    if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE)
+        return false;
+
+    if (scte35_insert_has_program_splice(p_scte35)) {
+        if (scte35_insert_has_splice_immediate(p_scte35)) {
+            if (scte35_insert_has_duration(p_scte35))
+                return i_length >= SCTE35_INSERT_HEADER_SIZE +
+                                   SCTE35_INSERT_HEADER2_SIZE +
+                                   SCTE35_BREAK_DURATION_HEADER_SIZE +
+                                   SCTE35_INSERT_FOOTER_SIZE;
+            return i_length >= SCTE35_INSERT_HEADER_SIZE +
+                               SCTE35_INSERT_HEADER2_SIZE +
+                               SCTE35_INSERT_FOOTER_SIZE;
+        }
+
+        if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
+                       SCTE35_SPLICE_TIME_HEADER_SIZE ||
+            i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
+                       scte35_splice_time_size(
+                           scte35_insert_get_splice_time(p_scte35)))
+            return false;
+
+        if (scte35_insert_has_duration(p_scte35))
+            return i_length >= SCTE35_INSERT_HEADER_SIZE +
+                SCTE35_INSERT_HEADER2_SIZE +
+                scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
+                + SCTE35_BREAK_DURATION_HEADER_SIZE +
+                SCTE35_INSERT_FOOTER_SIZE;
+        return i_length >= SCTE35_INSERT_HEADER_SIZE +
+            SCTE35_INSERT_HEADER2_SIZE +
+            scte35_splice_time_size(scte35_insert_get_splice_time(p_scte35))
+            + SCTE35_INSERT_FOOTER_SIZE;
+    }
+
+    if (i_length < SCTE35_INSERT_HEADER_SIZE + SCTE35_INSERT_HEADER2_SIZE +
+                   SCTE35_INSERT_COMPONENT_COUNT_SIZE)
+        return false;
+
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    const uint8_t *p_end = scte35_insert_get_component(p_scte35,
+            scte35_insert_get_component_count(p_scte35) + 1);
+    if (p_end == NULL)
+        return false;
+
+    if (scte35_insert_has_duration(p_scte35))
+        return i_length >= p_end + SCTE35_BREAK_DURATION_HEADER_SIZE +
+                                   SCTE35_INSERT_FOOTER_SIZE - p_command;
+    return i_length >= p_end + SCTE35_INSERT_FOOTER_SIZE - p_command;
+}
+
+/*****************************************************************************
+ * Splice Information Table - time_signal command
+ *****************************************************************************/
+#define SCTE35_TIME_SIGNAL_COMMAND              6
+#define SCTE35_TIME_SIGNAL_HEADER_SIZE          SCTE35_SPLICE_TIME_HEADER_SIZE
+#define SCTE35_TIME_SIGNAL_TIME_SIZE            SCTE35_SPLICE_TIME_TIME_SIZE
+
+static inline void scte35_time_signal_init(uint8_t *p_scte35, uint16_t i_length)
+{
+    scte35_init(p_scte35);
+    scte35_set_command_type(p_scte35, SCTE35_TIME_SIGNAL_COMMAND);
+    scte35_set_command_length(p_scte35,
+                              SCTE35_TIME_SIGNAL_HEADER_SIZE + i_length);
+    scte35_set_desclength(p_scte35, 0);
+}
+
+static inline uint8_t *scte35_time_signal_get_splice_time(const uint8_t *p_scte35)
+{
+    return scte35_get_command(p_scte35);
+}
+
+static inline bool scte35_time_signal_validate(const uint8_t *p_scte35)
+{
+    return scte35_get_command_length(p_scte35) >=
+        scte35_splice_time_size(scte35_time_signal_get_splice_time(p_scte35));
+}
+
+/*****************************************************************************
+ * Splice Information Table - bandwidth_reservation command
+ *****************************************************************************/
+#define SCTE35_BANDWIDTH_RESERVATION_COMMAND        7
+#define SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE    0
+
+static inline void scte35_bandwidth_reservation_init(uint8_t *p_scte35)
+{
+    scte35_init(p_scte35);
+    scte35_set_command_type(p_scte35, SCTE35_BANDWIDTH_RESERVATION_COMMAND);
+    scte35_set_command_length(p_scte35,
+                              SCTE35_BANDWIDTH_RESERVATION_HEADER_SIZE);
+    scte35_set_desclength(p_scte35, 0);
+}
+
+static inline bool scte35_bandwidth_reservation_validate(const uint8_t *p_scte35)
+{
+    return true;
+}
+
+/*****************************************************************************
+ * Splice Information Table - private command
+ *****************************************************************************/
+#define SCTE35_PRIVATE_COMMAND                      0xff
+#define SCTE35_PRIVATE_HEADER_SIZE                  4
+
+static inline void scte35_private_init(uint8_t *p_scte35, uint16_t i_length)
+{
+    scte35_init(p_scte35);
+    scte35_set_command_type(p_scte35, SCTE35_PRIVATE_COMMAND);
+    scte35_set_command_length(p_scte35,
+                              SCTE35_PRIVATE_HEADER_SIZE + i_length);
+    scte35_set_desclength(p_scte35, 0);
+}
+
+static inline uint32_t scte35_private_get_identifier(const uint8_t *p_scte35)
+{
+    const uint8_t *p_command = scte35_get_command(p_scte35);
+    return ((uint32_t)p_command[0] << 24) | (p_command[1] << 16) |
+           (p_command[2] << 8) | p_command[3];
+}
+
+static inline void scte35_private_set_identifier(uint8_t *p_scte35,
+                                                 uint32_t i_identifier)
+{
+    uint8_t *p_command = scte35_get_command(p_scte35);
+    p_command[0] = (i_identifier >> 24) & 0xff;
+    p_command[1] = (i_identifier >> 16) & 0xff;
+    p_command[2] = (i_identifier >> 8) & 0xff;
+    p_command[3] = i_identifier & 0xff;
+}
+
+static inline bool scte35_private_validate(const uint8_t *p_scte35)
+{
+    return scte35_get_command_length(p_scte35) >= SCTE35_PRIVATE_HEADER_SIZE;
+}
+
+/*****************************************************************************
+ * Splice Information Table validation
+ *****************************************************************************/
+static inline bool scte35_validate(const uint8_t *p_scte35)
+{
+    if (psi_get_syntax(p_scte35) ||
+        psi_get_tableid(p_scte35) != SCTE35_TABLE_ID)
+        return false;
+
+    if (!psi_check_crc(p_scte35))
+        return false;
+    if (scte35_get_protocol(p_scte35))
+        return false;
+
+    uint16_t i_section_size = psi_get_length(p_scte35) + PSI_HEADER_SIZE
+                               - PSI_CRC_SIZE;
+    if (i_section_size < SCTE35_HEADER_SIZE)
+        return false;
+
+    uint16_t i_command_length = scte35_get_command_length(p_scte35);
+    if (i_command_length != 0xfff &&
+        (i_section_size < SCTE35_HEADER_SIZE + i_command_length +
+                          SCTE35_HEADER2_SIZE ||
+         i_section_size < SCTE35_HEADER_SIZE + i_command_length +
+                          SCTE35_HEADER2_SIZE +
+                          scte35_get_desclength(p_scte35)))
+        return false;
+
+    switch (scte35_get_command_type(p_scte35)) {
+        case SCTE35_NULL_COMMAND:
+            if (!scte35_null_validate(p_scte35))
+                return false;
+            break;
+        case SCTE35_INSERT_COMMAND:
+            if (!scte35_insert_validate(p_scte35))
+                return false;
+            break;
+        case SCTE35_TIME_SIGNAL_COMMAND:
+            if (!scte35_time_signal_validate(p_scte35))
+                return false;
+            break;
+        case SCTE35_BANDWIDTH_RESERVATION_COMMAND:
+            if (!scte35_bandwidth_reservation_validate(p_scte35))
+                return false;
+            break;
+        case SCTE35_PRIVATE_COMMAND:
+            if (!scte35_private_validate(p_scte35))
+                return false;
+            break;
+        default:
+            break;
+    }
+
+    if (i_command_length != 0xfff &&
+        !descl_validate(scte35_get_descl(p_scte35),
+                        scte35_get_desclength(p_scte35)))
+        return false;
+
+    return true;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/scte/35_print.h b/scte/35_print.h
new file mode 100644
index 0000000..e8324fc
--- /dev/null
+++ b/scte/35_print.h
@@ -0,0 +1,296 @@
+/*****************************************************************************
+ * 35_print.h: SCTE 35 Digital Program Insertion Cueing Message for Cable
+ * (printing)
+ *****************************************************************************
+ * Copyright (C) 2015 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot at via.ecp.fr>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+#ifndef __BITSTREAM_SCTE_35_PRINT_H__
+#define __BITSTREAM_SCTE_35_PRINT_H__
+
+#include <bitstream/common.h>
+#include <bitstream/mpeg/psi/psi.h>
+#include <bitstream/mpeg/psi/descs_print.h>
+#include <bitstream/scte/35.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+ * Splice Information Table
+ *****************************************************************************/
+static inline const char *scte35_get_command_type_txt(uint8_t i_type) {
+    switch (i_type) {
+        case SCTE35_NULL_COMMAND: return "null";
+        case SCTE35_SCHEDULE_COMMAND: return "schedule";
+        case SCTE35_INSERT_COMMAND: return "insert";
+        case SCTE35_TIME_SIGNAL_COMMAND: return "time_signal";
+        case SCTE35_BANDWIDTH_RESERVATION_COMMAND: return "bandwidth_reservation";
+        case SCTE35_PRIVATE_COMMAND: return "private";
+        default: return "reserved";
+    }
+}
+
+static inline void scte35_null_print(const uint8_t *p_scte35,
+        f_print pf_print, void *print_opaque, print_type_t i_print_type)
+{
+    uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque,
+                 "<SCTE35 command=\"%"PRIu8"\" command_str=\"null\" pts_adjustment=\"%"PRIu64"\">",
+                 SCTE35_NULL_COMMAND, i_pts_adjustment);
+        break;
+    default:
+        pf_print(print_opaque,
+                 "new SCTE35 command=%"PRIu8" command_str=null pts_adjustment=%"PRIu64,
+                 SCTE35_NULL_COMMAND, i_pts_adjustment);
+    }
+}
+
+static inline void scte35_insert_print(const uint8_t *p_scte35,
+        f_print pf_print, void *print_opaque, print_type_t i_print_type)
+{
+    uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
+    uint32_t i_event_id = scte35_insert_get_event_id(p_scte35);
+
+    if (scte35_insert_has_cancel(p_scte35)) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque,
+                     "<SCTE35 command=\"%"PRIu8"\" command_str=\"insert\" pts_adjustment=\"%"PRIu64"\" event_id=\"%"PRIu32"\" cancel=\"1\">",
+                     SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id);
+            break;
+        default:
+            pf_print(print_opaque,
+                     "new SCTE35 command=%"PRIu8" command_str=insert pts_adjustment=%"PRIu64" event_id=%"PRIu32" cancel=true",
+                     SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id);
+        }
+        return;
+    }
+
+    bool b_out_of_network = scte35_insert_has_out_of_network(p_scte35);
+    bool b_program_splice = scte35_insert_has_program_splice(p_scte35);
+    bool b_duration = scte35_insert_has_duration(p_scte35);
+    bool b_splice_immediate = scte35_insert_has_splice_immediate(p_scte35);
+    uint16_t i_unique_program_id = scte35_insert_get_unique_program_id(p_scte35);
+
+    char psz_duration[256];
+    psz_duration[0] = '\0';
+    psz_duration[255] = '\0';
+    if (b_duration) {
+        const uint8_t *p_break_duration =
+            scte35_insert_get_break_duration(p_scte35);
+        bool b_auto_return =
+            scte35_break_duration_has_auto_return(p_break_duration);
+        uint64_t i_duration =
+            scte35_break_duration_get_duration(p_break_duration);
+
+        switch (i_print_type) {
+        case PRINT_XML:
+            snprintf(psz_duration, 255,
+                     " auto_return=\"%d\" duration=\"%"PRIu64"\"",
+                     b_auto_return ? 1 : 0, i_duration);
+            break;
+        default:
+            snprintf(psz_duration, 255,
+                     " auto_return=%s duration=%"PRIu64"",
+                     b_auto_return ? "true" : "false", i_duration);
+        }
+    }
+
+    char psz_splice_time[256];
+    psz_splice_time[0] = '\0';
+    psz_splice_time[255] = '\0';
+    if (b_splice_immediate) {
+        switch (i_print_type) {
+        case PRINT_XML:
+            snprintf(psz_splice_time, 255, " splice_time=\"immediate\"");
+            break;
+        default:
+            snprintf(psz_splice_time, 255, " splice_time=immediate");
+        }
+    } else {
+        const uint8_t *p_splice_time = NULL;
+        if (b_program_splice)
+            p_splice_time = scte35_insert_get_splice_time(p_scte35);
+        else if (scte35_insert_get_component_count(p_scte35))
+            p_splice_time = scte35_insert_component_get_splice_time(
+                    scte35_insert_get_component(p_scte35, 0));
+
+        if (p_splice_time == NULL ||
+            !scte35_splice_time_has_time_specified(p_splice_time)) {
+            switch (i_print_type) {
+            case PRINT_XML:
+                snprintf(psz_splice_time, 255, " splice_time=\"undefined\"");
+                break;
+            default:
+                snprintf(psz_splice_time, 255, " splice_time=undefined");
+            }
+        } else {
+            uint64_t i_pts_time =
+                scte35_splice_time_get_pts_time(p_splice_time);
+
+            switch (i_print_type) {
+            case PRINT_XML:
+                snprintf(psz_splice_time, 255, " splice_time=\"%"PRIu64"\"",
+                         i_pts_time);
+                break;
+            default:
+                snprintf(psz_splice_time, 255, " splice_time=%"PRIu64"",
+                         i_pts_time);
+            }
+        }
+    }
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque,
+                 "<SCTE35 command=\"%"PRIu8"\" command_str=\"insert\" pts_adjustment=\"%"PRIu64"\" event_id=\"%"PRIu32"\" cancel=\"0\" out_of_network=\"%d\" program_splice=\"%d\"%s%s unique_program_id=\"%"PRIu16"\">",
+                 SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id,
+                 b_out_of_network ? 1 : 0, b_program_splice ? 1 : 0,
+                 psz_splice_time, psz_duration, i_unique_program_id);
+        break;
+    default:
+        pf_print(print_opaque,
+                 "new SCTE35 command=%"PRIu8" command_str=insert pts_adjustment=%"PRIu64" event_id=%"PRIu32" cancel=false out_of_network=%s program_splice=%s%s%s unique_program_id=%"PRIu16,
+                 SCTE35_INSERT_COMMAND, i_pts_adjustment, i_event_id,
+                 b_out_of_network ? "true" : "false",
+                 b_program_splice ? "true" : "false",
+                 psz_splice_time, psz_duration, i_unique_program_id);
+    }
+}
+
+static inline void scte35_time_signal_print(const uint8_t *p_scte35,
+        f_print pf_print, void *print_opaque, print_type_t i_print_type)
+{
+    uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
+    const uint8_t *p_splice_time = scte35_time_signal_get_splice_time(p_scte35);
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        if (scte35_splice_time_has_time_specified(p_splice_time))
+            pf_print(print_opaque,
+                     "<SCTE35 command=\"%"PRIu8"\" command_str=\"time_signal\" pts_adjustment=\"%"PRIu64"\" splice_time=\"%"PRIu64"\">",
+                     SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment,
+                     scte35_splice_time_get_pts_time(p_splice_time));
+        else
+            pf_print(print_opaque,
+                     "<SCTE35 command=\"%"PRIu8"\" command_str=\"time_signal\" pts_adjustment=\"%"PRIu64"\" splice_time=\"undefined\">",
+                     SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment);
+        break;
+    default:
+        if (scte35_splice_time_has_time_specified(p_splice_time))
+            pf_print(print_opaque,
+                     "new SCTE35 command=%"PRIu8" command_str=time_signal pts_adjustment=%"PRIu64" splice_time=%"PRIu64,
+                     SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment,
+                     scte35_splice_time_get_pts_time(p_splice_time));
+        else
+            pf_print(print_opaque,
+                     "new SCTE35 command=%"PRIu8" command_str=time_signal pts_adjustment=%"PRIu64" splice_time=undefined",
+                     SCTE35_TIME_SIGNAL_COMMAND, i_pts_adjustment);
+    }
+}
+
+static inline void scte35_private_print(const uint8_t *p_scte35,
+        f_print pf_print, void *print_opaque, print_type_t i_print_type)
+{
+    uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
+    uint32_t i_identifier = scte35_private_get_identifier(p_scte35);
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque,
+                 "<SCTE35 command=\"%"PRIu8"\" command_str=\"private\" pts_adjustment=\"%"PRIu64"\" identifier=\"%"PRIu32"\" />",
+                 SCTE35_PRIVATE_COMMAND, i_pts_adjustment, i_identifier);
+        break;
+    default:
+        pf_print(print_opaque,
+                 "new SCTE35 command=%"PRIu8" command_str=private pts_adjustment=%"PRIu64" identifier=%"PRIu32,
+                 SCTE35_PRIVATE_COMMAND, i_pts_adjustment, i_identifier);
+    }
+}
+
+static inline void scte35_print(const uint8_t *p_scte35,
+        f_print pf_print, void *print_opaque, print_type_t i_print_type)
+{
+    uint8_t i_type = scte35_get_command_type(p_scte35);
+    bool done = false;
+
+    switch (i_type) {
+    case SCTE35_NULL_COMMAND:
+        scte35_null_print(p_scte35, pf_print, print_opaque, i_print_type);
+        done = true;
+        break;
+    case SCTE35_INSERT_COMMAND:
+        scte35_insert_print(p_scte35, pf_print, print_opaque, i_print_type);
+        done = true;
+        break;
+    case SCTE35_TIME_SIGNAL_COMMAND:
+        scte35_time_signal_print(p_scte35, pf_print, print_opaque, i_print_type);
+        done = true;
+        break;
+    case SCTE35_PRIVATE_COMMAND:
+        scte35_private_print(p_scte35, pf_print, print_opaque, i_print_type);
+        done = true;
+        break;
+    default:
+        break;
+    }
+
+    if (!done) {
+        uint64_t i_pts_adjustment = scte35_get_pts_adjustment(p_scte35);
+
+        switch (i_print_type) {
+        case PRINT_XML:
+            pf_print(print_opaque,
+                     "<SCTE35 command=\"%"PRIu8"\" command_str=\"%s\" pts_adjustment=\"%"PRIu64"\">",
+                     i_type, scte35_get_command_type_txt(i_type), i_pts_adjustment);
+            break;
+        default:
+            pf_print(print_opaque,
+                     "new SCTE35 command=%"PRIu8" command_str=%s pts_adjustment=%"PRIu64,
+                     i_type, scte35_get_command_type_txt(i_type), i_pts_adjustment);
+        }
+    }
+
+    /* TODO: print descriptors */
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(print_opaque, "</SCTE35>");
+        break;
+    default:
+        pf_print(print_opaque, "end SCTE35");
+    }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/smpte/2022_1_fec.h b/smpte/2022_1_fec.h
new file mode 100644
index 0000000..dc10e27
--- /dev/null
+++ b/smpte/2022_1_fec.h
@@ -0,0 +1,157 @@
+/*****************************************************************************
+ * 2022_1_fec.h
+ *****************************************************************************
+ * Copyright (C) 2014 Open Broadcast Systems Ltd
+ *
+ * Authors: Kieran Kunhya <kierank at obe.tv
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*
+ * Normative references:
+ *  - SMPTE 2022-1
+ */
+
+#ifndef __BITSTREAM_SMPTE_2022_1_FEC_H__
+#define __BITSTREAM_SMPTE_2022_1_FEC_H__
+
+#include <stdint.h>   /* uint8_t, uint16_t, etc... */
+#include <stdbool.h>  /* bool */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * Reminder : FEC Header
+    0               1               2               3
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |       SNBase low bits         |      Length Recovery          |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |E| PT recovery |                     Mask                      |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                         TS recovery                           |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |N|D|type |index|     Offset    |       NA      |SNBase ext bits|
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+static inline void smpte_fec_set_snbase_low(uint8_t *p_fec, uint16_t snbase_low)
+{
+    p_fec[0] = snbase_low >> 8;
+    p_fec[1] = snbase_low & 0xff;
+}
+
+static inline uint16_t smpte_fec_get_snbase_low(const uint8_t *p_fec)
+{
+    return (p_fec[0] << 8) | p_fec[1];
+}
+
+static inline void smpte_fec_set_length_rec(uint8_t *p_fec, uint16_t length_rec)
+{
+    p_fec[2] = length_rec >> 8;
+    p_fec[3] = length_rec & 0xff;
+}
+
+static inline uint16_t smpte_fec_get_length_rec(const uint8_t *p_fec)
+{
+    return (p_fec[2] << 8) | p_fec[3];
+}
+
+static inline void smpte_fec_set_extension(uint8_t *p_fec)
+{
+    p_fec[4] |= 0x80;
+}
+
+static inline bool smpte_fec_check_extension(const uint8_t *p_fec)
+{
+    return !!(p_fec[4] & 0x80);
+}
+
+static inline void smpte_fec_set_pt_recovery(uint8_t *p_fec, uint8_t pt_recovery)
+{
+    p_fec[4] |= pt_recovery & 0x7f;
+}
+
+static inline uint8_t smpte_fec_get_pt_recovery(const uint8_t *p_fec)
+{
+    return p_fec[4] & 0x7f;
+}
+
+static inline void smpte_fec_set_ts_recovery(uint8_t *p_fec, uint32_t snbase)
+{
+    p_fec[8] =  snbase >> 24;
+    p_fec[9] =  snbase >> 16;
+    p_fec[10] = snbase >> 8;
+    p_fec[11] = snbase & 0xff;
+}
+
+static inline uint32_t smpte_fec_get_ts_recovery(const uint8_t *p_fec)
+{
+    return (p_fec[8] << 24) | (p_fec[9] << 16) | (p_fec[10] << 8) | p_fec[11];
+}
+
+static inline void smpte_fec_set_d(uint8_t *p_fec)
+{
+    p_fec[12] |= 0x40;
+}
+
+static inline bool smpte_fec_check_d(const uint8_t *p_fec)
+{
+    return !!(p_fec[12] & 0x40);
+}
+
+static inline void smpte_fec_set_offset(uint8_t *p_fec, uint8_t offset)
+{
+    p_fec[13] = offset;
+}
+
+static inline uint8_t smpte_fec_get_offset(const uint8_t *p_fec)
+{
+    return p_fec[13];
+}
+
+static inline void smpte_fec_set_na(uint8_t *p_fec, uint8_t na)
+{
+    p_fec[14] = na;
+}
+
+static inline uint8_t smpte_fec_get_na(const uint8_t *p_fec)
+{
+    return p_fec[14];
+}
+
+static inline void smpte_fec_set_snbase_ext(uint8_t *p_fec, uint8_t snbase_ext)
+{
+    p_fec[15] = snbase_ext;
+}
+
+static inline uint8_t smpte_fec_get_snbase_ext(const uint8_t *p_fec)
+{
+    return p_fec[15];
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

-- 
bitstream packaging



More information about the pkg-multimedia-commits mailing list