diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/dav1d/tools/input | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/dav1d/tools/input')
-rw-r--r-- | third_party/dav1d/tools/input/annexb.c | 195 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/demuxer.h | 45 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/input.c | 134 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/input.h | 41 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/ivf.c | 158 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/parse.h | 109 | ||||
-rw-r--r-- | third_party/dav1d/tools/input/section5.c | 185 |
7 files changed, 867 insertions, 0 deletions
diff --git a/third_party/dav1d/tools/input/annexb.c b/third_party/dav1d/tools/input/annexb.c new file mode 100644 index 0000000000..032480d00c --- /dev/null +++ b/third_party/dav1d/tools/input/annexb.c @@ -0,0 +1,195 @@ +/* + * Copyright © 2018, VideoLAN and dav1d authors + * Copyright © 2018, Two Orioles, LLC + * Copyright © 2019, James Almer <jamrial@gmail.com> + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "common/intops.h" + +#include "dav1d/headers.h" + +#include "input/demuxer.h" +#include "input/parse.h" + +// these functions are based on an implementation from FFmpeg, and relicensed +// with author's permission + +#define PROBE_SIZE 1024 + +static int annexb_probe(const uint8_t *data) { + int ret, cnt = 0; + + size_t temporal_unit_size; + ret = leb(data + cnt, PROBE_SIZE - cnt, &temporal_unit_size); + if (ret < 0) + return 0; + cnt += ret; + + size_t frame_unit_size; + ret = leb(data + cnt, PROBE_SIZE - cnt, &frame_unit_size); + if (ret < 0 || ((uint64_t)frame_unit_size + ret) > temporal_unit_size) + return 0; + cnt += ret; + + temporal_unit_size -= ret; + + size_t obu_unit_size; + ret = leb(data + cnt, PROBE_SIZE - cnt, &obu_unit_size); + if (ret < 0 || ((uint64_t)obu_unit_size + ret) >= frame_unit_size) + return 0; + cnt += ret; + + temporal_unit_size -= obu_unit_size + ret; + frame_unit_size -= obu_unit_size + ret; + + // Check that the first OBU is a Temporal Delimiter. + size_t obu_size; + enum Dav1dObuType type; + ret = parse_obu_header(data + cnt, imin(PROBE_SIZE - cnt, (int) obu_unit_size), + &obu_size, &type, 1); + if (ret < 0 || type != DAV1D_OBU_TD || obu_size > 0) + return 0; + cnt += (int)obu_unit_size; + + // look for first frame and accompanying sequence header + int seq = 0; + while (cnt < PROBE_SIZE) { + ret = leb(data + cnt, PROBE_SIZE - cnt, &obu_unit_size); + if (ret < 0 || ((uint64_t)obu_unit_size + ret) > frame_unit_size) + return 0; + cnt += ret; + temporal_unit_size -= ret; + frame_unit_size -= ret; + + ret = parse_obu_header(data + cnt, imin(PROBE_SIZE - cnt, (int) obu_unit_size), + &obu_size, &type, 1); + if (ret < 0) + return 0; + cnt += (int)obu_unit_size; + + switch (type) { + case DAV1D_OBU_SEQ_HDR: + seq = 1; + break; + case DAV1D_OBU_FRAME: + case DAV1D_OBU_FRAME_HDR: + return seq; + case DAV1D_OBU_TD: + case DAV1D_OBU_TILE_GRP: + return 0; + default: + break; + } + + temporal_unit_size -= obu_unit_size; + frame_unit_size -= obu_unit_size; + if (frame_unit_size <= 0) + break; + } + + return 0; +} + +typedef struct DemuxerPriv { + FILE *f; + size_t temporal_unit_size; + size_t frame_unit_size; +} AnnexbInputContext; + +static int annexb_open(AnnexbInputContext *const c, const char *const file, + unsigned fps[2], unsigned *const num_frames, unsigned timebase[2]) +{ + int res; + size_t len; + + if (!(c->f = fopen(file, "rb"))) { + fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno)); + return -1; + } + + // TODO: Parse sequence header and read timing info if any. + fps[0] = 25; + fps[1] = 1; + timebase[0] = 25; + timebase[1] = 1; + for (*num_frames = 0;; (*num_frames)++) { + res = leb128(c->f, &len); + if (res < 0) + break; + fseeko(c->f, len, SEEK_CUR); + } + fseeko(c->f, 0, SEEK_SET); + + return 0; +} + +static int annexb_read(AnnexbInputContext *const c, Dav1dData *const data) { + size_t len; + int res; + + if (!c->temporal_unit_size) { + res = leb128(c->f, &c->temporal_unit_size); + if (res < 0) return -1; + } + if (!c->frame_unit_size) { + res = leb128(c->f, &c->frame_unit_size); + if (res < 0 || (c->frame_unit_size + res) > c->temporal_unit_size) return -1; + c->temporal_unit_size -= res; + } + res = leb128(c->f, &len); + if (res < 0 || (len + res) > c->frame_unit_size) return -1; + uint8_t *ptr = dav1d_data_create(data, len); + if (!ptr) return -1; + c->temporal_unit_size -= len + res; + c->frame_unit_size -= len + res; + if (fread(ptr, len, 1, c->f) != 1) { + fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno)); + dav1d_data_unref(data); + return -1; + } + + return 0; +} + +static void annexb_close(AnnexbInputContext *const c) { + fclose(c->f); +} + +const Demuxer annexb_demuxer = { + .priv_data_size = sizeof(AnnexbInputContext), + .name = "annexb", + .probe = annexb_probe, + .probe_sz = PROBE_SIZE, + .open = annexb_open, + .read = annexb_read, + .close = annexb_close, +}; diff --git a/third_party/dav1d/tools/input/demuxer.h b/third_party/dav1d/tools/input/demuxer.h new file mode 100644 index 0000000000..c2b88e1480 --- /dev/null +++ b/third_party/dav1d/tools/input/demuxer.h @@ -0,0 +1,45 @@ +/* + * 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_INPUT_DEMUXER_H +#define DAV1D_INPUT_DEMUXER_H + +#include "data.h" + +typedef struct DemuxerPriv DemuxerPriv; +typedef struct Demuxer { + int priv_data_size; + const char *name; + int probe_sz; + int (*probe)(const uint8_t *data); + int (*open)(DemuxerPriv *ctx, const char *filename, + unsigned fps[2], unsigned *num_frames, unsigned timebase[2]); + int (*read)(DemuxerPriv *ctx, Dav1dData *data); + void (*close)(DemuxerPriv *ctx); +} Demuxer; + +#endif /* DAV1D_INPUT_DEMUXER_H */ diff --git a/third_party/dav1d/tools/input/input.c b/third_party/dav1d/tools/input/input.c new file mode 100644 index 0000000000..3ed6983ace --- /dev/null +++ b/third_party/dav1d/tools/input/input.c @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#include "config.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common/attributes.h" +#include "common/intops.h" + +#include "input/input.h" +#include "input/demuxer.h" + +struct DemuxerContext { + DemuxerPriv *data; + const Demuxer *impl; +}; + +extern const Demuxer ivf_demuxer; +extern const Demuxer annexb_demuxer; +extern const Demuxer section5_demuxer; +static const Demuxer *const demuxers[] = { + &ivf_demuxer, + &annexb_demuxer, + §ion5_demuxer, + NULL +}; + +int input_open(DemuxerContext **const c_out, + const char *const name, const char *const filename, + unsigned fps[2], unsigned *const num_frames, unsigned timebase[2]) +{ + const Demuxer *impl; + DemuxerContext *c; + int res, i; + + if (name) { + for (i = 0; demuxers[i]; i++) { + if (!strcmp(demuxers[i]->name, name)) { + impl = demuxers[i]; + break; + } + } + if (!demuxers[i]) { + fprintf(stderr, "Failed to find demuxer named \"%s\"\n", name); + return DAV1D_ERR(ENOPROTOOPT); + } + } else { + int probe_sz = 0; + for (i = 0; demuxers[i]; i++) + probe_sz = imax(probe_sz, demuxers[i]->probe_sz); + uint8_t *const probe_data = malloc(probe_sz); + if (!probe_data) { + fprintf(stderr, "Failed to allocate memory\n"); + return DAV1D_ERR(ENOMEM); + } + FILE *f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "Failed to open input file %s: %s\n", filename, strerror(errno)); + return errno ? DAV1D_ERR(errno) : DAV1D_ERR(EIO); + } + res = !!fread(probe_data, 1, probe_sz, f); + fclose(f); + if (!res) { + free(probe_data); + fprintf(stderr, "Failed to read probe data\n"); + return errno ? DAV1D_ERR(errno) : DAV1D_ERR(EIO); + } + + for (i = 0; demuxers[i]; i++) { + if (demuxers[i]->probe(probe_data)) { + impl = demuxers[i]; + break; + } + } + free(probe_data); + if (!demuxers[i]) { + fprintf(stderr, + "Failed to probe demuxer for file %s\n", + filename); + return DAV1D_ERR(ENOPROTOOPT); + } + } + + if (!(c = calloc(1, sizeof(DemuxerContext) + impl->priv_data_size))) { + fprintf(stderr, "Failed to allocate memory\n"); + return DAV1D_ERR(ENOMEM); + } + c->impl = impl; + c->data = (DemuxerPriv *) &c[1]; + if ((res = impl->open(c->data, filename, fps, num_frames, timebase)) < 0) { + free(c); + return res; + } + *c_out = c; + + return 0; +} + +int input_read(DemuxerContext *const ctx, Dav1dData *const data) { + return ctx->impl->read(ctx->data, data); +} + +void input_close(DemuxerContext *const ctx) { + ctx->impl->close(ctx->data); + free(ctx); +} diff --git a/third_party/dav1d/tools/input/input.h b/third_party/dav1d/tools/input/input.h new file mode 100644 index 0000000000..7b2fdc94c4 --- /dev/null +++ b/third_party/dav1d/tools/input/input.h @@ -0,0 +1,41 @@ +/* + * 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_INPUT_INPUT_H +#define DAV1D_INPUT_INPUT_H + +#include "data.h" + +typedef struct DemuxerContext DemuxerContext; + +int input_open(DemuxerContext **const c_out, + const char *const name, const char *const filename, + unsigned fps[2], unsigned *num_frames, unsigned timebase[2]); +int input_read(DemuxerContext *ctx, Dav1dData *data); +void input_close(DemuxerContext *ctx); + +#endif /* DAV1D_INPUT_INPUT_H */ diff --git a/third_party/dav1d/tools/input/ivf.c b/third_party/dav1d/tools/input/ivf.c new file mode 100644 index 0000000000..7b572ee73c --- /dev/null +++ b/third_party/dav1d/tools/input/ivf.c @@ -0,0 +1,158 @@ +/* + * 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. + */ + +#include "config.h" + +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "input/demuxer.h" + +typedef struct DemuxerPriv { + FILE *f; +} IvfInputContext; + +static const uint8_t probe_data[] = { + 'D', 'K', 'I', 'F', + 0, 0, 0x20, 0, + 'A', 'V', '0', '1', +}; + +static int ivf_probe(const uint8_t *const data) { + return !memcmp(data, probe_data, sizeof(probe_data)); +} + +static unsigned rl32(const uint8_t *const p) { + return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0]; +} + +static int64_t rl64(const uint8_t *const p) { + return (((uint64_t) rl32(&p[4])) << 32) | rl32(p); +} + +static int ivf_open(IvfInputContext *const c, const char *const file, + unsigned fps[2], unsigned *const num_frames, unsigned timebase[2]) +{ + size_t res; + uint8_t hdr[32]; + + if (!(c->f = fopen(file, "rb"))) { + fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno)); + return -1; + } else if ((res = fread(hdr, 32, 1, c->f)) != 1) { + fprintf(stderr, "Failed to read stream header: %s\n", strerror(errno)); + fclose(c->f); + return -1; + } else if (memcmp(hdr, "DKIF", 4)) { + fprintf(stderr, "%s is not an IVF file [tag=%.4s|0x%02x%02x%02x%02x]\n", + file, hdr, hdr[0], hdr[1], hdr[2], hdr[3]); + fclose(c->f); + return -1; + } else if (memcmp(&hdr[8], "AV01", 4)) { + fprintf(stderr, "%s is not an AV1 file [tag=%.4s|0x%02x%02x%02x%02x]\n", + file, &hdr[8], hdr[8], hdr[9], hdr[10], hdr[11]); + fclose(c->f); + return -1; + } + + timebase[0] = rl32(&hdr[16]); + timebase[1] = rl32(&hdr[20]); + const unsigned duration = rl32(&hdr[24]); + + uint8_t data[4]; + for (*num_frames = 0;; (*num_frames)++) { + if ((res = fread(data, 4, 1, c->f)) != 1) + break; // EOF + fseeko(c->f, rl32(data) + 8, SEEK_CUR); + } + + uint64_t fps_num = (uint64_t) timebase[0] * *num_frames; + uint64_t fps_den = (uint64_t) timebase[1] * duration; + if (fps_num && fps_den) { /* Reduce fraction */ + uint64_t gcd = fps_num; + for (uint64_t a = fps_den, b; (b = a % gcd); a = gcd, gcd = b); + fps_num /= gcd; + fps_den /= gcd; + + while ((fps_num | fps_den) > UINT_MAX) { + fps_num >>= 1; + fps_den >>= 1; + } + } + if (fps_num && fps_den) { + fps[0] = (unsigned) fps_num; + fps[1] = (unsigned) fps_den; + } else { + fps[0] = fps[1] = 0; + } + + fseeko(c->f, 32, SEEK_SET); + + return 0; +} + +static int ivf_read(IvfInputContext *const c, Dav1dData *const buf) { + uint8_t data[8]; + uint8_t *ptr; + size_t res; + + const int64_t off = ftello(c->f); + if ((res = fread(data, 4, 1, c->f)) != 1) + return -1; // EOF + const ptrdiff_t sz = rl32(data); + if ((res = fread(data, 8, 1, c->f)) != 1) + return -1; // EOF + ptr = dav1d_data_create(buf, sz); + if (!ptr) return -1; + buf->m.offset = off; + buf->m.timestamp = rl64(data); + if ((res = fread(ptr, sz, 1, c->f)) != 1) { + fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno)); + dav1d_data_unref(buf); + return -1; + } + + return 0; +} + +static void ivf_close(IvfInputContext *const c) { + fclose(c->f); +} + +const Demuxer ivf_demuxer = { + .priv_data_size = sizeof(IvfInputContext), + .name = "ivf", + .probe = ivf_probe, + .probe_sz = sizeof(probe_data), + .open = ivf_open, + .read = ivf_read, + .close = ivf_close, +}; diff --git a/third_party/dav1d/tools/input/parse.h b/third_party/dav1d/tools/input/parse.h new file mode 100644 index 0000000000..f5805e8ca4 --- /dev/null +++ b/third_party/dav1d/tools/input/parse.h @@ -0,0 +1,109 @@ +/* + * Copyright © 2018, VideoLAN and dav1d authors + * Copyright © 2018, Two Orioles, LLC + * Copyright © 2019, James Almer <jamrial@gmail.com> + * 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_INPUT_PARSE_H +#define DAV1D_INPUT_PARSE_H + +#include <limits.h> + +#include "dav1d/headers.h" + +static int leb128(FILE *const f, size_t *const len) { + uint64_t val = 0; + unsigned i = 0, more; + do { + uint8_t v; + if (fread(&v, 1, 1, f) < 1) + return -1; + more = v & 0x80; + val |= ((uint64_t) (v & 0x7F)) << (i * 7); + i++; + } while (more && i < 8); + if (val > UINT_MAX || more) + return -1; + *len = (size_t) val; + return i; +} + +// these functions are based on an implementation from FFmpeg, and relicensed +// with author's permission + +static int leb(const uint8_t *ptr, int sz, size_t *const len) { + uint64_t val = 0; + unsigned i = 0, more; + do { + if (!sz--) return -1; + const int v = *ptr++; + more = v & 0x80; + val |= ((uint64_t) (v & 0x7F)) << (i * 7); + i++; + } while (more && i < 8); + if (val > UINT_MAX || more) + return -1; + *len = (size_t) val; + return i; +} + +static inline int parse_obu_header(const uint8_t *buf, int buf_size, + size_t *const obu_size, + enum Dav1dObuType *const type, + const int allow_implicit_size) +{ + int ret, extension_flag, has_size_flag; + + if (!buf_size) + return -1; + if (*buf & 0x80) // obu_forbidden_bit + return -1; + + *type = (*buf & 0x78) >> 3; + extension_flag = (*buf & 0x4) >> 2; + has_size_flag = (*buf & 0x2) >> 1; + // ignore obu_reserved_1bit + buf++; + buf_size--; + + if (extension_flag) { + buf++; + buf_size--; + // ignore fields + } + + if (has_size_flag) { + ret = leb(buf, buf_size, obu_size); + if (ret < 0) + return -1; + return (int) *obu_size + ret + 1 + extension_flag; + } else if (!allow_implicit_size) + return -1; + + *obu_size = buf_size; + return buf_size + 1 + extension_flag; +} + +#endif /* DAV1D_INPUT_PARSE_H */ diff --git a/third_party/dav1d/tools/input/section5.c b/third_party/dav1d/tools/input/section5.c new file mode 100644 index 0000000000..0c2ce28c63 --- /dev/null +++ b/third_party/dav1d/tools/input/section5.c @@ -0,0 +1,185 @@ +/* + * Copyright © 2019, VideoLAN and dav1d authors + * Copyright © 2019, Two Orioles, LLC + * Copyright © 2019, James Almer <jamrial@gmail.com> + * 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. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "dav1d/headers.h" + +#include "input/demuxer.h" +#include "input/parse.h" + +#define PROBE_SIZE 1024 + +static int section5_probe(const uint8_t *data) { + int ret, cnt = 0; + + // Check that the first OBU is a Temporal Delimiter. + size_t obu_size; + enum Dav1dObuType type; + ret = parse_obu_header(data + cnt, PROBE_SIZE - cnt, + &obu_size, &type, 0); + if (ret < 0 || type != DAV1D_OBU_TD || obu_size > 0) + return 0; + cnt += ret; + + // look for first frame and accompanying sequence header + int seq = 0; + while (cnt < PROBE_SIZE) { + ret = parse_obu_header(data + cnt, PROBE_SIZE - cnt, + &obu_size, &type, 0); + if (ret < 0) + return 0; + cnt += ret; + + switch (type) { + case DAV1D_OBU_SEQ_HDR: + seq = 1; + break; + case DAV1D_OBU_FRAME: + case DAV1D_OBU_FRAME_HDR: + return seq; + case DAV1D_OBU_TD: + case DAV1D_OBU_TILE_GRP: + return 0; + default: + break; + } + } + + return 0; +} + +typedef struct DemuxerPriv { + FILE *f; +} Section5InputContext; + +static int section5_open(Section5InputContext *const c, const char *const file, + unsigned fps[2], unsigned *const num_frames, unsigned timebase[2]) +{ + if (!(c->f = fopen(file, "rb"))) { + fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno)); + return -1; + } + + // TODO: Parse sequence header and read timing info if any. + fps[0] = 25; + fps[1] = 1; + timebase[0] = 25; + timebase[1] = 1; + *num_frames = 0; + for (;;) { + uint8_t byte[2]; + + if (fread(&byte[0], 1, 1, c->f) < 1) + break; + const enum Dav1dObuType obu_type = (byte[0] >> 3) & 0xf; + if (obu_type == DAV1D_OBU_TD) + (*num_frames)++; + const int has_length_field = byte[0] & 0x2; + if (!has_length_field) + return -1; + const int has_extension = byte[0] & 0x4; + if (has_extension && fread(&byte[1], 1, 1, c->f) < 1) + return -1; + size_t len; + const int res = leb128(c->f, &len); + if (res < 0) + return -1; + fseeko(c->f, len, SEEK_CUR); // skip packet + } + fseeko(c->f, 0, SEEK_SET); + + return 0; +} + +static int section5_read(Section5InputContext *const c, Dav1dData *const data) { + size_t total_bytes = 0; + + for (int first = 1;; first = 0) { + uint8_t byte[2]; + + if (fread(&byte[0], 1, 1, c->f) < 1) { + if (!first && feof(c->f)) break; + return -1; + } + const enum Dav1dObuType obu_type = (byte[0] >> 3) & 0xf; + if (first) { + if (obu_type != DAV1D_OBU_TD) + return -1; + } else { + if (obu_type == DAV1D_OBU_TD) { + // include TD in next packet + fseeko(c->f, -1, SEEK_CUR); + break; + } + } + const int has_length_field = byte[0] & 0x2; + if (!has_length_field) + return -1; + const int has_extension = !!(byte[0] & 0x4); + if (has_extension && fread(&byte[1], 1, 1, c->f) < 1) + return -1; + size_t len; + const int res = leb128(c->f, &len); + if (res < 0) + return -1; + total_bytes += 1 + has_extension + res + len; + fseeko(c->f, len, SEEK_CUR); // skip packet, we'll read it below + } + + fseeko(c->f, -(off_t)total_bytes, SEEK_CUR); + uint8_t *ptr = dav1d_data_create(data, total_bytes); + if (!ptr) return -1; + if (fread(ptr, total_bytes, 1, c->f) != 1) { + fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno)); + dav1d_data_unref(data); + return -1; + } + + return 0; +} + +static void section5_close(Section5InputContext *const c) { + fclose(c->f); +} + +const Demuxer section5_demuxer = { + .priv_data_size = sizeof(Section5InputContext), + .name = "section5", + .probe = section5_probe, + .probe_sz = PROBE_SIZE, + .open = section5_open, + .read = section5_read, + .close = section5_close, +}; |