diff mbox series

[FFmpeg-devel,vaapi-cavs,5/7] cavs: decode wqm and slice weighting for future usage

Message ID 20240121141846.4077778-5-jianfeng.zheng@mthreads.com
State New
Headers show
Series [FFmpeg-devel,vaapi-cavs,1/7] cavs: add cavs profile defs | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Jianfeng Zheng Jan. 21, 2024, 2:18 p.m. UTC
Signed-off-by: jianfeng.zheng <jianfeng.zheng@mthreads.com>
---
 libavcodec/cavs.h    |  26 +++++++-
 libavcodec/cavsdec.c | 142 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 147 insertions(+), 21 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h
index f490657959..33ef10e850 100644
--- a/libavcodec/cavs.h
+++ b/libavcodec/cavs.h
@@ -186,12 +186,36 @@  typedef struct AVSContext {
     int mb_width, mb_height;
     int width, height;
     int stream_revision; ///<0 for samples from 2006, 1 for rm52j encoder
-    int progressive;
+    int progressive_seq;
+    int progressive_frame;
     int pic_structure;
     int skip_mode_flag; ///< select between skip_count or one skip_flag per MB
     int loop_filter_disable;
     int alpha_offset, beta_offset;
     int ref_flag;
+
+    /** \defgroup guangdian profile
+     * @{
+     */
+    int aec_flag;
+    int weight_quant_flag;
+    int chroma_quant_param_delta_cb;
+    int chroma_quant_param_delta_cr;
+    uint8_t wqm_8x8[64];
+    /**@}*/
+
+    /** \defgroup slice weighting
+     * FFmpeg don't support slice weighting natively, but maybe needed for HWaccel.
+     * @{
+     */
+    uint32_t slice_weight_pred_flag : 1;
+    uint32_t mb_weight_pred_flag    : 1;
+    uint8_t luma_scale[4];
+    int8_t luma_shift[4];
+    uint8_t chroma_scale[4];
+    int8_t chroma_shift[4];
+    /**@}*/
+
     int mbx, mby, mbidx; ///< macroblock coordinates
     int flags;         ///< availability flags of neighbouring macroblocks
     int stc;           ///< last start code
diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c
index 6f462d861c..8d3ba530a6 100644
--- a/libavcodec/cavsdec.c
+++ b/libavcodec/cavsdec.c
@@ -30,6 +30,7 @@ 
 #include "avcodec.h"
 #include "get_bits.h"
 #include "golomb.h"
+#include "profiles.h"
 #include "cavs.h"
 #include "codec_internal.h"
 #include "decode.h"
@@ -37,6 +38,43 @@ 
 #include "mpeg12data.h"
 #include "startcode.h"
 
+static const uint8_t default_wq_param[4][6] = {
+    {128,  98, 106, 116, 116, 128},
+    {135, 143, 143, 160, 160, 213},
+    {128,  98, 106, 116, 116, 128},
+    {128, 128, 128, 128, 128, 128},
+};
+static const uint8_t wq_model_2_param[4][64] = {
+    {
+        0, 0, 0, 4, 4, 4, 5, 5,
+        0, 0, 3, 3, 3, 3, 5, 5,
+        0, 3, 2, 2, 1, 1, 5, 5,
+        4, 3, 2, 2, 1, 5, 5, 5,
+        4, 3, 1, 1, 5, 5, 5, 5,
+        4, 3, 1, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+    }, {
+        0, 0, 0, 4, 4, 4, 5, 5,
+        0, 0, 4, 4, 4, 4, 5, 5,
+        0, 3, 2, 2, 2, 1, 5, 5,
+        3, 3, 2, 2, 1, 5, 5, 5,
+        3, 3, 2, 1, 5, 5, 5, 5,
+        3, 3, 1, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+    }, {
+        0, 0, 0, 4, 4, 3, 5, 5,
+        0, 0, 4, 4, 3, 2, 5, 5,
+        0, 4, 4, 3, 2, 1, 5, 5,
+        4, 4, 3, 2, 1, 5, 5, 5,
+        4, 3, 2, 1, 5, 5, 5, 5,
+        3, 2, 1, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5,
+    }
+};
+
 static const uint8_t mv_scan[4] = {
     MV_FWD_X0, MV_FWD_X1,
     MV_FWD_X2, MV_FWD_X3
@@ -927,7 +965,11 @@  static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
 
 static inline int decode_slice_header(AVSContext *h, GetBitContext *gb)
 {
-    if (h->stc > 0xAF)
+    int i, nref;
+
+    av_log(h->avctx, AV_LOG_TRACE, "slice start code 0x%02x\n", h->stc);
+
+    if (h->stc > SLICE_MAX_START_CODE)
         av_log(h->avctx, AV_LOG_ERROR, "unexpected start code 0x%02x\n", h->stc);
 
     if (h->stc >= h->mb_height) {
@@ -946,11 +988,29 @@  static inline int decode_slice_header(AVSContext *h, GetBitContext *gb)
     }
     /* inter frame or second slice can have weighting params */
     if ((h->cur.f->pict_type != AV_PICTURE_TYPE_I) ||
-        (!h->pic_structure && h->mby >= h->mb_width / 2))
-        if (get_bits1(gb)) { //slice_weighting_flag
+        (!h->pic_structure && h->mby >= h->mb_height / 2)) {
+        h->slice_weight_pred_flag = get_bits1(gb);
+        if (h->slice_weight_pred_flag) {
+            nref = h->cur.f->pict_type == AV_PICTURE_TYPE_I ? 1 : (h->pic_structure ? 2 : 4);
+            for (i = 0; i < nref; i++) {
+                h->luma_scale[i] = get_bits(gb, 8);
+                h->luma_shift[i] = get_sbits(gb, 8);
+                skip_bits1(gb);
+                h->chroma_scale[i] = get_bits(gb, 8);
+                h->chroma_shift[i] = get_sbits(gb, 8);
+                skip_bits1(gb);
+            }
+            h->mb_weight_pred_flag = get_bits1(gb);
+            if (!h->avctx->hwaccel) {
             av_log(h->avctx, AV_LOG_ERROR,
                    "weighted prediction not yet supported\n");
         }
+        }
+    }
+    if (h->aec_flag) {
+        align_get_bits(gb);
+    }
+
     return 0;
 }
 
@@ -1108,7 +1168,11 @@  static int decode_pic(AVSContext *h)
 
     cavs_frame_unref(&h->cur);
 
-    skip_bits(&h->gb, 16);//bbv_dwlay
+    skip_bits(&h->gb, 16);//bbv_delay
+    if (h->profile == AV_PROFILE_CAVS_GUANGDIAN) {
+        skip_bits(&h->gb, 8);//bbv_dwlay_extension
+    }
+
     if (h->stc == PIC_PB_START_CODE) {
         h->cur.f->pict_type = get_bits(&h->gb, 2) + AV_PICTURE_TYPE_I;
         if (h->cur.f->pict_type > AV_PICTURE_TYPE_B) {
@@ -1192,9 +1256,9 @@  static int decode_pic(AVSContext *h)
 
     if (h->low_delay)
         get_ue_golomb(&h->gb); //bbv_check_times
-    h->progressive   = get_bits1(&h->gb);
+    h->progressive_frame = get_bits1(&h->gb);
     h->pic_structure = 1;
-    if (!h->progressive)
+    if (!h->progressive_frame)
         h->pic_structure = get_bits1(&h->gb);
     if (!h->pic_structure && h->stc == PIC_PB_START_CODE)
         skip_bits1(&h->gb);     //advanced_pred_mode_disable
@@ -1203,9 +1267,11 @@  static int decode_pic(AVSContext *h)
     h->pic_qp_fixed =
     h->qp_fixed = get_bits1(&h->gb);
     h->qp       = get_bits(&h->gb, 6);
+    h->skip_mode_flag = 0;
+    h->ref_flag = 0;
     if (h->cur.f->pict_type == AV_PICTURE_TYPE_I) {
-        if (!h->progressive && !h->pic_structure)
-            skip_bits1(&h->gb);//what is this?
+        if (!h->progressive_frame && !h->pic_structure)
+            h->skip_mode_flag  = get_bits1(&h->gb);
         skip_bits(&h->gb, 4);   //reserved bits
     } else {
         if (!(h->cur.f->pict_type == AV_PICTURE_TYPE_B && h->pic_structure == 1))
@@ -1220,12 +1286,46 @@  static int decode_pic(AVSContext *h)
         if (   h->alpha_offset < -64 || h->alpha_offset > 64
             || h-> beta_offset < -64 || h-> beta_offset > 64) {
             h->alpha_offset = h->beta_offset  = 0;
+            av_log(h->avctx, AV_LOG_ERROR, "invalid loop filter params\n");
             return AVERROR_INVALIDDATA;
         }
     } else {
         h->alpha_offset = h->beta_offset  = 0;
     }
 
+    h->weight_quant_flag = 0;
+    if (h->profile == AV_PROFILE_CAVS_GUANGDIAN) {
+        h->weight_quant_flag = get_bits1(&h->gb);
+        if (h->weight_quant_flag) {
+            int wq_param[6] = {128, 128, 128, 128, 128, 128};
+            int i, wqp_index, wq_model;
+            const uint8_t *m2p;
+
+            skip_bits1(&h->gb);
+            if (!get_bits1(&h->gb)) {
+                h->chroma_quant_param_delta_cb = get_se_golomb(&h->gb);
+                h->chroma_quant_param_delta_cr = get_se_golomb(&h->gb);
+            }
+            wqp_index = get_bits(&h->gb, 2);
+            wq_model = get_bits(&h->gb, 2);
+            m2p = wq_model_2_param[wq_model];
+
+            for (i = 0; i < 6; i++) {
+                int delta = (wqp_index == 1 || wqp_index == 2) ? get_se_golomb(&h->gb) : 0;
+                wq_param[i] = default_wq_param[wqp_index][i] + delta;
+                av_log(h->avctx, AV_LOG_DEBUG, "wqp[%d]=%d\n", i, wq_param[i]);
+            }
+            for (i = 0; i < 64; i++) {
+                h->wqm_8x8[i] = wq_param[ m2p[i] ];
+            }
+        } else {
+            memset(h->wqm_8x8, 128, sizeof(h->wqm_8x8));
+        }
+        h->aec_flag = get_bits1(&h->gb);
+        av_log(h->avctx, AV_LOG_DEBUG, "wq_flag=%d, aec_flag=%d\n",
+                h->weight_quant_flag, h->aec_flag);
+    }
+
     if (h->stream_revision > 0) {
         skip_stuffing_bits(h);
         skip_extension_and_user_data(h);
@@ -1311,13 +1411,8 @@  static int decode_seq_header(AVSContext *h)
     int ret;
 
     h->profile = get_bits(&h->gb, 8);
-    if (h->profile != 0x20) {
-        avpriv_report_missing_feature(h->avctx,
-                                      "only supprt JiZhun profile");
-        return AVERROR_PATCHWELCOME;
-    }
     h->level   = get_bits(&h->gb, 8);
-    skip_bits1(&h->gb); //progressive sequence
+    h->progressive_seq = get_bits1(&h->gb);
 
     width  = get_bits(&h->gb, 14);
     height = get_bits(&h->gb, 14);
@@ -1344,6 +1439,9 @@  static int decode_seq_header(AVSContext *h)
     skip_bits1(&h->gb);    //marker_bit
     skip_bits(&h->gb, 12); //bit_rate_upper
     h->low_delay =  get_bits1(&h->gb);
+    av_log(h->avctx, AV_LOG_DEBUG,
+            "seq: profile=0x%02x, level=0x%02x, size=%dx%d, low_delay=%d\n",
+            h->profile, h->level, width, height, h->low_delay);
 
     ret = ff_set_dimensions(h->avctx, width, height);
     if (ret < 0)
@@ -1369,8 +1467,6 @@  static int cavs_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
                              int *got_frame, AVPacket *avpkt)
 {
     AVSContext *h      = avctx->priv_data;
-    const uint8_t *buf = avpkt->data;
-    int buf_size       = avpkt->size;
     uint32_t stc       = -1;
     int input_size, ret;
     const uint8_t *buf_end;
@@ -1388,16 +1484,18 @@  static int cavs_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
 
     h->stc = 0;
 
-    buf_ptr = buf;
-    buf_end = buf + buf_size;
-    for(;;) {
+    buf_ptr = avpkt->data;
+    buf_end = avpkt->data + avpkt->size;
+    for(; buf_ptr < buf_end;) {
         buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &stc);
         if ((stc & 0xFFFFFE00) || buf_ptr == buf_end) {
             if (!h->stc)
                 av_log(h->avctx, AV_LOG_WARNING, "no frame decoded\n");
-            return FFMAX(0, buf_ptr - buf);
+            return FFMAX(0, buf_ptr - avpkt->data);
         }
         input_size = (buf_end - buf_ptr) * 8;
+        av_log(h->avctx, AV_LOG_TRACE, "Found start code 0x%04x, sz=%d\n",
+                stc, input_size / 8);
         switch (stc) {
         case CAVS_START_CODE:
             init_get_bits(&h->gb, buf_ptr, input_size);
@@ -1464,12 +1562,16 @@  static int cavs_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
             break;
         default:
             if (stc <= SLICE_MAX_START_CODE) {
+                h->stc = stc & 0xff;
                 init_get_bits(&h->gb, buf_ptr, input_size);
                 decode_slice_header(h, &h->gb);
+            } else {
+                av_log(h->avctx, AV_LOG_WARNING, "Skip unsupported start code 0x%04X\n", stc);
             }
             break;
         }
     }
+    return (buf_ptr - avpkt->data);
 }
 
 const FFCodec ff_cavs_decoder = {