mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +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)
|
GstH264SliceHdr * slice_hdr, GstH264Picture * picture, GstH264Dpb * dpb)
|
||||||
{
|
{
|
||||||
GArray *refs = gst_h264_dpb_get_pictures_all (dpb);
|
GArray *refs = gst_h264_dpb_get_pictures_all (dpb);
|
||||||
gint i;
|
gint i, entry_id = 0;
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
self->decode_params = (struct v4l2_ctrl_h264_decode_params) {
|
self->decode_params = (struct v4l2_ctrl_h264_decode_params) {
|
||||||
.nal_ref_idc = picture->nal_ref_idc,
|
.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,
|
.frame_num = slice_hdr->frame_num,
|
||||||
.idr_pic_id = slice_hdr->idr_pic_id,
|
.idr_pic_id = slice_hdr->idr_pic_id,
|
||||||
.pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb,
|
.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),
|
(slice_hdr->bottom_field_flag ? V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD : 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < refs->len; i++) {
|
switch (picture->field) {
|
||||||
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) {
|
|
||||||
case GST_H264_PICTURE_FIELD_FRAME:
|
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;
|
break;
|
||||||
case GST_H264_PICTURE_FIELD_TOP_FIELD:
|
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;
|
break;
|
||||||
case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
|
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;
|
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
|
* The reference is multiplied by 1000 because it's wassed as micro
|
||||||
* seconds and this TS is nanosecond.
|
* 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,
|
.reference_ts = (guint64) ref_pic->system_frame_number * 1000,
|
||||||
.frame_num = ref_pic->frame_num,
|
.frame_num = ref_pic->frame_num,
|
||||||
.pic_num = pic_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
|
.flags = V4L2_H264_DPB_ENTRY_FLAG_VALID
|
||||||
| (GST_H264_PICTURE_IS_REF (ref_pic) ?
|
| (GST_H264_PICTURE_IS_REF (ref_pic) ? V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0)
|
||||||
V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0)
|
| (GST_H264_PICTURE_IS_LONG_TERM_REF (ref_pic) ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0),
|
||||||
| (GST_H264_PICTURE_IS_LONG_TERM_REF (ref_pic) ?
|
|
||||||
V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0),
|
|
||||||
.fields = dpb_ref,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
@ -704,6 +739,10 @@ lookup_dpb_index (struct v4l2_h264_dpb_entry dpb[16], GstH264Picture * ref_pic)
|
||||||
if (!ref_pic)
|
if (!ref_pic)
|
||||||
return 0xff;
|
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;
|
ref_ts = (guint64) ref_pic->system_frame_number * 1000;
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE
|
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;
|
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
|
static void
|
||||||
gst_v4l2_codec_h264_dec_fill_references (GstV4l2CodecH264Dec * self,
|
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;
|
struct v4l2_ctrl_h264_slice_params *slice_params;
|
||||||
gint i, fields = V4L2_H264_FRAME_REF;
|
gint i;
|
||||||
|
|
||||||
if (self->interlaced)
|
|
||||||
fields = 0;
|
|
||||||
|
|
||||||
slice_params = &g_array_index (self->slice_params,
|
slice_params = &g_array_index (self->slice_params,
|
||||||
struct v4l2_ctrl_h264_slice_params, 0);
|
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);
|
g_array_index (ref_pic_list0, GstH264Picture *, i);
|
||||||
slice_params->ref_pic_list0[i].index =
|
slice_params->ref_pic_list0[i].index =
|
||||||
lookup_dpb_index (self->decode_params.dpb, ref_pic);
|
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++) {
|
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);
|
g_array_index (ref_pic_list1, GstH264Picture *, i);
|
||||||
slice_params->ref_pic_list1[i].index =
|
slice_params->ref_pic_list1[i].index =
|
||||||
lookup_dpb_index (self->decode_params.dpb, ref_pic);
|
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_slice_params (self, slice);
|
||||||
gst_v4l2_codec_h264_dec_fill_pred_weight (self, &slice->header);
|
gst_v4l2_codec_h264_dec_fill_pred_weight (self, &slice->header);
|
||||||
gst_v4l2_codec_h264_dec_fill_references (self, ref_pic_list0,
|
gst_v4l2_codec_h264_dec_fill_references (self,
|
||||||
ref_pic_list1);
|
GST_H264_PICTURE_IS_FRAME (picture), ref_pic_list0, ref_pic_list1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitstream_data = self->bitstream_map.data + self->bitstream_map.size;
|
bitstream_data = self->bitstream_map.data + self->bitstream_map.size;
|
||||||
|
|
Loading…
Reference in a new issue