summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <thibault.saunier@collabora.com>2011-08-02 12:37:02 +0200
committerThibault Saunier <thibault.saunier@collabora.com>2011-08-31 09:18:16 -0300
commit3052147bf500edd1e15851765119d7c8e973e15b (patch)
treed7f0dab0997147cd6a505dd3e50dae1d693f0c97
parentf6e8467111e96291dc764927e383cec2076bf871 (diff)
h264parse: Port to the new h.264 parsing library
-rw-r--r--gst/videoparsers/Makefile.am6
-rw-r--r--gst/videoparsers/gsth264parse.c602
-rw-r--r--gst/videoparsers/gsth264parse.h34
-rw-r--r--gst/videoparsers/h264parse.c1046
-rw-r--r--gst/videoparsers/h264parse.h186
5 files changed, 456 insertions, 1418 deletions
diff --git a/gst/videoparsers/Makefile.am b/gst/videoparsers/Makefile.am
index 4fa87b8a7..811d5f860 100644
--- a/gst/videoparsers/Makefile.am
+++ b/gst/videoparsers/Makefile.am
@@ -2,9 +2,8 @@ plugin_LTLIBRARIES = libgstvideoparsersbad.la
libgstvideoparsersbad_la_SOURCES = plugin.c \
h263parse.c gsth263parse.c \
- gsth264parse.c h264parse.c \
gstdiracparse.c dirac_parse.c \
- gstmpegvideoparse.c
+ gsth264parse.c gstmpegvideoparse.c
libgstvideoparsersbad_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
@@ -16,9 +15,8 @@ libgstvideoparsersbad_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gsth263parse.h h263parse.h \
- gsth264parse.h h264parse.h \
gstdiracparse.h dirac_parse.h \
- gstmpegvideoparse.h
+ gsth264parse.h gstmpegvideoparse.h
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c
index 089b5a787..875f04f96 100644
--- a/gst/videoparsers/gsth264parse.c
+++ b/gst/videoparsers/gsth264parse.c
@@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Collabora ltd
* Copyright (C) <2010> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
+ *
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * 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
@@ -163,9 +166,14 @@ gst_h264_parse_finalize (GObject * object)
static void
gst_h264_parse_reset_frame (GstH264Parse * h264parse)
{
+ GST_DEBUG_OBJECT (h264parse, "reset frame");
+
/* done parsing; reset state */
- h264parse->last_nal_pos = 0;
- h264parse->next_sc_pos = 0;
+ h264parse->nalu.valid = FALSE;
+ h264parse->nalu.offset = 0;
+ h264parse->nalu.size = 0;
+ h264parse->current_off = 0;
+
h264parse->picture_start = FALSE;
h264parse->update_caps = FALSE;
h264parse->idr_pos = -1;
@@ -202,7 +210,13 @@ gst_h264_parse_start (GstBaseParse * parse)
GST_DEBUG_OBJECT (parse, "start");
gst_h264_parse_reset (h264parse);
- gst_h264_params_create (&h264parse->params, GST_ELEMENT (h264parse));
+ h264parse->nalparser = gst_h264_nal_parser_new ();
+
+ h264parse->dts = GST_CLOCK_TIME_NONE;
+ h264parse->ts_trn_nb = GST_CLOCK_TIME_NONE;
+ h264parse->sei_pic_struct_pres_flag = FALSE;
+ h264parse->sei_pic_struct = 0;
+ h264parse->field_pic_flag = 0;
gst_base_parse_set_min_frame_size (parse, 6);
@@ -212,13 +226,19 @@ gst_h264_parse_start (GstBaseParse * parse)
static gboolean
gst_h264_parse_stop (GstBaseParse * parse)
{
+ guint i;
GstH264Parse *h264parse = GST_H264_PARSE (parse);
GST_DEBUG_OBJECT (parse, "stop");
gst_h264_parse_reset (h264parse);
- gst_h264_params_free (h264parse->params);
- h264parse->params = NULL;
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++)
+ gst_buffer_replace (&h264parse->sps_nals[i], NULL);
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++)
+ gst_buffer_replace (&h264parse->pps_nals[i], NULL);
+
+ g_free (h264parse->nalparser);
+ h264parse->nalparser = NULL;
return TRUE;
}
@@ -318,6 +338,8 @@ gst_h264_parse_wrap_nal (GstH264Parse * h264parse, guint format, guint8 * data,
GstBuffer *buf;
const guint nl = h264parse->nal_length_size;
+ GST_DEBUG ("Nal length %d %d", size, h264parse->nal_length_size);
+
buf = gst_buffer_new_and_alloc (size + nl + 4);
if (format == GST_H264_PARSE_FORMAT_AVC) {
GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), size << (32 - 8 * nl));
@@ -332,65 +354,158 @@ gst_h264_parse_wrap_nal (GstH264Parse * h264parse, guint format, guint8 * data,
return buf;
}
+static void
+gst_h264_parser_store_nal (GstH264Parse * h264parse, guint id,
+ GstH264NalUnitType naltype, GstH264NalUnit * nalu)
+{
+ GstBuffer *buf, **store;
+ guint size = nalu->size, store_size;
+
+ if (naltype == GST_H264_NAL_SPS) {
+ store_size = GST_H264_MAX_SPS_COUNT;
+ store = h264parse->sps_nals;
+ GST_DEBUG ("Storing sps %u", id);
+ } else if (naltype == GST_H264_NAL_PPS) {
+ store_size = GST_H264_MAX_PPS_COUNT;
+ store = h264parse->pps_nals;
+ GST_DEBUG ("Storing pps %u", id);
+ } else
+ return;
+
+ if (id >= store_size) {
+ GST_DEBUG_OBJECT (h264parse, "unable to store nal, id out-of-range %d", id);
+ return;
+ }
+
+ buf = gst_buffer_new_and_alloc (size);
+ memcpy (GST_BUFFER_DATA (buf), nalu->data + nalu->offset, size);
+
+ if (store[id])
+ gst_buffer_unref (store[id]);
+
+ store[id] = buf;
+}
+
/* SPS/PPS/IDR considered key, all others DELTA;
* so downstream waiting for keyframe can pick up at SPS/PPS/IDR */
#define NAL_TYPE_IS_KEY(nt) (((nt) == 5) || ((nt) == 7) || ((nt) == 8))
/* caller guarantees 2 bytes of nal payload */
static void
-gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
- gint sc_pos, gint nal_pos, guint nal_size)
+gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
{
guint nal_type;
+ GstH264SliceHdr slice;
+ GstH264PPS pps;
+ GstH264SPS sps;
+ GstH264SEIMessage sei;
+
+ gboolean slcparsed = FALSE;
+ GstH264NalParser *nalparser = h264parse->nalparser;
- g_return_if_fail (nal_pos - sc_pos > 0 && nal_pos - sc_pos <= 4);
/* nothing to do for broken input */
- if (G_UNLIKELY (nal_size < 2)) {
- GST_DEBUG_OBJECT (h264parse, "not processing nal size %u", nal_size);
+ if (G_UNLIKELY (nalu->size < 2)) {
+ GST_DEBUG_OBJECT (h264parse, "not processing nal size %u", nalu->size);
return;
}
- /* lower layer collects params */
- gst_h264_params_parse_nal (h264parse->params, data + nal_pos, nal_size);
-
/* we have a peek as well */
- nal_type = data[nal_pos] & 0x1f;
+ nal_type = nalu->type;
h264parse->keyframe |= NAL_TYPE_IS_KEY (nal_type);
+ GST_DEBUG_OBJECT (h264parse, "processing nal of type %u, size %u",
+ nal_type, nalu->size);
+
switch (nal_type) {
- case NAL_SPS:
- case NAL_PPS:
+ case GST_H264_NAL_SPS:
+ gst_h264_parser_parse_sps (nalparser, nalu, &sps, TRUE);
+
+ GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
+ h264parse->update_caps = TRUE;
+ /* found in stream, no need to forcibly push at start */
+ h264parse->push_codec = FALSE;
+
+ gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu);
+ break;
+ case GST_H264_NAL_PPS:
+ gst_h264_parser_parse_pps (nalparser, nalu, &pps);
/* parameters might have changed, force caps check */
GST_DEBUG_OBJECT (h264parse, "triggering src caps check");
h264parse->update_caps = TRUE;
/* found in stream, no need to forcibly push at start */
h264parse->push_codec = FALSE;
+
+ gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
break;
- case NAL_SLICE:
- case NAL_SLICE_DPA:
- case NAL_SLICE_DPB:
- case NAL_SLICE_DPC:
+ case GST_H264_NAL_SEI:
+ gst_h264_parser_parse_sei (nalparser, nalu, &sei);
+ switch (sei.payloadType) {
+ case GST_H264_SEI_PIC_TIMING:
+ h264parse->sei_pic_struct_pres_flag =
+ sei.pic_timing.pic_struct_present_flag;
+ h264parse->sei_cpb_removal_delay = sei.pic_timing.cpb_removal_delay;
+ if (h264parse->sei_pic_struct_pres_flag)
+ h264parse->sei_pic_struct = sei.pic_timing.pic_struct;
+ break;
+ case GST_H264_SEI_BUF_PERIOD:
+ if (h264parse->ts_trn_nb == GST_CLOCK_TIME_NONE ||
+ h264parse->dts == GST_CLOCK_TIME_NONE)
+ h264parse->ts_trn_nb = 0;
+ else
+ h264parse->ts_trn_nb = h264parse->dts;
+
+ GST_LOG_OBJECT (h264parse,
+ "new buffering period; ts_trn_nb updated: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (h264parse->ts_trn_nb));
+ break;
+ }
+ break;
+
+ case GST_H264_NAL_SLICE:
+ case GST_H264_NAL_SLICE_DPA:
+ case GST_H264_NAL_SLICE_DPB:
+ case GST_H264_NAL_SLICE_DPC:
+ slcparsed = TRUE;
+ if (gst_h264_parser_parse_slice_hdr (nalparser, nalu,
+ &slice, FALSE, FALSE) == GST_H264_PARSER_ERROR)
+ return;
+
/* real frame data */
- h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0);
+ h264parse->frame_start |= (slice.first_mb_in_slice == 0);
/* if we need to sneak codec NALs into the stream,
* this is a good place, so fake it as IDR
* (which should be at start anyway) */
+ GST_DEBUG ("Frame start: %i first_mb_in_slice %i", h264parse->frame_start,
+ slice.first_mb_in_slice);
if (G_LIKELY (!h264parse->push_codec))
break;
/* fall-through */
- case NAL_SLICE_IDR:
+ case GST_H264_NAL_SLICE_IDR:
+ if (!slcparsed) {
+ if (gst_h264_parser_parse_slice_hdr (nalparser, nalu,
+ &slice, FALSE, FALSE) == GST_H264_PARSER_ERROR)
+ return;
+ GST_DEBUG ("Frame start: %i first_mb_in_slice %i",
+ h264parse->frame_start, slice.first_mb_in_slice);
+ }
/* real frame data */
- h264parse->frame_start |= (h264parse->params->first_mb_in_slice == 0);
+ h264parse->frame_start |= (slice.first_mb_in_slice == 0);
+
/* mark where config needs to go if interval expired */
/* mind replacement buffer if applicable */
if (h264parse->format == GST_H264_PARSE_FORMAT_AVC)
h264parse->idr_pos = gst_adapter_available (h264parse->frame_out);
else
- h264parse->idr_pos = sc_pos;
+ h264parse->idr_pos = nalu->offset - 4;
GST_DEBUG_OBJECT (h264parse, "marking IDR in frame at offset %d",
h264parse->idr_pos);
+
+ GST_DEBUG ("first MB: %u, slice type: %u", slice.first_mb_in_slice,
+ slice.type);
break;
+ default:
+ gst_h264_parser_parse_nal (nalparser, nalu);
}
/* if AVC output needed, collect properly prefixed nal in adapter,
@@ -400,7 +515,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
GST_LOG_OBJECT (h264parse, "collecting NAL in AVC frame");
buf = gst_h264_parse_wrap_nal (h264parse, h264parse->format,
- data + nal_pos, nal_size);
+ nalu->data + nalu->offset, nalu->size);
gst_adapter_push (h264parse->frame_out, buf);
}
}
@@ -408,21 +523,31 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, guint8 * data,
/* caller guarantees at least 2 bytes of nal payload for each nal
* returns TRUE if next_nal indicates that nal terminates an AU */
static inline gboolean
-gst_h264_parse_collect_nal (GstH264Parse * h264parse, guint8 * nal,
- guint8 * next_nal)
+gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
+ guint size, GstH264NalUnit * nalu)
{
- gint nal_type;
gboolean complete;
+ GstH264ParserResult parse_res;
+ GstH264NalUnitType nal_type = nalu->type;
+ GstH264NalUnit nnalu;
+
+ GST_DEBUG ("Parsing collecte nal");
+ parse_res = gst_h264_parser_identify_nalu (h264parse->nalparser, data,
+ nalu->offset + nalu->size, size, &nnalu);
+
+ if (parse_res == GST_H264_PARSER_ERROR)
+ return FALSE;
- if (h264parse->align == GST_H264_PARSE_ALIGN_NAL)
+ if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
return TRUE;
+ }
/* determine if AU complete */
- nal_type = nal[0] & 0x1f;
GST_LOG_OBJECT (h264parse, "nal type: %d", nal_type);
/* coded slice NAL starts a picture,
* i.e. other types become aggregated in front of it */
- h264parse->picture_start |= (nal_type == 1 || nal_type == 2 || nal_type == 5);
+ h264parse->picture_start |= (nal_type == GST_H264_NAL_SLICE ||
+ nal_type == GST_H264_NAL_SLICE_DPA || nal_type == GST_H264_NAL_SLICE_IDR);
/* consider a coded slices (IDR or not) to start a picture,
* (so ending the previous one) if first_mb_in_slice == 0
@@ -431,35 +556,23 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, guint8 * nal,
* but in practice it works in sane cases, needs not much parsing,
* and also works with broken frame_num in NAL
* (where spec-wise would fail) */
- nal_type = next_nal[0] & 0x1f;
+ nal_type = nnalu.type;
+ complete = h264parse->picture_start && (nal_type >= GST_H264_NAL_SEI &&
+ nal_type <= GST_H264_NAL_AU_DELIMITER);
+
GST_LOG_OBJECT (h264parse, "next nal type: %d", nal_type);
- complete = h264parse->picture_start && (nal_type >= 6 && nal_type <= 9);
complete |= h264parse->picture_start &&
- (nal_type == 1 || nal_type == 2 || nal_type == 5) &&
+ (nal_type == GST_H264_NAL_SLICE ||
+ nal_type == GST_H264_NAL_SLICE_DPA ||
+ nal_type == GST_H264_NAL_SLICE_IDR) &&
/* first_mb_in_slice == 0 considered start of frame */
- (next_nal[1] & 0x80);
+ (nnalu.data[nnalu.offset + 1] & 0x80);
GST_LOG_OBJECT (h264parse, "au complete: %d", complete);
return complete;
}
-/* finds next startcode == 00 00 01, along with a subsequent byte */
-static guint
-gst_h264_parse_find_sc (GstBuffer * buffer, guint skip)
-{
- GstByteReader br;
- guint sc_pos = -1;
-
- gst_byte_reader_init_from_buffer (&br, buffer);
-
- /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
- sc_pos = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
- skip, gst_byte_reader_get_remaining (&br) - skip);
-
- return sc_pos;
-}
-
/* FIXME move into baseparse, or anything equivalent;
* see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
#define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x10000
@@ -470,10 +583,11 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
{
GstH264Parse *h264parse = GST_H264_PARSE (parse);
GstBuffer *buffer = frame->buffer;
- gint sc_pos, nal_pos, next_sc_pos, next_nal_pos;
guint8 *data;
- guint size;
+ guint size, current_off = 0;
gboolean drain;
+ GstH264NalParser *nalparser = h264parse->nalparser;
+ GstH264NalUnit nalu = h264parse->nalu;
/* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
@@ -495,105 +609,108 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
- GST_LOG_OBJECT (h264parse, "last_nal_pos: %d, last_scan_pos %d",
- h264parse->last_nal_pos, h264parse->next_sc_pos);
+ drain = GST_BASE_PARSE_DRAINING (parse);
+ current_off = h264parse->current_off;
- nal_pos = h264parse->last_nal_pos;
- next_sc_pos = h264parse->next_sc_pos;
+ GST_DEBUG ("Last parse position %u", current_off);
+ while (TRUE) {
+ switch (gst_h264_parser_identify_nalu (nalparser, data, current_off,
+ size, &nalu)) {
+ case GST_H264_PARSER_OK:
+ GST_DEBUG ("Complete nal found. %u Off: %u, Size: %u",
+ current_off, nalu.offset, nalu.size);
+
+ current_off = nalu.offset + nalu.size;
+ GST_DEBUG ("CURENT OFF. %u, %u", current_off, nalu.offset + nalu.size);
+ if (!h264parse->nalu.size && !h264parse->nalu.valid)
+ h264parse->nalu = nalu;
+ break;
+ case GST_H264_PARSER_BROKEN_LINK:
+ return FALSE;
+ case GST_H264_PARSER_ERROR:
+ current_off = size - 3;
+ goto parsing_error;
+ case GST_H264_PARSER_NO_NAL:
+ current_off = size - 3;
+ goto more;
+ case GST_H264_PARSER_BROKEN_DATA:
+ GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
+ "it contains a NAL unit of length %d", nalu.size);
+
+ /* broken nal at start -> arrange to skip it,
+ * otherwise have it terminate current au
+ * (and so it will be skipped on next frame round) */
+ if (nalu.sc_offset == h264parse->nalu.sc_offset) {
+ *skipsize = nalu.offset;
+
+ GST_DEBUG ("Skiping broken nal");
+ return FALSE;
+ } else {
+ nalu.size = 0;
- if (!next_sc_pos) {
- sc_pos = gst_h264_parse_find_sc (buffer, 0);
+ goto end;
+ }
+ case GST_H264_PARSER_NO_NAL_END:
+ GST_DEBUG ("Not a complete nal found at offset %u", nalu.offset);
+
+ current_off = nalu.sc_offset;
+ /* We keep the reference to this nal so we start over the parsing
+ * here */
+ if (!h264parse->nalu.size && !h264parse->nalu.valid)
+ h264parse->nalu = nalu;
+
+ if (drain) {
+ GST_DEBUG ("Drainning NAL %u %u %u", size, h264parse->nalu.offset,
+ h264parse->nalu.size);
+ /* Can't parse the nalu */
+ if (size - h264parse->nalu.offset < 2) {
+ *skipsize = nalu.offset;
+ return FALSE;
+ }
- if (sc_pos == -1) {
- /* SC not found, need more data */
- sc_pos = GST_BUFFER_SIZE (buffer) - 3;
- /* avoid going < 0 later on */
- nal_pos = next_sc_pos = sc_pos;
- goto more;
+ /* We parse it anyway */
+ nalu.size = size - nalu.offset;
+ break;
+ }
+ goto more;
}
- nal_pos = sc_pos + 3;
- next_sc_pos = nal_pos;
- /* sc might have 2 or 3 0-bytes */
- if (sc_pos > 0 && data[sc_pos - 1] == 00)
- sc_pos--;
- GST_LOG_OBJECT (h264parse, "found sc at offset %d", sc_pos);
- } else {
- /* previous checks already arrange sc at start */
- sc_pos = 0;
- }
+ current_off = nalu.offset + nalu.size;
- drain = GST_BASE_PARSE_DRAINING (parse);
- while (TRUE) {
- gint prev_sc_pos;
-
- next_sc_pos = gst_h264_parse_find_sc (buffer, next_sc_pos);
- if (next_sc_pos == -1) {
- GST_LOG_OBJECT (h264parse, "no next sc");
- if (drain) {
- /* FLUSH/EOS, it's okay if we can't find the next frame */
- next_sc_pos = size;
- next_nal_pos = size;
- } else {
- next_sc_pos = size - 3;
- goto more;
- }
- } else {
- next_nal_pos = next_sc_pos + 3;
- if (data[next_sc_pos - 1] == 00)
- next_sc_pos--;
- GST_LOG_OBJECT (h264parse, "found next sc at offset %d", next_sc_pos);
- /* need at least 1 more byte of next NAL */
- if (!drain && (next_nal_pos == size - 1))
- goto more;
- }
+ GST_DEBUG ("%p Complete nal found. Off: %u, Size: %u", data, nalu.offset,
+ nalu.size);
- /* determine nal's sc position */
- prev_sc_pos = nal_pos - 3;
- g_assert (prev_sc_pos >= 0);
- if (prev_sc_pos > 0 && data[prev_sc_pos - 1] == 0)
- prev_sc_pos--;
-
- /* already consume and gather info from NAL */
- if (G_UNLIKELY (next_sc_pos - nal_pos < 2)) {
- GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
- "it contains a NAL unit of length %d", next_sc_pos - nal_pos);
- /* broken nal at start -> arrange to skip it,
- * otherwise have it terminate current au
- * (and so it will be skippd on next frame round) */
- if (prev_sc_pos == sc_pos) {
- *skipsize = sc_pos + 2;
- return FALSE;
- } else {
- next_sc_pos = prev_sc_pos;
- break;
- }
- }
- gst_h264_parse_process_nal (h264parse, data, prev_sc_pos, nal_pos,
- next_sc_pos - nal_pos);
- if (next_nal_pos >= size - 1 ||
- gst_h264_parse_collect_nal (h264parse, data + nal_pos,
- data + next_nal_pos))
+ gst_h264_parse_process_nal (h264parse, &nalu);
+ if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu) || drain)
break;
-
- /* move along */
- next_sc_pos = nal_pos = next_nal_pos;
}
- *skipsize = sc_pos;
- *framesize = next_sc_pos - sc_pos;
+end:
+ /* FIXME this shouldnt be needed */
+ if (h264parse->nalu.sc_offset > 0 && data[h264parse->nalu.sc_offset - 1] == 0)
+ h264parse->nalu.sc_offset--;
+
+ *skipsize = h264parse->nalu.sc_offset;
+ *framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset; /* CHECKME */
+ h264parse->current_off = current_off;
return TRUE;
+parsing_error:
+ GST_DEBUG ("Error parsing Nal Unit");
more:
+
/* ask for best next available */
*framesize = G_MAXUINT;
+ if (!h264parse->nalu.size) {
+ /* skip up to initial startcode */
+ *skipsize = h264parse->nalu.sc_offset;
+ } else {
+ *skipsize = 0;
+ }
- /* skip up to initial startcode */
- *skipsize = sc_pos;
- /* resume scanning here next time */
- h264parse->last_nal_pos = nal_pos - sc_pos;
- h264parse->next_sc_pos = next_sc_pos - sc_pos;
+ /* Restart parsing from here next time */
+ h264parse->current_off = current_off;
return FALSE;
}
@@ -610,8 +727,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
/* only nal payload in stored nals */
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((nal = h264parse->sps_nals[i])) {
num_sps++;
/* size bytes also count */
sps_size += GST_BUFFER_SIZE (nal) + 2;
@@ -623,8 +740,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
}
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((nal = h264parse->pps_nals[i])) {
num_pps++;
/* size bytes also count */
pps_size += GST_BUFFER_SIZE (nal) + 2;
@@ -648,8 +765,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
data[5] = 0xe0 | num_sps; /* number of SPSs */
data += 6;
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((nal = h264parse->sps_nals[i])) {
GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal));
memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal));
data += 2 + GST_BUFFER_SIZE (nal);
@@ -658,8 +775,8 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
data[0] = num_pps;
data++;
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((nal = h264parse->pps_nals[i])) {
GST_WRITE_UINT16_BE (data, GST_BUFFER_SIZE (nal));
memcpy (data + 2, GST_BUFFER_DATA (nal), GST_BUFFER_SIZE (nal));
data += 2 + GST_BUFFER_SIZE (nal);
@@ -672,7 +789,7 @@ gst_h264_parse_make_codec_data (GstH264Parse * h264parse)
static void
gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
{
- GstH264ParamsSPS *sps;
+ GstH264SPS *sps;
GstCaps *sink_caps;
gboolean modified = FALSE;
GstBuffer *buf = NULL;
@@ -695,7 +812,7 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
else
sink_caps = gst_caps_new_simple ("video/x-h264", NULL);
- sps = h264parse->params->sps;
+ sps = h264parse->nalparser->last_sps;
GST_DEBUG_OBJECT (h264parse, "sps: %p", sps);
/* only codec-data for nice-and-clean au aligned packetized avc format */
@@ -764,6 +881,134 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
gst_buffer_unref (buf);
}
+static void
+gst_h264_parse_get_timestamp (GstH264Parse * h264parse,
+ GstClockTime * out_ts, GstClockTime * out_dur, gboolean frame)
+{
+ GstH264SPS *sps = h264parse->nalparser->last_sps;
+ GstClockTime upstream;
+ gint duration = 1;
+
+ g_return_if_fail (out_dur != NULL);
+ g_return_if_fail (out_ts != NULL);
+
+ upstream = *out_ts;
+
+ if (!frame) {
+ GST_LOG_OBJECT (h264parse, "no frame data -> 0 duration");
+ *out_dur = 0;
+ goto exit;
+ } else {
+ *out_ts = upstream;
+ }
+
+ if (!sps) {
+ GST_DEBUG_OBJECT (h264parse, "referred SPS invalid");
+ goto exit;
+ } else if (!sps->vui_parameters.timing_info_present_flag) {
+ GST_DEBUG_OBJECT (h264parse,
+ "unable to compute timestamp: timing info not present");
+ goto exit;
+ } else if (sps->vui_parameters.time_scale == 0) {
+ GST_DEBUG_OBJECT (h264parse,
+ "unable to compute timestamp: time_scale = 0 "
+ "(this is forbidden in spec; bitstream probably contains error)");
+ goto exit;
+ }
+
+ if (h264parse->sei_pic_struct_pres_flag &&
+ h264parse->sei_pic_struct != (guint8) - 1) {
+ /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
+ * are ways to infer its value. This is related to computing the
+ * TopFieldOrderCnt and BottomFieldOrderCnt, which looks
+ * complicated and thus not implemented for the time being. Yet
+ * the value we have here is correct for many applications
+ */
+ switch (h264parse->sei_pic_struct) {
+ case GST_H264_SEI_PIC_STRUCT_TOP_FIELD:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD:
+ duration = 1;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME:
+ case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP:
+ duration = 2;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+ case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+ duration = 3;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING:
+ duration = 4;
+ break;
+ case GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING:
+ duration = 6;
+ break;
+ default:
+ GST_DEBUG_OBJECT (h264parse,
+ "h264parse->sei_pic_struct of unknown value %d. Not parsed",
+ h264parse->sei_pic_struct);
+ break;
+ }
+ } else {
+ duration = h264parse->field_pic_flag ? 1 : 2;
+ }
+
+ GST_LOG_OBJECT (h264parse, "frame tick duration %d", duration);
+
+ /*
+ * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
+ * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
+ * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
+ * where
+ * Tc = num_units_in_tick / time_scale
+ */
+
+ if (h264parse->ts_trn_nb != GST_CLOCK_TIME_NONE) {
+ GST_LOG_OBJECT (h264parse, "buffering based ts");
+ /* buffering period is present */
+ if (upstream != GST_CLOCK_TIME_NONE) {
+ /* If upstream timestamp is valid, we respect it and adjust current
+ * reference point */
+ h264parse->ts_trn_nb = upstream -
+ (GstClockTime) gst_util_uint64_scale_int
+ (h264parse->sei_cpb_removal_delay * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick,
+ sps->vui_parameters.time_scale);
+ } else {
+ /* If no upstream timestamp is given, we write in new timestamp */
+ upstream = h264parse->dts = h264parse->ts_trn_nb +
+ (GstClockTime) gst_util_uint64_scale_int
+ (h264parse->sei_cpb_removal_delay * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick,
+ sps->vui_parameters.time_scale);
+ }
+ } else {
+ GstClockTime dur;
+
+ GST_LOG_OBJECT (h264parse, "duration based ts");
+ /* naive method: no removal delay specified
+ * track upstream timestamp and provide best guess frame duration */
+ dur = gst_util_uint64_scale_int (duration * GST_SECOND,
+ sps->vui_parameters.num_units_in_tick, sps->vui_parameters.time_scale);
+ /* sanity check */
+ if (dur < GST_MSECOND) {
+ GST_DEBUG_OBJECT (h264parse, "discarding dur %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (dur));
+ } else {
+ *out_dur = dur;
+ }
+ }
+
+exit:
+ if (GST_CLOCK_TIME_IS_VALID (upstream))
+ *out_ts = h264parse->dts = upstream;
+
+ if (GST_CLOCK_TIME_IS_VALID (*out_dur) &&
+ GST_CLOCK_TIME_IS_VALID (h264parse->dts))
+ h264parse->dts += *out_dur;
+}
+
static GstFlowReturn
gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
{
@@ -776,7 +1021,7 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_h264_parse_update_src_caps (h264parse, NULL);
- gst_h264_params_get_timestamp (h264parse->params,
+ gst_h264_parse_get_timestamp (h264parse,
&GST_BUFFER_TIMESTAMP (buffer), &GST_BUFFER_DURATION (buffer),
h264parse->frame_start);
@@ -864,16 +1109,16 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
/* send separate config NAL buffers */
GST_DEBUG_OBJECT (h264parse, "- sending SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((codec_nal = h264parse->sps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "sending SPS nal");
gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
timestamp);
h264parse->last_report = new_ts;
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((codec_nal = h264parse->pps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "sending PPS nal");
gst_h264_parse_push_codec_buffer (h264parse, codec_nal,
timestamp);
@@ -890,8 +1135,8 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
gst_byte_writer_put_data (&bw, GST_BUFFER_DATA (buffer),
h264parse->idr_pos);
GST_DEBUG_OBJECT (h264parse, "- inserting SPS/PPS");
- for (i = 0; i < MAX_SPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->sps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_SPS_COUNT; i++) {
+ if ((codec_nal = h264parse->sps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "inserting SPS nal");
gst_byte_writer_put_uint32_be (&bw,
bs ? 1 : GST_BUFFER_SIZE (codec_nal));
@@ -900,8 +1145,8 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
h264parse->last_report = new_ts;
}
}
- for (i = 0; i < MAX_PPS_COUNT; i++) {
- if ((codec_nal = h264parse->params->pps_nals[i])) {
+ for (i = 0; i < GST_H264_MAX_PPS_COUNT; i++) {
+ if ((codec_nal = h264parse->pps_nals[i])) {
GST_DEBUG_OBJECT (h264parse, "inserting PPS nal");
gst_byte_writer_put_uint32_be (&bw,
bs ? 1 : GST_BUFFER_SIZE (codec_nal));
@@ -937,7 +1182,9 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
GstStructure *str;
const GValue *value;
GstBuffer *codec_data = NULL;
- guint size, format, align;
+ guint size, format, align, off;
+ GstH264NalUnit nalu;
+ GstH264ParserResult parseres;
h264parse = GST_H264_PARSE (parse);
@@ -959,7 +1206,7 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
if (format != GST_H264_PARSE_FORMAT_BYTE &&
(value = gst_structure_get_value (str, "codec_data"))) {
guint8 *data;
- guint num_sps, num_pps, profile, len;
+ guint num_sps, num_pps, profile;
gint i;
GST_DEBUG_OBJECT (h264parse, "have packetized h264");
@@ -992,28 +1239,29 @@ gst_h264_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);
num_sps = data[5] & 0x1f;
- data += 6;
- size -= 6;
+ off = 6;
for (i = 0; i < num_sps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2 || len < 2)
+ parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
+ data, off, size - off, 2, &nalu);
+ if (parseres != GST_H264_PARSER_OK)
goto avcc_too_small;
- /* digest for later reference */
- gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
- data += len + 2;
- size -= len + 2;
+
+ gst_h264_parse_process_nal (h264parse, &nalu);
+ off = nalu.offset + nalu.size;
}
+
num_pps = data[0];
data++;
size++;
for (i = 0; i < num_pps; i++) {
- len = GST_READ_UINT16_BE (data);
- if (size < len + 2 || len < 2)
+ parseres = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
+ data, off, size - off, 2, &nalu);
+ if (parseres != GST_H264_PARSER_OK) {
goto avcc_too_small;
- /* digest for later reference */
- gst_h264_parse_process_nal (h264parse, data, 0, 2, len);
- data += len + 2;
- size -= len + 2;
+ }
+
+ gst_h264_parse_process_nal (h264parse, &nalu);
+ off = nalu.offset + nalu.size;
}
h264parse->codec_data = gst_buffer_ref (codec_data);
@@ -1089,10 +1337,12 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
GstBuffer *sub;
GstFlowReturn ret = GST_FLOW_OK;
guint32 len;
+ GstH264NalUnit nalu;
const guint nl = h264parse->nal_length_size;
GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d",
GST_BUFFER_SIZE (buffer));
+
gst_byte_reader_init_from_buffer (&br, buffer);
while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) {
GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d",
@@ -1114,9 +1364,10 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
break;
default:
goto not_negotiated;
- break;
}
+
GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len);
+
if (gst_byte_reader_get_remaining (&br) < len)
goto parse_failed;
if (h264parse->split_packetized) {
@@ -1133,9 +1384,10 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
/* NOTE: so if it is really configured to do so,
* pre_push can/will still insert codec-data at intervals,
* which is not really pure pass-through, but anyway ... */
- gst_h264_parse_process_nal (h264parse,
+ gst_h264_parser_identify_nalu (h264parse->nalparser,
GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl,
- gst_byte_reader_get_pos (&br), len);
+ GST_BUFFER_SIZE (buffer), &nalu);
+ gst_h264_parse_process_nal (h264parse, &nalu);
gst_byte_reader_skip_unchecked (&br, len);
}
}
diff --git a/gst/videoparsers/gsth264parse.h b/gst/videoparsers/gsth264parse.h
index 1aa132321..e013a3fac 100644
--- a/gst/videoparsers/gsth264parse.h
+++ b/gst/videoparsers/gsth264parse.h
@@ -1,7 +1,10 @@
/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) <2010> Collabora Multimedia
+ * Copyright (C) <2010> Collabora ltd
* Copyright (C) <2010> Nokia Corporation
+ * Copyright (C) <2011> Intel Corporation
+ *
+ * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * 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
@@ -24,8 +27,7 @@
#include <gst/gst.h>
#include <gst/base/gstbaseparse.h>
-
-#include "h264parse.h"
+#include <gst/codecparsers/gsth264parser.h>
G_BEGIN_DECLS
@@ -61,16 +63,34 @@ struct _GstH264Parse
gboolean packetized;
/* state */
- GstH264Params *params;
+ GstH264NalParser *nalparser;
+ GstH264NalUnit nalu;
guint align;
guint format;
+ guint current_off;
GstClockTime last_report;
gboolean push_codec;
+ /* collected SPS and PPS NALUs */
+ GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT];
+ GstBuffer *pps_nals[GST_H264_MAX_PPS_COUNT];
+
+ /* Infos we need to keep track of */
+ guint32 sei_cpb_removal_delay;
+ guint8 sei_pic_struct;
+ guint8 sei_pic_struct_pres_flag;
+ guint field_pic_flag;
+
+ /* cached timestamps */
+ /* (trying to) track upstream dts and interpolate */
+ GstClockTime dts;
+ /* dts at start of last buffering period */
+ GstClockTime ts_trn_nb;
+
/* frame parsing */
- guint last_nal_pos;
- guint next_sc_pos;
+ /*guint last_nal_pos;*/
+ /*guint next_sc_pos;*/
gint idr_pos;
gboolean update_caps;
GstAdapter *frame_out;
diff --git a/gst/videoparsers/h264parse.c b/gst/videoparsers/h264parse.c
deleted file mode 100644
index a556d449c..000000000
--- a/gst/videoparsers/h264parse.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) <2010> Collabora Multimedia
- * Copyright (C) <2010> Nokia Corporation
- *
- * Some bits C-c,C-v'ed and s/4/3 from h264parse:
- * (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.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "h264parse.h"
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_EXTERN (h264_parse_debug);
-#define GST_CAT_DEFAULT h264_parse_debug
-
-/* simple bitstream parser, automatically skips over
- * emulation_prevention_three_bytes. */
-typedef struct
-{
- const guint8 *orig_data;
- const guint8 *data;
- const guint8 *end;
- /* bitpos in the cache of next bit */
- gint head;
- /* cached bytes */
- guint64 cache;
-} GstNalBs;
-
-static void
-gst_nal_bs_init (GstNalBs * bs, const guint8 * data, guint size)
-{
- bs->orig_data = data;
- bs->data = data;
- bs->end = data + size;
- bs->head = 0;
- /* fill with something other than 0 to detect emulation prevention bytes */
- bs->cache = 0xffffffff;
-}
-
-static inline void
-gst_nal_bs_get_data (GstNalBs * bs, const guint8 ** data, guint * size)
-{
- *data = bs->orig_data;
- *size = bs->end - bs->orig_data;
-}
-
-static guint32
-gst_nal_bs_read (GstNalBs * bs, guint n)
-{
- guint32 res = 0;
- gint shift;
-
- if (n == 0)
- return res;
-
- /* fill up the cache if we need to */
- while (bs->head < n) {
- guint8 byte;
- gboolean check_three_byte;
-
- check_three_byte = TRUE;
- next_byte:
- if (bs->data >= bs->end) {
- /* we're at the end, can't produce more than head number of bits */
- n = bs->head;
- break;
- }
- /* get the byte, this can be an emulation_prevention_three_byte that we need
- * to ignore. */
- byte = *bs->data++;
- if (check_three_byte && byte == 0x03 && ((bs->cache & 0xffff) == 0)) {
- /* next byte goes unconditionally to the cache, even if it's 0x03 */
- check_three_byte = FALSE;
- goto next_byte;
- }
- /* shift bytes in cache, moving the head bits of the cache left */
- bs->cache = (bs->cache << 8) | byte;
- bs->head += 8;
- }
-
- /* bring the required bits down and truncate */
- if ((shift = bs->head - n) > 0)
- res = bs->cache >> shift;
- else
- res = bs->cache;
-
- /* mask out required bits */
- if (n < 32)
- res &= (1 << n) - 1;
-
- bs->head = shift;
-
- return res;
-}
-
-static gboolean
-gst_nal_bs_eos (GstNalBs * bs)
-{
- return (bs->data >= bs->end) && (bs->head == 0);
-}
-
-/* read unsigned Exp-Golomb code */
-static gint
-gst_nal_bs_read_ue (GstNalBs * bs)
-{
- gint i = 0;
-
- while (gst_nal_bs_read (bs, 1) == 0 && !gst_nal_bs_eos (bs) && i < 32)
- i++;
-
- return ((1 << i) - 1 + gst_nal_bs_read (bs, i));
-}
-
-/* read signed Exp-Golomb code */
-static gint
-gst_nal_bs_read_se (GstNalBs * bs)
-{
- gint i = 0;
-
- i = gst_nal_bs_read_ue (bs);
- /* (-1)^(i+1) Ceil (i / 2) */
- i = (i + 1) / 2 * (i & 1 ? 1 : -1);
-
- return i;
-}
-
-/* end parser helper */
-
-static void
-gst_h264_params_store_nal (GstH264Params * params, GstBuffer ** store,
- gint store_size, gint id, GstNalBs * bs)
-{
- const guint8 *data;
- GstBuffer *buf;
- guint size;
-
- if (id >= store_size) {
- GST_DEBUG_OBJECT (params->el,
- "unable to store nal, id out-of-range %d", id);
- return;
- }
-
- gst_nal_bs_get_data (bs, &data, &size);
- buf = gst_buffer_new_and_alloc (size);
- memcpy (GST_BUFFER_DATA (buf), data, size);
-
- if (store[id])
- gst_buffer_unref (store[id]);
-
- store[id] = buf;
-}
-
-static GstH264ParamsSPS *
-gst_h264_params_get_sps (GstH264Params * params, guint8 sps_id, gboolean set)
-{
- GstH264ParamsSPS *sps;
-
- g_return_val_if_fail (params != NULL, NULL);
-
- if (G_UNLIKELY (sps_id >= MAX_SPS_COUNT)) {
- GST_WARNING_OBJECT (params->el,
- "requested sps_id=%04x out of range", sps_id);
- return NULL;
- }
-
- sps = &params->sps_buffers[sps_id];
- if (set) {
- if (sps->valid) {
- params->sps = sps;
- } else {
- GST_WARNING_OBJECT (params->el, "invalid sps not selected");
- params->sps = NULL;
- sps = NULL;
- }
- }
-
- return sps;
-}
-
-static GstH264ParamsPPS *
-gst_h264_params_get_pps (GstH264Params * params, guint8 pps_id, gboolean set)
-{
- GstH264ParamsPPS *pps;
-
- g_return_val_if_fail (params != NULL, NULL);
-
- pps = &params->pps_buffers[pps_id];
- if (set) {
- if (pps->valid) {
- params->pps = pps;
- } else {
- GST_WARNING_OBJECT (params->el, "invalid pps not selected");
- params->pps = NULL;
- pps = NULL;
- }
- }
-
- return pps;
-}
-
-static gboolean
-gst_h264_params_decode_sps_vui_hrd (GstH264Params * params,
- GstH264ParamsSPS * sps, GstNalBs * bs)
-{
- gint sched_sel_idx;
-
- sps->cpb_cnt_minus1 = gst_nal_bs_read_ue (bs);
- if (sps->cpb_cnt_minus1 > 31U) {
- GST_WARNING_OBJECT (params->el, "cpb_cnt_minus1 = %d out of range",
- sps->cpb_cnt_minus1);
- return FALSE;
- }
-
- /* bit_rate_scale */
- gst_nal_bs_read (bs, 4);
- /* cpb_size_scale */
- gst_nal_bs_read (bs, 4);
-
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1; sched_sel_idx++) {
- /* bit_rate_value_minus1 */
- gst_nal_bs_read_ue (bs);
- /* cpb_size_value_minus1 */
- gst_nal_bs_read_ue (bs);
- /* cbr_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- sps->initial_cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->cpb_removal_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->dpb_output_delay_length_minus1 = gst_nal_bs_read (bs, 5);
- sps->time_offset_length_minus1 = gst_nal_bs_read (bs, 5);
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sps_vui (GstH264Params * params, GstH264ParamsSPS * sps,
- GstNalBs * bs)
-{
- if (G_UNLIKELY (!sps))
- return FALSE;
-
- /* aspect_ratio_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* aspect_ratio_idc */
- if (gst_nal_bs_read (bs, 8) == 255) {
- /* Extended_SAR */
- /* sar_width */
- gst_nal_bs_read (bs, 16);
- /* sar_height */
- gst_nal_bs_read (bs, 16);
- }
- }
-
- /* overscan_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* overscan_appropriate_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- /* video_signal_type_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* video_format */
- gst_nal_bs_read (bs, 3);
- /* video_full_range_flag */
- gst_nal_bs_read (bs, 1);
-
- /* colour_description_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* colour_primaries */
- gst_nal_bs_read (bs, 8);
- /* transfer_characteristics */
- gst_nal_bs_read (bs, 8);
- /* matrix_coefficients */
- gst_nal_bs_read (bs, 8);
- }
- }
-
- /* chroma_loc_info_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* chroma_sample_loc_type_top_field */
- gst_nal_bs_read_ue (bs);
- /* chroma_sample_loc_type_bottom_field */
- gst_nal_bs_read_ue (bs);
- }
-
- sps->timing_info_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->timing_info_present_flag) {
- guint32 num_units_in_tick = gst_nal_bs_read (bs, 32);
- guint32 time_scale = gst_nal_bs_read (bs, 32);
-
- /* If any of these parameters = 0, discard all timing_info */
- if (time_scale == 0) {
- GST_WARNING_OBJECT (params->el,
- "time_scale = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else if (num_units_in_tick == 0) {
- GST_WARNING_OBJECT (params->el,
- "num_units_in_tick = 0 detected in stream (incompliant to H.264 E.2.1)."
- " Discarding related info.");
- } else {
- sps->num_units_in_tick = num_units_in_tick;
- sps->time_scale = time_scale;
- sps->fixed_frame_rate_flag = gst_nal_bs_read (bs, 1);
- GST_LOG_OBJECT (params->el, "timing info: dur=%d/%d fixed=%d",
- num_units_in_tick, time_scale, sps->fixed_frame_rate_flag);
- }
- }
-
- sps->nal_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->nal_hrd_parameters_present_flag) {
- gst_h264_params_decode_sps_vui_hrd (params, sps, bs);
- }
- sps->vcl_hrd_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vcl_hrd_parameters_present_flag) {
- gst_h264_params_decode_sps_vui_hrd (params, sps, bs);
- }
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- gst_nal_bs_read (bs, 1); /* low_delay_hrd_flag */
- }
-
- sps->pic_struct_present_flag = gst_nal_bs_read (bs, 1);
-
- /* derive framerate */
- /* FIXME verify / also handle other cases */
- if (sps->fixed_frame_rate_flag && sps->frame_mbs_only_flag &&
- !sps->pic_struct_present_flag) {
- sps->fps_num = sps->time_scale;
- sps->fps_den = sps->num_units_in_tick;
- /* picture is a frame = 2 fields */
- sps->fps_den *= 2;
- GST_LOG_OBJECT (params->el, "framerate %d/%d", sps->fps_num, sps->fps_den);
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sps (GstH264Params * params, GstNalBs * bs)
-{
- guint8 profile_idc, level_idc;
- guint8 sps_id;
- GstH264ParamsSPS *sps = NULL;
- guint subwc[] = { 1, 2, 2, 1 };
- guint subhc[] = { 1, 2, 1, 1 };
- guint chroma;
- guint fc_top, fc_bottom, fc_left, fc_right;
- gint width, height;
-
- profile_idc = gst_nal_bs_read (bs, 8);
- /* constraint_set0_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* constraint_set1_flag */
- gst_nal_bs_read (bs, 1);
- /* reserved */
- gst_nal_bs_read (bs, 4);
- level_idc = gst_nal_bs_read (bs, 8);
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_params_get_sps (params, sps_id, FALSE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- gst_h264_params_store_nal (params, params->sps_nals, MAX_SPS_COUNT, sps_id,
- bs);
-
- /* could be redefined mid stream, arrange for clear state */
- memset (sps, 0, sizeof (*sps));
-
- GST_LOG_OBJECT (params->el, "sps id %d", sps_id);
- sps->valid = TRUE;
- /* validate and force activate this one if it is the first SPS we see */
- if (params->sps == NULL)
- params->sps = sps;
-
- sps->profile_idc = profile_idc;
- sps->level_idc = level_idc;
-
- if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122
- || profile_idc == 244 || profile_idc == 44 ||
- profile_idc == 83 || profile_idc == 86) {
- gint scp_flag = 0;
-
- /* chroma_format_idc */
- if ((chroma = gst_nal_bs_read_ue (bs)) == 3) {
- /* separate_colour_plane_flag */
- sps->scp_flag = gst_nal_bs_read (bs, 1);
- }
- /* bit_depth_luma_minus8 */
- gst_nal_bs_read_ue (bs);
- /* bit_depth_chroma_minus8 */
- gst_nal_bs_read_ue (bs);
- /* qpprime_y_zero_transform_bypass_flag */
- gst_nal_bs_read (bs, 1);
- /* seq_scaling_matrix_present_flag */
- if (gst_nal_bs_read (bs, 1)) {
- gint i, j, m, d;
-
- m = (chroma != 3) ? 8 : 12;
- for (i = 0; i < m; i++) {
- /* seq_scaling_list_present_flag[i] */
- d = gst_nal_bs_read (bs, 1);
- if (d) {
- gint lastScale = 8, nextScale = 8, deltaScale;
-
- j = (i < 6) ? 16 : 64;
- for (; j > 0; j--) {
- if (nextScale != 0) {
- deltaScale = gst_nal_bs_read_se (bs);
- nextScale = (lastScale + deltaScale + 256) % 256;
- }
- if (nextScale != 0)
- lastScale = nextScale;
- }
- }
- }
- }
- if (scp_flag)
- chroma = 0;
- } else {
- /* inferred value */
- chroma = 1;
- }
-
- /* between 0 and 12 */
- sps->log2_max_frame_num_minus4 = gst_nal_bs_read_ue (bs);
- if (sps->log2_max_frame_num_minus4 > 12) {
- GST_WARNING_OBJECT (params->el,
- "log2_max_frame_num_minus4 = %d out of range" " [0,12]",
- sps->log2_max_frame_num_minus4);
- return FALSE;
- }
-
- sps->pic_order_cnt_type = gst_nal_bs_read_ue (bs);
- if (sps->pic_order_cnt_type == 0) {
- sps->log2_max_pic_order_cnt_lsb_minus4 = gst_nal_bs_read_ue (bs);
- } else if (sps->pic_order_cnt_type == 1) {
- gint d;
-
- /* delta_pic_order_always_zero_flag */
- gst_nal_bs_read (bs, 1);
- /* offset_for_non_ref_pic */
- gst_nal_bs_read_ue (bs);
- /* offset_for_top_to_bottom_field */
- gst_nal_bs_read_ue (bs);
- /* num_ref_frames_in_pic_order_cnt_cycle */
- d = gst_nal_bs_read_ue (bs);
- for (; d > 0; d--) {
- /* offset_for_ref_frame[i] */
- gst_nal_bs_read_ue (bs);
- }
- }
-
- /* max_num_ref_frames */
- gst_nal_bs_read_ue (bs);
- /* gaps_in_frame_num_value_allowed_flag */
- gst_nal_bs_read (bs, 1);
- /* pic_width_in_mbs_minus1 */
- width = gst_nal_bs_read_ue (bs);
- /* pic_height_in_map_units_minus1 */
- height = gst_nal_bs_read_ue (bs);
-
- sps->frame_mbs_only_flag = gst_nal_bs_read (bs, 1);
- if (!sps->frame_mbs_only_flag) {
- /* mb_adaptive_frame_field_flag */
- gst_nal_bs_read (bs, 1);
- }
-
- width++;
- width *= 16;
- height++;
- height *= 16 * (2 - sps->frame_mbs_only_flag);
-
- /* direct_8x8_inference_flag */
- gst_nal_bs_read (bs, 1);
- /* frame_cropping_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* frame_crop_left_offset */
- fc_left = gst_nal_bs_read_ue (bs);
- /* frame_crop_right_offset */
- fc_right = gst_nal_bs_read_ue (bs);
- /* frame_crop_top_offset */
- fc_top = gst_nal_bs_read_ue (bs);
- /* frame_crop_bottom_offset */
- fc_bottom = gst_nal_bs_read_ue (bs);
- } else {
- fc_left = fc_right = fc_top = fc_bottom = 0;
- }
-
- GST_LOG_OBJECT (params->el, "decoding SPS: profile_idc = %d, "
- "level_idc = %d, sps_id = %d, pic_order_cnt_type = %d, "
- "frame_mbs_only_flag = %d",
- sps->profile_idc, sps->level_idc, sps_id, sps->pic_order_cnt_type,
- sps->frame_mbs_only_flag);
-
- /* calculate width and height */
- GST_LOG_OBJECT (params->el, "initial width=%d, height=%d", width, height);
- GST_LOG_OBJECT (params->el, "crop (%d,%d)(%d,%d)",
- fc_left, fc_top, fc_right, fc_bottom);
- if (chroma > 3) {
- GST_LOG_OBJECT (params->el, "chroma=%d in SPS is out of range", chroma);
- return FALSE;
- }
- width -= (fc_left + fc_right) * subwc[chroma];
- height -=
- (fc_top + fc_bottom) * subhc[chroma] * (2 - sps->frame_mbs_only_flag);
- if (width < 0 || height < 0) {
- GST_WARNING_OBJECT (params->el, "invalid width/height in SPS");
- return FALSE;
- }
- GST_LOG_OBJECT (params->el, "final width=%u, height=%u", width, height);
- sps->width = width;
- sps->height = height;
-
- sps->vui_parameters_present_flag = gst_nal_bs_read (bs, 1);
- if (sps->vui_parameters_present_flag) {
- /* discard parsing problem */
- gst_h264_params_decode_sps_vui (params, sps, bs);
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_pps (GstH264Params * params, GstNalBs * bs)
-{
- gint pps_id;
- GstH264ParamsPPS *pps = NULL;
-
- pps_id = gst_nal_bs_read_ue (bs);
- if (G_UNLIKELY (pps_id >= MAX_PPS_COUNT)) {
- GST_WARNING_OBJECT (params->el,
- "requested pps_id=%04x out of range", pps_id);
- return FALSE;
- }
-
-
- pps = gst_h264_params_get_pps (params, pps_id, FALSE);
- if (G_UNLIKELY (pps == NULL))
- return FALSE;
-
- /* validate and set */
- pps->valid = TRUE;
- params->pps = pps;
-
- gst_h264_params_store_nal (params, params->pps_nals, MAX_PPS_COUNT, pps_id,
- bs);
-
- pps->sps_id = gst_nal_bs_read_ue (bs);
- GST_LOG_OBJECT (params->el, "pps %d referencing sps %d", pps_id, pps->sps_id);
-
- /* activate referenced sps */
- if (!gst_h264_params_get_sps (params, pps->sps_id, TRUE))
- return FALSE;
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sei_buffering_period (GstH264Params * params,
- GstNalBs * bs)
-{
-#ifdef EXTRA_PARSE
- guint8 sps_id;
- gint sched_sel_idx;
- GstH264ParamsSPS *sps;
-
- sps_id = gst_nal_bs_read_ue (bs);
- sps = gst_h264_params_get_sps (params, sps_id, TRUE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- if (sps->nal_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- params->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- /* initial_cpb_removal_delay_offset */
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1);
- }
- }
-
- if (sps->vcl_hrd_parameters_present_flag) {
- for (sched_sel_idx = 0; sched_sel_idx <= sps->cpb_cnt_minus1;
- sched_sel_idx++) {
- params->initial_cpb_removal_delay[sched_sel_idx]
- = gst_nal_bs_read (bs,
- sps->initial_cpb_removal_delay_length_minus1 + 1);
- /* initial_cpb_removal_delay_offset */
- gst_nal_bs_read (bs, sps->initial_cpb_removal_delay_length_minus1 + 1);
- }
- }
-#endif
-
- if (params->ts_trn_nb == GST_CLOCK_TIME_NONE ||
- params->dts == GST_CLOCK_TIME_NONE)
- params->ts_trn_nb = 0;
- else
- params->ts_trn_nb = params->dts;
-
- GST_LOG_OBJECT (params->el,
- "new buffering period; ts_trn_nb updated: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (params->ts_trn_nb));
-
- return 0;
-}
-
-static gboolean
-gst_h264_params_decode_sei_picture_timing (GstH264Params * params,
- GstNalBs * bs)
-{
- GstH264ParamsSPS *sps = params->sps;
-
- if (sps == NULL) {
- GST_WARNING_OBJECT (params->el,
- "SPS == NULL; delayed decoding of picture timing info not implemented ");
- return FALSE;
- }
-
- if (sps->nal_hrd_parameters_present_flag
- || sps->vcl_hrd_parameters_present_flag) {
- params->sei_cpb_removal_delay =
- gst_nal_bs_read (bs, sps->cpb_removal_delay_length_minus1 + 1);
- /* sei_dpb_output_delay */
- gst_nal_bs_read (bs, sps->dpb_output_delay_length_minus1 + 1);
- }
-
- if (sps->pic_struct_present_flag) {
-#ifdef EXTRA_PARSE
- /* pic_struct to NumClockTS lookup table */
- static const guint8 sei_num_clock_ts_table[9] =
- { 1, 1, 1, 2, 2, 3, 3, 2, 3 };
- guint i, num_clock_ts;
- guint sei_ct_type = 0;
-#endif
-
- params->sei_pic_struct = gst_nal_bs_read (bs, 4);
- GST_LOG_OBJECT (params, "pic_struct:%d", params->sei_pic_struct);
- if (params->sei_pic_struct > SEI_PIC_STRUCT_FRAME_TRIPLING)
- return FALSE;
-
-#ifdef EXTRA_PARSE
- num_clock_ts = sei_num_clock_ts_table[params->sei_pic_struct];
-
- for (i = 0; i < num_clock_ts; i++) {
- /* clock_timestamp_flag */
- if (gst_nal_bs_read (bs, 1)) {
- guint full_timestamp_flag;
-
- sei_ct_type |= 1 << gst_nal_bs_read (bs, 2);
- /* nuit_field_based_flag */
- gst_nal_bs_read (bs, 1);
- /* counting_type */
- gst_nal_bs_read (bs, 5);
- full_timestamp_flag = gst_nal_bs_read (bs, 1);
- /* discontinuity_flag */
- gst_nal_bs_read (bs, 1);
- /* cnt_dropped_flag */
- gst_nal_bs_read (bs, 1);
- /* n_frames */
- gst_nal_bs_read (bs, 8);
- if (full_timestamp_flag) {
- /* seconds_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* minutes_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* hours_value 0..23 */
- gst_nal_bs_read (bs, 5);
- } else {
- /* seconds_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* seconds_value range 0..59 */
- gst_nal_bs_read (bs, 6);
- /* minutes_flag */
- if (gst_nal_bs_read (bs, 1)) {
- /* minutes_value 0..59 */
- gst_nal_bs_read (bs, 6);
- /* hours_flag */
- if (gst_nal_bs_read (bs, 1))
- /* hours_value 0..23 */
- gst_nal_bs_read (bs, 5);
- }
- }
- }
- if (sps->time_offset_length_minus1 >= 0) {
- /* time_offset */
- gst_nal_bs_read (bs, sps->time_offset_length_minus1 + 1);
- }
- }
- }
-
- GST_LOG_OBJECT (params, "ct_type:%X", sei_ct_type);
-#endif
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_sei (GstH264Params * params, GstNalBs * bs)
-{
- guint8 tmp;
- GstH264ParamsSEIPayloadType payloadType = 0;
- gint8 payloadSize = 0;
-
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadType += tmp;
- } while (tmp == 255);
- do {
- tmp = gst_nal_bs_read (bs, 8);
- payloadSize += tmp;
- } while (tmp == 255);
-
- GST_LOG_OBJECT (params->el,
- "SEI message received: payloadType = %d, payloadSize = %d bytes",
- payloadType, payloadSize);
-
- switch (payloadType) {
- case SEI_BUF_PERIOD:
- if (!gst_h264_params_decode_sei_buffering_period (params, bs))
- return FALSE;
- break;
- case SEI_PIC_TIMING:
- /* TODO: According to H264 D2.2 Note1, it might be the case that the
- * picture timing SEI message is encountered before the corresponding SPS
- * is specified. Need to hold down the message and decode it later. */
- if (!gst_h264_params_decode_sei_picture_timing (params, bs))
- return FALSE;
- break;
- default:
- GST_LOG_OBJECT (params->el,
- "SEI message of payloadType = %d is received but not parsed",
- payloadType);
- break;
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_h264_params_decode_slice_header (GstH264Params * params, GstNalBs * bs)
-{
- GstH264ParamsSPS *sps;
- GstH264ParamsPPS *pps;
- guint8 pps_id;
-
- params->first_mb_in_slice = gst_nal_bs_read_ue (bs);
- params->slice_type = gst_nal_bs_read_ue (bs);
-
- pps_id = gst_nal_bs_read_ue (bs);
- GST_LOG_OBJECT (params->el, "slice header references pps id %d", pps_id);
- pps = gst_h264_params_get_pps (params, pps_id, TRUE);
- if (G_UNLIKELY (pps == NULL))
- return FALSE;
- sps = gst_h264_params_get_sps (params, pps->sps_id, TRUE);
- if (G_UNLIKELY (sps == NULL))
- return FALSE;
-
- if (sps->scp_flag) {
- /* colour_plane_id */
- gst_nal_bs_read (bs, 2);
- }
-
- /* frame num */
- gst_nal_bs_read (bs, sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
-
- if (!sps->frame_mbs_only_flag) {
- params->field_pic_flag = gst_nal_bs_read (bs, 1);
- if (params->field_pic_flag)
- params->bottom_field_flag = gst_nal_bs_read (bs, 1);
- }
-
- /* not parsing the rest for the time being */
- return TRUE;
-}
-
-/* only payload in @data */
-gboolean
-gst_h264_params_parse_nal (GstH264Params * params, guint8 * data, gint size)
-{
- GstH264ParamsNalUnitType nal_type;
- GstNalBs bs;
- gint nal_ref_idc;
- gboolean res = TRUE;
-
- g_return_val_if_fail (params != NULL, FALSE);
- g_return_val_if_fail (data != NULL, FALSE);
- g_return_val_if_fail (size != 0, FALSE);
-
- nal_type = (data[0] & 0x1f);
- nal_ref_idc = (data[0] & 0x60) >> 5;
-
- GST_LOG_OBJECT (params->el, "NAL type: %d, ref_idc: %d", nal_type,
- nal_ref_idc);
-
- gst_nal_bs_init (&bs, data + 1, size - 1);
- /* optimality HACK */
- bs.orig_data = data;
-
- /* first parse some things needed to get to the frame type */
- switch (nal_type) {
- case NAL_SLICE:
- case NAL_SLICE_DPA:
- case NAL_SLICE_DPB:
- case NAL_SLICE_DPC:
- case NAL_SLICE_IDR:
- {
- gint first_mb_in_slice, slice_type;
-
- gst_h264_params_decode_slice_header (params, &bs);
- first_mb_in_slice = params->first_mb_in_slice;
- slice_type = params->slice_type;
-
- GST_LOG_OBJECT (params->el, "first MB: %d, slice type: %d",
- first_mb_in_slice, slice_type);
-
- switch (slice_type) {
- case 0:
- case 5:
- case 3:
- case 8: /* SP */
- /* P frames */
- GST_LOG_OBJECT (params->el, "we have a P slice");
- break;
- case 1:
- case 6:
- /* B frames */
- GST_LOG_OBJECT (params->el, "we have a B slice");
- break;
- case 2:
- case 7:
- case 4:
- case 9:
- /* I frames */
- GST_LOG_OBJECT (params->el, "we have an I slice");
- break;
- }
- break;
- }
- case NAL_SEI:
- GST_LOG_OBJECT (params->el, "SEI NAL");
- res = gst_h264_params_decode_sei (params, &bs);
- break;
- case NAL_SPS:
- GST_LOG_OBJECT (params->el, "SPS NAL");
- res = gst_h264_params_decode_sps (params, &bs);
- break;
- case NAL_PPS:
- GST_LOG_OBJECT (params->el, "PPS NAL");
- res = gst_h264_params_decode_pps (params, &bs);
- break;
- case NAL_AU_DELIMITER:
- GST_LOG_OBJECT (params->el, "AU delimiter NAL");
- break;
- default:
- GST_LOG_OBJECT (params->el, "unparsed NAL");
- break;
- }
-
- return res;
-}
-
-void
-gst_h264_params_get_timestamp (GstH264Params * params,
- GstClockTime * out_ts, GstClockTime * out_dur, gboolean frame)
-{
- GstH264ParamsSPS *sps = params->sps;
- GstClockTime upstream;
- gint duration = 1;
-
- g_return_if_fail (out_dur != NULL);
- g_return_if_fail (out_ts != NULL);
-
- upstream = *out_ts;
-
- if (!frame) {
- GST_LOG_OBJECT (params->el, "no frame data -> 0 duration");
- *out_dur = 0;
- goto exit;
- } else {
- *out_ts = upstream;
- }
-
- if (!sps) {
- GST_DEBUG_OBJECT (params->el, "referred SPS invalid");
- goto exit;
- } else if (!sps->timing_info_present_flag) {
- GST_DEBUG_OBJECT (params->el,
- "unable to compute timestamp: timing info not present");
- goto exit;
- } else if (sps->time_scale == 0) {
- GST_DEBUG_OBJECT (params->el,
- "unable to compute timestamp: time_scale = 0 "
- "(this is forbidden in spec; bitstream probably contains error)");
- goto exit;
- }
-
- if (sps->pic_struct_present_flag && params->sei_pic_struct != (guint8) - 1) {
- /* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
- * are ways to infer its value. This is related to computing the
- * TopFieldOrderCnt and BottomFieldOrderCnt, which looks
- * complicated and thus not implemented for the time being. Yet
- * the value we have here is correct for many applications
- */
- switch (params->sei_pic_struct) {
- case SEI_PIC_STRUCT_TOP_FIELD:
- case SEI_PIC_STRUCT_BOTTOM_FIELD:
- duration = 1;
- break;
- case SEI_PIC_STRUCT_FRAME:
- case SEI_PIC_STRUCT_TOP_BOTTOM:
- case SEI_PIC_STRUCT_BOTTOM_TOP:
- duration = 2;
- break;
- case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
- case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
- duration = 3;
- break;
- case SEI_PIC_STRUCT_FRAME_DOUBLING:
- duration = 4;
- break;
- case SEI_PIC_STRUCT_FRAME_TRIPLING:
- duration = 6;
- break;
- default:
- GST_DEBUG_OBJECT (params,
- "h264parse->sei_pic_struct of unknown value %d. Not parsed",
- params->sei_pic_struct);
- break;
- }
- } else {
- duration = params->field_pic_flag ? 1 : 2;
- }
-
- GST_LOG_OBJECT (params->el, "frame tick duration %d", duration);
-
- /*
- * h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
- * Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
- * Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
- * where
- * Tc = num_units_in_tick / time_scale
- */
-
- if (params->ts_trn_nb != GST_CLOCK_TIME_NONE) {
- GST_LOG_OBJECT (params->el, "buffering based ts");
- /* buffering period is present */
- if (upstream != GST_CLOCK_TIME_NONE) {
- /* If upstream timestamp is valid, we respect it and adjust current
- * reference point */
- params->ts_trn_nb = upstream -
- (GstClockTime) gst_util_uint64_scale_int
- (params->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- } else {
- /* If no upstream timestamp is given, we write in new timestamp */
- upstream = params->dts = params->ts_trn_nb +
- (GstClockTime) gst_util_uint64_scale_int
- (params->sei_cpb_removal_delay * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- }
- } else {
- GstClockTime dur;
-
- GST_LOG_OBJECT (params->el, "duration based ts");
- /* naive method: no removal delay specified
- * track upstream timestamp and provide best guess frame duration */
- dur = gst_util_uint64_scale_int (duration * GST_SECOND,
- sps->num_units_in_tick, sps->time_scale);
- /* sanity check */
- if (dur < GST_MSECOND) {
- GST_DEBUG_OBJECT (params->el, "discarding dur %" GST_TIME_FORMAT,
- GST_TIME_ARGS (dur));
- } else {
- *out_dur = dur;
- }
- }
-
-exit:
- if (GST_CLOCK_TIME_IS_VALID (upstream))
- *out_ts = params->dts = upstream;
-
- if (GST_CLOCK_TIME_IS_VALID (*out_dur) &&
- GST_CLOCK_TIME_IS_VALID (params->dts))
- params->dts += *out_dur;
-}
-
-void
-gst_h264_params_create (GstH264Params ** _params, GstElement * element)
-{
- GstH264Params *params;
-
- g_return_if_fail (_params != NULL);
-
- params = g_new0 (GstH264Params, 1);
- params->el = element;
-
- params->dts = GST_CLOCK_TIME_NONE;
- params->ts_trn_nb = GST_CLOCK_TIME_NONE;
-
- *_params = params;
-}
-
-void
-gst_h264_params_free (GstH264Params * params)
-{
- gint i;
-
- g_return_if_fail (params != NULL);
-
- for (i = 0; i < MAX_SPS_COUNT; i++)
- gst_buffer_replace (&params->sps_nals[i], NULL);
- for (i = 0; i < MAX_PPS_COUNT; i++)
- gst_buffer_replace (&params->pps_nals[i], NULL);
-
- g_free (params);
-}
diff --git a/gst/videoparsers/h264parse.h b/gst/videoparsers/h264parse.h
deleted file mode 100644
index 517c8542b..000000000
--- a/gst/videoparsers/h264parse.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* GStreamer H.264 Parser
- * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) <2010> Collabora Multimedia
- * Copyright (C) <2010> Nokia Corporation
- *
- * Some bits C-c,C-v'ed and s/4/3 from h264parse:
- * (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_PARAMS_H__
-#define __GST_H264_PARAMS_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-typedef enum
-{
- NAL_UNKNOWN = 0,
- NAL_SLICE = 1,
- NAL_SLICE_DPA = 2,
- NAL_SLICE_DPB = 3,
- NAL_SLICE_DPC = 4,
- NAL_SLICE_IDR = 5,
- NAL_SEI = 6,
- NAL_SPS = 7,
- NAL_PPS = 8,
- NAL_AU_DELIMITER = 9,
- NAL_SEQ_END = 10,
- NAL_STREAM_END = 11,
- NAL_FILTER_DATA = 12
-} GstH264ParamsNalUnitType;
-
-/* SEI type */
-typedef enum
-{
- SEI_BUF_PERIOD = 0,
- SEI_PIC_TIMING = 1
- /* and more... */
-} GstH264ParamsSEIPayloadType;
-
-/* SEI pic_struct type */
-typedef enum
-{
- SEI_PIC_STRUCT_FRAME = 0,
- SEI_PIC_STRUCT_TOP_FIELD = 1,
- SEI_PIC_STRUCT_BOTTOM_FIELD = 2,
- SEI_PIC_STRUCT_TOP_BOTTOM = 3,
- SEI_PIC_STRUCT_BOTTOM_TOP = 4,
- SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5,
- SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6,
- SEI_PIC_STRUCT_FRAME_DOUBLING = 7,
- SEI_PIC_STRUCT_FRAME_TRIPLING = 8
-} GstH264ParamsSEIPicStructType;
-
-typedef struct _GstH264Params GstH264Params;
-typedef struct _GstH264ParamsSPS GstH264ParamsSPS;
-typedef struct _GstH264ParamsPPS GstH264ParamsPPS;
-
-#define MAX_SPS_COUNT 32
-#define MAX_PPS_COUNT 256
-
-/* SPS: sequential parameter sets */
-struct _GstH264ParamsSPS
-{
- gboolean valid;
-
- /* raw values */
- guint8 profile_idc;
- guint8 level_idc;
-
- guint8 sps_id;
-
- guint8 pic_order_cnt_type;
-
- guint8 log2_max_frame_num_minus4;
- gboolean frame_mbs_only_flag;
- guint8 log2_max_pic_order_cnt_lsb_minus4;
-
- gboolean frame_cropping_flag;
- gboolean scp_flag;
-
- /* VUI parameters */
- gboolean vui_parameters_present_flag;
-
- gboolean timing_info_present_flag;
- guint32 num_units_in_tick;
- guint32 time_scale;
- gboolean fixed_frame_rate_flag;
-
- gboolean nal_hrd_parameters_present_flag;
- gboolean vcl_hrd_parameters_present_flag;
-
- /* hrd parameters */
- guint8 cpb_cnt_minus1;
- gint initial_cpb_removal_delay_length_minus1;
- gint cpb_removal_delay_length_minus1;
- gint dpb_output_delay_length_minus1;
- gboolean time_offset_length_minus1;
-
- gboolean pic_struct_present_flag;
-
- /* ... and probably more ... */
-
- /* derived values */
- gint width, height;
- gint fps_num, fps_den;
-};
-
-/* PPS: pic parameter sets */
-struct _GstH264ParamsPPS
-{
- gboolean valid;
-
- /* raw values */
- guint8 pps_id;
- guint8 sps_id;
-};
-
-struct _GstH264Params
-{
- /* debug purposes */
- GstElement *el;
-
- /* SPS: sequential parameter set */
- GstH264ParamsSPS sps_buffers[MAX_SPS_COUNT];
- /* current SPS; most recent one in stream or referenced by PPS */
- GstH264ParamsSPS *sps;
- /* PPS: sequential parameter set */
- GstH264ParamsPPS pps_buffers[MAX_PPS_COUNT];
- /* current PPS; most recent one in stream */
- GstH264ParamsPPS *pps;
-
- /* extracted from slice header or otherwise relevant nal */
- guint8 first_mb_in_slice;
- guint8 slice_type;
- gboolean field_pic_flag;
- gboolean bottom_field_flag;
-
- /* SEI: supplemental enhancement messages */
-#ifdef EXTRA_PARSE
- /* buffering period */
- guint32 initial_cpb_removal_delay[32];
-#endif
- /* picture timing */
- guint32 sei_cpb_removal_delay;
- guint8 sei_pic_struct;
- /* And more... */
-
- /* cached timestamps */
- /* (trying to) track upstream dts and interpolate */
- GstClockTime dts;
- /* dts at start of last buffering period */
- GstClockTime ts_trn_nb;
-
- /* collected SPS and PPS NALUs */
- GstBuffer *sps_nals[MAX_SPS_COUNT];
- GstBuffer *pps_nals[MAX_PPS_COUNT];
-};
-
-gboolean gst_h264_params_parse_nal (GstH264Params * params, guint8 * nal, gint size);
-void gst_h264_params_get_timestamp (GstH264Params * params,
- GstClockTime * out_ts, GstClockTime * out_dur,
- gboolean frame);
-void gst_h264_params_create (GstH264Params ** _params, GstElement * element);
-void gst_h264_params_free (GstH264Params * params);
-
-
-G_END_DECLS
-#endif