[FFmpeg-devel] [PATCH 03/13] avcodec/decode: support applying LCEVC enhacements

James Almer jamrial at gmail.com
Sat Aug 31 19:31:04 EEST 2024


Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/avcodec.c       |  2 ++
 libavcodec/avcodec.h       |  5 +++++
 libavcodec/decode.c        | 42 +++++++++++++++++++++++++++++++++++++-
 libavcodec/internal.h      |  2 ++
 libavcodec/lcevcdec.c      |  2 ++
 libavcodec/options_table.h |  1 +
 libavcodec/pthread_frame.c |  7 +++++++
 7 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 6065f1b689..380df267a0 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -446,6 +446,8 @@ av_cold void ff_codec_close(AVCodecContext *avctx)
         ff_refstruct_unref(&avci->pool);
         ff_refstruct_pool_uninit(&avci->progress_frame_pool);
 
+        av_buffer_unref(&avci->lcevc);
+
         ff_hwaccel_uninit(avctx);
 
         av_bsf_free(&avci->bsf);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 7a67300134..f6e01da738 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -418,6 +418,11 @@ typedef struct RcOverride{
  * Do not apply film grain, export it instead.
  */
 #define AV_CODEC_EXPORT_DATA_FILM_GRAIN (1 << 3)
+/**
+ * Decoding only.
+ * Do not apply picture enhancement layers, export them instead.
+ */
+#define AV_CODEC_EXPORT_DATA_ENHANCEMENTS (1 << 4)
 
 /**
  * The decoder will keep a reference to the frame and may reuse it later.
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 27dba8a1f3..dc868714ac 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -48,6 +48,7 @@
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "internal.h"
+#include "lcevcdec.h"
 #include "packet_internal.h"
 #include "progressframe.h"
 #include "refstruct.h"
@@ -1599,6 +1600,7 @@ int ff_attach_decode_data(AVFrame *frame)
 int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
 {
     const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
+    int lcevc = 0, width = 0, height = 0;
     int override_dimensions = 1;
     int ret;
 
@@ -1639,8 +1641,17 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
             ret = hwaccel->alloc_frame(avctx, frame);
             goto end;
         }
-    } else
+    } else {
         avctx->sw_pix_fmt = avctx->pix_fmt;
+        lcevc = CONFIG_LIBLCEVC_DEC && avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
+                avctx->internal->lcevc && av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC);
+        if (lcevc) {
+            width         = frame->width;
+            height        = frame->height;
+            frame->width  = frame->width  * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
+            frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
+        }
+    }
 
     ret = avctx->get_buffer2(avctx, frame, flags);
     if (ret < 0)
@@ -1652,6 +1663,20 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
     if (ret < 0)
         goto fail;
 
+    if (CONFIG_LIBLCEVC_DEC && lcevc) {
+        FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data;
+        fdd->post_process_opaque = av_buffer_ref(avctx->internal->lcevc);
+
+        frame->width  = width;
+        frame->height = height;
+        if (!fdd->post_process_opaque) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+        fdd->post_process_opaque_free = ff_lcevc_unref;
+        fdd->post_process = ff_lcevc_process;
+    }
+
 end:
     if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
         !(ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
@@ -1949,6 +1974,21 @@ int ff_decode_preinit(AVCodecContext *avctx)
     if (ret < 0)
         return ret;
 
+    if (CONFIG_LIBLCEVC_DEC && !(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
+        FFLCEVCContext *lcevc = av_mallocz(sizeof(*lcevc));
+
+        if (!lcevc || !(avci->lcevc = av_buffer_create((uint8_t *)lcevc, sizeof(*lcevc),
+                                                       ff_lcevc_free, lcevc, 0))) {
+            int explode = avctx->err_recognition & AV_EF_EXPLODE;
+            av_log(avctx, explode ? AV_LOG_ERROR: AV_LOG_WARNING,
+                   "Error allocating LCEVC context\n");
+            if (explode) {
+                av_free(lcevc);
+                return AVERROR(ENOMEM);
+            }
+        }
+    }
+
 #if FF_API_DROPCHANGED
     if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
         av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 98ab2797ce..aae78854cc 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -158,6 +158,8 @@ typedef struct AVCodecInternal {
     FFIccContext icc; /* used to read and write embedded ICC profiles */
 #endif
 
+    AVBufferRef *lcevc;
+
     /**
      * Set when the user has been warned about a failed allocation from
      * a fixed frame pool.
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index ae1d150986..47fdaaa9ef 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -229,6 +229,8 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
     if (ret < 0)
         return ret;
 
+    av_frame_remove_side_data(frame, AV_FRAME_DATA_LCEVC);
+
     return 0;
 }
 
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 33f1bce887..332f354fa6 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -93,6 +93,7 @@ static const AVOption avcodec_options[] = {
 {"prft", "export Producer Reference Time through packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_PRFT}, INT_MIN, INT_MAX, A|V|S|E, .unit = "export_side_data"},
 {"venc_params", "export video encoding parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"},
 {"film_grain", "export film grain parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_FILM_GRAIN}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"},
+{"enhancements", "export film grain parameters through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_EXPORT_DATA_ENHANCEMENTS}, INT_MIN, INT_MAX, V|D, .unit = "export_side_data"},
 {"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT_MAX},
 {"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E},
 {"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E},
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 019e33b7b2..00ad93cbdf 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -782,6 +782,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
             ff_refstruct_unref(&ctx->internal->pool);
             av_packet_free(&ctx->internal->in_pkt);
             av_packet_free(&ctx->internal->last_pkt_props);
+            av_buffer_unref(&ctx->internal->lcevc);
             av_freep(&ctx->internal);
             av_buffer_unref(&ctx->hw_frames_ctx);
             av_frame_side_data_free(&ctx->decoded_side_data,
@@ -878,6 +879,12 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
     if (!copy->internal->in_pkt)
         return AVERROR(ENOMEM);
 
+    if (avctx->internal->lcevc) {
+        copy->internal->lcevc = av_buffer_ref(avctx->internal->lcevc);
+        if (!copy->internal->lcevc)
+            return AVERROR(ENOMEM);
+    }
+
     copy->internal->last_pkt_props = av_packet_alloc();
     if (!copy->internal->last_pkt_props)
         return AVERROR(ENOMEM);
-- 
2.46.0



More information about the ffmpeg-devel mailing list