mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
v4l2codecs: h264: Fix split field handling
Split fields ends up on multiple picture and requires accessing the other_field to complete the information (POC). This also cleanup the DPB from non-reference (was not useful) and skips properly merge field instead of keeping them duplicated. This fixes most of interlace decoding seen in fluster. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2474>
This commit is contained in:
parent
ad5dcfb091
commit
4eb22b7695
1 changed files with 94 additions and 35 deletions
|
@ -530,13 +530,11 @@ gst_v4l2_codec_h264_dec_fill_decoder_params (GstV4l2CodecH264Dec * self,
|
|||
GstH264SliceHdr * slice_hdr, GstH264Picture * picture, GstH264Dpb * dpb)
|
||||
{
|
||||
GArray *refs = gst_h264_dpb_get_pictures_all (dpb);
|
||||
gint i;
|
||||
gint i, entry_id = 0;
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
self->decode_params = (struct v4l2_ctrl_h264_decode_params) {
|
||||
.nal_ref_idc = picture->nal_ref_idc,
|
||||
.top_field_order_cnt = picture->top_field_order_cnt,
|
||||
.bottom_field_order_cnt = picture->bottom_field_order_cnt,
|
||||
.frame_num = slice_hdr->frame_num,
|
||||
.idr_pic_id = slice_hdr->idr_pic_id,
|
||||
.pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb,
|
||||
|
@ -551,28 +549,38 @@ gst_v4l2_codec_h264_dec_fill_decoder_params (GstV4l2CodecH264Dec * self,
|
|||
(slice_hdr->bottom_field_flag ? V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD : 0),
|
||||
};
|
||||
|
||||
for (i = 0; i < refs->len; i++) {
|
||||
GstH264Picture *ref_pic = g_array_index (refs, GstH264Picture *, i);
|
||||
gint pic_num = ref_pic->pic_num;
|
||||
guchar dpb_ref = 0;
|
||||
|
||||
/* Unwrap pic_num */
|
||||
if (pic_num < 0)
|
||||
pic_num += slice_hdr->max_pic_num;
|
||||
|
||||
switch (ref_pic->field) {
|
||||
switch (picture->field) {
|
||||
case GST_H264_PICTURE_FIELD_FRAME:
|
||||
dpb_ref = V4L2_H264_FRAME_REF;
|
||||
self->decode_params.top_field_order_cnt = picture->top_field_order_cnt;
|
||||
self->decode_params.bottom_field_order_cnt =
|
||||
picture->bottom_field_order_cnt;
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_TOP_FIELD:
|
||||
dpb_ref = V4L2_H264_TOP_FIELD_REF;
|
||||
self->decode_params.top_field_order_cnt = picture->top_field_order_cnt;
|
||||
self->decode_params.bottom_field_order_cnt = 0;
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
|
||||
dpb_ref = V4L2_H264_BOTTOM_FIELD_REF;
|
||||
self->decode_params.top_field_order_cnt = 0;
|
||||
self->decode_params.bottom_field_order_cnt =
|
||||
picture->bottom_field_order_cnt;
|
||||
break;
|
||||
}
|
||||
|
||||
self->decode_params.dpb[i] = (struct v4l2_h264_dpb_entry) {
|
||||
for (i = 0; i < refs->len; i++) {
|
||||
GstH264Picture *ref_pic = g_array_index (refs, GstH264Picture *, i);
|
||||
gint pic_num = ref_pic->pic_num;
|
||||
struct v4l2_h264_dpb_entry *entry;
|
||||
|
||||
/* Skip non-reference as they are not useful to decoding */
|
||||
if (!GST_H264_PICTURE_IS_REF (ref_pic))
|
||||
continue;
|
||||
|
||||
/* The second field picture will be handled differently */
|
||||
if (ref_pic->second_field)
|
||||
continue;
|
||||
|
||||
entry = &self->decode_params.dpb[entry_id++];
|
||||
*entry = (struct v4l2_h264_dpb_entry) {
|
||||
/*
|
||||
* The reference is multiplied by 1000 because it's wassed as micro
|
||||
* seconds and this TS is nanosecond.
|
||||
|
@ -580,15 +588,42 @@ gst_v4l2_codec_h264_dec_fill_decoder_params (GstV4l2CodecH264Dec * self,
|
|||
.reference_ts = (guint64) ref_pic->system_frame_number * 1000,
|
||||
.frame_num = ref_pic->frame_num,
|
||||
.pic_num = pic_num,
|
||||
.top_field_order_cnt = ref_pic->pic_order_cnt,
|
||||
.bottom_field_order_cnt = ref_pic->bottom_field_order_cnt,
|
||||
.flags = V4L2_H264_DPB_ENTRY_FLAG_VALID
|
||||
| (GST_H264_PICTURE_IS_REF (ref_pic) ?
|
||||
V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0)
|
||||
| (GST_H264_PICTURE_IS_LONG_TERM_REF (ref_pic) ?
|
||||
V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0),
|
||||
.fields = dpb_ref,
|
||||
| (GST_H264_PICTURE_IS_REF (ref_pic) ? V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0)
|
||||
| (GST_H264_PICTURE_IS_LONG_TERM_REF (ref_pic) ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0),
|
||||
};
|
||||
|
||||
switch (ref_pic->field) {
|
||||
case GST_H264_PICTURE_FIELD_FRAME:
|
||||
entry->top_field_order_cnt = ref_pic->top_field_order_cnt;
|
||||
entry->bottom_field_order_cnt = ref_pic->bottom_field_order_cnt;
|
||||
entry->fields = V4L2_H264_FRAME_REF;
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_TOP_FIELD:
|
||||
entry->top_field_order_cnt = ref_pic->top_field_order_cnt;
|
||||
entry->fields = V4L2_H264_TOP_FIELD_REF;
|
||||
|
||||
if (ref_pic->other_field) {
|
||||
entry->bottom_field_order_cnt =
|
||||
ref_pic->other_field->bottom_field_order_cnt;
|
||||
entry->fields |= V4L2_H264_BOTTOM_FIELD_REF;
|
||||
} else {
|
||||
entry->flags |= V4L2_H264_DPB_ENTRY_FLAG_FIELD;
|
||||
}
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
|
||||
entry->bottom_field_order_cnt = ref_pic->bottom_field_order_cnt;
|
||||
entry->fields = V4L2_H264_BOTTOM_FIELD_REF;
|
||||
|
||||
if (ref_pic->other_field) {
|
||||
entry->top_field_order_cnt =
|
||||
ref_pic->other_field->top_field_order_cnt;
|
||||
entry->fields |= V4L2_H264_TOP_FIELD_REF;
|
||||
} else {
|
||||
entry->flags |= V4L2_H264_DPB_ENTRY_FLAG_FIELD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
|
||||
|
@ -704,6 +739,10 @@ lookup_dpb_index (struct v4l2_h264_dpb_entry dpb[16], GstH264Picture * ref_pic)
|
|||
if (!ref_pic)
|
||||
return 0xff;
|
||||
|
||||
/* DPB entries only stores first field in a merged fashion */
|
||||
if (ref_pic->second_field && ref_pic->other_field)
|
||||
ref_pic = ref_pic->other_field;
|
||||
|
||||
ref_ts = (guint64) ref_pic->system_frame_number * 1000;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE
|
||||
|
@ -714,15 +753,33 @@ lookup_dpb_index (struct v4l2_h264_dpb_entry dpb[16], GstH264Picture * ref_pic)
|
|||
return 0xff;
|
||||
}
|
||||
|
||||
static guint
|
||||
_get_v4l2_fields_ref (GstH264Picture * ref_pic, gboolean merge)
|
||||
{
|
||||
if (merge && ref_pic->other_field)
|
||||
return V4L2_H264_FRAME_REF;
|
||||
|
||||
switch (ref_pic->field) {
|
||||
case GST_H264_PICTURE_FIELD_FRAME:
|
||||
return V4L2_H264_FRAME_REF;
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_TOP_FIELD:
|
||||
return V4L2_H264_TOP_FIELD_REF;
|
||||
break;
|
||||
case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
|
||||
return V4L2_H264_BOTTOM_FIELD_REF;
|
||||
break;
|
||||
}
|
||||
|
||||
return V4L2_H264_FRAME_REF;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_v4l2_codec_h264_dec_fill_references (GstV4l2CodecH264Dec * self,
|
||||
GArray * ref_pic_list0, GArray * ref_pic_list1)
|
||||
gboolean cur_is_frame, GArray * ref_pic_list0, GArray * ref_pic_list1)
|
||||
{
|
||||
struct v4l2_ctrl_h264_slice_params *slice_params;
|
||||
gint i, fields = V4L2_H264_FRAME_REF;
|
||||
|
||||
if (self->interlaced)
|
||||
fields = 0;
|
||||
gint i;
|
||||
|
||||
slice_params = &g_array_index (self->slice_params,
|
||||
struct v4l2_ctrl_h264_slice_params, 0);
|
||||
|
@ -737,7 +794,8 @@ gst_v4l2_codec_h264_dec_fill_references (GstV4l2CodecH264Dec * self,
|
|||
g_array_index (ref_pic_list0, GstH264Picture *, i);
|
||||
slice_params->ref_pic_list0[i].index =
|
||||
lookup_dpb_index (self->decode_params.dpb, ref_pic);
|
||||
slice_params->ref_pic_list0[i].fields = fields;
|
||||
slice_params->ref_pic_list0[i].fields =
|
||||
_get_v4l2_fields_ref (ref_pic, cur_is_frame);
|
||||
}
|
||||
|
||||
for (i = 0; i < ref_pic_list1->len; i++) {
|
||||
|
@ -745,7 +803,8 @@ gst_v4l2_codec_h264_dec_fill_references (GstV4l2CodecH264Dec * self,
|
|||
g_array_index (ref_pic_list1, GstH264Picture *, i);
|
||||
slice_params->ref_pic_list1[i].index =
|
||||
lookup_dpb_index (self->decode_params.dpb, ref_pic);
|
||||
slice_params->ref_pic_list1[i].fields = fields;
|
||||
slice_params->ref_pic_list1[i].fields =
|
||||
_get_v4l2_fields_ref (ref_pic, cur_is_frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1182,8 +1241,8 @@ gst_v4l2_codec_h264_dec_decode_slice (GstH264Decoder * decoder,
|
|||
|
||||
gst_v4l2_codec_h264_dec_fill_slice_params (self, slice);
|
||||
gst_v4l2_codec_h264_dec_fill_pred_weight (self, &slice->header);
|
||||
gst_v4l2_codec_h264_dec_fill_references (self, ref_pic_list0,
|
||||
ref_pic_list1);
|
||||
gst_v4l2_codec_h264_dec_fill_references (self,
|
||||
GST_H264_PICTURE_IS_FRAME (picture), ref_pic_list0, ref_pic_list1);
|
||||
}
|
||||
|
||||
bitstream_data = self->bitstream_map.data + self->bitstream_map.size;
|
||||
|
|
Loading…
Reference in a new issue