From ca1733fbb17c50d0013795d0e2869bc216078f5a Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne <nicolas.dufresne@collabora.com> Date: Tue, 30 Nov 2021 09:35:38 -0500 Subject: [PATCH] WIP: Drafted interlaced support This is a large patch that sketch the idea, this is not working. Will reconstruct smaller patches, making sure it works every step now. --- drivers/media/v4l2-core/v4l2-h264.c | 327 +++++++++++++++--- .../staging/media/hantro/hantro_g1_h264_dec.c | 40 ++- drivers/staging/media/hantro/hantro_hw.h | 6 +- .../media/hantro/rockchip_vpu2_hw_h264_dec.c | 100 +++--- drivers/staging/media/rkvdec/rkvdec-h264.c | 34 +- include/media/v4l2-h264.h | 18 +- 6 files changed, 379 insertions(+), 146 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c index a299a1e17d599..eea1d39457a3f 100644 --- a/drivers/media/v4l2-core/v4l2-h264.c +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -34,16 +34,20 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, cur_frame_num = dec_params->frame_num; memset(b, 0, sizeof(*b)); - if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, dec_params->top_field_order_cnt); - else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + b->cur_pic_field = V4L2_H264_FRAME_REF; + } else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) { b->cur_pic_order_count = dec_params->bottom_field_order_cnt; - else + b->cur_pic_field = V4L2_H264_BOTTOM_FIELD_REF; + } else { b->cur_pic_order_count = dec_params->top_field_order_cnt; + b->cur_pic_field = V4L2_H264_TOP_FIELD_REF; + } for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { - u32 pic_order_count; + struct v4l2_h264_reference *ref; if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) continue; @@ -52,11 +56,13 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) b->refs[i].longterm = true; + /* FIXME we are missing a flag for "non-existing" references. */ + /* * 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. + * For long term reference, frame_num is set to + * long_term_frame_idx which requires no wrapping. */ if (dpb[i].frame_num > cur_frame_num) b->refs[i].frame_num = (int)dpb[i].frame_num - @@ -64,21 +70,37 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, else b->refs[i].frame_num = dpb[i].frame_num; - if (dpb[i].fields == V4L2_H264_FRAME_REF) - pic_order_count = min(dpb[i].top_field_order_cnt, - dpb[i].bottom_field_order_cnt); - else if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) - pic_order_count = dpb[i].bottom_field_order_cnt; - else - pic_order_count = dpb[i].top_field_order_cnt; - b->refs[i].pic_order_count = pic_order_count; - b->unordered_reflist[b->num_valid] = i; + if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { + b->refs[i].top_field_order_cnt = min(dpb[i].bottom_field_order_cnt, + dpb[i].top_field_order_cnt); + ref = &b->unordered_reflist[b->num_refs]; + ref->index = i; + ref->fields = V4L2_H264_FRAME_REF; + b->num_refs++; + } else { + if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) { + b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt; + ref = &b->unordered_reflist[b->num_refs]; + ref->index = i; + ref->fields = V4L2_H264_TOP_FIELD_REF; + b->num_refs++; + } + + if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) { + b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt; + ref = &b->unordered_reflist[b->num_refs]; + ref->index = i; + ref->fields = V4L2_H264_BOTTOM_FIELD_REF; + b->num_refs++; + } + } + b->num_valid++; } - for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++) - b->unordered_reflist[i] = i; + for (i = b->num_refs; i < ARRAY_SIZE(b->unordered_reflist); i++) + b->unordered_reflist[i] = (struct v4l2_h264_reference) { i, 0 }; } EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); @@ -88,8 +110,8 @@ static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, const struct v4l2_h264_reflist_builder *builder = data; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) @@ -116,15 +138,54 @@ static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, -1 : 1; } +static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b, + const struct v4l2_h264_reference *ref) +{ + if (ref->fields == V4L2_H264_BOTTOM_FIELD_REF) + return b->refs[ref->index].bottom_field_order_cnt; + else + return b->refs[ref->index].top_field_order_cnt; +} + +static int v4l2_h264_b0_st_ref_list_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *builder = data; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + poca = v4l2_h264_get_poc(builder, ptra); + pocb = v4l2_h264_get_poc(builder, ptrb); + + /* + * 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->cur_pic_order_count) != + (pocb < builder->cur_pic_order_count)) + return poca < pocb ? -1 : 1; + else if (poca < builder->cur_pic_order_count) + return pocb < poca ? -1 : 1; + + return poca < pocb ? -1 : 1; +} + static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) { const struct v4l2_h264_reflist_builder *builder = data; - s32 poca, pocb; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) @@ -144,17 +205,34 @@ static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, builder->refs[idxb].pic_num ? -1 : 1; - poca = builder->refs[idxa].pic_order_count; - pocb = builder->refs[idxb].pic_order_count; + return v4l2_h264_b0_st_ref_list_cmp(ptra, ptrb, data); +} + +static int v4l2_h264_b1_st_ref_list_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *builder = data; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + poca = v4l2_h264_get_poc(builder, ptra); + pocb = v4l2_h264_get_poc(builder, ptrb); /* - * Short term pics with POC < cur POC first in POC descending order - * followed by short term pics with POC > cur POC in POC ascending + * 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->cur_pic_order_count) != - (pocb < builder->cur_pic_order_count)) - return poca < pocb ? -1 : 1; + (pocb < builder->cur_pic_order_count)) + return pocb < poca ? -1 : 1; else if (poca < builder->cur_pic_order_count) return pocb < poca ? -1 : 1; @@ -165,17 +243,17 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) { const struct v4l2_h264_reflist_builder *builder = data; - s32 poca, pocb; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) return 1; if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { + /* Short term pics first. */ if (!builder->refs[idxa].longterm) return -1; @@ -189,21 +267,159 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, builder->refs[idxb].pic_num ? -1 : 1; - poca = builder->refs[idxa].pic_order_count; - pocb = builder->refs[idxb].pic_order_count; + return v4l2_h264_b1_st_ref_list_cmp(ptra, ptrb, data); +} + +static int v4l2_h264_desc_frame_num_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *b = data; + u8 idxa, idxb; + + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + return b->refs[idxb].frame_num < b->refs[idxa].frame_num ? -1 : 1; +} + +static int v4l2_h264_asc_frame_num_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *b = data; + u8 idxa, idxb; + + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + return b->refs[idxa].frame_num < b->refs[idxb].frame_num ? -1 : 1; +} + +static void v4l2_h264_alternate_field_merge(struct v4l2_h264_reference *reflist, + struct v4l2_h264_reference tmp_list[2][V4L2_H264_REF_LIST_LEN], + const u8 tmp_len[2], + const struct v4l2_h264_reflist_builder *b) +{ + const u8 field = b->cur_pic_field; + int l = 0, i = 0, j = 0, k = 0; + + for (l = 0; l < 2; l++) { + do { + for (; i < tmp_len[l]; i++) { + if (tmp_list[l][i].fields == field) { + reflist[k++] = tmp_list[l][i]; + break; + } + } + + for (; i < tmp_len[l]; i++) { + if (tmp_list[l][i].fields != field) { + reflist[k++] = tmp_list[l][i]; + break; + } + } + } while (i < tmp_len[l] || j < tmp_len[l]); + } +} + +static void v4l2_h264_build_p_ref_frame_list(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *reflist) +{ + memcpy(reflist, b->unordered_reflist, + sizeof(b->unordered_reflist[0]) * b->num_refs); + sort_r(reflist, b->num_refs, sizeof(*reflist), + v4l2_h264_p_ref_list_cmp, NULL, b); +} + +static void v4l2_h264_split_short_and_long_refs(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference refs[2][V4L2_H264_REF_LIST_LEN], + u8 refs_len[2]) +{ + int i; + + refs_len[0] = refs_len[1] = 0; + + for (i = 0; i < b->num_valid; i++) { + u8 idx = b->unordered_reflist[i].index; + u8 list_idx = 0; + + if (b->refs[idx].longterm) + list_idx = 1; + + refs[list_idx][refs_len[list_idx]] = b->unordered_reflist[i]; + refs_len[list_idx]++; + } +} + +static void v4l2_h264_build_p_ref_field_list(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *reflist) +{ + struct v4l2_h264_reference tmp_list[2][V4L2_H264_REF_LIST_LEN]; + u8 tmp_len[2]; + + v4l2_h264_split_short_and_long_refs(b, tmp_list, tmp_len); + + /* Sort short term in descending frame_num_wrap */ + sort_r(tmp_list[0], tmp_len[0], sizeof(*tmp_list[0]), + v4l2_h264_desc_frame_num_cmp, NULL, b); + + /* Short long term in ascending long_term_frame_idx */ + sort_r(tmp_list[1], tmp_len[1], sizeof(*tmp_list[1]), + v4l2_h264_asc_frame_num_cmp, NULL, b); /* - * 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. + * Merge references by alternating their field parity, starting with + * current picture parity. Do this for short term first, followed by + * long term. */ - if ((poca < builder->cur_pic_order_count) != - (pocb < builder->cur_pic_order_count)) - return pocb < poca ? -1 : 1; - else if (poca < builder->cur_pic_order_count) - return pocb < poca ? -1 : 1; + v4l2_h264_alternate_field_merge(reflist, tmp_list, tmp_len, b); +} + +static void v4l2_h264_build_b_ref_frame_list(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *b0_reflist, + struct v4l2_h264_reference *b1_reflist) +{ + memcpy(b0_reflist, b->unordered_reflist, + sizeof(b->unordered_reflist[0]) * b->num_valid); + sort_r(b0_reflist, b->num_valid, sizeof(*b0_reflist), + v4l2_h264_b0_ref_list_cmp, NULL, b); + + memcpy(b1_reflist, b->unordered_reflist, + sizeof(b->unordered_reflist[0]) * b->num_valid); + sort_r(b1_reflist, b->num_valid, sizeof(*b1_reflist), + v4l2_h264_b1_ref_list_cmp, NULL, b); - return poca < pocb ? -1 : 1; +} + +static void v4l2_h264_build_b_ref_field_list(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *b0_reflist, + struct v4l2_h264_reference *b1_reflist) +{ + struct v4l2_h264_reference tmp_list[2][V4L2_H264_REF_LIST_LEN]; + u8 tmp_len[2] = { 0, 0 }; + + v4l2_h264_split_short_and_long_refs(b, tmp_list, tmp_len); + + /* Long term reference is the same for b0 and b1 */ + sort_r(tmp_list[1], tmp_len[1], sizeof(*tmp_list[1]), + v4l2_h264_asc_frame_num_cmp , NULL, b); + + /* Sort for B0 POC order */ + sort_r(tmp_list[0], tmp_len[0], sizeof(*tmp_list[0]), + v4l2_h264_b0_st_ref_list_cmp, NULL, b); + v4l2_h264_alternate_field_merge(b0_reflist, tmp_list, tmp_len, b); + + /* Sort again but for B1 POC order */ + sort_r(tmp_list[0], tmp_len[0], sizeof(*tmp_list[0]), + v4l2_h264_b1_st_ref_list_cmp, NULL, b); + v4l2_h264_alternate_field_merge(b1_reflist, tmp_list, tmp_len, b); } /** @@ -220,12 +436,12 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, */ void v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, - u8 *reflist) + struct v4l2_h264_reference *reflist) { - memcpy(reflist, builder->unordered_reflist, - sizeof(builder->unordered_reflist[0]) * builder->num_valid); - sort_r(reflist, builder->num_valid, sizeof(*reflist), - v4l2_h264_p_ref_list_cmp, NULL, builder); + if (builder->cur_pic_field == V4L2_H264_FRAME_REF) + v4l2_h264_build_p_ref_frame_list(builder, reflist); + else + v4l2_h264_build_p_ref_field_list(builder, reflist); } EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); @@ -245,18 +461,15 @@ EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); */ void v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, - u8 *b0_reflist, u8 *b1_reflist) + struct v4l2_h264_reference *b0_reflist, + struct v4l2_h264_reference *b1_reflist) { - memcpy(b0_reflist, builder->unordered_reflist, - sizeof(builder->unordered_reflist[0]) * builder->num_valid); - sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), - v4l2_h264_b0_ref_list_cmp, NULL, builder); - - memcpy(b1_reflist, builder->unordered_reflist, - sizeof(builder->unordered_reflist[0]) * builder->num_valid); - sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), - v4l2_h264_b1_ref_list_cmp, NULL, builder); + if (builder->cur_pic_field == V4L2_H264_FRAME_REF) + v4l2_h264_build_b_ref_frame_list(builder, b0_reflist, b1_reflist); + else + v4l2_h264_build_b_ref_field_list(builder, b0_reflist, b1_reflist); + if (builder->num_valid > 1 && !memcmp(b1_reflist, b0_reflist, builder->num_valid)) swap(b1_reflist[0], b1_reflist[1]); diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index f49dbfb8a8433..70d94123f431f 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -126,7 +126,7 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) static void set_ref(struct hantro_ctx *ctx) { - const u8 *b0_reflist, *b1_reflist, *p_reflist; + const struct v4l2_h264_reference *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; int reg_num; u32 reg; @@ -135,6 +135,8 @@ static void set_ref(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); + /* FIXME Field decoding */ + /* * Set up reference frame picture numbers. * @@ -157,12 +159,12 @@ static void set_ref(struct hantro_ctx *ctx) */ reg_num = 0; for (i = 0; i < 15; i += 3) { - reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]); + reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2].index); vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++)); } @@ -171,12 +173,12 @@ static void set_ref(struct hantro_ctx *ctx) * of forward and backward reference picture lists and first 4 entries * of P forward picture list. */ - reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) | - G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]); + reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15].index) | + G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3].index); vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC); /* @@ -185,12 +187,12 @@ static void set_ref(struct hantro_ctx *ctx) */ reg_num = 0; for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) { - reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) | - G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) | - G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) | - G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) | - G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) | - G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]); + reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5].index); vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++)); } diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 60d4602d33ed5..a2aca3a7ff5f6 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -77,9 +77,9 @@ struct hantro_h264_dec_ctrls { * @b1: B1 reflist */ struct hantro_h264_dec_reflists { - u8 p[HANTRO_H264_DPB_SIZE]; - u8 b0[HANTRO_H264_DPB_SIZE]; - u8 b1[HANTRO_H264_DPB_SIZE]; + struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN]; }; /** diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c index 64a6330475ebe..78c1c343bd659 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c @@ -298,7 +298,7 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) static void set_ref(struct hantro_ctx *ctx) { - const u8 *b0_reflist, *b1_reflist, *p_reflist; + const struct v4l2_h264_reference *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; u32 reg; int i; @@ -307,20 +307,22 @@ static void set_ref(struct hantro_ctx *ctx) b1_reflist = ctx->h264_dec.reflists.b1; p_reflist = ctx->h264_dec.reflists.p; - reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9]) | - VDPU_REG_PINIT_RLIST_F8(p_reflist[8]) | - VDPU_REG_PINIT_RLIST_F7(p_reflist[7]) | - VDPU_REG_PINIT_RLIST_F6(p_reflist[6]) | - VDPU_REG_PINIT_RLIST_F5(p_reflist[5]) | - VDPU_REG_PINIT_RLIST_F4(p_reflist[4]); + /* FIXME handle field decoding */ + + reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9].index) | + VDPU_REG_PINIT_RLIST_F8(p_reflist[8].index) | + VDPU_REG_PINIT_RLIST_F7(p_reflist[7].index) | + VDPU_REG_PINIT_RLIST_F6(p_reflist[6].index) | + VDPU_REG_PINIT_RLIST_F5(p_reflist[5].index) | + VDPU_REG_PINIT_RLIST_F4(p_reflist[4].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(74)); - reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15]) | - VDPU_REG_PINIT_RLIST_F14(p_reflist[14]) | - VDPU_REG_PINIT_RLIST_F13(p_reflist[13]) | - VDPU_REG_PINIT_RLIST_F12(p_reflist[12]) | - VDPU_REG_PINIT_RLIST_F11(p_reflist[11]) | - VDPU_REG_PINIT_RLIST_F10(p_reflist[10]); + reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15].index) | + VDPU_REG_PINIT_RLIST_F14(p_reflist[14].index) | + VDPU_REG_PINIT_RLIST_F13(p_reflist[13].index) | + VDPU_REG_PINIT_RLIST_F12(p_reflist[12].index) | + VDPU_REG_PINIT_RLIST_F11(p_reflist[11].index) | + VDPU_REG_PINIT_RLIST_F10(p_reflist[10].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(75)); reg = VDPU_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | @@ -355,54 +357,54 @@ static void set_ref(struct hantro_ctx *ctx) VDPU_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(83)); - reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5]) | - VDPU_REG_BINIT_RLIST_F4(b0_reflist[4]) | - VDPU_REG_BINIT_RLIST_F3(b0_reflist[3]) | - VDPU_REG_BINIT_RLIST_F2(b0_reflist[2]) | - VDPU_REG_BINIT_RLIST_F1(b0_reflist[1]) | - VDPU_REG_BINIT_RLIST_F0(b0_reflist[0]); + reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5].index) | + VDPU_REG_BINIT_RLIST_F4(b0_reflist[4].index) | + VDPU_REG_BINIT_RLIST_F3(b0_reflist[3].index) | + VDPU_REG_BINIT_RLIST_F2(b0_reflist[2].index) | + VDPU_REG_BINIT_RLIST_F1(b0_reflist[1].index) | + VDPU_REG_BINIT_RLIST_F0(b0_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(100)); - reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11]) | - VDPU_REG_BINIT_RLIST_F10(b0_reflist[10]) | - VDPU_REG_BINIT_RLIST_F9(b0_reflist[9]) | - VDPU_REG_BINIT_RLIST_F8(b0_reflist[8]) | - VDPU_REG_BINIT_RLIST_F7(b0_reflist[7]) | - VDPU_REG_BINIT_RLIST_F6(b0_reflist[6]); + reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11].index) | + VDPU_REG_BINIT_RLIST_F10(b0_reflist[10].index) | + VDPU_REG_BINIT_RLIST_F9(b0_reflist[9].index) | + VDPU_REG_BINIT_RLIST_F8(b0_reflist[8].index) | + VDPU_REG_BINIT_RLIST_F7(b0_reflist[7].index) | + VDPU_REG_BINIT_RLIST_F6(b0_reflist[6].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(101)); - reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15]) | - VDPU_REG_BINIT_RLIST_F14(b0_reflist[14]) | - VDPU_REG_BINIT_RLIST_F13(b0_reflist[13]) | - VDPU_REG_BINIT_RLIST_F12(b0_reflist[12]); + reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15].index) | + VDPU_REG_BINIT_RLIST_F14(b0_reflist[14].index) | + VDPU_REG_BINIT_RLIST_F13(b0_reflist[13].index) | + VDPU_REG_BINIT_RLIST_F12(b0_reflist[12].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(102)); - reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5]) | - VDPU_REG_BINIT_RLIST_B4(b1_reflist[4]) | - VDPU_REG_BINIT_RLIST_B3(b1_reflist[3]) | - VDPU_REG_BINIT_RLIST_B2(b1_reflist[2]) | - VDPU_REG_BINIT_RLIST_B1(b1_reflist[1]) | - VDPU_REG_BINIT_RLIST_B0(b1_reflist[0]); + reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5].index) | + VDPU_REG_BINIT_RLIST_B4(b1_reflist[4].index) | + VDPU_REG_BINIT_RLIST_B3(b1_reflist[3].index) | + VDPU_REG_BINIT_RLIST_B2(b1_reflist[2].index) | + VDPU_REG_BINIT_RLIST_B1(b1_reflist[1].index) | + VDPU_REG_BINIT_RLIST_B0(b1_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(103)); - reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11]) | - VDPU_REG_BINIT_RLIST_B10(b1_reflist[10]) | - VDPU_REG_BINIT_RLIST_B9(b1_reflist[9]) | - VDPU_REG_BINIT_RLIST_B8(b1_reflist[8]) | - VDPU_REG_BINIT_RLIST_B7(b1_reflist[7]) | - VDPU_REG_BINIT_RLIST_B6(b1_reflist[6]); + reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11].index) | + VDPU_REG_BINIT_RLIST_B10(b1_reflist[10].index) | + VDPU_REG_BINIT_RLIST_B9(b1_reflist[9].index) | + VDPU_REG_BINIT_RLIST_B8(b1_reflist[8].index) | + VDPU_REG_BINIT_RLIST_B7(b1_reflist[7].index) | + VDPU_REG_BINIT_RLIST_B6(b1_reflist[6].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(104)); - reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15]) | - VDPU_REG_BINIT_RLIST_B14(b1_reflist[14]) | - VDPU_REG_BINIT_RLIST_B13(b1_reflist[13]) | - VDPU_REG_BINIT_RLIST_B12(b1_reflist[12]); + reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15].index) | + VDPU_REG_BINIT_RLIST_B14(b1_reflist[14].index) | + VDPU_REG_BINIT_RLIST_B13(b1_reflist[13].index) | + VDPU_REG_BINIT_RLIST_B12(b1_reflist[12].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(105)); - reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3]) | - VDPU_REG_PINIT_RLIST_F2(p_reflist[2]) | - VDPU_REG_PINIT_RLIST_F1(p_reflist[1]) | - VDPU_REG_PINIT_RLIST_F0(p_reflist[0]); + reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3].index) | + VDPU_REG_PINIT_RLIST_F2(p_reflist[2].index) | + VDPU_REG_PINIT_RLIST_F1(p_reflist[1].index) | + VDPU_REG_PINIT_RLIST_F0(p_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(106)); reg = VDPU_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 951e19231da21..02505d55e7f59 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -97,12 +97,12 @@ struct rkvdec_h264_priv_tbl { u8 err_info[RKV_ERROR_INFO_SIZE]; }; -#define RKVDEC_H264_DPB_SIZE 16 +#define RKVDEC_H264_REF_LIST_LEN 32 struct rkvdec_h264_reflists { - u8 p[RKVDEC_H264_DPB_SIZE]; - u8 b0[RKVDEC_H264_DPB_SIZE]; - u8 b1[RKVDEC_H264_DPB_SIZE]; + struct v4l2_h264_reference p[RKVDEC_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b0[RKVDEC_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b1[RKVDEC_H264_REF_LIST_LEN]; u8 num_valid; }; @@ -762,28 +762,36 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { for (i = 0; i < h264_ctx->reflists.num_valid; i++) { - u8 dpb_valid = 0; - u8 idx = 0; + struct v4l2_h264_reference *ref = NULL; + u8 dpb_valid; switch (j) { case 0: - idx = h264_ctx->reflists.p[i]; + ref = &h264_ctx->reflists.p[i]; break; case 1: - idx = h264_ctx->reflists.b0[i]; + ref = &h264_ctx->reflists.p[i]; break; case 2: - idx = h264_ctx->reflists.b1[i]; + ref = &h264_ctx->reflists.b0[i]; break; } - if (idx >= ARRAY_SIZE(dec_params->dpb)) + if (ref->index >= ARRAY_SIZE(dec_params->dpb)) continue; - dpb_valid = !!(dpb[idx].flags & - V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + + /* + * FIXME check if using TS if a refefrence is found and + * adapt dpb_valud accordingly. This is the safe way to + * determin if we have an "non-existing" frame being + * referenced. + */ + dpb_valid = 1; set_ps_field(hw_rps, DPB_INFO(i, j), - idx | dpb_valid << 4); + ref->index | dpb_valid << 4); + set_ps_field(hw_rps, BOTTOM_FLAG(i, j), + ref->fields == V4L2_H264_BOTTOM_FIELD_REF); } } } diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h index 4b1c71c935e0f..91b495d4eb3e5 100644 --- a/include/media/v4l2-h264.h +++ b/include/media/v4l2-h264.h @@ -18,12 +18,16 @@ * @refs.pic_order_count: reference picture order count * @refs.frame_num: reference frame number * @refs.pic_num: reference picture number + * @refs.top_field_order_cnt: top field order count + * @refs.bottom_field_order_cnt: bottom field order count * @refs.longterm: set to true for a long term reference * @refs: array of references + * @num_refs: number of reference pictures in the @refs array * @cur_pic_order_count: picture order count of the frame being decoded * @unordered_reflist: unordered list of references. Will be used to generate * ordered P/B0/B1 lists - * @num_valid: number of valid references in the refs array + * @num_valid: number of valid reference pictures or fields in the + * @unordered_reflist array * * This object stores the context of the P/B0/B1 reference list builder. * This procedure is described in section '8.2.4 Decoding process for reference @@ -31,13 +35,16 @@ */ struct v4l2_h264_reflist_builder { struct { - s32 pic_order_count; int frame_num; u32 pic_num; + s32 top_field_order_cnt; + s32 bottom_field_order_cnt; u16 longterm : 1; } refs[V4L2_H264_NUM_DPB_ENTRIES]; + u8 num_refs; s32 cur_pic_order_count; - u8 unordered_reflist[V4L2_H264_NUM_DPB_ENTRIES]; + u8 cur_pic_field; + struct v4l2_h264_reference unordered_reflist[V4L2_H264_REF_LIST_LEN]; u8 num_valid; }; @@ -63,7 +70,8 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, */ void v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, - u8 *b0_reflist, u8 *b1_reflist); + struct v4l2_h264_reference *b0_reflist, + struct v4l2_h264_reference *b1_reflist); /** * v4l2_h264_build_p_ref_list() - Build the P reference list @@ -79,6 +87,6 @@ v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, */ void v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, - u8 *reflist); + struct v4l2_h264_reference *reflist); #endif /* _MEDIA_V4L2_H264_H */ -- GitLab