Commit b5218cf4 authored by Boris Brezillon's avatar Boris Brezillon Committed by Mauro Carvalho Chehab
Browse files

media: hantro: h264: Use the generic H264 reflist builder



Now that the core provides generic reflist builders, we can use them
instead of implementing our own.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: default avatarEzequiel Garcia <ezequiel@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 624922a2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ config VIDEO_HANTRO
	select VIDEOBUF2_DMA_CONTIG
	select VIDEOBUF2_VMALLOC
	select V4L2_MEM2MEM_DEV
	select V4L2_H264
	help
	  Support for the Hantro IP based Video Processing Units present on
	  Rockchip and NXP i.MX8M SoCs, which accelerate video and image
+8 −229
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@
 */

#include <linux/types.h>
#include <linux/sort.h>
#include <media/v4l2-h264.h>
#include <media/v4l2-mem2mem.h>

#include "hantro.h"
@@ -240,229 +240,6 @@ static void prepare_table(struct hantro_ctx *ctx)
	reorder_scaling_list(ctx);
}

struct hantro_h264_reflist_builder {
	const struct v4l2_h264_dpb_entry *dpb;
	s32 pocs[HANTRO_H264_DPB_SIZE];
	u8 unordered_reflist[HANTRO_H264_DPB_SIZE];
	int frame_nums[HANTRO_H264_DPB_SIZE];
	s32 curpoc;
	u8 num_valid;
};

static s32 get_poc(enum v4l2_field field, s32 top_field_order_cnt,
		   s32 bottom_field_order_cnt)
{
	switch (field) {
	case V4L2_FIELD_TOP:
		return top_field_order_cnt;
	case V4L2_FIELD_BOTTOM:
		return bottom_field_order_cnt;
	default:
		break;
	}

	return min(top_field_order_cnt, bottom_field_order_cnt);
}

static void
init_reflist_builder(struct hantro_ctx *ctx,
		     struct hantro_h264_reflist_builder *b)
{
	const struct v4l2_ctrl_h264_slice_params *slice_params;
	const struct v4l2_ctrl_h264_decode_params *dec_param;
	const struct v4l2_ctrl_h264_sps *sps;
	struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx);
	const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb;
	struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
	int cur_frame_num, max_frame_num;
	unsigned int i;

	dec_param = ctx->h264_dec.ctrls.decode;
	slice_params = &ctx->h264_dec.ctrls.slices[0];
	sps = ctx->h264_dec.ctrls.sps;
	max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
	cur_frame_num = slice_params->frame_num;

	memset(b, 0, sizeof(*b));
	b->dpb = dpb;
	b->curpoc = get_poc(buf->field, dec_param->top_field_order_cnt,
			    dec_param->bottom_field_order_cnt);

	for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) {
		int buf_idx;

		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
			continue;

		buf_idx = vb2_find_timestamp(cap_q, dpb[i].reference_ts, 0);
		if (buf_idx < 0)
			continue;

		buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx));

		/*
		 * Handle frame_num wraparound as described in section
		 * '8.2.4.1 Decoding process for picture numbers' of the spec.
		 * TODO: This logic will have to be adjusted when we start
		 * supporting interlaced content.
		 */
		if (dpb[i].frame_num > cur_frame_num)
			b->frame_nums[i] = (int)dpb[i].frame_num - max_frame_num;
		else
			b->frame_nums[i] = dpb[i].frame_num;

		b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt,
				     dpb[i].bottom_field_order_cnt);
		b->unordered_reflist[b->num_valid] = i;
		b->num_valid++;
	}

	for (i = b->num_valid; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++)
		b->unordered_reflist[i] = i;
}

static int p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
{
	const struct hantro_h264_reflist_builder *builder = data;
	const struct v4l2_h264_dpb_entry *a, *b;
	u8 idxa, idxb;

	idxa = *((u8 *)ptra);
	idxb = *((u8 *)ptrb);
	a = &builder->dpb[idxa];
	b = &builder->dpb[idxb];

	if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
	    (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
		/* Short term pics firt. */
		if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
			return -1;
		else
			return 1;
	}

	/*
	 * Short term pics in descending pic num order, long term ones in
	 * ascending order.
	 */
	if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
		return HANTRO_CMP(builder->frame_nums[idxb],
				  builder->frame_nums[idxa]);

	return HANTRO_CMP(a->pic_num, b->pic_num);
}

