From c438899a706422b8362a13714580e988be4d638b Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Thu, 25 Aug 2016 17:28:17 +0200 Subject: [PATCH] Add AV1 video decoding support through libaom Signed-off-by: Diego Biurrun Signed-off-by: Luca Barbato --- Changelog | 1 + configure | 4 ++ doc/general.texi | 10 +++ libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 1 + libavcodec/libaom.c | 133 ++++++++++++++++++++++++++++++++++ libavcodec/libaom.h | 31 ++++++++ libavcodec/libaomdec.c | 160 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 342 insertions(+) create mode 100644 libavcodec/libaom.c create mode 100644 libavcodec/libaom.h create mode 100644 libavcodec/libaomdec.c diff --git a/Changelog b/Changelog index 51c3f85a28..0d20cd47df 100644 --- a/Changelog +++ b/Changelog @@ -20,6 +20,7 @@ version : - Intel QSV-accelerated MJPEG encoding - NVIDIA CUVID-accelerated H.264 and HEVC decoding - Intel QSV-accelerated overlay filter +- AV1 Support through libaom version 12: diff --git a/configure b/configure index b91be32102..a43fb93cdf 100755 --- a/configure +++ b/configure @@ -187,6 +187,7 @@ External library support: --enable-bzlib bzip2 compression [autodetect] --enable-frei0r video filtering plugins --enable-gnutls crypto + --enable-libaom AV1 video encoding/decoding --enable-libbs2b Bauer stereophonic-to-binaural DSP --enable-libcdio audio CD input --enable-libdc1394 IEEE 1394/Firewire camera input @@ -1349,6 +1350,7 @@ EXTERNAL_LIBRARY_LIST=" avxsynth frei0r gnutls + libaom libbs2b libdc1394 libdcadec @@ -2363,6 +2365,7 @@ avisynth_deps="LoadLibrary" avxsynth_deps="libdl" avisynth_demuxer_deps_any="avisynth avxsynth" avisynth_demuxer_select="riffdec" +libaom_av1_decoder_deps="libaom" libdcadec_decoder_deps="libdcadec" libfaac_encoder_deps="libfaac" libfaac_encoder_select="audio_frame_queue" @@ -4641,6 +4644,7 @@ enabled cuvid && require cuvid cuviddec.h cuvidCreateDecoder -lnvcuv enabled frei0r && require_header frei0r.h enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init && check_lib gmp gmp.h mpz_export -lgmp +enabled libaom && require_pkg_config libaom "aom >= 0.1.0" aom/aom_codec.h aom_codec_version enabled libbs2b && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new enabled libdcadec && require libdcadec libdcadec/dca_context.h dcadec_context_create -ldcadec diff --git a/doc/general.texi b/doc/general.texi index 0c92761a49..e066b42187 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -16,6 +16,14 @@ for more formats. None of them are used by default, their use has to be explicitly requested by passing the appropriate flags to @command{./configure}. +@section Alliance for Open Media libaom + +Libav can make use of the libaom library for AV1 decoding. + +Go to @url{http://aomedia.org/} and follow the instructions for +installing the library. Then pass @code{--enable-libaom} to configure to +enable it. + @section OpenCORE and VisualOn libraries Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer @@ -617,6 +625,8 @@ following image formats are supported: @item Autodesk Animator Flic video @tab @tab X @item Autodesk RLE @tab @tab X @tab fourcc: AASC +@item AV1 @tab @tab E + @tab Supported through external library libaom @item AVS (Audio Video Standard) video @tab @tab X @tab Video encoding used by the Creature Shock game. @item Beam Software VB @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 99969ac779..0b50a839bc 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -687,6 +687,7 @@ OBJS-$(CONFIG_TAK_DEMUXER) += tak.o OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o # external codec libraries +OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o OBJS-$(CONFIG_LIBDCADEC_DECODER) += libdcadec.o dca.o OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o @@ -814,6 +815,7 @@ SKIPHEADERS-$(CONFIG_CUVID) += cuvid.h SKIPHEADERS-$(CONFIG_AMF) += amfenc.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h +SKIPHEADERS-$(CONFIG_LIBAOM) += libaom.h SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index efde5a2b0e..ec923cd511 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -421,6 +421,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (XSUB, xsub); /* external libraries */ + REGISTER_DECODER(LIBAOM_AV1, libaom_av1); REGISTER_DECODER(LIBDCADEC, libdcadec) REGISTER_ENCODER(LIBFAAC, libfaac); REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac); diff --git a/libavcodec/libaom.c b/libavcodec/libaom.c new file mode 100644 index 0000000000..220b1bd245 --- /dev/null +++ b/libavcodec/libaom.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013 Guillaume Martres + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libaom.h" + +#define HIGH_DEPTH(fmt) \ +case AOM_IMG_FMT_I ## fmt ## 16: \ + switch (depth) { \ + case 8: \ + return AV_PIX_FMT_YUV ## fmt ## P; \ + case 10: \ + return AV_PIX_FMT_YUV ## fmt ## P10; \ + case 12: \ + return AV_PIX_FMT_YUV ## fmt ## P12; \ + default: \ + return AV_PIX_FMT_NONE; \ + } + +enum AVPixelFormat ff_aom_imgfmt_to_pixfmt(aom_img_fmt_t img, int depth) +{ + switch (img) { + case AOM_IMG_FMT_RGB24: + return AV_PIX_FMT_RGB24; + case AOM_IMG_FMT_RGB565: + return AV_PIX_FMT_RGB565BE; + case AOM_IMG_FMT_RGB555: + return AV_PIX_FMT_RGB555BE; + case AOM_IMG_FMT_UYVY: + return AV_PIX_FMT_UYVY422; + case AOM_IMG_FMT_YUY2: + return AV_PIX_FMT_YUYV422; + case AOM_IMG_FMT_YVYU: + return AV_PIX_FMT_YVYU422; + case AOM_IMG_FMT_BGR24: + return AV_PIX_FMT_BGR24; + case AOM_IMG_FMT_ARGB: + return AV_PIX_FMT_ARGB; + case AOM_IMG_FMT_ARGB_LE: + return AV_PIX_FMT_BGRA; + case AOM_IMG_FMT_RGB565_LE: + return AV_PIX_FMT_RGB565LE; + case AOM_IMG_FMT_RGB555_LE: + return AV_PIX_FMT_RGB555LE; + case AOM_IMG_FMT_I420: + return AV_PIX_FMT_YUV420P; + case AOM_IMG_FMT_I422: + return AV_PIX_FMT_YUV422P; + case AOM_IMG_FMT_I444: + return AV_PIX_FMT_YUV444P; + case AOM_IMG_FMT_444A: + return AV_PIX_FMT_YUVA444P; + case AOM_IMG_FMT_I440: + return AV_PIX_FMT_YUV440P; + HIGH_DEPTH(420) + HIGH_DEPTH(422) + HIGH_DEPTH(444) + default: + return AV_PIX_FMT_NONE; + } +} + +#undef HIGH_DEPTH + +aom_img_fmt_t ff_aom_pixfmt_to_imgfmt(enum AVPixelFormat pix) +{ + switch (pix) { + case AV_PIX_FMT_RGB24: + return AOM_IMG_FMT_RGB24; + case AV_PIX_FMT_RGB565BE: + return AOM_IMG_FMT_RGB565; + case AV_PIX_FMT_RGB555BE: + return AOM_IMG_FMT_RGB555; + case AV_PIX_FMT_UYVY422: + return AOM_IMG_FMT_UYVY; + case AV_PIX_FMT_YUYV422: + return AOM_IMG_FMT_YUY2; + case AV_PIX_FMT_YVYU422: + return AOM_IMG_FMT_YVYU; + case AV_PIX_FMT_BGR24: + return AOM_IMG_FMT_BGR24; + case AV_PIX_FMT_ARGB: + return AOM_IMG_FMT_ARGB; + case AV_PIX_FMT_BGRA: + return AOM_IMG_FMT_ARGB_LE; + case AV_PIX_FMT_RGB565LE: + return AOM_IMG_FMT_RGB565_LE; + case AV_PIX_FMT_RGB555LE: + return AOM_IMG_FMT_RGB555_LE; + case AV_PIX_FMT_YUV420P: + return AOM_IMG_FMT_I420; + case AV_PIX_FMT_YUV422P: + return AOM_IMG_FMT_I422; + case AV_PIX_FMT_YUV444P: + return AOM_IMG_FMT_I444; + case AV_PIX_FMT_YUVA444P: + return AOM_IMG_FMT_444A; + case AV_PIX_FMT_YUV440P: + return AOM_IMG_FMT_I440; + case AV_PIX_FMT_YUV420P10: + return AOM_IMG_FMT_I42016; + case AV_PIX_FMT_YUV422P10: + return AOM_IMG_FMT_I42216; + case AV_PIX_FMT_YUV444P10: + return AOM_IMG_FMT_I44416; + case AV_PIX_FMT_YUV420P12: + return AOM_IMG_FMT_I42016; + case AV_PIX_FMT_YUV422P12: + return AOM_IMG_FMT_I42216; + case AV_PIX_FMT_YUV444P12: + return AOM_IMG_FMT_I44416; + default: + return AOM_IMG_FMT_NONE; + } +} diff --git a/libavcodec/libaom.h b/libavcodec/libaom.h new file mode 100644 index 0000000000..d3d52f704e --- /dev/null +++ b/libavcodec/libaom.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013 Guillaume Martres + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_LIBAOM_H +#define AVCODEC_LIBAOM_H + +#include + +#include "libavutil/pixfmt.h" + +enum AVPixelFormat ff_aom_imgfmt_to_pixfmt(aom_img_fmt_t img, int depth); +aom_img_fmt_t ff_aom_pixfmt_to_imgfmt(enum AVPixelFormat pix); + +#endif /* AVCODEC_LIBAOM_H */ diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c new file mode 100644 index 0000000000..859c7729b6 --- /dev/null +++ b/libavcodec/libaomdec.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, Google, Inc. + * + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AV1 decoder support via libaom + */ + +#include +#include + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "internal.h" +#include "libaom.h" + +typedef struct AV1DecodeContext { + struct aom_codec_ctx decoder; +} AV1DecodeContext; + +static av_cold int aom_init(AVCodecContext *avctx) +{ + AV1DecodeContext *ctx = avctx->priv_data; + struct aom_codec_dec_cfg deccfg = { + /* token partitions+1 would be a decent choice */ + .threads = FFMIN(avctx->thread_count, 16) + }; + const struct aom_codec_iface *iface = &aom_codec_av1_dx_algo; + + av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str()); + av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config()); + + if (aom_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != AOM_CODEC_OK) { + const char *error = aom_codec_error(&ctx->decoder); + av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", + error); + return AVERROR(EINVAL); + } + + return 0; +} + +static void image_copy_16_to_8(AVFrame *pic, struct aom_image *img) +{ + int i; + + for (i = 0; i < 3; 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++; + } + } +} + + +static int aom_decode(AVCodecContext *avctx, void *data, int *got_frame, + AVPacket *avpkt) +{ + AV1DecodeContext *ctx = avctx->priv_data; + AVFrame *picture = data; + const void *iter = NULL; + struct aom_image *img; + int ret; + + if (aom_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL) != + AOM_CODEC_OK) { + const char *error = aom_codec_error(&ctx->decoder); + const char *detail = aom_codec_error_detail(&ctx->decoder); + + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); + if (detail) + av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", + detail); + return AVERROR_INVALIDDATA; + } + + if ((img = aom_codec_get_frame(&ctx->decoder, &iter))) { + avctx->pix_fmt = ff_aom_imgfmt_to_pixfmt(img->fmt, img->bit_depth); + if (avctx->pix_fmt == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (0x%02x %dbits)\n", + img->fmt, img->bit_depth); + return AVERROR_INVALIDDATA; + } + + if ((int)img->d_w != avctx->width || (int)img->d_h != avctx->height) { + av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", + avctx->width, avctx->height, img->d_w, img->d_h); + ret = ff_set_dimensions(avctx, img->d_w, img->d_h); + if (ret < 0) + return ret; + } + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) && img->bit_depth == 8) + image_copy_16_to_8(picture, img); + else + av_image_copy(picture->data, picture->linesize, (const uint8_t **)img->planes, + img->stride, avctx->pix_fmt, img->d_w, img->d_h); + switch (img->range) { + case AOM_CR_STUDIO_RANGE: + picture->color_range = AVCOL_RANGE_MPEG; + break; + case AOM_CR_FULL_RANGE: + picture->color_range = AVCOL_RANGE_JPEG; + break; + } + *got_frame = 1; + } + return avpkt->size; +} + +static av_cold int aom_free(AVCodecContext *avctx) +{ + AV1DecodeContext *ctx = avctx->priv_data; + aom_codec_destroy(&ctx->decoder); + return 0; +} + +AVCodec ff_libaom_av1_decoder = { + .name = "libaom-av1", + .long_name = NULL_IF_CONFIG_SMALL("libaom AV1"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(AV1DecodeContext), + .init = aom_init, + .close = aom_free, + .decode = aom_decode, + .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, + .wrapper_name = "libaom", +};