[FFmpeg-devel] [PATCH] avcodec/libaomenc: support AV_CODEC_CAP_ENCODER_RECON_FRAME

James Almer jamrial at gmail.com
Tue Aug 2 14:35:19 EEST 2022


Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/Makefile    |  4 +-
 libavcodec/libaom.c    | 49 +++++++++++++++++++++
 libavcodec/libaom.h    | 33 ++++++++++++++
 libavcodec/libaomdec.c | 27 +-----------
 libavcodec/libaomenc.c | 97 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 183 insertions(+), 27 deletions(-)
 create mode 100644 libavcodec/libaom.c
 create mode 100644 libavcodec/libaom.h

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index aff7752856..ca5a38bee1 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1055,8 +1055,8 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER)            += audiotoolboxenc.o
 OBJS-$(CONFIG_ILBC_AT_ENCODER)            += audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER)        += audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER)       += audiotoolboxenc.o
-OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o
-OBJS-$(CONFIG_LIBAOM_AV1_ENCODER)         += libaomenc.o
+OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o libaom.o
+OBJS-$(CONFIG_LIBAOM_AV1_ENCODER)         += libaomenc.o libaom.o
 OBJS-$(CONFIG_LIBARIBB24_DECODER)         += libaribb24.o ass.o
 OBJS-$(CONFIG_LIBCELT_DECODER)            += libcelt_dec.o
 OBJS-$(CONFIG_LIBCODEC2_DECODER)          += libcodec2.o
diff --git a/libavcodec/libaom.c b/libavcodec/libaom.c
new file mode 100644
index 0000000000..0befaaa530
--- /dev/null
+++ b/libavcodec/libaom.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AOM common functions
+ */
+
+#include "libavutil/pixdesc.h"
+#include "libaom.h"
+
+void ff_aom_image_copy_16_to_8(AVFrame *pic, struct aom_image *img)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format);
+    int i;
+
+    for (i = 0; i < desc->nb_components; i++) {
+        int w = img->d_w;
+        int h = img->d_h;
+        int x, y;
+
+        if (i) {
+            w = (w + img->x_chroma_shift) >> img->x_chroma_shift;
+            h = (h + img->y_chroma_shift) >> img->y_chroma_shift;
+        }
+
+        for (y = 0; y < h; y++) {
+            uint16_t *src = (uint16_t *)(img->planes[i] + y * img->stride[i]);
+            uint8_t *dst = pic->data[i] + y * pic->linesize[i];
+            for (x = 0; x < w; x++)
+                *dst++ = *src++;
+        }
+    }
+}
diff --git a/libavcodec/libaom.h b/libavcodec/libaom.h
new file mode 100644
index 0000000000..bb495af982
--- /dev/null
+++ b/libavcodec/libaom.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AOM common functions
+ */
+
+#ifndef AVCODEC_LIBAOM_H
+#define AVCODEC_LIBAOM_H
+
+#include <aom/aom_image.h>
+
+#include "libavutil/frame.h"
+
+void ff_aom_image_copy_16_to_8(AVFrame *pic, struct aom_image *img);
+
+#endif /* AVCODEC_LIBAOM_H */
diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c
index 3243610304..cb672b0e65 100644
--- a/libavcodec/libaomdec.c
+++ b/libavcodec/libaomdec.c
@@ -33,6 +33,7 @@
 #include "avcodec.h"
 #include "codec_internal.h"
 #include "internal.h"
+#include "libaom.h"
 #include "profiles.h"
 
 typedef struct AV1DecodeContext {
@@ -60,30 +61,6 @@ static av_cold int aom_init(AVCodecContext *avctx,
     return 0;
 }
 
-static void image_copy_16_to_8(AVFrame *pic, struct aom_image *img)
-{
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format);
-    int i;
-
-    for (i = 0; i < desc->nb_components; i++) {
-        int w = img->d_w;
-        int h = img->d_h;
-        int x, y;
-
-        if (i) {
-            w = (w + img->x_chroma_shift) >> img->x_chroma_shift;
-            h = (h + img->y_chroma_shift) >> img->y_chroma_shift;
-        }
-
-        for (y = 0; y < h; y++) {
-            uint16_t *src = (uint16_t *)(img->planes[i] + y * img->stride[i]);
-            uint8_t *dst = pic->data[i] + y * pic->linesize[i];
-            for (x = 0; x < w; x++)
-                *dst++ = *src++;
-        }
-    }
-}
-
 // returns 0 on success, AVERROR_INVALIDDATA otherwise
 static int set_pix_fmt(AVCodecContext *avctx, struct aom_image *img)
 {
@@ -223,7 +200,7 @@ static int aom_decode(AVCodecContext *avctx, AVFrame *picture,
         ff_set_sar(avctx, picture->sample_aspect_ratio);
 
         if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) && img->bit_depth == 8)
