diff options
author | Thibault Saunier <thibault.saunier@collabora.com> | 2011-07-29 10:56:15 +0200 |
---|---|---|
committer | Thibault Saunier <thibault.saunier@collabora.com> | 2011-08-31 09:15:46 -0300 |
commit | f6e8467111e96291dc764927e383cec2076bf871 (patch) | |
tree | c44fc5a1010ce135ff350282187d9bf35fe658a3 | |
parent | ad7028d1ddc567ed52634eb80966e22a29384ca7 (diff) |
codecparsers: h264: Add an h.264 bitstream parsing library
-rw-r--r-- | docs/libs/gst-plugins-bad-libs-docs.sgml | 1 | ||||
-rw-r--r-- | docs/libs/gst-plugins-bad-libs-sections.txt | 44 | ||||
-rw-r--r-- | docs/libs/gst-plugins-bad-libs.types | 1 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/Makefile.am | 5 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/gsth264parser.c | 1808 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/gsth264parser.h | 657 | ||||
-rw-r--r-- | tests/check/Makefile.am | 10 | ||||
-rw-r--r-- | tests/check/libs/h264parser.c | 182 |
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; +} |