From 4b8c47ee3795216cdae4957b45499a61806aa456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Tue, 17 Dec 2019 12:08:34 +0100 Subject: [PATCH] h26xparse: Handle state change on IDR first slice As the H265/H264 bitstream can support multiple slices, mastering_display_info_state and content_light_level_state should be changed only on first slice segment. Fix #1152 --- gst/videoparsers/gsth264parse.c | 62 +++++++++++++++++---------------- gst/videoparsers/gsth265parse.c | 3 +- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index c769defc82..a4c7fc1d94 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -879,6 +879,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) GstH264SPS sps = { 0, }; GstH264NalParser *nalparser = h264parse->nalparser; GstH264ParserResult pres; + GstH264SliceHdr slice; /* nothing to do for broken input */ if (G_UNLIKELY (nalu->size < 2)) { @@ -1006,30 +1007,29 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) GST_DEBUG_OBJECT (h264parse, "frame start: %i", h264parse->frame_start); if (nal_type == GST_H264_NAL_SLICE_EXT && !GST_H264_IS_MVC_NALU (nalu)) break; - { - GstH264SliceHdr slice; - pres = gst_h264_parser_parse_slice_hdr (nalparser, nalu, &slice, - FALSE, FALSE); - GST_DEBUG_OBJECT (h264parse, - "parse result %d, first MB: %u, slice type: %u", - pres, slice.first_mb_in_slice, slice.type); - if (pres == GST_H264_PARSER_OK) { - if (GST_H264_IS_I_SLICE (&slice) || GST_H264_IS_SI_SLICE (&slice)) - h264parse->keyframe = TRUE; - else if (GST_H264_IS_P_SLICE (&slice) - || GST_H264_IS_SP_SLICE (&slice)) - h264parse->predicted = TRUE; - else if (GST_H264_IS_B_SLICE (&slice)) - h264parse->bidirectional = TRUE; + pres = gst_h264_parser_parse_slice_hdr (nalparser, nalu, &slice, + FALSE, FALSE); + GST_DEBUG_OBJECT (h264parse, + "parse result %d, first MB: %u, slice type: %u", + pres, slice.first_mb_in_slice, slice.type); + if (pres == GST_H264_PARSER_OK) { + if (GST_H264_IS_I_SLICE (&slice) || GST_H264_IS_SI_SLICE (&slice)) + h264parse->keyframe = TRUE; + else if (GST_H264_IS_P_SLICE (&slice) + || GST_H264_IS_SP_SLICE (&slice)) + h264parse->predicted = TRUE; + else if (GST_H264_IS_B_SLICE (&slice)) + h264parse->bidirectional = TRUE; - h264parse->state |= GST_H264_PARSE_STATE_GOT_SLICE; - h264parse->field_pic_flag = slice.field_pic_flag; - } + h264parse->state |= GST_H264_PARSE_STATE_GOT_SLICE; + h264parse->field_pic_flag = slice.field_pic_flag; } + if (G_LIKELY (nal_type != GST_H264_NAL_SLICE_IDR && !h264parse->push_codec)) break; + /* if we need to sneak codec NALs into the stream, * this is a good place, so fake it as IDR * (which should be at start anyway) */ @@ -1049,19 +1049,21 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) GST_DEBUG_OBJECT (h264parse, "moved IDR mark to SEI position %d", h264parse->idr_pos); } + /* Reset state only on first IDR slice of CVS D.2.29 */ + if (slice.first_mb_in_slice == 0) { + if (h264parse->mastering_display_info_state == + GST_H264_PARSE_SEI_PARSED) + h264parse->mastering_display_info_state = GST_H264_PARSE_SEI_ACTIVE; + else if (h264parse->mastering_display_info_state == + GST_H264_PARSE_SEI_ACTIVE) + h264parse->mastering_display_info_state = GST_H264_PARSE_SEI_EXPIRED; - if (h264parse->mastering_display_info_state == GST_H264_PARSE_SEI_PARSED) - h264parse->mastering_display_info_state = GST_H264_PARSE_SEI_ACTIVE; - else if (h264parse->mastering_display_info_state == - GST_H264_PARSE_SEI_ACTIVE) - h264parse->mastering_display_info_state = GST_H264_PARSE_SEI_EXPIRED; - - if (h264parse->content_light_level_state == GST_H264_PARSE_SEI_PARSED) - h264parse->content_light_level_state = GST_H264_PARSE_SEI_ACTIVE; - else if (h264parse->content_light_level_state == - GST_H264_PARSE_SEI_ACTIVE) - h264parse->content_light_level_state = GST_H264_PARSE_SEI_EXPIRED; - + if (h264parse->content_light_level_state == GST_H264_PARSE_SEI_PARSED) + h264parse->content_light_level_state = GST_H264_PARSE_SEI_ACTIVE; + else if (h264parse->content_light_level_state == + GST_H264_PARSE_SEI_ACTIVE) + h264parse->content_light_level_state = GST_H264_PARSE_SEI_EXPIRED; + } break; case GST_H264_NAL_AU_DELIMITER: /* Just accumulate AU Delimiter, whether it's before SPS or not */ diff --git a/gst/videoparsers/gsth265parse.c b/gst/videoparsers/gsth265parse.c index 5b7abdc310..fb1c94c0c4 100644 --- a/gst/videoparsers/gsth265parse.c +++ b/gst/videoparsers/gsth265parse.c @@ -921,7 +921,8 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) is_irap = ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP) && (nal_type <= GST_H265_NAL_SLICE_CRA_NUT)) ? TRUE : FALSE; - if (no_rasl_output_flag && is_irap) { + if (no_rasl_output_flag && is_irap + && slice.first_slice_segment_in_pic_flag == 1) { if (h265parse->mastering_display_info_state == GST_H265_PARSE_SEI_PARSED) h265parse->mastering_display_info_state = GST_H265_PARSE_SEI_ACTIVE;