shithub: dav1d

Download patch

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;