h26{4,5}parse: add support for forward predicted trick mode

Also stop assigning TRUE to fields with |=
This commit is contained in:
Mathieu Duponchelle 2019-07-10 23:40:36 +02:00 committed by Mathieu Duponchelle
parent d6680b35b4
commit 2305bf272c
4 changed files with 83 additions and 21 deletions

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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