summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.com>2021-08-19 16:45:18 -0400
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>2021-08-20 19:29:53 +0000
commit4eb22b769559ef2696a78a03b30de215bd677d47 (patch)
treeb79c248181d586fa20622999ff2cef8d465f044b /sys
parentad5dcfb0912a17d4f8a77c59750bcdfee399b175 (diff)
downloadgstreamer-plugins-bad-4eb22b769559ef2696a78a03b30de215bd677d47.tar.gz
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>
Diffstat (limited to 'sys')
-rw-r--r--sys/v4l2codecs/gstv4l2codech264dec.c127
1 files changed, 93 insertions, 34 deletions
diff --git a/sys/v4l2codecs/gstv4l2codech264dec.c b/sys/v4l2codecs/gstv4l2codech264dec.c
index bd482b585..8517325fb 100644
--- a/sys/v4l2codecs/gstv4l2codech264dec.c
+++ b/sys/v4l2codecs/gstv4l2codech264dec.c
@@ -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;