mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 23:36:38 +00:00
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:
parent
dafa11b9d2
commit
877e69c9ec
2 changed files with 115 additions and 41 deletions
|
@ -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) {
|
||||
/* 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) {
|
||||
/* size not set; might depend on emulation_prevention_three_byte */
|
||||
res = gst_h265_parser_parse_pic_timing (parser,
|
||||
&sei->payload.pic_timing, &nr);
|
||||
} else
|
||||
res = GST_H265_PARSER_OK;
|
||||
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue