Commit 9bf9358b authored by James Almer's avatar James Almer

avcodec: libdav1d AV1 decoder wrapper.

Originally written by Ronald S. Bultje, with fixes, optimizations and
improvements by James Almer.
Signed-off-by: 's avatarJames Almer <jamrial@gmail.com>
parent f149a4a5
...@@ -25,6 +25,7 @@ version <next>: ...@@ -25,6 +25,7 @@ version <next>:
- Dropped support for building for Windows XP. The minimum supported Windows - Dropped support for building for Windows XP. The minimum supported Windows
version is Windows Vista. version is Windows Vista.
- support mbedTLS-based TLS - support mbedTLS-based TLS
- AV1 Support through libdav1d
version 12: version 12:
......
...@@ -190,6 +190,7 @@ External library support: ...@@ -190,6 +190,7 @@ External library support:
--enable-libaom AV1 video encoding/decoding --enable-libaom AV1 video encoding/decoding
--enable-libbs2b Bauer stereophonic-to-binaural DSP --enable-libbs2b Bauer stereophonic-to-binaural DSP
--enable-libcdio audio CD input --enable-libcdio audio CD input
--enable-libdav1d AV1 video decoding
--enable-libdc1394 IEEE 1394/Firewire camera input --enable-libdc1394 IEEE 1394/Firewire camera input
--enable-libdcadec DCA audio decoding --enable-libdcadec DCA audio decoding
--enable-libfaac AAC audio encoding --enable-libfaac AAC audio encoding
...@@ -1357,6 +1358,7 @@ EXTERNAL_LIBRARY_LIST=" ...@@ -1357,6 +1358,7 @@ EXTERNAL_LIBRARY_LIST="
gnutls gnutls
libaom libaom
libbs2b libbs2b
libdav1d
libdc1394 libdc1394
libdcadec libdcadec
libfontconfig libfontconfig
...@@ -2372,6 +2374,7 @@ avisynth_demuxer_deps_any="avisynth avxsynth" ...@@ -2372,6 +2374,7 @@ avisynth_demuxer_deps_any="avisynth avxsynth"
avisynth_demuxer_select="riffdec" avisynth_demuxer_select="riffdec"
libaom_av1_decoder_deps="libaom" libaom_av1_decoder_deps="libaom"
libaom_av1_encoder_deps="libaom" libaom_av1_encoder_deps="libaom"
libdav1d_decoder_deps="libdav1d"
libdcadec_decoder_deps="libdcadec" libdcadec_decoder_deps="libdcadec"
libfaac_encoder_deps="libfaac" libfaac_encoder_deps="libfaac"
libfaac_encoder_select="audio_frame_queue" libfaac_encoder_select="audio_frame_queue"
...@@ -4673,6 +4676,7 @@ enabled libaom && { ...@@ -4673,6 +4676,7 @@ enabled libaom && {
} }
enabled libbs2b && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open 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 libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.0.1" dav1d/dav1d.h dav1d_version
enabled libdcadec && require libdcadec libdcadec/dca_context.h dcadec_context_create -ldcadec enabled libdcadec && require libdcadec libdcadec/dca_context.h dcadec_context_create -ldcadec
enabled libfaac && require libfaac "stdint.h faac.h" faacEncGetVersion -lfaac enabled libfaac && require libfaac "stdint.h faac.h" faacEncGetVersion -lfaac
enabled libfdk_aac && require_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen enabled libfdk_aac && require_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen
......
...@@ -18,12 +18,16 @@ explicitly requested by passing the appropriate flags to ...@@ -18,12 +18,16 @@ explicitly requested by passing the appropriate flags to
@section Alliance for Open Media libaom @section Alliance for Open Media libaom
Libav can make use of the libaom library for AV1 decoding. Libav can make use of the libaom and libdav1d libraries for AV1 decoding.
Go to @url{http://aomedia.org/} and follow the instructions for Go to @url{http://aomedia.org/} and follow the instructions for
installing the library. Then pass @code{--enable-libaom} to configure to installing libaom. Then pass @code{--enable-libaom} to configure to
enable it. enable it.
Go to @url{https://code.videolan.org/videolan/dav1d/} and follow the
instructions for installing libdav1d. Then pass @code{--enable-libdav1d}
to configure to enable it.
@section OpenCORE and VisualOn libraries @section OpenCORE and VisualOn libraries
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
...@@ -625,8 +629,8 @@ following image formats are supported: ...@@ -625,8 +629,8 @@ following image formats are supported:
@item Autodesk Animator Flic video @tab @tab X @item Autodesk Animator Flic video @tab @tab X
@item Autodesk RLE @tab @tab X @item Autodesk RLE @tab @tab X
@tab fourcc: AASC @tab fourcc: AASC
@item AV1 @tab @tab E @item AV1 @tab E @tab E
@tab Supported through external library libaom @tab Supported through external libraries libaom and libdav1d
@item AVS (Audio Video Standard) video @tab @tab X @item AVS (Audio Video Standard) video @tab @tab X
@tab Video encoding used by the Creature Shock game. @tab Video encoding used by the Creature Shock game.
@item Beam Software VB @tab @tab X @item Beam Software VB @tab @tab X
......
...@@ -689,6 +689,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o ...@@ -689,6 +689,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o
# external codec libraries # external codec libraries
OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o
OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o
OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d.o
OBJS-$(CONFIG_LIBDCADEC_DECODER) += libdcadec.o dca.o OBJS-$(CONFIG_LIBDCADEC_DECODER) += libdcadec.o dca.o
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o
OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o
......
...@@ -422,6 +422,7 @@ void avcodec_register_all(void) ...@@ -422,6 +422,7 @@ void avcodec_register_all(void)
/* external libraries */ /* external libraries */
REGISTER_ENCDEC (LIBAOM_AV1, libaom_av1); REGISTER_ENCDEC (LIBAOM_AV1, libaom_av1);
REGISTER_DECODER(LIBDAV1D, libdav1d)
REGISTER_DECODER(LIBDCADEC, libdcadec) REGISTER_DECODER(LIBDCADEC, libdcadec)
REGISTER_ENCODER(LIBFAAC, libfaac); REGISTER_ENCODER(LIBFAAC, libfaac);
REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac); REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac);
......
/*
* Copyright (c) 2018 Ronald S. Bultje <rsbultje gmail com>
* Copyright (c) 2018 James Almer <jamrial gmail com>
*
* 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 <dav1d/dav1d.h>
#include "libavutil/avassert.h"
#include "libavutil/fifo.h"
#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "decode.h"
#include "internal.h"
typedef struct Libdav1dContext {
AVClass *class;
Dav1dContext *c;
AVFifoBuffer *cache;
Dav1dData data;
int tile_threads;
} Libdav1dContext;
static av_cold int libdav1d_init(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dSettings s;
int res;
av_log(c, AV_LOG_INFO, "libdav1d %s\n", dav1d_version());
dav1d_default_settings(&s);
s.n_tile_threads = dav1d->tile_threads;
s.n_frame_threads = FFMIN(c->thread_count ? c->thread_count : av_cpu_count(), 256);
dav1d->cache = av_fifo_alloc(8 * sizeof(AVPacket));
if (!dav1d->cache)
return AVERROR(ENOMEM);
res = dav1d_open(&dav1d->c, &s);
if (res < 0)
return AVERROR(ENOMEM);
return 0;
}
static void libdav1d_flush(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
av_fifo_reset(dav1d->cache);
dav1d_data_unref(&dav1d->data);
dav1d_flush(dav1d->c);
}
static int libdav1d_fifo_write(void *src, void *dst, int dst_size) {
AVPacket *pkt_dst = dst, *pkt_src = src;
av_assert2(dst_size >= sizeof(AVPacket));
pkt_src->buf = NULL;
av_packet_free_side_data(pkt_src);
*pkt_dst = *pkt_src;
return sizeof(AVPacket);
}
static void libdav1d_data_free(const uint8_t *data, void *opaque) {
AVBufferRef *buf = opaque;
av_buffer_unref(&buf);
}
static void libdav1d_frame_free(void *opaque, uint8_t *data) {
Dav1dPicture p = { 0 };
p.ref = opaque;
p.data[0] = (void *) 0x1; // this has to be non-NULL
dav1d_picture_unref(&p);
}
static const enum AVPixelFormat pix_fmt[][2] = {
[DAV1D_PIXEL_LAYOUT_I400] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10 },
[DAV1D_PIXEL_LAYOUT_I420] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10 },
[DAV1D_PIXEL_LAYOUT_I422] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10 },
[DAV1D_PIXEL_LAYOUT_I444] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10 },
};
// TODO: Update once 12bit support is added.
static const int profile[] = {
[DAV1D_PIXEL_LAYOUT_I400] = FF_PROFILE_AV1_MAIN,
[DAV1D_PIXEL_LAYOUT_I420] = FF_PROFILE_AV1_MAIN,
[DAV1D_PIXEL_LAYOUT_I422] = FF_PROFILE_AV1_PROFESSIONAL,
[DAV1D_PIXEL_LAYOUT_I444] = FF_PROFILE_AV1_HIGH,
};
static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame)
{
Libdav1dContext *dav1d = c->priv_data;
Dav1dData *data = &dav1d->data;
AVPacket pkt = { 0 };
Dav1dPicture p = { 0 };
int res;
if (!data->sz) {
res = ff_decode_get_packet(c, &pkt);
if (res < 0 && res != AVERROR_EOF)
return res;
if (pkt.size) {
if (!av_fifo_space(dav1d->cache)) {
res = av_fifo_realloc2(dav1d->cache, av_fifo_size(dav1d->cache) + 8 * sizeof(pkt));
if (res < 0) {
av_packet_unref(&pkt);
return res;
}
}
res = dav1d_data_wrap(data, pkt.data, pkt.size, libdav1d_data_free, pkt.buf);
if (res < 0) {
av_packet_unref(&pkt);
return res;
}
av_fifo_generic_write(dav1d->cache, &pkt, sizeof(pkt), libdav1d_fifo_write);
} else {
data = NULL;
}
}
res = dav1d_decode(dav1d->c, data, &p);
if (res < 0) {
if (res == -EINVAL)
res = AVERROR_INVALIDDATA;
else if (res == -EAGAIN && c->internal->draining)
res = AVERROR_EOF;
return res;
}
av_assert0(p.data[0] != NULL);
av_fifo_generic_read(dav1d->cache, &pkt, sizeof(pkt), NULL);
frame->buf[0] = av_buffer_create(NULL, 0, libdav1d_frame_free,
p.ref, AV_BUFFER_FLAG_READONLY);
if (!frame->buf[0]) {
dav1d_picture_unref(&p);
return AVERROR(ENOMEM);
}
frame->data[0] = p.data[0];
frame->data[1] = p.data[1];
frame->data[2] = p.data[2];
frame->linesize[0] = p.stride[0];
frame->linesize[1] = p.stride[1];
frame->linesize[2] = p.stride[1];
c->profile = profile[p.p.layout];
frame->format = c->pix_fmt = pix_fmt[p.p.layout][p.p.bpc == 10];
frame->width = p.p.w;
frame->height = p.p.h;
if (c->width != p.p.w || c->height != p.p.h) {
res = ff_set_dimensions(c, p.p.w, p.p.h);
if (res < 0)
return res;
}
switch (p.p.chr) {
case DAV1D_CHR_VERTICAL:
frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_LEFT;
break;
case DAV1D_CHR_COLOCATED:
frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
break;
}
frame->colorspace = c->colorspace = (enum AVColorSpace) p.p.mtrx;
frame->color_primaries = c->color_primaries = (enum AVColorPrimaries) p.p.pri;
frame->color_trc = c->color_trc = (enum AVColorTransferCharacteristic) p.p.trc;
frame->color_range = c->color_range = p.p.fullrange ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
// match timestamps and packet size
frame->pts = pkt.pts;
#if FF_API_PKT_PTS
FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = pkt.pts;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
frame->pkt_dts = pkt.dts;
frame->key_frame = p.p.type == DAV1D_FRAME_TYPE_KEY;
switch (p.p.type) {
case DAV1D_FRAME_TYPE_KEY:
case DAV1D_FRAME_TYPE_INTRA:
frame->pict_type = AV_PICTURE_TYPE_I;
break;
case DAV1D_FRAME_TYPE_INTER:
frame->pict_type = AV_PICTURE_TYPE_P;
break;
case DAV1D_FRAME_TYPE_SWITCH:
frame->pict_type = AV_PICTURE_TYPE_SP;
break;
default:
return AVERROR_INVALIDDATA;
}
return 0;
}
static av_cold int libdav1d_close(AVCodecContext *c)
{
Libdav1dContext *dav1d = c->priv_data;
av_fifo_free(dav1d->cache);
dav1d_data_unref(&dav1d->data);
dav1d_close(&dav1d->c);
return 0;
}
#define OFFSET(x) offsetof(Libdav1dContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption libdav1d_options[] = {
{ "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 64, VD, NULL },
{ NULL }
};
static const AVClass libdav1d_class = {
.class_name = "libdav1d decoder",
.item_name = av_default_item_name,
.option = libdav1d_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVCodec ff_libdav1d_decoder = {
.name = "libdav1d",
.long_name = NULL_IF_CONFIG_SMALL("dav1d AV1 decoder by VideoLAN"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_AV1,
.priv_data_size = sizeof(Libdav1dContext),
.init = libdav1d_init,
.close = libdav1d_close,
.flush = libdav1d_flush,
.receive_frame = libdav1d_receive_frame,
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP |
FF_CODEC_CAP_SETS_PKT_DTS,
.priv_class = &libdav1d_class,
.wrapper_name = "libdav1d",
};
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "libavutil/version.h" #include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 58 #define LIBAVCODEC_VERSION_MAJOR 58
#define LIBAVCODEC_VERSION_MINOR 11 #define LIBAVCODEC_VERSION_MINOR 12
#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment