summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <thibault.saunier@collabora.com>2011-07-29 10:56:15 +0200
committerThibault Saunier <thibault.saunier@collabora.com>2011-08-31 09:15:46 -0300
commitf6e8467111e96291dc764927e383cec2076bf871 (patch)
treec44fc5a1010ce135ff350282187d9bf35fe658a3
parentad7028d1ddc567ed52634eb80966e22a29384ca7 (diff)
codecparsers: h264: Add an h.264 bitstream parsing library
-rw-r--r--docs/libs/gst-plugins-bad-libs-docs.sgml1
-rw-r--r--docs/libs/gst-plugins-bad-libs-sections.txt44
-rw-r--r--docs/libs/gst-plugins-bad-libs.types1
-rw-r--r--gst-libs/gst/codecparsers/Makefile.am5
-rw-r--r--gst-libs/gst/codecparsers/gsth264parser.c1808
-rw-r--r--gst-libs/gst/codecparsers/gsth264parser.h657
-rw-r--r--tests/check/Makefile.am10
-rw-r--r--tests/check/libs/h264parser.c182
8 files changed, 2706 insertions, 2 deletions
diff --git a/docs/libs/gst-plugins-bad-libs-docs.sgml b/docs/libs/gst-plugins-bad-libs-docs.sgml
index d1113bca3..b31d6414e 100644
--- a/docs/libs/gst-plugins-bad-libs-docs.sgml
+++ b/docs/libs/gst-plugins-bad-libs-docs.sgml
@@ -28,6 +28,7 @@
<filename>gstreamer-plugins-bad-&GST_MAJORMINOR;.pc</filename> and adding
<filename>-lgscodeparsers-&GST_MAJORMINOR;</filename> to the library flags.
</para>
+ <xi:include href="xml/gsth264parser.xml" />
<xi:include href="xml/gstmpegvideoparser.xml" />
</chapter>
</part>
diff --git a/docs/libs/gst-plugins-bad-libs-sections.txt b/docs/libs/gst-plugins-bad-libs-sections.txt
index a09929c04..251d453cc 100644
--- a/docs/libs/gst-plugins-bad-libs-sections.txt
+++ b/docs/libs/gst-plugins-bad-libs-sections.txt
@@ -1,5 +1,49 @@
# codecparsers
<SECTION>
+<FILE>gsth264parser</FILE>
+<TITLE>h264parser</TITLE>
+<INCLUDE>gst/codecparsers/gsth264parser.h</INCLUDE>
+GST_H264_MAX_SPS_COUNT
+GST_H264_MAX_PPS_COUNT
+GST_H264_IS_P_SLICE
+GST_H264_IS_B_SLICE
+GST_H264_IS_I_SLICE
+GST_H264_IS_SP_SLICE
+GST_H264_IS_SI_SLICE
+GstH264NalUnitType
+GstH264ParserResult
+GstH264SEIPayloadType
+GstH264SEIPicStructType
+GstH264SliceType
+GstH264NalParser
+GstH264NalUnit
+GstH264SPS
+GstH264PPS
+GstH264HRDParams
+GstH264VUIParams
+GstH264DecRefPicMarking
+GstH264RefPicMarking
+GstH264PredWeightTable
+GstH264SliceHdr
+GstH264ClockTimestamp
+GstH264PicTiming
+GstH264BufferingPeriod
+GstH264SEIMessage
+gst_h264_parser_identify_nalu
+gst_h264_parser_identify_nalu_avc
+gst_h264_parser_parse_nal
+gst_h264_parser_parse_slice_hdr
+gst_h264_parser_parse_sps
+gst_h264_parser_parse_pps
+gst_h264_parser_parse_sei
+gst_h264_nal_parser_new
+gst_h264_parse_sps
+gst_h264_parse_pps
+<SUBSECTION Standard>
+<SUBSECTION Private>
+</SECTION>
+
+<SECTION>
<FILE>gstmpegvideoparser</FILE>
<TITLE>mpegvideoparser</TITLE>
<INCLUDE>gst/codecparsers/gstmpegvideoparser.h</INCLUDE>
diff --git a/docs/libs/gst-plugins-bad-libs.types b/docs/libs/gst-plugins-bad-libs.types
index 4ca1a2b46..493215718 100644
--- a/docs/libs/gst-plugins-bad-libs.types
+++ b/docs/libs/gst-plugins-bad-libs.types
@@ -1,3 +1,4 @@
#include <gst/gst.h>
+#include <gst/codecparsers/gsth264parser.h>
#include <gst/codecparsers/gstmpegvideoparser.h>
diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am
index 86a7b16d9..7fa44f158 100644
--- a/gst-libs/gst/codecparsers/Makefile.am
+++ b/gst-libs/gst/codecparsers/Makefile.am
@@ -1,12 +1,13 @@
lib_LTLIBRARIES = libgstcodecparsers-@GST_MAJORMINOR@.la
-libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = gstmpegvideoparser.c
+libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = \
+ gstmpegvideoparser.c gsth264parser.c
libgstcodecparsers_@GST_MAJORMINOR@includedir = \
$(includedir)/gstreamer-@GST_MAJORMINOR@/gst/codecparsers
libgstcodecparsers_@GST_MAJORMINOR@include_HEADERS = \
- gstmpegvideoparser.h
+ gstmpegvideoparser.h gsth264parser.h
libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS)
libgstcodecparsers_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c
new file mode 100644
index 000000000..bdd2899bd
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gsth264parser.c
@@ -0,0 +1,1808 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c:
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * (C) 2005 Michal Benes <michal.benes@itonis.tv>
+ * (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gsth264parser
+ * @short_description: Convenience library for h264 video
+ * bitstream parsing.
+ *
+ * It offers you basic parsing in AVC mode or not. Tp identify Nals in a bitstream and
+ * parse its basic headers, you should call:
+ * <itemizedlist>
+ * <listitem>
+ * gst_h264_parser_identify_nalu to identify the following nalu in not AVC bitstreams
+ * </listitem>
+ * <listitem>
+ * gst_h264_parser_identify_nalu_avc to identify the following nalu in AVC bitstreams
+ * </listitem>
+ * </itemizedlist>
+ *
+ * Then, depending on the #GstH264NalUnitType of the newly parsed #GstH264NalUnit, you should
+ * call the differents functions to parse the struct.
+ *
+ * Note: You should always call gst_h264_parser_parse_nal if you don't actually need
+ * #GstH264NalUnitType to be parsed for your personnal use. This, to guarantee that the
+ * #GstH264NalParser is always up to date.
+ *
+ * For more details about the structures, look at the ISO specifications.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gsth264parser.h"
+
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbitreader.h>
+#include <string.h>
+
+GST_DEBUG_CATEGORY (h264_parser_debug);
+#define GST_CAT_DEFAULT h264_parser_debug
+
+/**** Default scaling_lists according to Table 7-2 *****/
+const guint8 default_4x4_intra[16] = {
+ 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32,
+ 32, 37, 37, 42
+};
+
+const guint8 default_4x4_inter[16] = {
+ 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27,
+ 27, 30, 30, 34
+};
+
+const guint8 default_8x8_intra[64] = {
+ 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18,
+ 18, 18, 18, 23, 23, 23, 23, 23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27,
+ 27, 27, 27, 27, 27, 29, 29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33,
+ 33, 33, 33, 33, 36, 36, 36, 36, 38, 38, 38, 40, 40, 42
+};
+
+const guint8 default_8x8_inter[64] = {
+ 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19,
+ 19, 19, 19, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24,
+ 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28,
+ 28, 28, 28, 28, 30, 30, 30, 30, 32, 32, 32, 33, 33, 35
+};
+
+const guint8 zigzag_8x8[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+const guint8 zigzag_4x4[16] = {
+ 0, 1, 4, 8,
+ 5, 2, 3, 6,
+ 9, 12, 13, 10,
+ 7, 11, 14, 15,
+};
+
+/****** Nal parser ******/
+
+typedef struct
+{
+ const guint8 *data;
+ guint size;
+
+ guint byte; /* Byte position */
+ guint bits_in_cache; /* bitpos in the cache of next bit */
+ guint8 first_byte;
+ guint64 cache; /* cached bytes */
+} NalReader;
+
+static void
+nal_reader_init (NalReader * nr, const guint8 * data, guint size)
+{
+ nr->data = data;
+ nr->size = size;
+
+ nr->byte = 0;
+ nr->bits_in_cache = 0;
+ /* fill with something other than 0 to detect emulation prevention bytes */
+ nr->first_byte = 0xff;
+ nr->cache = 0xff;
+}
+
+static gboolean
+nal_reader_read (NalReader * nr, guint nbits)
+{
+ if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) {
+ GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in "
+ "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8);
+ return FALSE;
+ }
+
+ while (nr->bits_in_cache < nbits) {
+ guint8 byte;
+ gboolean check_three_byte;
+
+ check_three_byte = TRUE;
+ next_byte:
+ if (G_UNLIKELY (nr->byte >= nr->size))
+ return FALSE;
+
+ byte = nr->data[nr->byte++];
+
+ /* check if the byte is a emulation_prevention_three_byte */
+ if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 &&
+ ((nr->cache & 0xff) == 0)) {
+ /* next byte goes unconditionally to the cache, even if it's 0x03 */
+ check_three_byte = FALSE;
+ goto next_byte;
+ }
+ nr->cache = (nr->cache << 8) | nr->first_byte;
+ nr->first_byte = byte;
+ nr->bits_in_cache += 8;
+ }
+
+ return TRUE;
+}
+
+static inline gboolean
+nal_reader_skip (NalReader * nr, guint nbits)
+{
+ g_return_val_if_fail (nr != NULL, FALSE);
+
+ if (G_UNLIKELY (!nal_reader_read (nr, nbits)))
+ return FALSE;
+
+ nr->bits_in_cache -= nbits;
+
+ return TRUE;
+}
+
+static inline gboolean
+nal_reader_skip_to_byte (NalReader * nr)
+{
+ g_return_val_if_fail (nr != NULL, FALSE);
+
+ if (nr->bits_in_cache == 0) {
+ if (G_LIKELY ((nr->size - nr->byte) > 0))
+ nr->byte++;
+ else
+ return FALSE;
+ }
+
+ nr->bits_in_cache = 0;
+
+ return TRUE;
+}
+
+static inline guint
+nal_reader_get_pos (const NalReader * nr)
+{
+ return nr->byte * 8 - nr->bits_in_cache;
+}
+
+static inline guint
+nal_reader_get_remaining (const NalReader * nr)
+{
+ return (nr->size - nr->byte) * 8 + nr->bits_in_cache;
+}
+
+#define GST_NAL_READER_READ_BITS(bits) \
+static gboolean \
+nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \
+{ \
+ guint shift; \
+ \
+ g_return_val_if_fail (nr != NULL, FALSE); \
+ g_return_val_if_fail (val != NULL, FALSE); \
+ g_return_val_if_fail (nbits <= bits, FALSE); \
+ \
+ if (!nal_reader_read (nr, nbits)) \
+ return FALSE; \
+ \
+ /* bring the required bits down and truncate */ \
+ shift = nr->bits_in_cache - nbits; \
+ *val = nr->first_byte >> shift; \
+ \
+ *val |= nr->cache << (8 - shift); \
+ /* mask out required bits */ \
+ if (nbits < bits) \
+ *val &= ((guint##bits)1 << nbits) - 1; \
+ \
+ nr->bits_in_cache = shift; \
+ \
+ return TRUE; \
+} \
+
+GST_NAL_READER_READ_BITS (8);
+GST_NAL_READER_READ_BITS (16);
+GST_NAL_READER_READ_BITS (32);
+
+#define GST_NAL_READER_PEAK_BITS(bits) \
+static gboolean \
+nal_reader_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) \
+{ \
+ NalReader tmp; \
+ \
+ g_return_val_if_fail (nr != NULL, FALSE); \
+ tmp = *nr; \
+ return nal_reader_get_bits_uint##bits (&tmp, val, nbits); \
+}
+
+GST_NAL_READER_PEAK_BITS (8);
+
+static gboolean
+nal_reader_get_ue (NalReader * nr, guint32 * val)
+{
+ guint i = 0;
+ guint8 bit;
+ guint32 value;
+
+ if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) {
+
+ return FALSE;
+ }
+
+ while (bit == 0) {
+ i++;
+ if G_UNLIKELY
+ ((!nal_reader_get_bits_uint8 (nr, &bit, 1)))
+ return FALSE;
+ }
+
+ g_return_val_if_fail (i <= 32, FALSE);
+
+ if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i)))
+ return FALSE;
+
+ *val = (1 << i) - 1 + value;
+
+ return TRUE;
+}
+
+static gboolean
+nal_reader_get_se (NalReader * nr, gint32 * val)
+{
+ guint32 value;
+
+ if (G_UNLIKELY (!nal_reader_get_ue (nr, &value)))
+ return FALSE;
+
+ if (value % 2)
+ *val = (value / 2) + 1;
+ else
+ *val = -(value / 2);
+
+ return TRUE;
+}
+
+#define CHECK_ALLOWED(val, min, max) { \
+ if (val < min || val > max) { \
+ GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \
+ val, min, max); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT8(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT16(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT32(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UINT64(nr, val, nbits) { \
+ if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \
+ GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+ goto error; \
+ } \
+}
+
+#define READ_UE(nr, val) { \
+ if (!nal_reader_get_ue (nr, &val)) { \
+ GST_WARNING ("failed to read UE"); \
+ goto error; \
+ } \
+}
+
+#define READ_UE_ALLOWED(nr, val, min, max) { \
+ guint32 tmp; \
+ READ_UE (nr, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+#define READ_SE(nr, val) { \
+ if (!nal_reader_get_se (nr, &val)) { \
+ GST_WARNING ("failed to read SE"); \
+ goto error; \
+ } \
+}
+
+#define READ_SE_ALLOWED(nr, val, min, max) { \
+ gint32 tmp; \
+ READ_SE (nr, tmp); \
+ CHECK_ALLOWED (tmp, min, max); \
+ val = tmp; \
+}
+
+/*********** end of nal parser ***************/
+
+/***** Utils ****/
+#define EXTENDED_SAR 255
+
+static GstH264SPS *
+gst_h264_parser_get_sps (GstH264NalParser * nalparser, guint8 sps_id)
+{
+ GstH264SPS *sps;
+
+ sps = &nalparser->sps[sps_id];
+
+ if (sps->valid)
+ return sps;
+
+ return NULL;
+}
+
+static GstH264PPS *
+gst_h264_parser_get_pps (GstH264NalParser * nalparser, guint8 pps_id)
+{
+ GstH264PPS *pps;
+
+ pps = &nalparser->pps[pps_id];
+
+ if (pps->valid)
+ return pps;
+
+ return NULL;
+}
+
+static inline void
+set_nalu_datas (GstH264NalUnit * nalu)
+{
+ guint8 *data = nalu->data + nalu->offset;
+
+ nalu->type = (data[0] & 0x1f);
+ nalu->ref_idc = (data[0] & 0x60) >> 5;
+ nalu->idr_pic_flag = (nalu->type == 5 ? 1 : 0);
+
+ GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc);
+}
+
+static inline gint
+scan_for_start_codes (const guint8 * data, guint size)
+{
+ GstByteReader br;
+ gst_byte_reader_init (&br, data, size);
+
+ /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
+ return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
+ 0, size);
+}
+
+static gboolean
+gst_h264_parser_more_data (NalReader * nr)
+{
+ guint remaining;
+
+ remaining = nal_reader_get_remaining (nr);
+ if (remaining == 0)
+ return FALSE;
+
+ if (remaining <= 8) {
+ guint8 rbsp_stop_one_bit;
+
+ if (!nal_reader_peek_bits_uint8 (nr, &rbsp_stop_one_bit, 1))
+ return FALSE;
+
+ if (rbsp_stop_one_bit == 1) {
+ guint8 zero_bits;
+
+ if (remaining == 1)
+ return FALSE;
+
+ if (!nal_reader_peek_bits_uint8 (nr, &zero_bits, remaining))
+ return FALSE;
+
+ if ((zero_bits - (1 << (remaining - 1))) == 0)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/****** Parsing functions *****/
+
+static gboolean
+gst_h264_parse_hrd_parameters (GstH264HRDParams * hrd, NalReader * nr)
+{
+ guint sched_sel_idx;
+
+ GST_DEBUG ("parsing \"HRD Parameters\"");
+
+ READ_UE_ALLOWED (nr, hrd->cpb_cnt_minus1, 0, 31);
+ READ_UINT8 (nr, hrd->bit_rate_scale, 4);
+ READ_UINT8 (nr, hrd->cpb_size_scale, 4);
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1; sched_sel_idx++) {
+ READ_UE (nr, hrd->bit_rate_value_minus1[sched_sel_idx]);
+ READ_UE (nr, hrd->cpb_size_value_minus1[sched_sel_idx]);
+ }
+
+ READ_UINT8 (nr, hrd->initial_cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->cpb_removal_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->dpb_output_delay_length_minus1, 5);
+ READ_UINT8 (nr, hrd->time_offset_length, 5);
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"HRD Parameters\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parse_vui_parameters (GstH264SPS * sps, NalReader * nr)
+{
+ GstH264VUIParams *vui = &sps->vui_parameters;
+
+ GST_DEBUG ("parsing \"VUI Parameters\"");
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ vui->aspect_ratio_idc = 0;
+ vui->video_format = 5;
+ vui->video_full_range_flag = 0;
+ vui->colour_primaries = 2;
+ vui->transfer_characteristics = 2;
+ vui->matrix_coefficients = 2;
+ vui->chroma_sample_loc_type_top_field = 0;
+ vui->chroma_sample_loc_type_bottom_field = 0;
+ vui->low_delay_hrd_flag = 0;
+
+ READ_UINT8 (nr, vui->aspect_ratio_info_present_flag, 1);
+ if (vui->aspect_ratio_info_present_flag) {
+ READ_UINT8 (nr, vui->aspect_ratio_idc, 8);
+ if (vui->aspect_ratio_idc == EXTENDED_SAR) {
+ READ_UINT16 (nr, vui->sar_width, 16);
+ READ_UINT16 (nr, vui->sar_height, 16);
+ }
+ }
+
+ READ_UINT8 (nr, vui->overscan_info_present_flag, 1);
+ if (vui->overscan_info_present_flag)
+ READ_UINT8 (nr, vui->overscan_appropriate_flag, 1);
+
+ READ_UINT8 (nr, vui->video_signal_type_present_flag, 1);
+ if (vui->video_signal_type_present_flag) {
+
+ READ_UINT8 (nr, vui->video_format, 3);
+ READ_UINT8 (nr, vui->video_full_range_flag, 1);
+ READ_UINT8 (nr, vui->colour_description_present_flag, 1);
+ if (vui->colour_description_present_flag) {
+ READ_UINT8 (nr, vui->colour_primaries, 8);
+ READ_UINT8 (nr, vui->transfer_characteristics, 8);
+ READ_UINT8 (nr, vui->matrix_coefficients, 8);
+ }
+ }
+
+ READ_UINT8 (nr, vui->chroma_loc_info_present_flag, 1);
+ if (vui->chroma_loc_info_present_flag) {
+ READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_top_field, 0, 5);
+ READ_UE_ALLOWED (nr, vui->chroma_sample_loc_type_bottom_field, 0, 5);
+ }
+
+ READ_UINT8 (nr, vui->timing_info_present_flag, 1);
+ if (vui->timing_info_present_flag) {
+ READ_UINT32 (nr, vui->num_units_in_tick, 32);
+ if (vui->num_units_in_tick == 0)
+ GST_WARNING ("num_units_in_tick = 0 detected in stream "
+ "(incompliant to H.264 E.2.1).");
+
+ READ_UINT32 (nr, vui->time_scale, 32);
+ if (vui->time_scale == 0)
+ GST_WARNING ("time_scale = 0 detected in stream "
+ "(incompliant to H.264 E.2.1).");
+
+ READ_UINT8 (nr, vui->fixed_frame_rate_flag, 1);
+ }
+
+ READ_UINT8 (nr, vui->nal_hrd_parameters_present_flag, 1);
+ if (vui->nal_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->nal_hrd_parameters, nr))
+ goto error;
+ }
+
+ READ_UINT8 (nr, vui->vcl_hrd_parameters_present_flag, 1);
+ if (vui->vcl_hrd_parameters_present_flag) {
+ if (!gst_h264_parse_hrd_parameters (&vui->vcl_hrd_parameters, nr))
+ goto error;
+ }
+
+ if (vui->nal_hrd_parameters_present_flag ||
+ vui->vcl_hrd_parameters_present_flag)
+ READ_UINT8 (nr, vui->low_delay_hrd_flag, 1);
+
+ READ_UINT8 (nr, vui->pic_struct_present_flag, 1);
+ READ_UINT8 (nr, vui->bitstream_restriction_flag, 1);
+ if (vui->bitstream_restriction_flag) {
+ READ_UINT8 (nr, vui->motion_vectors_over_pic_boundaries_flag, 1);
+ READ_UE (nr, vui->max_bytes_per_pic_denom);
+ READ_UE_ALLOWED (nr, vui->max_bits_per_mb_denom, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_horizontal, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_vertical, 0, 16);
+ READ_UE_ALLOWED (nr, vui->log2_max_mv_length_vertical, 0, 16);
+ READ_UE (nr, vui->num_reorder_frames);
+ READ_UE (nr, vui->max_dec_frame_buffering);
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"VUI Parameters\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_scaling_list (NalReader * nr,
+ guint8 scaling_lists_4x4[6][16], guint8 scaling_lists_8x8[6][64],
+ const guint8 fallback_4x4_inter[16], const guint8 fallback_4x4_intra[16],
+ const guint8 fallback_8x8_inter[64], const guint8 fallback_8x8_intra[64],
+ guint8 n_lists)
+{
+ guint i;
+
+ GST_DEBUG ("parsing scaling lists");
+
+ for (i = 0; i < 12; i++) {
+ gboolean use_default = FALSE;
+
+ if (i < n_lists) {
+ guint8 scaling_list_present_flag;
+
+ READ_UINT8 (nr, scaling_list_present_flag, 1);
+ if (scaling_list_present_flag) {
+ guint8 *scaling_list;
+ const guint8 *scan;
+ guint size;
+ guint j;
+ guint8 last_scale, next_scale;
+
+ if (i < 6) {
+ scaling_list = scaling_lists_4x4[i];
+ scan = zigzag_4x4;
+ size = 16;
+ } else {
+ scaling_list = scaling_lists_8x8[i - 6];
+ scan = zigzag_8x8;
+ size = 64;
+ }
+
+ last_scale = 8;
+ next_scale = 8;
+ for (j = 0; j < size; j++) {
+ if (next_scale != 0) {
+ gint32 delta_scale;
+
+ READ_SE (nr, delta_scale);
+ next_scale = (last_scale + delta_scale) & 0xff;
+ }
+ if (j == 0 && next_scale == 0) {
+ use_default = TRUE;
+ break;
+ }
+ last_scale = scaling_list[scan[j]] =
+ (next_scale == 0) ? last_scale : next_scale;
+ }
+ } else
+ use_default = TRUE;
+ } else
+ use_default = TRUE;
+
+ if (use_default) {
+ switch (i) {
+ case 0:
+ memcpy (scaling_lists_4x4[0], fallback_4x4_intra, 16);
+ break;
+ case 1:
+ memcpy (scaling_lists_4x4[1], scaling_lists_4x4[0], 16);
+ break;
+ case 2:
+ memcpy (scaling_lists_4x4[2], scaling_lists_4x4[1], 16);
+ break;
+ case 3:
+ memcpy (scaling_lists_4x4[3], fallback_4x4_inter, 16);
+ break;
+ case 4:
+ memcpy (scaling_lists_4x4[4], scaling_lists_4x4[3], 16);
+ break;
+ case 5:
+ memcpy (scaling_lists_4x4[5], scaling_lists_4x4[4], 16);
+ break;
+ case 6:
+ memcpy (scaling_lists_8x8[0], fallback_8x8_intra, 64);
+ break;
+ case 7:
+ memcpy (scaling_lists_8x8[1], fallback_8x8_inter, 64);
+ break;
+ case 8:
+ memcpy (scaling_lists_8x8[2], scaling_lists_8x8[0], 64);
+ break;
+ case 9:
+ memcpy (scaling_lists_8x8[3], scaling_lists_8x8[1], 64);
+ break;
+ case 10:
+ memcpy (scaling_lists_8x8[4], scaling_lists_8x8[2], 64);
+ break;
+ case 11:
+ memcpy (scaling_lists_8x8[5], scaling_lists_8x8[3], 64);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing scaling lists");
+ return FALSE;
+}
+
+static gboolean
+slice_parse_ref_pic_list_reordering (GstH264SliceHdr * slice, NalReader * nr)
+{
+ GST_DEBUG ("parsing \"Reference picture list reordering\"");
+
+ if (!(slice->type == GST_H264_I_SLICE) && !(slice->type == GST_H264_SI_SLICE)) {
+ guint8 ref_pic_list_reordering_flag_l0;
+ guint32 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (nr, ref_pic_list_reordering_flag_l0, 1);
+ if (ref_pic_list_reordering_flag_l0)
+ do {
+ READ_UE (nr, reordering_of_pic_nums_idc);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_pic_num_minus1 G_GNUC_UNUSED;
+
+ READ_UE_ALLOWED (nr, abs_diff_pic_num_minus1, 0,
+ slice->max_pic_num - 1);
+ } else if (reordering_of_pic_nums_idc == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (nr, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ if (slice->type == GST_H264_B_SLICE) {
+ guint8 ref_pic_list_reordering_flag_l1;
+ guint32 reordering_of_pic_nums_idc;
+
+ READ_UINT8 (nr, ref_pic_list_reordering_flag_l1, 1);
+ if (ref_pic_list_reordering_flag_l1)
+ do {
+ READ_UE (nr, reordering_of_pic_nums_idc);
+ if (reordering_of_pic_nums_idc == 0 || reordering_of_pic_nums_idc == 1) {
+ guint32 abs_diff_num_minus1;
+
+ READ_UE (nr, abs_diff_num_minus1);
+ } else if (reordering_of_pic_nums_idc == 2) {
+ guint32 long_term_pic_num;
+
+ READ_UE (nr, long_term_pic_num);
+ }
+ } while (reordering_of_pic_nums_idc != 3);
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Reference picture list reordering\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_dec_ref_pic_marking (GstH264SliceHdr * slice,
+ GstH264NalUnit * nalu, NalReader * nr)
+{
+ GstH264DecRefPicMarking *dec_ref_pic_m;
+
+ GST_DEBUG ("parsing \"Decoded reference picture marking\"");
+
+ dec_ref_pic_m = &slice->dec_ref_pic_marking;
+
+ if (nalu->idr_pic_flag) {
+ READ_UINT8 (nr, dec_ref_pic_m->no_output_of_prior_pics_flag, 1);
+ READ_UINT8 (nr, dec_ref_pic_m->long_term_reference_flag, 1);
+ } else {
+ READ_UINT8 (nr, dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag, 1);
+ if (dec_ref_pic_m->adaptive_ref_pic_marking_mode_flag) {
+ guint32 mem_mgmt_ctrl_op;
+ GstH264RefPicMarking *refpicmarking;
+
+ dec_ref_pic_m->n_ref_pic_marking = 0;
+ while (1) {
+ refpicmarking =
+ &dec_ref_pic_m->ref_pic_marking[dec_ref_pic_m->n_ref_pic_marking];
+
+ READ_UE (nr, mem_mgmt_ctrl_op);
+ if (mem_mgmt_ctrl_op == 0)
+ break;
+
+ refpicmarking->memory_management_control_operation = mem_mgmt_ctrl_op;
+
+ if (mem_mgmt_ctrl_op == 1 || mem_mgmt_ctrl_op == 3)
+ READ_UE (nr, refpicmarking->difference_of_pic_nums_minus1);
+
+ if (mem_mgmt_ctrl_op == 2)
+ READ_UE (nr, refpicmarking->long_term_pic_num);
+
+ if (mem_mgmt_ctrl_op == 3 || mem_mgmt_ctrl_op == 6)
+ READ_UE (nr, refpicmarking->long_term_frame_idx);
+
+ if (mem_mgmt_ctrl_op == 4)
+ READ_UE (nr, refpicmarking->max_long_term_frame_idx_plus1);
+
+ dec_ref_pic_m->n_ref_pic_marking++;
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Decoded reference picture marking\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_slice_parse_pred_weight_table (GstH264SliceHdr * slice,
+ NalReader * nr, guint8 chroma_array_type)
+{
+ GstH264PredWeightTable *p;
+ gint i;
+
+ GST_DEBUG ("parsing \"Prediction weight table\"");
+
+ p = &slice->pred_weight_table;
+
+ READ_UE_ALLOWED (nr, p->luma_log2_weight_denom, 0, 7);
+ /* set default values */
+ default_luma_weight = 1 << p->luma_log2_weight_denom;
+ for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l0); i++)
+ p->luma_weight_l0[i] = default_luma_weight;
+ memset (p->luma_offset_l0, 0, sizeof (p->luma_offset_l0));
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i < G_N_ELEMENTS (p->luma_weight_l1); i++)
+ p->luma_weight_l1[i] = default_luma_weight;
+ memset (p->luma_offset_l1, 0, sizeof (p->luma_offset_l1));
+ }
+
+ if (chroma_array_type != 0) {
+ READ_UE_ALLOWED (nr, p->chroma_log2_weight_denom, 0, 7);
+ /* set default values */
+ default_chroma_weight = 1 << p->chroma_log2_weight_denom;
+ for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l0); i++) {
+ p->chroma_weight_l0[i][0] = default_chroma_weight;
+ p->chroma_weight_l0[i][1] = default_chroma_weight;
+ }
+ memset (p->chroma_offset_l0, 0, sizeof (p->chroma_offset_l0));
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i < G_N_ELEMENTS (p->chroma_weight_l1); i++) {
+ p->chroma_weight_l1[i][0] = default_chroma_weight;
+ p->chroma_weight_l1[i][1] = default_chroma_weight;
+ }
+ memset (p->chroma_offset_l1, 0, sizeof (p->chroma_offset_l1));
+ }
+ }
+
+ for (i = 0; i <= slice->num_ref_idx_l0_active_minus1; i++) {
+ guint8 luma_weight_l0_flag;
+
+ READ_UINT8 (nr, luma_weight_l0_flag, 1);
+ if (luma_weight_l0_flag) {
+ READ_SE_ALLOWED (nr, p->luma_weight_l0[i], -128, 127);
+ READ_SE_ALLOWED (nr, p->luma_offset_l0[i], -128, 127);
+ }
+ if (chroma_array_type != 0) {
+ guint8 chroma_weight_l0_flag;
+ gint j;
+
+ READ_UINT8 (nr, chroma_weight_l0_flag, 1);
+ if (chroma_weight_l0_flag) {
+ for (j = 0; j < 2; j++) {
+ READ_SE_ALLOWED (nr, p->chroma_weight_l0[i][j], -128, 127);
+ READ_SE_ALLOWED (nr, p->chroma_offset_l0[i][j], -128, 127);
+ }
+ }
+ }
+ }
+
+ if (GST_H264_IS_B_SLICE (slice)) {
+ for (i = 0; i <= slice->num_ref_idx_l1_active_minus1; i++) {
+ guint8 luma_weight_l1_flag;
+
+ READ_UINT8 (nr, luma_weight_l1_flag, 1);
+ if (luma_weight_l1_flag) {
+ READ_SE_ALLOWED (nr, p->luma_weight_l1[i], -128, 127);
+ READ_SE_ALLOWED (nr, p->luma_offset_l1[i], -128, 127);
+ }
+ if (chroma_array_type != 0) {
+ guint8 chroma_weight_l1_flag;
+ gint j;
+
+ READ_UINT8 (nr, chroma_weight_l1_flag, 1);
+ if (chroma_weight_l1_flag) {
+ for (j = 0; j < 2; j++) {
+ READ_SE_ALLOWED (nr, p->chroma_weight_l1[i][j], -128, 127);
+ READ_SE_ALLOWED (nr, p->chroma_offset_l1[i][j], -128, 127);
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+
+error:
+ GST_WARNING ("error parsing \"Prediction weight table\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_buffering_period (GstH264NalParser * nalparser,
+ GstH264BufferingPeriod * per, NalReader * nr)
+{
+ GstH264SPS *sps;
+ guint8 sps_id;
+
+ GST_DEBUG ("parsing \"Buffering period\"");
+
+ READ_UE_ALLOWED (nr, sps_id, 0, GST_H264_MAX_SPS_COUNT);
+ sps = gst_h264_parser_get_sps (nalparser, sps_id);
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ sps_id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+ per->sps = sps;
+
+ if (sps->vui_parameters_present_flag) {
+ GstH264VUIParams *vui = &sps->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ GstH264HRDParams *hrd = &vui->nal_hrd_parameters;
+ guint8 sched_sel_idx;
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1;
+ sched_sel_idx++) {
+ READ_UINT8 (nr, per->nal_initial_cpb_removal_delay[sched_sel_idx], 5);
+ READ_UINT8 (nr,
+ per->nal_initial_cpb_removal_delay_offset[sched_sel_idx], 5);
+ }
+ }
+
+ if (vui->vcl_hrd_parameters_present_flag) {
+ GstH264HRDParams *hrd = &vui->vcl_hrd_parameters;
+ guint8 sched_sel_idx;
+
+ for (sched_sel_idx = 0; sched_sel_idx <= hrd->cpb_cnt_minus1;
+ sched_sel_idx++) {
+ READ_UINT8 (nr, per->vcl_initial_cpb_removal_delay[sched_sel_idx], 5);
+ READ_UINT8 (nr,
+ per->vcl_initial_cpb_removal_delay_offset[sched_sel_idx], 5);
+ }
+ }
+ }
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Buffering period\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+static gboolean
+gst_h264_parse_clock_timestamp (GstH264ClockTimestamp * tim,
+ GstH264VUIParams * vui, NalReader * nr)
+{
+ guint8 full_timestamp_flag;
+ guint8 time_offset_length;
+
+ GST_DEBUG ("parsing \"Clock timestamp\"");
+
+ /* defalt values */
+ tim->time_offset = 0;
+
+ READ_UINT8 (nr, tim->ct_type, 2);
+ READ_UINT8 (nr, tim->nuit_field_based_flag, 1);
+ READ_UINT8 (nr, tim->counting_type, 5);
+ READ_UINT8 (nr, full_timestamp_flag, 1);
+ READ_UINT8 (nr, tim->discontinuity_flag, 1);
+ READ_UINT8 (nr, tim->cnt_dropped_flag, 1);
+ READ_UINT8 (nr, tim->n_frames, 8);
+
+ if (full_timestamp_flag) {
+ tim->seconds_flag = TRUE;
+ READ_UINT8 (nr, tim->seconds_value, 6);
+
+ tim->minutes_flag = TRUE;
+ READ_UINT8 (nr, tim->minutes_value, 6);
+
+ tim->hours_flag = TRUE;
+ READ_UINT8 (nr, tim->hours_value, 5);
+ } else {
+ READ_UINT8 (nr, tim->seconds_flag, 1);
+ if (tim->seconds_flag) {
+ READ_UINT8 (nr, tim->seconds_value, 6);
+ READ_UINT8 (nr, tim->minutes_flag, 1);
+ if (tim->minutes_flag) {
+ READ_UINT8 (nr, tim->minutes_value, 6);
+ READ_UINT8 (nr, tim->hours_flag, 1);
+ if (tim->hours_flag)
+ READ_UINT8 (nr, tim->hours_value, 5);
+ }
+ }
+ }
+
+ time_offset_length = 0;
+ if (vui->nal_hrd_parameters_present_flag)
+ time_offset_length = vui->nal_hrd_parameters.time_offset_length;
+ else if (vui->vcl_hrd_parameters_present_flag)
+ time_offset_length = vui->vcl_hrd_parameters.time_offset_length;
+
+ if (time_offset_length > 0)
+ READ_UINT32 (nr, tim->time_offset, time_offset_length);
+
+error:
+ GST_WARNING ("error parsing \"Clock timestamp\"");
+ return FALSE;
+}
+
+static gboolean
+gst_h264_parser_parse_pic_timing (GstH264NalParser * nalparser,
+ GstH264PicTiming * tim, NalReader * nr)
+{
+ GST_DEBUG ("parsing \"Picture timing\"");
+ if (!nalparser->last_sps || !nalparser->last_sps->valid) {
+ GST_WARNING ("didn't get the associated sequence paramater set for the "
+ "current access unit");
+ goto error;
+ }
+
+ /* default values */
+ memset (tim->clock_timestamp_flag, 0, 3);
+
+ if (nalparser->last_sps->vui_parameters_present_flag) {
+ GstH264VUIParams *vui = &nalparser->last_sps->vui_parameters;
+
+ if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT32 (nr, tim->cpb_removal_delay,
+ vui->nal_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT32 (nr, tim->dpb_output_delay,
+ vui->nal_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ } else if (vui->nal_hrd_parameters_present_flag) {
+ READ_UINT32 (nr, tim->cpb_removal_delay,
+ vui->vcl_hrd_parameters.cpb_removal_delay_length_minus1 + 1);
+ READ_UINT32 (nr, tim->dpb_output_delay,
+ vui->vcl_hrd_parameters.dpb_output_delay_length_minus1 + 1);
+ }
+
+ if (vui->pic_struct_present_flag) {
+ const guint8 num_clock_ts_table[9] = {
+ 1, 1, 1, 2, 2, 3, 3, 2, 3
+ };
+ guint8 num_clock_num_ts;
+ guint i;
+
+ READ_UINT8 (nr, tim->pic_struct, 4);
+ CHECK_ALLOWED (tim->pic_struct, 0, 8);
+
+ num_clock_num_ts = num_clock_ts_table[tim->pic_struct];
+ for (i = 0; i < num_clock_num_ts; i++) {
+ READ_UINT8 (nr, tim->clock_timestamp_flag[i], 1);
+ if (tim->clock_timestamp_flag[i]) {
+ if (!gst_h264_parse_clock_timestamp (&tim->clock_timestamp[i], vui,
+ nr))
+ goto error;
+ }
+ }
+ }
+ }
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Picture timing\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+/******** API *************/
+
+/**
+ * gst_h264_nal_parser_new:
+ *
+ * Creates a nez #GstH264NalParser
+ *
+ * Returns: a new #GstH264NalParser
+ */
+GstH264NalParser *
+gst_h264_nal_parser_new (void)
+{
+ GstH264NalParser *nalparser;
+
+ nalparser = g_malloc0 (sizeof (GstH264NalParser));
+ GST_DEBUG_CATEGORY_INIT (h264_parser_debug, "codecparsers_h264", 0,
+ "h264 parser library");
+
+ return nalparser;
+}
+
+/**
+ * gst_h264_parser_identify_nalu:
+ * @nalparser: a #GstH264NalParser
+ * @data: The data to parse
+ * @offset: the offset from which to parse @data
+ * @size: the size of @data
+ * @nalu: The #GstH264NalUnit where to store parsed nal headers
+ *
+ * Parses the buffer and set @nalu from the next nalu data from @data
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_identify_nalu (GstH264NalParser * nalparser,
+ const guint8 * data, guint offset, gsize size, GstH264NalUnit * nalu)
+{
+ gint off1, off2;
+
+ if (size - 4 <= offset) {
+ GST_DEBUG ("Can't parse, buffer is to small size %u, offset %u", size,
+ offset);
+ return GST_H264_PARSER_ERROR;
+ }
+
+ off1 = scan_for_start_codes (data + offset, size - offset);
+
+ if (off1 < 0) {
+ GST_DEBUG ("No start code prefix in this buffer");
+ return GST_H264_PARSER_NO_NAL;
+ }
+
+ if (offset + off1 == size - 1) {
+ GST_DEBUG ("Missing data to identify nal unit");
+
+ return GST_H264_PARSER_ERROR;
+ }
+
+ nalu->valid = TRUE;
+ nalu->sc_offset = offset + off1;
+ /* sc might have 2 or 3 0-bytes */
+ if (nalu->sc_offset > 0 && data[nalu->sc_offset - 1] == 00)
+ nalu->sc_offset--;
+
+ nalu->offset = offset + off1 + 3;
+ nalu->data = (guint8 *) data;
+ set_nalu_datas (nalu);
+
+ off2 = scan_for_start_codes (data + nalu->offset, size - nalu->offset);
+ if (off2 < 0) {
+ GST_DEBUG ("Nal start %d, No end found", nalu->offset);
+
+ return GST_H264_PARSER_NO_NAL_END;
+ }
+
+ if (off2 > 0 && data[nalu->offset + off2 - 1] == 00)
+ off2--;
+
+ nalu->size = off2;
+ if (nalu->size < 2)
+ return GST_H264_PARSER_BROKEN_DATA;
+
+ GST_DEBUG ("Complete nal found. Off: %d, Size: %d", nalu->offset, nalu->size);
+ return GST_H264_PARSER_OK;
+}
+
+/**
+ * gst_h264_parser_identify_nalu_avc:
+ * @data: The data to parse, must be the beging of the Nal unit
+ * @size: the size of @data
+ * @nal_length_size: the size in bytes of the AVC nal length prefix.
+ * @nalu: The #GstH264NalUnit where to store parsed nal headers
+ *
+ * Parses the data and sets @nalu from @data.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_identify_nalu_avc (GstH264NalParser * nalparser,
+ const guint8 * data, guint offset, gsize size, guint8 nal_length_size,
+ GstH264NalUnit * nalu)
+{
+ GstBitReader br;
+
+ size = size - offset;
+ gst_bit_reader_init (&br, data + offset, size);
+
+ gst_bit_reader_get_bits_uint32 (&br, &nalu->size, nal_length_size * 8);
+ nalu->sc_offset = offset;
+ nalu->offset = offset + nal_length_size;
+
+ if (size < nalu->size + nal_length_size) {
+ nalu->size = 0;
+
+ return GST_H264_PARSER_NO_NAL_END;
+ }
+
+ nalu->data = (guint8 *) data;
+
+ set_nalu_datas (nalu);
+
+ if (nalu->size < 2)
+ return GST_H264_PARSER_BROKEN_DATA;
+
+ nalu->valid = TRUE;
+
+ return GST_H264_PARSER_OK;
+}
+
+GstH264ParserResult
+gst_h264_parser_parse_nal (GstH264NalParser * nalparser, GstH264NalUnit * nalu)
+{
+ GstH264SPS sps;
+ GstH264PPS pps;
+
+ switch (nalu->type) {
+ case GST_H264_NAL_SPS:
+ return gst_h264_parser_parse_sps (nalparser, nalu, &sps, FALSE);
+ break;
+ case GST_H264_NAL_PPS:
+ return gst_h264_parser_parse_pps (nalparser, nalu, &pps);
+ }
+
+ return GST_H264_PARSER_OK;
+}
+
+/**
+ * gst_h264_parser_parse_sps:
+ * @nalparser: a #GstH264NalParser
+ * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SPS to set.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses the @data, and sets the @sps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_sps (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264SPS * sps, gboolean parse_vui_params)
+{
+ GstH264ParserResult res = gst_h264_parse_sps (nalu, sps, parse_vui_params);
+
+ if (res == GST_H264_PARSER_OK) {
+ GST_DEBUG ("adding sequence parameter set with id: %d to array", sps->id);
+
+ nalparser->sps[sps->id] = *sps;
+ nalparser->last_sps = &nalparser->sps[sps->id];
+ }
+
+
+
+ return res;
+}
+
+/**
+ * gst_h264_parse_sps:
+ * @nalu: The #GST_H264_NAL_SPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SPS to set.
+ * @parse_vui_params: Whether to parse the vui_params or not
+ *
+ * Parses the @data, and sets the @sps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps,
+ gboolean parse_vui_params)
+{
+ NalReader nr;
+ gint width, height;
+ guint8 frame_cropping_flag;
+ guint subwc[] = { 1, 2, 2, 1 };
+ guint subhc[] = { 1, 2, 1, 1 };
+ GstH264VUIParams *vui = NULL;
+
+ GST_DEBUG ("parsing SPS");
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ sps->chroma_format_idc = 1;
+ sps->separate_colour_plane_flag = 0;
+ sps->bit_depth_luma_minus8 = 0;
+ sps->bit_depth_chroma_minus8 = 0;
+ memset (sps->scaling_lists_4x4, 16, 96);
+ memset (sps->scaling_lists_8x8, 16, 384);
+ sps->mb_adaptive_frame_field_flag = 0;
+ sps->frame_crop_left_offset = 0;
+ sps->frame_crop_right_offset = 0;
+ sps->frame_crop_top_offset = 0;
+ sps->frame_crop_bottom_offset = 0;
+
+ READ_UINT8 (&nr, sps->profile_idc, 8);
+ READ_UINT8 (&nr, sps->constraint_set0_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set1_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set2_flag, 1);
+ READ_UINT8 (&nr, sps->constraint_set3_flag, 1);
+
+ /* skip reserved_zero_4bits */
+ if (!nal_reader_skip (&nr, 4))
+ goto error;
+
+ READ_UINT8 (&nr, sps->level_idc, 8);
+
+ READ_UE_ALLOWED (&nr, sps->id, 0, GST_H264_MAX_SPS_COUNT);
+
+ if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
+ sps->profile_idc == 122 || sps->profile_idc == 244 ||
+ sps->profile_idc == 44 || sps->profile_idc == 83 ||
+ sps->profile_idc == 86) {
+ READ_UE_ALLOWED (&nr, sps->chroma_format_idc, 0, 3);
+ if (sps->chroma_format_idc == 3)
+ READ_UINT8 (&nr, sps->separate_colour_plane_flag, 1);
+
+ READ_UE_ALLOWED (&nr, sps->bit_depth_luma_minus8, 0, 6);
+ READ_UE_ALLOWED (&nr, sps->bit_depth_chroma_minus8, 0, 6);
+ READ_UINT8 (&nr, sps->qpprime_y_zero_transform_bypass_flag, 1);
+
+ READ_UINT8 (&nr, sps->scaling_matrix_present_flag, 1);
+ if (sps->scaling_matrix_present_flag) {
+ guint8 n_lists;
+
+ n_lists = (sps->chroma_format_idc != 3) ? 8 : 12;
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ sps->scaling_lists_4x4, sps->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, n_lists))
+ goto error;
+ }
+ }
+
+ READ_UE_ALLOWED (&nr, sps->log2_max_frame_num_minus4, 0, 12);
+
+ sps->max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
+
+ READ_UE_ALLOWED (&nr, sps->pic_order_cnt_type, 0, 2);
+ if (sps->pic_order_cnt_type == 0) {
+ READ_UE_ALLOWED (&nr, sps->log2_max_pic_order_cnt_lsb_minus4, 0, 12);
+ } else if (sps->pic_order_cnt_type == 1) {
+ guint i;
+
+ READ_UINT8 (&nr, sps->delta_pic_order_always_zero_flag, 1);
+ READ_SE (&nr, sps->offset_for_non_ref_pic);
+ READ_SE (&nr, sps->offset_for_top_to_bottom_field);
+ READ_UE_ALLOWED (&nr, sps->num_ref_frames_in_pic_order_cnt_cycle, 0, 255);
+
+ for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
+ READ_SE (&nr, sps->offset_for_ref_frame[i]);
+ }
+
+ READ_UE (&nr, sps->num_ref_frames);
+ READ_UINT8 (&nr, sps->gaps_in_frame_num_value_allowed_flag, 1);
+ READ_UE (&nr, sps->pic_width_in_mbs_minus1);
+ READ_UE (&nr, sps->pic_height_in_map_units_minus1);
+ READ_UINT8 (&nr, sps->frame_mbs_only_flag, 1);
+
+ if (!sps->frame_mbs_only_flag)
+ READ_UINT8 (&nr, sps->mb_adaptive_frame_field_flag, 1);
+
+ READ_UINT8 (&nr, sps->direct_8x8_inference_flag, 1);
+ READ_UINT8 (&nr, frame_cropping_flag, 1);
+ if (frame_cropping_flag) {
+ READ_UE (&nr, sps->frame_crop_left_offset);
+ READ_UE (&nr, sps->frame_crop_right_offset);
+ READ_UE (&nr, sps->frame_crop_top_offset);
+ READ_UE (&nr, sps->frame_crop_bottom_offset);
+ }
+
+ READ_UINT8 (&nr, sps->vui_parameters_present_flag, 1);
+ if (sps->vui_parameters_present_flag && parse_vui_params) {
+ if (!gst_h264_parse_vui_parameters (sps, &nr))
+ goto error;
+ vui = &sps->vui_parameters;
+ }
+
+ /* calculate ChromaArrayType */
+ if (sps->separate_colour_plane_flag)
+ sps->chroma_array_type = 0;
+ else
+ sps->chroma_array_type = sps->chroma_format_idc;
+
+ /* Calculate width and height */
+ width = (sps->pic_width_in_mbs_minus1 + 1);
+ width *= 16;
+ height = (sps->pic_height_in_map_units_minus1 + 1);
+ height *= 16 * (2 - sps->frame_mbs_only_flag);
+ GST_LOG ("initial width=%d, height=%d", width, height);
+
+ width -= (sps->frame_crop_left_offset + sps->frame_crop_right_offset)
+ * subwc[sps->chroma_format_idc];
+ height -= (sps->frame_crop_top_offset + sps->frame_crop_bottom_offset
+ * subhc[sps->chroma_format_idc] * (2 - sps->frame_mbs_only_flag));
+ if (width < 0 || height < 0) {
+ GST_WARNING ("invalid width/height in SPS");
+ return FALSE;
+ }
+ GST_LOG ("final width=%u, height=%u", width, height);
+ sps->width = width;
+ sps->height = height;
+
+ /* derive framerate */
+ /* FIXME verify / also handle other cases */
+ GST_LOG ("Framerate: %u %u %u %u", parse_vui_params,
+ vui->fixed_frame_rate_flag, sps->frame_mbs_only_flag,
+ vui->pic_struct_present_flag);
+
+ if (parse_vui_params && vui->fixed_frame_rate_flag &&
+ sps->frame_mbs_only_flag && !vui->pic_struct_present_flag) {
+ sps->fps_num = vui->time_scale;
+ sps->fps_den = vui->num_units_in_tick;
+ /* picture is a frame = 2 fields */
+ sps->fps_den *= 2;
+ GST_LOG ("framerate %d/%d", sps->fps_num, sps->fps_den);
+ }
+
+ sps->valid = TRUE;
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Sequence parameter set\"");
+
+ return GST_H264_PARSER_ERROR;
+}
+
+/**
+ * gst_h264_parse_pps:
+ * @nalparser: a #GstH264NalParser
+ * @data: the data to parse
+ * @size: the size of @data
+ * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264PPS to set.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264PPS * pps)
+{
+ NalReader nr;
+ GstH264SPS *sps;
+ gint sps_id;
+ guint8 pic_scaling_matrix_present_flag;
+ gint qp_bd_offset;
+
+ GST_DEBUG ("parsing PPS");
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size);
+
+ READ_UE_ALLOWED (&nr, pps->id, 0, GST_H264_MAX_PPS_COUNT);
+ READ_UE_ALLOWED (&nr, sps_id, 0, GST_H264_MAX_SPS_COUNT);
+
+ sps = gst_h264_parser_get_sps (nalparser, sps_id);
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ sps_id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+ pps->sequence = sps;
+ qp_bd_offset = 6 * (sps->bit_depth_luma_minus8 +
+ sps->separate_colour_plane_flag);
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ pps->slice_group_id = NULL;
+ pps->transform_8x8_mode_flag = 0;
+ memcpy (&pps->scaling_lists_4x4, &sps->scaling_lists_4x4, 96);
+ memcpy (&pps->scaling_lists_8x8, &sps->scaling_lists_8x8, 384);
+
+ READ_UINT8 (&nr, pps->entropy_coding_mode_flag, 1);
+ READ_UINT8 (&nr, pps->pic_order_present_flag, 1);
+ READ_UE_ALLOWED (&nr, pps->num_slice_groups_minus1, 0, 7);
+ if (pps->num_slice_groups_minus1 > 0) {
+ READ_UE_ALLOWED (&nr, pps->slice_group_map_type, 0, 6);
+
+ if (pps->slice_group_map_type == 0) {
+ gint i;
+
+ for (i = 0; i <= pps->num_slice_groups_minus1; i++)
+ READ_UE (&nr, pps->run_length_minus1[i]);
+ } else if (pps->slice_group_map_type == 2) {
+ gint i;
+
+ for (i = 0; i <= pps->num_slice_groups_minus1; i++) {
+ READ_UE (&nr, pps->top_left[i]);
+ READ_UE (&nr, pps->bottom_right[i]);
+ }
+ } else if (pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
+ READ_UINT8 (&nr, pps->slice_group_change_direction_flag, 1);
+ READ_UE (&nr, pps->slice_group_change_rate_minus1);
+ } else if (pps->slice_group_map_type == 6) {
+ gint bits;
+ gint i;
+
+ READ_UE (&nr, pps->pic_size_in_map_units_minus1);
+ bits = g_bit_storage (pps->num_slice_groups_minus1);
+
+ pps->slice_group_id =
+ g_new (guint8, pps->pic_size_in_map_units_minus1 + 1);
+ for (i = 0; i <= pps->pic_size_in_map_units_minus1; i++)
+ READ_UINT8 (&nr, pps->slice_group_id[i], bits);
+ }
+ }
+
+ READ_UE_ALLOWED (&nr, pps->num_ref_idx_l0_active_minus1, 0, 31);
+ READ_UE_ALLOWED (&nr, pps->num_ref_idx_l1_active_minus1, 0, 31);
+ READ_UINT8 (&nr, pps->weighted_pred_flag, 1);
+ READ_UINT8 (&nr, pps->weighted_bipred_idc, 2);
+ READ_SE_ALLOWED (&nr, pps->pic_init_qp_minus26, -(26 + qp_bd_offset), 25);
+ READ_SE_ALLOWED (&nr, pps->pic_init_qs_minus26, -26, 25);
+ READ_SE_ALLOWED (&nr, pps->chroma_qp_index_offset, -12, 12);
+ pps->second_chroma_qp_index_offset = pps->chroma_qp_index_offset;
+ READ_UINT8 (&nr, pps->deblocking_filter_control_present_flag, 1);
+ READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1);
+ READ_UINT8 (&nr, pps->redundant_pic_cnt_present_flag, 1);
+
+ if (!gst_h264_parser_more_data (&nr))
+ goto done;
+
+ READ_UINT8 (&nr, pps->transform_8x8_mode_flag, 1);
+
+ READ_UINT8 (&nr, pic_scaling_matrix_present_flag, 1);
+ if (pic_scaling_matrix_present_flag) {
+ guint8 n_lists;
+
+ n_lists = 6 + ((sps->chroma_format_idc != 3) ? 2 : 6) *
+ pps->transform_8x8_mode_flag;
+
+ if (sps->scaling_matrix_present_flag) {
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ pps->scaling_lists_4x4, pps->scaling_lists_8x8,
+ sps->scaling_lists_4x4[0], sps->scaling_lists_4x4[3],
+ sps->scaling_lists_8x8[0], sps->scaling_lists_8x8[3], n_lists))
+ goto error;
+ } else {
+ if (!gst_h264_parser_parse_scaling_list (&nr,
+ pps->scaling_lists_4x4, pps->scaling_lists_8x8,
+ default_4x4_inter, default_4x4_intra,
+ default_8x8_inter, default_8x8_intra, n_lists))
+ goto error;
+ }
+ }
+
+ /* FIXME For some reson second_chroma_qp_index_offset is not always present */
+ if (G_UNLIKELY (nr.byte * 8 + (8 - nr.bits_in_cache) > nr.size * 8))
+ READ_SE_ALLOWED (&nr, pps->second_chroma_qp_index_offset, -12, 12);
+
+ pps->valid = TRUE;
+
+done:
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Picture parameter set\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+/**
+ * gst_h264_parser_parse_pps:
+ * @nalparser: a #GstH264NalParser
+ * @data: the data to parse
+ * @size: the size of @data
+ * @nalu: The #GST_H264_NAL_PPS #GstH264NalUnit you want to parse
+ * @slice: The #GstH264PPS to set.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_pps (GstH264NalParser * nalparser,
+ GstH264NalUnit * nalu, GstH264PPS * pps)
+{
+ GstH264ParserResult res = gst_h264_parse_pps (nalparser, nalu, pps);
+
+ if (res == GST_H264_PARSER_OK) {
+ GST_DEBUG ("adding picture parameter set with id: %d to array", pps->id);
+
+ nalparser->pps[pps->id] = *pps;
+ nalparser->last_pps = &nalparser->pps[pps->id];
+ }
+
+ return res;
+}
+
+/**
+ * gst_h264_parser_parse_slice_hdr:
+ * @nalu: The #GST_H264_NAL_SLICE #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SliceHdr to set.
+ * @parse_pred_weight_table: Whether to parse the pred_weight_table or not
+ * @parse_dec_ref_pic_marking: Whether to parse the dec_ref_pic_marking or not
+ *
+ * Parses the @data, and sets the @slice.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_slice_hdr (GstH264NalParser * nalparser,
+ GstH264NalUnit * nalu, GstH264SliceHdr * slice,
+ gboolean parse_pred_weight_table, gboolean parse_dec_ref_pic_marking)
+{
+ NalReader nr;
+ gint pps_id;
+ GstH264PPS *pps;
+ GstH264SPS *sps;
+
+ if (!nalu->size) {
+ GST_DEBUG ("Invalid Nal Unit");
+ return GST_H264_PARSER_ERROR;
+ }
+
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size);
+
+ READ_UE (&nr, slice->first_mb_in_slice);
+ READ_UE (&nr, slice->type);
+
+ GST_DEBUG ("parsing \"Slice header\", slice type %u", slice->type);
+
+ READ_UE_ALLOWED (&nr, pps_id, 0, GST_H264_MAX_PPS_COUNT);
+ pps = gst_h264_parser_get_pps (nalparser, pps_id);
+
+ if (!pps) {
+ GST_WARNING ("couldn't find associated picture parameter set with id: %d",
+ pps_id);
+
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+
+ slice->pps = pps;
+ sps = pps->sequence;
+ if (!sps) {
+ GST_WARNING ("couldn't find associated sequence parameter set with id: %d",
+ pps->id);
+ return GST_H264_PARSER_BROKEN_LINK;
+ }
+
+ /* set default values for fields that might not be present in the bitstream
+ and have valid defaults */
+ slice->field_pic_flag = 0;
+ slice->bottom_field_flag = 0;
+ slice->delta_pic_order_cnt_bottom = 0;
+ slice->delta_pic_order_cnt[0] = 0;
+ slice->delta_pic_order_cnt[1] = 0;
+ slice->redundant_pic_cnt = 0;
+ slice->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_active_minus1;
+ slice->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_active_minus1;
+ slice->disable_deblocking_filter_idc = 0;
+ slice->slice_alpha_c0_offset_div2 = 0;
+
+ if (sps->separate_colour_plane_flag)
+ READ_UINT8 (&nr, slice->colour_plane_id, 2);
+
+ READ_UINT16 (&nr, slice->frame_num, sps->log2_max_frame_num_minus4 + 4);
+
+ if (!sps->frame_mbs_only_flag) {
+ READ_UINT8 (&nr, slice->field_pic_flag, 1);
+ if (slice->field_pic_flag)
+ READ_UINT8 (&nr, slice->bottom_field_flag, 1);
+ }
+
+ /* calculate MaxPicNum */
+ if (slice->field_pic_flag)
+ slice->max_pic_num = sps->max_frame_num;
+ else
+ slice->max_pic_num = 2 * sps->max_frame_num;
+
+ if (nalu->type == 5)
+ READ_UE_ALLOWED (&nr, slice->idr_pic_id, 0, G_MAXUINT16);
+
+ if (sps->pic_order_cnt_type == 0) {
+ READ_UINT16 (&nr, slice->pic_order_cnt_lsb,
+ sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+
+ if (pps->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&nr, slice->delta_pic_order_cnt_bottom);
+ }
+
+ if (sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag) {
+ READ_SE (&nr, slice->delta_pic_order_cnt[0]);
+ if (pps->pic_order_present_flag && !slice->field_pic_flag)
+ READ_SE (&nr, slice->delta_pic_order_cnt[1]);
+ }
+
+ if (pps->redundant_pic_cnt_present_flag)
+ READ_UE_ALLOWED (&nr, slice->redundant_pic_cnt, 0, G_MAXINT8);
+
+ if (GST_H264_IS_B_SLICE (slice))
+ READ_UINT8 (&nr, slice->direct_spatial_mv_pred_flag, 1);
+
+ if (GST_H264_IS_P_SLICE (slice) || GST_H264_IS_SP_SLICE (slice) ||
+ GST_H264_IS_B_SLICE (slice)) {
+ guint8 num_ref_idx_active_override_flag;
+
+ READ_UINT8 (&nr, num_ref_idx_active_override_flag, 1);
+ if (num_ref_idx_active_override_flag) {
+ READ_UE_ALLOWED (&nr, slice->num_ref_idx_l0_active_minus1, 0, 31);
+
+ if (GST_H264_IS_B_SLICE (slice))
+ READ_UE_ALLOWED (&nr, slice->num_ref_idx_l1_active_minus1, 0, 31);
+ }
+ }
+
+ if (!slice_parse_ref_pic_list_reordering (slice, &nr))
+ goto error;
+
+ if ((pps->weighted_pred_flag && (GST_H264_IS_P_SLICE (slice)
+ || GST_H264_IS_SP_SLICE (slice)))
+ || (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice))) {
+ if (!gst_h264_slice_parse_pred_weight_table (slice, &nr,
+ sps->chroma_array_type))
+ goto error;
+ }
+
+ if (nalu->ref_idc != 0) {
+ if (!gst_h264_slice_parse_dec_ref_pic_marking (slice, nalu, &nr))
+ goto error;
+ }
+
+ if (pps->entropy_coding_mode_flag && !GST_H264_IS_I_SLICE (slice) &&
+ !GST_H264_IS_SI_SLICE (slice))
+ READ_UE_ALLOWED (&nr, slice->cabac_init_idc, 0, 2);
+
+ READ_SE_ALLOWED (&nr, slice->slice_qp_delta, -87, 77);
+
+ if (GST_H264_IS_SP_SLICE (slice) || GST_H264_IS_SI_SLICE (slice)) {
+ guint8 sp_for_switch_flag;
+
+ if (GST_H264_IS_SP_SLICE (slice))
+ READ_UINT8 (&nr, sp_for_switch_flag, 1);
+ READ_SE_ALLOWED (&nr, slice->slice_qs_delta, -51, 51);
+ }
+
+ if (pps->deblocking_filter_control_present_flag) {
+ READ_UE_ALLOWED (&nr, slice->disable_deblocking_filter_idc, 0, 2);
+ if (slice->disable_deblocking_filter_idc != 1) {
+ READ_SE_ALLOWED (&nr, slice->slice_alpha_c0_offset_div2, -6, 6);
+ READ_SE_ALLOWED (&nr, slice->slice_beta_offset_div2, -6, 6);
+ }
+ }
+
+ if (pps->num_slice_groups_minus1 > 0 &&
+ pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
+ /* Ceil(Log2(PicSizeInMapUnits / SliceGroupChangeRate + 1)) [7-33] */
+ guint32 PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1;
+ guint32 PicHeightInMapUnits = sps->pic_height_in_map_units_minus1 + 1;
+ guint32 PicSizeInMapUnits = PicWidthInMbs * PicHeightInMapUnits;
+ guint32 SliceGroupChangeRate = pps->slice_group_change_rate_minus1 + 1;
+ const guint n = ceil_log2 (PicSizeInMapUnits / SliceGroupChangeRate + 1);
+ READ_UINT16 (&nr, slice->slice_group_change_cycle, n);
+ }
+
+ slice->header_size = nal_reader_get_pos (&nr);
+
+ return GST_H264_PARSER_OK;
+
+error:
+ GST_WARNING ("error parsing \"Slice header\"");
+ return GST_H264_PARSER_ERROR;
+}
+
+/**
+ * gst_h264_parser_parse_sei:
+ * @nalparser: a #GstH264NalParser
+ * @nalu: The #GST_H264_NAL_SEI #GstH264NalUnit you want to parse
+ * @slice: The #GstH264SEIMessage to set.
+ *
+ * Parses the @data, and sets the @pps.
+ *
+ * Returns: a #GstH264ParserResult
+ */
+GstH264ParserResult
+gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
+ GstH264SEIMessage * sei)
+{
+ NalReader nr;
+
+ guint32 payloadSize;
+ guint8 payload_type_byte, payload_size_byte;
+ guint remaining, payload_size;
+ gboolean res;
+
+ GST_DEBUG ("parsing \"Sei message\"");
+
+ nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size);
+
+ sei->payloadType = 0;
+ do {
+ READ_UINT8 (&nr, payload_type_byte, 8);
+ sei->payloadType += payload_type_byte;
+ } while (payload_type_byte == 0xff);
+
+ payloadSize = 0;
+ do {
+ READ_UINT8 (&nr, payload_size_byte, 8);
+ payloadSize += payload_size_byte;
+ }
+ while (payload_size_byte == 0xff);
+
+ remaining = nal_reader_get_remaining (&nr) * 8;
+ payload_size = payloadSize < remaining ? payloadSize : remaining;
+
+ GST_DEBUG ("SEI message received: payloadType %u, payloadSize = %u bytes",
+ sei->payloadType, payload_size);
+
+ if (sei->payloadType == GST_H264_SEI_BUF_PERIOD) {
+ /* Set the nal reader size properly */
+ nr.size = payload_size;
+ res = gst_h264_parser_parse_buffering_period (nalparser,
+ &sei->buffering_period, &nr);
+ } else if (sei->payloadType == GST_H264_SEI_PIC_TIMING) {
+ /* Set the nal reader size properly */
+ nr.size = payload_size;
+ res = gst_h264_parser_parse_pic_timing (nalparser, &sei->pic_timing, &nr);
+ } else
+ res = GST_H264_PARSER_OK;
+
+ return res;
+
+error:
+ GST_WARNING ("error parsing \"Sei message\"");
+ return GST_H264_PARSER_ERROR;
+}
diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h
new file mode 100644
index 000000000..c7fae9584
--- /dev/null
+++ b/gst-libs/gst/codecparsers/gsth264parser.h
@@ -0,0 +1,657 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c:
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Nokia Corporation
+ *
+ * (C) 2005 Michal Benes <michal.benes@itonis.tv>
+ * (C) 2008 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_H264_PARSER_H__
+#define __GST_H264_PARSER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_H264_MAX_SPS_COUNT 32
+#define GST_H264_MAX_PPS_COUNT 256
+
+#define GST_H264_IS_P_SLICE(slice) (((slice)->type % 5) == GST_H264_P_SLICE)
+#define GST_H264_IS_B_SLICE(slice) (((slice)->type % 5) == GST_H264_B_SLICE)
+#define GST_H264_IS_I_SLICE(slice) (((slice)->type % 5) == GST_H264_I_SLICE)
+#define GST_H264_IS_SP_SLICE(slice) (((slice)->type % 5) == GST_H264_SP_SLICE)
+#define GST_H264_IS_SI_SLICE(slice) (((slice)->type % 5) == GST_H264_SI_SLICE)
+
+/**
+ * GstH264NalUnitType:
+ * @GST_H264_NAL_UNKNOWN: Unkonw nal type
+ * @GST_H264_NAL_SLICE: Slice nal
+ * @GST_H264_NAL_SLICE_DPA: DPA slice nal
+ * @GST_H264_NAL_SLICE_DPB: DPB slice nal
+ * @GST_H264_NAL_SLICE_DPC: DPC slice nal
+ * @GST_H264_NAL_SLICE_IDR: DPR slice nal
+ * @GST_H264_NAL_SEI: Supplemental enhancement information nal unit
+ * @GST_H264_NAL_SPS: Sequence parameter set nal unit
+ * @GST_H264_NAL_PPS: Picture parameter set nal unit
+ * @GST_H264_NAL_AU_DELIMITER: Access unit delimiter nal unit
+ * @GST_H264_NAL_SEQ_END: End of sequence nal unit
+ * @GST_H264_NAL_STREAM_END: End of stream nal unit
+ * @GST_H264_NAL_FILTER_DATA: Filler data na lunit
+ *
+ * Indicates the type of H264 Nal Units
+ */
+typedef enum
+{
+ GST_H264_NAL_UNKNOWN = 0,
+ GST_H264_NAL_SLICE = 1,
+ GST_H264_NAL_SLICE_DPA = 2,
+ GST_H264_NAL_SLICE_DPB = 3,
+ GST_H264_NAL_SLICE_DPC = 4,
+ GST_H264_NAL_SLICE_IDR = 5,
+ GST_H264_NAL_SEI = 6,
+ GST_H264_NAL_SPS = 7,
+ GST_H264_NAL_PPS = 8,
+ GST_H264_NAL_AU_DELIMITER = 9,
+ GST_H264_NAL_SEQ_END = 10,
+ GST_H264_NAL_STREAM_END = 11,
+ GST_H264_NAL_FILLER_DATA = 12
+} GstH264NalUnitType;
+
+/**
+ * GstH264ParserResult:
+ * @GST_H264_PARSER_OK: The parsing succeded
+ * @GST_H264_PARSER_BROKEN_DATA: The data we parsed where broken
+ * @GST_H264_PARSER_BROKEN_LINK: The link to a needed struct for the parsing couldn't be found
+ * @GST_H264_PARSER_ERROR: An error accured when parsing
+ * @GST_H264_PARSER_NO_NAL: No nal found during the parsing
+ * @GST_H264_PARSER_NO_NAL_END: Start of the nal found, not the end.
+ *
+ * Information about how the parsing of a H264 elements went.
+ */
+typedef enum
+{
+ GST_H264_PARSER_OK,
+ GST_H264_PARSER_BROKEN_DATA,
+ GST_H264_PARSER_BROKEN_LINK,
+ GST_H264_PARSER_ERROR,
+ GST_H264_PARSER_NO_NAL,
+ GST_H264_PARSER_NO_NAL_END
+} GstH264ParserResult;
+
+/**
+ * GstH264SEIPayloadType:
+ * @GST_H264_SEI_BUF_PERIOD: The Sei Message contains a buffering period message
+ * @GST_H264_SEI_PIC_TIMING: The Sei Message contains a picture timing message
+ * ...
+ *
+ * The type of the SEI message information
+ */
+typedef enum
+{
+ GST_H264_SEI_BUF_PERIOD = 0,
+ GST_H264_SEI_PIC_TIMING = 1
+ /* and more... */
+} GstH264SEIPayloadType;
+
+/**
+ * GstH264SEIPicStructType:
+ * @GST_H264_SEI_PIC_STRUCT_FRAME: Picture is a frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_FIELD: Top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD: Botom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM: Top bottom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP: bottom top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP: top bottom top field of frame
+ * @GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: bottom top bottom field of frame
+ * @GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING: indicates that the frame should
+ * be displayed two times consecutively
+ * @GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING: indicates that the frame should be
+ * displayed three times consecutively
+ *
+ * SEI pic_struct type
+ */
+typedef enum
+{
+ GST_H264_SEI_PIC_STRUCT_FRAME = 0,
+ GST_H264_SEI_PIC_STRUCT_TOP_FIELD = 1,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2,
+ GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4,
+ GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5,
+ GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6,
+ GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7,
+ GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8
+} GstH264SEIPicStructType;
+
+typedef enum
+{
+ GST_H264_P_SLICE = 0,
+ GST_H264_B_SLICE = 1,
+ GST_H264_I_SLICE = 2,
+ GST_H264_SP_SLICE = 3,
+ GST_H264_SI_SLICE = 4,
+ GST_H264_S_P_SLICE = 5,
+ GST_H264_S_B_SLICE = 6,
+ GST_H264_S_I_SLICE = 7,
+ GST_H264_S_SP_SLICE = 8,
+ GST_H264_S_SI_SLICE = 9
+} GstH264SliceType;
+
+typedef struct _GstH264NalParser GstH264NalParser;
+
+typedef struct _GstH264NalUnit GstH264NalUnit;
+
+typedef struct _GstH264SPS GstH264SPS;
+typedef struct _GstH264PPS GstH264PPS;
+typedef struct _GstH264HRDParams GstH264HRDParams;
+typedef struct _GstH264VUIParams GstH264VUIParams;
+
+typedef struct _GstH264DecRefPicMarking GstH264DecRefPicMarking;
+typedef struct _GstH264RefPicMarking GstH264RefPicMarking;
+typedef struct _GstH264PredWeightTable GstH264PredWeightTable;
+typedef struct _GstH264SliceHdr GstH264SliceHdr;
+
+typedef struct _GstH264ClockTimestamp GstH264ClockTimestamp;
+typedef struct _GstH264PicTiming GstH264PicTiming;
+typedef struct _GstH264BufferingPeriod GstH264BufferingPeriod;
+typedef struct _GstH264SEIMessage GstH264SEIMessage;
+
+/**
+ * GstH264NalUnit:
+ * @ref_idc: not equal to 0 specifies that the content of the NAL unit contains a sequence
+ * parameter set, a sequence * parameter set extension, a subset sequence parameter set, a
+ * picture parameter set, a slice of a reference picture, a slice data partition of a
+ * reference picture, or a prefix NAL unit preceding a slice of a reference picture.
+ * @type: A #GstH264NalUnitType
+ * @idr_pic_flag: calculated idr_pic_flag
+ * @size: The size of the nal unit starting from @offset
+ * @offset: The offset of the actual start of the nal unit
+ * @sc_offset:The offset of the start code of the nal unit
+ * @valid: If the nal unit is valid, which mean it has
+ * already been parsed
+ * @data: The data from which the Nalu has been parsed
+ *
+ * Structure defining the Nal unit headers
+ */
+struct _GstH264NalUnit
+{
+ guint16 ref_idc;
+ guint16 type;
+
+ /* calculated values */
+ guint8 idr_pic_flag;
+ guint size;
+ guint offset;
+ guint sc_offset;
+ gboolean valid;
+
+ guint8 *data;
+};
+
+/**
+ * GstH264HRDParams:
+ * @cpb_cnt_minus1: plus 1 specifies the number of alternative
+ * CPB specifications in the bitstream
+ * @bit_rate_scale: specifies the maximum input bit rate of the
+ * SchedSelIdx-th CPB
+ * @cpb_size_scale: specifies the CPB size of the SchedSelIdx-th CPB
+ * @guint32 bit_rate_value_minus1: specifies the maximum input bit rate for the
+ * SchedSelIdx-th CPB
+ * @cpb_size_value_minus1: is used together with cpb_size_scale to specify the
+ * SchedSelIdx-th CPB size
+ * @cbr_flag: Specifies if running in itermediate bitrate mode or constant
+ * @initial_cpb_removal_delay_length_minus1: specifies the length in bits of
+ * the cpb_removal_delay syntax element
+ * @cpb_removal_delay_length_minus1: specifies the length in bits of the
+ * dpb_output_delay syntax element
+ * @dpb_output_delay_length_minus1: >0 specifies the length in bits of the time_offset syntax element.
+ * =0 specifies that the time_offset syntax element is not present
+ * @time_offset_length: Length of the time offset
+ *
+ * Defines the HRD parameters
+ */
+struct _GstH264HRDParams
+{
+ guint8 cpb_cnt_minus1;
+ guint8 bit_rate_scale;
+ guint8 cpb_size_scale;
+
+ guint32 bit_rate_value_minus1[32];
+ guint32 cpb_size_value_minus1[32];
+ guint8 cbr_flag[32];
+
+ guint8 initial_cpb_removal_delay_length_minus1;
+ guint8 cpb_removal_delay_length_minus1;
+ guint8 dpb_output_delay_length_minus1;
+ guint8 time_offset_length;
+};
+
+/**
+ * GstH264VUIParams:
+ * @aspect_ratio_info_present_flag: %TRUE specifies that aspect_ratio_idc is present.
+ * %FALSE specifies that aspect_ratio_idc is not present
+ * @aspect_ratio_idc specifies the value of the sample aspect ratio of the luma samples
+ * @sar_width indicates the horizontal size of the sample aspect ratio
+ * @sar_height indicates the vertical size of the sample aspect ratio
+ * @overscan_info_present_flag: %TRUE overscan_appropriate_flag is present %FALSE otherwize
+ * @overscan_appropriate_flag: %TRUE indicates that the cropped decoded pictures
+ * output are suitable for display using overscan. %FALSE the cropped decoded pictures
+ * output contain visually important information
+ * @video_signal_type_present_flag: %TRUE specifies that video_format, video_full_range_flag and
+ * colour_description_present_flag are present.
+ * @video_format: indicates the representation of the picture
+ * @video_full_range_flag: indicates the black level and range of the luma and chroma signals
+ * @colour_description_present_flag: %TRUE specifies that colour_primaries,
+ * transfer_characteristics and matrix_coefficients are present
+ * @colour_primaries: indicates the chromaticity coordinates of the source primaries
+ * @transfer_characteristics: indicates the opto-electronic transfer characteristic
+ * @matrix_coefficients: describes the matrix coefficients used in deriving luma and chroma signals
+ * @chroma_loc_info_present_flag: %TRUE specifies that chroma_sample_loc_type_top_field and
+ * chroma_sample_loc_type_bottom_field are present, %FALSE otherwize
+ * @chroma_sample_loc_type_top_field: specify the location of chroma for top field
+ * @chroma_sample_loc_type_bottom_field specify the location of chroma for bottom field
+ * @timing_info_present_flag: %TRUE specifies that num_units_in_tick,
+ * time_scale and fixed_frame_rate_flag are present in the bitstream
+ * @num_units_in_tick: is the number of time units of a clock operating at the frequency time_scale Hz
+ * time_scale: is the number of time units that pass in one second
+ * @fixed_frame_rate_flag: %TRUE indicates that the temporal distance between the HRD output times
+ * of any two consecutive pictures in output order is constrained as specified in the spec, %FALSE
+ * otherwize.
+ * @nal_hrd_parameters_present_flag: %TRUE if nal hrd parameters present in the bitstream
+ * @vcl_hrd_parameters_present_flag: %TRUE if nal vlc hrd parameters present in the bitstream
+ * @low_delay_hrd_flag: specifies the HRD operational mode
+ * @pic_struct_present_flag: %TRUE specifies that picture timing SEI messages are present or not
+ * @bitstream_restriction_flag: %TRUE specifies that the following coded video sequence bitstream restriction
+ * parameters are present
+ * @motion_vectors_over_pic_boundaries_flag: %FALSE indicates that no sample outside the
+ * picture boundaries and no sample at a fractional sample position, %TRUE indicates that one or more
+ * samples outside picture boundaries may be used in inter prediction
+ * @max_bytes_per_pic_denom: indicates a number of bytes not exceeded by the sum of the sizes of
+ * the VCL NAL units associated with any coded picture in the coded video sequence.
+ * @max_bits_per_mb_denom: indicates the maximum number of coded bits of macroblock_layer()
+ * @log2_max_mv_length_horizontal: indicate the maximum absolute value of a decoded horizontal
+ * motion vector component
+ * @log2_max_mv_length_vertical: indicate the maximum absolute value of a decoded vertical
+ * motion vector component
+ * @num_reorder_frames: indicates the maximum number of frames, complementary field pairs,
+ * or non-paired fields that precede any frame,
+ * @max_dec_frame_buffering: specifies the required size of the HRD decoded picture buffer in
+ * units of frame buffers.
+ *
+ * The structure representing the VUI parameters.
+ */
+struct _GstH264VUIParams
+{
+ guint8 aspect_ratio_info_present_flag;
+ guint8 aspect_ratio_idc;
+ /* if aspect_ratio_idc == 255 */
+ guint16 sar_width;
+ guint16 sar_height;
+
+ guint8 overscan_info_present_flag;
+ /* if overscan_info_present_flag */
+ guint8 overscan_appropriate_flag;
+
+ guint8 video_signal_type_present_flag;
+ guint8 video_format;
+ guint8 video_full_range_flag;
+ guint8 colour_description_present_flag;
+ guint8 colour_primaries;
+ guint8 transfer_characteristics;
+ guint8 matrix_coefficients;
+
+ guint8 chroma_loc_info_present_flag;
+ guint8 chroma_sample_loc_type_top_field;
+ guint8 chroma_sample_loc_type_bottom_field;
+
+ guint8 timing_info_present_flag;
+ /* if timing_info_present_flag */
+ guint32 num_units_in_tick;
+ guint32 time_scale;
+ guint8 fixed_frame_rate_flag;
+
+ guint8 nal_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParams nal_hrd_parameters;
+
+ guint8 vcl_hrd_parameters_present_flag;
+ /* if nal_hrd_parameters_present_flag */
+ GstH264HRDParams vcl_hrd_parameters;
+
+ guint8 low_delay_hrd_flag;
+ guint8 pic_struct_present_flag;
+
+ guint8 bitstream_restriction_flag;
+ /* if bitstream_restriction_flag */
+ guint8 motion_vectors_over_pic_boundaries_flag;
+ guint32 max_bytes_per_pic_denom;
+ guint32 max_bits_per_mb_denom;
+ guint32 log2_max_mv_length_horizontal;
+ guint32 log2_max_mv_length_vertical;
+ guint32 num_reorder_frames;
+ guint32 max_dec_frame_buffering;
+};
+
+/**
+ * GstH264SPS:
+ * @id: The ID of the sequence parameter set
+ * @profile_idc: indicate the profile to which the coded video sequence conforms
+ *
+ *
+ */
+struct _GstH264SPS
+{
+ gint id;
+
+ guint8 profile_idc;
+ guint8 constraint_set0_flag;
+ guint8 constraint_set1_flag;
+ guint8 constraint_set2_flag;
+ guint8 constraint_set3_flag;
+ guint8 level_idc;
+
+ guint8 chroma_format_idc;
+ guint8 separate_colour_plane_flag;
+ guint8 bit_depth_luma_minus8;
+ guint8 bit_depth_chroma_minus8;
+ guint8 qpprime_y_zero_transform_bypass_flag;
+
+ guint8 scaling_matrix_present_flag;
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 log2_max_frame_num_minus4;
+ guint8 pic_order_cnt_type;
+
+ /* if pic_order_cnt_type == 0 */
+ guint8 log2_max_pic_order_cnt_lsb_minus4;
+
+ /* else if pic_order_cnt_type == 1 */
+ guint8 delta_pic_order_always_zero_flag;
+ gint32 offset_for_non_ref_pic;
+ gint32 offset_for_top_to_bottom_field;
+ guint8 num_ref_frames_in_pic_order_cnt_cycle;
+ gint32 offset_for_ref_frame[255];
+
+ guint32 num_ref_frames;
+ guint8 gaps_in_frame_num_value_allowed_flag;
+ guint32 pic_width_in_mbs_minus1;
+ guint32 pic_height_in_map_units_minus1;
+ guint8 frame_mbs_only_flag;
+
+ guint8 mb_adaptive_frame_field_flag;
+
+ guint8 direct_8x8_inference_flag;
+
+ guint8 frame_cropping_flag;
+
+ /* if frame_cropping_flag */
+ guint32 frame_crop_left_offset;
+ guint32 frame_crop_right_offset;
+ guint32 frame_crop_top_offset;
+ guint32 frame_crop_bottom_offset;
+
+ guint8 vui_parameters_present_flag;
+ /* if vui_parameters_present_flag */
+ GstH264VUIParams vui_parameters;
+
+ /* calculated values */
+ guint8 chroma_array_type;
+ guint32 max_frame_num;
+ gint width, height;
+ gint fps_num, fps_den;
+ gboolean valid;
+};
+
+struct _GstH264PPS
+{
+ gint id;
+
+ GstH264SPS *sequence;
+
+ guint8 entropy_coding_mode_flag;
+ guint8 pic_order_present_flag;
+
+ guint32 num_slice_groups_minus1;
+
+ /* if num_slice_groups_minus1 > 0 */
+ guint8 slice_group_map_type;
+ /* and if slice_group_map_type == 0 */
+ guint32 run_length_minus1[8];
+ /* or if slice_group_map_type == 2 */
+ guint32 top_left[8];
+ guint32 bottom_right[8];
+ /* or if slice_group_map_type == (3, 4, 5) */
+ guint8 slice_group_change_direction_flag;
+ guint32 slice_group_change_rate_minus1;
+ /* or if slice_group_map_type == 6 */
+ guint32 pic_size_in_map_units_minus1;
+ guint8 *slice_group_id;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+ guint8 weighted_pred_flag;
+ guint8 weighted_bipred_idc;
+ gint8 pic_init_qp_minus26;
+ gint8 pic_init_qs_minus26;
+ gint8 chroma_qp_index_offset;
+ guint8 deblocking_filter_control_present_flag;
+ guint8 constrained_intra_pred_flag;
+ guint8 redundant_pic_cnt_present_flag;
+
+ guint8 transform_8x8_mode_flag;
+
+ guint8 scaling_lists_4x4[6][16];
+ guint8 scaling_lists_8x8[6][64];
+
+ guint8 second_chroma_qp_index_offset;
+
+ gboolean valid;
+};
+
+struct _GstH264PredWeightTable
+{
+ guint8 luma_log2_weight_denom;
+ guint8 chroma_log2_weight_denom;
+
+ guint8 luma_weight_l0[32];
+ guint8 luma_offset_l0[32];
+
+ /* if seq->ChromaArrayType != 0 */
+ guint8 chroma_weight_l0[32][2];
+ guint8 chroma_offset_l0[32][2];
+
+ /* if slice->slice_type % 5 == 1 */
+ guint8 luma_weight_l1[32];
+ guint8 luma_offset_l1[32];
+ /* and if seq->ChromaArrayType != 0 */
+ guint8 chroma_weight_l1[32][2];
+ guint8 chroma_offset_l1[32][2];
+};
+
+struct _GstH264RefPicMarking
+{
+ guint8 memory_management_control_operation;
+
+ guint32 difference_of_pic_nums_minus1;
+ guint32 long_term_pic_num;
+ guint32 long_term_frame_idx;
+ guint32 max_long_term_frame_idx_plus1;
+};
+
+struct _GstH264DecRefPicMarking
+{
+ /* if slice->nal_unit.IdrPicFlag */
+ guint8 no_output_of_prior_pics_flag;
+ guint8 long_term_reference_flag;
+
+ guint8 adaptive_ref_pic_marking_mode_flag;
+ GstH264RefPicMarking ref_pic_marking[10];
+ guint8 n_ref_pic_marking;
+};
+
+
+struct _GstH264SliceHdr
+{
+ guint32 first_mb_in_slice;
+ guint32 type;
+ GstH264PPS *pps;
+
+ /* if seq->separate_colour_plane_flag */
+ guint8 colour_plane_id;
+
+ guint16 frame_num;
+
+ guint8 field_pic_flag;
+ guint8 bottom_field_flag;
+
+ /* if nal_unit.type == 5 */
+ guint16 idr_pic_id;
+
+ /* if seq->pic_order_cnt_type == 0 */
+ guint16 pic_order_cnt_lsb;
+ /* if seq->pic_order_present_flag && !field_pic_flag */
+ gint32 delta_pic_order_cnt_bottom;
+
+ gint32 delta_pic_order_cnt[2];
+ guint8 redundant_pic_cnt;
+
+ /* if slice_type == B_SLICE */
+ guint8 direct_spatial_mv_pred_flag;
+
+ guint8 num_ref_idx_l0_active_minus1;
+ guint8 num_ref_idx_l1_active_minus1;
+
+ GstH264PredWeightTable pred_weight_table;
+ /* if nal_unit.ref_idc != 0 */
+ GstH264DecRefPicMarking dec_ref_pic_marking;
+
+ /* calculated values */
+ guint32 max_pic_num;
+ gboolean valid;
+};
+
+
+struct _GstH264ClockTimestamp
+{
+ guint8 ct_type;
+ guint8 nuit_field_based_flag;
+ guint8 counting_type;
+ guint8 discontinuity_flag;
+ guint8 cnt_dropped_flag;
+ guint8 n_frames;
+
+ guint8 seconds_flag;
+ guint8 seconds_value;
+
+ guint8 minutes_flag;
+ guint8 minutes_value;
+
+ guint8 hours_flag;
+ guint8 hours_value;
+
+ guint32 time_offset;
+};
+
+struct _GstH264PicTiming
+{
+ guint32 cpb_removal_delay;
+ guint32 dpb_output_delay;
+
+ guint8 pic_struct_present_flag;
+ /* if pic_struct_present_flag */
+ guint8 pic_struct;
+
+ guint8 clock_timestamp_flag[3];
+ GstH264ClockTimestamp clock_timestamp[3];
+};
+
+struct _GstH264BufferingPeriod
+{
+ GstH264SPS *sps;
+
+ /* seq->vui_parameters->nal_hrd_parameters_present_flag */
+ guint8 nal_initial_cpb_removal_delay[32];
+ guint8 nal_initial_cpb_removal_delay_offset[32];
+
+ /* seq->vui_parameters->vcl_hrd_parameters_present_flag */
+ guint8 vcl_initial_cpb_removal_delay[32];
+ guint8 vcl_initial_cpb_removal_delay_offset[32];
+};
+
+struct _GstH264SEIMessage
+{
+ GstH264SEIPayloadType payloadType;
+
+ union {
+ GstH264BufferingPeriod buffering_period;
+ GstH264PicTiming pic_timing;
+ /* ... could implement more */
+ };
+};
+
+/* Opaque structure */
+struct _GstH264NalParser
+{
+ GstH264SPS sps[GST_H264_MAX_SPS_COUNT];
+ GstH264PPS pps[GST_H264_MAX_PPS_COUNT];
+ GstH264SPS *last_sps;
+ GstH264PPS *last_pps;
+};
+
+GstH264NalParser *gst_h264_nal_parser_new (void);
+
+GstH264ParserResult gst_h264_parser_identify_nalu (GstH264NalParser *nalparser,
+ const guint8 *data, guint offset,
+ gsize size, GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_identify_nalu_avc (GstH264NalParser *nalparser, const guint8 *data,
+ guint offset, gsize size, guint8 nal_length_size,
+ GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_parse_nal (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu);
+
+GstH264ParserResult gst_h264_parser_parse_slice_hdr (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
+ GstH264SliceHdr *slice, gboolean parse_pred_weight_table,
+ gboolean parse_dec_ref_pic_marking);
+
+GstH264ParserResult gst_h264_parser_parse_sps (GstH264NalParser *nalparser, GstH264NalUnit *nalu,
+ GstH264SPS *sps, gboolean parse_vui_params);
+
+GstH264ParserResult gst_h264_parser_parse_pps (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264PPS *pps);
+
+GstH264ParserResult gst_h264_parser_parse_sei (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264SEIMessage *sei);
+
+void gst_h264_nal_parser_free (GstH264NalParser *nalparser);
+
+GstH264ParserResult gst_h264_parse_sps (GstH264NalUnit *nalu,
+ GstH264SPS *sps, gboolean parse_vui_params);
+
+GstH264ParserResult gst_h264_parse_pps (GstH264NalParser *nalparser,
+ GstH264NalUnit *nalu, GstH264PPS *pps);
+
+G_END_DECLS
+#endif
diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
index 8528eb235..47bd813c9 100644
--- a/tests/check/Makefile.am
+++ b/tests/check/Makefile.am
@@ -184,6 +184,7 @@ check_PROGRAMS = \
$(check_mimic) \
elements/rtpmux \
libs/mpegvideoparser \
+ libs/h264parser \
$(check_schro) \
$(check_vp8) \
elements/viewfinderbin \
@@ -224,6 +225,15 @@ libs_mpegvideoparser_LDADD = \
$(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+libs_h264parser_CFLAGS = \
+ $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+libs_h264parser_LDADD = \
+ $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \
+ $(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \
+ $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
elements_voaacenc_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
diff --git a/tests/check/libs/h264parser.c b/tests/check/libs/h264parser.c
new file mode 100644
index 000000000..15bc7ec92
--- /dev/null
+++ b/tests/check/libs/h264parser.c
@@ -0,0 +1,182 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <gst/check/gstcheck.h>
+#include <gst/codecparsers/gsth264parser.h>
+
+static guint8 slice_dpa[] = {
+ 0x00, 0x00, 0x01, 0x02, 0x00, 0x02, 0x01, 0x03, 0x00,
+ 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00,
+ 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00,
+ 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00,
+ 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00,
+ 0x1d, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00,
+ 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x28, 0x00,
+ 0x29, 0x00, 0x2a, 0x00, 0x2b, 0x00, 0x2c, 0x00, 0x2d, 0x00, 0x2e, 0x00,
+ 0x2f, 0x00, 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00,
+ 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00,
+ 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x40, 0x00,
+ 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00,
+ 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00,
+ 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00,
+ 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00,
+ 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00,
+ 0x5f, 0x00, 0x60, 0x00, 0x61, 0x01, 0x04, 0x00, 0xc4, 0x00, 0xa6, 0x00,
+ 0xc5, 0x00, 0xab, 0x00, 0x82, 0x00, 0xc2, 0x00, 0xd8, 0x00, 0xc6, 0x00,
+ 0xe4, 0x00, 0xbe, 0x00, 0xb0, 0x00, 0xe6, 0x00, 0xb6, 0x00, 0xb7, 0x00,
+ 0xb4, 0x00, 0xb5, 0x00, 0x87, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xd9, 0x00,
+ 0x8c, 0x00, 0xe5, 0x00, 0xbf, 0x00, 0xb1, 0x00, 0xe7, 0x00, 0xbb, 0x00,
+ 0xa3, 0x00, 0x84, 0x00, 0x85, 0x00, 0xbd, 0x00, 0x96, 0x00, 0xe8, 0x00,
+ 0x86, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x9d, 0x00, 0xa9, 0x00, 0x8a, 0x01,
+ 0x05, 0x00, 0x83, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0x8d, 0x00, 0x97, 0x00,
+ 0x88, 0x00, 0xde, 0x00, 0xf1, 0x00, 0x9e, 0x00, 0xaa, 0x00, 0xf5, 0x00,
+ 0xf4, 0x00, 0xf6, 0x00, 0xa2, 0x00, 0xad, 0x00, 0xc9, 0x00, 0xc7, 0x00,
+ 0xae, 0x00, 0x62, 0x00, 0x63, 0x00, 0x90, 0x00, 0x64, 0x00, 0xcb, 0x00,
+ 0x65, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xcd, 0x00,
+ 0xce, 0x00, 0xe9, 0x00, 0x66, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xd1, 0x00,
+ 0xaf, 0x00, 0x67, 0x00, 0x91, 0x00, 0xd6, 0x00, 0xd4, 0x00, 0xd5, 0x00,
+ 0x68, 0x00, 0xeb, 0x00, 0xed, 0x00, 0x89, 0x00, 0x6a, 0x00, 0x69, 0x00,
+ 0x6b, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x6e, 0x00, 0xa0, 0x00, 0x6f, 0x00,
+ 0x71, 0x00, 0x70, 0x00, 0x72, 0x00, 0x73, 0x00, 0x75, 0x00, 0x74, 0x00,
+ 0x76, 0x00, 0x77, 0x00, 0xea, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x79, 0x00,
+ 0x7b, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0xa1, 0x00, 0x7f, 0x00, 0x7e, 0x00,
+ 0x80, 0x00, 0x81, 0x00, 0xec, 0x00, 0xee, 0x00, 0xba, 0x01, 0x06, 0x00,
+ 0xef, 0x00, 0xe1, 0x00, 0xe0, 0x00, 0xdc, 0x01, 0x07, 0x01, 0x08, 0x01,
+ 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x00, 0xdb, 0x00, 0xe2, 0x01,
+ 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x00,
+ 0xdf, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x00,
+ 0xfd, 0x00, 0xff, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1a, 0x01, 0x1b, 0x01,
+ 0x1c, 0x01, 0x1d, 0x01, 0x1e, 0x01, 0x1f, 0x01, 0x20, 0x01, 0x21, 0x01,
+ 0x22, 0x01, 0x23, 0x01, 0x24, 0x01, 0x25, 0x01, 0x26, 0x00, 0xfe, 0x01,
+ 0x00, 0x01, 0x27, 0x01, 0x28, 0x01, 0x29, 0x01, 0x2a, 0x01, 0x2b, 0x01,
+ 0x2c, 0x01, 0x2d, 0x01, 0x2e, 0x01, 0x2f, 0x01, 0x30, 0x01, 0x31, 0x00,
+ 0xe3, 0x00, 0xd7, 0x01, 0x32, 0x00, 0xf8, 0x00, 0xf9, 0x01, 0x33, 0x01,
+ 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, 0x01, 0x38, 0x01, 0x39, 0x01,
+ 0x3a, 0x01, 0x3b, 0x01, 0x3c, 0x01, 0x3d, 0x01, 0x3e, 0x01, 0x3f, 0x01,
+ 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, 0x44, 0x01, 0x45, 0x01,
+ 0x46, 0x01, 0x47, 0x01, 0x48, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4b, 0x01,
+ 0x4c, 0x00, 0x08, 0x05, 0x2e, 0x6e, 0x75, 0x6c, 0x6c, 0x0c, 0x76, 0x69,
+ 0x73, 0x69, 0x62, 0x6c, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x04, 0x45,
+ 0x75, 0x72, 0x6f, 0x06, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x62,
+ 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x74, 0x68, 0x06, 0x53, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x54, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06,
+ 0x5a, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x73, 0x61, 0x63, 0x75, 0x74,
+ 0x65, 0x06, 0x74, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x7a, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0x07, 0x41, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07,
+ 0x61, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x0c, 0x73, 0x63, 0x6f, 0x6d,
+ 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x53, 0x63, 0x6f,
+ 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x5a, 0x64,
+ 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x4c, 0x63, 0x61,
+ 0x72, 0x6f, 0x6e, 0x06, 0x6c, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0a, 0x7a,
+ 0x64, 0x6f, 0x74, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x52, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x41, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06,
+ 0x4c, 0x61, 0x63, 0x75, 0x74, 0x65, 0x07, 0x45, 0x6f, 0x67, 0x6f, 0x6e,
+ 0x65, 0x6b, 0x06, 0x45, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x44, 0x63,
+ 0x61, 0x72, 0x6f, 0x6e, 0x07, 0x44, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e,
+ 0x06, 0x4e, 0x61, 0x63, 0x75, 0x74, 0x65, 0x06, 0x4e, 0x63, 0x61, 0x72,
+ 0x6f, 0x6e, 0x0d, 0x4f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d,
+ 0x6c, 0x61, 0x75, 0x74, 0x06, 0x52, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05,
+ 0x55, 0x72, 0x69, 0x6e, 0x67, 0x09, 0x6e, 0x75, 0x6e, 0x67, 0x61, 0x64,
+ 0x65, 0x73, 0x68, 0x0d, 0x55, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75,
+ 0x6d, 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x54, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x06, 0x72, 0x61, 0x63, 0x75, 0x74,
+ 0x65, 0x06, 0x61, 0x62, 0x72, 0x65, 0x76, 0x65, 0x06, 0x6c, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0x07, 0x65, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x06,
+ 0x65, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x06, 0x64, 0x63, 0x61, 0x72, 0x6f,
+ 0x6e, 0x07, 0x64, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x06, 0x6e, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0x06, 0x6e, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x0d,
+ 0x6f, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d, 0x6c, 0x61, 0x75,
+ 0x74, 0x06, 0x72, 0x63, 0x61, 0x72, 0x6f, 0x6e, 0x05, 0x75, 0x72, 0x69,
+ 0x6e, 0x67, 0x0d, 0x75, 0x68, 0x75, 0x6e, 0x67, 0x61, 0x72, 0x75, 0x6d,
+ 0x6c, 0x61, 0x75, 0x74, 0x0c, 0x74, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0a, 0x49, 0x64, 0x6f, 0x74, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x52, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x72, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6f, 0x67, 0x6f, 0x6e,
+ 0x65, 0x6b, 0x07, 0x41, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x45,
+ 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x45, 0x64, 0x6f, 0x74, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x47, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4b, 0x63, 0x6f, 0x6d, 0x6d,
+ 0x61, 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x49, 0x6d, 0x61, 0x63,
+ 0x72, 0x6f, 0x6e, 0x0c, 0x4c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x4e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x4f, 0x6d, 0x61, 0x63, 0x72, 0x6f,
+ 0x6e, 0x07, 0x55, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x55, 0x6d,
+ 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x69, 0x6f, 0x67, 0x6f, 0x6e, 0x65,
+ 0x6b, 0x07, 0x61, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x07, 0x65, 0x6d,
+ 0x61, 0x63, 0x72, 0x6f, 0x6e, 0x0a, 0x65, 0x64, 0x6f, 0x74, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x67, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61,
+ 0x63, 0x63, 0x65, 0x6e, 0x74, 0x0c, 0x6b, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+ 0x61, 0x63, 0x63, 0x65, 0x6e, 0x74, 0x07, 0x69, 0x6d, 0x61, 0x63, 0x72,
+ 0x6f, 0x6e, 0x0c, 0x6c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63, 0x63,
+ 0x65, 0x6e, 0x74, 0x0c, 0x6e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x61, 0x63,
+ 0x63, 0x65, 0x6e, 0x74, 0x07, 0x6f, 0x6d, 0x61, 0x63, 0x72, 0x6f, 0x6e,
+ 0x07, 0x75, 0x6f, 0x67, 0x6f, 0x6e, 0x65, 0x6b, 0x07, 0x75, 0x6d, 0x61,
+ 0x63, 0x72, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02
+};
+
+GST_START_TEST (test_h264_parse_slice_dpa)
+{
+ GstH264ParserResult res;
+ GstH264NalUnit nalu;
+
+ GstH264NalParser *parser = gst_h264_nal_parser_new ();
+
+ res = gst_h264_parser_identify_nalu (parser, slice_dpa, 0,
+ sizeof (slice_dpa), &nalu);
+
+ assert_equals_int (res, GST_H264_PARSER_OK);
+ assert_equals_int (nalu.type, GST_H264_NAL_SLICE_DPA);
+
+ g_free (parser);
+}
+
+GST_END_TEST;
+
+static Suite *
+h264parser_suite (void)
+{
+ Suite *s = suite_create ("H264 Parser library");
+
+ TCase *tc_chain = tcase_create ("general");
+
+ suite_add_tcase (s, tc_chain);
+ tcase_add_test (tc_chain, test_h264_parse_slice_dpa);
+
+ return s;
+}
+
+int
+main (int argc, char **argv)
+{
+ int nf;
+
+ Suite *s = h264parser_suite ();
+
+ SRunner *sr = srunner_create (s);
+
+ gst_check_init (&argc, &argv);
+
+ srunner_run_all (sr, CK_NORMAL);
+ nf = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return nf;
+}