diff options
author | James Almer <jamrial@gmail.com> | 2018-11-08 20:32:31 +0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2018-11-14 03:13:27 +0300 |
commit | 026069693ef5511368e105cc177f72c917e0f3a9 (patch) | |
tree | 5368c3ba550e8913c7052dd9f9232a8f9f5456a0 | |
parent | ec53ec6d5b4ebbb06d5c7209fd4f25634a6ad606 (diff) |
implement a decoupled decode API
-rw-r--r-- | include/dav1d/dav1d.h | 35 | ||||
-rw-r--r-- | src/data.c | 13 | ||||
-rw-r--r-- | src/data.h | 38 | ||||
-rw-r--r-- | src/internal.h | 2 | ||||
-rw-r--r-- | src/lib.c | 26 | ||||
-rw-r--r-- | tests/libfuzzer/dav1d_fuzzer.c | 8 | ||||
-rw-r--r-- | tools/dav1d.c | 12 |
7 files changed, 116 insertions, 18 deletions
diff --git a/include/dav1d/dav1d.h b/include/dav1d/dav1d.h index aadfde5..7179e6c 100644 --- a/include/dav1d/dav1d.h +++ b/include/dav1d/dav1d.h @@ -62,8 +62,8 @@ DAV1D_API void dav1d_default_settings(Dav1dSettings *s); /** * 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 void dav1d_default_settings(Dav1dSettings *s); 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, 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 in Input bitstream data. On success, the caller retains ownership of - * the input reference if the data was not fully consumed. * @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. @@ -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) { @@ -64,6 +65,18 @@ int dav1d_data_wrap(Dav1dData *const buf, const uint8_t *const ptr, const size_t 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) { validate_input(buf != NULL); diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..40bd17d --- /dev/null +++ b/src/data.h @@ -0,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__ */ diff --git a/src/internal.h b/src/internal.h index 9988879..4ab49b1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -40,6 +40,7 @@ typedef struct Dav1dTileContext Dav1dTileContext; #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 @@ struct Dav1dContext { Av1FrameHeader frame_hdr; // FIXME make ref? // decoded output picture queue + Dav1dData in; Dav1dPicture out; struct { Dav1dThreadPicture *out_delayed; @@ -157,15 +157,28 @@ error: 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 @@ int dav1d_decode(Dav1dContext *const c, } 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 @@ int dav1d_decode(Dav1dContext *const c, } 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 @@ void dav1d_close(Dav1dContext **const c_out) { 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]) diff --git a/tests/libfuzzer/dav1d_fuzzer.c b/tests/libfuzzer/dav1d_fuzzer.c index ec2d609..4a7ecb1 100644 --- a/tests/libfuzzer/dav1d_fuzzer.c +++ b/tests/libfuzzer/dav1d_fuzzer.c @@ -97,8 +97,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 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 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 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); diff --git a/tools/dav1d.c b/tools/dav1d.c index 692322c..3d01279 100644 --- a/tools/dav1d.c +++ b/tools/dav1d.c @@ -108,7 +108,15 @@ int main(const int argc, char *const *const argv) { 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)); @@ -139,7 +147,7 @@ int main(const int argc, char *const *const argv) { // 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)); |