static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
{
	const struct hantro_h264_reflist_builder *builder = data;
	const struct v4l2_h264_dpb_entry *a, *b;
	s32 poca, pocb;
	u8 idxa, idxb;

	idxa = *((u8 *)ptra);
	idxb = *((u8 *)ptrb);
	a = &builder->dpb[idxa];
	b = &builder->dpb[idxb];

	if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
	    (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
		/* Short term pics firt. */
		if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
			return -1;
		else
			return 1;
	}

	/* Long term pics in ascending pic num order. */
	if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
		return HANTRO_CMP(a->pic_num, b->pic_num);

	poca = builder->pocs[idxa];
	pocb = builder->pocs[idxb];

	/*
	 * Short term pics with POC < cur POC first in POC descending order
	 * followed by short term pics with POC > cur POC in POC ascending
	 * order.
	 */
	if ((poca < builder->curpoc) != (pocb < builder->curpoc))
		return HANTRO_CMP(poca, pocb);
	else if (poca < builder->curpoc)
		return HANTRO_CMP(pocb, poca);

	return HANTRO_CMP(poca, pocb);
}

static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data)
{
	const struct hantro_h264_reflist_builder *builder = data;
	const struct v4l2_h264_dpb_entry *a, *b;
	s32 poca, pocb;
	u8 idxa, idxb;

	idxa = *((u8 *)ptra);
	idxb = *((u8 *)ptrb);
	a = &builder->dpb[idxa];
	b = &builder->dpb[idxb];

	if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) !=
	    (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) {
		/* Short term pics firt. */
		if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM))
			return -1;
		else
			return 1;
	}

	/* Long term pics in ascending pic num order. */
	if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
		return HANTRO_CMP(a->pic_num, b->pic_num);

	poca = builder->pocs[idxa];
	pocb = builder->pocs[idxb];

	/*
	 * Short term pics with POC > cur POC first in POC ascending order
	 * followed by short term pics with POC < cur POC in POC descending
	 * order.
	 */
	if ((poca < builder->curpoc) != (pocb < builder->curpoc))
		return HANTRO_CMP(pocb, poca);
	else if (poca < builder->curpoc)
		return HANTRO_CMP(pocb, poca);

	return HANTRO_CMP(poca, pocb);
}

static void
build_p_ref_list(const struct hantro_h264_reflist_builder *builder,
		 u8 *reflist)
{
	memcpy(reflist, builder->unordered_reflist,
	       sizeof(builder->unordered_reflist));
	sort_r(reflist, builder->num_valid, sizeof(*reflist),
	       p_ref_list_cmp, NULL, builder);
}

static void
build_b_ref_lists(const struct hantro_h264_reflist_builder *builder,
		  u8 *b0_reflist, u8 *b1_reflist)
{
	memcpy(b0_reflist, builder->unordered_reflist,
	       sizeof(builder->unordered_reflist));
	sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
	       b0_ref_list_cmp, NULL, builder);

	memcpy(b1_reflist, builder->unordered_reflist,
	       sizeof(builder->unordered_reflist));
	sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
	       b1_ref_list_cmp, NULL, builder);

	if (builder->num_valid > 1 &&
	    !memcmp(b1_reflist, b0_reflist, builder->num_valid))
		swap(b1_reflist[0], b1_reflist[1]);
}

static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a,
			    const struct v4l2_h264_dpb_entry *b)
{
@@ -560,7 +337,7 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx)
{
	struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec;
	struct hantro_h264_dec_ctrls *ctrls = &h264_ctx->ctrls;
	struct hantro_h264_reflist_builder reflist_builder;
	struct v4l2_h264_reflist_builder reflist_builder;

	hantro_start_prepare_run(ctx);

@@ -596,9 +373,11 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx)
	prepare_table(ctx);

	/* Build the P/B{0,1} ref lists. */
	init_reflist_builder(ctx, &reflist_builder);
	build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
	build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
	v4l2_h264_init_reflist_builder(&reflist_builder, ctrls->decode,
				       &ctrls->slices[0], ctrls->sps,
				       ctx->h264_dec.dpb);
	v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
	v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
				    h264_ctx->reflists.b1);
	return 0;
}