From 2305bf272c7a203786d73bc5225383673b2c6243 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Wed, 10 Jul 2019 23:40:36 +0200 Subject: [PATCH] h26{4,5}parse: add support for forward predicted trick mode Also stop assigning TRUE to fields with |= --- gst/videoparsers/gsth264parse.c | 34 ++++++++++++++++--- gst/videoparsers/gsth264parse.h | 5 +++ gst/videoparsers/gsth265parse.c | 60 ++++++++++++++++++++++++--------- gst/videoparsers/gsth265parse.h | 5 +++ 4 files changed, 83 insertions(+), 21 deletions(-) diff --git a/gst/videoparsers/gsth264parse.c b/gst/videoparsers/gsth264parse.c index c60ab43681..abf6bab15e 100644 --- a/gst/videoparsers/gsth264parse.c +++ b/gst/videoparsers/gsth264parse.c @@ -193,6 +193,8 @@ gst_h264_parse_reset_frame (GstH264Parse * h264parse) h264parse->idr_pos = -1; h264parse->sei_pos = -1; h264parse->keyframe = FALSE; + h264parse->predicted = FALSE; + h264parse->bidirectional = FALSE; h264parse->header = FALSE; h264parse->frame_start = FALSE; h264parse->aud_insert = TRUE; @@ -260,6 +262,7 @@ gst_h264_parse_reset (GstH264Parse * h264parse) gst_event_replace (&h264parse->force_key_unit_event, NULL); h264parse->discont = FALSE; + h264parse->discard_bidirectional = FALSE; gst_h264_parse_reset_stream_info (h264parse); } @@ -855,7 +858,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) if (pres != GST_H264_PARSER_OK) { GST_WARNING_OBJECT (h264parse, "failed to parse SPS:"); h264parse->state |= GST_H264_PARSE_STATE_GOT_SPS; - h264parse->header |= TRUE; + h264parse->header = TRUE; return FALSE; } @@ -875,7 +878,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) gst_h264_parser_store_nal (h264parse, sps.id, nal_type, nalu); gst_h264_sps_clear (&sps); h264parse->state |= GST_H264_PARSE_STATE_GOT_SPS; - h264parse->header |= TRUE; + h264parse->header = TRUE; break; case GST_H264_NAL_PPS: /* expected state: got-sps */ @@ -910,14 +913,14 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) gst_h264_parser_store_nal (h264parse, pps.id, nal_type, nalu); gst_h264_pps_clear (&pps); h264parse->state |= GST_H264_PARSE_STATE_GOT_PPS; - h264parse->header |= TRUE; + h264parse->header = TRUE; break; case GST_H264_NAL_SEI: /* expected state: got-sps */ if (!GST_H264_PARSE_STATE_VALID (h264parse, GST_H264_PARSE_STATE_GOT_SPS)) return FALSE; - h264parse->header |= TRUE; + h264parse->header = TRUE; gst_h264_parse_process_sei (h264parse, nalu); /* mark SEI pos */ if (h264parse->sei_pos == -1) { @@ -962,7 +965,12 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu) 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; + 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; @@ -2335,6 +2343,9 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) else GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + if (h264parse->discard_bidirectional && h264parse->bidirectional) + goto discard; + if (h264parse->header) GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER); else @@ -2356,7 +2367,14 @@ gst_h264_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) gst_buffer_unref (buf); } +done: return GST_FLOW_OK; + +discard: + GST_DEBUG_OBJECT (h264parse, "Discarding bidirectional frame"); + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; + gst_h264_parse_reset_frame (h264parse); + goto done; } /* sends a codec NAL downstream, decorating and transforming as needed. @@ -3156,6 +3174,12 @@ gst_h264_parse_event (GstBaseParse * parse, GstEvent * event) || segment->applied_rate != 1.0)) h264parse->do_ts = FALSE; + if (segment->flags & GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) { + GST_DEBUG_OBJECT (h264parse, "Will discard bidirectional frames"); + h264parse->discard_bidirectional = TRUE; + } + + h264parse->last_report = GST_CLOCK_TIME_NONE; res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event); diff --git a/gst/videoparsers/gsth264parse.h b/gst/videoparsers/gsth264parse.h index 14f3ea716a..812f110702 100644 --- a/gst/videoparsers/gsth264parse.h +++ b/gst/videoparsers/gsth264parse.h @@ -123,6 +123,8 @@ struct _GstH264Parse gboolean update_caps; GstAdapter *frame_out; gboolean keyframe; + gboolean predicted; + gboolean bidirectional; gboolean header; gboolean frame_start; /* AU state */ @@ -147,6 +149,9 @@ struct _GstH264Parse guint8 closedcaptions[96]; guint closedcaptions_size; GstVideoCaptionType closedcaptions_type; + + /* For forward predicted trickmode */ + gboolean discard_bidirectional; }; struct _GstH264ParseClass diff --git a/gst/videoparsers/gsth265parse.c b/gst/videoparsers/gsth265parse.c index 686f146d2d..501ab14fd1 100644 --- a/gst/videoparsers/gsth265parse.c +++ b/gst/videoparsers/gsth265parse.c @@ -189,6 +189,8 @@ gst_h265_parse_reset_frame (GstH265Parse * h265parse) h265parse->idr_pos = -1; h265parse->sei_pos = -1; h265parse->keyframe = FALSE; + h265parse->predicted = FALSE; + h265parse->bidirectional = FALSE; h265parse->header = FALSE; h265parse->have_vps_in_frame = FALSE; h265parse->have_sps_in_frame = FALSE; @@ -255,6 +257,7 @@ gst_h265_parse_reset (GstH265Parse * h265parse) gst_event_replace (&h265parse->force_key_unit_event, NULL); h265parse->discont = FALSE; + h265parse->discard_bidirectional = FALSE; gst_h265_parse_reset_stream_info (h265parse); } @@ -593,11 +596,11 @@ gst_h265_parse_process_sei (GstH265Parse * h265parse, GstH265NalUnit * nalu) minfo.Wx_n = sei.payload.mastering_display_colour_volume.white_point_x; minfo.Wy_n = sei.payload.mastering_display_colour_volume.white_point_y; minfo.max_luma_n = - sei.payload. - mastering_display_colour_volume.max_display_mastering_luminance; + sei.payload.mastering_display_colour_volume. + max_display_mastering_luminance; minfo.min_luma_n = - sei.payload. - mastering_display_colour_volume.min_display_mastering_luminance; + sei.payload.mastering_display_colour_volume. + min_display_mastering_luminance; minfo.Gx_d = minfo.Gy_d = minfo.Bx_d = minfo.By_d = minfo.Rx_d = minfo.Ry_d = minfo.Wx_d = minfo.Wy_d = chroma_den; @@ -716,7 +719,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) } gst_h265_parser_store_nal (h265parse, vps.id, nal_type, nalu); - h265parse->header |= TRUE; + h265parse->header = TRUE; break; case GST_H265_NAL_SPS: /* reset state, everything else is obsolete */ @@ -732,7 +735,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) if (pres != GST_H265_PARSER_OK) { GST_WARNING_OBJECT (h265parse, "failed to parse SPS:"); h265parse->state |= GST_H265_PARSE_STATE_GOT_SPS; - h265parse->header |= TRUE; + h265parse->header = TRUE; return FALSE; } GST_WARNING_OBJECT (h265parse, @@ -753,7 +756,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) } gst_h265_parser_store_nal (h265parse, sps.id, nal_type, nalu); - h265parse->header |= TRUE; + h265parse->header = TRUE; h265parse->state |= GST_H265_PARSE_STATE_GOT_SPS; break; case GST_H265_NAL_PPS: @@ -789,7 +792,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) } gst_h265_parser_store_nal (h265parse, pps.id, nal_type, nalu); - h265parse->header |= TRUE; + h265parse->header = TRUE; h265parse->state |= GST_H265_PARSE_STATE_GOT_PPS; break; case GST_H265_NAL_PREFIX_SEI: @@ -798,7 +801,7 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) if (!GST_H265_PARSE_STATE_VALID (h265parse, GST_H265_PARSE_STATE_GOT_SPS)) return FALSE; - h265parse->header |= TRUE; + h265parse->header = TRUE; gst_h265_parse_process_sei (h265parse, nalu); @@ -844,7 +847,11 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu) if (pres == GST_H265_PARSER_OK) { if (GST_H265_IS_I_SLICE (&slice)) - h265parse->keyframe |= TRUE; + h265parse->keyframe = TRUE; + else if (GST_H265_IS_P_SLICE (&slice)) + h265parse->predicted = TRUE; + else if (GST_H265_IS_B_SLICE (&slice)) + h265parse->bidirectional = TRUE; h265parse->state |= GST_H265_PARSE_STATE_GOT_SLICE; } @@ -2118,6 +2125,10 @@ gst_h265_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) else GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); + if (h265parse->discard_bidirectional && h265parse->bidirectional) + goto discard; + + if (h265parse->header) GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER); else @@ -2139,7 +2150,15 @@ gst_h265_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) gst_buffer_unref (buf); } +done: return GST_FLOW_OK; + +discard: + GST_DEBUG_OBJECT (h265parse, "Discarding bidirectional frame"); + frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; + gst_h265_parse_reset_frame (h265parse); + goto done; + } /* sends a codec NAL downstream, decorating and transforming as needed. @@ -2551,12 +2570,12 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) h265parse->parsed_fps_d, NULL, flags, - h265parse->time_code.hours_flag[i] ? h265parse-> - time_code.hours_value[i] : 0, - h265parse->time_code.minutes_flag[i] ? h265parse-> - time_code.minutes_value[i] : 0, - h265parse->time_code.seconds_flag[i] ? h265parse-> - time_code.seconds_value[i] : 0, n_frames, field_count); + h265parse->time_code.hours_flag[i] ? h265parse->time_code. + hours_value[i] : 0, + h265parse->time_code.minutes_flag[i] ? h265parse->time_code. + minutes_value[i] : 0, + h265parse->time_code.seconds_flag[i] ? h265parse->time_code. + seconds_value[i] : 0, n_frames, field_count); } } @@ -2846,8 +2865,17 @@ gst_h265_parse_event (GstBaseParse * parse, GstEvent * event) break; case GST_EVENT_SEGMENT: { + const GstSegment *segment = NULL; + + gst_event_parse_segment (event, &segment); + h265parse->last_report = GST_CLOCK_TIME_NONE; + if (segment->flags & GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED) { + GST_DEBUG_OBJECT (h265parse, "Will discard bidirectional frames"); + h265parse->discard_bidirectional = TRUE; + } + res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event); break; } diff --git a/gst/videoparsers/gsth265parse.h b/gst/videoparsers/gsth265parse.h index 7b777e3369..0af1528d70 100644 --- a/gst/videoparsers/gsth265parse.h +++ b/gst/videoparsers/gsth265parse.h @@ -102,6 +102,8 @@ struct _GstH265Parse gboolean update_caps; GstAdapter *frame_out; gboolean keyframe; + gboolean predicted; + gboolean bidirectional; gboolean header; /* AU state */ gboolean picture_start; @@ -119,6 +121,9 @@ struct _GstH265Parse GstVideoContentLightLevel content_light_level; guint content_light_level_state; + + /* For forward predicted trickmode */ + gboolean discard_bidirectional; }; struct _GstH265ParseClass