Skip to content

Instantly share code, notes, and snippets.

@WyohKnott
Created October 9, 2018 13:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WyohKnott/09e84e4fc9f67fc1b8190a9855119ba9 to your computer and use it in GitHub Desktop.
Save WyohKnott/09e84e4fc9f67fc1b8190a9855119ba9 to your computer and use it in GitHub Desktop.
dav1d patch for FFMPEG
From 3cdb0dc45c322d108ac15f59df915313ba6865e9 Mon Sep 17 00:00:00 2001
From: "Ronald S. Bultje" <rsbultje@gmail.com>
Date: Mon, 21 May 2018 17:46:48 -0400
Subject: [PATCH] libdav1d-based AV1 decoder.
---
configure | 4 +
libavcodec/Makefile | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/libdav1d_dec.c | 180 ++++++++++++++++++++++++++++++++++++++
4 files changed, 186 insertions(+)
create mode 100644 libavcodec/libdav1d_dec.c
diff --git a/configure b/configure
index 0d6ee0abfc..3a19f743ac 100755
--- a/configure
+++ b/configure
@@ -226,6 +226,7 @@ External library support:
--enable-libcelt enable CELT decoding via libcelt [no]
--enable-libcdio enable audio CD grabbing with libcdio [no]
--enable-libcodec2 enable codec2 en/decoding using libcodec2 [no]
+ --enable-libdav1d enable AV1 decoding via libdav1d [no]
--enable-libdavs2 enable AVS2 decoding via libdavs2 [no]
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394
and libraw1394 [no]
@@ -1709,6 +1710,7 @@ EXTERNAL_LIBRARY_LIST="
libcaca
libcelt
libcodec2
+ libdav1d
libdc1394
libdrm
libflite
@@ -3077,6 +3079,7 @@ libaom_av1_encoder_select="extract_extradata_bsf"
libcelt_decoder_deps="libcelt"
libcodec2_decoder_deps="libcodec2"
libcodec2_encoder_deps="libcodec2"
+libdav1d_decoder_deps="libdav1d"
libdavs2_decoder_deps="libdavs2"
libfdk_aac_decoder_deps="libfdk_aac"
libfdk_aac_encoder_deps="libfdk_aac"
@@ -6050,6 +6053,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 &&
die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas
enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2
+enabled libdav1d && require_pkg_config libdav1d dav1d dav1d/dav1d.h dav1d_version
enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.5.115" davs2.h davs2_decoder_open
enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f8673f0121..b238071202 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -950,6 +950,7 @@ OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o
OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o
OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o codec2utils.o
OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o codec2utils.o
+OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d_dec.o
OBJS-$(CONFIG_LIBDAVS2_DECODER) += libdavs2.o
OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o
OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index a461131c78..31f43f2ee2 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -672,6 +672,7 @@ extern AVCodec ff_libaom_av1_encoder;
extern AVCodec ff_libcelt_decoder;
extern AVCodec ff_libcodec2_encoder;
extern AVCodec ff_libcodec2_decoder;
+extern AVCodec ff_libdav1d_decoder;
extern AVCodec ff_libdavs2_decoder;
extern AVCodec ff_libfdk_aac_encoder;
extern AVCodec ff_libfdk_aac_decoder;
diff --git a/libavcodec/libdav1d_dec.c b/libavcodec/libdav1d_dec.c
new file mode 100644
index 0000000000..c3bf0ada08
--- /dev/null
+++ b/libavcodec/libdav1d_dec.c
@@ -0,0 +1,179 @@
+#include "libavutil/opt.h"
+#include "dav1d/dav1d.h"
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct Libdav1dContext {
+ AVClass *class;
+ Dav1dContext *c;
+
+ int frame_threads, tile_threads;
+ struct {
+ uint64_t pos, pts, dts;
+ unsigned flags, size;
+ int64_t reordered_opaque;
+ } *cache;
+ int cache_size, cache_fill;
+} Libdav1dContext;
+
+static av_cold int libdav1d_dec_init(AVCodecContext *c)
+{
+ Libdav1dContext *dav1d = c->priv_data;
+ Dav1dSettings s;
+ int res;
+
+ dav1d_default_settings(&s);
+ s.n_tile_threads = dav1d->tile_threads;
+ s.n_frame_threads = dav1d->frame_threads;
+ if ((res = dav1d_open(&dav1d->c, &s)) < 0)
+ return res;
+ dav1d->cache = NULL;
+ dav1d->cache_size = dav1d->cache_fill = 0;
+ c->has_b_frames = 1;
+
+ return 0;
+}
+
+static av_cold int libdav1d_dec_close(AVCodecContext *c)
+{
+ Libdav1dContext *dav1d = c->priv_data;
+
+ dav1d_close(&dav1d->c);
+ dav1d->c = NULL;
+ av_freep(&dav1d->cache);
+ dav1d->cache_fill = dav1d->cache_size = 0;
+
+ return 0;
+}
+
+static av_cold void libdav1d_flush(AVCodecContext *c)
+{
+ Libdav1dContext *dav1d = c->priv_data;
+ dav1d_flush(dav1d->c);
+ dav1d->cache_fill = 0;
+}
+
+static void libdav1d_ref_free_wrapper(void *opaque, uint8_t *data) {
+ Dav1dPicture p;
+ memset(&p, 0, sizeof(p));
+ p.ref = opaque;
+ p.data[0] = (void *) 0x1; // this has to be non-NULL
+ dav1d_picture_unref(&p);
+}
+
+static int libdav1d_dec_decode(AVCodecContext *c, void *frame,
+ int *got_frame_ptr, AVPacket *pkt)
+{
+ Libdav1dContext *dav1d = c->priv_data;
+ Dav1dData *data_ptr, data_mem;
+ Dav1dPicture p;
+ int res;
+
+ if (pkt) {
+ if (dav1d->cache_size == dav1d->cache_fill) {
+ dav1d->cache_size += 8;
+ dav1d->cache = realloc(dav1d->cache, sizeof(*dav1d->cache) * dav1d->cache_size);
+ }
+ dav1d->cache[dav1d->cache_fill].pos = pkt->pos;
+ dav1d->cache[dav1d->cache_fill].pts = pkt->pts;
+ dav1d->cache[dav1d->cache_fill].dts = pkt->dts;
+ dav1d->cache[dav1d->cache_fill].size = pkt->size;
+ dav1d->cache[dav1d->cache_fill].flags = pkt->flags;
+ dav1d->cache[dav1d->cache_fill].reordered_opaque = c->reordered_opaque;
+ dav1d->cache_fill++;
+ data_ptr = &data_mem;
+ dav1d_data_create(data_ptr, pkt->size);
+ memcpy(data_ptr->data, pkt->data, pkt->size);
+ } else {
+ data_ptr = NULL;
+ }
+
+ memset(&p, 0, sizeof(p));
+ if ((res = dav1d_decode(dav1d->c, data_ptr, &p)) < 0)
+ if (res != -EAGAIN)
+ return res;
+
+ if (!res) {
+ assert(p.data[0] != NULL);
+ static const enum AVPixelFormat pix_fmt[][2] = {
+ [DAV1D_PIXEL_LAYOUT_I400] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16 },
+ [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 },
+ };
+ AVFrame *f = av_frame_alloc();
+ f->format = c->pix_fmt = pix_fmt[p.p.layout][p.p.bpc == 10];
+ f->width = c->width = p.p.w;
+ f->height = c->height = p.p.h;
+ f->data[0] = p.data[0];
+ f->data[1] = p.data[1];
+ f->data[2] = p.data[2];
+ f->linesize[0] = p.stride[0];
+ f->linesize[1] = p.stride[1];
+ f->linesize[2] = p.stride[1];
+ f->color_primaries = p.p.pri;
+ f->color_trc = p.p.trc;
+ f->chroma_location = p.p.chr;
+ f->colorspace = p.p.mtrx;
+ f->color_range = p.p.fullrange ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
+ AVBufferRef *ref =
+ av_buffer_create(NULL, 0,
+ libdav1d_ref_free_wrapper,
+ p.ref, AV_BUFFER_FLAG_READONLY);
+ f->buf[0] = av_buffer_ref(ref);
+ f->buf[1] = av_buffer_ref(ref);
+ f->buf[2] = av_buffer_ref(ref);
+
+ av_buffer_unref(&ref);
+ *got_frame_ptr = 1;
+
+ // match timestamps and packet size
+ f->reordered_opaque = dav1d->cache[0].reordered_opaque;
+ f->pkt_pos = dav1d->cache[0].pos;
+ f->pkt_pts = f->best_effort_timestamp = dav1d->cache[0].pts;
+ f->pkt_dts = dav1d->cache[0].dts;
+ f->pkt_size = dav1d->cache[0].size;
+ f->key_frame = !!(dav1d->cache[0].flags & AV_PKT_FLAG_KEY);
+ if (--dav1d->cache_fill)
+ memcpy(dav1d->cache, &dav1d->cache[1],
+ sizeof(*dav1d->cache) * dav1d->cache_fill);
+ f->pict_type = f->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ av_frame_move_ref(frame, f);
+ } else {
+ *got_frame_ptr = 0;
+ }
+
+ return pkt->size;
+}
+
+#define OFFSET(x) offsetof(Libdav1dContext, x)
+#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption av1_options[] = {
+ { "framethreads", "Frame threads", OFFSET(frame_threads),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, VD, NULL },
+ { "tilethreads", "Tile threads", OFFSET(tile_threads),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 64, VD, NULL },
+ { NULL }
+};
+
+static const AVClass av1_class = {
+ .class_name = "av1",
+ .item_name = av_default_item_name,
+ .option = av1_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_dec_init,
+ .close = libdav1d_dec_close,
+ .flush = libdav1d_flush,
+ .decode = libdav1d_dec_decode,
+ .capabilities = AV_CODEC_CAP_DELAY | FF_CODEC_CAP_SETS_PKT_DTS |
+ AV_CODEC_CAP_AUTO_THREADS,
+ .priv_class = &av1_class,
+};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment