h264dec: support exporting QP tables through the AVVideoEncParams API
authorAnton Khirnov <anton@khirnov.net>
Tue, 10 Mar 2020 17:26:00 +0000 (18:26 +0100)
committerAnton Khirnov <anton@khirnov.net>
Mon, 25 May 2020 09:59:42 +0000 (11:59 +0200)
doc/APIchanges
libavcodec/h264_picture.c
libavcodec/h264_slice.c
libavcodec/h264dec.c
libavcodec/h264dec.h
libavutil/version.h
libavutil/video_enc_params.h

index 24c81d8..56ec9f8 100644 (file)
@@ -15,6 +15,9 @@ libavutil:     2017-10-21
 
 API changes, most recent first:
 
+2020-05-23 - xxxxxxxxxx - lavu 56.49.100 - video_enc_params.h
+  Add AV_VIDEO_ENC_PARAMS_H264.
+
 2020-05-23 - xxxxxxxxxx - lavu 56.48.100 - hwcontext.h
   Add av_hwdevice_ctx_create_derived_opts.
 
index 2113947..eec5e9f 100644 (file)
@@ -54,6 +54,7 @@ void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
 
     av_buffer_unref(&pic->qscale_table_buf);
     av_buffer_unref(&pic->mb_type_buf);
+    av_buffer_unref(&pic->pps_buf);
     for (i = 0; i < 2; i++) {
         av_buffer_unref(&pic->motion_val_buf[i]);
         av_buffer_unref(&pic->ref_index_buf[i]);
@@ -77,12 +78,14 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
 
     dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf);
     dst->mb_type_buf      = av_buffer_ref(src->mb_type_buf);
-    if (!dst->qscale_table_buf || !dst->mb_type_buf) {
+    dst->pps_buf          = av_buffer_ref(src->pps_buf);
+    if (!dst->qscale_table_buf || !dst->mb_type_buf || !dst->pps_buf) {
         ret = AVERROR(ENOMEM);
         goto fail;
     }
     dst->qscale_table = src->qscale_table;
     dst->mb_type      = src->mb_type;
+    dst->pps          = src->pps;
 
     for (i = 0; i < 2; i++) {
         dst->motion_val_buf[i] = av_buffer_ref(src->motion_val_buf[i]);
@@ -120,6 +123,9 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
     dst->recovered     = src->recovered;
     dst->invalid_gap   = src->invalid_gap;
     dst->sei_recovery_frame_cnt = src->sei_recovery_frame_cnt;
+    dst->mb_width      = src->mb_width;
+    dst->mb_height     = src->mb_height;
+    dst->mb_stride     = src->mb_stride;
 
     return 0;
 fail:
index 5a8a4a7..7139537 100644 (file)
@@ -243,6 +243,15 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
         pic->ref_index[i]  = pic->ref_index_buf[i]->data;
     }
 
+    pic->pps_buf = av_buffer_ref(h->ps.pps_ref);
+    if (!pic->pps_buf)
+        goto fail;
+    pic->pps = (const PPS*)pic->pps_buf->data;
+
+    pic->mb_width  = h->mb_width;
+    pic->mb_height = h->mb_height;
+    pic->mb_stride = h->mb_stride;
+
     return 0;
 fail:
     ff_h264_unref_picture(h, pic);
index 4c355fe..47d7cbf 100644 (file)
@@ -32,6 +32,8 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/opt.h"
 #include "libavutil/stereo3d.h"
+#include "libavutil/video_enc_params.h"
+
 #include "internal.h"
 #include "bytestream.h"
 #include "cabac.h"
@@ -812,6 +814,40 @@ static int get_consumed_bytes(int pos, int buf_size)
     return pos;
 }
 
+static int h264_export_enc_params(AVFrame *f, H264Picture *p)
+{
+    AVVideoEncParams *par;
+    unsigned int nb_mb = p->mb_height * p->mb_width;
+    unsigned int x, y;
+
+    par = av_video_enc_params_create_side_data(f, AV_VIDEO_ENC_PARAMS_H264, nb_mb);
+    if (!par)
+        return AVERROR(ENOMEM);
+
+    par->qp = p->pps->init_qp;
+
+    par->delta_qp[1][0] = p->pps->chroma_qp_index_offset[0];
+    par->delta_qp[1][1] = p->pps->chroma_qp_index_offset[0];
+    par->delta_qp[2][0] = p->pps->chroma_qp_index_offset[1];
+    par->delta_qp[2][1] = p->pps->chroma_qp_index_offset[1];
+
+    for (y = 0; y < p->mb_height; y++)
+        for (x = 0; x < p->mb_width; x++) {
+            const unsigned int block_idx = y * p->mb_width + x;
+            const unsigned int     mb_xy = y * p->mb_stride + x;
+            AVVideoBlockParams *b = av_video_enc_params_block(par, block_idx);
+
+            b->src_x = x * 16;
+            b->src_y = y * 16;
+            b->w     = 16;
+            b->h     = 16;
+
+            b->delta_qp = p->qscale_table[mb_xy] - par->qp;
+        }
+
+    return 0;
+}
+
 static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
 {
     AVFrame *src = srcp->f;
@@ -826,7 +862,16 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
     if (srcp->sei_recovery_frame_cnt == 0)
         dst->key_frame = 1;
 
+    if (h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS) {
+        ret = h264_export_enc_params(dst, srcp);
+        if (ret < 0)
+            goto fail;
+    }
+
     return 0;
+fail:
+    av_frame_unref(dst);
+    return ret;
 }
 
 static int is_extra(const uint8_t *buf, int buf_size)
index 530e2d4..29c4d4e 100644 (file)
@@ -161,6 +161,12 @@ typedef struct H264Picture {
     int recovered;          ///< picture at IDR or recovery point + recovery count
     int invalid_gap;
     int sei_recovery_frame_cnt;
+
+    AVBufferRef *pps_buf;
+    const PPS   *pps;
+
+    int mb_width, mb_height;
+    int mb_stride;
 } H264Picture;
 
 typedef struct H264Ref {
index 5821bcd..7acecf5 100644 (file)
@@ -79,7 +79,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  56
-#define LIBAVUTIL_VERSION_MINOR  48
+#define LIBAVUTIL_VERSION_MINOR  49
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
index 0cf79c4..43fa443 100644 (file)
@@ -42,6 +42,19 @@ enum AVVideoEncParamsType {
      *   unsigned 8-bit.
      */
     AV_VIDEO_ENC_PARAMS_VP9,
+
+    /**
+     * H.264 stores:
+     * - in PPS (per-picture):
+     *   * initial QP_Y (luma) value, exported as AVVideoEncParams.qp
+     *   * delta(s) for chroma QP values (same for both, or each separately),
+     *     exported as in the corresponding entries in AVVideoEncParams.delta_qp
+     * - per-slice QP delta, not exported directly, added to the per-MB value
+     * - per-MB delta; not exported directly; the final per-MB quantizer
+     *   parameter - QP_Y - minus the value in AVVideoEncParams.qp is exported
+     *   as AVVideoBlockParams.qp_delta.
+     */
+    AV_VIDEO_ENC_PARAMS_H264,
 };
 
 /**