codecparser: h265: Fix parsing multiple SEI messages in a single SEI Nal

An SEI Nal can have more than one SEI message.

Change in API: the gst_h265_parser_parse_sei()
This commit is contained in:
Sreerenj Balachandran 2015-04-17 15:01:57 +03:00 committed by Sebastian Dröge
parent dafa11b9d2
commit 877e69c9ec
2 changed files with 115 additions and 41 deletions

View file

@ -2224,68 +2224,106 @@ error:
return GST_H265_PARSER_ERROR;
}
/**
* gst_h265_parser_parse_sei:
* @parser: a #GstH265Parser
* @nalu: The #GST_H265_NAL_SEI #GstH265NalUnit to parse
* @sei: The #GstH265SEIMessage to fill.
*
* Parses @data, and fills the @sei structures.
* The resulting @sei structure shall be deallocated with
* gst_h265_sei_free() when it is no longer needed
*
* Returns: a #GstH265ParserResult
*/
GstH265ParserResult
gst_h265_parser_parse_sei (GstH265Parser * parser,
GstH265NalUnit * nalu, GstH265SEIMessage * sei)
static gboolean
nal_reader_has_more_data_in_payload (NalReader * nr,
guint32 payload_start_pos_bit, guint32 payloadSize)
{
if (nal_reader_is_byte_aligned (nr) &&
(nal_reader_get_pos (nr) == (payload_start_pos_bit + 8 * payloadSize)))
return FALSE;
return TRUE;
}
static GstH265ParserResult
gst_h265_parser_parse_sei_message (GstH265Parser * parser,
guint8 nal_type, NalReader * nr, GstH265SEIMessage * sei)
{
NalReader nr;
guint32 payloadSize;
guint8 payload_type_byte, payload_size_byte;
#ifndef GST_DISABLE_GST_DEBUG
guint remaining, payload_size;
#endif
GstH265ParserResult res;
guint32 payload_start_pos_bit;
GstH265ParserResult res = GST_H265_PARSER_OK;
GST_DEBUG ("parsing \"Sei message\"");
nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
/* init */
memset (sei, 0, sizeof (*sei));
sei->payloadType = 0;
do {
READ_UINT8 (&nr, payload_type_byte, 8);
READ_UINT8 (nr, payload_type_byte, 8);
sei->payloadType += payload_type_byte;
} while (payload_type_byte == 0xff);
payloadSize = 0;
do {
READ_UINT8 (&nr, payload_size_byte, 8);
READ_UINT8 (nr, payload_size_byte, 8);
payloadSize += payload_size_byte;
}
while (payload_size_byte == 0xff);
#ifndef GST_DISABLE_GST_DEBUG
remaining = nal_reader_get_remaining (&nr) * 8;
payload_size = payloadSize < remaining ? payloadSize : remaining;
remaining = nal_reader_get_remaining (nr);
payload_size = payloadSize * 8 < remaining ? payloadSize * 8 : remaining;
payload_start_pos_bit = nal_reader_get_pos (nr);
GST_DEBUG
("SEI message received: payloadType %u, payloadSize = %u bytes",
sei->payloadType, payload_size);
#endif
if (sei->payloadType == GST_H265_SEI_BUF_PERIOD) {
if (nal_type == GST_H265_NAL_PREFIX_SEI) {
switch (sei->payloadType) {
case GST_H265_SEI_BUF_PERIOD:
/* size not set; might depend on emulation_prevention_three_byte */
res = gst_h265_parser_parse_buffering_period (parser,
&sei->payload.buffering_period, &nr);
} else if (sei->payloadType == GST_H265_SEI_PIC_TIMING) {
&sei->payload.buffering_period, nr);
break;
case GST_H265_SEI_PIC_TIMING:
/* size not set; might depend on emulation_prevention_three_byte */
res = gst_h265_parser_parse_pic_timing (parser,
&sei->payload.pic_timing, &nr);
} else
&sei->payload.pic_timing, nr);
break;
default:
/* Just consume payloadSize bytes, which does not account for
emulation prevention bytes */
if (!nal_reader_skip_long (nr, payload_size))
goto error;
res = GST_H265_PARSER_OK;
break;
}
} else if (nal_type == GST_H265_NAL_SUFFIX_SEI) {
switch (sei->payloadType) {
default:
/* Just consume payloadSize bytes, which does not account for
emulation prevention bytes */
if (!nal_reader_skip_long (nr, payload_size))
goto error;
res = GST_H265_PARSER_OK;
break;
}
}
/* Not parsing the reserved_payload_extension, but it shouldn't be
* an issue because of 1: There shall not be any reserved_payload_extension
* present in bitstreams conforming to the specification.2. Even though
* it is present, the size will be less than total PayloadSize since the
* size of reserved_payload_extension is supposed to be
* 8 * payloadSize - nEarlierBits - nPayloadZeroBits -1 which means the
* the current implementation will still skip all unnecessary bits correctly.
* In theory, we can have a more optimized implementation by skipping the
* data left in PayLoadSize without out individually checking for each bits,
* since the totoal size will be always less than payloadSize*/
if (nal_reader_has_more_data_in_payload (nr, payload_start_pos_bit,
payloadSize)) {
/* Skip the byte alignment bits */
if (!nal_reader_skip (nr, 1))
goto error;
while (!nal_reader_is_byte_aligned (nr)) {
if (!nal_reader_skip (nr, 1))
goto error;
}
}
return res;
error:
GST_WARNING ("error parsing \"Sei message\"");
gst_h265_sei_free (sei);
return GST_H265_PARSER_ERROR;
}
@ -2404,6 +2442,42 @@ gst_h265_sei_free (GstH265SEIMessage * sei)
}
}
/**
* gst_h265_parser_parse_sei:
* @nalparser: a #GstH265Parser
* @nalu: The #GST_H265_NAL_SEI #GstH265NalUnit to parse
* @messages: The GArray of #GstH265SEIMessage to fill. The caller must free it when done.
*
* Parses @data, create and fills the @messages array.
*
* Returns: a #GstH265ParserResult
*/
GstH265ParserResult
gst_h265_parser_parse_sei (GstH265Parser * nalparser, GstH265NalUnit * nalu,
GArray ** messages)
{
NalReader nr;
GstH265SEIMessage sei;
GstH265ParserResult res;
GST_DEBUG ("parsing SEI nal");
nal_reader_init (&nr, nalu->data + nalu->offset + nalu->header_bytes,
nalu->size - nalu->header_bytes);
*messages = g_array_new (FALSE, FALSE, sizeof (GstH265SEIMessage));
g_array_set_clear_func (*messages, (GDestroyNotify) gst_h265_sei_free);
do {
res = gst_h265_parser_parse_sei_message (nalparser, nalu->type, &nr, &sei);
if (res == GST_H265_PARSER_OK)
g_array_append_val (*messages, sei);
else
break;
} while (nal_reader_has_more_data (&nr));
return res;
}
/**
* gst_h265_quant_matrix_4x4_get_zigzag_from_raster:
* @out_quant: (out): The resulting quantization matrix

View file

@ -1035,7 +1035,7 @@ GstH265ParserResult gst_h265_parser_parse_pps (GstH265Parser * parser,
GstH265ParserResult gst_h265_parser_parse_sei (GstH265Parser * parser,
GstH265NalUnit * nalu,
GstH265SEIMessage * sei);
GArray **messages);
void gst_h265_parser_free (GstH265Parser * parser);