From 064b875e894f45ea9e0426696559645d87af0bc3 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 10 Mar 2020 18:26:00 +0100 Subject: [PATCH] h264dec: support exporting QP tables through the AVVideoEncParams API --- doc/APIchanges | 3 +++ libavcodec/h264_picture.c | 8 ++++++- libavcodec/h264_slice.c | 9 ++++++++ libavcodec/h264dec.c | 45 ++++++++++++++++++++++++++++++++++++ libavcodec/h264dec.h | 6 +++++ libavutil/version.h | 2 +- libavutil/video_enc_params.h | 13 +++++++++++ 7 files changed, 84 insertions(+), 2 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 24c81d856c..56ec9f8ac3 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -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. diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index 2113947d1d..eec5e9fb9a 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -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: diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 5a8a4a7f86..713953778a 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -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); diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 4c355feb18..47d7cbf158 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -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) diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 530e2d4071..29c4d4e42c 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -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 { diff --git a/libavutil/version.h b/libavutil/version.h index 5821bcdd0e..7acecf5a97 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -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, \ diff --git a/libavutil/video_enc_params.h b/libavutil/video_enc_params.h index 0cf79c435c..43fa443154 100644 --- a/libavutil/video_enc_params.h +++ b/libavutil/video_enc_params.h @@ -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, }; /**