codecs: h264decoder: Split gap picture as well if needed

field pair pictures might be required for reference list
depending on context.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1812>
This commit is contained in:
Seungha Yang 2020-11-17 18:59:35 +09:00
parent 4ee6167616
commit e1adc572a7
2 changed files with 62 additions and 34 deletions

View file

@ -185,6 +185,8 @@ gst_h264_decoder_sliding_window_picture_marking (GstH264Decoder * self,
GstH264Picture * picture); GstH264Picture * picture);
static void gst_h264_decoder_do_output_picture (GstH264Decoder * self, static void gst_h264_decoder_do_output_picture (GstH264Decoder * self,
GstH264Picture * picture); GstH264Picture * picture);
static GstH264Picture *gst_h264_decoder_new_field_picture (GstH264Decoder *
self, GstH264Picture * picture);
static void static void
gst_h264_decoder_class_init (GstH264DecoderClass * klass) gst_h264_decoder_class_init (GstH264DecoderClass * klass)
@ -606,6 +608,47 @@ gst_h264_decoder_update_pic_nums (GstH264Decoder * self,
g_array_unref (dpb); g_array_unref (dpb);
} }
static GstH264Picture *
gst_h264_decoder_split_frame (GstH264Decoder * self, GstH264Picture * picture)
{
GstH264Picture *other_field;
g_assert (GST_H264_PICTURE_IS_FRAME (picture));
other_field = gst_h264_decoder_new_field_picture (self, picture);
if (!other_field) {
GST_WARNING_OBJECT (self,
"Couldn't split frame into complementary field pair");
return NULL;
}
GST_LOG_OBJECT (self, "Split picture %p, poc %d, frame num %d",
picture, picture->pic_order_cnt, picture->frame_num);
/* FIXME: enhance TFF decision by using picture timing SEI */
if (picture->top_field_order_cnt < picture->bottom_field_order_cnt) {
picture->field = GST_H264_PICTURE_FIELD_TOP_FIELD;
picture->pic_order_cnt = picture->top_field_order_cnt;
other_field->field = GST_H264_PICTURE_FIELD_BOTTOM_FIELD;
other_field->pic_order_cnt = picture->bottom_field_order_cnt;
} else {
picture->field = GST_H264_PICTURE_FIELD_BOTTOM_FIELD;
picture->pic_order_cnt = picture->bottom_field_order_cnt;
other_field->field = GST_H264_PICTURE_FIELD_TOP_FIELD;
other_field->pic_order_cnt = picture->top_field_order_cnt;
}
other_field->top_field_order_cnt = picture->top_field_order_cnt;
other_field->bottom_field_order_cnt = picture->bottom_field_order_cnt;
other_field->frame_num = picture->frame_num;
other_field->ref = picture->ref;
other_field->nonexisting = picture->nonexisting;
return other_field;
}
static gboolean static gboolean
gst_h264_decoder_handle_frame_num_gap (GstH264Decoder * self, gint frame_num) gst_h264_decoder_handle_frame_num_gap (GstH264Decoder * self, gint frame_num)
{ {
@ -669,7 +712,15 @@ gst_h264_decoder_handle_frame_num_gap (GstH264Decoder * self, gint frame_num)
} }
gst_h264_dpb_delete_unused (priv->dpb); gst_h264_dpb_delete_unused (priv->dpb);
gst_h264_dpb_add (priv->dpb, picture); if (gst_h264_dpb_get_interlaced (priv->dpb)) {
GstH264Picture *other_field =
gst_h264_decoder_split_frame (self, picture);
gst_h264_dpb_add (priv->dpb, picture);
gst_h264_dpb_add (priv->dpb, other_field);
} else {
gst_h264_dpb_add (priv->dpb, picture);
}
while (gst_h264_dpb_needs_bump (priv->dpb, priv->max_num_reorder_frames, while (gst_h264_dpb_needs_bump (priv->dpb, priv->max_num_reorder_frames,
FALSE)) { FALSE)) {
GstH264Picture *to_output; GstH264Picture *to_output;
@ -793,7 +844,9 @@ gst_h264_decoder_new_field_picture (GstH264Decoder * self,
} }
new_picture = gst_h264_picture_new (); new_picture = gst_h264_picture_new ();
if (!klass->new_field_picture (self, picture, new_picture)) { /* don't confuse subclass by non-existing picture */
if (!picture->nonexisting &&
!klass->new_field_picture (self, picture, new_picture)) {
GST_ERROR_OBJECT (self, "Subclass couldn't handle new field picture"); GST_ERROR_OBJECT (self, "Subclass couldn't handle new field picture");
gst_h264_picture_unref (new_picture); gst_h264_picture_unref (new_picture);
@ -1679,40 +1732,14 @@ gst_h264_decoder_finish_picture (GstH264Decoder * self,
*/ */
if (gst_h264_dpb_get_interlaced (priv->dpb) && if (gst_h264_dpb_get_interlaced (priv->dpb) &&
GST_H264_PICTURE_IS_FRAME (picture)) { GST_H264_PICTURE_IS_FRAME (picture)) {
GstH264Picture *other_field = GstH264Picture *other_field = gst_h264_decoder_split_frame (self, picture);
gst_h264_decoder_new_field_picture (self, picture);
gst_h264_dpb_add (priv->dpb, picture);
if (!other_field) { if (!other_field) {
GST_WARNING_OBJECT (self, GST_WARNING_OBJECT (self,
"Couldn't split frame into complementary field pair"); "Couldn't split frame into complementary field pair");
/* Keep decoding anyway... */ /* Keep decoding anyway... */
gst_h264_dpb_add (priv->dpb, picture);
} else { } else {
GST_LOG_OBJECT (self, "Split picture %p, poc %d, frame num %d",
picture, picture->pic_order_cnt, picture->frame_num);
/* FIXME: enhance TFF decision by using picture timing SEI */
if (picture->top_field_order_cnt < picture->bottom_field_order_cnt) {
picture->field = GST_H264_PICTURE_FIELD_TOP_FIELD;
picture->pic_order_cnt = picture->top_field_order_cnt;
other_field->field = GST_H264_PICTURE_FIELD_BOTTOM_FIELD;
other_field->pic_order_cnt = picture->bottom_field_order_cnt;
} else {
picture->field = GST_H264_PICTURE_FIELD_BOTTOM_FIELD;
picture->pic_order_cnt = picture->bottom_field_order_cnt;
other_field->field = GST_H264_PICTURE_FIELD_TOP_FIELD;
other_field->pic_order_cnt = picture->top_field_order_cnt;
}
other_field->top_field_order_cnt = picture->top_field_order_cnt;
other_field->bottom_field_order_cnt = picture->bottom_field_order_cnt;
other_field->frame_num = picture->frame_num;
other_field->ref = picture->ref;
gst_h264_dpb_add (priv->dpb, picture);
gst_h264_dpb_add (priv->dpb, other_field); gst_h264_dpb_add (priv->dpb, other_field);
} }
} else { } else {

View file

@ -265,16 +265,17 @@ gst_h264_dpb_add (GstH264Dpb * dpb, GstH264Picture * picture)
/* We can do output only when field pair are complete */ /* We can do output only when field pair are complete */
if (picture->second_field) { if (picture->second_field) {
dpb->num_output_needed++; dpb->num_output_needed++;
/* And link each field */
if (picture->other_field)
picture->other_field->other_field = picture;
} }
} }
} else { } else {
picture->needed_for_output = FALSE; picture->needed_for_output = FALSE;
} }
/* Link each field */
if (picture->second_field && picture->other_field) {
picture->other_field->other_field = picture;
}
g_array_append_val (dpb->pic_list, picture); g_array_append_val (dpb->pic_list, picture);
} }