mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
h264parse: Fix multiple SEI messages in one SEI RBSP parsing.
An SEI RBSP could contains more than one SEI message as specified in 7.4.2.3.1. This commit change the parser API: the gst_h264_parser_parse_sei() function now create and fill a GArray containing GstH264SEIMessage. https://bugzilla.gnome.org/show_bug.cgi?id=721715
This commit is contained in:
parent
24c87b18c2
commit
af78b45979
3 changed files with 155 additions and 72 deletions
|
@ -269,6 +269,21 @@ nal_reader_skip (NalReader * nr, guint nbits)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
nal_reader_skip_to_next_byte (NalReader * nr)
|
||||
{
|
||||
if (nr->bits_in_cache == 0) {
|
||||
if (G_LIKELY ((nr->size - nr->byte) > 0))
|
||||
nr->byte++;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nr->bits_in_cache = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
nal_reader_get_pos (const NalReader * nr)
|
||||
{
|
||||
|
@ -490,6 +505,14 @@ scan_for_start_codes (const guint8 * data, guint size)
|
|||
0, size);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_h264_parser_byte_aligned (NalReader * nr)
|
||||
{
|
||||
if (nr->bits_in_cache != 0)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_h264_parser_more_data (NalReader * nr)
|
||||
{
|
||||
|
@ -1145,6 +1168,80 @@ error:
|
|||
return GST_H264_PARSER_ERROR;
|
||||
}
|
||||
|
||||
static GstH264ParserResult
|
||||
gst_h264_parser_parse_sei_message (GstH264NalParser * nalparser,
|
||||
NalReader * nr, GstH264SEIMessage * sei)
|
||||
{
|
||||
guint32 payloadSize;
|
||||
guint8 payload_type_byte, payload_size_byte;
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
guint remaining, payload_size;
|
||||
#endif
|
||||
GstH264ParserResult res;
|
||||
|
||||
GST_DEBUG ("parsing \"Sei message\"");
|
||||
|
||||
sei->payloadType = 0;
|
||||
do {
|
||||
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);
|
||||
payloadSize += payload_size_byte;
|
||||
}
|
||||
while (payload_size_byte == 0xff);
|
||||
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
remaining = nal_reader_get_remaining (nr);
|
||||
payload_size = payloadSize * 8 < remaining ? payloadSize * 8 : remaining;
|
||||
|
||||
GST_DEBUG ("SEI message received: payloadType %u, payloadSize = %u bits",
|
||||
sei->payloadType, payload_size);
|
||||
#endif
|
||||
|
||||
if (sei->payloadType == GST_H264_SEI_BUF_PERIOD) {
|
||||
/* size not set; might depend on emulation_prevention_three_byte */
|
||||
res = gst_h264_parser_parse_buffering_period (nalparser,
|
||||
&sei->payload.buffering_period, nr);
|
||||
} else if (sei->payloadType == GST_H264_SEI_PIC_TIMING) {
|
||||
/* size not set; might depend on emulation_prevention_three_byte */
|
||||
res = gst_h264_parser_parse_pic_timing (nalparser,
|
||||
&sei->payload.pic_timing, nr);
|
||||
} else {
|
||||
/* Just consume payloadSize */
|
||||
guint32 i;
|
||||
for (i = 0; i < payloadSize; i++)
|
||||
nal_reader_skip_to_next_byte (nr);
|
||||
res = GST_H264_PARSER_OK;
|
||||
}
|
||||
|
||||
/* When SEI message doesn't end at byte boundary,
|
||||
* check remaining bits fit the specification.
|
||||
*/
|
||||
if (!gst_h264_parser_byte_aligned (nr)) {
|
||||
guint8 bit_equal_to_one;
|
||||
READ_UINT8 (nr, bit_equal_to_one, 1);
|
||||
if (!bit_equal_to_one)
|
||||
GST_WARNING ("Bit non equal to one.");
|
||||
|
||||
while (!gst_h264_parser_byte_aligned (nr)) {
|
||||
guint8 bit_equal_to_zero;
|
||||
READ_UINT8 (nr, bit_equal_to_zero, 1);
|
||||
if (bit_equal_to_zero)
|
||||
GST_WARNING ("Bit non equal to zero.");
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
error:
|
||||
GST_WARNING ("error parsing \"Sei message\"");
|
||||
return GST_H264_PARSER_ERROR;
|
||||
}
|
||||
|
||||
/******** API *************/
|
||||
|
||||
/**
|
||||
|
@ -1942,69 +2039,33 @@ error:
|
|||
* gst_h264_parser_parse_sei:
|
||||
* @nalparser: a #GstH264NalParser
|
||||
* @nalu: The #GST_H264_NAL_SEI #GstH264NalUnit to parse
|
||||
* @sei: The #GstH264SEIMessage to fill.
|
||||
* @messages: The GArray of #GstH264SEIMessage to fill. The caller must free it when done.
|
||||
*
|
||||
* Parses @data, and fills the @sei structures.
|
||||
* Parses @data, create and fills the @messages array.
|
||||
*
|
||||
* Returns: a #GstH264ParserResult
|
||||
*/
|
||||
GstH264ParserResult
|
||||
gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu,
|
||||
GstH264SEIMessage * sei)
|
||||
GArray ** messages)
|
||||
{
|
||||
NalReader nr;
|
||||
|
||||
guint32 payloadSize;
|
||||
guint8 payload_type_byte, payload_size_byte;
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
guint remaining, payload_size;
|
||||
#endif
|
||||
GstH264SEIMessage sei;
|
||||
GstH264ParserResult res;
|
||||
|
||||
GST_DEBUG ("parsing \"Sei message\"");
|
||||
|
||||
GST_DEBUG ("parsing SEI nal");
|
||||
nal_reader_init (&nr, nalu->data + nalu->offset + 1, nalu->size - 1);
|
||||
*messages = g_array_new (FALSE, FALSE, sizeof (GstH264SEIMessage));
|
||||
|
||||
/* init */
|
||||
memset (sei, 0, sizeof (*sei));
|
||||
|
||||
sei->payloadType = 0;
|
||||
do {
|
||||
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);
|
||||
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;
|
||||
|
||||
GST_DEBUG ("SEI message received: payloadType %u, payloadSize = %u bytes",
|
||||
sei->payloadType, payload_size);
|
||||
#endif
|
||||
|
||||
if (sei->payloadType == GST_H264_SEI_BUF_PERIOD) {
|
||||
/* size not set; might depend on emulation_prevention_three_byte */
|
||||
res = gst_h264_parser_parse_buffering_period (nalparser,
|
||||
&sei->payload.buffering_period, &nr);
|
||||
} else if (sei->payloadType == GST_H264_SEI_PIC_TIMING) {
|
||||
/* size not set; might depend on emulation_prevention_three_byte */
|
||||
res = gst_h264_parser_parse_pic_timing (nalparser,
|
||||
&sei->payload.pic_timing, &nr);
|
||||
} else
|
||||
res = GST_H264_PARSER_OK;
|
||||
res = gst_h264_parser_parse_sei_message (nalparser, &nr, &sei);
|
||||
if (res == GST_H264_PARSER_OK)
|
||||
g_array_append_val (*messages, sei);
|
||||
else
|
||||
break;
|
||||
} while (gst_h264_parser_more_data (&nr));
|
||||
|
||||
return res;
|
||||
|
||||
error:
|
||||
GST_WARNING ("error parsing \"Sei message\"");
|
||||
return GST_H264_PARSER_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -749,7 +749,7 @@ GstH264ParserResult gst_h264_parser_parse_pps (GstH264NalParser *nalpars
|
|||
GstH264NalUnit *nalu, GstH264PPS *pps);
|
||||
|
||||
GstH264ParserResult gst_h264_parser_parse_sei (GstH264NalParser *nalparser,
|
||||
GstH264NalUnit *nalu, GstH264SEIMessage *sei);
|
||||
GstH264NalUnit *nalu, GArray ** messages);
|
||||
|
||||
void gst_h264_nal_parser_free (GstH264NalParser *nalparser);
|
||||
|
||||
|
|
|
@ -460,6 +460,50 @@ _nal_name (GstH264NalUnitType nal_type)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gst_h264_parse_process_sei (GstH264Parse * h264parse, GstH264NalUnit * nalu)
|
||||
{
|
||||
GstH264SEIMessage sei;
|
||||
GstH264NalParser *nalparser = h264parse->nalparser;
|
||||
GstH264ParserResult pres;
|
||||
GArray *messages;
|
||||
guint i;
|
||||
|
||||
pres = gst_h264_parser_parse_sei (nalparser, nalu, &messages);
|
||||
if (pres != GST_H264_PARSER_OK)
|
||||
GST_WARNING_OBJECT (h264parse, "failed to parse one ore more SEI message");
|
||||
|
||||
/* Even if pres != GST_H264_PARSER_OK, some message could have been parsed and
|
||||
* stored in messages.
|
||||
*/
|
||||
for (i = 0; i < messages->len; i++) {
|
||||
sei = g_array_index (messages, GstH264SEIMessage, i);
|
||||
switch (sei.payloadType) {
|
||||
case GST_H264_SEI_PIC_TIMING:
|
||||
h264parse->sei_pic_struct_pres_flag =
|
||||
sei.payload.pic_timing.pic_struct_present_flag;
|
||||
h264parse->sei_cpb_removal_delay =
|
||||
sei.payload.pic_timing.cpb_removal_delay;
|
||||
if (h264parse->sei_pic_struct_pres_flag)
|
||||
h264parse->sei_pic_struct = sei.payload.pic_timing.pic_struct;
|
||||
GST_LOG_OBJECT (h264parse, "pic timing updated");
|
||||
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;
|
||||
}
|
||||
}
|
||||
g_array_free (messages, TRUE);
|
||||
}
|
||||
|
||||
/* caller guarantees 2 bytes of nal payload */
|
||||
static void
|
||||
gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
|
||||
|
@ -467,7 +511,6 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
|
|||
guint nal_type;
|
||||
GstH264PPS pps = { 0, };
|
||||
GstH264SPS sps = { 0, };
|
||||
GstH264SEIMessage sei;
|
||||
GstH264NalParser *nalparser = h264parse->nalparser;
|
||||
GstH264ParserResult pres;
|
||||
|
||||
|
@ -528,28 +571,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
|
|||
gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu);
|
||||
break;
|
||||
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.payload.pic_timing.pic_struct_present_flag;
|
||||
h264parse->sei_cpb_removal_delay =
|
||||
sei.payload.pic_timing.cpb_removal_delay;
|
||||
if (h264parse->sei_pic_struct_pres_flag)
|
||||
h264parse->sei_pic_struct = sei.payload.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;
|
||||
}
|
||||
gst_h264_parse_process_sei (h264parse, nalu);
|
||||
/* mark SEI pos */
|
||||
if (h264parse->sei_pos == -1) {
|
||||
if (h264parse->transform)
|
||||
|
|
Loading…
Reference in a new issue