-            image_copy_16_to_8(picture, img);
+            ff_aom_image_copy_16_to_8(picture, img);
         else {
             const uint8_t *planes[4] = { img->planes[0], img->planes[1], img->planes[2] };
             const int      stride[4] = { img->stride[0], img->stride[1], img->stride[2] };
diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c
index b792226744..1fd69d59a7 100644
--- a/libavcodec/libaomenc.c
+++ b/libavcodec/libaomenc.c
@@ -31,6 +31,7 @@
 #include "libavutil/base64.h"
 #include "libavutil/common.h"
 #include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
@@ -41,6 +42,7 @@
 #include "codec_internal.h"
 #include "encode.h"
 #include "internal.h"
+#include "libaom.h"
 #include "packet_internal.h"
 #include "profiles.h"
 
@@ -208,6 +210,7 @@ static const char *const ctlidstr[] = {
 #ifdef AOM_CTRL_AV1E_GET_TARGET_SEQ_LEVEL_IDX
     [AV1E_GET_TARGET_SEQ_LEVEL_IDX]     = "AV1E_GET_TARGET_SEQ_LEVEL_IDX",
 #endif
+    [AV1_GET_NEW_FRAME_IMAGE]           = "AV1_GET_NEW_FRAME_IMAGE",
 };
 
 static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
@@ -364,6 +367,31 @@ static av_cold int codecctl_intp(AVCodecContext *avctx,
 }
 #endif
 
+static av_cold int codecctl_imgp(AVCodecContext *avctx,
+#ifdef UENUM1BYTE
+                                 aome_enc_control_id id,
+#else
+                                 enum aome_enc_control_id id,
+#endif
+                                 struct aom_image *img)
+{
+    AOMContext *ctx = avctx->priv_data;
+    char buf[80];
+    int res;
+
+    snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]);
+
+    res = aom_codec_control(&ctx->encoder, id, img);
+    if (res != AOM_CODEC_OK) {
+        snprintf(buf, sizeof(buf), "Failed to get %s codec control",
+                 ctlidstr[id]);
+        log_encoder_error(avctx, buf);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
 static av_cold int aom_free(AVCodecContext *avctx)
 {
     AOMContext *ctx = avctx->priv_data;
@@ -1206,6 +1234,37 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out)
     return size;
 }
 
+static enum AVPixelFormat aomfmt_to_pixfmt(struct aom_image *img)
+{
+    switch (img->fmt) {
+    case AOM_IMG_FMT_I420:
+    case AOM_IMG_FMT_I42016:
+        if (img->bit_depth == 8)
+            return img->monochrome ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_YUV420P;
+        else if (img->bit_depth == 10)
+            return img->monochrome ? AV_PIX_FMT_GRAY10 : AV_PIX_FMT_YUV420P10;
+        else
+            return img->monochrome ? AV_PIX_FMT_GRAY12 : AV_PIX_FMT_YUV420P12;
+    case AOM_IMG_FMT_I422:
+    case AOM_IMG_FMT_I42216:
+        if (img->bit_depth == 8)
+            return AV_PIX_FMT_YUV422P;
+        else if (img->bit_depth == 10)
+            return AV_PIX_FMT_YUV422P10;
+        else
+            return AV_PIX_FMT_YUV422P12;
+    case AOM_IMG_FMT_I444:
+    case AOM_IMG_FMT_I44416:
+        if (img->bit_depth == 8)
+            return AV_PIX_FMT_YUV444P;
+        else if (img->bit_depth == 10)
+            return AV_PIX_FMT_YUV444P10;
+        else
+            return AV_PIX_FMT_YUV444P12;
+    };
+    return AV_PIX_FMT_NONE;
+}
+
 static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
                       const AVFrame *frame, int *got_packet)
 {
@@ -1259,6 +1318,43 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt,
     }
 
     *got_packet = !!coded_size;
+
+    if (*got_packet && avctx->flags & AV_CODEC_FLAG_RECON_FRAME) {
+        AVCodecInternal *avci = avctx->internal;
+        struct aom_image img;
+
+        av_frame_unref(avci->recon_frame);
+
+        res = codecctl_imgp(avctx, AV1_GET_NEW_FRAME_IMAGE, &img);
+        if (res < 0)
+            return res;
+
+        avci->recon_frame->format = aomfmt_to_pixfmt(&img);
+        if (avci->recon_frame->format == AV_PIX_FMT_NONE) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Unhandled reconstructed frame colorspace: %d\n",
+                   img.fmt);
+            return AVERROR(ENOSYS);
+        }
+
+        avci->recon_frame->width  = img.d_w;
+        avci->recon_frame->height = img.d_h;
+
+        res = av_frame_get_buffer(avci->recon_frame, 0);
+        if (res < 0)
+            return res;
+
+        if ((img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) && img.bit_depth == 8)
+            ff_aom_image_copy_16_to_8(avci->recon_frame, &img);
+        else {
+            const uint8_t *planes[4] = { img.planes[0], img.planes[1], img.planes[2] };
+            const int      stride[4] = { img.stride[0], img.stride[1], img.stride[2] };
+
+            av_image_copy(avci->recon_frame->data, avci->recon_frame->linesize, planes,
+                          stride, avci->recon_frame->format, img.d_w, img.d_h);
+        }
+    }
+
     return 0;
 }
 
@@ -1434,6 +1530,7 @@ FFCodec ff_libaom_av1_encoder = {
     .p.type         = AVMEDIA_TYPE_VIDEO,
     .p.id           = AV_CODEC_ID_AV1,
     .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
+                      AV_CODEC_CAP_ENCODER_RECON_FRAME |
                       AV_CODEC_CAP_OTHER_THREADS,
     .p.profiles     = NULL_IF_CONFIG_SMALL(ff_av1_profiles),
     .p.priv_class   = &class_aom,
-- 
2.37.1



More information about the ffmpeg-devel mailing list