ref: c7007c923a825f4d6b928e7afc24a6b1d6bcc98d
parent: 9ea56386dee2706d94f3c2dac1720bcf4961aaba
author: Michael Bradshaw <mjbshaw@google.com>
date: Thu Dec 13 11:57:49 EST 2018
Add a user data pointer to Dav1dDataProps
--- a/include/dav1d/common.h
+++ b/include/dav1d/common.h
@@ -44,6 +44,14 @@
#endif
/**
+ * A reference-counted object wrapper for a user-configurable pointer.
+ */
+typedef struct Dav1dUserData {
+ const uint8_t *data; ///< data pointer
+ struct Dav1dRef *ref; ///< allocation origin
+} Dav1dUserData;
+
+/**
* Input packet metadata which are copied from the input data used to
* decode each image into the matching structure of the output image
* returned back to the user. Since these are metadata fields, they
@@ -56,6 +64,7 @@
int64_t duration; ///< container duration of input data, 0 if unknown (default)
int64_t offset; ///< stream offset of input data, -1 if unknown (default)
size_t size; ///< packet size, default Dav1dData.sz
+ struct Dav1dUserData user_data; ///< user-configurable data, default NULL members
} Dav1dDataProps;
#endif // __DAV1D_COMMON_H__
--- a/include/dav1d/data.h
+++ b/include/dav1d/data.h
@@ -58,18 +58,49 @@
* @param sz Size of the data.
* @param free_callback Function to be called when we release our last
* reference to this data. In this callback, $buf will be
- * the $buf argument to this function, and $user_data
- * will be the $user_data input argument to this function.
- * @param user_data Opaque parameter passed to free_callback().
+ * the $buf argument to this function, and $cookie will
+ * be the $cookie input argument to this function.
+ * @param cookie Opaque parameter passed to free_callback().
*
* @return 0 on success. A negative errno value on error.
*/
DAV1D_API int dav1d_data_wrap(Dav1dData *data, const uint8_t *buf, size_t sz,
- void (*free_callback)(const uint8_t *buf, void *user_data),
- void *user_data);
+ void (*free_callback)(const uint8_t *buf, void *cookie),
+ void *cookie);
/**
+ * Wrap a user-provided data pointer into a reference counted object.
+ *
+ * data->m.user_data field will initialized to wrap the provided $user_data
+ * pointer.
+ *
+ * $free_callback will be called on the same thread that released the last
+ * reference. If frame threading is used, make sure $free_callback is
+ * thread-safe.
+ *
+ * @param data Input context.
+ * @param user_data The user data to be wrapped.
+ * @param free_callback Function to be called when we release our last
+ * reference to this data. In this callback, $user_data
+ * will be the $user_data argument to this function, and
+ * $cookie will be the $cookie input argument to this
+ * function.
+ * @param cookie Opaque parameter passed to $free_callback.
+ *
+ * @return 0 on success. A negative errno value on error.
+ */
+DAV1D_API int dav1d_data_wrap_user_data(Dav1dData *data,
+ const uint8_t *user_data,
+ void (*free_callback)(const uint8_t *user_data,
+ void *cookie),
+ void *cookie);
+
+/**
* Free the data reference.
+ *
+ * The reference count for data->m.user_data will be decremented (if it has been
+ * initialized with dav1d_data_wrap_user_data). The $data object will be memset
+ * to 0.
*
* @param data Input context.
*/
--- a/src/data.c
+++ b/src/data.c
@@ -27,6 +27,7 @@
#include "config.h"
+#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
@@ -49,6 +50,8 @@
buf->m.timestamp = INT64_MIN;
buf->m.duration = 0;
buf->m.offset = -1;
+ buf->m.user_data.data = NULL;
+ buf->m.user_data.ref = NULL;
return buf->ref->data;
}
@@ -56,14 +59,14 @@
int dav1d_data_wrap_internal(Dav1dData *const buf, const uint8_t *const ptr,
const size_t sz,
void (*const free_callback)(const uint8_t *data,
- void *user_data),
- void *const user_data)
+ void *cookie),
+ void *const cookie)
{
validate_input_or_ret(buf != NULL, -EINVAL);
validate_input_or_ret(ptr != NULL, -EINVAL);
validate_input_or_ret(free_callback != NULL, -EINVAL);
- buf->ref = dav1d_ref_wrap(ptr, free_callback, user_data);
+ buf->ref = dav1d_ref_wrap(ptr, free_callback, cookie);
if (!buf->ref) return -ENOMEM;
buf->data = ptr;
buf->sz = buf->m.size = sz;
@@ -70,10 +73,28 @@
buf->m.timestamp = INT64_MIN;
buf->m.duration = 0;
buf->m.offset = -1;
+ buf->m.user_data.data = NULL;
+ buf->m.user_data.ref = NULL;
return 0;
}
+int dav1d_data_wrap_user_data_internal(Dav1dData *const buf,
+ const uint8_t *const user_data,
+ void (*const free_callback)(const uint8_t *user_data,
+ void *cookie),
+ void *const cookie)
+{
+ validate_input_or_ret(buf != NULL, -EINVAL);
+ validate_input_or_ret(free_callback != NULL, -EINVAL);
+
+ buf->m.user_data.ref = dav1d_ref_wrap(user_data, free_callback, cookie);
+ if (!buf->m.user_data.ref) return -ENOMEM;
+ buf->m.user_data.data = user_data;
+
+ return 0;
+}
+
void dav1d_data_move_ref(Dav1dData *const dst, Dav1dData *const src) {
validate_input(dst != NULL);
validate_input(dst->data == NULL);
@@ -86,12 +107,24 @@
memset(src, 0, sizeof(*src));
}
+void dav1d_data_props_copy(Dav1dDataProps *const dst,
+ const Dav1dDataProps *const src)
+{
+ assert(dst != NULL);
+ assert(src != NULL);
+
+ *dst = *src;
+ if (dst->user_data.ref) dav1d_ref_inc(dst->user_data.ref);
+}
+
void dav1d_data_unref_internal(Dav1dData *const buf) {
validate_input(buf != NULL);
+ struct Dav1dRef *user_data_ref = buf->m.user_data.ref;
if (buf->ref) {
validate_input(buf->data != NULL);
dav1d_ref_dec(&buf->ref);
}
memset(buf, 0, sizeof(*buf));
+ dav1d_ref_dec(&user_data_ref);
}
--- a/src/data.h
+++ b/src/data.h
@@ -35,11 +35,22 @@
*/
void dav1d_data_move_ref(Dav1dData *dst, Dav1dData *src);
+/**
+ * Copy the source properties to the destitionatin and increase the
+ * user_data's reference count (if it's not NULL).
+ */
+void dav1d_data_props_copy(Dav1dDataProps *dst, const Dav1dDataProps *src);
+
uint8_t *dav1d_data_create_internal(Dav1dData *buf, size_t sz);
int dav1d_data_wrap_internal(Dav1dData *buf, const uint8_t *ptr, size_t sz,
void (*free_callback)(const uint8_t *data,
void *user_data),
void *user_data);
+int dav1d_data_wrap_user_data_internal(Dav1dData *buf,
+ const uint8_t *user_data,
+ void (*free_callback)(const uint8_t *user_data,
+ void *cookie),
+ void *cookie);
void dav1d_data_unref_internal(Dav1dData *buf);
#endif /* __DAV1D_SRC_DATA_H__ */
--- a/src/decode.c
+++ b/src/decode.c
@@ -3185,7 +3185,7 @@
f->frame_hdr->show_frame, &c->allocator);
if (res < 0) goto error;
- f->sr_cur.p.m = f->tile[0].data.m;
+ dav1d_data_props_copy(&f->sr_cur.p.m, &f->tile[0].data.m);
f->sr_cur.p.frame_hdr = f->frame_hdr;
f->sr_cur.p.frame_hdr_ref = f->frame_hdr_ref;
dav1d_ref_inc(f->frame_hdr_ref);
--- a/src/lib.c
+++ b/src/lib.c
@@ -521,6 +521,18 @@
return dav1d_data_wrap_internal(buf, ptr, sz, free_callback, user_data);
}
+int dav1d_data_wrap_user_data(Dav1dData *const buf,
+ const uint8_t *const user_data,
+ void (*const free_callback)(const uint8_t *user_data,
+ void *cookie),
+ void *const cookie)
+{
+ return dav1d_data_wrap_user_data_internal(buf,
+ user_data,
+ free_callback,
+ cookie);
+}
+
void dav1d_data_unref(Dav1dData *const buf) {
dav1d_data_unref_internal(buf);
}
--- a/src/obu.c
+++ b/src/obu.c
@@ -1325,7 +1325,7 @@
assert(pkt_bytelen >= (bit_pos >> 3));
dav1d_ref_inc(in->ref);
c->tile[c->n_tile_data].data.ref = in->ref;
- c->tile[c->n_tile_data].data.m = in->m;
+ dav1d_data_props_copy(&c->tile[c->n_tile_data].data.m, &in->m);
c->tile[c->n_tile_data].data.data = in->data + (bit_pos >> 3);
c->tile[c->n_tile_data].data.sz = pkt_bytelen - (bit_pos >> 3);
// ensure tile groups are in order and sane, see 6.10.1
@@ -1359,7 +1359,7 @@
if (c->n_fc == 1) {
dav1d_picture_ref(&c->out,
&c->refs[c->frame_hdr->existing_frame_idx].p.p);
- c->out.m = in->m;
+ dav1d_data_props_copy(&c->out.m, &in->m);
} else {
// need to append this to the frame output queue
const unsigned next = c->frame_thread.next++;
@@ -1383,7 +1383,7 @@
dav1d_thread_picture_ref(out_delayed,
&c->refs[c->frame_hdr->existing_frame_idx].p);
out_delayed->visible = 1;
- out_delayed->p.m = in->m;
+ dav1d_data_props_copy(&out_delayed->p.m, &in->m);
pthread_mutex_unlock(&f->frame_thread.td.lock);
}
if (c->refs[c->frame_hdr->existing_frame_idx].p.p.frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY) {
--- a/src/picture.c
+++ b/src/picture.c
@@ -92,8 +92,10 @@
static void free_buffer(const uint8_t *const data, void *const user_data) {
struct pic_ctx_context *pic_ctx = user_data;
+ struct Dav1dRef *user_data_ref = pic_ctx->pic.m.user_data.ref;
pic_ctx->allocator.release_picture_callback(&pic_ctx->pic,
pic_ctx->allocator.cookie);
+ if (user_data_ref) dav1d_ref_dec(&user_data_ref);
free(pic_ctx);
}
@@ -120,6 +122,8 @@
p->m.timestamp = INT64_MIN;
p->m.duration = 0;
p->m.offset = -1;
+ p->m.user_data.data = NULL;
+ p->m.user_data.ref = NULL;
p->p.layout = layout;
p->p.bpc = bpc;
int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);
@@ -176,7 +180,7 @@
if (!res) {
dst->p = src->p;
- dst->m = src->m;
+ dav1d_data_props_copy(&dst->m, &src->m);
dst->p.w = w;
dst->frame_hdr = src->frame_hdr;
dst->frame_hdr_ref = src->frame_hdr_ref;