ref: 1c42f8bf81d8fc1ac2d7a89dd00337fd70c5ae80
parent: 793c50481b0fa407f5b0bd6eda8599c6c3249563
author: Steve Lhomme <robux4@ycbcr.xyz>
date: Fri Oct 19 13:34:41 EDT 2018
Add support for external picture buffer allocation
--- a/include/dav1d/dav1d.h
+++ b/include/dav1d/dav1d.h
@@ -38,6 +38,7 @@
typedef struct Dav1dSettings {
int n_frame_threads;
int n_tile_threads;
+ Dav1dPicAllocator allocator;
} Dav1dSettings;
/**
--- a/include/dav1d/picture.h
+++ b/include/dav1d/picture.h
@@ -143,7 +143,42 @@
Dav1dPictureParameters p;
int poc; ///< frame number
+
+ void *allocator_data; ///< pointer managed by the allocator
} Dav1dPicture;
+
+typedef struct Dav1dPicAllocator {
+ void *cookie; ///< custom data to pass to the allocator callbacks.
+ /**
+ * Allocate the picture buffer based on the Dav1dPictureParameters.
+ *
+ * The data[0], data[1] and data[2] must be 32 bits aligned and with a
+ * pixel width/height multiple of 128 pixels.
+ * data[1] and data[2] must share the same stride[1].
+ *
+ * @param pic The picture to allocate the buffer for. The callback needs to
+ * fill the picture data[0], data[1], data[2], stride[0] and
+ * stride[1].
+ * The allocator can fill the pic allocator_data pointer with
+ * a custom pointer that will be passed to
+ * release_picture_callback().
+ * @param cookie Custom pointer passed to all calls.
+ *
+ * @return 0 on success. A negative errno value on error.
+ */
+ int (*alloc_picture_callback)(Dav1dPicture *pic, void *cookie);
+ /**
+ * Release the picture buffer.
+ *
+ * @param buf The buffer that was returned by
+ * alloc_picture_callback().
+ * @param allocator_tag The Dav1dPicture.allocator_data that was filled by
+ * alloc_picture_callback()
+ * @param cookie Custom pointer passed to all calls.
+ */
+ void (*release_picture_callback)(uint8_t *buf, void *allocator_data,
+ void *cookie);
+} Dav1dPicAllocator;
/**
* Release reference to a picture.
--- a/src/data.c
+++ b/src/data.c
@@ -56,7 +56,7 @@
validate_input_or_ret(ptr != NULL, -EINVAL);
validate_input_or_ret(free_callback != NULL, -EINVAL);
- buf->ref = dav1d_ref_wrap(ptr, sz, free_callback, user_data);
+ buf->ref = dav1d_ref_wrap(ptr, free_callback, user_data);
if (!buf->ref) return -ENOMEM;
buf->data = ptr;
buf->sz = sz;
--- a/src/decode.c
+++ b/src/decode.c
@@ -2891,7 +2891,8 @@
f->frame_hdr.height,
f->seq_hdr.layout, f->seq_hdr.bpc,
c->n_fc > 1 ? &f->frame_thread.td : NULL,
- f->frame_hdr.show_frame)) < 0)
+ f->frame_hdr.show_frame,
+ &c->allocator)) < 0)
{
if (f->frame_hdr.refresh_context)
dav1d_cdf_thread_unref(&f->out_cdf);
--- a/src/internal.h
+++ b/src/internal.h
@@ -110,6 +110,8 @@
EdgeTip tip_sb128[256];
EdgeTip tip_sb64[64];
} intra_edge;
+
+ Dav1dPicAllocator allocator;
};
struct Dav1dFrameContext {
--- a/src/lib.c
+++ b/src/lib.c
@@ -57,6 +57,9 @@
void dav1d_default_settings(Dav1dSettings *const s) {
s->n_frame_threads = 1;
s->n_tile_threads = 1;
+ s->allocator.cookie = NULL;
+ s->allocator.alloc_picture_callback = default_picture_allocator;
+ s->allocator.release_picture_callback = default_picture_release;
}
int dav1d_open(Dav1dContext **const c_out,
@@ -71,11 +74,16 @@
s->n_tile_threads <= 64, -EINVAL);
validate_input_or_ret(s->n_frame_threads >= 1 &&
s->n_frame_threads <= 256, -EINVAL);
+ validate_input_or_ret(s->allocator.alloc_picture_callback != NULL,
+ -EINVAL);
+ validate_input_or_ret(s->allocator.release_picture_callback != NULL,
+ -EINVAL);
Dav1dContext *const c = *c_out = dav1d_alloc_aligned(sizeof(*c), 32);
if (!c) goto error;
memset(c, 0, sizeof(*c));
+ c->allocator = s->allocator;
c->n_fc = s->n_frame_threads;
c->fc = dav1d_alloc_aligned(sizeof(*c->fc) * s->n_frame_threads, 32);
if (!c->fc) goto error;
--- a/src/picture.c
+++ b/src/picture.c
@@ -41,14 +41,71 @@
#include "src/ref.h"
#include "src/thread.h"
+int default_picture_allocator(Dav1dPicture *const p, void *cookie) {
+ assert(cookie == NULL);
+ const int hbd = p->p.bpc > 8;
+ const int aligned_w = (p->p.w + 127) & ~127;
+ const int aligned_h = (p->p.h + 127) & ~127;
+ const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
+ const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
+ const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
+ p->stride[0] = aligned_w << hbd;
+ p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0;
+ const size_t y_sz = p->stride[0] * aligned_h;
+ const size_t uv_sz = p->stride[1] * (aligned_h >> ss_ver);
+ const size_t pic_size = y_sz + 2 * uv_sz;
+
+ uint8_t *data = dav1d_alloc_aligned(pic_size, 32);
+ if (data == NULL) {
+ fprintf(stderr, "Failed to allocate memory of size %zu: %s\n",
+ pic_size, strerror(errno));
+ return -1;
+ }
+
+ p->data[0] = data;
+ p->data[1] = has_chroma ? data + y_sz : NULL;
+ p->data[2] = has_chroma ? data + y_sz + uv_sz : NULL;
+
+#ifndef NDEBUG /* safety check */
+ p->allocator_data = data;
+#endif
+
+ return 0;
+}
+
+void default_picture_release(uint8_t *const data, void *const allocator_data,
+ void *cookie)
+{
+ assert(cookie == NULL);
+#ifndef NDEBUG /* safety check */
+ assert(allocator_data == data);
+#endif
+ dav1d_free_aligned(data);
+}
+
+struct pic_ctx_context {
+ Dav1dPicAllocator allocator;
+ void *allocator_data;
+ void *extra_ptr; /* MUST BE AT THE END */
+};
+
+static void free_buffer(uint8_t *data, void *user_data)
+{
+ struct pic_ctx_context *pic_ctx = user_data;
+
+ pic_ctx->allocator.release_picture_callback(data,
+ pic_ctx->allocator_data,
+ pic_ctx->allocator.cookie);
+ free(pic_ctx);
+}
+
static int picture_alloc_with_edges(Dav1dPicture *const p,
const int w, const int h,
const enum Dav1dPixelLayout layout,
const int bpc,
- const int extra, void **const extra_ptr)
+ Dav1dPicAllocator *const p_allocator,
+ const size_t extra, void **const extra_ptr)
{
- int aligned_h;
-
if (p->data[0]) {
fprintf(stderr, "Picture already allocated!\n");
return -1;
@@ -55,13 +112,11 @@
}
assert(bpc > 0 && bpc <= 16);
- const int hbd = bpc > 8;
- const int aligned_w = (w + 127) & ~127;
- const int has_chroma = layout != DAV1D_PIXEL_LAYOUT_I400;
- const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
- const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
- p->stride[0] = aligned_w << hbd;
- p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0;
+ struct pic_ctx_context *pic_ctx = malloc(extra + sizeof(struct pic_ctx_context));
+ if (pic_ctx == NULL) {
+ return -ENOMEM;
+ }
+
p->p.w = w;
p->p.h = h;
p->p.pri = DAV1D_COLOR_PRI_UNKNOWN;
@@ -68,24 +123,27 @@
p->p.trc = DAV1D_TRC_UNKNOWN;
p->p.mtrx = DAV1D_MC_UNKNOWN;
p->p.chr = DAV1D_CHR_UNKNOWN;
- aligned_h = (h + 127) & ~127;
p->p.layout = layout;
p->p.bpc = bpc;
- const size_t y_sz = p->stride[0] * aligned_h;
- const size_t uv_sz = p->stride[1] * (aligned_h >> ss_ver);
- if (!(p->ref = dav1d_ref_create(y_sz + 2 * uv_sz + extra))) {
- fprintf(stderr, "Failed to allocate memory of size %zu: %s\n",
- y_sz + 2 * uv_sz + extra, strerror(errno));
+ int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);
+ if (res < 0) {
+ free(pic_ctx);
return -ENOMEM;
}
- uint8_t *data = p->ref->data;
- p->data[0] = data;
- p->data[1] = has_chroma ? data + y_sz : NULL;
- p->data[2] = has_chroma ? data + y_sz + uv_sz : NULL;
- if (extra)
- *extra_ptr = &data[y_sz + uv_sz * 2];
+ pic_ctx->allocator = *p_allocator;
+ pic_ctx->allocator_data = p->allocator_data;
+ if (!(p->ref = dav1d_ref_wrap(p->data[0], free_buffer, pic_ctx))) {
+ p_allocator->release_picture_callback(p->data[0], p->allocator_data,
+ p_allocator->cookie);
+ fprintf(stderr, "Failed to wrap picture: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ if (extra && extra_ptr)
+ *extra_ptr = &pic_ctx->extra_ptr;
+
return 0;
}
@@ -92,12 +150,13 @@
int dav1d_thread_picture_alloc(Dav1dThreadPicture *const p,
const int w, const int h,
const enum Dav1dPixelLayout layout, const int bpc,
- struct thread_data *const t, const int visible)
+ struct thread_data *const t, const int visible,
+ Dav1dPicAllocator *const p_allocator)
{
p->t = t;
const int res =
- picture_alloc_with_edges(&p->p, w, h, layout, bpc,
+ picture_alloc_with_edges(&p->p, w, h, layout, bpc, p_allocator,
t != NULL ? sizeof(atomic_int) * 2 : 0,
(void **) &p->progress);
--- a/src/picture.h
+++ b/src/picture.h
@@ -56,7 +56,8 @@
*/
int dav1d_thread_picture_alloc(Dav1dThreadPicture *p, int w, int h,
enum Dav1dPixelLayout layout, int bpc,
- struct thread_data *t, int visible);
+ struct thread_data *t, int visible,
+ Dav1dPicAllocator *);
/**
* Create a copy of a picture.
@@ -87,5 +88,8 @@
*/
void dav1d_thread_picture_signal(const Dav1dThreadPicture *p, int y,
enum PlaneType plane_type);
+
+int default_picture_allocator(Dav1dPicture *, void *cookie);
+void default_picture_release(uint8_t *, void *allocator_data, void *cookie);
#endif /* __DAV1D_SRC_PICTURE_H__ */
--- a/src/ref.c
+++ b/src/ref.c
@@ -36,24 +36,21 @@
}
Dav1dRef *dav1d_ref_create(const size_t size) {
- Dav1dRef *res = malloc(sizeof(Dav1dRef));
+ Dav1dRef *res;
void *data = dav1d_alloc_aligned(size, 32);
-
- if (!res || !data) {
- if (res) free(res);
- if (data) free(data);
+ if (!data) {
return NULL;
}
- res->size = size;
- atomic_init(&res->ref_cnt, 1);
- res->data = data;
- res->free_callback = default_free_callback;
+ res = dav1d_ref_wrap(data, default_free_callback, NULL);
+ if (!res) {
+ free(data);
+ }
return res;
}
-Dav1dRef *dav1d_ref_wrap(uint8_t *const ptr, const size_t sz,
+Dav1dRef *dav1d_ref_wrap(uint8_t *const ptr,
void (*free_callback)(uint8_t *data, void *user_data),
void *user_data)
{
@@ -61,7 +58,6 @@
if (!res) return NULL;
res->data = ptr;
- res->size = sz;
atomic_init(&res->ref_cnt, 1);
res->free_callback = free_callback;
res->user_data = user_data;
--- a/src/ref.h
+++ b/src/ref.h
@@ -35,7 +35,6 @@
struct Dav1dRef {
void *data;
- size_t size;
atomic_int ref_cnt;
void (*free_callback)(uint8_t *data, void *user_data);
void *user_data;
@@ -42,7 +41,7 @@
};
Dav1dRef *dav1d_ref_create(size_t size);
-Dav1dRef *dav1d_ref_wrap(uint8_t *ptr, size_t sz,
+Dav1dRef *dav1d_ref_wrap(uint8_t *ptr,
void (*free_callback)(uint8_t *data, void *user_data),
void *user_data);
void dav1d_ref_inc(Dav1dRef *ref);