diff mbox series

[FFmpeg-devel,6/9] avcodec/av1dec: add display frame for film grain usage

Message ID 20210617061037.20335-6-fei.w.wang@intel.com
State Superseded
Headers show
Series [FFmpeg-devel,1/9] cbs_av1: fix incorrect data type | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished

Commit Message

Fei Wang June 17, 2021, 6:10 a.m. UTC
Make it flexible if decode frame(without apply film grain) and display
frame(applied film grain) both needed when decode film grain clips.

Signed-off-by: Fei Wang <fei.w.wang@intel.com>
---
 libavcodec/av1dec.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/av1dec.h |  3 +++
 2 files changed, 45 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 3fca17e84b..af2ecb4f0c 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -569,6 +569,8 @@  static int get_pixel_format(AVCodecContext *avctx)
 static void av1_frame_unref(AVCodecContext *avctx, AV1Frame *f)
 {
     ff_thread_release_buffer(avctx, &f->tf);
+    if (f->tf_display.f->buf[0])
+        ff_thread_release_buffer(avctx, &f->tf_display);
     av_buffer_unref(&f->hwaccel_priv_buf);
     f->hwaccel_picture_private = NULL;
     av_buffer_unref(&f->header_ref);
@@ -588,6 +590,12 @@  static int av1_frame_ref(AVCodecContext *avctx, AV1Frame *dst, const AV1Frame *s
     if (ret < 0)
         return ret;
 
+    if (src->tf_display.f->buf[0]) {
+        ret = ff_thread_ref_frame(&dst->tf_display, &src->tf_display);
+        if (ret < 0)
+            return ret;
+    }
+
     dst->header_ref = av_buffer_ref(src->header_ref);
     if (!dst->header_ref)
         goto fail;
@@ -634,9 +642,11 @@  static av_cold int av1_decode_free(AVCodecContext *avctx)
     for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++) {
         av1_frame_unref(avctx, &s->ref[i]);
         av_frame_free(&s->ref[i].tf.f);
+        av_frame_free(&s->ref[i].tf_display.f);
     }
     av1_frame_unref(avctx, &s->cur_frame);
     av_frame_free(&s->cur_frame.tf.f);
+    av_frame_free(&s->cur_frame.tf_display.f);
 
     av_buffer_unref(&s->seq_ref);
     av_buffer_unref(&s->header_ref);
@@ -738,6 +748,13 @@  static av_cold int av1_decode_init(AVCodecContext *avctx)
                    "Failed to allocate reference frame buffer %d.\n", i);
             return AVERROR(ENOMEM);
         }
+
+        s->ref[i].tf_display.f = av_frame_alloc();
+        if (!s->ref[i].tf_display.f) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Failed to allocate display frame buffer %d.\n", i);
+            return AVERROR(ENOMEM);
+        }
     }
 
     s->cur_frame.tf.f = av_frame_alloc();
@@ -747,6 +764,13 @@  static av_cold int av1_decode_init(AVCodecContext *avctx)
         return AVERROR(ENOMEM);
     }
 
+    s->cur_frame.tf_display.f = av_frame_alloc();
+    if (!s->cur_frame.tf_display.f) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Failed to allocate current display frame buffer.\n");
+        return AVERROR(ENOMEM);
+    }
+
     ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_AV1, avctx);
     if (ret < 0)
         return ret;
@@ -819,6 +843,16 @@  static int av1_frame_alloc(AVCodecContext *avctx, AV1Frame *f)
         break;
     }
 
+    if (header->film_grain.apply_grain &&
+        (avctx->pix_fmt == AV_PIX_FMT_VAAPI) &&
+        !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN)) {
+        if ((ret = ff_thread_get_buffer(avctx, &f->tf_display, AV_GET_BUFFER_FLAG_REF)) < 0)
+            goto fail;
+
+        f->tf_display.f->key_frame = frame->key_frame;
+        f->tf_display.f->pict_type = frame->pict_type;
+    }
+
     if (avctx->hwaccel) {
         const AVHWAccel *hwaccel = avctx->hwaccel;
         if (hwaccel->frame_priv_data_size) {
@@ -902,9 +936,16 @@  static int set_output_frame(AVCodecContext *avctx, AVFrame *frame,
                             const AVPacket *pkt, int *got_frame)
 {
     AV1DecContext *s = avctx->priv_data;
-    const AVFrame *srcframe = s->cur_frame.tf.f;
+    const AVFrame *srcframe;
     int ret;
 
+    /* Use tf_display as output when it is available. */
+    if (s->cur_frame.tf_display.f->buf[0]) {
+        srcframe = s->cur_frame.tf_display.f;
+    } else {
+        srcframe= s->cur_frame.tf.f;
+    }
+
     // TODO: all layers
     if (s->operating_point_idc &&
         av_log2(s->operating_point_idc >> 8) > s->cur_frame.spatial_id)
diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h
index 4e140588b9..5af3dfc867 100644
--- a/libavcodec/av1dec.h
+++ b/libavcodec/av1dec.h
@@ -33,6 +33,9 @@ 
 typedef struct AV1Frame {
     ThreadFrame tf;
 
+    /** current tf_display is only used for VA-API to apply film grain */
+    ThreadFrame tf_display;
+
     AVBufferRef *hwaccel_priv_buf;
     void *hwaccel_picture_private;