mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 16:51:10 +00:00
gst/h264parse/gsth264parse.*: Parse codec_data and use the nalu_size_length field to get the NALU length in packetize...
Original commit message from CVS: * gst/h264parse/gsth264parse.c: (gst_nal_bs_init), (gst_h264_parse_sink_setcaps), (gst_h264_parse_chain_forward), (gst_h264_parse_queue_buffer), (gst_h264_parse_chain_reverse), (gst_h264_parse_chain): * gst/h264parse/gsth264parse.h: Parse codec_data and use the nalu_size_length field to get the NALU length in packetized h264. When queueing a packetized buffer in reverse mode, don't unref the buffer twice. Avoid accessing the buffer TIMESTAMP field after we pushed it on the adaptor.
This commit is contained in:
parent
53bad8dd1e
commit
10d104fcae
3 changed files with 111 additions and 31 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2008-06-03 Wim Taymans <wim.taymans@collabora.co.uk>
|
||||
|
||||
* gst/h264parse/gsth264parse.c: (gst_nal_bs_init),
|
||||
(gst_h264_parse_sink_setcaps), (gst_h264_parse_chain_forward),
|
||||
(gst_h264_parse_queue_buffer), (gst_h264_parse_chain_reverse),
|
||||
(gst_h264_parse_chain):
|
||||
* gst/h264parse/gsth264parse.h:
|
||||
Parse codec_data and use the nalu_size_length field to get the NALU
|
||||
length in packetized h264.
|
||||
When queueing a packetized buffer in reverse mode, don't unref the
|
||||
buffer twice.
|
||||
Avoid accessing the buffer TIMESTAMP field after we pushed it on
|
||||
the adaptor.
|
||||
|
||||
2008-06-03 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
|
||||
* gst/interleave/interleave.c:
|
||||
|
|
|
@ -127,14 +127,14 @@ gst_nal_list_delete_head (GstNalList * list)
|
|||
* emulation_prevention_three_bytes. */
|
||||
typedef struct
|
||||
{
|
||||
guint8 *data;
|
||||
guint8 *end;
|
||||
const guint8 *data;
|
||||
const guint8 *end;
|
||||
gint head; /* bitpos in the cache of next bit */
|
||||
guint64 cache; /* cached bytes */
|
||||
} GstNalBs;
|
||||
|
||||
static void
|
||||
gst_nal_bs_init (GstNalBs * bs, guint8 * data, guint size)
|
||||
gst_nal_bs_init (GstNalBs * bs, const guint8 * data, guint size)
|
||||
{
|
||||
bs->data = data;
|
||||
bs->end = data + size;
|
||||
|
@ -335,6 +335,8 @@ gst_h264_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
|
|||
GstH264Parse *h264parse;
|
||||
GstStructure *str;
|
||||
const GValue *value;
|
||||
guint8 *data;
|
||||
guint size;
|
||||
|
||||
h264parse = GST_H264PARSE (GST_PAD_PARENT (pad));
|
||||
|
||||
|
@ -342,18 +344,59 @@ gst_h264_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
|
|||
|
||||
/* packetized video has a codec_data */
|
||||
if ((value = gst_structure_get_value (str, "codec_data"))) {
|
||||
GstBuffer *buffer;
|
||||
gint profile;
|
||||
|
||||
GST_DEBUG_OBJECT (h264parse, "have packetized h264");
|
||||
h264parse->packetized = TRUE;
|
||||
|
||||
buffer = gst_value_get_buffer (value);
|
||||
data = GST_BUFFER_DATA (buffer);
|
||||
size = GST_BUFFER_SIZE (buffer);
|
||||
|
||||
/* parse the avcC data */
|
||||
if (size < 7)
|
||||
goto avcc_too_small;
|
||||
/* parse the version, this must be 1 */
|
||||
if (data[0] != 1)
|
||||
goto wrong_version;
|
||||
|
||||
/* AVCProfileIndication */
|
||||
/* profile_compat */
|
||||
/* AVCLevelIndication */
|
||||
profile = (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
GST_DEBUG_OBJECT (h264parse, "profile %06x", profile);
|
||||
|
||||
/* 6 bits reserved | 2 bits lengthSizeMinusOne */
|
||||
/* this is the number of bytes in front of the NAL units to mark their
|
||||
* length */
|
||||
h264parse->nal_length_size = (data[4] & 0x03) + 1;
|
||||
GST_DEBUG_OBJECT (h264parse, "nal length %u", h264parse->nal_length_size);
|
||||
|
||||
/* FIXME, PPS, SPS have vital info for detecting new I-frames */
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (h264parse, "have bytestream h264");
|
||||
h264parse->packetized = FALSE;
|
||||
/* we have 4 sync bytes */
|
||||
h264parse->nal_length_size = 4;
|
||||
}
|
||||
|
||||
/* forward the caps */
|
||||
res = gst_pad_set_caps (h264parse->srcpad, caps);
|
||||
|
||||
return res;
|
||||
|
||||
/* ERRORS */
|
||||
avcc_too_small:
|
||||
{
|
||||
GST_ERROR_OBJECT (h264parse, "avcC size %u < 7", size);
|
||||
return FALSE;
|
||||
}
|
||||
wrong_version:
|
||||
{
|
||||
GST_ERROR_OBJECT (h264parse, "wrong avcC version");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -382,31 +425,30 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
|||
{
|
||||
GstFlowReturn res = GST_FLOW_OK;
|
||||
const guint8 *data;
|
||||
GstClockTime timestamp;
|
||||
|
||||
if (discont) {
|
||||
gst_adapter_clear (h264parse->adapter);
|
||||
h264parse->discont = TRUE;
|
||||
}
|
||||
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
|
||||
gst_adapter_push (h264parse->adapter, buffer);
|
||||
|
||||
while (res == GST_FLOW_OK) {
|
||||
gint i;
|
||||
gint next_nalu_pos = -1;
|
||||
guint32 nalu_size;
|
||||
gint avail;
|
||||
gboolean delta_unit = TRUE;
|
||||
|
||||
avail = gst_adapter_available (h264parse->adapter);
|
||||
if (avail < 5)
|
||||
if (avail < h264parse->nal_length_size + 1)
|
||||
break;
|
||||
data = gst_adapter_peek (h264parse->adapter, avail);
|
||||
|
||||
nalu_size = (data[0] << 24)
|
||||
+ (data[1] << 16) + (data[2] << 8) + data[3];
|
||||
|
||||
if (nalu_size == 1) {
|
||||
/* Bytestream format */
|
||||
if (!h264parse->packetized) {
|
||||
/* Bytestream format, first 4 bytes are sync code */
|
||||
/* Find next NALU header */
|
||||
for (i = 1; i < avail - 4; ++i) {
|
||||
if (data[i + 0] == 0 && data[i + 1] == 0 && data[i + 2] == 0
|
||||
|
@ -416,21 +458,32 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
guint32 nalu_size;
|
||||
|
||||
nalu_size = 0;
|
||||
for (i = 0; i < h264parse->nal_length_size; i++)
|
||||
nalu_size = (nalu_size << 8) | data[i];
|
||||
|
||||
/* Packetized format, see if we have to split it, usually splitting is not
|
||||
* a good idea as decoders have no way of handling it. */
|
||||
if (h264parse->split_packetized) {
|
||||
if (nalu_size + 4 <= avail)
|
||||
next_nalu_pos = nalu_size + 4;
|
||||
if (nalu_size + h264parse->nal_length_size <= avail)
|
||||
next_nalu_pos = nalu_size + h264parse->nal_length_size;
|
||||
} else {
|
||||
next_nalu_pos = avail;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip nalu_size bytes or sync */
|
||||
data += h264parse->nal_length_size;
|
||||
avail -= h264parse->nal_length_size;
|
||||
|
||||
/* Figure out if this is a delta unit */
|
||||
{
|
||||
gint nal_type, nal_ref_idc;
|
||||
|
||||
nal_type = (data[4] & 0x1f);
|
||||
nal_ref_idc = (data[4] & 0x60) >> 5;
|
||||
nal_type = (data[0] & 0x1f);
|
||||
nal_ref_idc = (data[0] & 0x60) >> 5;
|
||||
|
||||
GST_DEBUG_OBJECT (h264parse, "NAL type: %d, ref_idc: %d", nal_type,
|
||||
nal_ref_idc);
|
||||
|
@ -439,9 +492,8 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
|||
if (nal_type >= NAL_SLICE && nal_type <= NAL_SLICE_IDR) {
|
||||
GstNalBs bs;
|
||||
gint first_mb_in_slice, slice_type;
|
||||
guint8 *bs_data = (guint8 *) data + 5;
|
||||
|
||||
gst_nal_bs_init (&bs, bs_data, avail - 5);
|
||||
gst_nal_bs_init (&bs, data + 1, avail - 1);
|
||||
|
||||
first_mb_in_slice = gst_nal_bs_read_ue (&bs);
|
||||
slice_type = gst_nal_bs_read_ue (&bs);
|
||||
|
@ -495,12 +547,13 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
|||
h264parse->discont = FALSE;
|
||||
}
|
||||
|
||||
if (delta_unit) {
|
||||
if (delta_unit)
|
||||
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
}
|
||||
else
|
||||
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||
|
||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (h264parse->srcpad));
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||
res = gst_pad_push (h264parse->srcpad, outbuf);
|
||||
} else {
|
||||
/* NALU can not be parsed yet, we wait for more data in the adapter. */
|
||||
|
@ -584,19 +637,29 @@ gst_h264_parse_queue_buffer (GstH264Parse * parse, GstBuffer * buffer)
|
|||
|
||||
/* now parse all the NAL units in this buffer, for bytestream we only have one
|
||||
* NAL unit but for packetized streams we can have multiple ones */
|
||||
while (size >= 5) {
|
||||
nalu_size = (data[0] << 24)
|
||||
+ (data[1] << 16) + (data[2] << 8) + data[3];
|
||||
while (size >= parse->nal_length_size + 1) {
|
||||
gint i;
|
||||
|
||||
link->nal_ref_idc = (data[4] & 0x60) >> 5;
|
||||
link->nal_type = (data[4] & 0x1f);
|
||||
nalu_size = 0;
|
||||
if (parse->packetized) {
|
||||
for (i = 0; i < parse->nal_length_size; i++)
|
||||
nalu_size = (nalu_size << 8) | data[i];
|
||||
}
|
||||
|
||||
/* skip nalu_size or sync bytes */
|
||||
data += parse->nal_length_size;
|
||||
size -= parse->nal_length_size;
|
||||
|
||||
link->nal_ref_idc = (data[0] & 0x60) >> 5;
|
||||
link->nal_type = (data[0] & 0x1f);
|
||||
|
||||
/* nalu_size is 0 for bytestream, we have a complete packet */
|
||||
GST_DEBUG_OBJECT (parse, "size: %u, NAL type: %d, ref_idc: %d",
|
||||
nalu_size, link->nal_type, link->nal_ref_idc);
|
||||
|
||||
/* first parse some things needed to get to the frame type */
|
||||
if (link->nal_type >= NAL_SLICE && link->nal_type <= NAL_SLICE_IDR) {
|
||||
gst_nal_bs_init (&bs, data + 5, size - 5);
|
||||
gst_nal_bs_init (&bs, data + 1, size - 1);
|
||||
|
||||
link->first_mb_in_slice = gst_nal_bs_read_ue (&bs);
|
||||
link->slice_type = gst_nal_bs_read_ue (&bs);
|
||||
|
@ -629,11 +692,11 @@ gst_h264_parse_queue_buffer (GstH264Parse * parse, GstBuffer * buffer)
|
|||
}
|
||||
}
|
||||
/* bytestream, we can exit now */
|
||||
if (nalu_size == 1)
|
||||
if (!parse->packetized)
|
||||
break;
|
||||
|
||||
/* packetized format, continue parsing all packets, skip size */
|
||||
nalu_size += 4;
|
||||
/* packetized format, continue parsing all packets, skip size, we already
|
||||
* skipped the nal_length_size bytes */
|
||||
data += nalu_size;
|
||||
size -= nalu_size;
|
||||
}
|
||||
|
@ -717,6 +780,7 @@ gst_h264_parse_chain_reverse (GstH264Parse * h264parse, gboolean discont,
|
|||
* store them */
|
||||
GST_DEBUG_OBJECT (h264parse, "copied packetized buffer");
|
||||
res = gst_h264_parse_queue_buffer (h264parse, gbuf);
|
||||
gbuf = NULL;
|
||||
} else {
|
||||
/* bytestream, we have to split the NALUs on the sync markers */
|
||||
code = 0xffffffff;
|
||||
|
@ -808,10 +872,11 @@ gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
if (!gst_pad_set_caps (h264parse->srcpad, caps))
|
||||
goto caps_failed;
|
||||
|
||||
/* we assume the bytestream format but won't really fail otherwise if the
|
||||
* data turns out to be a nicely aligned packetized format (except we don't
|
||||
* do the codec_data caps with the PPS and SPS). */
|
||||
/* we assume the bytestream format. If the data turns out to be packetized,
|
||||
* we have a problem because we don't know the length of the nalu_size
|
||||
* indicator. Packetized input MUST set the codec_data. */
|
||||
h264parse->packetized = FALSE;
|
||||
h264parse->nal_length_size = 4;
|
||||
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ struct _GstH264Parse
|
|||
GstPad *srcpad;
|
||||
|
||||
gboolean split_packetized;
|
||||
guint nal_length_size;
|
||||
|
||||
GstSegment segment;
|
||||
gboolean packetized;
|
||||
|
|
Loading…
Reference in a new issue