avcodec: libdav1d AV1 decoder wrapper.

Originally written by Ronald S. Bultje, with fixes, optimizations and
improvements by James Almer.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer 2018-11-06 01:11:22 -03:00
parent f149a4a5fc
commit 9bf9358b61
7 changed files with 285 additions and 5 deletions

View File

@ -25,6 +25,7 @@ version <next>:
- Dropped support for building for Windows XP. The minimum supported Windows
version is Windows Vista.
- support mbedTLS-based TLS
- AV1 Support through libdav1d
version 12:

4
configure vendored
View File

@ -190,6 +190,7 @@ External library support:
--enable-libaom AV1 video encoding/decoding
--enable-libbs2b Bauer stereophonic-to-binaural DSP
--enable-libcdio audio CD input
--enable-libdav1d AV1 video decoding
--enable-libdc1394 IEEE 1394/Firewire camera input
--enable-libdcadec DCA audio decoding
--enable-libfaac AAC audio encoding
@ -1357,6 +1358,7 @@ EXTERNAL_LIBRARY_LIST="
gnutls
libaom
libbs2b
libdav1d
libdc1394
libdcadec
libfontconfig
@ -2372,6 +2374,7 @@ avisynth_demuxer_deps_any="avisynth avxsynth"
avisynth_demuxer_select="riffdec"
libaom_av1_decoder_deps="libaom"
libaom_av1_encoder_deps="libaom"
libdav1d_decoder_deps="libdav1d"
libdcadec_decoder_deps="libdcadec"
libfaac_encoder_deps="libfaac"
libfaac_encoder_select="audio_frame_queue"
@ -4673,6 +4676,7 @@ enabled libaom && {
}
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 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 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

View File

@ -18,12 +18,16 @@ explicitly requested by passing the appropriate flags to
@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
installing the library. Then pass @code{--enable-libaom} to configure to
installing libaom. Then pass @code{--enable-libaom} to configure to
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
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
@ -625,8 +629,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 AV1 @tab E @tab E
@tab Supported through external libraries libaom and libdav1d
@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

View File

@ -689,6 +689,7 @@ OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o
# external codec libraries
OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.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_LIBFAAC_ENCODER) += libfaac.o
OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o

View File

@ -422,6 +422,7 @@ void avcodec_register_all(void)
/* external libraries */
REGISTER_ENCDEC (LIBAOM_AV1, libaom_av1);
REGISTER_DECODER(LIBDAV1D, libdav1d)
REGISTER_DECODER(LIBDCADEC, libdcadec)
REGISTER_ENCODER(LIBFAAC, libfaac);
REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac);

269
libavcodec/libdav1d.c Normal file
View File

@ -0,0 +1,269 @@
/*
* 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",
};

View File

@ -28,7 +28,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 58
#define LIBAVCODEC_VERSION_MINOR 11
#define LIBAVCODEC_VERSION_MINOR 12
#define LIBAVCODEC_VERSION_MICRO 0
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \