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: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Boris Brezillon 2020-04-04 00:13:42 +02:00 committed by Mauro Carvalho Chehab
parent 624922a273
commit b5218cf40c
2 changed files with 9 additions and 229 deletions

View File

@ -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

View File

@ -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,10 +373,12 @@ 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,
h264_ctx->reflists.b1);
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;
}