diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c index 4f0f986cc4..52f2bf7398 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.c +++ b/gst-libs/gst/codecparsers/gsth264parser.c @@ -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; } /** diff --git a/gst-libs/gst/codecparsers/gsth264parser.h b/gst-libs/gst/codecparsers/gsth264parser.h index 798f339470..f0cd49174f 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.h +++ b/gst-libs/gst/codecparsers/gsth264parser.h @@ -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); diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index 8a144d692d..c1e724dfc7 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -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)