shithub: dav1d

Download patch

ref: 026069693ef5511368e105cc177f72c917e0f3a9
parent: ec53ec6d5b4ebbb06d5c7209fd4f25634a6ad606
author: James Almer <jamrial@gmail.com>
date: Thu Nov 8 09:32:31 EST 2018

implement a decoupled decode API

--- a/include/dav1d/dav1d.h
+++ b/include/dav1d/dav1d.h
@@ -62,8 +62,8 @@
 /**
  * Allocate and open a decoder instance.
  *
- * @param c_out The decoder instance to open. To be used in iterative calls to
- *              dav1d_decode(). *c_out will be set to the allocated context.
+ * @param c_out The decoder instance to open. *c_out will be set to the
+ *              allocated context.
  * @param     s Input settings context.
  *
  * @note The context must be freed using dav1d_close() when decoding is
@@ -74,25 +74,40 @@
 DAV1D_API int dav1d_open(Dav1dContext **c_out, const Dav1dSettings *s);
 
 /**
- * Decode one frame.
+ * Feed bitstream data to the decoder.
  *
  * @param   c Input decoder instance.
- * @param  in Input bitstream data. On success, the caller retains ownership of
- *            the input reference if the data was not fully consumed.
+ * @param  in Input bitstream data. On success, ownership of the reference is
+ *            passed to the library.
+ *
+ * @return
+ *         0: Success, and the data was consumed.
+ *   -EAGAIN: The data can't be consumed. dav1d_get_picture() should be called
+ *            to get one or more frames before the function can consume new
+ *            data.
+ *   other negative errno codes: Error during decoding or because of invalid
+ *                               passed-in arguments.
+ */
+DAV1D_API int dav1d_send_data(Dav1dContext *c, Dav1dData *in);
+
+/**
+ * Return a decoded picture.
+ *
+ * @param   c Input decoder instance.
  * @param out Output frame. The caller assumes ownership of the returned
  *            reference.
  *
  * @return
  *         0: Success, and a frame is returned.
- *   -EAGAIN: Not enough data to output a frame. The fuction should be called
- *            again with new input.
+ *   -EAGAIN: Not enough data to output a frame. dav1d_send_data() should be
+ *            called with new input.
  *   other negative errno codes: Error during decoding or because of invalid
  *                               passed-in arguments.
  *
- * @note To flush the decoder (i.e. all input is finished), feed it NULL input
- *       data until it returns -EAGAIN.
+ * @note To drain buffered frames from the decoder (i.e. on end of stream),
+ *       call this function until it returns -EAGAIN.
  */
-DAV1D_API int dav1d_decode(Dav1dContext *c, Dav1dData *in, Dav1dPicture *out);
+DAV1D_API int dav1d_get_picture(Dav1dContext *c, Dav1dPicture *out);
 
 /**
  * Close a decoder instance and free all associated memory.
--- a/src/data.c
+++ b/src/data.c
@@ -35,6 +35,7 @@
 
 #include "common/validate.h"
 
+#include "src/data.h"
 #include "src/ref.h"
 
 uint8_t * dav1d_data_create(Dav1dData *const buf, const size_t sz) {
@@ -62,6 +63,18 @@
     buf->sz = sz;
 
     return 0;
+}
+
+void dav1d_data_move_ref(Dav1dData *const dst, Dav1dData *const src) {
+    validate_input(dst != NULL);
+    validate_input(dst->data == NULL);
+    validate_input(src != NULL);
+
+    if (src->ref)
+        validate_input(src->data != NULL);
+
+    *dst = *src;
+    memset(src, 0, sizeof(*src));
 }
 
 void dav1d_data_unref(Dav1dData *const buf) {
--- /dev/null
+++ b/src/data.h
@@ -1,0 +1,38 @@
+/*
+ * Copyright © 2018, VideoLAN and dav1d authors
+ * Copyright © 2018, Two Orioles, LLC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DAV1D_SRC_DATA_H__
+#define __DAV1D_SRC_DATA_H__
+
+#include "dav1d/data.h"
+
+/**
+ * Move a data reference.
+ */
+void dav1d_data_move_ref(Dav1dData *dst, Dav1dData *src);
+
+#endif /* __DAV1D_SRC_DATA_H__ */
--- a/src/internal.h
+++ b/src/internal.h
@@ -40,6 +40,7 @@
 
 #include "src/cdef.h"
 #include "src/cdf.h"
+#include "src/data.h"
 #include "src/env.h"
 #include "src/intra_edge.h"
 #include "src/ipred.h"
