codecs: h264decoder: Add support for field-pair input frame

In case that upstream pushed buffer as a frame unit, not picture
unit for interlaced stream, baseclass should be able to detect
AU boundary (i.e., complementary field pair).

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1947>
This commit is contained in:
Seungha Yang 2021-01-10 23:11:01 +09:00
parent 6366435e19
commit e14bbd7f5c

View file

@ -668,6 +668,7 @@ gst_h264_decoder_split_frame (GstH264Decoder * self, GstH264Picture * picture)
other_field->frame_num = picture->frame_num; other_field->frame_num = picture->frame_num;
other_field->ref = picture->ref; other_field->ref = picture->ref;
other_field->nonexisting = picture->nonexisting; other_field->nonexisting = picture->nonexisting;
other_field->system_frame_number = picture->system_frame_number;
return other_field; return other_field;
} }
@ -965,6 +966,29 @@ gst_h264_decoder_parse_slice (GstH264Decoder * self, GstH264NalUnit * nalu)
priv->active_pps = priv->current_slice.header.pps; priv->active_pps = priv->current_slice.header.pps;
priv->active_sps = priv->active_pps->sequence; priv->active_sps = priv->active_pps->sequence;
/* Check whether field picture boundary within given codec frame.
* This might happen in case that upstream sent buffer per frame unit,
* not picture unit (i.e., AU unit).
* If AU boundary is detected, then finish first field picture we decoded
* in this chain, we should finish the current picture and
* start new field picture decoding */
if (gst_h264_dpb_get_interlaced (priv->dpb) && priv->current_picture &&
!GST_H264_PICTURE_IS_FRAME (priv->current_picture) &&
!priv->current_picture->second_field) {
GstH264PictureField prev_field = priv->current_picture->field;
GstH264PictureField cur_field = GST_H264_PICTURE_FIELD_FRAME;
if (priv->current_slice.header.field_pic_flag)
cur_field = priv->current_slice.header.bottom_field_flag ?
GST_H264_PICTURE_FIELD_BOTTOM_FIELD :
GST_H264_PICTURE_FIELD_TOP_FIELD;
if (cur_field != prev_field) {
GST_LOG_OBJECT (self,
"Found new field picture, finishing the first field picture");
gst_h264_decoder_finish_current_picture (self);
}
}
if (!priv->current_picture) { if (!priv->current_picture) {
GstH264DecoderClass *klass = GST_H264_DECODER_GET_CLASS (self); GstH264DecoderClass *klass = GST_H264_DECODER_GET_CLASS (self);
GstH264Picture *picture = NULL; GstH264Picture *picture = NULL;
@ -1742,8 +1766,12 @@ gst_h264_decoder_finish_picture (GstH264Decoder * self,
* them as such */ * them as such */
gst_h264_dpb_delete_unused (priv->dpb); gst_h264_dpb_delete_unused (priv->dpb);
/* If this is the second field, drop corresponding frame */ /* If field pictures belong to different codec frame,
if (picture->second_field) { * drop codec frame of the second field because we are consuming
* only the first codec frame via GstH264Decoder::output_picture() method */
if (picture->second_field && picture->other_field &&
picture->system_frame_number !=
picture->other_field->system_frame_number) {
GstVideoCodecFrame *frame = gst_video_decoder_get_frame (decoder, GstVideoCodecFrame *frame = gst_video_decoder_get_frame (decoder,
picture->system_frame_number); picture->system_frame_number);