mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
h264parse: Port to the new h.264 parsing library
This commit is contained in:
parent
a1cfba43f6
commit
b968f82b18
5 changed files with 459 additions and 1421 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL)
|
||||
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) {
|
||||
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);
|
||||
|
||||
nal_pos = h264parse->last_nal_pos;
|
||||
next_sc_pos = h264parse->next_sc_pos;
|
||||
|
||||
if (!next_sc_pos) {
|
||||
sc_pos = gst_h264_parse_find_sc (buffer, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
drain = GST_BASE_PARSE_DRAINING (parse);
|
||||
current_off = h264parse->current_off;
|
||||
|
||||
GST_DEBUG ("Last parse position %u", current_off);
|
||||
while (TRUE) {
|
||||
gint prev_sc_pos;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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))
|
||||
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);
|
||||
|
||||
/* move along */
|
||||
next_sc_pos = nal_pos = next_nal_pos;
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* We parse it anyway */
|
||||
nalu.size = size - nalu.offset;
|
||||
break;
|
||||
}
|
||||
goto more;
|
||||
}
|
||||
|
||||
current_off = nalu.offset + nalu.size;
|
||||
|
||||
GST_DEBUG ("%p Complete nal found. Off: %u, Size: %u", data, nalu.offset,
|
||||
nalu.size);
|
||||
|
||||
gst_h264_parse_process_nal (h264parse, &nalu);
|
||||
if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu) || drain)
|
||||
break;
|
||||
}
|
||||
|
||||
*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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
Loading…
Reference in a new issue