@@ -80,6 +81,7 @@
     Av1FrameHeader frame_hdr; // FIXME make ref?
 
     // decoded output picture queue
+    Dav1dData in;
     Dav1dPicture out;
     struct {
         Dav1dThreadPicture *out_delayed;
--- a/src/lib.c
+++ b/src/lib.c
@@ -157,15 +157,28 @@
     return -ENOMEM;
 }
 
-int dav1d_decode(Dav1dContext *const c,
-                 Dav1dData *const in, Dav1dPicture *const out)
+int dav1d_send_data(Dav1dContext *const c, Dav1dData *const in)
 {
+    validate_input_or_ret(c != NULL, -EINVAL);
+    validate_input_or_ret(in != NULL, -EINVAL);
+    validate_input_or_ret(in->data == NULL || in->sz, -EINVAL);
+
+    if (c->in.data)
+        return -EAGAIN;
+    dav1d_data_move_ref(&c->in, in);
+
+    return 0;
+}
+
+int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
+{
     int res;
 
     validate_input_or_ret(c != NULL, -EINVAL);
     validate_input_or_ret(out != NULL, -EINVAL);
 
-    if (!in) {
+    Dav1dData *const in = &c->in;
+    if (!in->data) {
         if (c->n_fc == 1) return -EAGAIN;
 
         // flush
@@ -198,8 +211,10 @@
     }
 
     while (in->sz > 0) {
-        if ((res = dav1d_parse_obus(c, in)) < 0)
+        if ((res = dav1d_parse_obus(c, in)) < 0) {
+            dav1d_data_unref(in);
             return res;
+        }
 
         assert((size_t)res <= in->sz);
         in->sz -= res;
@@ -220,6 +235,8 @@
 }
 
 void dav1d_flush(Dav1dContext *const c) {
+    dav1d_data_unref(&c->in);
+
     if (c->n_fc == 1) return;
 
     for (unsigned n = 0; n < c->n_fc; n++)
@@ -298,6 +315,7 @@
         dav1d_free_aligned(f->lf.lr_lpf_line);
     }
     dav1d_free_aligned(c->fc);
+    dav1d_data_unref(&c->in);
     if (c->n_fc > 1) {
         for (unsigned n = 0; n < c->n_fc; n++)
             if (c->frame_thread.out_delayed[n].p.data[0])
--- a/tests/libfuzzer/dav1d_fuzzer.c
+++ b/tests/libfuzzer/dav1d_fuzzer.c
@@ -97,8 +97,12 @@
         ptr += frame_size;
 
         do {
+            if ((err = dav1d_send_data(ctx, &buf)) < 0) {
+                if (err != -EAGAIN)
+                    break;
+            }
             memset(&pic, 0, sizeof(pic));
-            err = dav1d_decode(ctx, &buf, &pic);
+            err = dav1d_get_picture(ctx, &pic);
             if (err == 0) {
                 dav1d_picture_unref(&pic);
             } else if (err != -EAGAIN) {
@@ -112,7 +116,7 @@
 
     do {
         memset(&pic, 0, sizeof(pic));
-        err = dav1d_decode(ctx, NULL, &pic);
+        err = dav1d_get_picture(ctx, &pic);
         if (err == 0)
             dav1d_picture_unref(&pic);
     } while (err == 0);
--- a/tools/dav1d.c
+++ b/tools/dav1d.c
@@ -108,12 +108,20 @@
 
     do {
         memset(&p, 0, sizeof(p));
-        if ((res = dav1d_decode(c, &data, &p)) < 0) {
+        if ((res = dav1d_send_data(c, &data)) < 0) {
             if (res != -EAGAIN) {
                 fprintf(stderr, "Error decoding frame: %s\n",
                         strerror(-res));
                 break;
             }
+        }
+
+        if ((res = dav1d_get_picture(c, &p)) < 0) {
+            if (res != -EAGAIN) {
+                fprintf(stderr, "Error decoding frame: %s\n",
+                        strerror(-res));
+                break;
+            }
             res = 0;
         } else {
             if (!n_out) {
@@ -139,7 +147,7 @@
 
     // flush
     if (res == 0) while (!cli_settings.limit || n_out < cli_settings.limit) {
-        if ((res = dav1d_decode(c, NULL, &p)) < 0) {
+        if ((res = dav1d_get_picture(c, &p)) < 0) {
             if (res != -EAGAIN) {
                 fprintf(stderr, "Error decoding frame: %s\n",
                         strerror(-res));