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/dav1d.c | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.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/dav1d.c')
-rw-r--r-- | third_party/dav1d/tools/dav1d.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/third_party/dav1d/tools/dav1d.c b/third_party/dav1d/tools/dav1d.c new file mode 100644 index 0000000000..907af3f8ef --- /dev/null +++ b/third_party/dav1d/tools/dav1d.c @@ -0,0 +1,317 @@ +/* + * 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 "vcs_version.h" +#include "cli_config.h" + +#include <errno.h> +#include <inttypes.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_IO_H +# include <io.h> +#endif +#ifdef _WIN32 +# include <windows.h> +#endif +#ifdef __APPLE__ +#include <mach/mach_time.h> +#endif + +#include "dav1d/dav1d.h" + +#include "input/input.h" + +#include "output/output.h" + +#include "dav1d_cli_parse.h" + +static uint64_t get_time_nanos(void) { +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + uint64_t seconds = t.QuadPart / frequency.QuadPart; + uint64_t fractions = t.QuadPart % frequency.QuadPart; + return 1000000000 * seconds + 1000000000 * fractions / frequency.QuadPart; +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return 1000000000ULL * ts.tv_sec + ts.tv_nsec; +#elif defined(__APPLE__) + mach_timebase_info_data_t info; + mach_timebase_info(&info); + return mach_absolute_time() * info.numer / info.denom; +#endif +} + +static void sleep_nanos(uint64_t d) { +#ifdef _WIN32 + Sleep((unsigned)(d / 1000000)); +#else + const struct timespec ts = { + .tv_sec = (time_t)(d / 1000000000), + .tv_nsec = d % 1000000000, + }; + nanosleep(&ts, NULL); +#endif +} + +static void synchronize(const int realtime, const unsigned cache, + const unsigned n_out, const uint64_t nspf, + const uint64_t tfirst, uint64_t *const elapsed, + FILE *const frametimes) +{ + const uint64_t tcurr = get_time_nanos(); + const uint64_t last = *elapsed; + *elapsed = tcurr - tfirst; + if (realtime) { + const uint64_t deadline = nspf * n_out; + if (*elapsed < deadline) { + const uint64_t remaining = deadline - *elapsed; + if (remaining > nspf * cache) sleep_nanos(remaining - nspf * cache); + *elapsed = deadline; + } + } + if (frametimes) { + const uint64_t frametime = *elapsed - last; + fprintf(frametimes, "%" PRIu64 "\n", frametime); + fflush(frametimes); + } +} + +static void print_stats(const int istty, const unsigned n, const unsigned num, + const uint64_t elapsed, const double i_fps) +{ + char buf[80], *b = buf, *const end = buf + 80; + + if (istty) + *b++ = '\r'; + if (num == 0xFFFFFFFF) + b += snprintf(b, end - b, "Decoded %u frames", n); + else + b += snprintf(b, end - b, "Decoded %u/%u frames (%.1lf%%)", + n, num, 100.0 * n / num); + if (b < end) { + const double d_fps = 1e9 * n / elapsed; + if (i_fps) { + const double speed = d_fps / i_fps; + b += snprintf(b, end - b, " - %.2lf/%.2lf fps (%.2lfx)", + d_fps, i_fps, speed); + } else { + b += snprintf(b, end - b, " - %.2lf fps", d_fps); + } + } + if (!istty) + strcpy(b > end - 2 ? end - 2 : b, "\n"); + fputs(buf, stderr); +} + +int main(const int argc, char *const *const argv) { + const int istty = isatty(fileno(stderr)); + int res = 0; + CLISettings cli_settings; + Dav1dSettings lib_settings; + DemuxerContext *in; + MuxerContext *out = NULL; + Dav1dPicture p; + Dav1dContext *c; + Dav1dData data; + unsigned n_out = 0, total, fps[2], timebase[2]; + uint64_t nspf, tfirst, elapsed; + double i_fps; + FILE *frametimes = NULL; + const char *version = dav1d_version(); + + if (strcmp(version, DAV1D_VERSION)) { + fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n", + version, DAV1D_VERSION); + return EXIT_FAILURE; + } + + parse(argc, argv, &cli_settings, &lib_settings); + + if ((res = input_open(&in, cli_settings.demuxer, + cli_settings.inputfile, + fps, &total, timebase)) < 0) + { + return EXIT_FAILURE; + } + for (unsigned i = 0; i <= cli_settings.skip; i++) { + if ((res = input_read(in, &data)) < 0) { + input_close(in); + return EXIT_FAILURE; + } + if (i < cli_settings.skip) dav1d_data_unref(&data); + } + + if (!cli_settings.quiet) + fprintf(stderr, "dav1d %s - by VideoLAN\n", dav1d_version()); + + // skip frames until a sequence header is found + if (cli_settings.skip) { + Dav1dSequenceHeader seq; + unsigned seq_skip = 0; + while (dav1d_parse_sequence_header(&seq, data.data, data.sz)) { + if ((res = input_read(in, &data)) < 0) { + input_close(in); + return EXIT_FAILURE; + } + seq_skip++; + } + if (seq_skip && !cli_settings.quiet) + fprintf(stderr, + "skipped %u packets due to missing sequence header\n", + seq_skip); + } + + //getc(stdin); + if (cli_settings.limit != 0 && cli_settings.limit < total) + total = cli_settings.limit; + + if ((res = dav1d_open(&c, &lib_settings))) + return EXIT_FAILURE; + + if (cli_settings.frametimes) + frametimes = fopen(cli_settings.frametimes, "w"); + + if (cli_settings.realtime != REALTIME_CUSTOM) { + if (fps[1] == 0) { + i_fps = 0; + nspf = 0; + } else { + i_fps = (double)fps[0] / fps[1]; + nspf = 1000000000ULL * fps[1] / fps[0]; + } + } else { + i_fps = cli_settings.realtime_fps; + nspf = (uint64_t)(1000000000.0 / cli_settings.realtime_fps); + } + tfirst = get_time_nanos(); + + do { + memset(&p, 0, sizeof(p)); + if ((res = dav1d_send_data(c, &data)) < 0) { + if (res != DAV1D_ERR(EAGAIN)) { + fprintf(stderr, "Error decoding frame: %s\n", + strerror(DAV1D_ERR(res))); + break; + } + } + + if ((res = dav1d_get_picture(c, &p)) < 0) { + if (res != DAV1D_ERR(EAGAIN)) { + fprintf(stderr, "Error decoding frame: %s\n", + strerror(DAV1D_ERR(res))); + break; + } + res = 0; + } else { + if (!n_out) { + if ((res = output_open(&out, cli_settings.muxer, + cli_settings.outputfile, + &p.p, fps)) < 0) + { + if (frametimes) fclose(frametimes); + return EXIT_FAILURE; + } + } + if ((res = output_write(out, &p)) < 0) + break; + n_out++; + if (nspf || !cli_settings.quiet) { + synchronize(cli_settings.realtime, cli_settings.realtime_cache, + n_out, nspf, tfirst, &elapsed, frametimes); + } + if (!cli_settings.quiet) + print_stats(istty, n_out, total, elapsed, i_fps); + } + + if (cli_settings.limit && n_out == cli_settings.limit) + break; + } while (data.sz > 0 || !input_read(in, &data)); + + if (data.sz > 0) dav1d_data_unref(&data); + + // flush + if (res == 0) while (!cli_settings.limit || n_out < cli_settings.limit) { + if ((res = dav1d_get_picture(c, &p)) < 0) { + if (res != DAV1D_ERR(EAGAIN)) { + fprintf(stderr, "Error decoding frame: %s\n", + strerror(DAV1D_ERR(res))); + } else { + res = 0; + break; + } + } else { + if (!n_out) { + if ((res = output_open(&out, cli_settings.muxer, + cli_settings.outputfile, + &p.p, fps)) < 0) + { + if (frametimes) fclose(frametimes); + return EXIT_FAILURE; + } + } + if ((res = output_write(out, &p)) < 0) + break; + n_out++; + if (nspf || !cli_settings.quiet) { + synchronize(cli_settings.realtime, cli_settings.realtime_cache, + n_out, nspf, tfirst, &elapsed, frametimes); + } + if (!cli_settings.quiet) + print_stats(istty, n_out, total, elapsed, i_fps); + } + } + + if (frametimes) fclose(frametimes); + + input_close(in); + if (out) { + if (!cli_settings.quiet && istty) + fprintf(stderr, "\n"); + if (cli_settings.verify) + res |= output_verify(out, cli_settings.verify); + else + output_close(out); + } else { + fprintf(stderr, "No data decoded\n"); + res = 1; + } + dav1d_close(&c); + + return (res == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} |