mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1729481: Exclude more things from dav1d to make it easier to update r=jbauman
Depends on D124940 Differential Revision: https://phabricator.services.mozilla.com/D124941
This commit is contained in:
parent
4fe1475a38
commit
3b40e004e9
@ -50,6 +50,11 @@ vendoring:
|
||||
exclude:
|
||||
- build/.gitattributes
|
||||
- build/.gitignore
|
||||
- doc
|
||||
- examples
|
||||
- package
|
||||
- tests
|
||||
- tools
|
||||
|
||||
update-actions:
|
||||
- action: copy-file
|
||||
|
19
third_party/dav1d/doc/Doxyfile.in
vendored
19
third_party/dav1d/doc/Doxyfile.in
vendored
@ -1,19 +0,0 @@
|
||||
PROJECT_NAME = dav1d
|
||||
OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT@
|
||||
STRIP_FROM_PATH = @DOXYGEN_STRIP@
|
||||
OUTPUT_LANGUAGE = English
|
||||
TAB_SIZE = 4
|
||||
EXTRACT_ALL = YES
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
INPUT = @DOXYGEN_INPUT@
|
||||
FILE_PATTERNS = *.h
|
||||
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_LATEX = NO
|
108
third_party/dav1d/doc/PATENTS
vendored
108
third_party/dav1d/doc/PATENTS
vendored
@ -1,108 +0,0 @@
|
||||
Alliance for Open Media Patent License 1.0
|
||||
|
||||
1. License Terms.
|
||||
|
||||
1.1. Patent License. Subject to the terms and conditions of this License, each
|
||||
Licensor, on behalf of itself and successors in interest and assigns,
|
||||
grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as expressly stated in this
|
||||
License) patent license to its Necessary Claims to make, use, sell, offer
|
||||
for sale, import or distribute any Implementation.
|
||||
|
||||
1.2. Conditions.
|
||||
|
||||
1.2.1. Availability. As a condition to the grant of rights to Licensee to make,
|
||||
sell, offer for sale, import or distribute an Implementation under
|
||||
Section 1.1, Licensee must make its Necessary Claims available under
|
||||
this License, and must reproduce this License with any Implementation
|
||||
as follows:
|
||||
|
||||
a. For distribution in source code, by including this License in the
|
||||
root directory of the source code with its Implementation.
|
||||
|
||||
b. For distribution in any other form (including binary, object form,
|
||||
and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist,
|
||||
GDSII, etc.)), by including this License in the documentation, legal
|
||||
notices, and/or other written materials provided with the
|
||||
Implementation.
|
||||
|
||||
1.2.2. Additional Conditions. This license is directly from Licensor to
|
||||
Licensee. Licensee acknowledges as a condition of benefiting from it
|
||||
that no rights from Licensor are received from suppliers, distributors,
|
||||
or otherwise in connection with this License.
|
||||
|
||||
1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents
|
||||
initiates patent litigation or files, maintains, or voluntarily
|
||||
participates in a lawsuit against another entity or any person asserting
|
||||
that any Implementation infringes Necessary Claims, any patent licenses
|
||||
granted under this License directly to the Licensee are immediately
|
||||
terminated as of the date of the initiation of action unless 1) that suit
|
||||
was in response to a corresponding suit regarding an Implementation first
|
||||
brought against an initiating entity, or 2) that suit was brought to
|
||||
enforce the terms of this License (including intervention in a third-party
|
||||
action by a Licensee).
|
||||
|
||||
1.4. Disclaimers. The Reference Implementation and Specification are provided
|
||||
"AS IS" and without warranty. The entire risk as to implementing or
|
||||
otherwise using the Reference Implementation or Specification is assumed
|
||||
by the implementer and user. Licensor expressly disclaims any warranties
|
||||
(express, implied, or otherwise), including implied warranties of
|
||||
merchantability, non-infringement, fitness for a particular purpose, or
|
||||
title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO
|
||||
ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL,
|
||||
INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF
|
||||
ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH
|
||||
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR
|
||||
NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
2. Definitions.
|
||||
|
||||
2.1. Affiliate. “Affiliate” means an entity that directly or indirectly
|
||||
Controls, is Controlled by, or is under common Control of that party.
|
||||
|
||||
2.2. Control. “Control” means direct or indirect control of more than 50% of
|
||||
the voting power to elect directors of that corporation, or for any other
|
||||
entity, the power to direct management of such entity.
|
||||
|
||||
2.3. Decoder. "Decoder" means any decoder that conforms fully with all
|
||||
non-optional portions of the Specification.
|
||||
|
||||
2.4. Encoder. "Encoder" means any encoder that produces a bitstream that can
|
||||
be decoded by a Decoder only to the extent it produces such a bitstream.
|
||||
|
||||
2.5. Final Deliverable. “Final Deliverable” means the final version of a
|
||||
deliverable approved by the Alliance for Open Media as a Final
|
||||
Deliverable.
|
||||
|
||||
2.6. Implementation. "Implementation" means any implementation, including the
|
||||
Reference Implementation, that is an Encoder and/or a Decoder. An
|
||||
Implementation also includes components of an Implementation only to the
|
||||
extent they are used as part of an Implementation.
|
||||
|
||||
2.7. License. “License” means this license.
|
||||
|
||||
2.8. Licensee. “Licensee” means any person or entity who exercises patent
|
||||
rights granted under this License.
|
||||
|
||||
2.9. Licensor. "Licensor" means (i) any Licensee that makes, sells, offers
|
||||
for sale, imports or distributes any Implementation, or (ii) a person
|
||||
or entity that has a licensing obligation to the Implementation as a
|
||||
result of its membership and/or participation in the Alliance for Open
|
||||
Media working group that developed the Specification.
|
||||
|
||||
2.10. Necessary Claims. "Necessary Claims" means all claims of patents or
|
||||
patent applications, (a) that currently or at any time in the future,
|
||||
are owned or controlled by the Licensor, and (b) (i) would be an
|
||||
Essential Claim as defined by the W3C Policy as of February 5, 2004
|
||||
(https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential)
|
||||
as if the Specification was a W3C Recommendation; or (ii) are infringed
|
||||
by the Reference Implementation.
|
||||
|
||||
2.11. Reference Implementation. “Reference Implementation” means an Encoder
|
||||
and/or Decoder released by the Alliance for Open Media as a Final
|
||||
Deliverable.
|
||||
|
||||
2.12. Specification. “Specification” means the specification designated by
|
||||
the Alliance for Open Media as a Final Deliverable for which this
|
||||
License was issued.
|
||||
|
BIN
third_party/dav1d/doc/dav1d_logo.png
vendored
BIN
third_party/dav1d/doc/dav1d_logo.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
1
third_party/dav1d/doc/dav1d_logo.svg
vendored
1
third_party/dav1d/doc/dav1d_logo.svg
vendored
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 5.3 KiB |
43
third_party/dav1d/doc/meson.build
vendored
43
third_party/dav1d/doc/meson.build
vendored
@ -1,43 +0,0 @@
|
||||
# Copyright © 2018, VideoLAN and dav1d authors
|
||||
# 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.
|
||||
|
||||
doxygen = find_program('doxygen', required: false)
|
||||
dot = find_program('dot', required: false)
|
||||
|
||||
if doxygen.found() and dot.found()
|
||||
conf_data = configuration_data()
|
||||
conf_data.set('DOXYGEN_INPUT', join_paths(dav1d_src_root, 'include/dav1d'))
|
||||
conf_data.set('DOXYGEN_STRIP', join_paths(dav1d_src_root, 'include'))
|
||||
conf_data.set('DOXYGEN_OUTPUT', meson.current_build_dir())
|
||||
doxyfile = configure_file(input: 'Doxyfile.in',
|
||||
output: 'Doxyfile',
|
||||
configuration: conf_data)
|
||||
|
||||
custom_target('doc',
|
||||
build_by_default: false,
|
||||
command: [doxygen, doxyfile],
|
||||
output: ['html']
|
||||
)
|
||||
endif
|
||||
|
786
third_party/dav1d/examples/dav1dplay.c
vendored
786
third_party/dav1d/examples/dav1dplay.c
vendored
@ -1,786 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019, VideoLAN and dav1d authors
|
||||
* 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 <getopt.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "dav1d/dav1d.h"
|
||||
|
||||
#include "common/attributes.h"
|
||||
#include "tools/input/input.h"
|
||||
#include "dp_fifo.h"
|
||||
#include "dp_renderer.h"
|
||||
|
||||
#define FRAME_OFFSET_TO_PTS(foff) \
|
||||
(uint64_t)(((foff) * rd_ctx->spf) * 1000000000.0 + .5)
|
||||
#define TS_TO_PTS(ts) \
|
||||
(uint64_t)(((ts) * rd_ctx->timebase) * 1000000000.0 + .5)
|
||||
|
||||
// Selected renderer callbacks and cookie
|
||||
static const Dav1dPlayRenderInfo *renderer_info = { NULL };
|
||||
|
||||
/**
|
||||
* Render context structure
|
||||
* This structure contains informations necessary
|
||||
* to be shared between the decoder and the renderer
|
||||
* threads.
|
||||
*/
|
||||
typedef struct render_context
|
||||
{
|
||||
Dav1dPlaySettings settings;
|
||||
Dav1dSettings lib_settings;
|
||||
|
||||
// Renderer private data (passed to callbacks)
|
||||
void *rd_priv;
|
||||
|
||||
// Lock to protect access to the context structure
|
||||
SDL_mutex *lock;
|
||||
|
||||
// Timestamp of last displayed frame (in timebase unit)
|
||||
int64_t last_ts;
|
||||
// Timestamp of last decoded frame (in timebase unit)
|
||||
int64_t current_ts;
|
||||
// Ticks when last frame was received
|
||||
uint32_t last_ticks;
|
||||
// PTS time base
|
||||
double timebase;
|
||||
// Seconds per frame
|
||||
double spf;
|
||||
// Number of frames
|
||||
uint32_t total;
|
||||
|
||||
// Fifo
|
||||
Dav1dPlayPtrFifo *fifo;
|
||||
|
||||
// Custom SDL2 event types
|
||||
uint32_t event_types;
|
||||
|
||||
// User pause state
|
||||
uint8_t user_paused;
|
||||
// Internal pause state
|
||||
uint8_t paused;
|
||||
// Start of internal pause state
|
||||
uint32_t pause_start;
|
||||
// Duration of internal pause state
|
||||
uint32_t pause_time;
|
||||
|
||||
// Seek accumulator
|
||||
int seek;
|
||||
|
||||
// Indicates if termination of the decoder thread was requested
|
||||
uint8_t dec_should_terminate;
|
||||
} Dav1dPlayRenderContext;
|
||||
|
||||
static void dp_settings_print_usage(const char *const app,
|
||||
const char *const reason, ...)
|
||||
{
|
||||
if (reason) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, reason);
|
||||
vfprintf(stderr, reason, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n\n");
|
||||
}
|
||||
fprintf(stderr, "Usage: %s [options]\n\n", app);
|
||||
fprintf(stderr, "Supported options:\n"
|
||||
" --input/-i $file: input file\n"
|
||||
" --untimed/-u: ignore PTS, render as fast as possible\n"
|
||||
" --framethreads $num: number of frame threads (default: 1)\n"
|
||||
" --tilethreads $num: number of tile threads (default: 1)\n"
|
||||
" --pfthreads $num: number of postfilter threads(default: 1)\n"
|
||||
" --highquality: enable high quality rendering\n"
|
||||
" --zerocopy/-z: enable zero copy upload path\n"
|
||||
" --gpugrain/-g: enable GPU grain synthesis\n"
|
||||
" --version/-v: print version and exit\n"
|
||||
" --renderer/-r: select renderer backend (default: auto)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static unsigned parse_unsigned(const char *const optarg, const int option,
|
||||
const char *const app)
|
||||
{
|
||||
char *end;
|
||||
const unsigned res = (unsigned) strtoul(optarg, &end, 0);
|
||||
if (*end || end == optarg)
|
||||
dp_settings_print_usage(app, "Invalid argument \"%s\" for option %s; should be an integer",
|
||||
optarg, option);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void dp_rd_ctx_parse_args(Dav1dPlayRenderContext *rd_ctx,
|
||||
const int argc, char *const *const argv)
|
||||
{
|
||||
int o;
|
||||
Dav1dPlaySettings *settings = &rd_ctx->settings;
|
||||
Dav1dSettings *lib_settings = &rd_ctx->lib_settings;
|
||||
|
||||
// Short options
|
||||
static const char short_opts[] = "i:vuzgr:";
|
||||
|
||||
enum {
|
||||
ARG_FRAME_THREADS = 256,
|
||||
ARG_TILE_THREADS,
|
||||
ARG_POSTFILTER_THREADS,
|
||||
ARG_HIGH_QUALITY,
|
||||
};
|
||||
|
||||
// Long options
|
||||
static const struct option long_opts[] = {
|
||||
{ "input", 1, NULL, 'i' },
|
||||
{ "version", 0, NULL, 'v' },
|
||||
{ "untimed", 0, NULL, 'u' },
|
||||
{ "framethreads", 1, NULL, ARG_FRAME_THREADS },
|
||||
{ "tilethreads", 1, NULL, ARG_TILE_THREADS },
|
||||
{ "pfthreads", 1, NULL, ARG_POSTFILTER_THREADS },
|
||||
{ "highquality", 0, NULL, ARG_HIGH_QUALITY },
|
||||
{ "zerocopy", 0, NULL, 'z' },
|
||||
{ "gpugrain", 0, NULL, 'g' },
|
||||
{ "renderer", 0, NULL, 'r'},
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||
switch (o) {
|
||||
case 'i':
|
||||
settings->inputfile = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
fprintf(stderr, "%s\n", dav1d_version());
|
||||
exit(0);
|
||||
case 'u':
|
||||
settings->untimed = true;
|
||||
break;
|
||||
case ARG_HIGH_QUALITY:
|
||||
settings->highquality = true;
|
||||
break;
|
||||
case 'z':
|
||||
settings->zerocopy = true;
|
||||
break;
|
||||
case 'g':
|
||||
settings->gpugrain = true;
|
||||
break;
|
||||
case 'r':
|
||||
settings->renderer_name = optarg;
|
||||
break;
|
||||
case ARG_FRAME_THREADS:
|
||||
lib_settings->n_frame_threads =
|
||||
parse_unsigned(optarg, ARG_FRAME_THREADS, argv[0]);
|
||||
break;
|
||||
case ARG_TILE_THREADS:
|
||||
lib_settings->n_tile_threads =
|
||||
parse_unsigned(optarg, ARG_TILE_THREADS, argv[0]);
|
||||
break;
|
||||
case ARG_POSTFILTER_THREADS:
|
||||
lib_settings->n_postfilter_threads =
|
||||
parse_unsigned(optarg, ARG_POSTFILTER_THREADS, argv[0]);
|
||||
break;
|
||||
default:
|
||||
dp_settings_print_usage(argv[0], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
dp_settings_print_usage(argv[0],
|
||||
"Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
|
||||
if (!settings->inputfile)
|
||||
dp_settings_print_usage(argv[0], "Input file (-i/--input) is required");
|
||||
if (settings->renderer_name && strcmp(settings->renderer_name, "auto") == 0)
|
||||
settings->renderer_name = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a Dav1dPlayRenderContext
|
||||
*/
|
||||
static void dp_rd_ctx_destroy(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
assert(rd_ctx != NULL);
|
||||
|
||||
renderer_info->destroy_renderer(rd_ctx->rd_priv);
|
||||
dp_fifo_destroy(rd_ctx->fifo);
|
||||
SDL_DestroyMutex(rd_ctx->lock);
|
||||
free(rd_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Dav1dPlayRenderContext
|
||||
*
|
||||
* \note The Dav1dPlayRenderContext must be destroyed
|
||||
* again by using dp_rd_ctx_destroy.
|
||||
*/
|
||||
static Dav1dPlayRenderContext *dp_rd_ctx_create(int argc, char **argv)
|
||||
{
|
||||
Dav1dPlayRenderContext *rd_ctx;
|
||||
|
||||
// Alloc
|
||||
rd_ctx = calloc(1, sizeof(Dav1dPlayRenderContext));
|
||||
if (rd_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Register a custom event to notify our SDL main thread
|
||||
// about new frames
|
||||
rd_ctx->event_types = SDL_RegisterEvents(3);
|
||||
if (rd_ctx->event_types == UINT32_MAX) {
|
||||
fprintf(stderr, "Failure to create custom SDL event types!\n");
|
||||
free(rd_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rd_ctx->fifo = dp_fifo_create(5);
|
||||
if (rd_ctx->fifo == NULL) {
|
||||
fprintf(stderr, "Failed to create FIFO for output pictures!\n");
|
||||
free(rd_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rd_ctx->lock = SDL_CreateMutex();
|
||||
if (rd_ctx->lock == NULL) {
|
||||
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
|
||||
dp_fifo_destroy(rd_ctx->fifo);
|
||||
free(rd_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse and validate arguments
|
||||
dav1d_default_settings(&rd_ctx->lib_settings);
|
||||
memset(&rd_ctx->settings, 0, sizeof(rd_ctx->settings));
|
||||
dp_rd_ctx_parse_args(rd_ctx, argc, argv);
|
||||
|
||||
// Select renderer
|
||||
renderer_info = dp_get_renderer(rd_ctx->settings.renderer_name);
|
||||
|
||||
if (renderer_info == NULL) {
|
||||
printf("No suitable rendered matching %s found.\n",
|
||||
(rd_ctx->settings.renderer_name) ? rd_ctx->settings.renderer_name : "auto");
|
||||
} else {
|
||||
printf("Using %s renderer\n", renderer_info->name);
|
||||
}
|
||||
|
||||
rd_ctx->rd_priv = (renderer_info) ? renderer_info->create_renderer() : NULL;
|
||||
if (rd_ctx->rd_priv == NULL) {
|
||||
SDL_DestroyMutex(rd_ctx->lock);
|
||||
dp_fifo_destroy(rd_ctx->fifo);
|
||||
free(rd_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rd_ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify about new event
|
||||
*/
|
||||
static void dp_rd_ctx_post_event(Dav1dPlayRenderContext *rd_ctx, uint32_t type)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = type;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the decoder context with a new dav1d picture
|
||||
*
|
||||
* Once the decoder decoded a new picture, this call can be used
|
||||
* to update the internal texture of the render context with the
|
||||
* new picture.
|
||||
*/
|
||||
static void dp_rd_ctx_update_with_dav1d_picture(Dav1dPlayRenderContext *rd_ctx,
|
||||
Dav1dPicture *dav1d_pic)
|
||||
{
|
||||
rd_ctx->current_ts = dav1d_pic->m.timestamp;
|
||||
renderer_info->update_frame(rd_ctx->rd_priv, dav1d_pic, &rd_ctx->settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle pause state
|
||||
*/
|
||||
static void dp_rd_ctx_toggle_pause(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
rd_ctx->user_paused = !rd_ctx->user_paused;
|
||||
if (rd_ctx->seek)
|
||||
goto out;
|
||||
rd_ctx->paused = rd_ctx->user_paused;
|
||||
uint32_t now = SDL_GetTicks();
|
||||
if (rd_ctx->paused)
|
||||
rd_ctx->pause_start = now;
|
||||
else {
|
||||
rd_ctx->pause_time += now - rd_ctx->pause_start;
|
||||
rd_ctx->pause_start = 0;
|
||||
rd_ctx->last_ticks = now;
|
||||
}
|
||||
out:
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query pause state
|
||||
*/
|
||||
static int dp_rd_ctx_is_paused(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
int ret;
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
ret = rd_ctx->paused;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request seeking, in seconds
|
||||
*/
|
||||
static void dp_rd_ctx_seek(Dav1dPlayRenderContext *rd_ctx, int sec)
|
||||
{
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
rd_ctx->seek += sec;
|
||||
if (!rd_ctx->paused)
|
||||
rd_ctx->pause_start = SDL_GetTicks();
|
||||
rd_ctx->paused = 1;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
}
|
||||
|
||||
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
|
||||
Dav1dData *data, DemuxerContext *in_ctx);
|
||||
static inline void destroy_pic(void *a);
|
||||
|
||||
/**
|
||||
* Seek the stream, if requested
|
||||
*/
|
||||
static int dp_rd_ctx_handle_seek(Dav1dPlayRenderContext *rd_ctx,
|
||||
DemuxerContext *in_ctx,
|
||||
Dav1dContext *c, Dav1dData *data)
|
||||
{
|
||||
int res = 0;
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
if (!rd_ctx->seek)
|
||||
goto out;
|
||||
int64_t seek = rd_ctx->seek * 1000000000ULL;
|
||||
uint64_t pts = TS_TO_PTS(rd_ctx->current_ts);
|
||||
pts = ((int64_t)pts > -seek) ? pts + seek : 0;
|
||||
int end = pts >= FRAME_OFFSET_TO_PTS(rd_ctx->total);
|
||||
if (end)
|
||||
pts = FRAME_OFFSET_TO_PTS(rd_ctx->total - 1);
|
||||
uint64_t target_pts = pts;
|
||||
dav1d_flush(c);
|
||||
uint64_t shift = FRAME_OFFSET_TO_PTS(5);
|
||||
while (1) {
|
||||
if (shift > pts)
|
||||
shift = pts;
|
||||
if ((res = input_seek(in_ctx, pts - shift)))
|
||||
goto out;
|
||||
Dav1dSequenceHeader seq;
|
||||
uint64_t cur_pts;
|
||||
do {
|
||||
if ((res = input_read(in_ctx, data)))
|
||||
break;
|
||||
cur_pts = TS_TO_PTS(data->m.timestamp);
|
||||
res = dav1d_parse_sequence_header(&seq, data->data, data->sz);
|
||||
} while (res && cur_pts < pts);
|
||||
if (!res && cur_pts <= pts)
|
||||
break;
|
||||
if (shift > pts)
|
||||
shift = pts;
|
||||
pts -= shift;
|
||||
}
|
||||
if (!res) {
|
||||
pts = TS_TO_PTS(data->m.timestamp);
|
||||
while (pts < target_pts) {
|
||||
Dav1dPicture *p;
|
||||
if ((res = decode_frame(&p, c, data, in_ctx)))
|
||||
break;
|
||||
if (p) {
|
||||
pts = TS_TO_PTS(p->m.timestamp);
|
||||
if (pts < target_pts)
|
||||
destroy_pic(p);
|
||||
else {
|
||||
dp_fifo_push(rd_ctx->fifo, p);
|
||||
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME;
|
||||
dp_rd_ctx_post_event(rd_ctx, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
rd_ctx->last_ts = data->m.timestamp - rd_ctx->spf / rd_ctx->timebase;
|
||||
rd_ctx->current_ts = data->m.timestamp;
|
||||
}
|
||||
}
|
||||
out:
|
||||
rd_ctx->paused = rd_ctx->user_paused;
|
||||
if (!rd_ctx->paused && rd_ctx->seek) {
|
||||
uint32_t now = SDL_GetTicks();
|
||||
rd_ctx->pause_time += now - rd_ctx->pause_start;
|
||||
rd_ctx->pause_start = 0;
|
||||
rd_ctx->last_ticks = now;
|
||||
}
|
||||
rd_ctx->seek = 0;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
if (res)
|
||||
fprintf(stderr, "Error seeking, aborting\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate decoder thread (async)
|
||||
*/
|
||||
static void dp_rd_ctx_request_shutdown(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
rd_ctx->dec_should_terminate = 1;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query state of decoder shutdown request
|
||||
*/
|
||||
static int dp_rd_ctx_should_terminate(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
ret = rd_ctx->dec_should_terminate;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the currently available texture
|
||||
*
|
||||
* Renders the currently available texture, if any.
|
||||
*/
|
||||
static void dp_rd_ctx_render(Dav1dPlayRenderContext *rd_ctx)
|
||||
{
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
// Calculate time since last frame was received
|
||||
uint32_t ticks_now = SDL_GetTicks();
|
||||
uint32_t ticks_diff = (rd_ctx->last_ticks != 0) ? ticks_now - rd_ctx->last_ticks : 0;
|
||||
|
||||
// Calculate when to display the frame
|
||||
int64_t ts_diff = rd_ctx->current_ts - rd_ctx->last_ts;
|
||||
int32_t pts_diff = (ts_diff * rd_ctx->timebase) * 1000.0 + .5;
|
||||
int32_t wait_time = pts_diff - ticks_diff;
|
||||
|
||||
// In untimed mode, simply don't wait
|
||||
if (rd_ctx->settings.untimed)
|
||||
wait_time = 0;
|
||||
|
||||
// This way of timing the playback is not accurate, as there is no guarantee
|
||||
// that SDL_Delay will wait for exactly the requested amount of time so in a
|
||||
// accurate player this would need to be done in a better way.
|
||||
if (wait_time > 0) {
|
||||
SDL_Delay(wait_time);
|
||||
} else if (wait_time < -10 && !rd_ctx->paused) { // Do not warn for minor time drifts
|
||||
fprintf(stderr, "Frame displayed %f seconds too late\n", wait_time / 1000.0);
|
||||
}
|
||||
|
||||
renderer_info->render(rd_ctx->rd_priv, &rd_ctx->settings);
|
||||
|
||||
rd_ctx->last_ts = rd_ctx->current_ts;
|
||||
rd_ctx->last_ticks = SDL_GetTicks();
|
||||
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
}
|
||||
|
||||
static int decode_frame(Dav1dPicture **p, Dav1dContext *c,
|
||||
Dav1dData *data, DemuxerContext *in_ctx)
|
||||
{
|
||||
int res;
|
||||
// Send data packets we got from the demuxer to dav1d
|
||||
if ((res = dav1d_send_data(c, data)) < 0) {
|
||||
// On EAGAIN, dav1d can not consume more data and
|
||||
// dav1d_get_picture needs to be called first, which
|
||||
// will happen below, so just keep going in that case
|
||||
// and do not error out.
|
||||
if (res != DAV1D_ERR(EAGAIN)) {
|
||||
dav1d_data_unref(data);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
*p = calloc(1, sizeof(**p));
|
||||
// Try to get a decoded frame
|
||||
if ((res = dav1d_get_picture(c, *p)) < 0) {
|
||||
// In all error cases, even EAGAIN, p needs to be freed as
|
||||
// it is never added to the queue and would leak.
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
// On EAGAIN, it means dav1d has not enough data to decode
|
||||
// therefore this is not a decoding error but just means
|
||||
// we need to feed it more data, which happens in the next
|
||||
// run of the decoder loop.
|
||||
if (res != DAV1D_ERR(EAGAIN))
|
||||
goto err;
|
||||
}
|
||||
return data->sz == 0 ? input_read(in_ctx, data) : 0;
|
||||
err:
|
||||
fprintf(stderr, "Error decoding frame: %s\n",
|
||||
strerror(-res));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline void destroy_pic(void *a)
|
||||
{
|
||||
Dav1dPicture *p = (Dav1dPicture *)a;
|
||||
dav1d_picture_unref(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* Decoder thread "main" function */
|
||||
static int decoder_thread_main(void *cookie)
|
||||
{
|
||||
Dav1dPlayRenderContext *rd_ctx = cookie;
|
||||
|
||||
Dav1dPicture *p;
|
||||
Dav1dContext *c = NULL;
|
||||
Dav1dData data;
|
||||
DemuxerContext *in_ctx = NULL;
|
||||
int res = 0;
|
||||
unsigned total, timebase[2], fps[2];
|
||||
|
||||
Dav1dPlaySettings settings = rd_ctx->settings;
|
||||
|
||||
if ((res = input_open(&in_ctx, "ivf",
|
||||
settings.inputfile,
|
||||
fps, &total, timebase)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open demuxer\n");
|
||||
res = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rd_ctx->timebase = (double)timebase[1] / timebase[0];
|
||||
rd_ctx->spf = (double)fps[1] / fps[0];
|
||||
rd_ctx->total = total;
|
||||
|
||||
if ((res = dav1d_open(&c, &rd_ctx->lib_settings))) {
|
||||
fprintf(stderr, "Failed opening dav1d decoder\n");
|
||||
res = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((res = input_read(in_ctx, &data)) < 0) {
|
||||
fprintf(stderr, "Failed demuxing input\n");
|
||||
res = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Decoder loop
|
||||
while (1) {
|
||||
if (dp_rd_ctx_should_terminate(rd_ctx) ||
|
||||
(res = dp_rd_ctx_handle_seek(rd_ctx, in_ctx, c, &data)) ||
|
||||
(res = decode_frame(&p, c, &data, in_ctx)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (p) {
|
||||
// Queue frame
|
||||
SDL_LockMutex(rd_ctx->lock);
|
||||
int seek = rd_ctx->seek;
|
||||
SDL_UnlockMutex(rd_ctx->lock);
|
||||
if (!seek) {
|
||||
dp_fifo_push(rd_ctx->fifo, p);
|
||||
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
|
||||
dp_rd_ctx_post_event(rd_ctx, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release remaining data
|
||||
if (data.sz > 0)
|
||||
dav1d_data_unref(&data);
|
||||
// Do not drain in case an error occured and caused us to leave the
|
||||
// decoding loop early.
|
||||
if (res < 0)
|
||||
goto cleanup;
|
||||
|
||||
// Drain decoder
|
||||
// When there is no more data to feed to the decoder, for example
|
||||
// because the file ended, we still need to request pictures, as
|
||||
// even though we do not have more data, there can be frames decoded
|
||||
// from data we sent before. So we need to call dav1d_get_picture until
|
||||
// we get an EAGAIN error.
|
||||
do {
|
||||
if (dp_rd_ctx_should_terminate(rd_ctx))
|
||||
break;
|
||||
p = calloc(1, sizeof(*p));
|
||||
res = dav1d_get_picture(c, p);
|
||||
if (res < 0) {
|
||||
free(p);
|
||||
if (res != DAV1D_ERR(EAGAIN)) {
|
||||
fprintf(stderr, "Error decoding frame: %s\n",
|
||||
strerror(-res));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Queue frame
|
||||
dp_fifo_push(rd_ctx->fifo, p);
|
||||
uint32_t type = rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME;
|
||||
dp_rd_ctx_post_event(rd_ctx, type);
|
||||
}
|
||||
} while (res != DAV1D_ERR(EAGAIN));
|
||||
|
||||
cleanup:
|
||||
dp_rd_ctx_post_event(rd_ctx, rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT);
|
||||
|
||||
if (in_ctx)
|
||||
input_close(in_ctx);
|
||||
if (c)
|
||||
dav1d_close(&c);
|
||||
|
||||
return (res != DAV1D_ERR(EAGAIN) && res < 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
SDL_Thread *decoder_thread;
|
||||
|
||||
// Check for version mismatch between library and tool
|
||||
const char *version = dav1d_version();
|
||||
if (strcmp(version, DAV1D_VERSION)) {
|
||||
fprintf(stderr, "Version mismatch (library: %s, executable: %s)\n",
|
||||
version, DAV1D_VERSION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Init SDL2 library
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
|
||||
return 10;
|
||||
|
||||
// Create render context
|
||||
Dav1dPlayRenderContext *rd_ctx = dp_rd_ctx_create(argc, argv);
|
||||
if (rd_ctx == NULL) {
|
||||
fprintf(stderr, "Failed creating render context\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (rd_ctx->settings.zerocopy) {
|
||||
if (renderer_info->alloc_pic) {
|
||||
rd_ctx->lib_settings.allocator = (Dav1dPicAllocator) {
|
||||
.cookie = rd_ctx->rd_priv,
|
||||
.alloc_picture_callback = renderer_info->alloc_pic,
|
||||
.release_picture_callback = renderer_info->release_pic,
|
||||
};
|
||||
} else {
|
||||
fprintf(stderr, "--zerocopy unsupported by selected renderer\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (rd_ctx->settings.gpugrain) {
|
||||
if (renderer_info->supports_gpu_grain) {
|
||||
rd_ctx->lib_settings.apply_grain = 0;
|
||||
} else {
|
||||
fprintf(stderr, "--gpugrain unsupported by selected renderer\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Start decoder thread
|
||||
decoder_thread = SDL_CreateThread(decoder_thread_main, "Decoder thread", rd_ctx);
|
||||
|
||||
// Main loop
|
||||
#define NUM_MAX_EVENTS 8
|
||||
SDL_Event events[NUM_MAX_EVENTS];
|
||||
int num_frame_events = 0;
|
||||
uint32_t start_time = 0, n_out = 0;
|
||||
while (1) {
|
||||
int num_events = 0;
|
||||
SDL_WaitEvent(NULL);
|
||||
while (num_events < NUM_MAX_EVENTS && SDL_PollEvent(&events[num_events++]))
|
||||
break;
|
||||
for (int i = 0; i < num_events; ++i) {
|
||||
SDL_Event *e = &events[i];
|
||||
if (e->type == SDL_QUIT) {
|
||||
dp_rd_ctx_request_shutdown(rd_ctx);
|
||||
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
|
||||
SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME);
|
||||
SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME);
|
||||
num_frame_events = 0;
|
||||
} else if (e->type == SDL_WINDOWEVENT) {
|
||||
if (e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
// TODO: Handle window resizes
|
||||
} else if(e->window.event == SDL_WINDOWEVENT_EXPOSED) {
|
||||
dp_rd_ctx_render(rd_ctx);
|
||||
}
|
||||
} else if (e->type == SDL_KEYDOWN) {
|
||||
SDL_KeyboardEvent *kbde = (SDL_KeyboardEvent *)e;
|
||||
if (kbde->keysym.sym == SDLK_SPACE) {
|
||||
dp_rd_ctx_toggle_pause(rd_ctx);
|
||||
} else if (kbde->keysym.sym == SDLK_LEFT ||
|
||||
kbde->keysym.sym == SDLK_RIGHT)
|
||||
{
|
||||
if (kbde->keysym.sym == SDLK_LEFT)
|
||||
dp_rd_ctx_seek(rd_ctx, -5);
|
||||
else if (kbde->keysym.sym == SDLK_RIGHT)
|
||||
dp_rd_ctx_seek(rd_ctx, +5);
|
||||
dp_fifo_flush(rd_ctx->fifo, destroy_pic);
|
||||
SDL_FlushEvent(rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME);
|
||||
num_frame_events = 0;
|
||||
}
|
||||
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_NEW_FRAME) {
|
||||
num_frame_events++;
|
||||
// Store current ticks for stats calculation
|
||||
if (start_time == 0)
|
||||
start_time = SDL_GetTicks();
|
||||
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_SEEK_FRAME) {
|
||||
// Dequeue frame and update the render context with it
|
||||
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
|
||||
// Do not update textures during termination
|
||||
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
|
||||
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
|
||||
n_out++;
|
||||
}
|
||||
destroy_pic(p);
|
||||
} else if (e->type == rd_ctx->event_types + DAV1D_EVENT_DEC_QUIT) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (num_frame_events && !dp_rd_ctx_is_paused(rd_ctx)) {
|
||||
// Dequeue frame and update the render context with it
|
||||
Dav1dPicture *p = dp_fifo_shift(rd_ctx->fifo);
|
||||
// Do not update textures during termination
|
||||
if (!dp_rd_ctx_should_terminate(rd_ctx)) {
|
||||
dp_rd_ctx_update_with_dav1d_picture(rd_ctx, p);
|
||||
dp_rd_ctx_render(rd_ctx);
|
||||
n_out++;
|
||||
}
|
||||
destroy_pic(p);
|
||||
num_frame_events--;
|
||||
}
|
||||
}
|
||||
|
||||
out:;
|
||||
// Print stats
|
||||
uint32_t time_ms = SDL_GetTicks() - start_time - rd_ctx->pause_time;
|
||||
printf("Decoded %u frames in %d seconds, avg %.02f fps\n",
|
||||
n_out, time_ms / 1000, n_out/ (time_ms / 1000.0));
|
||||
|
||||
int decoder_ret = 0;
|
||||
SDL_WaitThread(decoder_thread, &decoder_ret);
|
||||
dp_rd_ctx_destroy(rd_ctx);
|
||||
return decoder_ret;
|
||||
}
|
147
third_party/dav1d/examples/dp_fifo.c
vendored
147
third_party/dav1d/examples/dp_fifo.c
vendored
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019, VideoLAN and dav1d authors
|
||||
* 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 <SDL.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "dp_fifo.h"
|
||||
|
||||
// FIFO structure
|
||||
struct dp_fifo
|
||||
{
|
||||
SDL_mutex *lock;
|
||||
SDL_cond *cond_change;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
void **entries;
|
||||
int push_wait;
|
||||
int flush;
|
||||
};
|
||||
|
||||
|
||||
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity)
|
||||
{
|
||||
Dav1dPlayPtrFifo *fifo;
|
||||
|
||||
assert(capacity > 0);
|
||||
if (capacity <= 0)
|
||||
return NULL;
|
||||
|
||||
fifo = malloc(sizeof(*fifo));
|
||||
if (fifo == NULL)
|
||||
return NULL;
|
||||
|
||||
fifo->capacity = capacity;
|
||||
fifo->count = 0;
|
||||
fifo->push_wait = 0;
|
||||
fifo->flush = 0;
|
||||
|
||||
fifo->lock = SDL_CreateMutex();
|
||||
if (fifo->lock == NULL) {
|
||||
free(fifo);
|
||||
return NULL;
|
||||
}
|
||||
fifo->cond_change = SDL_CreateCond();
|
||||
if (fifo->cond_change == NULL) {
|
||||
SDL_DestroyMutex(fifo->lock);
|
||||
free(fifo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fifo->entries = calloc(capacity, sizeof(void*));
|
||||
if (fifo->entries == NULL) {
|
||||
dp_fifo_destroy(fifo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fifo;
|
||||
}
|
||||
|
||||
// Destroy FIFO
|
||||
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo)
|
||||
{
|
||||
assert(fifo->count == 0);
|
||||
SDL_DestroyMutex(fifo->lock);
|
||||
SDL_DestroyCond(fifo->cond_change);
|
||||
free(fifo->entries);
|
||||
free(fifo);
|
||||
}
|
||||
|
||||
// Push to FIFO
|
||||
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element)
|
||||
{
|
||||
SDL_LockMutex(fifo->lock);
|
||||
while (fifo->count == fifo->capacity) {
|
||||
fifo->push_wait = 1;
|
||||
SDL_CondWait(fifo->cond_change, fifo->lock);
|
||||
fifo->push_wait = 0;
|
||||
if (fifo->flush) {
|
||||
SDL_CondSignal(fifo->cond_change);
|
||||
SDL_UnlockMutex(fifo->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fifo->entries[fifo->count++] = element;
|
||||
if (fifo->count == 1)
|
||||
SDL_CondSignal(fifo->cond_change);
|
||||
SDL_UnlockMutex(fifo->lock);
|
||||
}
|
||||
|
||||
// Helper that shifts the FIFO array
|
||||
static void *dp_fifo_array_shift(void **arr, size_t len)
|
||||
{
|
||||
void *shifted_element = arr[0];
|
||||
for (size_t i = 1; i < len; ++i)
|
||||
arr[i-1] = arr[i];
|
||||
return shifted_element;
|
||||
}
|
||||
|
||||
// Get item from FIFO
|
||||
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo)
|
||||
{
|
||||
SDL_LockMutex(fifo->lock);
|
||||
while (fifo->count == 0)
|
||||
SDL_CondWait(fifo->cond_change, fifo->lock);
|
||||
void *res = dp_fifo_array_shift(fifo->entries, fifo->count--);
|
||||
if (fifo->count == fifo->capacity - 1)
|
||||
SDL_CondSignal(fifo->cond_change);
|
||||
SDL_UnlockMutex(fifo->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *))
|
||||
{
|
||||
SDL_LockMutex(fifo->lock);
|
||||
fifo->flush = 1;
|
||||
if (fifo->push_wait) {
|
||||
SDL_CondSignal(fifo->cond_change);
|
||||
SDL_CondWait(fifo->cond_change, fifo->lock);
|
||||
}
|
||||
while (fifo->count)
|
||||
destroy_elem(fifo->entries[--fifo->count]);
|
||||
fifo->flush = 0;
|
||||
SDL_UnlockMutex(fifo->lock);
|
||||
}
|
63
third_party/dav1d/examples/dp_fifo.h
vendored
63
third_party/dav1d/examples/dp_fifo.h
vendored
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019, VideoLAN and dav1d authors
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dav1dPlay FIFO helper
|
||||
*/
|
||||
|
||||
typedef struct dp_fifo Dav1dPlayPtrFifo;
|
||||
|
||||
/* Create a FIFO
|
||||
*
|
||||
* Creates a FIFO with the given capacity.
|
||||
* If the capacity is reached, new inserts into the FIFO
|
||||
* will block until enough space is available again.
|
||||
*/
|
||||
Dav1dPlayPtrFifo *dp_fifo_create(size_t capacity);
|
||||
|
||||
/* Destroy a FIFO
|
||||
*
|
||||
* The FIFO must be empty before it is destroyed!
|
||||
*/
|
||||
void dp_fifo_destroy(Dav1dPlayPtrFifo *fifo);
|
||||
|
||||
/* Shift FIFO
|
||||
*
|
||||
* Return the first item from the FIFO, thereby removing it from
|
||||
* the FIFO and making room for new entries.
|
||||
*/
|
||||
void *dp_fifo_shift(Dav1dPlayPtrFifo *fifo);
|
||||
|
||||
/* Push to FIFO
|
||||
*
|
||||
* Add an item to the end of the FIFO.
|
||||
* If the FIFO is full, this call will block until there is again enough
|
||||
* space in the FIFO, so calling this from the "consumer" thread if no
|
||||
* other thread will call dp_fifo_shift will lead to a deadlock.
|
||||
*/
|
||||
void dp_fifo_push(Dav1dPlayPtrFifo *fifo, void *element);
|
||||
|
||||
void dp_fifo_flush(Dav1dPlayPtrFifo *fifo, void (*destroy_elem)(void *));
|
135
third_party/dav1d/examples/dp_renderer.h
vendored
135
third_party/dav1d/examples/dp_renderer.h
vendored
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020, VideoLAN and dav1d authors
|
||||
* 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 <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dav1d/dav1d.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#ifdef HAVE_PLACEBO
|
||||
# include <libplacebo/config.h>
|
||||
#endif
|
||||
|
||||
// Check libplacebo Vulkan rendering
|
||||
#if defined(HAVE_VULKAN) && defined(SDL_VIDEO_VULKAN)
|
||||
# if defined(PL_HAVE_VULKAN) && PL_HAVE_VULKAN
|
||||
# define HAVE_RENDERER_PLACEBO
|
||||
# define HAVE_PLACEBO_VULKAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Check libplacebo OpenGL rendering
|
||||
#if defined(PL_HAVE_OPENGL) && PL_HAVE_OPENGL
|
||||
# define HAVE_RENDERER_PLACEBO
|
||||
# define HAVE_PLACEBO_OPENGL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Settings structure
|
||||
* Hold all settings available for the player,
|
||||
* this is usually filled by parsing arguments
|
||||
* from the console.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *inputfile;
|
||||
const char *renderer_name;
|
||||
int highquality;
|
||||
int untimed;
|
||||
int zerocopy;
|
||||
int gpugrain;
|
||||
} Dav1dPlaySettings;
|
||||
|
||||
#define WINDOW_WIDTH 910
|
||||
#define WINDOW_HEIGHT 512
|
||||
|
||||
enum {
|
||||
DAV1D_EVENT_NEW_FRAME,
|
||||
DAV1D_EVENT_SEEK_FRAME,
|
||||
DAV1D_EVENT_DEC_QUIT
|
||||
};
|
||||
|
||||
/**
|
||||
* Renderer info
|
||||
*/
|
||||
typedef struct rdr_info
|
||||
{
|
||||
// Renderer name
|
||||
const char *name;
|
||||
// Cookie passed to the renderer implementation callbacks
|
||||
void *cookie;
|
||||
// Callback to create the renderer
|
||||
void* (*create_renderer)();
|
||||
// Callback to destroy the renderer
|
||||
void (*destroy_renderer)(void *cookie);
|
||||
// Callback to the render function that renders a prevously sent frame
|
||||
void (*render)(void *cookie, const Dav1dPlaySettings *settings);
|
||||
// Callback to the send frame function, _may_ also unref dav1d_pic!
|
||||
int (*update_frame)(void *cookie, Dav1dPicture *dav1d_pic,
|
||||
const Dav1dPlaySettings *settings);
|
||||
// Callback for alloc/release pictures (optional)
|
||||
int (*alloc_pic)(Dav1dPicture *pic, void *cookie);
|
||||
void (*release_pic)(Dav1dPicture *pic, void *cookie);
|
||||
// Whether or not this renderer can apply on-GPU film grain synthesis
|
||||
int supports_gpu_grain;
|
||||
} Dav1dPlayRenderInfo;
|
||||
|
||||
extern const Dav1dPlayRenderInfo rdr_placebo_vk;
|
||||
extern const Dav1dPlayRenderInfo rdr_placebo_gl;
|
||||
extern const Dav1dPlayRenderInfo rdr_sdl;
|
||||
|
||||
// Available renderes ordered by priority
|
||||
static const Dav1dPlayRenderInfo* const dp_renderers[] = {
|
||||
&rdr_placebo_vk,
|
||||
&rdr_placebo_gl,
|
||||
&rdr_sdl,
|
||||
};
|
||||
|
||||
static inline const Dav1dPlayRenderInfo *dp_get_renderer(const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < (sizeof(dp_renderers)/sizeof(*dp_renderers)); ++i)
|
||||
{
|
||||
if (dp_renderers[i]->name == NULL)
|
||||
continue;
|
||||
|
||||
if (name == NULL || strcmp(name, dp_renderers[i]->name) == 0) {
|
||||
return dp_renderers[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline SDL_Window *dp_create_sdl_window(int window_flags)
|
||||
{
|
||||
SDL_Window *win;
|
||||
window_flags |= SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
win = SDL_CreateWindow("Dav1dPlay", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
WINDOW_WIDTH, WINDOW_HEIGHT, window_flags);
|
||||
SDL_SetWindowResizable(win, SDL_TRUE);
|
||||
|
||||
return win;
|
||||
}
|
423
third_party/dav1d/examples/dp_renderer_placebo.c
vendored
423
third_party/dav1d/examples/dp_renderer_placebo.c
vendored
@ -1,423 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020, VideoLAN and dav1d authors
|
||||
* 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 "dp_renderer.h"
|
||||
|
||||
#ifdef HAVE_RENDERER_PLACEBO
|
||||
#include <assert.h>
|
||||
|
||||
#include <libplacebo/renderer.h>
|
||||
#include <libplacebo/utils/dav1d.h>
|
||||
|
||||
#ifdef HAVE_PLACEBO_VULKAN
|
||||
# include <libplacebo/vulkan.h>
|
||||
# include <SDL_vulkan.h>
|
||||
#endif
|
||||
#ifdef HAVE_PLACEBO_OPENGL
|
||||
# include <libplacebo/opengl.h>
|
||||
# include <SDL_opengl.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Renderer context for libplacebo
|
||||
*/
|
||||
typedef struct renderer_priv_ctx
|
||||
{
|
||||
// SDL window
|
||||
SDL_Window *win;
|
||||
// Placebo context
|
||||
struct pl_context *ctx;
|
||||
// Placebo renderer
|
||||
struct pl_renderer *renderer;
|
||||
#ifdef HAVE_PLACEBO_VULKAN
|
||||
// Placebo Vulkan handle
|
||||
const struct pl_vulkan *vk;
|
||||
// Placebo Vulkan instance
|
||||
const struct pl_vk_inst *vk_inst;
|
||||
// Vulkan surface
|
||||
VkSurfaceKHR surf;
|
||||
#endif
|
||||
#ifdef HAVE_PLACEBO_OPENGL
|
||||
// Placebo OpenGL handle
|
||||
const struct pl_opengl *gl;
|
||||
#endif
|
||||
// Placebo GPU
|
||||
const struct pl_gpu *gpu;
|
||||
// Placebo swapchain
|
||||
const struct pl_swapchain *swapchain;
|
||||
// Lock protecting access to the texture
|
||||
SDL_mutex *lock;
|
||||
// Image to render, and planes backing them
|
||||
struct pl_frame image;
|
||||
const struct pl_tex *plane_tex[3];
|
||||
} Dav1dPlayRendererPrivateContext;
|
||||
|
||||
static Dav1dPlayRendererPrivateContext*
|
||||
placebo_renderer_create_common(int window_flags)
|
||||
{
|
||||
// Create Window
|
||||
SDL_Window *sdlwin = dp_create_sdl_window(window_flags | SDL_WINDOW_RESIZABLE);
|
||||
if (sdlwin == NULL)
|
||||
return NULL;
|
||||
|
||||
// Alloc
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
|
||||
if (rd_priv_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*rd_priv_ctx = (Dav1dPlayRendererPrivateContext) {0};
|
||||
rd_priv_ctx->win = sdlwin;
|
||||
|
||||
// Init libplacebo
|
||||
rd_priv_ctx->ctx = pl_context_create(PL_API_VER, &(struct pl_context_params) {
|
||||
.log_cb = pl_log_color,
|
||||
#ifndef NDEBUG
|
||||
.log_level = PL_LOG_DEBUG,
|
||||
#else
|
||||
.log_level = PL_LOG_WARN,
|
||||
#endif
|
||||
});
|
||||
if (rd_priv_ctx->ctx == NULL) {
|
||||
free(rd_priv_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create Mutex
|
||||
rd_priv_ctx->lock = SDL_CreateMutex();
|
||||
if (rd_priv_ctx->lock == NULL) {
|
||||
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
|
||||
pl_context_destroy(&(rd_priv_ctx->ctx));
|
||||
free(rd_priv_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rd_priv_ctx;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PLACEBO_OPENGL
|
||||
static void *placebo_renderer_create_gl()
|
||||
{
|
||||
SDL_Window *sdlwin = NULL;
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
|
||||
// Common init
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
|
||||
placebo_renderer_create_common(SDL_WINDOW_OPENGL);
|
||||
|
||||
if (rd_priv_ctx == NULL)
|
||||
return NULL;
|
||||
sdlwin = rd_priv_ctx->win;
|
||||
|
||||
// Init OpenGL
|
||||
struct pl_opengl_params params = pl_opengl_default_params;
|
||||
# ifndef NDEBUG
|
||||
params.debug = true;
|
||||
# endif
|
||||
|
||||
SDL_GLContext glcontext = SDL_GL_CreateContext(sdlwin);
|
||||
SDL_GL_MakeCurrent(sdlwin, glcontext);
|
||||
|
||||
rd_priv_ctx->gl = pl_opengl_create(rd_priv_ctx->ctx, ¶ms);
|
||||
if (!rd_priv_ctx->gl) {
|
||||
fprintf(stderr, "Failed creating opengl device!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
rd_priv_ctx->swapchain = pl_opengl_create_swapchain(rd_priv_ctx->gl,
|
||||
&(struct pl_opengl_swapchain_params) {
|
||||
.swap_buffers = (void (*)(void *)) SDL_GL_SwapWindow,
|
||||
.priv = sdlwin,
|
||||
});
|
||||
|
||||
if (!rd_priv_ctx->swapchain) {
|
||||
fprintf(stderr, "Failed creating opengl swapchain!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
|
||||
SDL_GL_GetDrawableSize(sdlwin, &w, &h);
|
||||
|
||||
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
|
||||
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
rd_priv_ctx->gpu = rd_priv_ctx->gl->gpu;
|
||||
|
||||
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
|
||||
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
|
||||
|
||||
return rd_priv_ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PLACEBO_VULKAN
|
||||
static void *placebo_renderer_create_vk()
|
||||
{
|
||||
SDL_Window *sdlwin = NULL;
|
||||
|
||||
// Common init
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx =
|
||||
placebo_renderer_create_common(SDL_WINDOW_VULKAN);
|
||||
|
||||
if (rd_priv_ctx == NULL)
|
||||
return NULL;
|
||||
sdlwin = rd_priv_ctx->win;
|
||||
|
||||
// Init Vulkan
|
||||
unsigned num = 0;
|
||||
if (!SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, NULL)) {
|
||||
fprintf(stderr, "Failed enumerating Vulkan extensions: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char **extensions = malloc(num * sizeof(const char *));
|
||||
assert(extensions);
|
||||
|
||||
SDL_bool ok = SDL_Vulkan_GetInstanceExtensions(sdlwin, &num, extensions);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Failed getting Vk instance extensions\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
printf("Requesting %d additional Vulkan extensions:\n", num);
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
printf(" %s\n", extensions[i]);
|
||||
}
|
||||
|
||||
struct pl_vk_inst_params iparams = pl_vk_inst_default_params;
|
||||
iparams.extensions = extensions;
|
||||
iparams.num_extensions = num;
|
||||
|
||||
rd_priv_ctx->vk_inst = pl_vk_inst_create(rd_priv_ctx->ctx, &iparams);
|
||||
if (!rd_priv_ctx->vk_inst) {
|
||||
fprintf(stderr, "Failed creating Vulkan instance!\n");
|
||||
exit(1);
|
||||
}
|
||||
free(extensions);
|
||||
|
||||
if (!SDL_Vulkan_CreateSurface(sdlwin, rd_priv_ctx->vk_inst->instance, &rd_priv_ctx->surf)) {
|
||||
fprintf(stderr, "Failed creating vulkan surface: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct pl_vulkan_params params = pl_vulkan_default_params;
|
||||
params.instance = rd_priv_ctx->vk_inst->instance;
|
||||
params.surface = rd_priv_ctx->surf;
|
||||
params.allow_software = true;
|
||||
|
||||
rd_priv_ctx->vk = pl_vulkan_create(rd_priv_ctx->ctx, ¶ms);
|
||||
if (!rd_priv_ctx->vk) {
|
||||
fprintf(stderr, "Failed creating vulkan device!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
// Create swapchain
|
||||
rd_priv_ctx->swapchain = pl_vulkan_create_swapchain(rd_priv_ctx->vk,
|
||||
&(struct pl_vulkan_swapchain_params) {
|
||||
.surface = rd_priv_ctx->surf,
|
||||
.present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR,
|
||||
});
|
||||
|
||||
if (!rd_priv_ctx->swapchain) {
|
||||
fprintf(stderr, "Failed creating vulkan swapchain!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int w = WINDOW_WIDTH, h = WINDOW_HEIGHT;
|
||||
if (!pl_swapchain_resize(rd_priv_ctx->swapchain, &w, &h)) {
|
||||
fprintf(stderr, "Failed resizing vulkan swapchain!\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
rd_priv_ctx->gpu = rd_priv_ctx->vk->gpu;
|
||||
|
||||
if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
|
||||
printf("Note: window dimensions differ (got %dx%d)\n", w, h);
|
||||
|
||||
return rd_priv_ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void placebo_renderer_destroy(void *cookie)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
pl_renderer_destroy(&(rd_priv_ctx->renderer));
|
||||
pl_swapchain_destroy(&(rd_priv_ctx->swapchain));
|
||||
for (int i = 0; i < 3; i++)
|
||||
pl_tex_destroy(rd_priv_ctx->gpu, &(rd_priv_ctx->plane_tex[i]));
|
||||
|
||||
#ifdef HAVE_PLACEBO_VULKAN
|
||||
if (rd_priv_ctx->vk) {
|
||||
pl_vulkan_destroy(&(rd_priv_ctx->vk));
|
||||
vkDestroySurfaceKHR(rd_priv_ctx->vk_inst->instance, rd_priv_ctx->surf, NULL);
|
||||
pl_vk_inst_destroy(&(rd_priv_ctx->vk_inst));
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_PLACEBO_OPENGL
|
||||
if (rd_priv_ctx->gl)
|
||||
pl_opengl_destroy(&(rd_priv_ctx->gl));
|
||||
#endif
|
||||
|
||||
SDL_DestroyWindow(rd_priv_ctx->win);
|
||||
|
||||
pl_context_destroy(&(rd_priv_ctx->ctx));
|
||||
}
|
||||
|
||||
static void placebo_render(void *cookie, const Dav1dPlaySettings *settings)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_LockMutex(rd_priv_ctx->lock);
|
||||
if (!rd_priv_ctx->image.num_planes) {
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare rendering
|
||||
if (rd_priv_ctx->renderer == NULL) {
|
||||
rd_priv_ctx->renderer = pl_renderer_create(rd_priv_ctx->ctx, rd_priv_ctx->gpu);
|
||||
}
|
||||
|
||||
struct pl_swapchain_frame frame;
|
||||
bool ok = pl_swapchain_start_frame(rd_priv_ctx->swapchain, &frame);
|
||||
if (!ok) {
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pl_render_params render_params = {0};
|
||||
if (settings->highquality)
|
||||
render_params = pl_render_default_params;
|
||||
|
||||
struct pl_frame target;
|
||||
pl_frame_from_swapchain(&target, &frame);
|
||||
pl_rect2df_aspect_copy(&target.crop, &rd_priv_ctx->image.crop, 0.0);
|
||||
if (pl_frame_is_cropped(&target))
|
||||
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 0.0 });
|
||||
|
||||
if (!pl_render_image(rd_priv_ctx->renderer, &rd_priv_ctx->image, &target, &render_params)) {
|
||||
fprintf(stderr, "Failed rendering frame!\n");
|
||||
pl_tex_clear(rd_priv_ctx->gpu, frame.fbo, (float[4]){ 1.0 });
|
||||
}
|
||||
|
||||
ok = pl_swapchain_submit_frame(rd_priv_ctx->swapchain);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Failed submitting frame!\n");
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
pl_swapchain_swap_buffers(rd_priv_ctx->swapchain);
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
}
|
||||
|
||||
static int placebo_upload_image(void *cookie, Dav1dPicture *dav1d_pic,
|
||||
const Dav1dPlaySettings *settings)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *p = cookie;
|
||||
assert(p != NULL);
|
||||
int ret = 0;
|
||||
|
||||
if (!dav1d_pic)
|
||||
return ret;
|
||||
|
||||
struct pl_dav1d_upload_params params = {
|
||||
.picture = dav1d_pic,
|
||||
.film_grain = settings->gpugrain,
|
||||
.gpu_allocated = settings->zerocopy,
|
||||
.asynchronous = true,
|
||||
};
|
||||
|
||||
SDL_LockMutex(p->lock);
|
||||
if (!pl_upload_dav1dpicture(p->gpu, &p->image, p->plane_tex, ¶ms)) {
|
||||
fprintf(stderr, "Failed uploading planes!\n");
|
||||
p->image = (struct pl_frame) {0};
|
||||
ret = -1;
|
||||
}
|
||||
SDL_UnlockMutex(p->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int placebo_alloc_pic(Dav1dPicture *const pic, void *cookie)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_LockMutex(rd_priv_ctx->lock);
|
||||
int ret = pl_allocate_dav1dpicture(pic, rd_priv_ctx->gpu);
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void placebo_release_pic(Dav1dPicture *pic, void *cookie)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_LockMutex(rd_priv_ctx->lock);
|
||||
pl_release_dav1dpicture(pic, rd_priv_ctx->gpu);
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PLACEBO_VULKAN
|
||||
const Dav1dPlayRenderInfo rdr_placebo_vk = {
|
||||
.name = "placebo-vk",
|
||||
.create_renderer = placebo_renderer_create_vk,
|
||||
.destroy_renderer = placebo_renderer_destroy,
|
||||
.render = placebo_render,
|
||||
.update_frame = placebo_upload_image,
|
||||
.alloc_pic = placebo_alloc_pic,
|
||||
.release_pic = placebo_release_pic,
|
||||
.supports_gpu_grain = 1,
|
||||
};
|
||||
#else
|
||||
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PLACEBO_OPENGL
|
||||
const Dav1dPlayRenderInfo rdr_placebo_gl = {
|
||||
.name = "placebo-gl",
|
||||
.create_renderer = placebo_renderer_create_gl,
|
||||
.destroy_renderer = placebo_renderer_destroy,
|
||||
.render = placebo_render,
|
||||
.update_frame = placebo_upload_image,
|
||||
.supports_gpu_grain = 1,
|
||||
};
|
||||
#else
|
||||
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
|
||||
#endif
|
||||
|
||||
#else
|
||||
const Dav1dPlayRenderInfo rdr_placebo_vk = { NULL };
|
||||
const Dav1dPlayRenderInfo rdr_placebo_gl = { NULL };
|
||||
#endif
|
164
third_party/dav1d/examples/dp_renderer_sdl.c
vendored
164
third_party/dav1d/examples/dp_renderer_sdl.c
vendored
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020, VideoLAN and dav1d authors
|
||||
* 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 "dp_renderer.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* Renderer context for SDL
|
||||
*/
|
||||
typedef struct renderer_priv_ctx
|
||||
{
|
||||
// SDL window
|
||||
SDL_Window *win;
|
||||
// SDL renderer
|
||||
SDL_Renderer *renderer;
|
||||
// Lock protecting access to the texture
|
||||
SDL_mutex *lock;
|
||||
// Texture to render
|
||||
SDL_Texture *tex;
|
||||
} Dav1dPlayRendererPrivateContext;
|
||||
|
||||
static void *sdl_renderer_create()
|
||||
{
|
||||
SDL_Window *win = dp_create_sdl_window(0);
|
||||
if (win == NULL)
|
||||
return NULL;
|
||||
|
||||
// Alloc
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = malloc(sizeof(Dav1dPlayRendererPrivateContext));
|
||||
if (rd_priv_ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
rd_priv_ctx->win = win;
|
||||
|
||||
// Create renderer
|
||||
rd_priv_ctx->renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
|
||||
// Set scale quality
|
||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||
|
||||
// Create Mutex
|
||||
rd_priv_ctx->lock = SDL_CreateMutex();
|
||||
if (rd_priv_ctx->lock == NULL) {
|
||||
fprintf(stderr, "SDL_CreateMutex failed: %s\n", SDL_GetError());
|
||||
free(rd_priv_ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rd_priv_ctx->tex = NULL;
|
||||
|
||||
return rd_priv_ctx;
|
||||
}
|
||||
|
||||
static void sdl_renderer_destroy(void *cookie)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_DestroyRenderer(rd_priv_ctx->renderer);
|
||||
SDL_DestroyMutex(rd_priv_ctx->lock);
|
||||
free(rd_priv_ctx);
|
||||
}
|
||||
|
||||
static void sdl_render(void *cookie, const Dav1dPlaySettings *settings)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_LockMutex(rd_priv_ctx->lock);
|
||||
|
||||
if (rd_priv_ctx->tex == NULL) {
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
// Display the frame
|
||||
SDL_RenderClear(rd_priv_ctx->renderer);
|
||||
SDL_RenderCopy(rd_priv_ctx->renderer, rd_priv_ctx->tex, NULL, NULL);
|
||||
SDL_RenderPresent(rd_priv_ctx->renderer);
|
||||
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
}
|
||||
|
||||
static int sdl_update_texture(void *cookie, Dav1dPicture *dav1d_pic,
|
||||
const Dav1dPlaySettings *settings)
|
||||
{
|
||||
Dav1dPlayRendererPrivateContext *rd_priv_ctx = cookie;
|
||||
assert(rd_priv_ctx != NULL);
|
||||
|
||||
SDL_LockMutex(rd_priv_ctx->lock);
|
||||
|
||||
if (dav1d_pic == NULL) {
|
||||
rd_priv_ctx->tex = NULL;
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int width = dav1d_pic->p.w;
|
||||
int height = dav1d_pic->p.h;
|
||||
int tex_w = width;
|
||||
int tex_h = height;
|
||||
|
||||
enum Dav1dPixelLayout dav1d_layout = dav1d_pic->p.layout;
|
||||
|
||||
if (DAV1D_PIXEL_LAYOUT_I420 != dav1d_layout || dav1d_pic->p.bpc != 8) {
|
||||
fprintf(stderr, "Unsupported pixel format, only 8bit 420 supported so far.\n");
|
||||
exit(50);
|
||||
}
|
||||
|
||||
SDL_Texture *texture = rd_priv_ctx->tex;
|
||||
if (texture != NULL) {
|
||||
SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h);
|
||||
if (tex_w != width || tex_h != height) {
|
||||
SDL_DestroyTexture(texture);
|
||||
texture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (texture == NULL) {
|
||||
texture = SDL_CreateTexture(rd_priv_ctx->renderer, SDL_PIXELFORMAT_IYUV,
|
||||
SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
}
|
||||
|
||||
SDL_UpdateYUVTexture(texture, NULL,
|
||||
dav1d_pic->data[0], (int)dav1d_pic->stride[0], // Y
|
||||
dav1d_pic->data[1], (int)dav1d_pic->stride[1], // U
|
||||
dav1d_pic->data[2], (int)dav1d_pic->stride[1] // V
|
||||
);
|
||||
|
||||
rd_priv_ctx->tex = texture;
|
||||
SDL_UnlockMutex(rd_priv_ctx->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Dav1dPlayRenderInfo rdr_sdl = {
|
||||
.name = "sdl",
|
||||
.create_renderer = sdl_renderer_create,
|
||||
.destroy_renderer = sdl_renderer_destroy,
|
||||
.render = sdl_render,
|
||||
.update_frame = sdl_update_texture
|
||||
};
|
74
third_party/dav1d/examples/meson.build
vendored
74
third_party/dav1d/examples/meson.build
vendored
@ -1,74 +0,0 @@
|
||||
# Copyright © 2018, VideoLAN and dav1d authors
|
||||
# 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.
|
||||
|
||||
#
|
||||
# Build definition for the dav1d examples
|
||||
#
|
||||
|
||||
# Leave subdir if examples are disabled
|
||||
if not get_option('enable_examples')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
|
||||
# dav1d player sources
|
||||
dav1dplay_sources = files(
|
||||
'dav1dplay.c',
|
||||
'dp_fifo.c',
|
||||
'dp_renderer_placebo.c',
|
||||
'dp_renderer_sdl.c',
|
||||
)
|
||||
|
||||
sdl2_dependency = dependency('sdl2', version: '>= 2.0.1', required: true)
|
||||
|
||||
if sdl2_dependency.found()
|
||||
dav1dplay_deps = [sdl2_dependency, libm_dependency]
|
||||
dav1dplay_cflags = []
|
||||
|
||||
placebo_dependency = dependency('libplacebo', version: '>= 3.110.0', required: false)
|
||||
|
||||
if placebo_dependency.found()
|
||||
dav1dplay_deps += placebo_dependency
|
||||
dav1dplay_cflags += '-DHAVE_PLACEBO'
|
||||
|
||||
# If libplacebo is found, we might be able to use Vulkan
|
||||
# with it, in which case we need the Vulkan library too.
|
||||
vulkan_dependency = dependency('vulkan', required: false)
|
||||
if vulkan_dependency.found()
|
||||
dav1dplay_deps += vulkan_dependency
|
||||
dav1dplay_cflags += '-DHAVE_VULKAN'
|
||||
endif
|
||||
endif
|
||||
|
||||
dav1dplay = executable('dav1dplay',
|
||||
dav1dplay_sources,
|
||||
rev_target,
|
||||
|
||||
link_with : [libdav1d, dav1d_input_objs],
|
||||
include_directories : [dav1d_inc_dirs],
|
||||
dependencies : [getopt_dependency, dav1dplay_deps],
|
||||
install : true,
|
||||
c_args : dav1dplay_cflags,
|
||||
)
|
||||
endif
|
@ -1,16 +0,0 @@
|
||||
[binaries]
|
||||
c = 'aarch64-linux-android21-clang'
|
||||
cpp = 'aarch64-linux-android21-clang++'
|
||||
ar = 'aarch64-linux-android-ar'
|
||||
strip = 'aarch64-linux-android-strip'
|
||||
pkgconfig = 'pkg-config'
|
||||
windres = 'aarch64-linux-android-windres'
|
||||
|
||||
[properties]
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'android'
|
||||
cpu_family = 'aarch64'
|
||||
endian = 'little'
|
||||
cpu = 'aarch64'
|
@ -1,16 +0,0 @@
|
||||
[binaries]
|
||||
c = 'armv7a-linux-androideabi16-clang'
|
||||
cpp = 'armv7a-linux-androideabi16-clang++'
|
||||
ar = 'arm-linux-androideabi-ar'
|
||||
strip = 'arm-linux-androideabi-strip'
|
||||
pkgconfig = 'pkg-config'
|
||||
windres = 'arm-linux-androideabi-windres'
|
||||
|
||||
[properties]
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'android'
|
||||
cpu_family = 'arm'
|
||||
endian = 'little'
|
||||
cpu = 'arm'
|
@ -1,15 +0,0 @@
|
||||
[binaries]
|
||||
c = 'gcc'
|
||||
cpp = 'g++'
|
||||
ar = 'ar'
|
||||
strip = 'strip'
|
||||
|
||||
[properties]
|
||||
c_link_args = ['-m32', '-Wl,-z,text']
|
||||
c_args = ['-m32']
|
||||
|
||||
[host_machine]
|
||||
system = 'linux'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
@ -1,17 +0,0 @@
|
||||
[binaries]
|
||||
c = 'i686-w64-mingw32-gcc'
|
||||
cpp = 'i686-w64-mingw32-g++'
|
||||
ar = 'i686-w64-mingw32-ar'
|
||||
strip = 'i686-w64-mingw32-strip'
|
||||
windres = 'i686-w64-mingw32-windres'
|
||||
exe_wrapper = ['wine']
|
||||
|
||||
[properties]
|
||||
c_link_args = ['-static-libgcc']
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
@ -1,17 +0,0 @@
|
||||
[binaries]
|
||||
c = 'x86_64-w64-mingw32-gcc'
|
||||
cpp = 'x86_64-w64-mingw32-g++'
|
||||
ar = 'x86_64-w64-mingw32-ar'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
windres = 'x86_64-w64-mingw32-windres'
|
||||
exe_wrapper = ['wine']
|
||||
|
||||
[properties]
|
||||
c_link_args = ['-static-libgcc']
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
24
third_party/dav1d/package/snap/snapcraft.yaml
vendored
24
third_party/dav1d/package/snap/snapcraft.yaml
vendored
@ -1,24 +0,0 @@
|
||||
name: dav1d
|
||||
base: core18
|
||||
version: git
|
||||
version-script: git describe HEAD --always
|
||||
summary: AV1 decoder from VideoLAN
|
||||
description: |
|
||||
A small and fast AV1 decoder from the people who brought you VLC.
|
||||
|
||||
grade: stable
|
||||
confinement: strict # use 'strict' once you have the right plugs and slots
|
||||
|
||||
apps:
|
||||
dav1d:
|
||||
command: usr/bin/dav1d
|
||||
plugs: [ 'home' ]
|
||||
|
||||
parts:
|
||||
dav1d:
|
||||
plugin: meson
|
||||
source: ../../
|
||||
build-packages: [ 'nasm' ]
|
||||
meson-parameters:
|
||||
- --prefix=/usr
|
||||
- --buildtype=release
|
201
third_party/dav1d/tests/checkasm/arm/checkasm_32.S
vendored
201
third_party/dav1d/tests/checkasm/arm/checkasm_32.S
vendored
@ -1,201 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2015 Martin Storsjo
|
||||
* Copyright © 2015 Janne Grunau
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
#define PRIVATE_PREFIX checkasm_
|
||||
|
||||
#include "src/arm/asm.S"
|
||||
#include "src/arm/32/util.S"
|
||||
|
||||
const register_init, align=3
|
||||
.quad 0x21f86d66c8ca00ce
|
||||
.quad 0x75b6ba21077c48ad
|
||||
.quad 0xed56bb2dcb3c7736
|
||||
.quad 0x8bda43d3fd1a7e06
|
||||
.quad 0xb64a9c9e5d318408
|
||||
.quad 0xdf9a54b303f1d3a3
|
||||
.quad 0x4a75479abd64e097
|
||||
.quad 0x249214109d5d1c88
|
||||
endconst
|
||||
|
||||
const error_message_fpscr
|
||||
.asciz "failed to preserve register FPSCR, changed bits: %x"
|
||||
error_message_gpr:
|
||||
.asciz "failed to preserve register r%d"
|
||||
error_message_vfp:
|
||||
.asciz "failed to preserve register d%d"
|
||||
error_message_stack:
|
||||
.asciz "failed to preserve stack"
|
||||
endconst
|
||||
|
||||
@ max number of args used by any asm function.
|
||||
#define MAX_ARGS 15
|
||||
|
||||
#define ARG_STACK 4*(MAX_ARGS - 4)
|
||||
|
||||
@ Align the used stack space to 8 to preserve the stack alignment.
|
||||
@ +8 for stack canary reference.
|
||||
#define ARG_STACK_A (((ARG_STACK + pushed + 7) & ~7) - pushed + 8)
|
||||
|
||||
.macro clobbercheck variant
|
||||
.equ pushed, 4*9
|
||||
function checked_call_\variant, export=1
|
||||
push {r4-r11, lr}
|
||||
.ifc \variant, vfp
|
||||
vpush {d8-d15}
|
||||
fmrx r4, FPSCR
|
||||
push {r4}
|
||||
.equ pushed, pushed + 16*4 + 4
|
||||
.endif
|
||||
|
||||
movrel r12, register_init
|
||||
.ifc \variant, vfp
|
||||
vldm r12, {d8-d15}
|
||||
.endif
|
||||
ldm r12, {r4-r11}
|
||||
|
||||
sub sp, sp, #ARG_STACK_A
|
||||
.equ pos, 0
|
||||
.rept MAX_ARGS-4
|
||||
ldr r12, [sp, #ARG_STACK_A + pushed + 8 + pos]
|
||||
str r12, [sp, #pos]
|
||||
.equ pos, pos + 4
|
||||
.endr
|
||||
|
||||
@ For stack overflows, the callee is free to overwrite the parameters
|
||||
@ that were passed on the stack (if any), so we can only check after
|
||||
@ that point. First figure out how many parameters the function
|
||||
@ really took on the stack:
|
||||
ldr r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
|
||||
@ Load the first non-parameter value from the stack, that should be
|
||||
@ left untouched by the function. Store a copy of it inverted, so that
|
||||
@ e.g. overwriting everything with zero would be noticed.
|
||||
ldr r12, [sp, r12, lsl #2]
|
||||
mvn r12, r12
|
||||
str r12, [sp, #ARG_STACK_A - 4]
|
||||
|
||||
mov r12, r0
|
||||
mov r0, r2
|
||||
mov r1, r3
|
||||
ldrd r2, r3, [sp, #ARG_STACK_A + pushed]
|
||||
@ Call the target function
|
||||
blx r12
|
||||
|
||||
@ Load the number of stack parameters, stack canary and its reference
|
||||
ldr r12, [sp, #ARG_STACK_A + pushed + 8 + 4*(MAX_ARGS-4)]
|
||||
ldr r2, [sp, r12, lsl #2]
|
||||
ldr r3, [sp, #ARG_STACK_A - 4]
|
||||
|
||||
add sp, sp, #ARG_STACK_A
|
||||
push {r0, r1}
|
||||
|
||||
mvn r3, r3
|
||||
cmp r2, r3
|
||||
bne 5f
|
||||
|
||||
movrel r12, register_init
|
||||
.ifc \variant, vfp
|
||||
.macro check_reg_vfp, dreg, offset
|
||||
ldrd r2, r3, [r12, #8 * (\offset)]
|
||||
vmov r0, lr, \dreg
|
||||
eor r2, r2, r0
|
||||
eor r3, r3, lr
|
||||
orrs r2, r2, r3
|
||||
bne 4f
|
||||
.endm
|
||||
|
||||
.irp n, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
@ keep track of the checked double/SIMD register
|
||||
mov r1, #\n
|
||||
check_reg_vfp d\n, \n-8
|
||||
.endr
|
||||
.purgem check_reg_vfp
|
||||
|
||||
fmrx r1, FPSCR
|
||||
ldr r3, [sp, #8]
|
||||
eor r1, r1, r3
|
||||
@ Ignore changes in bits 0-4 and 7
|
||||
bic r1, r1, #0x9f
|
||||
@ Ignore changes in the topmost 5 bits
|
||||
bics r1, r1, #0xf8000000
|
||||
bne 3f
|
||||
.endif
|
||||
|
||||
@ keep track of the checked GPR
|
||||
mov r1, #4
|
||||
.macro check_reg reg1, reg2=
|
||||
ldrd r2, r3, [r12], #8
|
||||
eors r2, r2, \reg1
|
||||
bne 2f
|
||||
add r1, r1, #1
|
||||
.ifnb \reg2
|
||||
eors r3, r3, \reg2
|
||||
bne 2f
|
||||
.endif
|
||||
add r1, r1, #1
|
||||
.endm
|
||||
check_reg r4, r5
|
||||
check_reg r6, r7
|
||||
@ r9 is a volatile register in the ios ABI
|
||||
#ifdef __APPLE__
|
||||
check_reg r8
|
||||
#else
|
||||
check_reg r8, r9
|
||||
#endif
|
||||
check_reg r10, r11
|
||||
.purgem check_reg
|
||||
|
||||
b 0f
|
||||
5:
|
||||
movrel r0, error_message_stack
|
||||
b 1f
|
||||
4:
|
||||
movrel r0, error_message_vfp
|
||||
b 1f
|
||||
3:
|
||||
movrel r0, error_message_fpscr
|
||||
b 1f
|
||||
2:
|
||||
movrel r0, error_message_gpr
|
||||
1:
|
||||
#ifdef PREFIX
|
||||
bl _checkasm_fail_func
|
||||
#else
|
||||
bl checkasm_fail_func
|
||||
#endif
|
||||
0:
|
||||
pop {r0, r1}
|
||||
.ifc \variant, vfp
|
||||
pop {r2}
|
||||
fmxr FPSCR, r2
|
||||
vpop {d8-d15}
|
||||
.endif
|
||||
pop {r4-r11, pc}
|
||||
endfunc
|
||||
.endm
|
||||
|
||||
clobbercheck vfp
|
211
third_party/dav1d/tests/checkasm/arm/checkasm_64.S
vendored
211
third_party/dav1d/tests/checkasm/arm/checkasm_64.S
vendored
@ -1,211 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2015 Martin Storsjo
|
||||
* Copyright © 2015 Janne Grunau
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
#define PRIVATE_PREFIX checkasm_
|
||||
|
||||
#include "src/arm/asm.S"
|
||||
#include "src/arm/64/util.S"
|
||||
|
||||
const register_init, align=4
|
||||
.quad 0x21f86d66c8ca00ce
|
||||
.quad 0x75b6ba21077c48ad
|
||||
.quad 0xed56bb2dcb3c7736
|
||||
.quad 0x8bda43d3fd1a7e06
|
||||
.quad 0xb64a9c9e5d318408
|
||||
.quad 0xdf9a54b303f1d3a3
|
||||
.quad 0x4a75479abd64e097
|
||||
.quad 0x249214109d5d1c88
|
||||
.quad 0x1a1b2550a612b48c
|
||||
.quad 0x79445c159ce79064
|
||||
.quad 0x2eed899d5a28ddcd
|
||||
.quad 0x86b2536fcd8cf636
|
||||
.quad 0xb0856806085e7943
|
||||
.quad 0x3f2bf84fc0fcca4e
|
||||
.quad 0xacbd382dcf5b8de2
|
||||
.quad 0xd229e1f5b281303f
|
||||
.quad 0x71aeaff20b095fd9
|
||||
.quad 0xab63e2e11fa38ed9
|
||||
endconst
|
||||
|
||||
|
||||
const error_message_register
|
||||
.asciz "failed to preserve register"
|
||||
error_message_stack:
|
||||
.asciz "stack clobbered"
|
||||
endconst
|
||||
|
||||
|
||||
// max number of args used by any asm function.
|
||||
#define MAX_ARGS 15
|
||||
|
||||
#define CLOBBER_STACK ((8*MAX_ARGS + 15) & ~15)
|
||||
|
||||
function stack_clobber, export=1
|
||||
mov x3, sp
|
||||
mov x2, #CLOBBER_STACK
|
||||
1:
|
||||
stp x0, x1, [sp, #-16]!
|
||||
subs x2, x2, #16
|
||||
b.gt 1b
|
||||
mov sp, x3
|
||||
ret
|
||||
endfunc
|
||||
|
||||
// + 16 for stack canary reference
|
||||
#define ARG_STACK ((8*(MAX_ARGS - 8) + 15) & ~15 + 16)
|
||||
|
||||
function checked_call, export=1
|
||||
stp x29, x30, [sp, #-16]!
|
||||
mov x29, sp
|
||||
stp x19, x20, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp d8, d9, [sp, #-16]!
|
||||
stp d10, d11, [sp, #-16]!
|
||||
stp d12, d13, [sp, #-16]!
|
||||
stp d14, d15, [sp, #-16]!
|
||||
|
||||
movrel x9, register_init
|
||||
ldp d8, d9, [x9], #16
|
||||
ldp d10, d11, [x9], #16
|
||||
ldp d12, d13, [x9], #16
|
||||
ldp d14, d15, [x9], #16
|
||||
ldp x19, x20, [x9], #16
|
||||
ldp x21, x22, [x9], #16
|
||||
ldp x23, x24, [x9], #16
|
||||
ldp x25, x26, [x9], #16
|
||||
ldp x27, x28, [x9], #16
|
||||
|
||||
sub sp, sp, #ARG_STACK
|
||||
.equ pos, 0
|
||||
.rept MAX_ARGS-8
|
||||
// Skip the first 8 args, that are loaded into registers
|
||||
ldr x9, [x29, #16 + 8*8 + pos]
|
||||
str x9, [sp, #pos]
|
||||
.equ pos, pos + 8
|
||||
.endr
|
||||
|
||||
// Fill x8-x17 with garbage. This doesn't have to be preserved,
|
||||
// but avoids relying on them having any particular value.
|
||||
movrel x9, register_init
|
||||
ldp x10, x11, [x9], #32
|
||||
ldp x12, x13, [x9], #32
|
||||
ldp x14, x15, [x9], #32
|
||||
ldp x16, x17, [x9], #32
|
||||
ldp x8, x9, [x9]
|
||||
|
||||
// For stack overflows, the callee is free to overwrite the parameters
|
||||
// that were passed on the stack (if any), so we can only check after
|
||||
// that point. First figure out how many parameters the function
|
||||
// really took on the stack:
|
||||
ldr w2, [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
|
||||
// Load the first non-parameter value from the stack, that should be
|
||||
// left untouched by the function. Store a copy of it inverted, so that
|
||||
// e.g. overwriting everything with zero would be noticed.
|
||||
ldr x2, [sp, x2, lsl #3]
|
||||
mvn x2, x2
|
||||
str x2, [sp, #ARG_STACK-8]
|
||||
|
||||
// Load the in-register arguments
|
||||
mov x12, x0
|
||||
ldp x0, x1, [x29, #16]
|
||||
ldp x2, x3, [x29, #32]
|
||||
ldp x4, x5, [x29, #48]
|
||||
ldp x6, x7, [x29, #64]
|
||||
// Call the target function
|
||||
blr x12
|
||||
|
||||
// Load the number of stack parameters, stack canary and its reference
|
||||
ldr w2, [x29, #16 + 8*8 + (MAX_ARGS-8)*8]
|
||||
ldr x2, [sp, x2, lsl #3]
|
||||
ldr x3, [sp, #ARG_STACK-8]
|
||||
|
||||
add sp, sp, #ARG_STACK
|
||||
stp x0, x1, [sp, #-16]!
|
||||
|
||||
mvn x3, x3
|
||||
cmp x2, x3
|
||||
b.ne 2f
|
||||
|
||||
movrel x9, register_init
|
||||
movi v3.8h, #0
|
||||
|
||||
.macro check_reg_neon reg1, reg2
|
||||
ldr q1, [x9], #16
|
||||
uzp1 v2.2d, v\reg1\().2d, v\reg2\().2d
|
||||
eor v1.16b, v1.16b, v2.16b
|
||||
orr v3.16b, v3.16b, v1.16b
|
||||
.endm
|
||||
check_reg_neon 8, 9
|
||||
check_reg_neon 10, 11
|
||||
check_reg_neon 12, 13
|
||||
check_reg_neon 14, 15
|
||||
uqxtn v3.8b, v3.8h
|
||||
umov x3, v3.d[0]
|
||||
|
||||
.macro check_reg reg1, reg2
|
||||
ldp x0, x1, [x9], #16
|
||||
eor x0, x0, \reg1
|
||||
eor x1, x1, \reg2
|
||||
orr x3, x3, x0
|
||||
orr x3, x3, x1
|
||||
.endm
|
||||
check_reg x19, x20
|
||||
check_reg x21, x22
|
||||
check_reg x23, x24
|
||||
check_reg x25, x26
|
||||
check_reg x27, x28
|
||||
|
||||
cbz x3, 0f
|
||||
|
||||
movrel x0, error_message_register
|
||||
b 1f
|
||||
2:
|
||||
movrel x0, error_message_stack
|
||||
1:
|
||||
#ifdef PREFIX
|
||||
bl _checkasm_fail_func
|
||||
#else
|
||||
bl checkasm_fail_func
|
||||
#endif
|
||||
0:
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp d14, d15, [sp], #16
|
||||
ldp d12, d13, [sp], #16
|
||||
ldp d10, d11, [sp], #16
|
||||
ldp d8, d9, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
ret
|
||||
endfunc
|
150
third_party/dav1d/tests/checkasm/cdef.c
vendored
150
third_party/dav1d/tests/checkasm/cdef.c
vendored
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common/dump.h"
|
||||
|
||||
#include "src/levels.h"
|
||||
#include "src/cdef.h"
|
||||
|
||||
static int to_binary(int x) { /* 0-15 -> 0000-1111 */
|
||||
return (x & 1) + 5 * (x & 2) + 25 * (x & 4) + 125 * (x & 8);
|
||||
}
|
||||
|
||||
static void init_tmp(pixel *buf, int n, const int bitdepth_max) {
|
||||
const int fill_type = rnd() & 7;
|
||||
if (fill_type == 0)
|
||||
while (n--) /* check for cdef_filter underflows */
|
||||
*buf++ = rnd() & 1;
|
||||
else if (fill_type == 1)
|
||||
while (n--) /* check for cdef_filter overflows */
|
||||
*buf++ = bitdepth_max - (rnd() & 1);
|
||||
else
|
||||
while (n--)
|
||||
*buf++ = rnd() & bitdepth_max;
|
||||
}
|
||||
|
||||
static void check_cdef_filter(const cdef_fn fn, const int w, const int h) {
|
||||
ALIGN_STK_64(pixel, c_src, 16 * 10 + 16, ), *const c_dst = c_src + 8;
|
||||
ALIGN_STK_64(pixel, a_src, 16 * 10 + 16, ), *const a_dst = a_src + 8;
|
||||
ALIGN_STK_64(pixel, top_buf, 16 * 2 + 16, ), *const top = top_buf + 8;
|
||||
ALIGN_STK_16(pixel, left, 8,[2]);
|
||||
const ptrdiff_t stride = 16 * sizeof(pixel);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel (*left)[2],
|
||||
const pixel *top, int pri_strength, int sec_strength,
|
||||
int dir, int damping, enum CdefEdgeFlags edges HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(fn, "cdef_filter_%dx%d_%dbpc", w, h, BITDEPTH)) {
|
||||
for (int dir = 0; dir < 8; dir++) {
|
||||
for (enum CdefEdgeFlags edges = 0x0; edges <= 0xf; edges++) {
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
|
||||
|
||||
init_tmp(c_src, 16 * 10 + 16, bitdepth_max);
|
||||
init_tmp(top_buf, 16 * 2 + 16, bitdepth_max);
|
||||
init_tmp((pixel *) left, 8 * 2, bitdepth_max);
|
||||
memcpy(a_src, c_src, (16 * 10 + 16) * sizeof(pixel));
|
||||
|
||||
const int lvl = 1 + (rnd() % 62);
|
||||
const int damping = 3 + (rnd() & 3) + bitdepth_min_8 - (w == 4 || (rnd() & 1));
|
||||
int pri_strength = (lvl >> 2) << bitdepth_min_8;
|
||||
int sec_strength = lvl & 3;
|
||||
sec_strength += sec_strength == 3;
|
||||
sec_strength <<= bitdepth_min_8;
|
||||
call_ref(c_dst, stride, left, top, pri_strength, sec_strength,
|
||||
dir, damping, edges HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, stride, left, top, pri_strength, sec_strength,
|
||||
dir, damping, edges HIGHBD_TAIL_SUFFIX);
|
||||
if (checkasm_check_pixel(c_dst, stride, a_dst, stride, w, h, "dst")) {
|
||||
fprintf(stderr, "strength = %d:%d, dir = %d, damping = %d, edges = %04d\n",
|
||||
pri_strength, sec_strength, dir, damping, to_binary(edges));
|
||||
return;
|
||||
}
|
||||
if (dir == 7 && (edges == 0x5 || edges == 0xa || edges == 0xf)) {
|
||||
/* Benchmark a fixed set of cases to get consistent results:
|
||||
* 1) top/left edges and pri_strength only
|
||||
* 2) bottom/right edges and sec_strength only
|
||||
* 3) all edges and both pri_strength and sec_strength
|
||||
*/
|
||||
pri_strength = (edges & 1) << bitdepth_min_8;
|
||||
sec_strength = (edges & 2) << bitdepth_min_8;
|
||||
bench_new(a_dst, stride, left, top, pri_strength, sec_strength,
|
||||
dir, damping, edges HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_cdef_direction(const cdef_dir_fn fn) {
|
||||
ALIGN_STK_64(pixel, src, 8 * 8,);
|
||||
|
||||
declare_func(int, pixel *src, ptrdiff_t dst_stride, unsigned *var
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(fn, "cdef_dir_%dbpc", BITDEPTH)) {
|
||||
unsigned c_var, a_var;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
init_tmp(src, 64, bitdepth_max);
|
||||
|
||||
const int c_dir = call_ref(src, 8 * sizeof(pixel), &c_var HIGHBD_TAIL_SUFFIX);
|
||||
const int a_dir = call_new(src, 8 * sizeof(pixel), &a_var HIGHBD_TAIL_SUFFIX);
|
||||
if (c_var != a_var || c_dir != a_dir) {
|
||||
if (fail()) {
|
||||
hex_fdump(stderr, src, 8 * sizeof(pixel), 8, 8, "src");
|
||||
fprintf(stderr, "c_dir %d a_dir %d\n", c_dir, a_dir);
|
||||
}
|
||||
}
|
||||
bench_new(src, 8 * sizeof(pixel), &a_var HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
report("cdef_dir");
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_cdef)(void) {
|
||||
Dav1dCdefDSPContext c;
|
||||
bitfn(dav1d_cdef_dsp_init)(&c);
|
||||
|
||||
check_cdef_direction(c.dir);
|
||||
|
||||
check_cdef_filter(c.fb[0], 8, 8);
|
||||
check_cdef_filter(c.fb[1], 4, 8);
|
||||
check_cdef_filter(c.fb[2], 4, 4);
|
||||
report("cdef_filter");
|
||||
}
|
869
third_party/dav1d/tests/checkasm/checkasm.c
vendored
869
third_party/dav1d/tests/checkasm/checkasm.c
vendored
@ -1,869 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/cpu.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define COLOR_RED FOREGROUND_RED
|
||||
#define COLOR_GREEN FOREGROUND_GREEN
|
||||
#define COLOR_YELLOW (FOREGROUND_RED|FOREGROUND_GREEN)
|
||||
|
||||
static unsigned get_seed(void) {
|
||||
return GetTickCount();
|
||||
}
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#define COLOR_RED 1
|
||||
#define COLOR_GREEN 2
|
||||
#define COLOR_YELLOW 3
|
||||
|
||||
static unsigned get_seed(void) {
|
||||
#ifdef __APPLE__
|
||||
return (unsigned) mach_absolute_time();
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (unsigned) (1000000000ULL * ts.tv_sec + ts.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* List of tests to invoke */
|
||||
static const struct {
|
||||
const char *name;
|
||||
void (*func)(void);
|
||||
} tests[] = {
|
||||
{ "msac", checkasm_check_msac },
|
||||
#if CONFIG_8BPC
|
||||
{ "cdef_8bpc", checkasm_check_cdef_8bpc },
|
||||
{ "filmgrain_8bpc", checkasm_check_filmgrain_8bpc },
|
||||
{ "ipred_8bpc", checkasm_check_ipred_8bpc },
|
||||
{ "itx_8bpc", checkasm_check_itx_8bpc },
|
||||
{ "loopfilter_8bpc", checkasm_check_loopfilter_8bpc },
|
||||
{ "looprestoration_8bpc", checkasm_check_looprestoration_8bpc },
|
||||
{ "mc_8bpc", checkasm_check_mc_8bpc },
|
||||
#endif
|
||||
#if CONFIG_16BPC
|
||||
{ "cdef_16bpc", checkasm_check_cdef_16bpc },
|
||||
{ "filmgrain_16bpc", checkasm_check_filmgrain_16bpc },
|
||||
{ "ipred_16bpc", checkasm_check_ipred_16bpc },
|
||||
{ "itx_16bpc", checkasm_check_itx_16bpc },
|
||||
{ "loopfilter_16bpc", checkasm_check_loopfilter_16bpc },
|
||||
{ "looprestoration_16bpc", checkasm_check_looprestoration_16bpc },
|
||||
{ "mc_16bpc", checkasm_check_mc_16bpc },
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* List of cpu flags to check */
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *suffix;
|
||||
unsigned flag;
|
||||
} cpus[] = {
|
||||
#if ARCH_X86
|
||||
{ "SSE2", "sse2", DAV1D_X86_CPU_FLAG_SSE2 },
|
||||
{ "SSSE3", "ssse3", DAV1D_X86_CPU_FLAG_SSSE3 },
|
||||
{ "SSE4.1", "sse4", DAV1D_X86_CPU_FLAG_SSE41 },
|
||||
{ "AVX2", "avx2", DAV1D_X86_CPU_FLAG_AVX2 },
|
||||
{ "AVX-512 (Ice Lake)", "avx512icl", DAV1D_X86_CPU_FLAG_AVX512ICL },
|
||||
#elif ARCH_AARCH64 || ARCH_ARM
|
||||
{ "NEON", "neon", DAV1D_ARM_CPU_FLAG_NEON },
|
||||
#elif ARCH_PPC64LE
|
||||
{ "VSX", "vsx", DAV1D_PPC_CPU_FLAG_VSX },
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
typedef struct CheckasmFuncVersion {
|
||||
struct CheckasmFuncVersion *next;
|
||||
void *func;
|
||||
int ok;
|
||||
unsigned cpu;
|
||||
int iterations;
|
||||
uint64_t cycles;
|
||||
} CheckasmFuncVersion;
|
||||
|
||||
/* Binary search tree node */
|
||||
typedef struct CheckasmFunc {
|
||||
struct CheckasmFunc *child[2];
|
||||
CheckasmFuncVersion versions;
|
||||
uint8_t color; /* 0 = red, 1 = black */
|
||||
char name[];
|
||||
} CheckasmFunc;
|
||||
|
||||
/* Internal state */
|
||||
static struct {
|
||||
CheckasmFunc *funcs;
|
||||
CheckasmFunc *current_func;
|
||||
CheckasmFuncVersion *current_func_ver;
|
||||
const char *current_test_name;
|
||||
const char *bench_pattern;
|
||||
size_t bench_pattern_len;
|
||||
int num_checked;
|
||||
int num_failed;
|
||||
int nop_time;
|
||||
unsigned cpu_flag;
|
||||
const char *cpu_flag_name;
|
||||
const char *test_name;
|
||||
unsigned seed;
|
||||
int bench_c;
|
||||
int verbose;
|
||||
int function_listing;
|
||||
#if ARCH_X86_64
|
||||
void (*simd_warmup)(void);
|
||||
#endif
|
||||
} state;
|
||||
|
||||
/* float compare support code */
|
||||
typedef union {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} intfloat;
|
||||
|
||||
static uint32_t xs_state[4];
|
||||
|
||||
static void xor128_srand(unsigned seed) {
|
||||
xs_state[0] = seed;
|
||||
xs_state[1] = ( seed & 0xffff0000) | (~seed & 0x0000ffff);
|
||||
xs_state[2] = (~seed & 0xffff0000) | ( seed & 0x0000ffff);
|
||||
xs_state[3] = ~seed;
|
||||
}
|
||||
|
||||
// xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
|
||||
// Journal of Statistical Software. 8 (14).
|
||||
// doi:10.18637/jss.v008.i14.
|
||||
int xor128_rand(void) {
|
||||
const uint32_t x = xs_state[0];
|
||||
const uint32_t t = x ^ (x << 11);
|
||||
|
||||
xs_state[0] = xs_state[1];
|
||||
xs_state[1] = xs_state[2];
|
||||
xs_state[2] = xs_state[3];
|
||||
uint32_t w = xs_state[3];
|
||||
|
||||
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
||||
xs_state[3] = w;
|
||||
|
||||
return w >> 1;
|
||||
}
|
||||
|
||||
static int is_negative(const intfloat u) {
|
||||
return u.i >> 31;
|
||||
}
|
||||
|
||||
int float_near_ulp(const float a, const float b, const unsigned max_ulp) {
|
||||
intfloat x, y;
|
||||
|
||||
x.f = a;
|
||||
y.f = b;
|
||||
|
||||
if (is_negative(x) != is_negative(y)) {
|
||||
// handle -0.0 == +0.0
|
||||
return a == b;
|
||||
}
|
||||
|
||||
if (llabs((int64_t)x.i - y.i) <= max_ulp)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int float_near_ulp_array(const float *const a, const float *const b,
|
||||
const unsigned max_ulp, const int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
if (!float_near_ulp(a[i], b[i], max_ulp))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int float_near_abs_eps(const float a, const float b, const float eps) {
|
||||
return fabsf(a - b) < eps;
|
||||
}
|
||||
|
||||
int float_near_abs_eps_array(const float *const a, const float *const b,
|
||||
const float eps, const int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
if (!float_near_abs_eps(a[i], b[i], eps))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int float_near_abs_eps_ulp(const float a, const float b, const float eps,
|
||||
const unsigned max_ulp)
|
||||
{
|
||||
return float_near_ulp(a, b, max_ulp) || float_near_abs_eps(a, b, eps);
|
||||
}
|
||||
|
||||
int float_near_abs_eps_array_ulp(const float *const a, const float *const b,
|
||||
const float eps, const unsigned max_ulp,
|
||||
const int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
if (!float_near_abs_eps_ulp(a[i], b[i], eps, max_ulp))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print colored text to stderr if the terminal supports it */
|
||||
static void color_printf(const int color, const char *const fmt, ...) {
|
||||
static int8_t use_color = -1;
|
||||
va_list arg;
|
||||
|
||||
#ifdef _WIN32
|
||||
static HANDLE con;
|
||||
static WORD org_attributes;
|
||||
|
||||
if (use_color < 0) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO con_info;
|
||||
con = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (con && con != INVALID_HANDLE_VALUE &&
|
||||
GetConsoleScreenBufferInfo(con, &con_info))
|
||||
{
|
||||
org_attributes = con_info.wAttributes;
|
||||
use_color = 1;
|
||||
} else
|
||||
use_color = 0;
|
||||
}
|
||||
if (use_color)
|
||||
SetConsoleTextAttribute(con, (org_attributes & 0xfff0) |
|
||||
(color & 0x0f));
|
||||
#else
|
||||
if (use_color < 0) {
|
||||
const char *const term = getenv("TERM");
|
||||
use_color = term && strcmp(term, "dumb") && isatty(2);
|
||||
}
|
||||
if (use_color)
|
||||
fprintf(stderr, "\x1b[%d;3%dm", (color & 0x08) >> 3, color & 0x07);
|
||||
#endif
|
||||
|
||||
va_start(arg, fmt);
|
||||
vfprintf(stderr, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (use_color) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(con, org_attributes);
|
||||
#else
|
||||
fprintf(stderr, "\x1b[0m");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Deallocate a tree */
|
||||
static void destroy_func_tree(CheckasmFunc *const f) {
|
||||
if (f) {
|
||||
CheckasmFuncVersion *v = f->versions.next;
|
||||
while (v) {
|
||||
CheckasmFuncVersion *next = v->next;
|
||||
free(v);
|
||||
v = next;
|
||||
}
|
||||
|
||||
destroy_func_tree(f->child[0]);
|
||||
destroy_func_tree(f->child[1]);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a zero-initialized block, clean up and exit on failure */
|
||||
static void *checkasm_malloc(const size_t size) {
|
||||
void *const ptr = calloc(1, size);
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "checkasm: malloc failed\n");
|
||||
destroy_func_tree(state.funcs);
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Get the suffix of the specified cpu flag */
|
||||
static const char *cpu_suffix(const unsigned cpu) {
|
||||
for (int i = (int)(sizeof(cpus) / sizeof(*cpus)) - 2; i >= 0; i--)
|
||||
if (cpu & cpus[i].flag)
|
||||
return cpus[i].suffix;
|
||||
|
||||
return "c";
|
||||
}
|
||||
|
||||
#ifdef readtime
|
||||
static int cmp_nop(const void *a, const void *b) {
|
||||
return *(const uint16_t*)a - *(const uint16_t*)b;
|
||||
}
|
||||
|
||||
/* Measure the overhead of the timing code (in decicycles) */
|
||||
static int measure_nop_time(void) {
|
||||
uint16_t nops[10000];
|
||||
int nop_sum = 0;
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
uint64_t t = readtime();
|
||||
nops[i] = (uint16_t) (readtime() - t);
|
||||
}
|
||||
|
||||
qsort(nops, 10000, sizeof(uint16_t), cmp_nop);
|
||||
for (int i = 2500; i < 7500; i++)
|
||||
nop_sum += nops[i];
|
||||
|
||||
return nop_sum / 500;
|
||||
}
|
||||
|
||||
/* Print benchmark results */
|
||||
static void print_benchs(const CheckasmFunc *const f) {
|
||||
if (f) {
|
||||
print_benchs(f->child[0]);
|
||||
|
||||
/* Only print functions with at least one assembly version */
|
||||
if (state.bench_c || f->versions.cpu || f->versions.next) {
|
||||
const CheckasmFuncVersion *v = &f->versions;
|
||||
do {
|
||||
if (v->iterations) {
|
||||
const int decicycles = (int) (10*v->cycles/v->iterations -
|
||||
state.nop_time) / 4;
|
||||
printf("%s_%s: %d.%d\n", f->name, cpu_suffix(v->cpu),
|
||||
decicycles/10, decicycles%10);
|
||||
}
|
||||
} while ((v = v->next));
|
||||
}
|
||||
|
||||
print_benchs(f->child[1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void print_functions(const CheckasmFunc *const f) {
|
||||
if (f) {
|
||||
print_functions(f->child[0]);
|
||||
printf("%s\n", f->name);
|
||||
print_functions(f->child[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#define is_digit(x) ((x) >= '0' && (x) <= '9')
|
||||
|
||||
/* ASCIIbetical sort except preserving natural order for numbers */
|
||||
static int cmp_func_names(const char *a, const char *b) {
|
||||
const char *const start = a;
|
||||
int ascii_diff, digit_diff;
|
||||
|
||||
for (; !(ascii_diff = *(const unsigned char*)a -
|
||||
*(const unsigned char*)b) && *a; a++, b++);
|
||||
for (; is_digit(*a) && is_digit(*b); a++, b++);
|
||||
|
||||
if (a > start && is_digit(a[-1]) &&
|
||||
(digit_diff = is_digit(*a) - is_digit(*b)))
|
||||
{
|
||||
return digit_diff;
|
||||
}
|
||||
|
||||
return ascii_diff;
|
||||
}
|
||||
|
||||
/* Perform a tree rotation in the specified direction and return the new root */
|
||||
static CheckasmFunc *rotate_tree(CheckasmFunc *const f, const int dir) {
|
||||
CheckasmFunc *const r = f->child[dir^1];
|
||||
f->child[dir^1] = r->child[dir];
|
||||
r->child[dir] = f;
|
||||
r->color = f->color;
|
||||
f->color = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
#define is_red(f) ((f) && !(f)->color)
|
||||
|
||||
/* Balance a left-leaning red-black tree at the specified node */
|
||||
static void balance_tree(CheckasmFunc **const root) {
|
||||
CheckasmFunc *const f = *root;
|
||||
|
||||
if (is_red(f->child[0]) && is_red(f->child[1])) {
|
||||
f->color ^= 1;
|
||||
f->child[0]->color = f->child[1]->color = 1;
|
||||
}
|
||||
else if (!is_red(f->child[0]) && is_red(f->child[1]))
|
||||
*root = rotate_tree(f, 0); /* Rotate left */
|
||||
else if (is_red(f->child[0]) && is_red(f->child[0]->child[0]))
|
||||
*root = rotate_tree(f, 1); /* Rotate right */
|
||||
}
|
||||
|
||||
/* Get a node with the specified name, creating it if it doesn't exist */
|
||||
static CheckasmFunc *get_func(CheckasmFunc **const root, const char *const name) {
|
||||
CheckasmFunc *f = *root;
|
||||
|
||||
if (f) {
|
||||
/* Search the tree for a matching node */
|
||||
const int cmp = cmp_func_names(name, f->name);
|
||||
if (cmp) {
|
||||
f = get_func(&f->child[cmp > 0], name);
|
||||
|
||||
/* Rebalance the tree on the way up if a new node was inserted */
|
||||
if (!f->versions.func)
|
||||
balance_tree(root);
|
||||
}
|
||||
} else {
|
||||
/* Allocate and insert a new node into the tree */
|
||||
const size_t name_length = strlen(name) + 1;
|
||||
f = *root = checkasm_malloc(offsetof(CheckasmFunc, name) + name_length);
|
||||
memcpy(f->name, name, name_length);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
checkasm_context checkasm_context_buf;
|
||||
|
||||
/* Crash handling: attempt to catch crashes and handle them
|
||||
* gracefully instead of just aborting abruptly. */
|
||||
#ifdef _WIN32
|
||||
static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
|
||||
switch (e->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
checkasm_fail_func("fatal arithmetic error");
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
checkasm_fail_func("illegal instruction");
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
checkasm_fail_func("segmentation fault");
|
||||
break;
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
checkasm_load_context();
|
||||
return EXCEPTION_CONTINUE_EXECUTION; /* never reached, but shuts up gcc */
|
||||
}
|
||||
#else
|
||||
static void signal_handler(const int s) {
|
||||
checkasm_set_signal_handler_state(0);
|
||||
checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
|
||||
s == SIGILL ? "illegal instruction" :
|
||||
"segmentation fault");
|
||||
checkasm_load_context();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform tests and benchmarks for the specified
|
||||
* cpu flag if supported by the host */
|
||||
static void check_cpu_flag(const char *const name, unsigned flag) {
|
||||
const unsigned old_cpu_flag = state.cpu_flag;
|
||||
|
||||
flag |= old_cpu_flag;
|
||||
dav1d_set_cpu_flags_mask(flag);
|
||||
state.cpu_flag = dav1d_get_cpu_flags();
|
||||
|
||||
if (!flag || state.cpu_flag != old_cpu_flag) {
|
||||
state.cpu_flag_name = name;
|
||||
for (int i = 0; tests[i].func; i++) {
|
||||
if (state.test_name && strcmp(tests[i].name, state.test_name))
|
||||
continue;
|
||||
xor128_srand(state.seed);
|
||||
state.current_test_name = tests[i].name;
|
||||
tests[i].func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the name of the current CPU flag, but only do it once */
|
||||
static void print_cpu_name(void) {
|
||||
if (state.cpu_flag_name) {
|
||||
color_printf(COLOR_YELLOW, "%s:\n", state.cpu_flag_name);
|
||||
state.cpu_flag_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
state.seed = get_seed();
|
||||
|
||||
while (argc > 1) {
|
||||
if (!strncmp(argv[1], "--help", 6)) {
|
||||
fprintf(stdout,
|
||||
"checkasm [options] <random seed>\n"
|
||||
" <random seed> Numeric value to seed the rng\n"
|
||||
"Options:\n"
|
||||
" --test=<test_name> Test only <test_name>\n"
|
||||
" --bench=<pattern> Test and benchmark the functions matching <pattern>\n"
|
||||
" --list-functions List available functions\n"
|
||||
" --list-tests List available tests\n"
|
||||
" --bench-c Benchmark the C-only functions\n"
|
||||
" --verbose -v Print failures verbosely\n");
|
||||
return 0;
|
||||
} else if (!strncmp(argv[1], "--bench-c", 9)) {
|
||||
state.bench_c = 1;
|
||||
} else if (!strncmp(argv[1], "--bench", 7)) {
|
||||
#ifndef readtime
|
||||
fprintf(stderr,
|
||||
"checkasm: --bench is not supported on your system\n");
|
||||
return 1;
|
||||
#endif
|
||||
if (argv[1][7] == '=') {
|
||||
state.bench_pattern = argv[1] + 8;
|
||||
state.bench_pattern_len = strlen(state.bench_pattern);
|
||||
} else
|
||||
state.bench_pattern = "";
|
||||
} else if (!strncmp(argv[1], "--test=", 7)) {
|
||||
state.test_name = argv[1] + 7;
|
||||
} else if (!strcmp(argv[1], "--list-functions")) {
|
||||
state.function_listing = 1;
|
||||
} else if (!strcmp(argv[1], "--list-tests")) {
|
||||
for (int i = 0; tests[i].name; i++)
|
||||
printf("%s\n", tests[i].name);
|
||||
return 0;
|
||||
} else if (!strcmp(argv[1], "--verbose") || !strcmp(argv[1], "-v")) {
|
||||
state.verbose = 1;
|
||||
} else {
|
||||
state.seed = (unsigned) strtoul(argv[1], NULL, 10);
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
dav1d_init_cpu();
|
||||
|
||||
#ifdef readtime
|
||||
if (state.bench_pattern) {
|
||||
static int testing = 0;
|
||||
checkasm_save_context();
|
||||
if (!testing) {
|
||||
checkasm_set_signal_handler_state(1);
|
||||
testing = 1;
|
||||
readtime();
|
||||
checkasm_set_signal_handler_state(0);
|
||||
} else {
|
||||
fprintf(stderr, "checkasm: unable to access cycle counter\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (!state.function_listing) {
|
||||
fprintf(stderr, "checkasm: using random seed %u\n", state.seed);
|
||||
#if ARCH_X86_64
|
||||
void checkasm_warmup_avx2(void);
|
||||
void checkasm_warmup_avx512(void);
|
||||
const unsigned cpu_flags = dav1d_get_cpu_flags();
|
||||
if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX512ICL)
|
||||
state.simd_warmup = checkasm_warmup_avx512;
|
||||
else if (cpu_flags & DAV1D_X86_CPU_FLAG_AVX2)
|
||||
state.simd_warmup = checkasm_warmup_avx2;
|
||||
checkasm_simd_warmup();
|
||||
#endif
|
||||
}
|
||||
|
||||
check_cpu_flag(NULL, 0);
|
||||
|
||||
if (state.function_listing) {
|
||||
print_functions(state.funcs);
|
||||
} else {
|
||||
for (int i = 0; cpus[i].flag; i++)
|
||||
check_cpu_flag(cpus[i].name, cpus[i].flag);
|
||||
if (!state.num_checked) {
|
||||
fprintf(stderr, "checkasm: no tests to perform\n");
|
||||
} else if (state.num_failed) {
|
||||
fprintf(stderr, "checkasm: %d of %d tests have failed\n",
|
||||
state.num_failed, state.num_checked);
|
||||
ret = 1;
|
||||
} else {
|
||||
fprintf(stderr, "checkasm: all %d tests passed\n", state.num_checked);
|
||||
#ifdef readtime
|
||||
if (state.bench_pattern) {
|
||||
state.nop_time = measure_nop_time();
|
||||
printf("nop: %d.%d\n", state.nop_time/10, state.nop_time%10);
|
||||
print_benchs(state.funcs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
destroy_func_tree(state.funcs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Decide whether or not the specified function needs to be tested and
|
||||
* allocate/initialize data structures if needed. Returns a pointer to a
|
||||
* reference function if the function should be tested, otherwise NULL */
|
||||
void *checkasm_check_func(void *const func, const char *const name, ...) {
|
||||
char name_buf[256];
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, name);
|
||||
const int name_length = vsnprintf(name_buf, sizeof(name_buf), name, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (!func || name_length <= 0 || (size_t)name_length >= sizeof(name_buf))
|
||||
return NULL;
|
||||
|
||||
state.current_func = get_func(&state.funcs, name_buf);
|
||||
|
||||
if (state.function_listing) /* Save function names without running tests */
|
||||
return NULL;
|
||||
|
||||
state.funcs->color = 1;
|
||||
CheckasmFuncVersion *v = &state.current_func->versions;
|
||||
void *ref = func;
|
||||
|
||||
if (v->func) {
|
||||
CheckasmFuncVersion *prev;
|
||||
do {
|
||||
/* Only test functions that haven't already been tested */
|
||||
if (v->func == func)
|
||||
return NULL;
|
||||
|
||||
if (v->ok)
|
||||
ref = v->func;
|
||||
|
||||
prev = v;
|
||||
} while ((v = v->next));
|
||||
|
||||
v = prev->next = checkasm_malloc(sizeof(CheckasmFuncVersion));
|
||||
}
|
||||
|
||||
v->func = func;
|
||||
v->ok = 1;
|
||||
v->cpu = state.cpu_flag;
|
||||
state.current_func_ver = v;
|
||||
xor128_srand(state.seed);
|
||||
|
||||
if (state.cpu_flag || state.bench_c)
|
||||
state.num_checked++;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Decide whether or not the current function needs to be benchmarked */
|
||||
int checkasm_bench_func(void) {
|
||||
return !state.num_failed && state.bench_pattern &&
|
||||
!strncmp(state.current_func->name, state.bench_pattern,
|
||||
state.bench_pattern_len);
|
||||
}
|
||||
|
||||
/* Indicate that the current test has failed, return whether verbose printing
|
||||
* is requested. */
|
||||
int checkasm_fail_func(const char *const msg, ...) {
|
||||
if (state.current_func_ver && state.current_func_ver->cpu &&
|
||||
state.current_func_ver->ok)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
print_cpu_name();
|
||||
fprintf(stderr, " %s_%s (", state.current_func->name,
|
||||
cpu_suffix(state.current_func_ver->cpu));
|
||||
va_start(arg, msg);
|
||||
vfprintf(stderr, msg, arg);
|
||||
va_end(arg);
|
||||
fprintf(stderr, ")\n");
|
||||
|
||||
state.current_func_ver->ok = 0;
|
||||
state.num_failed++;
|
||||
}
|
||||
return state.verbose;
|
||||
}
|
||||
|
||||
/* Update benchmark results of the current function */
|
||||
void checkasm_update_bench(const int iterations, const uint64_t cycles) {
|
||||
state.current_func_ver->iterations += iterations;
|
||||
state.current_func_ver->cycles += cycles;
|
||||
}
|
||||
|
||||
/* Print the outcome of all tests performed since
|
||||
* the last time this function was called */
|
||||
void checkasm_report(const char *const name, ...) {
|
||||
static int prev_checked, prev_failed;
|
||||
static size_t max_length;
|
||||
|
||||
if (state.num_checked > prev_checked) {
|
||||
int pad_length = (int) max_length + 4;
|
||||
va_list arg;
|
||||
|
||||
print_cpu_name();
|
||||
pad_length -= fprintf(stderr, " - %s.", state.current_test_name);
|
||||
va_start(arg, name);
|
||||
pad_length -= vfprintf(stderr, name, arg);
|
||||
va_end(arg);
|
||||
fprintf(stderr, "%*c", imax(pad_length, 0) + 2, '[');
|
||||
|
||||
if (state.num_failed == prev_failed)
|
||||
color_printf(COLOR_GREEN, "OK");
|
||||
else
|
||||
color_printf(COLOR_RED, "FAILED");
|
||||
fprintf(stderr, "]\n");
|
||||
|
||||
prev_checked = state.num_checked;
|
||||
prev_failed = state.num_failed;
|
||||
} else if (!state.cpu_flag) {
|
||||
/* Calculate the amount of padding required
|
||||
* to make the output vertically aligned */
|
||||
size_t length = strlen(state.current_test_name);
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, name);
|
||||
length += vsnprintf(NULL, 0, name, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (length > max_length)
|
||||
max_length = length;
|
||||
}
|
||||
}
|
||||
|
||||
void checkasm_set_signal_handler_state(const int enabled) {
|
||||
#ifdef _WIN32
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
if (enabled)
|
||||
AddVectoredExceptionHandler(0, signal_handler);
|
||||
else
|
||||
RemoveVectoredExceptionHandler(signal_handler);
|
||||
#endif
|
||||
#else
|
||||
void (*const handler)(int) = enabled ? signal_handler : SIG_DFL;
|
||||
signal(SIGBUS, handler);
|
||||
signal(SIGFPE, handler);
|
||||
signal(SIGILL, handler);
|
||||
signal(SIGSEGV, handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int check_err(const char *const file, const int line,
|
||||
const char *const name, const int w, const int h,
|
||||
int *const err)
|
||||
{
|
||||
if (*err)
|
||||
return 0;
|
||||
if (!checkasm_fail_func("%s:%d", file, line))
|
||||
return 1;
|
||||
*err = 1;
|
||||
fprintf(stderr, "%s (%dx%d):\n", name, w, h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEF_CHECKASM_CHECK_FUNC(type, fmt) \
|
||||
int checkasm_check_##type(const char *const file, const int line, \
|
||||
const type *buf1, ptrdiff_t stride1, \
|
||||
const type *buf2, ptrdiff_t stride2, \
|
||||
const int w, int h, const char *const name, \
|
||||
const int align_w, const int align_h, \
|
||||
const int padding) \
|
||||
{ \
|
||||
int aligned_w = (w + align_w - 1) & ~(align_w - 1); \
|
||||
int aligned_h = (h + align_h - 1) & ~(align_h - 1); \
|
||||
int err = 0; \
|
||||
stride1 /= sizeof(*buf1); \
|
||||
stride2 /= sizeof(*buf2); \
|
||||
int y = 0; \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1], &buf2[y*stride2], w*sizeof(*buf1))) \
|
||||
break; \
|
||||
if (y != h) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
for (y = 0; y < h; y++) { \
|
||||
for (int x = 0; x < w; x++) \
|
||||
fprintf(stderr, " " fmt, buf1[x]); \
|
||||
fprintf(stderr, " "); \
|
||||
for (int x = 0; x < w; x++) \
|
||||
fprintf(stderr, " " fmt, buf2[x]); \
|
||||
fprintf(stderr, " "); \
|
||||
for (int x = 0; x < w; x++) \
|
||||
fprintf(stderr, "%c", buf1[x] != buf2[x] ? 'x' : '.'); \
|
||||
buf1 += stride1; \
|
||||
buf2 += stride2; \
|
||||
fprintf(stderr, "\n"); \
|
||||
} \
|
||||
buf1 -= h*stride1; \
|
||||
buf2 -= h*stride2; \
|
||||
} \
|
||||
for (y = -padding; y < 0; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
(w + 2*padding)*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite above\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = aligned_h; y < aligned_h + padding; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
(w + 2*padding)*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite below\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1 - padding], &buf2[y*stride2 - padding], \
|
||||
padding*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite left\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (y = 0; y < h; y++) \
|
||||
if (memcmp(&buf1[y*stride1 + aligned_w], &buf2[y*stride2 + aligned_w], \
|
||||
padding*sizeof(*buf1))) { \
|
||||
if (check_err(file, line, name, w, h, &err)) \
|
||||
return 1; \
|
||||
fprintf(stderr, " overwrite right\n"); \
|
||||
break; \
|
||||
} \
|
||||
return err; \
|
||||
}
|
||||
|
||||
DEF_CHECKASM_CHECK_FUNC(int8_t, "%4d")
|
||||
DEF_CHECKASM_CHECK_FUNC(uint8_t, "%02x")
|
||||
DEF_CHECKASM_CHECK_FUNC(uint16_t, "%04x")
|
||||
DEF_CHECKASM_CHECK_FUNC(int16_t, "%6d")
|
||||
DEF_CHECKASM_CHECK_FUNC(int32_t, "%9d")
|
||||
|
||||
#if ARCH_X86_64
|
||||
void checkasm_simd_warmup(void)
|
||||
{
|
||||
if (state.simd_warmup)
|
||||
state.simd_warmup();
|
||||
}
|
||||
#endif
|
349
third_party/dav1d/tests/checkasm/checkasm.h
vendored
349
third_party/dav1d/tests/checkasm/checkasm.h
vendored
@ -1,349 +0,0 @@
|
||||
/*
|
||||
* 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_TESTS_CHECKASM_CHECKASM_H
|
||||
#define DAV1D_TESTS_CHECKASM_CHECKASM_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if ARCH_X86_64 && defined(_WIN32)
|
||||
/* setjmp/longjmp on 64-bit Windows will try to use SEH to unwind the stack,
|
||||
* which doesn't work for assembly functions without unwind information. */
|
||||
#include <windows.h>
|
||||
#define checkasm_context CONTEXT
|
||||
#define checkasm_save_context() RtlCaptureContext(&checkasm_context_buf)
|
||||
#define checkasm_load_context() RtlRestoreContext(&checkasm_context_buf, NULL)
|
||||
#else
|
||||
#include <setjmp.h>
|
||||
#define checkasm_context jmp_buf
|
||||
#define checkasm_save_context() setjmp(checkasm_context_buf)
|
||||
#define checkasm_load_context() longjmp(checkasm_context_buf, 1)
|
||||
#endif
|
||||
|
||||
#include "include/common/attributes.h"
|
||||
#include "include/common/bitdepth.h"
|
||||
#include "include/common/intops.h"
|
||||
|
||||
int xor128_rand(void);
|
||||
#define rnd xor128_rand
|
||||
|
||||
#define decl_check_bitfns(name) \
|
||||
name##_8bpc(void); \
|
||||
name##_16bpc(void)
|
||||
|
||||
void checkasm_check_msac(void);
|
||||
decl_check_bitfns(void checkasm_check_cdef);
|
||||
decl_check_bitfns(void checkasm_check_filmgrain);
|
||||
decl_check_bitfns(void checkasm_check_ipred);
|
||||
decl_check_bitfns(void checkasm_check_itx);
|
||||
decl_check_bitfns(void checkasm_check_loopfilter);
|
||||
decl_check_bitfns(void checkasm_check_looprestoration);
|
||||
decl_check_bitfns(void checkasm_check_mc);
|
||||
|
||||
void *checkasm_check_func(void *func, const char *name, ...);
|
||||
int checkasm_bench_func(void);
|
||||
int checkasm_fail_func(const char *msg, ...);
|
||||
void checkasm_update_bench(int iterations, uint64_t cycles);
|
||||
void checkasm_report(const char *name, ...);
|
||||
void checkasm_set_signal_handler_state(int enabled);
|
||||
extern checkasm_context checkasm_context_buf;
|
||||
|
||||
/* float compare utilities */
|
||||
int float_near_ulp(float a, float b, unsigned max_ulp);
|
||||
int float_near_abs_eps(float a, float b, float eps);
|
||||
int float_near_abs_eps_ulp(float a, float b, float eps, unsigned max_ulp);
|
||||
int float_near_ulp_array(const float *a, const float *b, unsigned max_ulp,
|
||||
int len);
|
||||
int float_near_abs_eps_array(const float *a, const float *b, float eps,
|
||||
int len);
|
||||
int float_near_abs_eps_array_ulp(const float *a, const float *b, float eps,
|
||||
unsigned max_ulp, int len);
|
||||
|
||||
#define BENCH_RUNS (1 << 12) /* Trade-off between accuracy and speed */
|
||||
|
||||
/* Decide whether or not the specified function needs to be tested */
|
||||
#define check_func(func, ...)\
|
||||
(func_ref = checkasm_check_func((func_new = func), __VA_ARGS__))
|
||||
|
||||
/* Declare the function prototype. The first argument is the return value,
|
||||
* the remaining arguments are the function parameters. Naming parameters
|
||||
* is optional. */
|
||||
#define declare_func(ret, ...)\
|
||||
declare_new(ret, __VA_ARGS__)\
|
||||
void *func_ref, *func_new;\
|
||||
typedef ret func_type(__VA_ARGS__);\
|
||||
checkasm_save_context()
|
||||
|
||||
/* Indicate that the current test has failed */
|
||||
#define fail() checkasm_fail_func("%s:%d", __FILE__, __LINE__)
|
||||
|
||||
/* Print the test outcome */
|
||||
#define report checkasm_report
|
||||
|
||||
/* Call the reference function */
|
||||
#define call_ref(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
((func_type *)func_ref)(__VA_ARGS__));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
|
||||
#if HAVE_ASM
|
||||
#if ARCH_X86
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#include <intrin.h>
|
||||
#define readtime() (_mm_lfence(), __rdtsc())
|
||||
#else
|
||||
static inline uint64_t readtime(void) {
|
||||
uint32_t eax, edx;
|
||||
__asm__ __volatile__("lfence\nrdtsc" : "=a"(eax), "=d"(edx));
|
||||
return (((uint64_t)edx) << 32) | eax;
|
||||
}
|
||||
#define readtime readtime
|
||||
#endif
|
||||
#elif (ARCH_AARCH64 || ARCH_ARM) && defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#define readtime() mach_absolute_time()
|
||||
#elif ARCH_AARCH64
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#define readtime() (_InstructionSynchronizationBarrier(), ReadTimeStampCounter())
|
||||
#else
|
||||
static inline uint64_t readtime(void) {
|
||||
uint64_t cycle_counter;
|
||||
/* This requires enabling user mode access to the cycle counter (which
|
||||
* can only be done from kernel space).
|
||||
* This could also read cntvct_el0 instead of pmccntr_el0; that register
|
||||
* might also be readable (depending on kernel version), but it has much
|
||||
* worse precision (it's a fixed 50 MHz timer). */
|
||||
__asm__ __volatile__("isb\nmrs %0, pmccntr_el0"
|
||||
: "=r"(cycle_counter)
|
||||
:: "memory");
|
||||
return cycle_counter;
|
||||
}
|
||||
#define readtime readtime
|
||||
#endif
|
||||
#elif ARCH_ARM && !defined(_MSC_VER) && __ARM_ARCH >= 7
|
||||
static inline uint64_t readtime(void) {
|
||||
uint32_t cycle_counter;
|
||||
/* This requires enabling user mode access to the cycle counter (which
|
||||
* can only be done from kernel space). */
|
||||
__asm__ __volatile__("isb\nmrc p15, 0, %0, c9, c13, 0"
|
||||
: "=r"(cycle_counter)
|
||||
:: "memory");
|
||||
return cycle_counter;
|
||||
}
|
||||
#define readtime readtime
|
||||
#elif ARCH_PPC64LE
|
||||
static inline uint64_t readtime(void) {
|
||||
uint32_t tbu, tbl, temp;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1:\n"
|
||||
"mfspr %2,269\n"
|
||||
"mfspr %0,268\n"
|
||||
"mfspr %1,269\n"
|
||||
"cmpw %2,%1\n"
|
||||
"bne 1b\n"
|
||||
: "=r"(tbl), "=r"(tbu), "=r"(temp)
|
||||
:
|
||||
: "cc");
|
||||
|
||||
return (((uint64_t)tbu) << 32) | (uint64_t)tbl;
|
||||
}
|
||||
#define readtime readtime
|
||||
#endif
|
||||
|
||||
/* Verifies that clobbered callee-saved registers
|
||||
* are properly saved and restored */
|
||||
void checkasm_checked_call(void *func, ...);
|
||||
|
||||
#if ARCH_X86_64
|
||||
/* Evil hack: detect incorrect assumptions that 32-bit ints are zero-extended
|
||||
* to 64-bit. This is done by clobbering the stack with junk around the stack
|
||||
* pointer and calling the assembly function through checked_call() with added
|
||||
* dummy arguments which forces all real arguments to be passed on the stack
|
||||
* and not in registers. For 32-bit arguments the upper half of the 64-bit
|
||||
* register locations on the stack will now contain junk which will cause
|
||||
* misbehaving functions to either produce incorrect output or segfault. Note
|
||||
* that even though this works extremely well in practice, it's technically
|
||||
* not guaranteed and false negatives is theoretically possible, but there
|
||||
* can never be any false positives. */
|
||||
void checkasm_stack_clobber(uint64_t clobber, ...);
|
||||
/* YMM and ZMM registers on x86 are turned off to save power when they haven't
|
||||
* been used for some period of time. When they are used there will be a
|
||||
* "warmup" period during which performance will be reduced and inconsistent
|
||||
* which is problematic when trying to benchmark individual functions. We can
|
||||
* work around this by periodically issuing "dummy" instructions that uses
|
||||
* those registers to keep them powered on. */
|
||||
void checkasm_simd_warmup(void);
|
||||
#define declare_new(ret, ...)\
|
||||
ret (*checked_call)(void *, int, int, int, int, int, __VA_ARGS__,\
|
||||
int, int, int, int, int, int, int, int,\
|
||||
int, int, int, int, int, int, int) =\
|
||||
(void *)checkasm_checked_call;
|
||||
#define CLOB (UINT64_C(0xdeadbeefdeadbeef))
|
||||
#ifdef _WIN32
|
||||
#define STACKARGS 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0
|
||||
#else
|
||||
#define STACKARGS 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0
|
||||
#endif
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
checkasm_simd_warmup(),\
|
||||
checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
|
||||
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
|
||||
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB),\
|
||||
checked_call(func_new, 0, 0, 0, 0, 0, __VA_ARGS__, STACKARGS));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#elif ARCH_X86_32
|
||||
#define declare_new(ret, ...)\
|
||||
ret (*checked_call)(void *, __VA_ARGS__, int, int, int, int, int, int,\
|
||||
int, int, int, int, int, int, int, int, int) =\
|
||||
(void *)checkasm_checked_call;
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
checked_call(func_new, __VA_ARGS__, 15, 14, 13, 12,\
|
||||
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#elif ARCH_ARM
|
||||
/* Use a dummy argument, to offset the real parameters by 2, not only 1.
|
||||
* This makes sure that potential 8-byte-alignment of parameters is kept
|
||||
* the same even when the extra parameters have been removed. */
|
||||
void checkasm_checked_call_vfp(void *func, int dummy, ...);
|
||||
#define declare_new(ret, ...)\
|
||||
ret (*checked_call)(void *, int dummy, __VA_ARGS__,\
|
||||
int, int, int, int, int, int, int, int,\
|
||||
int, int, int, int, int, int, int) =\
|
||||
(void *)checkasm_checked_call_vfp;
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
checked_call(func_new, 0, __VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#elif ARCH_AARCH64 && !defined(__APPLE__)
|
||||
void checkasm_stack_clobber(uint64_t clobber, ...);
|
||||
#define declare_new(ret, ...)\
|
||||
ret (*checked_call)(void *, int, int, int, int, int, int, int,\
|
||||
__VA_ARGS__, int, int, int, int, int, int, int, int,\
|
||||
int, int, int, int, int, int, int) =\
|
||||
(void *)checkasm_checked_call;
|
||||
#define CLOB (UINT64_C(0xdeadbeefdeadbeef))
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
|
||||
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
|
||||
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
|
||||
CLOB, CLOB, CLOB, CLOB, CLOB),\
|
||||
checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__,\
|
||||
7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#else
|
||||
#define declare_new(ret, ...)
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
((func_type *)func_new)(__VA_ARGS__));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#endif
|
||||
#else /* HAVE_ASM */
|
||||
#define declare_new(ret, ...)
|
||||
/* Call the function */
|
||||
#define call_new(...)\
|
||||
(checkasm_set_signal_handler_state(1),\
|
||||
((func_type *)func_new)(__VA_ARGS__));\
|
||||
checkasm_set_signal_handler_state(0)
|
||||
#endif /* HAVE_ASM */
|
||||
|
||||
/* Benchmark the function */
|
||||
#ifdef readtime
|
||||
#define bench_new(...)\
|
||||
do {\
|
||||
func_type *tfunc = func_new;\
|
||||
checkasm_set_signal_handler_state(1);\
|
||||
if (checkasm_bench_func()) {\
|
||||
uint64_t tsum = 0;\
|
||||
int tcount = 0;\
|
||||
for (int ti = 0; ti < BENCH_RUNS; ti++) {\
|
||||
uint64_t t = readtime();\
|
||||
tfunc(__VA_ARGS__);\
|
||||
tfunc(__VA_ARGS__);\
|
||||
tfunc(__VA_ARGS__);\
|
||||
tfunc(__VA_ARGS__);\
|
||||
t = readtime() - t;\
|
||||
if (t*tcount <= tsum*4 && ti > 0) {\
|
||||
tsum += t;\
|
||||
tcount++;\
|
||||
}\
|
||||
}\
|
||||
checkasm_update_bench(tcount, tsum);\
|
||||
} else {\
|
||||
tfunc(__VA_ARGS__);\
|
||||
}\
|
||||
checkasm_set_signal_handler_state(0);\
|
||||
} while (0)
|
||||
#else
|
||||
#define bench_new(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#define PIXEL_RECT(name, w, h) \
|
||||
ALIGN_STK_64(pixel, name##_buf, ((h)+32)*((w)+64) + 64,); \
|
||||
ptrdiff_t name##_stride = sizeof(pixel)*((w)+64); \
|
||||
(void)name##_stride; \
|
||||
pixel *name = name##_buf + ((w)+64)*16 + 64
|
||||
|
||||
#define CLEAR_PIXEL_RECT(name) \
|
||||
memset(name##_buf, 0x99, sizeof(name##_buf)) \
|
||||
|
||||
#define DECL_CHECKASM_CHECK_FUNC(type) \
|
||||
int checkasm_check_##type(const char *const file, const int line, \
|
||||
const type *const buf1, const ptrdiff_t stride1, \
|
||||
const type *const buf2, const ptrdiff_t stride2, \
|
||||
const int w, const int h, const char *const name, \
|
||||
const int align_w, const int align_h, \
|
||||
const int padding)
|
||||
|
||||
DECL_CHECKASM_CHECK_FUNC(int8_t);
|
||||
DECL_CHECKASM_CHECK_FUNC(uint8_t);
|
||||
DECL_CHECKASM_CHECK_FUNC(uint16_t);
|
||||
DECL_CHECKASM_CHECK_FUNC(int16_t);
|
||||
DECL_CHECKASM_CHECK_FUNC(int32_t);
|
||||
|
||||
|
||||
#define CONCAT(a,b) a ## b
|
||||
|
||||
#define checkasm_check2(prefix, ...) CONCAT(checkasm_check_, prefix)(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define checkasm_check(prefix, ...) checkasm_check2(prefix, __VA_ARGS__, 0, 0, 0)
|
||||
|
||||
#ifdef BITDEPTH
|
||||
#define checkasm_check_pixel(...) checkasm_check(PIXEL_TYPE, __VA_ARGS__)
|
||||
#define checkasm_check_pixel_padded(...) checkasm_check2(PIXEL_TYPE, __VA_ARGS__, 1, 1, 8)
|
||||
#define checkasm_check_pixel_padded_align(...) checkasm_check2(PIXEL_TYPE, __VA_ARGS__, 8)
|
||||
#define checkasm_check_coef(...) checkasm_check(COEF_TYPE, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* DAV1D_TESTS_CHECKASM_CHECKASM_H */
|
401
third_party/dav1d/tests/checkasm/filmgrain.c
vendored
401
third_party/dav1d/tests/checkasm/filmgrain.c
vendored
@ -1,401 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019, VideoLAN and dav1d authors
|
||||
* Copyright © 2019, 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/levels.h"
|
||||
#include "src/film_grain.h"
|
||||
#define UNIT_TEST 1
|
||||
#include "src/fg_apply_tmpl.c"
|
||||
|
||||
#if BITDEPTH == 8
|
||||
#define checkasm_check_entry(...) checkasm_check(int8_t, __VA_ARGS__)
|
||||
#else
|
||||
#define checkasm_check_entry(...) checkasm_check(int16_t, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static const char ss_name[][4] = {
|
||||
[DAV1D_PIXEL_LAYOUT_I420 - 1] = "420",
|
||||
[DAV1D_PIXEL_LAYOUT_I422 - 1] = "422",
|
||||
[DAV1D_PIXEL_LAYOUT_I444 - 1] = "444",
|
||||
};
|
||||
|
||||
static void check_gen_grny(const Dav1dFilmGrainDSPContext *const dsp) {
|
||||
entry grain_lut_c[GRAIN_HEIGHT][GRAIN_WIDTH];
|
||||
entry grain_lut_a[GRAIN_HEIGHT + 1][GRAIN_WIDTH];
|
||||
|
||||
declare_func(void, entry grain_lut[][GRAIN_WIDTH],
|
||||
const Dav1dFilmGrainData *data HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (check_func(dsp->generate_grain_y, "gen_grain_y_ar%d_%dbpc", i, BITDEPTH)) {
|
||||
ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
|
||||
fg_data[0].seed = rnd() & 0xFFFF;
|
||||
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#endif
|
||||
|
||||
fg_data[0].grain_scale_shift = rnd() & 3;
|
||||
fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
|
||||
fg_data[0].ar_coeff_lag = i;
|
||||
const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
|
||||
for (int n = 0; n < num_y_pos; n++)
|
||||
fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
|
||||
|
||||
call_ref(grain_lut_c, fg_data HIGHBD_TAIL_SUFFIX);
|
||||
call_new(grain_lut_a, fg_data HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_entry(grain_lut_c[0], sizeof(entry) * GRAIN_WIDTH,
|
||||
grain_lut_a[0], sizeof(entry) * GRAIN_WIDTH,
|
||||
GRAIN_WIDTH, GRAIN_HEIGHT, "grain_lut");
|
||||
|
||||
bench_new(grain_lut_a, fg_data HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
|
||||
report("gen_grain_y");
|
||||
}
|
||||
|
||||
static void check_gen_grnuv(const Dav1dFilmGrainDSPContext *const dsp) {
|
||||
entry grain_lut_y[GRAIN_HEIGHT + 1][GRAIN_WIDTH];
|
||||
entry grain_lut_c[GRAIN_HEIGHT][GRAIN_WIDTH];
|
||||
entry grain_lut_a[GRAIN_HEIGHT + 1][GRAIN_WIDTH];
|
||||
|
||||
declare_func(void, entry grain_lut[][GRAIN_WIDTH],
|
||||
const entry grain_lut_y[][GRAIN_WIDTH],
|
||||
const Dav1dFilmGrainData *data, intptr_t uv HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int layout_idx = 0; layout_idx < 3; layout_idx++) {
|
||||
const enum Dav1dPixelLayout layout = layout_idx + 1;
|
||||
const int ss_x = layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int ss_y = layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (check_func(dsp->generate_grain_uv[layout_idx],
|
||||
"gen_grain_uv_ar%d_%dbpc_%s",
|
||||
i, BITDEPTH, ss_name[layout_idx]))
|
||||
{
|
||||
ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
|
||||
fg_data[0].seed = rnd() & 0xFFFF;
|
||||
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#endif
|
||||
|
||||
fg_data[0].num_y_points = rnd() & 1;
|
||||
fg_data[0].grain_scale_shift = rnd() & 3;
|
||||
fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
|
||||
fg_data[0].ar_coeff_lag = i;
|
||||
const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
|
||||
for (int n = 0; n < num_y_pos; n++)
|
||||
fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
|
||||
dsp->generate_grain_y(grain_lut_y, fg_data HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
const int uv = rnd() & 1;
|
||||
const int num_uv_pos = num_y_pos + !!fg_data[0].num_y_points;
|
||||
for (int n = 0; n < num_uv_pos; n++)
|
||||
fg_data[0].ar_coeffs_uv[uv][n] = (rnd() & 0xff) - 128;
|
||||
if (!fg_data[0].num_y_points)
|
||||
fg_data[0].ar_coeffs_uv[uv][num_uv_pos] = 0;
|
||||
memset(grain_lut_c, 0xff, sizeof(grain_lut_c));
|
||||
memset(grain_lut_a, 0xff, sizeof(grain_lut_a));
|
||||
call_ref(grain_lut_c, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
|
||||
call_new(grain_lut_a, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
|
||||
int w = ss_x ? 44 : GRAIN_WIDTH;
|
||||
int h = ss_y ? 38 : GRAIN_HEIGHT;
|
||||
checkasm_check_entry(grain_lut_c[0], sizeof(entry) * GRAIN_WIDTH,
|
||||
grain_lut_a[0], sizeof(entry) * GRAIN_WIDTH,
|
||||
w, h, "grain_lut");
|
||||
|
||||
bench_new(grain_lut_a, grain_lut_y, fg_data, uv HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report("gen_grain_uv");
|
||||
}
|
||||
|
||||
static void check_fgy_sbrow(const Dav1dFilmGrainDSPContext *const dsp) {
|
||||
PIXEL_RECT(c_dst, 128, 32);
|
||||
PIXEL_RECT(a_dst, 128, 32);
|
||||
PIXEL_RECT(src, 128, 32);
|
||||
const ptrdiff_t stride = c_dst_stride;
|
||||
|
||||
declare_func(void, pixel *dst_row, const pixel *src_row, ptrdiff_t stride,
|
||||
const Dav1dFilmGrainData *data, size_t pw,
|
||||
const uint8_t scaling[SCALING_SIZE],
|
||||
const entry grain_lut[][GRAIN_WIDTH],
|
||||
int bh, int row_num HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(dsp->fgy_32x32xn, "fgy_32x32xn_%dbpc", BITDEPTH)) {
|
||||
ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 16,);
|
||||
fg_data[0].seed = rnd() & 0xFFFF;
|
||||
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
uint8_t scaling[SCALING_SIZE];
|
||||
entry grain_lut[GRAIN_HEIGHT + 1][GRAIN_WIDTH];
|
||||
fg_data[0].grain_scale_shift = rnd() & 3;
|
||||
fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
|
||||
fg_data[0].ar_coeff_lag = rnd() & 3;
|
||||
const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
|
||||
for (int n = 0; n < num_y_pos; n++)
|
||||
fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
|
||||
dsp->generate_grain_y(grain_lut, fg_data HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
fg_data[0].num_y_points = 2 + (rnd() % 13);
|
||||
const int pad = 0xff / fg_data[0].num_y_points;
|
||||
for (int n = 0; n < fg_data[0].num_y_points; n++) {
|
||||
fg_data[0].y_points[n][0] = 0xff * n / fg_data[0].num_y_points;
|
||||
fg_data[0].y_points[n][0] += rnd() % pad;
|
||||
fg_data[0].y_points[n][1] = rnd() & 0xff;
|
||||
}
|
||||
generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].y_points,
|
||||
fg_data[0].num_y_points, scaling);
|
||||
|
||||
fg_data[0].clip_to_restricted_range = rnd() & 1;
|
||||
fg_data[0].scaling_shift = (rnd() & 3) + 8;
|
||||
for (fg_data[0].overlap_flag = 0; fg_data[0].overlap_flag <= 1;
|
||||
fg_data[0].overlap_flag++)
|
||||
{
|
||||
for (int i = 0; i <= 2 * fg_data[0].overlap_flag; i++) {
|
||||
int w, h, row_num;
|
||||
if (fg_data[0].overlap_flag) {
|
||||
w = 35 + (rnd() % 93);
|
||||
if (i == 0) {
|
||||
row_num = 0;
|
||||
h = 1 + (rnd() % 31);
|
||||
} else {
|
||||
row_num = 1 + (rnd() & 0x7ff);
|
||||
if (i == 1) {
|
||||
h = 3 + (rnd() % 30);
|
||||
} else {
|
||||
h = 1 + (rnd() & 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w = 1 + (rnd() & 127);
|
||||
h = 1 + (rnd() & 31);
|
||||
row_num = rnd() & 0x7ff;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 32; y++) {
|
||||
// Src pixels past the right edge can be uninitialized
|
||||
for (int x = 0; x < 128; x++)
|
||||
src[y * PXSTRIDE(stride) + x] = rnd();
|
||||
for (int x = 0; x < w; x++)
|
||||
src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
|
||||
}
|
||||
|
||||
CLEAR_PIXEL_RECT(c_dst);
|
||||
CLEAR_PIXEL_RECT(a_dst);
|
||||
call_ref(c_dst, src, stride, fg_data, w, scaling, grain_lut, h,
|
||||
row_num HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, src, stride, fg_data, w, scaling, grain_lut, h,
|
||||
row_num HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
checkasm_check_pixel_padded_align(c_dst, stride, a_dst, stride,
|
||||
w, h, "dst", 32, 2);
|
||||
}
|
||||
}
|
||||
fg_data[0].overlap_flag = 1;
|
||||
for (int y = 0; y < 32; y++) {
|
||||
// Make sure all pixels are in range
|
||||
for (int x = 0; x < 128; x++)
|
||||
src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
|
||||
}
|
||||
bench_new(a_dst, src, stride, fg_data, 64, scaling, grain_lut, 32,
|
||||
1 HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
|
||||
report("fgy_32x32xn");
|
||||
}
|
||||
|
||||
static void check_fguv_sbrow(const Dav1dFilmGrainDSPContext *const dsp) {
|
||||
PIXEL_RECT(c_dst, 128, 32);
|
||||
PIXEL_RECT(a_dst, 128, 32);
|
||||
PIXEL_RECT(src, 128, 32);
|
||||
PIXEL_RECT(luma_src, 128, 32);
|
||||
const ptrdiff_t lstride = luma_src_stride;
|
||||
|
||||
declare_func(void, pixel *dst_row, const pixel *src_row, ptrdiff_t stride,
|
||||
const Dav1dFilmGrainData *data, size_t pw,
|
||||
const uint8_t scaling[SCALING_SIZE],
|
||||
const entry grain_lut[][GRAIN_WIDTH], int bh, int row_num,
|
||||
const pixel *luma_row, ptrdiff_t luma_stride, int uv_pl,
|
||||
int is_identity HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int layout_idx = 0; layout_idx < 3; layout_idx++) {
|
||||
const enum Dav1dPixelLayout layout = layout_idx + 1;
|
||||
const int ss_x = layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int ss_y = layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const ptrdiff_t stride = c_dst_stride;
|
||||
|
||||
for (int csfl = 0; csfl <= 1; csfl++) {
|
||||
if (check_func(dsp->fguv_32x32xn[layout_idx],
|
||||
"fguv_32x32xn_%dbpc_%s_csfl%d",
|
||||
BITDEPTH, ss_name[layout_idx], csfl))
|
||||
{
|
||||
ALIGN_STK_16(Dav1dFilmGrainData, fg_data, 1,);
|
||||
|
||||
fg_data[0].seed = rnd() & 0xFFFF;
|
||||
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
const int uv_pl = rnd() & 1;
|
||||
const int is_identity = rnd() & 1;
|
||||
|
||||
uint8_t scaling[SCALING_SIZE];
|
||||
entry grain_lut[2][GRAIN_HEIGHT + 1][GRAIN_WIDTH];
|
||||
fg_data[0].grain_scale_shift = rnd() & 3;
|
||||
fg_data[0].ar_coeff_shift = (rnd() & 3) + 6;
|
||||
fg_data[0].ar_coeff_lag = rnd() & 3;
|
||||
const int num_y_pos = 2 * fg_data[0].ar_coeff_lag * (fg_data[0].ar_coeff_lag + 1);
|
||||
for (int n = 0; n < num_y_pos; n++)
|
||||
fg_data[0].ar_coeffs_y[n] = (rnd() & 0xff) - 128;
|
||||
const int num_uv_pos = num_y_pos + 1;
|
||||
for (int n = 0; n < num_uv_pos; n++)
|
||||
fg_data[0].ar_coeffs_uv[uv_pl][n] = (rnd() & 0xff) - 128;
|
||||
dsp->generate_grain_y(grain_lut[0], fg_data HIGHBD_TAIL_SUFFIX);
|
||||
dsp->generate_grain_uv[layout_idx](grain_lut[1], grain_lut[0],
|
||||
fg_data, uv_pl HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
if (csfl) {
|
||||
fg_data[0].num_y_points = 2 + (rnd() % 13);
|
||||
const int pad = 0xff / fg_data[0].num_y_points;
|
||||
for (int n = 0; n < fg_data[0].num_y_points; n++) {
|
||||
fg_data[0].y_points[n][0] = 0xff * n / fg_data[0].num_y_points;
|
||||
fg_data[0].y_points[n][0] += rnd() % pad;
|
||||
fg_data[0].y_points[n][1] = rnd() & 0xff;
|
||||
}
|
||||
generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].y_points,
|
||||
fg_data[0].num_y_points, scaling);
|
||||
} else {
|
||||
fg_data[0].num_uv_points[uv_pl] = 2 + (rnd() % 9);
|
||||
const int pad = 0xff / fg_data[0].num_uv_points[uv_pl];
|
||||
for (int n = 0; n < fg_data[0].num_uv_points[uv_pl]; n++) {
|
||||
fg_data[0].uv_points[uv_pl][n][0] = 0xff * n / fg_data[0].num_uv_points[uv_pl];
|
||||
fg_data[0].uv_points[uv_pl][n][0] += rnd() % pad;
|
||||
fg_data[0].uv_points[uv_pl][n][1] = rnd() & 0xff;
|
||||
}
|
||||
generate_scaling(bitdepth_from_max(bitdepth_max), fg_data[0].uv_points[uv_pl],
|
||||
fg_data[0].num_uv_points[uv_pl], scaling);
|
||||
|
||||
fg_data[0].uv_mult[uv_pl] = (rnd() & 0xff) - 128;
|
||||
fg_data[0].uv_luma_mult[uv_pl] = (rnd() & 0xff) - 128;
|
||||
fg_data[0].uv_offset[uv_pl] = (rnd() & 0x1ff) - 256;
|
||||
}
|
||||
|
||||
fg_data[0].clip_to_restricted_range = rnd() & 1;
|
||||
fg_data[0].scaling_shift = (rnd() & 3) + 8;
|
||||
fg_data[0].chroma_scaling_from_luma = csfl;
|
||||
for (fg_data[0].overlap_flag = 0; fg_data[0].overlap_flag <= 1;
|
||||
fg_data[0].overlap_flag++)
|
||||
{
|
||||
for (int i = 0; i <= 2 * fg_data[0].overlap_flag; i++) {
|
||||
int w, h, row_num;
|
||||
if (fg_data[0].overlap_flag) {
|
||||
w = (36 >> ss_x) + (rnd() % (92 >> ss_x));
|
||||
if (i == 0) {
|
||||
row_num = 0;
|
||||
h = 1 + (rnd() & (31 >> ss_y));
|
||||
} else {
|
||||
row_num = 1 + (rnd() & 0x7ff);
|
||||
if (i == 1) {
|
||||
h = (ss_y ? 2 : 3) + (rnd() % (ss_y ? 15 : 30));
|
||||
} else {
|
||||
h = ss_y ? 1 : 1 + (rnd() & 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w = 1 + (rnd() & (127 >> ss_x));
|
||||
h = 1 + (rnd() & (31 >> ss_y));
|
||||
row_num = rnd() & 0x7ff;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 32; y++) {
|
||||
// Src pixels past the right edge can be uninitialized
|
||||
for (int x = 0; x < 128; x++) {
|
||||
src[y * PXSTRIDE(stride) + x] = rnd();
|
||||
luma_src[y * PXSTRIDE(lstride) + x] = rnd();
|
||||
}
|
||||
for (int x = 0; x < w; x++)
|
||||
src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
|
||||
for (int x = 0; x < (w << ss_x); x++)
|
||||
luma_src[y * PXSTRIDE(lstride) + x] &= bitdepth_max;
|
||||
}
|
||||
|
||||
CLEAR_PIXEL_RECT(c_dst);
|
||||
CLEAR_PIXEL_RECT(a_dst);
|
||||
call_ref(c_dst, src, stride, fg_data, w, scaling, grain_lut[1], h,
|
||||
row_num, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, src, stride, fg_data, w, scaling, grain_lut[1], h,
|
||||
row_num, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
checkasm_check_pixel_padded_align(c_dst, stride,
|
||||
a_dst, stride,
|
||||
w, h, "dst",
|
||||
32 >> ss_x, 2);
|
||||
}
|
||||
}
|
||||
|
||||
fg_data[0].overlap_flag = 1;
|
||||
for (int y = 0; y < 32; y++) {
|
||||
// Make sure all pixels are in range
|
||||
for (int x = 0; x < 128; x++) {
|
||||
src[y * PXSTRIDE(stride) + x] &= bitdepth_max;
|
||||
luma_src[y * PXSTRIDE(lstride) + x] &= bitdepth_max;
|
||||
}
|
||||
}
|
||||
bench_new(a_dst, src, stride, fg_data, 32, scaling, grain_lut[1], 16,
|
||||
1, luma_src, lstride, uv_pl, is_identity HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report("fguv_32x32xn");
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_filmgrain)(void) {
|
||||
Dav1dFilmGrainDSPContext c;
|
||||
|
||||
bitfn(dav1d_film_grain_dsp_init)(&c);
|
||||
|
||||
check_gen_grny(&c);
|
||||
check_gen_grnuv(&c);
|
||||
check_fgy_sbrow(&c);
|
||||
check_fguv_sbrow(&c);
|
||||
}
|
289
third_party/dav1d/tests/checkasm/ipred.c
vendored
289
third_party/dav1d/tests/checkasm/ipred.c
vendored
@ -1,289 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
#include "src/ipred.h"
|
||||
#include "src/levels.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *const intra_pred_mode_names[N_IMPL_INTRA_PRED_MODES] = {
|
||||
[DC_PRED] = "dc",
|
||||
[DC_128_PRED] = "dc_128",
|
||||
[TOP_DC_PRED] = "dc_top",
|
||||
[LEFT_DC_PRED] = "dc_left",
|
||||
[HOR_PRED] = "h",
|
||||
[VERT_PRED] = "v",
|
||||
[PAETH_PRED] = "paeth",
|
||||
[SMOOTH_PRED] = "smooth",
|
||||
[SMOOTH_V_PRED] = "smooth_v",
|
||||
[SMOOTH_H_PRED] = "smooth_h",
|
||||
[Z1_PRED] = "z1",
|
||||
[Z2_PRED] = "z2",
|
||||
[Z3_PRED] = "z3",
|
||||
[FILTER_PRED] = "filter"
|
||||
};
|
||||
|
||||
static const char *const cfl_ac_names[3] = { "420", "422", "444" };
|
||||
|
||||
static const char *const cfl_pred_mode_names[DC_128_PRED + 1] = {
|
||||
[DC_PRED] = "cfl",
|
||||
[DC_128_PRED] = "cfl_128",
|
||||
[TOP_DC_PRED] = "cfl_top",
|
||||
[LEFT_DC_PRED] = "cfl_left",
|
||||
};
|
||||
|
||||
static const uint8_t z_angles[27] = {
|
||||
3, 6, 9,
|
||||
14, 17, 20, 23, 26, 29, 32,
|
||||
36, 39, 42, 45, 48, 51, 54,
|
||||
58, 61, 64, 67, 70, 73, 76,
|
||||
81, 84, 87
|
||||
};
|
||||
|
||||
static void check_intra_pred(Dav1dIntraPredDSPContext *const c) {
|
||||
PIXEL_RECT(c_dst, 64, 64);
|
||||
PIXEL_RECT(a_dst, 64, 64);
|
||||
ALIGN_STK_64(pixel, topleft_buf, 257,);
|
||||
pixel *const topleft = topleft_buf + 128;
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t stride, const pixel *topleft,
|
||||
int width, int height, int angle, int max_width, int max_height
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int mode = 0; mode < N_IMPL_INTRA_PRED_MODES; mode++) {
|
||||
int bpc_min = BITDEPTH, bpc_max = BITDEPTH;
|
||||
if (mode == FILTER_PRED && BITDEPTH == 16) {
|
||||
bpc_min = 10;
|
||||
bpc_max = 12;
|
||||
}
|
||||
for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2)
|
||||
for (int w = 4; w <= (mode == FILTER_PRED ? 32 : 64); w <<= 1)
|
||||
if (check_func(c->intra_pred[mode], "intra_pred_%s_w%d_%dbpc",
|
||||
intra_pred_mode_names[mode], w, bpc))
|
||||
{
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4,
|
||||
(mode == FILTER_PRED ? 32 : 64)); h <<= 1)
|
||||
{
|
||||
const ptrdiff_t stride = c_dst_stride;
|
||||
|
||||
int a = 0, maxw = 0, maxh = 0;
|
||||
if (mode >= Z1_PRED && mode <= Z3_PRED) { /* angle */
|
||||
a = (90 * (mode - Z1_PRED) + z_angles[rnd() % 27]) |
|
||||
(rnd() & 0x600);
|
||||
if (mode == Z2_PRED) {
|
||||
maxw = rnd(), maxh = rnd();
|
||||
maxw = 1 + (maxw & (maxw & 4096 ? 4095 : w - 1));
|
||||
maxh = 1 + (maxh & (maxh & 4096 ? 4095 : h - 1));
|
||||
}
|
||||
} else if (mode == FILTER_PRED) /* filter_idx */
|
||||
a = (rnd() % 5) | (rnd() & ~511);
|
||||
|
||||
int bitdepth_max;
|
||||
if (bpc == 16)
|
||||
bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
else
|
||||
bitdepth_max = (1 << bpc) - 1;
|
||||
|
||||
for (int i = -h * 2; i <= w * 2; i++)
|
||||
topleft[i] = rnd() & bitdepth_max;
|
||||
|
||||
CLEAR_PIXEL_RECT(c_dst);
|
||||
CLEAR_PIXEL_RECT(a_dst);
|
||||
call_ref(c_dst, stride, topleft, w, h, a, maxw, maxh
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, stride, topleft, w, h, a, maxw, maxh
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
if (checkasm_check_pixel_padded(c_dst, stride,
|
||||
a_dst, stride,
|
||||
w, h, "dst"))
|
||||
{
|
||||
if (mode == Z1_PRED || mode == Z3_PRED)
|
||||
fprintf(stderr, "angle = %d (0x%03x)\n",
|
||||
a & 0x1ff, a & 0x600);
|
||||
else if (mode == Z2_PRED)
|
||||
fprintf(stderr, "angle = %d (0x%03x), "
|
||||
"max_width = %d, max_height = %d\n",
|
||||
a & 0x1ff, a & 0x600, maxw, maxh);
|
||||
else if (mode == FILTER_PRED)
|
||||
fprintf(stderr, "filter_idx = %d\n", a & 0x1ff);
|
||||
}
|
||||
|
||||
bench_new(a_dst, stride, topleft, w, h, a, 128, 128
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
report("intra_pred");
|
||||
}
|
||||
|
||||
static void check_cfl_ac(Dav1dIntraPredDSPContext *const c) {
|
||||
ALIGN_STK_64(int16_t, c_dst, 32 * 32,);
|
||||
ALIGN_STK_64(int16_t, a_dst, 32 * 32,);
|
||||
ALIGN_STK_64(pixel, luma, 32 * 32,);
|
||||
|
||||
declare_func(void, int16_t *ac, const pixel *y, ptrdiff_t stride,
|
||||
int w_pad, int h_pad, int cw, int ch);
|
||||
|
||||
for (int layout = 1; layout <= DAV1D_PIXEL_LAYOUT_I444; layout++) {
|
||||
const int ss_ver = layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const int ss_hor = layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int h_step = 2 >> ss_hor, v_step = 2 >> ss_ver;
|
||||
for (int w = 4; w <= (32 >> ss_hor); w <<= 1)
|
||||
if (check_func(c->cfl_ac[layout - 1], "cfl_ac_%s_w%d_%dbpc",
|
||||
cfl_ac_names[layout - 1], w, BITDEPTH))
|
||||
{
|
||||
for (int h = imax(w / 4, 4);
|
||||
h <= imin(w * 4, (32 >> ss_ver)); h <<= 1)
|
||||
{
|
||||
const ptrdiff_t stride = 32 * sizeof(pixel);
|
||||
for (int w_pad = imax((w >> 2) - h_step, 0);
|
||||
w_pad >= 0; w_pad -= h_step)
|
||||
{
|
||||
for (int h_pad = imax((h >> 2) - v_step, 0);
|
||||
h_pad >= 0; h_pad -= v_step)
|
||||
{
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
for (int y = 0; y < (h << ss_ver); y++)
|
||||
for (int x = 0; x < (w << ss_hor); x++)
|
||||
luma[y * 32 + x] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, luma, stride, w_pad, h_pad, w, h);
|
||||
call_new(a_dst, luma, stride, w_pad, h_pad, w, h);
|
||||
checkasm_check(int16_t, c_dst, w * sizeof(*c_dst),
|
||||
a_dst, w * sizeof(*a_dst),
|
||||
w, h, "dst");
|
||||
}
|
||||
}
|
||||
|
||||
bench_new(a_dst, luma, stride, 0, 0, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
report("cfl_ac");
|
||||
}
|
||||
|
||||
static void check_cfl_pred(Dav1dIntraPredDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, c_dst, 32 * 32,);
|
||||
ALIGN_STK_64(pixel, a_dst, 32 * 32,);
|
||||
ALIGN_STK_64(int16_t, ac, 32 * 32,);
|
||||
ALIGN_STK_64(pixel, topleft_buf, 257,);
|
||||
pixel *const topleft = topleft_buf + 128;
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t stride, const pixel *topleft,
|
||||
int width, int height, const int16_t *ac, int alpha
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int mode = 0; mode <= DC_128_PRED; mode += 1 + 2 * !mode)
|
||||
for (int w = 4; w <= 32; w <<= 1)
|
||||
if (check_func(c->cfl_pred[mode], "cfl_pred_%s_w%d_%dbpc",
|
||||
cfl_pred_mode_names[mode], w, BITDEPTH))
|
||||
{
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 32); h <<= 1)
|
||||
{
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
const ptrdiff_t stride = w * sizeof(pixel);
|
||||
|
||||
int alpha = ((rnd() & 15) + 1) * (1 - (rnd() & 2));
|
||||
|
||||
for (int i = -h * 2; i <= w * 2; i++)
|
||||
topleft[i] = rnd() & bitdepth_max;
|
||||
|
||||
int luma_avg = w * h >> 1;
|
||||
for (int i = 0; i < w * h; i++)
|
||||
luma_avg += ac[i] = rnd() & (bitdepth_max << 3);
|
||||
luma_avg /= w * h;
|
||||
for (int i = 0; i < w * h; i++)
|
||||
ac[i] -= luma_avg;
|
||||
|
||||
call_ref(c_dst, stride, topleft, w, h, ac, alpha
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, stride, topleft, w, h, ac, alpha
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, stride, a_dst, stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, stride, topleft, w, h, ac, alpha
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("cfl_pred");
|
||||
}
|
||||
|
||||
static void check_pal_pred(Dav1dIntraPredDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, c_dst, 64 * 64,);
|
||||
ALIGN_STK_64(pixel, a_dst, 64 * 64,);
|
||||
ALIGN_STK_64(uint8_t, idx, 64 * 64,);
|
||||
ALIGN_STK_16(uint16_t, pal, 8,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t stride, const uint16_t *pal,
|
||||
const uint8_t *idx, int w, int h);
|
||||
|
||||
for (int w = 4; w <= 64; w <<= 1)
|
||||
if (check_func(c->pal_pred, "pal_pred_w%d_%dbpc", w, BITDEPTH))
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 64); h <<= 1)
|
||||
{
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
const ptrdiff_t stride = w * sizeof(pixel);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
pal[i] = rnd() & bitdepth_max;
|
||||
|
||||
for (int i = 0; i < w * h; i++)
|
||||
idx[i] = rnd() & 7;
|
||||
|
||||
call_ref(c_dst, stride, pal, idx, w, h);
|
||||
call_new(a_dst, stride, pal, idx, w, h);
|
||||
checkasm_check_pixel(c_dst, stride, a_dst, stride, w, h, "dst");
|
||||
|
||||
bench_new(a_dst, stride, pal, idx, w, h);
|
||||
}
|
||||
report("pal_pred");
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_ipred)(void) {
|
||||
Dav1dIntraPredDSPContext c;
|
||||
bitfn(dav1d_intra_pred_dsp_init)(&c);
|
||||
|
||||
check_intra_pred(&c);
|
||||
check_cfl_ac(&c);
|
||||
check_cfl_pred(&c);
|
||||
check_pal_pred(&c);
|
||||
}
|
308
third_party/dav1d/tests/checkasm/itx.c
vendored
308
third_party/dav1d/tests/checkasm/itx.c
vendored
@ -1,308 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "src/itx.h"
|
||||
#include "src/levels.h"
|
||||
#include "src/scan.h"
|
||||
#include "src/tables.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_SQRT1_2
|
||||
#define M_SQRT1_2 0.707106781186547524401
|
||||
#endif
|
||||
|
||||
enum Tx1D { DCT, ADST, FLIPADST, IDENTITY, WHT };
|
||||
|
||||
static const uint8_t itx_1d_types[N_TX_TYPES_PLUS_LL][2] = {
|
||||
[DCT_DCT] = { DCT, DCT },
|
||||
[ADST_DCT] = { DCT, ADST },
|
||||
[DCT_ADST] = { ADST, DCT },
|
||||
[ADST_ADST] = { ADST, ADST },
|
||||
[FLIPADST_DCT] = { DCT, FLIPADST },
|
||||
[DCT_FLIPADST] = { FLIPADST, DCT },
|
||||
[FLIPADST_FLIPADST] = { FLIPADST, FLIPADST },
|
||||
[ADST_FLIPADST] = { FLIPADST, ADST },
|
||||
[FLIPADST_ADST] = { ADST, FLIPADST },
|
||||
[IDTX] = { IDENTITY, IDENTITY },
|
||||
[V_DCT] = { IDENTITY, DCT },
|
||||
[H_DCT] = { DCT, IDENTITY },
|
||||
[V_ADST] = { IDENTITY, ADST },
|
||||
[H_ADST] = { ADST, IDENTITY },
|
||||
[V_FLIPADST] = { IDENTITY, FLIPADST },
|
||||
[H_FLIPADST] = { FLIPADST, IDENTITY },
|
||||
[WHT_WHT] = { WHT, WHT },
|
||||
};
|
||||
|
||||
static const char *const itx_1d_names[5] = {
|
||||
[DCT] = "dct",
|
||||
[ADST] = "adst",
|
||||
[FLIPADST] = "flipadst",
|
||||
[IDENTITY] = "identity",
|
||||
[WHT] = "wht"
|
||||
};
|
||||
|
||||
static const double scaling_factors[9] = {
|
||||
4.0000, /* 4x4 */
|
||||
4.0000 * M_SQRT1_2, /* 4x8 8x4 */
|
||||
2.0000, /* 4x16 8x8 16x4 */
|
||||
2.0000 * M_SQRT1_2, /* 8x16 16x8 */
|
||||
1.0000, /* 8x32 16x16 32x8 */
|
||||
0.5000 * M_SQRT1_2, /* 16x32 32x16 */
|
||||
0.2500, /* 16x64 32x32 64x16 */
|
||||
0.1250 * M_SQRT1_2, /* 32x64 64x32 */
|
||||
0.0625, /* 64x64 */
|
||||
};
|
||||
|
||||
/* FIXME: Ensure that those forward transforms are similar to the real AV1
|
||||
* transforms. The FLIPADST currently uses the ADST forward transform for
|
||||
* example which is obviously "incorrect", but we're just using it for now
|
||||
* since it does produce coefficients in the correct range at least. */
|
||||
|
||||
/* DCT-II */
|
||||
static void fdct_1d(double *const out, const double *const in, const int sz) {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
out[i] = 0.0;
|
||||
for (int j = 0; j < sz; j++)
|
||||
out[i] += in[j] * cos(M_PI * (2 * j + 1) * i / (sz * 2.0));
|
||||
}
|
||||
out[0] *= M_SQRT1_2;
|
||||
}
|
||||
|
||||
/* See "Towards jointly optimal spatial prediction and adaptive transform in
|
||||
* video/image coding", by J. Han, A. Saxena, and K. Rose
|
||||
* IEEE Proc. ICASSP, pp. 726-729, Mar. 2010.
|
||||
* and "A Butterfly Structured Design of The Hybrid Transform Coding Scheme",
|
||||
* by Jingning Han, Yaowu Xu, and Debargha Mukherjee
|
||||
* http://research.google.com/pubs/archive/41418.pdf
|
||||
*/
|
||||
static void fadst_1d(double *const out, const double *const in, const int sz) {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
out[i] = 0.0;
|
||||
for (int j = 0; j < sz; j++)
|
||||
out[i] += in[j] * sin(M_PI *
|
||||
(sz == 4 ? ( j + 1) * (2 * i + 1) / (8.0 + 1.0) :
|
||||
(2 * j + 1) * (2 * i + 1) / (sz * 4.0)));
|
||||
}
|
||||
}
|
||||
|
||||
static void fwht4_1d(double *const out, const double *const in)
|
||||
{
|
||||
const double t0 = in[0] + in[1];
|
||||
const double t3 = in[3] - in[2];
|
||||
const double t4 = (t0 - t3) * 0.5;
|
||||
const double t1 = t4 - in[1];
|
||||
const double t2 = t4 - in[2];
|
||||
out[0] = t0 - t2;
|
||||
out[1] = t2;
|
||||
out[2] = t3 + t1;
|
||||
out[3] = t1;
|
||||
}
|
||||
|
||||
static int copy_subcoefs(coef *coeff,
|
||||
const enum RectTxfmSize tx, const enum TxfmType txtp,
|
||||
const int sw, const int sh, const int subsh)
|
||||
{
|
||||
/* copy the topleft coefficients such that the return value (being the
|
||||
* coefficient scantable index for the eob token) guarantees that only
|
||||
* the topleft $sub out of $sz (where $sz >= $sub) coefficients in both
|
||||
* dimensions are non-zero. This leads to braching to specific optimized
|
||||
* simd versions (e.g. dc-only) so that we get full asm coverage in this
|
||||
* test */
|
||||
|
||||
const enum TxClass tx_class = dav1d_tx_type_class[txtp];
|
||||
const uint16_t *const scan = dav1d_scans[tx];
|
||||
const int sub_high = subsh > 0 ? subsh * 8 - 1 : 0;
|
||||
const int sub_low = subsh > 1 ? sub_high - 8 : 0;
|
||||
int n, eob;
|
||||
|
||||
for (n = 0, eob = 0; n < sw * sh; n++) {
|
||||
int rc, rcx, rcy;
|
||||
if (tx_class == TX_CLASS_2D)
|
||||
rc = scan[n], rcx = rc % sh, rcy = rc / sh;
|
||||
else if (tx_class == TX_CLASS_H)
|
||||
rcx = n % sh, rcy = n / sh, rc = n;
|
||||
else /* tx_class == TX_CLASS_V */
|
||||
rcx = n / sw, rcy = n % sw, rc = rcy * sh + rcx;
|
||||
|
||||
/* Pick a random eob within this sub-itx */
|
||||
if (rcx > sub_high || rcy > sub_high) {
|
||||
break; /* upper boundary */
|
||||
} else if (!eob && (rcx > sub_low || rcy > sub_low))
|
||||
eob = n; /* lower boundary */
|
||||
}
|
||||
|
||||
if (eob)
|
||||
eob += rnd() % (n - eob - 1);
|
||||
if (tx_class == TX_CLASS_2D)
|
||||
for (n = eob + 1; n < sw * sh; n++)
|
||||
coeff[scan[n]] = 0;
|
||||
else if (tx_class == TX_CLASS_H)
|
||||
for (n = eob + 1; n < sw * sh; n++)
|
||||
coeff[n] = 0;
|
||||
else /* tx_class == TX_CLASS_V */ {
|
||||
for (int rcx = eob / sw, rcy = eob % sw; rcx < sh; rcx++, rcy = -1)
|
||||
while (++rcy < sw)
|
||||
coeff[rcy * sh + rcx] = 0;
|
||||
n = sw * sh;
|
||||
}
|
||||
for (; n < 32 * 32; n++)
|
||||
coeff[n] = rnd();
|
||||
return eob;
|
||||
}
|
||||
|
||||
static int ftx(coef *const buf, const enum RectTxfmSize tx,
|
||||
const enum TxfmType txtp, const int w, const int h,
|
||||
const int subsh, const int bitdepth_max)
|
||||
{
|
||||
double out[64 * 64], temp[64 * 64];
|
||||
const double scale = scaling_factors[ctz(w * h) - 4];
|
||||
const int sw = imin(w, 32), sh = imin(h, 32);
|
||||
|
||||
for (int i = 0; i < h; i++) {
|
||||
double in[64], temp_out[64];
|
||||
|
||||
for (int i = 0; i < w; i++)
|
||||
in[i] = (rnd() & (2 * bitdepth_max + 1)) - bitdepth_max;
|
||||
|
||||
switch (itx_1d_types[txtp][0]) {
|
||||
case DCT:
|
||||
fdct_1d(temp_out, in, w);
|
||||
break;
|
||||
case ADST:
|
||||
case FLIPADST:
|
||||
fadst_1d(temp_out, in, w);
|
||||
break;
|
||||
case WHT:
|
||||
fwht4_1d(temp_out, in);
|
||||
break;
|
||||
case IDENTITY:
|
||||
memcpy(temp_out, in, w * sizeof(*temp_out));
|
||||
break;
|
||||
}
|
||||
|
||||
for (int j = 0; j < w; j++)
|
||||
temp[j * h + i] = temp_out[j] * scale;
|
||||
}
|
||||
|
||||
for (int i = 0; i < w; i++) {
|
||||
switch (itx_1d_types[txtp][0]) {
|
||||
case DCT:
|
||||
fdct_1d(&out[i * h], &temp[i * h], h);
|
||||
break;
|
||||
case ADST:
|
||||
case FLIPADST:
|
||||
fadst_1d(&out[i * h], &temp[i * h], h);
|
||||
break;
|
||||
case WHT:
|
||||
fwht4_1d(&out[i * h], &temp[i * h]);
|
||||
break;
|
||||
case IDENTITY:
|
||||
memcpy(&out[i * h], &temp[i * h], h * sizeof(*out));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < sh; y++)
|
||||
for (int x = 0; x < sw; x++)
|
||||
buf[y * sw + x] = (coef) (out[y * w + x] + 0.5);
|
||||
|
||||
return copy_subcoefs(buf, tx, txtp, sw, sh, subsh);
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_itx)(void) {
|
||||
#if BITDEPTH == 16
|
||||
const int bpc_min = 10, bpc_max = 12;
|
||||
#else
|
||||
const int bpc_min = 8, bpc_max = 8;
|
||||
#endif
|
||||
|
||||
ALIGN_STK_64(coef, coeff, 2, [32 * 32]);
|
||||
ALIGN_STK_64(pixel, c_dst, 64 * 64,);
|
||||
ALIGN_STK_64(pixel, a_dst, 64 * 64,);
|
||||
Dav1dInvTxfmDSPContext c = { { { 0 } } }; /* Zero unused function pointer elements. */
|
||||
|
||||
static const uint8_t txfm_size_order[N_RECT_TX_SIZES] = {
|
||||
TX_4X4, RTX_4X8, RTX_4X16,
|
||||
RTX_8X4, TX_8X8, RTX_8X16, RTX_8X32,
|
||||
RTX_16X4, RTX_16X8, TX_16X16, RTX_16X32, RTX_16X64,
|
||||
RTX_32X8, RTX_32X16, TX_32X32, RTX_32X64,
|
||||
RTX_64X16, RTX_64X32, TX_64X64
|
||||
};
|
||||
|
||||
static const uint8_t subsh_iters[5] = { 2, 2, 3, 5, 5 };
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, coef *coeff, int eob
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int i = 0; i < N_RECT_TX_SIZES; i++) {
|
||||
const enum RectTxfmSize tx = txfm_size_order[i];
|
||||
const int w = dav1d_txfm_dimensions[tx].w * 4;
|
||||
const int h = dav1d_txfm_dimensions[tx].h * 4;
|
||||
const int subsh_max = subsh_iters[imax(dav1d_txfm_dimensions[tx].lw,
|
||||
dav1d_txfm_dimensions[tx].lh)];
|
||||
|
||||
for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
|
||||
bitfn(dav1d_itx_dsp_init)(&c, bpc);
|
||||
for (enum TxfmType txtp = 0; txtp < N_TX_TYPES_PLUS_LL; txtp++)
|
||||
for (int subsh = 0; subsh < subsh_max; subsh++)
|
||||
if (check_func(c.itxfm_add[tx][txtp],
|
||||
"inv_txfm_add_%dx%d_%s_%s_%d_%dbpc",
|
||||
w, h, itx_1d_names[itx_1d_types[txtp][0]],
|
||||
itx_1d_names[itx_1d_types[txtp][1]], subsh,
|
||||
bpc))
|
||||
{
|
||||
const int bitdepth_max = (1 << bpc) - 1;
|
||||
const int eob = ftx(coeff[0], tx, txtp, w, h, subsh, bitdepth_max);
|
||||
memcpy(coeff[1], coeff[0], sizeof(*coeff));
|
||||
|
||||
for (int j = 0; j < w * h; j++)
|
||||
c_dst[j] = a_dst[j] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, w * sizeof(*c_dst), coeff[0], eob
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, w * sizeof(*c_dst), coeff[1], eob
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
checkasm_check_pixel(c_dst, w * sizeof(*c_dst),
|
||||
a_dst, w * sizeof(*a_dst),
|
||||
w, h, "dst");
|
||||
if (memcmp(coeff[0], coeff[1], sizeof(*coeff)))
|
||||
fail();
|
||||
|
||||
bench_new(a_dst, w * sizeof(*c_dst), coeff[0], eob
|
||||
HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("add_%dx%d", w, h);
|
||||
}
|
||||
}
|
203
third_party/dav1d/tests/checkasm/loopfilter.c
vendored
203
third_party/dav1d/tests/checkasm/loopfilter.c
vendored
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/levels.h"
|
||||
#include "src/loopfilter.h"
|
||||
|
||||
static void init_lpf_border(pixel *const dst, const ptrdiff_t stride,
|
||||
int E, int I, const int bitdepth_max)
|
||||
{
|
||||
const int bitdepth_min_8 = bitdepth_from_max(bitdepth_max) - 8;
|
||||
const int F = 1 << bitdepth_min_8;
|
||||
E <<= bitdepth_min_8;
|
||||
I <<= bitdepth_min_8;
|
||||
|
||||
const int filter_type = rnd() % 4;
|
||||
const int edge_diff = rnd() % ((E + 2) * 4) - 2 * (E + 2);
|
||||
switch (filter_type) {
|
||||
case 0: // random, unfiltered
|
||||
for (int i = -8; i < 8; i++)
|
||||
dst[i * stride] = rnd() & bitdepth_max;
|
||||
break;
|
||||
case 1: // long flat
|
||||
dst[-8 * stride] = rnd() & bitdepth_max;
|
||||
dst[+7 * stride] = rnd() & bitdepth_max;
|
||||
dst[+0 * stride] = rnd() & bitdepth_max;
|
||||
dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
|
||||
for (int i = 1; i < 7; i++) {
|
||||
dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
|
||||
rnd() % (2 * (F + 1)) - (F + 1));
|
||||
dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
|
||||
rnd() % (2 * (F + 1)) - (F + 1));
|
||||
}
|
||||
break;
|
||||
case 2: // short flat
|
||||
for (int i = 4; i < 8; i++) {
|
||||
dst[-(1 + i) * stride] = rnd() & bitdepth_max;
|
||||
dst[+(0 + i) * stride] = rnd() & bitdepth_max;
|
||||
}
|
||||
dst[+0 * stride] = rnd() & bitdepth_max;
|
||||
dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
dst[-(1 + i) * stride] = iclip_pixel(dst[-1 * stride] +
|
||||
rnd() % (2 * (F + 1)) - (F + 1));
|
||||
dst[+(0 + i) * stride] = iclip_pixel(dst[+0 * stride] +
|
||||
rnd() % (2 * (F + 1)) - (F + 1));
|
||||
}
|
||||
break;
|
||||
case 3: // normal or hev
|
||||
for (int i = 4; i < 8; i++) {
|
||||
dst[-(1 + i) * stride] = rnd() & bitdepth_max;
|
||||
dst[+(0 + i) * stride] = rnd() & bitdepth_max;
|
||||
}
|
||||
dst[+0 * stride] = rnd() & bitdepth_max;
|
||||
dst[-1 * stride] = iclip_pixel(dst[+0 * stride] + edge_diff);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
dst[-(1 + i) * stride] = iclip_pixel(dst[-(0 + i) * stride] +
|
||||
rnd() % (2 * (I + 1)) - (I + 1));
|
||||
dst[+(0 + i) * stride] = iclip_pixel(dst[+(i - 1) * stride] +
|
||||
rnd() % (2 * (I + 1)) - (I + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_lpf_sb(loopfilter_sb_fn fn, const char *const name,
|
||||
const int n_blks, const int lf_idx,
|
||||
const int is_chroma, const int dir)
|
||||
{
|
||||
ALIGN_STK_64(pixel, c_dst_mem, 128 * 16,);
|
||||
ALIGN_STK_64(pixel, a_dst_mem, 128 * 16,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const uint32_t *mask,
|
||||
const uint8_t (*l)[4], ptrdiff_t b4_stride,
|
||||
const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX);
|
||||
|
||||
pixel *a_dst, *c_dst;
|
||||
ptrdiff_t stride, b4_stride;
|
||||
int w, h;
|
||||
if (dir) {
|
||||
a_dst = a_dst_mem + 128 * 8;
|
||||
c_dst = c_dst_mem + 128 * 8;
|
||||
w = 128;
|
||||
h = 16;
|
||||
b4_stride = 32;
|
||||
} else {
|
||||
a_dst = a_dst_mem + 8;
|
||||
c_dst = c_dst_mem + 8;
|
||||
w = 16;
|
||||
h = 128;
|
||||
b4_stride = 2;
|
||||
}
|
||||
stride = w * sizeof(pixel);
|
||||
|
||||
Av1FilterLUT lut;
|
||||
const int sharp = rnd() & 7;
|
||||
for (int level = 0; level < 64; level++) {
|
||||
int limit = level;
|
||||
|
||||
if (sharp > 0) {
|
||||
limit >>= (sharp + 3) >> 2;
|
||||
limit = imin(limit, 9 - sharp);
|
||||
}
|
||||
limit = imax(limit, 1);
|
||||
|
||||
lut.i[level] = limit;
|
||||
lut.e[level] = 2 * (level + 2) + limit;
|
||||
}
|
||||
lut.sharp[0] = (sharp + 3) >> 2;
|
||||
lut.sharp[1] = sharp ? 9 - sharp : 0xff;
|
||||
|
||||
const int n_strengths = is_chroma ? 2 : 3;
|
||||
for (int i = 0; i < n_strengths; i++) {
|
||||
if (check_func(fn, "%s_w%d_%dbpc", name,
|
||||
is_chroma ? 4 + 2 * i : 4 << i, BITDEPTH))
|
||||
{
|
||||
uint32_t vmask[4] = { 0 };
|
||||
uint8_t l[32 * 2][4];
|
||||
|
||||
for (int j = 0; j < n_blks; j++) {
|
||||
const int idx = rnd() % (i + 2);
|
||||
if (idx) vmask[idx - 1] |= 1U << j;
|
||||
if (dir) {
|
||||
l[j][lf_idx] = rnd() & 63;
|
||||
l[j + 32][lf_idx] = rnd() & 63;
|
||||
} else {
|
||||
l[j * 2][lf_idx] = rnd() & 63;
|
||||
l[j * 2 + 1][lf_idx] = rnd() & 63;
|
||||
}
|
||||
}
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4 * n_blks; i++) {
|
||||
const int x = i >> 2;
|
||||
int L;
|
||||
if (dir) {
|
||||
L = l[32 + x][lf_idx] ? l[32 + x][lf_idx] : l[x][lf_idx];
|
||||
} else {
|
||||
L = l[2 * x + 1][lf_idx] ? l[2 * x + 1][lf_idx] : l[2 * x][lf_idx];
|
||||
}
|
||||
init_lpf_border(c_dst + i * (dir ? 1 : 16), dir ? 128 : 1,
|
||||
lut.e[L], lut.i[L], bitdepth_max);
|
||||
}
|
||||
memcpy(a_dst_mem, c_dst_mem, 128 * sizeof(pixel) * 16);
|
||||
|
||||
call_ref(c_dst, stride,
|
||||
vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
|
||||
&lut, n_blks HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, stride,
|
||||
vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
|
||||
&lut, n_blks HIGHBD_TAIL_SUFFIX);
|
||||
|
||||
checkasm_check_pixel(c_dst_mem, stride, a_dst_mem, stride,
|
||||
w, h, "dst");
|
||||
bench_new(a_dst, stride,
|
||||
vmask, (const uint8_t(*)[4]) &l[dir ? 32 : 1][lf_idx], b4_stride,
|
||||
&lut, n_blks HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report(name);
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_loopfilter)(void) {
|
||||
Dav1dLoopFilterDSPContext c;
|
||||
|
||||
bitfn(dav1d_loop_filter_dsp_init)(&c);
|
||||
|
||||
check_lpf_sb(c.loop_filter_sb[0][0], "lpf_h_sb_y", 32, 0, 0, 0);
|
||||
check_lpf_sb(c.loop_filter_sb[0][1], "lpf_v_sb_y", 32, 1, 0, 1);
|
||||
check_lpf_sb(c.loop_filter_sb[1][0], "lpf_h_sb_uv", 16, 2, 1, 0);
|
||||
check_lpf_sb(c.loop_filter_sb[1][1], "lpf_v_sb_uv", 16, 2, 1, 1);
|
||||
}
|
202
third_party/dav1d/tests/checkasm/looprestoration.c
vendored
202
third_party/dav1d/tests/checkasm/looprestoration.c
vendored
@ -1,202 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/levels.h"
|
||||
#include "src/looprestoration.h"
|
||||
#include "src/tables.h"
|
||||
|
||||
static int to_binary(int x) { /* 0-15 -> 0000-1111 */
|
||||
return (x & 1) + 5 * (x & 2) + 25 * (x & 4) + 125 * (x & 8);
|
||||
}
|
||||
|
||||
static void init_tmp(pixel *buf, const ptrdiff_t stride,
|
||||
const int w, const int h, const int bitdepth_max)
|
||||
{
|
||||
const int noise_mask = bitdepth_max >> 4;
|
||||
const int x_off = rnd() & 7, y_off = rnd() & 7;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
buf[x] = (((x + x_off) ^ (y + y_off)) & 8 ? bitdepth_max : 0) ^
|
||||
(rnd() & noise_mask);
|
||||
}
|
||||
buf += PXSTRIDE(stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_wiener(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
|
||||
ALIGN_STK_64(pixel, c_src, 448 * 64,), *const c_dst = c_src + 32;
|
||||
ALIGN_STK_64(pixel, a_src, 448 * 64,), *const a_dst = a_src + 32;
|
||||
ALIGN_STK_64(pixel, edge_buf, 448 * 8,), *const h_edge = edge_buf + 32;
|
||||
pixel left[64][4];
|
||||
LooprestorationParams params;
|
||||
int16_t (*const filter)[8] = params.filter;
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride,
|
||||
const pixel (*const left)[4],
|
||||
const pixel *lpf, ptrdiff_t lpf_stride,
|
||||
int w, int h, const LooprestorationParams *params,
|
||||
enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int t = 0; t < 2; t++) {
|
||||
if (check_func(c->wiener[t], "wiener_%dtap_%dbpc", t ? 5 : 7, bpc)) {
|
||||
filter[0][0] = filter[0][6] = t ? 0 : (rnd() & 15) - 5;
|
||||
filter[0][1] = filter[0][5] = (rnd() & 31) - 23;
|
||||
filter[0][2] = filter[0][4] = (rnd() & 63) - 17;
|
||||
filter[0][3] = -(filter[0][0] + filter[0][1] + filter[0][2]) * 2;
|
||||
#if BITDEPTH != 8
|
||||
filter[0][3] += 128;
|
||||
#endif
|
||||
|
||||
filter[1][0] = filter[1][6] = t ? 0 : (rnd() & 15) - 5;
|
||||
filter[1][1] = filter[1][5] = (rnd() & 31) - 23;
|
||||
filter[1][2] = filter[1][4] = (rnd() & 63) - 17;
|
||||
filter[1][3] = 128 - (filter[1][0] + filter[1][1] + filter[1][2]) * 2;
|
||||
|
||||
const int base_w = 1 + (rnd() % 384);
|
||||
const int base_h = 1 + (rnd() & 63);
|
||||
const int bitdepth_max = (1 << bpc) - 1;
|
||||
|
||||
init_tmp(c_src, 448 * sizeof(pixel), 448, 64, bitdepth_max);
|
||||
init_tmp(edge_buf, 448 * sizeof(pixel), 448, 8, bitdepth_max);
|
||||
init_tmp((pixel *) left, 4 * sizeof(pixel), 4, 64, bitdepth_max);
|
||||
|
||||
for (enum LrEdgeFlags edges = 0; edges <= 0xf; edges++) {
|
||||
const int w = edges & LR_HAVE_RIGHT ? 256 : base_w;
|
||||
const int h = edges & LR_HAVE_BOTTOM ? 64 : base_h;
|
||||
|
||||
memcpy(a_src, c_src, 448 * 64 * sizeof(pixel));
|
||||
|
||||
call_ref(c_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
|
||||
if (checkasm_check_pixel(c_dst, 448 * sizeof(pixel),
|
||||
a_dst, 448 * sizeof(pixel),
|
||||
w, h, "dst"))
|
||||
{
|
||||
fprintf(stderr, "size = %dx%d, edges = %04d\n",
|
||||
w, h, to_binary(edges));
|
||||
break;
|
||||
}
|
||||
}
|
||||
bench_new(a_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
256, 64, ¶ms, 0xf HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_sgr(Dav1dLoopRestorationDSPContext *const c, const int bpc) {
|
||||
ALIGN_STK_64(pixel, c_src, 448 * 64,), *const c_dst = c_src + 32;
|
||||
ALIGN_STK_64(pixel, a_src, 448 * 64,), *const a_dst = a_src + 32;
|
||||
ALIGN_STK_64(pixel, edge_buf, 448 * 8,), *const h_edge = edge_buf + 32;
|
||||
pixel left[64][4];
|
||||
LooprestorationParams params;
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride,
|
||||
const pixel (*const left)[4],
|
||||
const pixel *lpf, ptrdiff_t lpf_stride,
|
||||
int w, int h, const LooprestorationParams *params,
|
||||
enum LrEdgeFlags edges HIGHBD_DECL_SUFFIX);
|
||||
|
||||
static const struct { char name[4]; uint8_t idx; } sgr_data[3] = {
|
||||
{ "5x5", 14 },
|
||||
{ "3x3", 10 },
|
||||
{ "mix", 0 },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (check_func(c->sgr[i], "sgr_%s_%dbpc", sgr_data[i].name, bpc)) {
|
||||
const uint16_t *const sgr_params = dav1d_sgr_params[sgr_data[i].idx];
|
||||
params.sgr.s0 = sgr_params[0];
|
||||
params.sgr.s1 = sgr_params[1];
|
||||
params.sgr.w0 = sgr_params[0] ? (rnd() & 127) - 96 : 0;
|
||||
params.sgr.w1 = (sgr_params[1] ? 160 - (rnd() & 127) : 33) - params.sgr.w0;
|
||||
|
||||
const int base_w = 1 + (rnd() % 384);
|
||||
const int base_h = 1 + (rnd() & 63);
|
||||
const int bitdepth_max = (1 << bpc) - 1;
|
||||
|
||||
init_tmp(c_src, 448 * sizeof(pixel), 448, 64, bitdepth_max);
|
||||
init_tmp(edge_buf, 448 * sizeof(pixel), 448, 8, bitdepth_max);
|
||||
init_tmp((pixel *) left, 4 * sizeof(pixel), 4, 64, bitdepth_max);
|
||||
|
||||
for (enum LrEdgeFlags edges = 0; edges <= 0xf; edges++) {
|
||||
const int w = edges & LR_HAVE_RIGHT ? 256 : base_w;
|
||||
const int h = edges & LR_HAVE_BOTTOM ? 64 : base_h;
|
||||
|
||||
memcpy(a_src, c_src, 448 * 64 * sizeof(pixel));
|
||||
|
||||
call_ref(c_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
w, h, ¶ms, edges HIGHBD_TAIL_SUFFIX);
|
||||
if (checkasm_check_pixel(c_dst, 448 * sizeof(pixel),
|
||||
a_dst, 448 * sizeof(pixel),
|
||||
w, h, "dst"))
|
||||
{
|
||||
fprintf(stderr, "size = %dx%d, edges = %04d\n",
|
||||
w, h, to_binary(edges));
|
||||
break;
|
||||
}
|
||||
}
|
||||
bench_new(a_dst, 448 * sizeof(pixel), left,
|
||||
h_edge, 448 * sizeof(pixel),
|
||||
256, 64, ¶ms, 0xf HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_looprestoration)(void) {
|
||||
#if BITDEPTH == 16
|
||||
const int bpc_min = 10, bpc_max = 12;
|
||||
#else
|
||||
const int bpc_min = 8, bpc_max = 8;
|
||||
#endif
|
||||
for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
|
||||
Dav1dLoopRestorationDSPContext c;
|
||||
bitfn(dav1d_loop_restoration_dsp_init)(&c, bpc);
|
||||
check_wiener(&c, bpc);
|
||||
}
|
||||
report("wiener");
|
||||
for (int bpc = bpc_min; bpc <= bpc_max; bpc += 2) {
|
||||
Dav1dLoopRestorationDSPContext c;
|
||||
bitfn(dav1d_loop_restoration_dsp_init)(&c, bpc);
|
||||
check_sgr(&c, bpc);
|
||||
}
|
||||
report("sgr");
|
||||
}
|
756
third_party/dav1d/tests/checkasm/mc.c
vendored
756
third_party/dav1d/tests/checkasm/mc.c
vendored
@ -1,756 +0,0 @@
|
||||
/*
|
||||
* 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include "src/levels.h"
|
||||
#include "src/mc.h"
|
||||
|
||||
static const char *const filter_names[] = {
|
||||
"8tap_regular", "8tap_regular_smooth", "8tap_regular_sharp",
|
||||
"8tap_sharp_regular", "8tap_sharp_smooth", "8tap_sharp",
|
||||
"8tap_smooth_regular", "8tap_smooth", "8tap_smooth_sharp",
|
||||
"bilinear"
|
||||
};
|
||||
|
||||
static const char *const mxy_names[] = { "0", "h", "v", "hv" };
|
||||
static const char *const scaled_paths[] = { "", "_dy1", "_dy2" };
|
||||
|
||||
static int mc_h_next(const int h) {
|
||||
switch (h) {
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
return (h * 3) >> 1;
|
||||
case 6:
|
||||
case 12:
|
||||
case 24:
|
||||
return (h & (h - 1)) * 2;
|
||||
default:
|
||||
return h * 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_mc(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 135 * 135,);
|
||||
ALIGN_STK_64(pixel, c_dst, 128 * 128,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
const pixel *src = src_buf + 135 * 3 + 3;
|
||||
const ptrdiff_t src_stride = 135 * sizeof(pixel);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
|
||||
ptrdiff_t src_stride, int w, int h, int mx, int my
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int filter = 0; filter < N_2D_FILTERS; filter++)
|
||||
for (int w = 2; w <= 128; w <<= 1) {
|
||||
const ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int mxy = 0; mxy < 4; mxy++)
|
||||
if (check_func(c->mc[filter], "mc_%s_w%d_%s_%dbpc",
|
||||
filter_names[filter], w, mxy_names[mxy], BITDEPTH))
|
||||
{
|
||||
const int h_min = w <= 32 ? 2 : w / 4;
|
||||
const int h_max = imax(imin(w * 4, 128), 32);
|
||||
for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
|
||||
const int mx = (mxy & 1) ? rnd() % 15 + 1 : 0;
|
||||
const int my = (mxy & 2) ? rnd() % 15 + 1 : 0;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 135 * 135; i++)
|
||||
src_buf[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride,
|
||||
a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
if (filter == FILTER_2D_8TAP_REGULAR ||
|
||||
filter == FILTER_2D_BILINEAR)
|
||||
{
|
||||
bench_new(a_dst, dst_stride, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
report("mc");
|
||||
}
|
||||
|
||||
/* Generate worst case input in the topleft corner, randomize the rest */
|
||||
static void generate_mct_input(pixel *const buf, const int bitdepth_max) {
|
||||
static const int8_t pattern[8] = { -1, 0, -1, 0, 0, -1, 0, -1 };
|
||||
const int sign = -(rnd() & 1);
|
||||
|
||||
for (int y = 0; y < 135; y++)
|
||||
for (int x = 0; x < 135; x++)
|
||||
buf[135*y+x] = ((x | y) < 8 ? (pattern[x] ^ pattern[y] ^ sign)
|
||||
: rnd()) & bitdepth_max;
|
||||
}
|
||||
|
||||
static void check_mct(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 135 * 135,);
|
||||
ALIGN_STK_64(int16_t, c_tmp, 128 * 128,);
|
||||
ALIGN_STK_64(int16_t, a_tmp, 128 * 128,);
|
||||
const pixel *src = src_buf + 135 * 3 + 3;
|
||||
const ptrdiff_t src_stride = 135 * sizeof(pixel);
|
||||
|
||||
declare_func(void, int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
|
||||
int w, int h, int mx, int my HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int filter = 0; filter < N_2D_FILTERS; filter++)
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
for (int mxy = 0; mxy < 4; mxy++)
|
||||
if (check_func(c->mct[filter], "mct_%s_w%d_%s_%dbpc",
|
||||
filter_names[filter], w, mxy_names[mxy], BITDEPTH))
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
|
||||
{
|
||||
const int mx = (mxy & 1) ? rnd() % 15 + 1 : 0;
|
||||
const int my = (mxy & 2) ? rnd() % 15 + 1 : 0;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
generate_mct_input(src_buf, bitdepth_max);
|
||||
|
||||
call_ref(c_tmp, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_tmp, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check(int16_t, c_tmp, w * sizeof(*c_tmp),
|
||||
a_tmp, w * sizeof(*a_tmp),
|
||||
w, h, "tmp");
|
||||
|
||||
if (filter == FILTER_2D_8TAP_REGULAR ||
|
||||
filter == FILTER_2D_BILINEAR)
|
||||
{
|
||||
bench_new(a_tmp, src, src_stride, w, h,
|
||||
mx, my HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("mct");
|
||||
}
|
||||
|
||||
static void check_mc_scaled(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 263 * 263,);
|
||||
ALIGN_STK_64(pixel, c_dst, 128 * 128,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
const pixel *src = src_buf + 263 * 3 + 3;
|
||||
const ptrdiff_t src_stride = 263 * sizeof(pixel);
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
|
||||
ptrdiff_t src_stride, int w, int h,
|
||||
int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int filter = 0; filter < N_2D_FILTERS; filter++)
|
||||
for (int w = 2; w <= 128; w <<= 1) {
|
||||
const ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
if (check_func(c->mc_scaled[filter], "mc_scaled_%s_w%d%s_%dbpc",
|
||||
filter_names[filter], w, scaled_paths[p], BITDEPTH))
|
||||
{
|
||||
const int h_min = w <= 32 ? 2 : w / 4;
|
||||
const int h_max = imax(imin(w * 4, 128), 32);
|
||||
for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
|
||||
const int mx = rnd() % 1024;
|
||||
const int my = rnd() % 1024;
|
||||
const int dx = rnd() % 2048 + 1;
|
||||
const int dy = !p
|
||||
? rnd() % 2048 + 1
|
||||
: p << 10; // ystep=1.0 and ystep=2.0 paths
|
||||
|
||||
for (int k = 0; k < 263 * 263; k++)
|
||||
src_buf[k] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride,
|
||||
a_dst, dst_stride, w, h, "dst");
|
||||
|
||||
if (filter == FILTER_2D_8TAP_REGULAR ||
|
||||
filter == FILTER_2D_BILINEAR)
|
||||
bench_new(a_dst, dst_stride, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
report("mc_scaled");
|
||||
}
|
||||
|
||||
static void check_mct_scaled(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 263 * 263,);
|
||||
ALIGN_STK_64(int16_t, c_tmp, 128 * 128,);
|
||||
ALIGN_STK_64(int16_t, a_tmp, 128 * 128,);
|
||||
const pixel *src = src_buf + 263 * 3 + 3;
|
||||
const ptrdiff_t src_stride = 263 * sizeof(pixel);
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
declare_func(void, int16_t *tmp, const pixel *src, ptrdiff_t src_stride,
|
||||
int w, int h, int mx, int my, int dx, int dy HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int filter = 0; filter < N_2D_FILTERS; filter++)
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
for (int p = 0; p < 3; ++p) {
|
||||
if (check_func(c->mct_scaled[filter], "mct_scaled_%s_w%d%s_%dbpc",
|
||||
filter_names[filter], w, scaled_paths[p], BITDEPTH))
|
||||
{
|
||||
const int h_min = imax(w / 4, 4);
|
||||
const int h_max = imin(w * 4, 128);
|
||||
for (int h = h_min; h <= h_max; h = mc_h_next(h)) {
|
||||
const int mx = rnd() % 1024;
|
||||
const int my = rnd() % 1024;
|
||||
const int dx = rnd() % 2048 + 1;
|
||||
const int dy = !p
|
||||
? rnd() % 2048 + 1
|
||||
: p << 10; // ystep=1.0 and ystep=2.0 paths
|
||||
|
||||
for (int k = 0; k < 263 * 263; k++)
|
||||
src_buf[k] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_tmp, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_tmp, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check(int16_t, c_tmp, w * sizeof(*c_tmp),
|
||||
a_tmp, w * sizeof(*a_tmp),
|
||||
w, h, "tmp");
|
||||
|
||||
if (filter == FILTER_2D_8TAP_REGULAR ||
|
||||
filter == FILTER_2D_BILINEAR)
|
||||
bench_new(a_tmp, src, src_stride,
|
||||
w, h, mx, my, dx, dy HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
report("mct_scaled");
|
||||
}
|
||||
|
||||
static void init_tmp(Dav1dMCDSPContext *const c, pixel *const buf,
|
||||
int16_t (*const tmp)[128 * 128], const int bitdepth_max)
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
generate_mct_input(buf, bitdepth_max);
|
||||
c->mct[FILTER_2D_8TAP_SHARP](tmp[i], buf + 135 * 3 + 3,
|
||||
135 * sizeof(pixel), 128, 128,
|
||||
8, 8 HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_avg(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
|
||||
ALIGN_STK_64(pixel, c_dst, 135 * 135,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
|
||||
const int16_t *tmp2, int w, int h HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
if (check_func(c->avg, "avg_w%d_%dbpc", w, BITDEPTH)) {
|
||||
ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
|
||||
{
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
init_tmp(c, c_dst, tmp, bitdepth_max);
|
||||
call_ref(c_dst, dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp[0], tmp[1], w, h HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("avg");
|
||||
}
|
||||
|
||||
static void check_w_avg(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
|
||||
ALIGN_STK_64(pixel, c_dst, 135 * 135,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
|
||||
const int16_t *tmp2, int w, int h, int weight HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
if (check_func(c->w_avg, "w_avg_w%d_%dbpc", w, BITDEPTH)) {
|
||||
ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
|
||||
{
|
||||
int weight = rnd() % 15 + 1;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
init_tmp(c, c_dst, tmp, bitdepth_max);
|
||||
|
||||
call_ref(c_dst, dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp[0], tmp[1], w, h, weight HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("w_avg");
|
||||
}
|
||||
|
||||
static void check_mask(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
|
||||
ALIGN_STK_64(pixel, c_dst, 135 * 135,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
ALIGN_STK_64(uint8_t, mask, 128 * 128,);
|
||||
|
||||
for (int i = 0; i < 128 * 128; i++)
|
||||
mask[i] = rnd() % 65;
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
|
||||
const int16_t *tmp2, int w, int h, const uint8_t *mask
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
if (check_func(c->mask, "mask_w%d_%dbpc", w, BITDEPTH)) {
|
||||
ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
|
||||
{
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
init_tmp(c, c_dst, tmp, bitdepth_max);
|
||||
call_ref(c_dst, dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp[0], tmp[1], w, h, mask HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("mask");
|
||||
}
|
||||
|
||||
static void check_w_mask(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(int16_t, tmp, 2, [128 * 128]);
|
||||
ALIGN_STK_64(pixel, c_dst, 135 * 135,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 128,);
|
||||
ALIGN_STK_64(uint8_t, c_mask, 128 * 128,);
|
||||
ALIGN_STK_64(uint8_t, a_mask, 128 * 128,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const int16_t *tmp1,
|
||||
const int16_t *tmp2, int w, int h, uint8_t *mask, int sign
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
static const uint16_t ss[] = { 444, 422, 420 };
|
||||
static const uint8_t ss_hor[] = { 0, 1, 1 };
|
||||
static const uint8_t ss_ver[] = { 0, 0, 1 };
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
if (check_func(c->w_mask[i], "w_mask_%d_w%d_%dbpc", ss[i], w,
|
||||
BITDEPTH))
|
||||
{
|
||||
ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1)
|
||||
{
|
||||
int sign = rnd() & 1;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
init_tmp(c, c_dst, tmp, bitdepth_max);
|
||||
|
||||
call_ref(c_dst, dst_stride, tmp[0], tmp[1], w, h,
|
||||
c_mask, sign HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, tmp[0], tmp[1], w, h,
|
||||
a_mask, sign HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride,
|
||||
a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
checkasm_check(uint8_t, c_mask, w >> ss_hor[i],
|
||||
a_mask, w >> ss_hor[i],
|
||||
w >> ss_hor[i], h >> ss_ver[i],
|
||||
"mask");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp[0], tmp[1], w, h,
|
||||
a_mask, sign HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
}
|
||||
report("w_mask");
|
||||
}
|
||||
|
||||
static void check_blend(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, tmp, 32 * 32,);
|
||||
ALIGN_STK_64(pixel, c_dst, 32 * 32,);
|
||||
ALIGN_STK_64(pixel, a_dst, 32 * 32,);
|
||||
ALIGN_STK_64(uint8_t, mask, 32 * 32,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
|
||||
int w, int h, const uint8_t *mask);
|
||||
|
||||
for (int w = 4; w <= 32; w <<= 1) {
|
||||
const ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
if (check_func(c->blend, "blend_w%d_%dbpc", w, BITDEPTH))
|
||||
for (int h = imax(w / 2, 4); h <= imin(w * 2, 32); h <<= 1) {
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
for (int i = 0; i < 32 * 32; i++) {
|
||||
tmp[i] = rnd() & bitdepth_max;
|
||||
mask[i] = rnd() % 65;
|
||||
}
|
||||
for (int i = 0; i < w * h; i++)
|
||||
c_dst[i] = a_dst[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, tmp, w, h, mask);
|
||||
call_new(a_dst, dst_stride, tmp, w, h, mask);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp, w, h, mask);
|
||||
}
|
||||
}
|
||||
report("blend");
|
||||
}
|
||||
|
||||
static void check_blend_v(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, tmp, 32 * 128,);
|
||||
ALIGN_STK_64(pixel, c_dst, 32 * 128,);
|
||||
ALIGN_STK_64(pixel, a_dst, 32 * 128,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
|
||||
int w, int h);
|
||||
|
||||
for (int w = 2; w <= 32; w <<= 1) {
|
||||
const ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
if (check_func(c->blend_v, "blend_v_w%d_%dbpc", w, BITDEPTH))
|
||||
for (int h = 2; h <= (w == 2 ? 64 : 128); h <<= 1) {
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < w * h; i++)
|
||||
c_dst[i] = a_dst[i] = rnd() & bitdepth_max;
|
||||
for (int i = 0; i < 32 * 128; i++)
|
||||
tmp[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, tmp, w, h);
|
||||
call_new(a_dst, dst_stride, tmp, w, h);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp, w, h);
|
||||
}
|
||||
}
|
||||
report("blend_v");
|
||||
}
|
||||
|
||||
static void check_blend_h(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, tmp, 128 * 32,);
|
||||
ALIGN_STK_64(pixel, c_dst, 128 * 32,);
|
||||
ALIGN_STK_64(pixel, a_dst, 128 * 32,);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *tmp,
|
||||
int w, int h);
|
||||
|
||||
for (int w = 2; w <= 128; w <<= 1) {
|
||||
const ptrdiff_t dst_stride = w * sizeof(pixel);
|
||||
if (check_func(c->blend_h, "blend_h_w%d_%dbpc", w, BITDEPTH))
|
||||
for (int h = (w == 128 ? 4 : 2); h <= 32; h <<= 1) {
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
for (int i = 0; i < w * h; i++)
|
||||
c_dst[i] = a_dst[i] = rnd() & bitdepth_max;
|
||||
for (int i = 0; i < 128 * 32; i++)
|
||||
tmp[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, tmp, w, h);
|
||||
call_new(a_dst, dst_stride, tmp, w, h);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
w, h, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, tmp, w, h);
|
||||
}
|
||||
}
|
||||
report("blend_h");
|
||||
}
|
||||
|
||||
static void check_warp8x8(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 15 * 15,);
|
||||
ALIGN_STK_64(pixel, c_dst, 8 * 8,);
|
||||
ALIGN_STK_64(pixel, a_dst, 8 * 8,);
|
||||
int16_t abcd[4];
|
||||
const pixel *src = src_buf + 15 * 3 + 3;
|
||||
const ptrdiff_t dst_stride = 8 * sizeof(pixel);
|
||||
const ptrdiff_t src_stride = 15 * sizeof(pixel);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const pixel *src,
|
||||
ptrdiff_t src_stride, const int16_t *abcd, int mx, int my
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(c->warp8x8, "warp_8x8_%dbpc", BITDEPTH)) {
|
||||
const int mx = (rnd() & 0x1fff) - 0xa00;
|
||||
const int my = (rnd() & 0x1fff) - 0xa00;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
abcd[i] = (rnd() & 0x1fff) - 0xa00;
|
||||
|
||||
for (int i = 0; i < 15 * 15; i++)
|
||||
src_buf[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_dst, dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
8, 8, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
report("warp8x8");
|
||||
}
|
||||
|
||||
static void check_warp8x8t(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, src_buf, 15 * 15,);
|
||||
ALIGN_STK_64(int16_t, c_tmp, 8 * 8,);
|
||||
ALIGN_STK_64(int16_t, a_tmp, 8 * 8,);
|
||||
int16_t abcd[4];
|
||||
const pixel *src = src_buf + 15 * 3 + 3;
|
||||
const ptrdiff_t src_stride = 15 * sizeof(pixel);
|
||||
|
||||
declare_func(void, int16_t *tmp, ptrdiff_t tmp_stride, const pixel *src,
|
||||
ptrdiff_t src_stride, const int16_t *abcd, int mx, int my
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(c->warp8x8t, "warp_8x8t_%dbpc", BITDEPTH)) {
|
||||
const int mx = (rnd() & 0x1fff) - 0xa00;
|
||||
const int my = (rnd() & 0x1fff) - 0xa00;
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
abcd[i] = (rnd() & 0x1fff) - 0xa00;
|
||||
|
||||
for (int i = 0; i < 15 * 15; i++)
|
||||
src_buf[i] = rnd() & bitdepth_max;
|
||||
|
||||
call_ref(c_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check(int16_t, c_tmp, 8 * sizeof(*c_tmp),
|
||||
a_tmp, 8 * sizeof(*a_tmp),
|
||||
8, 8, "tmp");
|
||||
|
||||
bench_new(a_tmp, 8, src, src_stride, abcd, mx, my HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
report("warp8x8t");
|
||||
}
|
||||
|
||||
enum EdgeFlags {
|
||||
HAVE_TOP = 1,
|
||||
HAVE_BOTTOM = 2,
|
||||
HAVE_LEFT = 4,
|
||||
HAVE_RIGHT = 8,
|
||||
};
|
||||
|
||||
static void random_offset_for_edge(int *const x, int *const y,
|
||||
const int bw, const int bh,
|
||||
int *const iw, int *const ih,
|
||||
const enum EdgeFlags edge)
|
||||
{
|
||||
#define set_off(edge1, edge2, pos, dim) \
|
||||
*i##dim = edge & (HAVE_##edge1 | HAVE_##edge2) ? 160 : 1 + (rnd() % (b##dim - 2)); \
|
||||
switch (edge & (HAVE_##edge1 | HAVE_##edge2)) { \
|
||||
case HAVE_##edge1 | HAVE_##edge2: \
|
||||
assert(b##dim <= *i##dim); \
|
||||
*pos = rnd() % (*i##dim - b##dim + 1); \
|
||||
break; \
|
||||
case HAVE_##edge1: \
|
||||
*pos = (*i##dim - b##dim) + 1 + (rnd() % (b##dim - 1)); \
|
||||
break; \
|
||||
case HAVE_##edge2: \
|
||||
*pos = -(1 + (rnd() % (b##dim - 1))); \
|
||||
break; \
|
||||
case 0: \
|
||||
assert(b##dim - 1 > *i##dim); \
|
||||
*pos = -(1 + (rnd() % (b##dim - *i##dim - 1))); \
|
||||
break; \
|
||||
}
|
||||
set_off(LEFT, RIGHT, x, w);
|
||||
set_off(TOP, BOTTOM, y, h);
|
||||
}
|
||||
|
||||
static void check_emuedge(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, c_dst, 135 * 192,);
|
||||
ALIGN_STK_64(pixel, a_dst, 135 * 192,);
|
||||
ALIGN_STK_64(pixel, src, 160 * 160,);
|
||||
|
||||
for (int i = 0; i < 160 * 160; i++)
|
||||
src[i] = rnd() & ((1U << BITDEPTH) - 1);
|
||||
|
||||
declare_func(void, intptr_t bw, intptr_t bh, intptr_t iw, intptr_t ih,
|
||||
intptr_t x, intptr_t y,
|
||||
pixel *dst, ptrdiff_t dst_stride,
|
||||
const pixel *src, ptrdiff_t src_stride);
|
||||
|
||||
int x, y, iw, ih;
|
||||
for (int w = 4; w <= 128; w <<= 1)
|
||||
if (check_func(c->emu_edge, "emu_edge_w%d_%dbpc", w, BITDEPTH)) {
|
||||
for (int h = imax(w / 4, 4); h <= imin(w * 4, 128); h <<= 1) {
|
||||
// we skip 0xf, since it implies that we don't need emu_edge
|
||||
for (enum EdgeFlags edge = 0; edge < 0xf; edge++) {
|
||||
const int bw = w + (rnd() & 7);
|
||||
const int bh = h + (rnd() & 7);
|
||||
random_offset_for_edge(&x, &y, bw, bh, &iw, &ih, edge);
|
||||
call_ref(bw, bh, iw, ih, x, y,
|
||||
c_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
|
||||
call_new(bw, bh, iw, ih, x, y,
|
||||
a_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
|
||||
checkasm_check_pixel(c_dst, 192 * sizeof(pixel),
|
||||
a_dst, 192 * sizeof(pixel),
|
||||
bw, bh, "dst");
|
||||
}
|
||||
}
|
||||
for (enum EdgeFlags edge = 1; edge < 0xf; edge <<= 1) {
|
||||
random_offset_for_edge(&x, &y, w + 7, w + 7, &iw, &ih, edge);
|
||||
bench_new(w + 7, w + 7, iw, ih, x, y,
|
||||
a_dst, 192 * sizeof(pixel), src, 160 * sizeof(pixel));
|
||||
}
|
||||
}
|
||||
report("emu_edge");
|
||||
}
|
||||
|
||||
static int get_upscale_x0(const int in_w, const int out_w, const int step) {
|
||||
const int err = out_w * step - (in_w << 14);
|
||||
const int x0 = (-((out_w - in_w) << 13) + (out_w >> 1)) / out_w + 128 - (err >> 1);
|
||||
return x0 & 0x3fff;
|
||||
}
|
||||
|
||||
static void check_resize(Dav1dMCDSPContext *const c) {
|
||||
ALIGN_STK_64(pixel, c_dst, 1024 * 64,);
|
||||
ALIGN_STK_64(pixel, a_dst, 1024 * 64,);
|
||||
ALIGN_STK_64(pixel, src, 512 * 64,);
|
||||
|
||||
const int height = 64;
|
||||
const int max_src_width = 512;
|
||||
const ptrdiff_t dst_stride = 1024 * sizeof(pixel);
|
||||
const ptrdiff_t src_stride = 512 * sizeof(pixel);
|
||||
|
||||
declare_func(void, pixel *dst, ptrdiff_t dst_stride,
|
||||
const pixel *src, ptrdiff_t src_stride,
|
||||
int dst_w, int src_w, int h, int dx, int mx0
|
||||
HIGHBD_DECL_SUFFIX);
|
||||
|
||||
if (check_func(c->resize, "resize_%dbpc", BITDEPTH)) {
|
||||
#if BITDEPTH == 16
|
||||
const int bitdepth_max = rnd() & 1 ? 0x3ff : 0xfff;
|
||||
#else
|
||||
const int bitdepth_max = 0xff;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < max_src_width * height; i++)
|
||||
src[i] = rnd() & bitdepth_max;
|
||||
|
||||
const int w_den = 9 + (rnd() & 7);
|
||||
const int src_w = 16 + (rnd() % (max_src_width - 16 + 1));
|
||||
const int dst_w = w_den * src_w >> 3;
|
||||
#define scale_fac(ref_sz, this_sz) \
|
||||
((((ref_sz) << 14) + ((this_sz) >> 1)) / (this_sz))
|
||||
const int dx = scale_fac(src_w, dst_w);
|
||||
#undef scale_fac
|
||||
const int mx0 = get_upscale_x0(src_w, dst_w, dx);
|
||||
|
||||
call_ref(c_dst, dst_stride, src, src_stride,
|
||||
dst_w, height, src_w, dx, mx0 HIGHBD_TAIL_SUFFIX);
|
||||
call_new(a_dst, dst_stride, src, src_stride,
|
||||
dst_w, height, src_w, dx, mx0 HIGHBD_TAIL_SUFFIX);
|
||||
checkasm_check_pixel(c_dst, dst_stride, a_dst, dst_stride,
|
||||
dst_w, height, "dst");
|
||||
|
||||
bench_new(a_dst, dst_stride, src, src_stride,
|
||||
512, height, 512 * 8 / w_den, dx, mx0 HIGHBD_TAIL_SUFFIX);
|
||||
}
|
||||
|
||||
report("resize");
|
||||
}
|
||||
|
||||
void bitfn(checkasm_check_mc)(void) {
|
||||
Dav1dMCDSPContext c;
|
||||
bitfn(dav1d_mc_dsp_init)(&c);
|
||||
|
||||
check_mc(&c);
|
||||
check_mct(&c);
|
||||
check_mc_scaled(&c);
|
||||
check_mct_scaled(&c);
|
||||
check_avg(&c);
|
||||
check_w_avg(&c);
|
||||
check_mask(&c);
|
||||
check_w_mask(&c);
|
||||
check_blend(&c);
|
||||
check_blend_v(&c);
|
||||
check_blend_h(&c);
|
||||
check_warp8x8(&c);
|
||||
check_warp8x8t(&c);
|
||||
check_emuedge(&c);
|
||||
check_resize(&c);
|
||||
}
|
291
third_party/dav1d/tests/checkasm/msac.c
vendored
291
third_party/dav1d/tests/checkasm/msac.c
vendored
@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019, VideoLAN and dav1d authors
|
||||
* Copyright © 2019, 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 "tests/checkasm/checkasm.h"
|
||||
|
||||
#include "src/cpu.h"
|
||||
#include "src/msac.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUF_SIZE 8192
|
||||
|
||||
/* The normal code doesn't use function pointers */
|
||||
typedef unsigned (*decode_symbol_adapt_fn)(MsacContext *s, uint16_t *cdf,
|
||||
size_t n_symbols);
|
||||
typedef unsigned (*decode_adapt_fn)(MsacContext *s, uint16_t *cdf);
|
||||
typedef unsigned (*decode_bool_equi_fn)(MsacContext *s);
|
||||
typedef unsigned (*decode_bool_fn)(MsacContext *s, unsigned f);
|
||||
|
||||
typedef struct {
|
||||
decode_symbol_adapt_fn symbol_adapt4;
|
||||
decode_symbol_adapt_fn symbol_adapt8;
|
||||
decode_symbol_adapt_fn symbol_adapt16;
|
||||
decode_adapt_fn bool_adapt;
|
||||
decode_bool_equi_fn bool_equi;
|
||||
decode_bool_fn bool;
|
||||
decode_adapt_fn hi_tok;
|
||||
} MsacDSPContext;
|
||||
|
||||
static void randomize_cdf(uint16_t *const cdf, const int n) {
|
||||
int i;
|
||||
for (i = 15; i > n; i--)
|
||||
cdf[i] = rnd(); // padding
|
||||
cdf[i] = 0; // count
|
||||
do {
|
||||
cdf[i - 1] = cdf[i] + rnd() % (32768 - cdf[i] - i) + 1;
|
||||
} while (--i > 0);
|
||||
}
|
||||
|
||||
/* memcmp() on structs can have weird behavior due to padding etc. */
|
||||
static int msac_cmp(const MsacContext *const a, const MsacContext *const b) {
|
||||
return a->buf_pos != b->buf_pos || a->buf_end != b->buf_end ||
|
||||
a->dif != b->dif || a->rng != b->rng || a->cnt != b->cnt ||
|
||||
a->allow_update_cdf != b->allow_update_cdf;
|
||||
}
|
||||
|
||||
static void msac_dump(unsigned c_res, unsigned a_res,
|
||||
const MsacContext *const a, const MsacContext *const b,
|
||||
const uint16_t *const cdf_a, const uint16_t *const cdf_b,
|
||||
const int num_cdf)
|
||||
{
|
||||
if (c_res != a_res)
|
||||
fprintf(stderr, "c_res %u a_res %u\n", c_res, a_res);
|
||||
if (a->buf_pos != b->buf_pos)
|
||||
fprintf(stderr, "buf_pos %p vs %p\n", a->buf_pos, b->buf_pos);
|
||||
if (a->buf_end != b->buf_end)
|
||||
fprintf(stderr, "buf_end %p vs %p\n", a->buf_end, b->buf_end);
|
||||
if (a->dif != b->dif)
|
||||
fprintf(stderr, "dif %zx vs %zx\n", a->dif, b->dif);
|
||||
if (a->rng != b->rng)
|
||||
fprintf(stderr, "rng %u vs %u\n", a->rng, b->rng);
|
||||
if (a->cnt != b->cnt)
|
||||
fprintf(stderr, "cnt %d vs %d\n", a->cnt, b->cnt);
|
||||
if (a->allow_update_cdf)
|
||||
fprintf(stderr, "allow_update_cdf %d vs %d\n",
|
||||
a->allow_update_cdf, b->allow_update_cdf);
|
||||
if (num_cdf && memcmp(cdf_a, cdf_b, sizeof(*cdf_a) * (num_cdf + 1))) {
|
||||
fprintf(stderr, "cdf:\n");
|
||||
for (int i = 0; i <= num_cdf; i++)
|
||||
fprintf(stderr, " %5u", cdf_a[i]);
|
||||
fprintf(stderr, "\n");
|
||||
for (int i = 0; i <= num_cdf; i++)
|
||||
fprintf(stderr, " %5u", cdf_b[i]);
|
||||
fprintf(stderr, "\n");
|
||||
for (int i = 0; i <= num_cdf; i++)
|
||||
fprintf(stderr, " %c", cdf_a[i] != cdf_b[i] ? 'x' : '.');
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_SYMBOL_ADAPT(n, n_min, n_max) do { \
|
||||
if (check_func(c->symbol_adapt##n, "msac_decode_symbol_adapt%d", n)) { \
|
||||
for (int cdf_update = 0; cdf_update <= 1; cdf_update++) { \
|
||||
for (int ns = n_min; ns <= n_max; ns++) { \
|
||||
dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update); \
|
||||
s_a = s_c; \
|
||||
randomize_cdf(cdf[0], ns); \
|
||||
memcpy(cdf[1], cdf[0], sizeof(*cdf)); \
|
||||
for (int i = 0; i < 64; i++) { \
|
||||
unsigned c_res = call_ref(&s_c, cdf[0], ns); \
|
||||
unsigned a_res = call_new(&s_a, cdf[1], ns); \
|
||||
if (c_res != a_res || msac_cmp(&s_c, &s_a) || \
|
||||
memcmp(cdf[0], cdf[1], sizeof(**cdf) * (ns + 1))) \
|
||||
{ \
|
||||
if (fail()) \
|
||||
msac_dump(c_res, a_res, &s_c, &s_a, \
|
||||
cdf[0], cdf[1], ns); \
|
||||
} \
|
||||
} \
|
||||
if (cdf_update && ns == n - 1) \
|
||||
bench_new(&s_a, cdf[1], ns); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void check_decode_symbol(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
ALIGN_STK_32(uint16_t, cdf, 2, [16]);
|
||||
MsacContext s_c, s_a;
|
||||
|
||||
declare_func(unsigned, MsacContext *s, uint16_t *cdf, size_t n_symbols);
|
||||
CHECK_SYMBOL_ADAPT( 4, 1, 4);
|
||||
CHECK_SYMBOL_ADAPT( 8, 1, 7);
|
||||
CHECK_SYMBOL_ADAPT(16, 3, 15);
|
||||
report("decode_symbol");
|
||||
}
|
||||
|
||||
static void check_decode_bool_adapt(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
MsacContext s_c, s_a;
|
||||
|
||||
declare_func(unsigned, MsacContext *s, uint16_t *cdf);
|
||||
if (check_func(c->bool_adapt, "msac_decode_bool_adapt")) {
|
||||
uint16_t cdf[2][2];
|
||||
for (int cdf_update = 0; cdf_update <= 1; cdf_update++) {
|
||||
dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update);
|
||||
s_a = s_c;
|
||||
cdf[0][0] = cdf[1][0] = rnd() % 32767 + 1;
|
||||
cdf[0][1] = cdf[1][1] = 0;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
unsigned c_res = call_ref(&s_c, cdf[0]);
|
||||
unsigned a_res = call_new(&s_a, cdf[1]);
|
||||
if (c_res != a_res || msac_cmp(&s_c, &s_a) ||
|
||||
memcmp(cdf[0], cdf[1], sizeof(*cdf)))
|
||||
{
|
||||
if (fail())
|
||||
msac_dump(c_res, a_res, &s_c, &s_a, cdf[0], cdf[1], 1);
|
||||
}
|
||||
}
|
||||
if (cdf_update)
|
||||
bench_new(&s_a, cdf[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_decode_bool_equi(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
MsacContext s_c, s_a;
|
||||
|
||||
declare_func(unsigned, MsacContext *s);
|
||||
if (check_func(c->bool_equi, "msac_decode_bool_equi")) {
|
||||
dav1d_msac_init(&s_c, buf, BUF_SIZE, 1);
|
||||
s_a = s_c;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
unsigned c_res = call_ref(&s_c);
|
||||
unsigned a_res = call_new(&s_a);
|
||||
if (c_res != a_res || msac_cmp(&s_c, &s_a)) {
|
||||
if (fail())
|
||||
msac_dump(c_res, a_res, &s_c, &s_a, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
bench_new(&s_a);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_decode_bool(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
MsacContext s_c, s_a;
|
||||
|
||||
declare_func(unsigned, MsacContext *s, unsigned f);
|
||||
if (check_func(c->bool, "msac_decode_bool")) {
|
||||
dav1d_msac_init(&s_c, buf, BUF_SIZE, 1);
|
||||
s_a = s_c;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
const unsigned f = rnd() & 0x7fff;
|
||||
unsigned c_res = call_ref(&s_c, f);
|
||||
unsigned a_res = call_new(&s_a, f);
|
||||
if (c_res != a_res || msac_cmp(&s_c, &s_a)) {
|
||||
if (fail())
|
||||
msac_dump(c_res, a_res, &s_c, &s_a, NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
bench_new(&s_a, 16384);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void check_decode_bool_funcs(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
check_decode_bool_adapt(c, buf);
|
||||
check_decode_bool_equi(c, buf);
|
||||
check_decode_bool(c, buf);
|
||||
report("decode_bool");
|
||||
}
|
||||
|
||||
static void check_decode_hi_tok(MsacDSPContext *const c, uint8_t *const buf) {
|
||||
ALIGN_STK_16(uint16_t, cdf, 2, [16]);
|
||||
MsacContext s_c, s_a;
|
||||
|
||||
declare_func(unsigned, MsacContext *s, uint16_t *cdf);
|
||||
if (check_func(c->hi_tok, "msac_decode_hi_tok")) {
|
||||
for (int cdf_update = 0; cdf_update <= 1; cdf_update++) {
|
||||
dav1d_msac_init(&s_c, buf, BUF_SIZE, !cdf_update);
|
||||
s_a = s_c;
|
||||
randomize_cdf(cdf[0], 3);
|
||||
memcpy(cdf[1], cdf[0], sizeof(*cdf));
|
||||
for (int i = 0; i < 64; i++) {
|
||||
unsigned c_res = call_ref(&s_c, cdf[0]);
|
||||
unsigned a_res = call_new(&s_a, cdf[1]);
|
||||
if (c_res != a_res || msac_cmp(&s_c, &s_a) ||
|
||||
memcmp(cdf[0], cdf[1], sizeof(*cdf)))
|
||||
{
|
||||
if (fail())
|
||||
msac_dump(c_res, a_res, &s_c, &s_a, cdf[0], cdf[1], 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cdf_update)
|
||||
bench_new(&s_a, cdf[1]);
|
||||
}
|
||||
}
|
||||
report("decode_hi_tok");
|
||||
}
|
||||
|
||||
void checkasm_check_msac(void) {
|
||||
MsacDSPContext c;
|
||||
c.symbol_adapt4 = dav1d_msac_decode_symbol_adapt_c;
|
||||
c.symbol_adapt8 = dav1d_msac_decode_symbol_adapt_c;
|
||||
c.symbol_adapt16 = dav1d_msac_decode_symbol_adapt_c;
|
||||
c.bool_adapt = dav1d_msac_decode_bool_adapt_c;
|
||||
c.bool_equi = dav1d_msac_decode_bool_equi_c;
|
||||
c.bool = dav1d_msac_decode_bool_c;
|
||||
c.hi_tok = dav1d_msac_decode_hi_tok_c;
|
||||
|
||||
#if (ARCH_AARCH64 || ARCH_ARM) && HAVE_ASM
|
||||
if (dav1d_get_cpu_flags() & DAV1D_ARM_CPU_FLAG_NEON) {
|
||||
c.symbol_adapt4 = dav1d_msac_decode_symbol_adapt4_neon;
|
||||
c.symbol_adapt8 = dav1d_msac_decode_symbol_adapt8_neon;
|
||||
c.symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_neon;
|
||||
c.bool_adapt = dav1d_msac_decode_bool_adapt_neon;
|
||||
c.bool_equi = dav1d_msac_decode_bool_equi_neon;
|
||||
c.bool = dav1d_msac_decode_bool_neon;
|
||||
c.hi_tok = dav1d_msac_decode_hi_tok_neon;
|
||||
}
|
||||
#elif ARCH_X86 && HAVE_ASM
|
||||
if (dav1d_get_cpu_flags() & DAV1D_X86_CPU_FLAG_SSE2) {
|
||||
c.symbol_adapt4 = dav1d_msac_decode_symbol_adapt4_sse2;
|
||||
c.symbol_adapt8 = dav1d_msac_decode_symbol_adapt8_sse2;
|
||||
c.symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_sse2;
|
||||
c.bool_adapt = dav1d_msac_decode_bool_adapt_sse2;
|
||||
c.bool_equi = dav1d_msac_decode_bool_equi_sse2;
|
||||
c.bool = dav1d_msac_decode_bool_sse2;
|
||||
c.hi_tok = dav1d_msac_decode_hi_tok_sse2;
|
||||
}
|
||||
|
||||
#if ARCH_X86_64
|
||||
if (dav1d_get_cpu_flags() & DAV1D_X86_CPU_FLAG_AVX2) {
|
||||
c.symbol_adapt16 = dav1d_msac_decode_symbol_adapt16_avx2;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uint8_t buf[BUF_SIZE];
|
||||
for (int i = 0; i < BUF_SIZE; i++)
|
||||
buf[i] = rnd();
|
||||
|
||||
check_decode_symbol(&c, buf);
|
||||
check_decode_bool_funcs(&c, buf);
|
||||
check_decode_hi_tok(&c, buf);
|
||||
}
|
287
third_party/dav1d/tests/checkasm/x86/checkasm.asm
vendored
287
third_party/dav1d/tests/checkasm/x86/checkasm.asm
vendored
@ -1,287 +0,0 @@
|
||||
; 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.asm"
|
||||
%undef private_prefix
|
||||
%define private_prefix checkasm
|
||||
%include "ext/x86/x86inc.asm"
|
||||
|
||||
SECTION_RODATA 16
|
||||
|
||||
%if ARCH_X86_64
|
||||
; just random numbers to reduce the chance of incidental match
|
||||
%if WIN64
|
||||
x6: dq 0x1a1b2550a612b48c,0x79445c159ce79064
|
||||
x7: dq 0x2eed899d5a28ddcd,0x86b2536fcd8cf636
|
||||
x8: dq 0xb0856806085e7943,0x3f2bf84fc0fcca4e
|
||||
x9: dq 0xacbd382dcf5b8de2,0xd229e1f5b281303f
|
||||
x10: dq 0x71aeaff20b095fd9,0xab63e2e11fa38ed9
|
||||
x11: dq 0x89b0c0765892729a,0x77d410d5c42c882d
|
||||
x12: dq 0xc45ea11a955d8dd5,0x24b3c1d2a024048b
|
||||
x13: dq 0x2e8ec680de14b47c,0xdd7b8919edd42786
|
||||
x14: dq 0x135ce6888fa02cbf,0x11e53e2b2ac655ef
|
||||
x15: dq 0x011ff554472a7a10,0x6de8f4c914c334d5
|
||||
n7: dq 0x21f86d66c8ca00ce
|
||||
n8: dq 0x75b6ba21077c48ad
|
||||
%endif
|
||||
n9: dq 0xed56bb2dcb3c7736
|
||||
n10: dq 0x8bda43d3fd1a7e06
|
||||
n11: dq 0xb64a9c9e5d318408
|
||||
n12: dq 0xdf9a54b303f1d3a3
|
||||
n13: dq 0x4a75479abd64e097
|
||||
n14: dq 0x249214109d5d1c88
|
||||
%endif
|
||||
|
||||
errmsg_reg: db "failed to preserve register", 0
|
||||
errmsg_stack: db "stack corruption", 0
|
||||
|
||||
SECTION .text
|
||||
|
||||
cextern fail_func
|
||||
|
||||
; max number of args used by any asm function.
|
||||
; (max_args % 4) must equal 3 for stack alignment
|
||||
%define max_args 15
|
||||
|
||||
%if ARCH_X86_64
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; int checkasm_stack_clobber(uint64_t clobber, ...)
|
||||
;-----------------------------------------------------------------------------
|
||||
cglobal stack_clobber, 1, 2
|
||||
; Clobber the stack with junk below the stack pointer
|
||||
%define argsize (max_args+6)*8
|
||||
SUB rsp, argsize
|
||||
mov r1, argsize-8
|
||||
.loop:
|
||||
mov [rsp+r1], r0
|
||||
sub r1, 8
|
||||
jge .loop
|
||||
ADD rsp, argsize
|
||||
RET
|
||||
|
||||
%if WIN64
|
||||
%assign free_regs 7
|
||||
%define stack_param rsp+32 ; shadow space
|
||||
%define num_stack_params rsp+stack_offset+22*8
|
||||
DECLARE_REG_TMP 4
|
||||
%else
|
||||
%assign free_regs 9
|
||||
%define stack_param rsp
|
||||
%define num_stack_params rsp+stack_offset+16*8
|
||||
DECLARE_REG_TMP 7
|
||||
%endif
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; void checkasm_checked_call(void *func, ...)
|
||||
;-----------------------------------------------------------------------------
|
||||
INIT_XMM
|
||||
cglobal checked_call, 2, 15, 16, max_args*8+64+8
|
||||
mov t0, r0
|
||||
|
||||
; All arguments have been pushed on the stack instead of registers in
|
||||
; order to test for incorrect assumptions that 32-bit ints are
|
||||
; zero-extended to 64-bit.
|
||||
mov r0, r6mp
|
||||
mov r1, r7mp
|
||||
mov r2, r8mp
|
||||
mov r3, r9mp
|
||||
%if UNIX64
|
||||
mov r4, r10mp
|
||||
mov r5, r11mp
|
||||
%else ; WIN64
|
||||
; Move possible floating-point arguments to the correct registers
|
||||
movq m0, r0
|
||||
movq m1, r1
|
||||
movq m2, r2
|
||||
movq m3, r3
|
||||
|
||||
%assign i 6
|
||||
%rep 16-6
|
||||
mova m %+ i, [x %+ i]
|
||||
%assign i i+1
|
||||
%endrep
|
||||
%endif
|
||||
|
||||
; write stack canaries to the area above parameters passed on the stack
|
||||
mov r9d, [num_stack_params]
|
||||
mov r8, [rsp+stack_offset] ; return address
|
||||
not r8
|
||||
%assign i 0
|
||||
%rep 8 ; 64 bytes
|
||||
mov [stack_param+(r9+i)*8], r8
|
||||
%assign i i+1
|
||||
%endrep
|
||||
dec r9d
|
||||
jl .stack_setup_done ; no stack parameters
|
||||
.copy_stack_parameter:
|
||||
mov r8, [stack_param+stack_offset+7*8+r9*8]
|
||||
mov [stack_param+r9*8], r8
|
||||
dec r9d
|
||||
jge .copy_stack_parameter
|
||||
.stack_setup_done:
|
||||
|
||||
%assign i 14
|
||||
%rep 15-free_regs
|
||||
mov r %+ i, [n %+ i]
|
||||
%assign i i-1
|
||||
%endrep
|
||||
call t0
|
||||
|
||||
; check for failure to preserve registers
|
||||
xor r14, [n14]
|
||||
lea r0, [errmsg_reg]
|
||||
%assign i 13
|
||||
%rep 14-free_regs
|
||||
xor r %+ i, [n %+ i]
|
||||
or r14, r %+ i
|
||||
%assign i i-1
|
||||
%endrep
|
||||
%if WIN64
|
||||
pxor m6, [x6]
|
||||
%assign i 7
|
||||
%rep 16-7
|
||||
pxor m %+ i, [x %+ i]
|
||||
por m6, m %+ i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
packsswb m6, m6
|
||||
movq r5, m6
|
||||
or r14, r5
|
||||
%endif
|
||||
jnz .fail
|
||||
|
||||
; check for stack corruption
|
||||
mov r9d, [num_stack_params]
|
||||
mov r8, [rsp+stack_offset]
|
||||
mov r4, [stack_param+r9*8]
|
||||
not r8
|
||||
xor r4, r8
|
||||
%assign i 1
|
||||
%rep 6
|
||||
mov r5, [stack_param+(r9+i)*8]
|
||||
xor r5, r8
|
||||
or r4, r5
|
||||
%assign i i+1
|
||||
%endrep
|
||||
xor r8, [stack_param+(r9+7)*8]
|
||||
or r4, r8
|
||||
jz .ok
|
||||
add r0, errmsg_stack-errmsg_reg
|
||||
.fail:
|
||||
; Call fail_func() with a descriptive message to mark it as a failure.
|
||||
; Save the return value located in rdx:rax first to prevent clobbering.
|
||||
mov r9, rax
|
||||
mov r10, rdx
|
||||
xor eax, eax
|
||||
call fail_func
|
||||
mov rdx, r10
|
||||
mov rax, r9
|
||||
.ok:
|
||||
RET
|
||||
|
||||
; trigger a warmup of vector units
|
||||
%macro WARMUP 0
|
||||
cglobal warmup, 0, 0
|
||||
xorps m0, m0
|
||||
mulps m0, m0
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_YMM avx2
|
||||
WARMUP
|
||||
INIT_ZMM avx512
|
||||
WARMUP
|
||||
|
||||
%else
|
||||
|
||||
; just random numbers to reduce the chance of incidental match
|
||||
%assign n3 0x6549315c
|
||||
%assign n4 0xe02f3e23
|
||||
%assign n5 0xb78d0d1d
|
||||
%assign n6 0x33627ba7
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; void checkasm_checked_call(void *func, ...)
|
||||
;-----------------------------------------------------------------------------
|
||||
cglobal checked_call, 1, 7
|
||||
mov r3, [esp+stack_offset] ; return address
|
||||
mov r1, [esp+stack_offset+17*4] ; num_stack_params
|
||||
mov r2, 27
|
||||
not r3
|
||||
sub r2, r1
|
||||
.push_canary:
|
||||
push r3
|
||||
dec r2
|
||||
jg .push_canary
|
||||
.push_parameter:
|
||||
push dword [esp+32*4]
|
||||
dec r1
|
||||
jg .push_parameter
|
||||
mov r3, n3
|
||||
mov r4, n4
|
||||
mov r5, n5
|
||||
mov r6, n6
|
||||
call r0
|
||||
|
||||
; check for failure to preserve registers
|
||||
xor r3, n3
|
||||
xor r4, n4
|
||||
xor r5, n5
|
||||
xor r6, n6
|
||||
or r3, r4
|
||||
or r5, r6
|
||||
LEA r1, errmsg_reg
|
||||
or r3, r5
|
||||
jnz .fail
|
||||
|
||||
; check for stack corruption
|
||||
mov r3, [esp+48*4] ; num_stack_params
|
||||
mov r6, [esp+31*4] ; return address
|
||||
mov r4, [esp+r3*4]
|
||||
sub r3, 26
|
||||
not r6
|
||||
xor r4, r6
|
||||
.check_canary:
|
||||
mov r5, [esp+(r3+27)*4]
|
||||
xor r5, r6
|
||||
or r4, r5
|
||||
inc r3
|
||||
jl .check_canary
|
||||
test r4, r4
|
||||
jz .ok
|
||||
add r1, errmsg_stack-errmsg_reg
|
||||
.fail:
|
||||
mov r3, eax
|
||||
mov r4, edx
|
||||
mov [esp], r1
|
||||
call fail_func
|
||||
mov edx, r4
|
||||
mov eax, r3
|
||||
.ok:
|
||||
add esp, 27*4
|
||||
RET
|
||||
|
||||
%endif ; ARCH_X86_64
|
33
third_party/dav1d/tests/header_test.c
vendored
33
third_party/dav1d/tests/header_test.c
vendored
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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 DAV1D_TEST_HEADER
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
102
third_party/dav1d/tests/libfuzzer/alloc_fail.c
vendored
102
third_party/dav1d/tests/libfuzzer/alloc_fail.c
vendored
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2018, Janne Grunau
|
||||
* 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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "alloc_fail.h"
|
||||
|
||||
static int fail_probability;
|
||||
|
||||
void dav1d_setup_alloc_fail(unsigned seed, unsigned probability) {
|
||||
srand(seed);
|
||||
|
||||
while (probability >= RAND_MAX)
|
||||
probability >>= 1;
|
||||
|
||||
fail_probability = probability;
|
||||
}
|
||||
|
||||
void * __wrap_malloc(size_t);
|
||||
|
||||
void * __wrap_malloc(size_t sz) {
|
||||
if (rand() < fail_probability)
|
||||
return NULL;
|
||||
return malloc(sz);
|
||||
}
|
||||
|
||||
#if defined(HAVE_POSIX_MEMALIGN)
|
||||
int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size);
|
||||
|
||||
int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size) {
|
||||
if (rand() < fail_probability)
|
||||
return ENOMEM;
|
||||
return posix_memalign(memptr, alignment, size);
|
||||
}
|
||||
#else
|
||||
#error "HAVE_POSIX_MEMALIGN required"
|
||||
#endif
|
||||
|
||||
int __wrap_pthread_create(pthread_t *, const pthread_attr_t *,
|
||||
void *(*) (void *), void *);
|
||||
|
||||
int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg)
|
||||
{
|
||||
if (rand() < (fail_probability + RAND_MAX/16))
|
||||
return EAGAIN;
|
||||
|
||||
return pthread_create(thread, attr, start_routine, arg);
|
||||
}
|
||||
|
||||
int __wrap_pthread_mutex_init(pthread_mutex_t *,
|
||||
const pthread_mutexattr_t *);
|
||||
|
||||
int __wrap_pthread_mutex_init(pthread_mutex_t *restrict mutex,
|
||||
const pthread_mutexattr_t *restrict attr)
|
||||
{
|
||||
if (rand() < (fail_probability + RAND_MAX/8))
|
||||
return ENOMEM;
|
||||
|
||||
return pthread_mutex_init(mutex, attr);
|
||||
}
|
||||
|
||||
int __wrap_pthread_cond_init(pthread_cond_t *,
|
||||
const pthread_condattr_t *);
|
||||
|
||||
int __wrap_pthread_cond_init(pthread_cond_t *restrict cond,
|
||||
const pthread_condattr_t *restrict attr)
|
||||
{
|
||||
if (rand() < (fail_probability + RAND_MAX/16))
|
||||
return ENOMEM;
|
||||
|
||||
return pthread_cond_init(cond, attr);
|
||||
}
|
35
third_party/dav1d/tests/libfuzzer/alloc_fail.h
vendored
35
third_party/dav1d/tests/libfuzzer/alloc_fail.h
vendored
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2018, Janne Grunau
|
||||
* 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_TESTS_LIBFUZZER_ALLOC_FAIL_H
|
||||
#define DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H
|
||||
|
||||
#include <dav1d/common.h>
|
||||
|
||||
DAV1D_API void dav1d_setup_alloc_fail(unsigned seed, unsigned probability);
|
||||
|
||||
#endif /* DAV1D_TESTS_LIBFUZZER_ALLOC_FAIL_H */
|
199
third_party/dav1d/tests/libfuzzer/dav1d_fuzzer.c
vendored
199
third_party/dav1d/tests/libfuzzer/dav1d_fuzzer.c
vendored
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2018, Janne Grunau
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <dav1d/dav1d.h>
|
||||
#include "src/cpu.h"
|
||||
#include "dav1d_fuzzer.h"
|
||||
|
||||
#ifdef DAV1D_ALLOC_FAIL
|
||||
|
||||
#include "alloc_fail.h"
|
||||
|
||||
static unsigned djb_xor(const uint8_t * c, size_t len) {
|
||||
unsigned hash = 5381;
|
||||
for(size_t i = 0; i < len; i++)
|
||||
hash = hash * 33 ^ c[i];
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned r32le(const uint8_t *const p) {
|
||||
return ((uint32_t)p[3] << 24U) | (p[2] << 16U) | (p[1] << 8U) | p[0];
|
||||
}
|
||||
|
||||
#define DAV1D_FUZZ_MAX_SIZE 4096 * 4096
|
||||
|
||||
// search for "--cpumask xxx" in argv and remove both parameters
|
||||
int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
int i = 1;
|
||||
for (; i < *argc; i++) {
|
||||
if (!strcmp((*argv)[i], "--cpumask")) {
|
||||
const char * cpumask = (*argv)[i+1];
|
||||
if (cpumask) {
|
||||
char *end;
|
||||
unsigned res;
|
||||
if (!strncmp(cpumask, "0x", 2)) {
|
||||
cpumask += 2;
|
||||
res = (unsigned) strtoul(cpumask, &end, 16);
|
||||
} else {
|
||||
res = (unsigned) strtoul(cpumask, &end, 0);
|
||||
}
|
||||
if (end != cpumask && !end[0]) {
|
||||
dav1d_set_cpu_flags_mask(res);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < *argc - 2; i++) {
|
||||
(*argv)[i] = (*argv)[i + 2];
|
||||
}
|
||||
|
||||
*argc = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// expects ivf input
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
||||
{
|
||||
Dav1dSettings settings = { 0 };
|
||||
Dav1dContext * ctx = NULL;
|
||||
Dav1dPicture pic;
|
||||
const uint8_t *ptr = data;
|
||||
int have_seq_hdr = 0;
|
||||
int err;
|
||||
|
||||
dav1d_version();
|
||||
|
||||
if (size < 32) goto end;
|
||||
#ifdef DAV1D_ALLOC_FAIL
|
||||
unsigned h = djb_xor(ptr, 32);
|
||||
unsigned seed = h;
|
||||
unsigned probability = h > (RAND_MAX >> 5) ? RAND_MAX >> 5 : h;
|
||||
int n_frame_threads = (h & 0xf) + 1;
|
||||
int n_tile_threads = ((h >> 4) & 0x7) + 1;
|
||||
if (n_frame_threads > 5) n_frame_threads = 1;
|
||||
if (n_tile_threads > 3) n_tile_threads = 1;
|
||||
#endif
|
||||
ptr += 32; // skip ivf header
|
||||
|
||||
dav1d_default_settings(&settings);
|
||||
|
||||
#ifdef DAV1D_MT_FUZZING
|
||||
settings.n_frame_threads = settings.n_tile_threads = 2;
|
||||
#elif defined(DAV1D_ALLOC_FAIL)
|
||||
settings.n_frame_threads = n_frame_threads;
|
||||
settings.n_tile_threads = n_tile_threads;
|
||||
dav1d_setup_alloc_fail(seed, probability);
|
||||
#else
|
||||
settings.n_frame_threads = settings.n_tile_threads = 1;
|
||||
#endif
|
||||
#if defined(DAV1D_FUZZ_MAX_SIZE)
|
||||
settings.frame_size_limit = DAV1D_FUZZ_MAX_SIZE;
|
||||
#endif
|
||||
|
||||
err = dav1d_open(&ctx, &settings);
|
||||
if (err < 0) goto end;
|
||||
|
||||
while (ptr <= data + size - 12) {
|
||||
Dav1dData buf;
|
||||
uint8_t *p;
|
||||
|
||||
size_t frame_size = r32le(ptr);
|
||||
ptr += 12;
|
||||
|
||||
if (frame_size > size || ptr > data + size - frame_size)
|
||||
break;
|
||||
|
||||
if (!frame_size) continue;
|
||||
|
||||
if (!have_seq_hdr) {
|
||||
Dav1dSequenceHeader seq = { 0 };
|
||||
int err = dav1d_parse_sequence_header(&seq, ptr, frame_size);
|
||||
// skip frames until we see a sequence header
|
||||
if (err != 0) {
|
||||
ptr += frame_size;
|
||||
continue;
|
||||
}
|
||||
have_seq_hdr = 1;
|
||||
}
|
||||
|
||||
// copy frame data to a new buffer to catch reads past the end of input
|
||||
p = dav1d_data_create(&buf, frame_size);
|
||||
if (!p) goto cleanup;
|
||||
memcpy(p, ptr, frame_size);
|
||||
ptr += frame_size;
|
||||
|
||||
do {
|
||||
if ((err = dav1d_send_data(ctx, &buf)) < 0) {
|
||||
if (err != DAV1D_ERR(EAGAIN))
|
||||
break;
|
||||
}
|
||||
memset(&pic, 0, sizeof(pic));
|
||||
err = dav1d_get_picture(ctx, &pic);
|
||||
if (err == 0) {
|
||||
dav1d_picture_unref(&pic);
|
||||
} else if (err != DAV1D_ERR(EAGAIN)) {
|
||||
break;
|
||||
}
|
||||
} while (buf.sz > 0);
|
||||
|
||||
if (buf.sz > 0)
|
||||
dav1d_data_unref(&buf);
|
||||
}
|
||||
|
||||
memset(&pic, 0, sizeof(pic));
|
||||
if ((err = dav1d_get_picture(ctx, &pic)) == 0) {
|
||||
/* Test calling dav1d_picture_unref() after dav1d_close() */
|
||||
do {
|
||||
Dav1dPicture pic2 = { 0 };
|
||||
if ((err = dav1d_get_picture(ctx, &pic2)) == 0)
|
||||
dav1d_picture_unref(&pic2);
|
||||
} while (err != DAV1D_ERR(EAGAIN));
|
||||
|
||||
dav1d_close(&ctx);
|
||||
dav1d_picture_unref(&pic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
dav1d_close(&ctx);
|
||||
end:
|
||||
return 0;
|
||||
}
|
37
third_party/dav1d/tests/libfuzzer/dav1d_fuzzer.h
vendored
37
third_party/dav1d/tests/libfuzzer/dav1d_fuzzer.h
vendored
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2018, Janne Grunau
|
||||
* 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_TESTS_LIBFUZZER_DAV1D_FUZZER_H
|
||||
#define DAV1D_TESTS_LIBFUZZER_DAV1D_FUZZER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||
|
||||
#endif /* DAV1D_TESTS_LIBFUZZER_DAV1D_FUZZER_H */
|
100
third_party/dav1d/tests/libfuzzer/main.c
vendored
100
third_party/dav1d/tests/libfuzzer/main.c
vendored
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018, VideoLAN and dav1d authors
|
||||
* Copyright © 2018, Janne Grunau
|
||||
* 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 <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dav1d_fuzzer.h"
|
||||
|
||||
// expects ivf input
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ret = -1;
|
||||
FILE *f = NULL;
|
||||
int64_t fsize;
|
||||
const char *filename = NULL;
|
||||
uint8_t *data = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (LLVMFuzzerInitialize(&argc, &argv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stdout, "Usage:\n%s fuzzing_testcase.ivf\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
filename = argv[1];
|
||||
|
||||
if (!(f = fopen(filename, "rb"))) {
|
||||
fprintf(stderr, "failed to open %s: %s\n", filename, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fseeko(f, 0, SEEK_END) == -1) {
|
||||
fprintf(stderr, "fseek(%s, 0, SEEK_END) failed: %s\n", filename,
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if ((fsize = ftello(f)) == -1) {
|
||||
fprintf(stderr, "ftell(%s) failed: %s\n", filename, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
rewind(f);
|
||||
|
||||
if (fsize < 0 || fsize > INT_MAX) {
|
||||
fprintf(stderr, "%s is too large: %"PRId64"\n", filename, fsize);
|
||||
goto error;
|
||||
}
|
||||
size = (size_t)fsize;
|
||||
|
||||
if (!(data = malloc(size))) {
|
||||
fprintf(stderr, "failed to allocate: %zu bytes\n", size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fread(data, size, 1, f) == size) {
|
||||
fprintf(stderr, "failed to read %zu bytes from %s: %s\n", size,
|
||||
filename, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = LLVMFuzzerTestOneInput(data, size);
|
||||
|
||||
error:
|
||||
free(data);
|
||||
if (f) fclose(f);
|
||||
return ret;
|
||||
}
|
102
third_party/dav1d/tests/libfuzzer/meson.build
vendored
102
third_party/dav1d/tests/libfuzzer/meson.build
vendored
@ -1,102 +0,0 @@
|
||||
# Copyright © 2020, VideoLAN and dav1d authors
|
||||
# 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.
|
||||
|
||||
#
|
||||
# Build definition for the dav1d fuzzing binaries
|
||||
#
|
||||
|
||||
if fuzzing_engine == 'none' and not have_fseeko
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
dav1d_fuzzer_sources = files('dav1d_fuzzer.c')
|
||||
fuzzer_ldflags = []
|
||||
fuzzer_link_lang = {}
|
||||
|
||||
if get_option('fuzzer_ldflags') != ''
|
||||
fuzzer_ldflags += [get_option('fuzzer_ldflags')]
|
||||
endif
|
||||
|
||||
if fuzzing_engine == 'none'
|
||||
dav1d_fuzzer_sources += files('main.c')
|
||||
elif fuzzing_engine == 'libfuzzer'
|
||||
fuzzer_ldflags += ['-fsanitize=fuzzer']
|
||||
elif fuzzing_engine == 'oss-fuzz'
|
||||
# libFuzzingEngine needs c++
|
||||
add_languages('cpp')
|
||||
fuzzer_link_lang = {'link_language': 'cpp'}
|
||||
endif
|
||||
|
||||
dav1d_fuzzer = executable('dav1d_fuzzer',
|
||||
dav1d_fuzzer_sources,
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: [stackalign_flag, stackrealign_flag],
|
||||
link_args: fuzzer_ldflags,
|
||||
link_with : libdav1d,
|
||||
build_by_default: true,
|
||||
dependencies : [thread_dependency],
|
||||
kwargs: fuzzer_link_lang
|
||||
)
|
||||
|
||||
dav1d_fuzzer_mt = executable('dav1d_fuzzer_mt',
|
||||
dav1d_fuzzer_sources,
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: [stackalign_flag, stackrealign_flag, '-DDAV1D_MT_FUZZING'],
|
||||
link_args: fuzzer_ldflags,
|
||||
link_with : libdav1d,
|
||||
build_by_default: true,
|
||||
dependencies : [thread_dependency],
|
||||
kwargs: fuzzer_link_lang
|
||||
)
|
||||
|
||||
objcopy = find_program('objcopy',
|
||||
required: false)
|
||||
if (objcopy.found() and
|
||||
not get_option('b_lto') and
|
||||
get_option('default_library') == 'static' and
|
||||
cc.has_function('posix_memalign', prefix : '#include <stdlib.h>', args : test_args))
|
||||
|
||||
libdav1d_af = custom_target('libdav1d_af',
|
||||
input: libdav1d,
|
||||
output: 'libdav1d_af.a',
|
||||
depends: libdav1d,
|
||||
command: [objcopy,
|
||||
'--redefine-sym', 'malloc=__wrap_malloc',
|
||||
'--redefine-sym', 'posix_memalign=__wrap_posix_memalign',
|
||||
'--redefine-sym', 'pthread_create=__wrap_pthread_create',
|
||||
'--redefine-sym', 'pthread_cond_init=__wrap_pthread_cond_init',
|
||||
'--redefine-sym', 'pthread_mutex_init=__wrap_pthread_mutex_init',
|
||||
'@INPUT@', '@OUTPUT@'])
|
||||
|
||||
dav1d_fuzzer_mem = executable('dav1d_fuzzer_mem',
|
||||
dav1d_fuzzer_sources + ['alloc_fail.c'],
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: [stackalign_flag, stackrealign_flag, '-DDAV1D_ALLOC_FAIL'],
|
||||
link_args: fuzzer_ldflags + [join_paths(libdav1d_af.full_path())],
|
||||
link_depends: libdav1d_af,
|
||||
build_by_default: false,
|
||||
dependencies : [thread_dependency],
|
||||
kwargs: fuzzer_link_lang
|
||||
)
|
||||
endif
|
151
third_party/dav1d/tests/meson.build
vendored
151
third_party/dav1d/tests/meson.build
vendored
@ -1,151 +0,0 @@
|
||||
# Copyright © 2018, VideoLAN and dav1d authors
|
||||
# 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.
|
||||
|
||||
#
|
||||
# Build definition for the dav1d tests
|
||||
#
|
||||
|
||||
# Leave subdir if tests are disabled
|
||||
if not get_option('enable_tests')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
if is_asm_enabled
|
||||
checkasm_sources = files(
|
||||
'checkasm/checkasm.c',
|
||||
'checkasm/msac.c',
|
||||
)
|
||||
|
||||
checkasm_tmpl_sources = files(
|
||||
'checkasm/cdef.c',
|
||||
'checkasm/filmgrain.c',
|
||||
'checkasm/ipred.c',
|
||||
'checkasm/itx.c',
|
||||
'checkasm/loopfilter.c',
|
||||
'checkasm/looprestoration.c',
|
||||
'checkasm/mc.c',
|
||||
)
|
||||
|
||||
checkasm_bitdepth_objs = []
|
||||
foreach bitdepth : dav1d_bitdepths
|
||||
checkasm_bitdepth_lib = static_library(
|
||||
'checkasm_bitdepth_@0@'.format(bitdepth),
|
||||
checkasm_tmpl_sources,
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: ['-DBITDEPTH=@0@'.format(bitdepth), stackalign_flag],
|
||||
install: false,
|
||||
build_by_default: false,
|
||||
)
|
||||
checkasm_bitdepth_objs += checkasm_bitdepth_lib.extract_all_objects()
|
||||
endforeach
|
||||
|
||||
checkasm_asm_objs = []
|
||||
checkasm_asm_sources = []
|
||||
if host_machine.cpu_family() == 'aarch64' or host_machine.cpu() == 'arm64'
|
||||
checkasm_asm_sources += files('checkasm/arm/checkasm_64.S')
|
||||
elif host_machine.cpu_family().startswith('arm')
|
||||
checkasm_asm_sources += files('checkasm/arm/checkasm_32.S')
|
||||
elif host_machine.cpu_family().startswith('x86')
|
||||
checkasm_asm_objs += nasm_gen.process(files('checkasm/x86/checkasm.asm'))
|
||||
endif
|
||||
|
||||
if use_gaspp
|
||||
checkasm_asm_objs += gaspp_gen.process(checkasm_asm_sources)
|
||||
else
|
||||
checkasm_sources += checkasm_asm_sources
|
||||
endif
|
||||
|
||||
checkasm = executable('checkasm',
|
||||
checkasm_sources,
|
||||
checkasm_asm_objs,
|
||||
|
||||
objects: [
|
||||
checkasm_bitdepth_objs,
|
||||
libdav1d.extract_all_objects(recursive: true),
|
||||
],
|
||||
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: [stackalign_flag, stackrealign_flag],
|
||||
build_by_default: false,
|
||||
dependencies : [
|
||||
thread_dependency,
|
||||
rt_dependency,
|
||||
libdl_dependency,
|
||||
libm_dependency,
|
||||
],
|
||||
)
|
||||
|
||||
test('checkasm', checkasm, suite: 'checkasm', timeout: 180, is_parallel: false)
|
||||
benchmark('checkasm', checkasm, suite: 'checkasm', timeout: 3600, args: '--bench')
|
||||
endif
|
||||
|
||||
c99_extension_flag = cc.first_supported_argument(
|
||||
'-Werror=c11-extensions',
|
||||
'-Werror=c99-c11-compat',
|
||||
'-Wc11-extensions',
|
||||
'-Wc99-c11-compat',
|
||||
)
|
||||
|
||||
# dav1d_api_headers
|
||||
foreach header : dav1d_api_headers
|
||||
target = header + '_test'
|
||||
|
||||
header_test_exe = executable(target,
|
||||
'header_test.c',
|
||||
include_directories: dav1d_inc_dirs,
|
||||
c_args: ['-DDAV1D_TEST_HEADER="@0@"'.format(header), c99_extension_flag],
|
||||
build_by_default: true
|
||||
)
|
||||
|
||||
test(target, header_test_exe, suite: 'headers')
|
||||
endforeach
|
||||
|
||||
|
||||
# fuzzing binaries
|
||||
subdir('libfuzzer')
|
||||
|
||||
# seek stress test binary, depends on dav1d cli tool
|
||||
if get_option('enable_tools')
|
||||
seek_stress_sources = files('seek_stress.c')
|
||||
seek_stress = executable('seek_stress',
|
||||
seek_stress_sources, rev_target,
|
||||
objects: [
|
||||
dav1d.extract_objects('dav1d_cli_parse.c'),
|
||||
dav1d_input_objs.extract_objects('input/input.c', 'input/ivf.c'),
|
||||
],
|
||||
include_directories: [dav1d_inc_dirs, include_directories('../tools')],
|
||||
link_with: libdav1d,
|
||||
dependencies: [
|
||||
thread_dependency,
|
||||
rt_dependency,
|
||||
getopt_dependency,
|
||||
libm_dependency,
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
# Include dav1d test data repository with additional tests
|
||||
if get_option('testdata_tests')
|
||||
subdir('dav1d-test-data')
|
||||
endif
|
243
third_party/dav1d/tests/seek_stress.c
vendored
243
third_party/dav1d/tests/seek_stress.c
vendored
@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020, VideoLAN and dav1d authors
|
||||
* Copyright © 2020, 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dav1d/dav1d.h"
|
||||
#include "input/input.h"
|
||||
#include "input/demuxer.h"
|
||||
#include "dav1d_cli_parse.h"
|
||||
|
||||
#define NUM_RAND_SEEK 3
|
||||
#define NUM_REL_SEEK 4
|
||||
#define NUM_END_SEEK 2
|
||||
|
||||
const Demuxer annexb_demuxer = { .name = "" };
|
||||
const Demuxer section5_demuxer = { .name = "" };
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
static unsigned get_seed(void) {
|
||||
return GetTickCount();
|
||||
}
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach_time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
static unsigned get_seed(void) {
|
||||
#ifdef __APPLE__
|
||||
return (unsigned) mach_absolute_time();
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (unsigned) (1000000000ULL * ts.tv_sec + ts.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t xs_state[4];
|
||||
|
||||
static void xor128_srand(unsigned seed) {
|
||||
xs_state[0] = seed;
|
||||
xs_state[1] = ( seed & 0xffff0000) | (~seed & 0x0000ffff);
|
||||
xs_state[2] = (~seed & 0xffff0000) | ( seed & 0x0000ffff);
|
||||
xs_state[3] = ~seed;
|
||||
}
|
||||
|
||||
// xor128 from Marsaglia, George (July 2003). "Xorshift RNGs".
|
||||
// Journal of Statistical Software. 8 (14).
|
||||
// doi:10.18637/jss.v008.i14.
|
||||
static int xor128_rand(void) {
|
||||
const uint32_t x = xs_state[0];
|
||||
const uint32_t t = x ^ (x << 11);
|
||||
|
||||
xs_state[0] = xs_state[1];
|
||||
xs_state[1] = xs_state[2];
|
||||
xs_state[2] = xs_state[3];
|
||||
uint32_t w = xs_state[3];
|
||||
|
||||
w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
|
||||
xs_state[3] = w;
|
||||
|
||||
return w >> 1;
|
||||
}
|
||||
|
||||
static inline int decode_frame(Dav1dPicture *const p,
|
||||
Dav1dContext *const c, Dav1dData *const data)
|
||||
{
|
||||
int res;
|
||||
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)));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if ((res = dav1d_get_picture(c, p)) < 0) {
|
||||
if (res != DAV1D_ERR(EAGAIN)) {
|
||||
fprintf(stderr, "Error decoding frame: %s\n",
|
||||
strerror(DAV1D_ERR(res)));
|
||||
return res;
|
||||
}
|
||||
} else dav1d_picture_unref(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_rand(DemuxerContext *const in, Dav1dContext *const c,
|
||||
Dav1dData *const data, const double fps)
|
||||
{
|
||||
int res = 0;
|
||||
Dav1dPicture p;
|
||||
const int num_frames = xor128_rand() % (int)(fps * 5);
|
||||
for (int i = 0; i < num_frames; i++) {
|
||||
if ((res = decode_frame(&p, c, data))) break;
|
||||
if (input_read(in, data) || data->sz == 0) break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int decode_all(DemuxerContext *const in,
|
||||
Dav1dContext *const c, Dav1dData *const data)
|
||||
{
|
||||
int res = 0;
|
||||
Dav1dPicture p;
|
||||
do { if ((res = decode_frame(&p, c, data))) break;
|
||||
} while (!input_read(in, data) && data->sz > 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int seek(DemuxerContext *const in, Dav1dContext *const c,
|
||||
const uint64_t pts, Dav1dData *const data)
|
||||
{
|
||||
int res;
|
||||
if ((res = input_seek(in, pts))) return res;
|
||||
Dav1dSequenceHeader seq;
|
||||
do { if ((res = input_read(in, data))) break;
|
||||
} while (dav1d_parse_sequence_header(&seq, data->data, data->sz));
|
||||
dav1d_flush(c);
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(const int argc, char *const *const argv) {
|
||||
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;
|
||||
}
|
||||
|
||||
CLISettings cli_settings;
|
||||
Dav1dSettings lib_settings;
|
||||
DemuxerContext *in;
|
||||
Dav1dContext *c;
|
||||
Dav1dData data;
|
||||
unsigned total, i_fps[2], i_timebase[2];
|
||||
double timebase, spf, fps;
|
||||
uint64_t pts;
|
||||
|
||||
xor128_srand(get_seed());
|
||||
parse(argc, argv, &cli_settings, &lib_settings);
|
||||
|
||||
if (input_open(&in, "ivf", cli_settings.inputfile,
|
||||
i_fps, &total, i_timebase) < 0 ||
|
||||
!i_timebase[0] || !i_timebase[1] || !i_fps[0] || !i_fps[1])
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
if (dav1d_open(&c, &lib_settings))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
timebase = (double)i_timebase[1] / i_timebase[0];
|
||||
spf = (double)i_fps[1] / i_fps[0];
|
||||
fps = (double)i_fps[0] / i_fps[1];
|
||||
if (fps < 1) goto end;
|
||||
|
||||
#define FRAME_OFFSET_TO_PTS(foff) \
|
||||
(uint64_t)llround(((foff) * spf) * 1000000000.0)
|
||||
#define TS_TO_PTS(ts) \
|
||||
(uint64_t)llround(((ts) * timebase) * 1000000000.0)
|
||||
|
||||
// seek at random pts
|
||||
for (int i = 0; i < NUM_RAND_SEEK; i++) {
|
||||
pts = FRAME_OFFSET_TO_PTS(xor128_rand() % total);
|
||||
if (seek(in, c, pts, &data)) continue;
|
||||
if (decode_rand(in, c, &data, fps)) goto end;
|
||||
}
|
||||
pts = TS_TO_PTS(data.m.timestamp);
|
||||
|
||||
// seek left / right randomly with random intervals within 1s
|
||||
for (int i = 0, tries = 0;
|
||||
i - tries < NUM_REL_SEEK && tries < NUM_REL_SEEK / 2;
|
||||
i++)
|
||||
{
|
||||
const int sign = xor128_rand() & 1 ? -1 : +1;
|
||||
const float diff = (xor128_rand() % 100) / 100.f;
|
||||
int64_t new_pts = pts + sign * FRAME_OFFSET_TO_PTS(diff * fps);
|
||||
const int64_t new_ts = llround(new_pts / (timebase * 1000000000.0));
|
||||
new_pts = TS_TO_PTS(new_ts);
|
||||
if (new_pts < 0 || (uint64_t)new_pts >= FRAME_OFFSET_TO_PTS(total)) {
|
||||
if (seek(in, c, FRAME_OFFSET_TO_PTS(total / 2), &data)) break;
|
||||
pts = TS_TO_PTS(data.m.timestamp);
|
||||
tries++;
|
||||
continue;
|
||||
}
|
||||
if (seek(in, c, new_pts, &data))
|
||||
if (seek(in, c, 0, &data)) goto end;
|
||||
if (decode_rand(in, c, &data, fps)) goto end;
|
||||
pts = TS_TO_PTS(data.m.timestamp);
|
||||
}
|
||||
|
||||
unsigned shift = 0;
|
||||
do {
|
||||
shift += 5;
|
||||
if (shift > total)
|
||||
shift = total;
|
||||
} while (seek(in, c, FRAME_OFFSET_TO_PTS(total - shift), &data));
|
||||
|
||||
// simulate seeking after the end of the file
|
||||
for (int i = 0; i < NUM_END_SEEK; i++) {
|
||||
if (seek(in, c, FRAME_OFFSET_TO_PTS(total - shift), &data)) goto end;
|
||||
if (decode_all(in, c, &data)) goto end;
|
||||
int num_flush = 1 + 64 + xor128_rand() % 64;
|
||||
while (num_flush--) dav1d_flush(c);
|
||||
}
|
||||
|
||||
end:
|
||||
input_close(in);
|
||||
dav1d_close(&c);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
562
third_party/dav1d/tools/compat/getopt.c
vendored
562
third_party/dav1d/tools/compat/getopt.c
vendored
@ -1,562 +0,0 @@
|
||||
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
|
||||
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Dieter Baron and Thomas Klausner.
|
||||
*
|
||||
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
|
||||
|
||||
#ifdef REPLACE_GETOPT
|
||||
int opterr = 1; /* if error message should be printed */
|
||||
int optind = 1; /* index into parent argv vector */
|
||||
int optopt = '?'; /* character checked for validity */
|
||||
#undef optreset /* see getopt.h */
|
||||
#define optreset __mingw_optreset
|
||||
int optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
#endif
|
||||
|
||||
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||
|
||||
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||
|
||||
/* return values */
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||
#define INORDER (int)1
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
#define __progname __argv[0]
|
||||
#else
|
||||
extern char __declspec(dllimport) *__progname;
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
static char EMSG[] = "";
|
||||
#else
|
||||
#define EMSG ""
|
||||
#endif
|
||||
|
||||
static int getopt_internal(int, char * const *, const char *,
|
||||
const struct option *, int *, int);
|
||||
static int parse_long_options(char * const *, const char *,
|
||||
const struct option *, int *, int);
|
||||
static int gcd(int, int);
|
||||
static void permute_args(int, int, int, char * const *);
|
||||
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
|
||||
/* XXX: set optreset to 1 rather than these two */
|
||||
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||
|
||||
/* Error messages */
|
||||
static const char recargchar[] = "option requires an argument -- %c";
|
||||
static const char recargstring[] = "option requires an argument -- %s";
|
||||
static const char ambig[] = "ambiguous option -- %.*s";
|
||||
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||
static const char illoptchar[] = "unknown option -- %c";
|
||||
static const char illoptstring[] = "unknown option -- %s";
|
||||
|
||||
static void
|
||||
_vwarnx(const char *fmt,va_list ap)
|
||||
{
|
||||
(void)fprintf(stderr,"%s: ",__progname);
|
||||
if (fmt != NULL)
|
||||
(void)vfprintf(stderr,fmt,ap);
|
||||
(void)fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
static void
|
||||
warnx(const char *fmt,...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap,fmt);
|
||||
_vwarnx(fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the greatest common divisor of a and b.
|
||||
*/
|
||||
static int
|
||||
gcd(int a, int b)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = a % b;
|
||||
while (c != 0) {
|
||||
a = b;
|
||||
b = c;
|
||||
c = a % b;
|
||||
}
|
||||
|
||||
return (b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||
* in each block).
|
||||
*/
|
||||
static void
|
||||
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||
char * const *nargv)
|
||||
{
|
||||
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||
char *swap;
|
||||
|
||||
/*
|
||||
* compute lengths of blocks and number and size of cycles
|
||||
*/
|
||||
nnonopts = panonopt_end - panonopt_start;
|
||||
nopts = opt_end - panonopt_end;
|
||||
ncycle = gcd(nnonopts, nopts);
|
||||
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||
|
||||
for (i = 0; i < ncycle; i++) {
|
||||
cstart = panonopt_end+i;
|
||||
pos = cstart;
|
||||
for (j = 0; j < cyclelen; j++) {
|
||||
if (pos >= panonopt_end)
|
||||
pos -= nnonopts;
|
||||
else
|
||||
pos += nopts;
|
||||
swap = nargv[pos];
|
||||
/* LINTED const cast */
|
||||
((char **) nargv)[pos] = nargv[cstart];
|
||||
/* LINTED const cast */
|
||||
((char **)nargv)[cstart] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* parse_long_options --
|
||||
* Parse long options in argc/argv argument vector.
|
||||
* Returns -1 if short_too is set and the option does not match long_options.
|
||||
*/
|
||||
static int
|
||||
parse_long_options(char * const *nargv, const char *options,
|
||||
const struct option *long_options, int *idx, int short_too)
|
||||
{
|
||||
char *current_argv, *has_equal;
|
||||
size_t current_argv_len;
|
||||
int i, ambiguous, match;
|
||||
|
||||
#define IDENTICAL_INTERPRETATION(_x, _y) \
|
||||
(long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
|
||||
long_options[(_x)].flag == long_options[(_y)].flag && \
|
||||
long_options[(_x)].val == long_options[(_y)].val)
|
||||
|
||||
current_argv = place;
|
||||
match = -1;
|
||||
ambiguous = 0;
|
||||
|
||||
optind++;
|
||||
|
||||
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||
/* argument found (--option=arg) */
|
||||
current_argv_len = has_equal - current_argv;
|
||||
has_equal++;
|
||||
} else
|
||||
current_argv_len = strlen(current_argv);
|
||||
|
||||
for (i = 0; long_options[i].name; i++) {
|
||||
/* find matching long option */
|
||||
if (strncmp(current_argv, long_options[i].name,
|
||||
current_argv_len))
|
||||
continue;
|
||||
|
||||
if (strlen(long_options[i].name) == current_argv_len) {
|
||||
/* exact match */
|
||||
match = i;
|
||||
ambiguous = 0;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If this is a known short option, don't allow
|
||||
* a partial match of a single character.
|
||||
*/
|
||||
if (short_too && current_argv_len == 1)
|
||||
continue;
|
||||
|
||||
if (match == -1) /* partial match */
|
||||
match = i;
|
||||
else if (!IDENTICAL_INTERPRETATION(i, match))
|
||||
ambiguous = 1;
|
||||
}
|
||||
if (ambiguous) {
|
||||
/* ambiguous abbreviation */
|
||||
if (PRINT_ERROR)
|
||||
warnx(ambig, (int)current_argv_len,
|
||||
current_argv);
|
||||
optopt = 0;
|
||||
return (BADCH);
|
||||
}
|
||||
if (match != -1) { /* option found */
|
||||
if (long_options[match].has_arg == no_argument
|
||||
&& has_equal) {
|
||||
if (PRINT_ERROR)
|
||||
warnx(noarg, (int)current_argv_len,
|
||||
current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless of flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
return (BADARG);
|
||||
}
|
||||
if (long_options[match].has_arg == required_argument ||
|
||||
long_options[match].has_arg == optional_argument) {
|
||||
if (has_equal)
|
||||
optarg = has_equal;
|
||||
else if (long_options[match].has_arg ==
|
||||
required_argument) {
|
||||
/*
|
||||
* optional argument doesn't use next nargv
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
}
|
||||
}
|
||||
if ((long_options[match].has_arg == required_argument)
|
||||
&& (optarg == NULL)) {
|
||||
/*
|
||||
* Missing argument; leading ':' indicates no error
|
||||
* should be generated.
|
||||
*/
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargstring,
|
||||
current_argv);
|
||||
/*
|
||||
* XXX: GNU sets optopt to val regardless of flag
|
||||
*/
|
||||
if (long_options[match].flag == NULL)
|
||||
optopt = long_options[match].val;
|
||||
else
|
||||
optopt = 0;
|
||||
--optind;
|
||||
return (BADARG);
|
||||
}
|
||||
} else { /* unknown option */
|
||||
if (short_too) {
|
||||
--optind;
|
||||
return (-1);
|
||||
}
|
||||
if (PRINT_ERROR)
|
||||
warnx(illoptstring, current_argv);
|
||||
optopt = 0;
|
||||
return (BADCH);
|
||||
}
|
||||
if (idx)
|
||||
*idx = match;
|
||||
if (long_options[match].flag) {
|
||||
*long_options[match].flag = long_options[match].val;
|
||||
return (0);
|
||||
} else
|
||||
return (long_options[match].val);
|
||||
#undef IDENTICAL_INTERPRETATION
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_internal --
|
||||
* Parse argc/argv argument vector. Called by user level routines.
|
||||
*/
|
||||
static int
|
||||
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||
const struct option *long_options, int *idx, int flags)
|
||||
{
|
||||
char *oli; /* option letter list index */
|
||||
int optchar, short_too;
|
||||
static int posixly_correct = -1;
|
||||
|
||||
if (options == NULL)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||
* XXX using optreset. Work around this braindamage.
|
||||
*/
|
||||
if (optind == 0)
|
||||
optind = optreset = 1;
|
||||
|
||||
/*
|
||||
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||
* string begins with a '+'.
|
||||
*
|
||||
* CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
|
||||
* optreset != 0 for GNU compatibility.
|
||||
*/
|
||||
if (posixly_correct == -1 || optreset != 0)
|
||||
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
|
||||
if (*options == '-')
|
||||
flags |= FLAG_ALLARGS;
|
||||
else if (posixly_correct || *options == '+')
|
||||
flags &= ~FLAG_PERMUTE;
|
||||
if (*options == '+' || *options == '-')
|
||||
options++;
|
||||
|
||||
optarg = NULL;
|
||||
if (optreset)
|
||||
nonopt_start = nonopt_end = -1;
|
||||
start:
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc) { /* end of argument vector */
|
||||
place = EMSG;
|
||||
if (nonopt_end != -1) {
|
||||
/* do permutation, if we have to */
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
else if (nonopt_start != -1) {
|
||||
/*
|
||||
* If we skipped non-options, set optind
|
||||
* to the first of them.
|
||||
*/
|
||||
optind = nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return (-1);
|
||||
}
|
||||
if (*(place = nargv[optind]) != '-' ||
|
||||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||
place = EMSG; /* found non-option */
|
||||
if (flags & FLAG_ALLARGS) {
|
||||
/*
|
||||
* GNU extension:
|
||||
* return non-option as argument to option 1
|
||||
*/
|
||||
optarg = nargv[optind++];
|
||||
return (INORDER);
|
||||
}
|
||||
if (!(flags & FLAG_PERMUTE)) {
|
||||
/*
|
||||
* If no permutation wanted, stop parsing
|
||||
* at first non-option.
|
||||
*/
|
||||
return (-1);
|
||||
}
|
||||
/* do permutation */
|
||||
if (nonopt_start == -1)
|
||||
nonopt_start = optind;
|
||||
else if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
nonopt_start = optind -
|
||||
(nonopt_end - nonopt_start);
|
||||
nonopt_end = -1;
|
||||
}
|
||||
optind++;
|
||||
/* process next argument */
|
||||
goto start;
|
||||
}
|
||||
if (nonopt_start != -1 && nonopt_end == -1)
|
||||
nonopt_end = optind;
|
||||
|
||||
/*
|
||||
* If we have "-" do nothing, if "--" we are done.
|
||||
*/
|
||||
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||
optind++;
|
||||
place = EMSG;
|
||||
/*
|
||||
* We found an option (--), so if we skipped
|
||||
* non-options, we have to permute.
|
||||
*/
|
||||
if (nonopt_end != -1) {
|
||||
permute_args(nonopt_start, nonopt_end,
|
||||
optind, nargv);
|
||||
optind -= nonopt_end - nonopt_start;
|
||||
}
|
||||
nonopt_start = nonopt_end = -1;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check long options if:
|
||||
* 1) we were passed some
|
||||
* 2) the arg is not just "-"
|
||||
* 3) either the arg starts with -- we are getopt_long_only()
|
||||
*/
|
||||
if (long_options != NULL && place != nargv[optind] &&
|
||||
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||
short_too = 0;
|
||||
if (*place == '-')
|
||||
place++; /* --foo long option */
|
||||
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||
short_too = 1; /* could be short option too */
|
||||
|
||||
optchar = parse_long_options(nargv, options, long_options,
|
||||
idx, short_too);
|
||||
if (optchar != -1) {
|
||||
place = EMSG;
|
||||
return (optchar);
|
||||
}
|
||||
}
|
||||
|
||||
if ((optchar = (int)*place++) == (int)':' ||
|
||||
(optchar == (int)'-' && *place != '\0') ||
|
||||
(oli = strchr(options, optchar)) == NULL) {
|
||||
/*
|
||||
* If the user specified "-" and '-' isn't listed in
|
||||
* options, return -1 (non-option) as per POSIX.
|
||||
* Otherwise, it is an unknown option character (or ':').
|
||||
*/
|
||||
if (optchar == (int)'-' && *place == '\0')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (PRINT_ERROR)
|
||||
warnx(illoptchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADCH);
|
||||
}
|
||||
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||
/* -W long-option */
|
||||
if (*place) /* no space */
|
||||
/* NOTHING */;
|
||||
else if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADARG);
|
||||
} else /* white space */
|
||||
place = nargv[optind];
|
||||
optchar = parse_long_options(nargv, options, long_options,
|
||||
idx, 0);
|
||||
place = EMSG;
|
||||
return (optchar);
|
||||
}
|
||||
if (*++oli != ':') { /* doesn't take argument */
|
||||
if (!*place)
|
||||
++optind;
|
||||
} else { /* takes (optional) argument */
|
||||
optarg = NULL;
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (oli[1] != ':') { /* arg not optional */
|
||||
if (++optind >= nargc) { /* no arg */
|
||||
place = EMSG;
|
||||
if (PRINT_ERROR)
|
||||
warnx(recargchar, optchar);
|
||||
optopt = optchar;
|
||||
return (BADARG);
|
||||
} else
|
||||
optarg = nargv[optind];
|
||||
}
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
/* dump back option letter */
|
||||
return (optchar);
|
||||
}
|
||||
|
||||
#ifdef REPLACE_GETOPT
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*
|
||||
* [eventually this will replace the BSD getopt]
|
||||
*/
|
||||
int
|
||||
getopt(int nargc, char * const *nargv, const char *options)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||
*
|
||||
* Furthermore, since many privileged programs call getopt()
|
||||
* before dropping privileges it makes sense to keep things
|
||||
* as simple (and bug-free) as possible.
|
||||
*/
|
||||
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||
}
|
||||
#endif /* REPLACE_GETOPT */
|
||||
|
||||
/*
|
||||
* getopt_long --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long(int nargc, char * const *nargv, const char *options,
|
||||
const struct option *long_options, int *idx)
|
||||
{
|
||||
|
||||
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||
FLAG_PERMUTE));
|
||||
}
|
||||
|
||||
/*
|
||||
* getopt_long_only --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||
const struct option *long_options, int *idx)
|
||||
{
|
||||
|
||||
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||
FLAG_PERMUTE|FLAG_LONGONLY));
|
||||
}
|
316
third_party/dav1d/tools/dav1d.c
vendored
316
third_party/dav1d/tools/dav1d.c
vendored
@ -1,316 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
10
third_party/dav1d/tools/dav1d.manifest
vendored
10
third_party/dav1d/tools/dav1d.manifest
vendored
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="VideoLAN.dav1d" version="1.0.0.0"/>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
33
third_party/dav1d/tools/dav1d.rc.in
vendored
33
third_party/dav1d/tools/dav1d.rc.in
vendored
@ -1,33 +0,0 @@
|
||||
#define API_VERSION_NUMBER @API_VERSION_MAJOR@,@API_VERSION_MINOR@,@API_VERSION_REVISION@,0
|
||||
#define API_VERSION_NUMBER_STR "@API_VERSION_MAJOR@.@API_VERSION_MINOR@.@API_VERSION_REVISION@"
|
||||
#define PROJECT_VERSION_NUMBER @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_REVISION@,0
|
||||
#define PROJECT_VERSION_NUMBER_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_REVISION@"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
1 RT_MANIFEST "dav1d.manifest"
|
||||
1 VERSIONINFO
|
||||
FILETYPE VFT_APP
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
PRODUCTVERSION PROJECT_VERSION_NUMBER
|
||||
FILEVERSION API_VERSION_NUMBER
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "VideoLAN"
|
||||
VALUE "ProductName", "dav1d"
|
||||
VALUE "ProductVersion", PROJECT_VERSION_NUMBER_STR
|
||||
VALUE "FileVersion", API_VERSION_NUMBER_STR
|
||||
VALUE "FileDescription", "dav1d " PROJECT_VERSION_NUMBER_STR " - AV1 decoder"
|
||||
VALUE "InternalName", "dav1d"
|
||||
VALUE "OriginalFilename", "dav1d.exe"
|
||||
VALUE "LegalCopyright", "Copyright \251 @COPYRIGHT_YEARS@ VideoLAN and dav1d Authors"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
382
third_party/dav1d/tools/dav1d_cli_parse.c
vendored
382
third_party/dav1d/tools/dav1d_cli_parse.c
vendored
@ -1,382 +0,0 @@
|
||||
/*
|
||||
* 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 "cli_config.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "dav1d_cli_parse.h"
|
||||
#include "src/cpu.h"
|
||||
|
||||
static const char short_opts[] = "i:o:vql:s:";
|
||||
|
||||
enum {
|
||||
ARG_DEMUXER = 256,
|
||||
ARG_MUXER,
|
||||
ARG_FRAME_TIMES,
|
||||
ARG_REALTIME,
|
||||
ARG_REALTIME_CACHE,
|
||||
ARG_FRAME_THREADS,
|
||||
ARG_TILE_THREADS,
|
||||
ARG_POSTFILTER_THREADS,
|
||||
ARG_VERIFY,
|
||||
ARG_FILM_GRAIN,
|
||||
ARG_OPPOINT,
|
||||
ARG_ALL_LAYERS,
|
||||
ARG_SIZE_LIMIT,
|
||||
ARG_CPU_MASK,
|
||||
};
|
||||
|
||||
static const struct option long_opts[] = {
|
||||
{ "input", 1, NULL, 'i' },
|
||||
{ "output", 1, NULL, 'o' },
|
||||
{ "quiet", 0, NULL, 'q' },
|
||||
{ "demuxer", 1, NULL, ARG_DEMUXER },
|
||||
{ "muxer", 1, NULL, ARG_MUXER },
|
||||
{ "version", 0, NULL, 'v' },
|
||||
{ "frametimes", 1, NULL, ARG_FRAME_TIMES },
|
||||
{ "limit", 1, NULL, 'l' },
|
||||
{ "skip", 1, NULL, 's' },
|
||||
{ "realtime", 2, NULL, ARG_REALTIME },
|
||||
{ "realtimecache", 1, NULL, ARG_REALTIME_CACHE },
|
||||
{ "framethreads", 1, NULL, ARG_FRAME_THREADS },
|
||||
{ "tilethreads", 1, NULL, ARG_TILE_THREADS },
|
||||
{ "pfthreads", 1, NULL, ARG_POSTFILTER_THREADS },
|
||||
{ "verify", 1, NULL, ARG_VERIFY },
|
||||
{ "filmgrain", 1, NULL, ARG_FILM_GRAIN },
|
||||
{ "oppoint", 1, NULL, ARG_OPPOINT },
|
||||
{ "alllayers", 1, NULL, ARG_ALL_LAYERS },
|
||||
{ "sizelimit", 1, NULL, ARG_SIZE_LIMIT },
|
||||
{ "cpumask", 1, NULL, ARG_CPU_MASK },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
#if HAVE_XXHASH_H
|
||||
#define AVAILABLE_MUXERS "'md5', 'xxh3', 'yuv', 'yuv4mpeg2' or 'null'"
|
||||
#else
|
||||
#define AVAILABLE_MUXERS "'md5', 'yuv', 'yuv4mpeg2' or 'null'"
|
||||
#endif
|
||||
|
||||
#if ARCH_AARCH64 || ARCH_ARM
|
||||
#define ALLOWED_CPU_MASKS " or 'neon'"
|
||||
#elif ARCH_PPC64LE
|
||||
#define ALLOWED_CPU_MASKS " or 'vsx'"
|
||||
#elif ARCH_X86
|
||||
#define ALLOWED_CPU_MASKS \
|
||||
", 'sse2', 'ssse3', 'sse41', 'avx2' or 'avx512icl'"
|
||||
#else
|
||||
#define ALLOWED_CPU_MASKS "not yet implemented for this architecture"
|
||||
#endif
|
||||
|
||||
static void usage(const char *const app, const char *const reason, ...) {
|
||||
if (reason) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, reason);
|
||||
vfprintf(stderr, reason, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n\n");
|
||||
}
|
||||
fprintf(stderr, "Usage: %s [options]\n\n", app);
|
||||
fprintf(stderr, "Supported options:\n"
|
||||
" --input/-i $file: input file\n"
|
||||
" --output/-o $file: output file\n"
|
||||
" --demuxer $name: force demuxer type ('ivf', 'section5' or 'annexb'; default: detect from content)\n"
|
||||
" --muxer $name: force muxer type (" AVAILABLE_MUXERS "; default: detect from extension)\n"
|
||||
" --quiet/-q: disable status messages\n"
|
||||
" --frametimes $file: dump frame times to file\n"
|
||||
" --limit/-l $num: stop decoding after $num frames\n"
|
||||
" --skip/-s $num: skip decoding of the first $num frames\n"
|
||||
" --realtime [$fract]: limit framerate, optional argument to override input framerate\n"
|
||||
" --realtimecache $num: set the size of the cache in realtime mode (default: 0)\n"
|
||||
" --version/-v: print version and exit\n"
|
||||
" --framethreads $num: number of frame threads (default: 1)\n"
|
||||
" --tilethreads $num: number of tile threads (default: 1)\n"
|
||||
" --pfthreads $num: number of postfilter threads (default: 1)\n"
|
||||
" --filmgrain $num: enable film grain application (default: 1, except if muxer is md5 or xxh3)\n"
|
||||
" --oppoint $num: select an operating point of a scalable AV1 bitstream (0 - 31)\n"
|
||||
" --alllayers $num: output all spatial layers of a scalable AV1 bitstream (default: 1)\n"
|
||||
" --sizelimit $num: stop decoding if the frame size exceeds the specified limit\n"
|
||||
" --verify $md5: verify decoded md5. implies --muxer md5, no output\n"
|
||||
" --cpumask $mask: restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void error(const char *const app, const char *const optarg,
|
||||
const int option, const char *const shouldbe)
|
||||
{
|
||||
char optname[256];
|
||||
int n;
|
||||
|
||||
for (n = 0; long_opts[n].name; n++)
|
||||
if (long_opts[n].val == option)
|
||||
break;
|
||||
assert(long_opts[n].name);
|
||||
if (long_opts[n].val < 256) {
|
||||
sprintf(optname, "-%c/--%s", long_opts[n].val, long_opts[n].name);
|
||||
} else {
|
||||
sprintf(optname, "--%s", long_opts[n].name);
|
||||
}
|
||||
|
||||
usage(app, "Invalid argument \"%s\" for option %s; should be %s",
|
||||
optarg, optname, shouldbe);
|
||||
}
|
||||
|
||||
static unsigned parse_unsigned(const char *const optarg, const int option,
|
||||
const char *const app)
|
||||
{
|
||||
char *end;
|
||||
const unsigned res = (unsigned) strtoul(optarg, &end, 0);
|
||||
if (*end || end == optarg) error(app, optarg, option, "an integer");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int parse_optional_fraction(const char *const optarg, const int option,
|
||||
const char *const app, double *value)
|
||||
{
|
||||
if (optarg == NULL) return 0;
|
||||
char *end;
|
||||
*value = strtod(optarg, &end);
|
||||
if (*end == '/' && end != optarg) {
|
||||
const char *optarg2 = end + 1;
|
||||
*value /= strtod(optarg2, &end);
|
||||
if (*end || end == optarg2) error(app, optarg, option, "a fraction");
|
||||
} else if (*end || end == optarg) {
|
||||
error(app, optarg, option, "a fraction");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct EnumParseTable {
|
||||
const char *str;
|
||||
const int val;
|
||||
} EnumParseTable;
|
||||
|
||||
#if ARCH_X86
|
||||
enum CpuMask {
|
||||
X86_CPU_MASK_SSE2 = DAV1D_X86_CPU_FLAG_SSE2,
|
||||
X86_CPU_MASK_SSSE3 = DAV1D_X86_CPU_FLAG_SSSE3 | X86_CPU_MASK_SSE2,
|
||||
X86_CPU_MASK_SSE41 = DAV1D_X86_CPU_FLAG_SSE41 | X86_CPU_MASK_SSSE3,
|
||||
X86_CPU_MASK_AVX2 = DAV1D_X86_CPU_FLAG_AVX2 | X86_CPU_MASK_SSE41,
|
||||
X86_CPU_MASK_AVX512ICL = DAV1D_X86_CPU_FLAG_AVX512ICL | X86_CPU_MASK_AVX2,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const EnumParseTable cpu_mask_tbl[] = {
|
||||
#if ARCH_AARCH64 || ARCH_ARM
|
||||
{ "neon", DAV1D_ARM_CPU_FLAG_NEON },
|
||||
#elif ARCH_PPC64LE
|
||||
{ "vsx", DAV1D_PPC_CPU_FLAG_VSX },
|
||||
#elif ARCH_X86
|
||||
{ "sse2", X86_CPU_MASK_SSE2 },
|
||||
{ "ssse3", X86_CPU_MASK_SSSE3 },
|
||||
{ "sse41", X86_CPU_MASK_SSE41 },
|
||||
{ "avx2", X86_CPU_MASK_AVX2 },
|
||||
{ "avx512icl", X86_CPU_MASK_AVX512ICL },
|
||||
#endif
|
||||
{ "none", 0 },
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(n) (sizeof(n)/sizeof(*(n)))
|
||||
|
||||
static unsigned parse_enum(char *optarg, const EnumParseTable *const tbl,
|
||||
const int tbl_sz, const int option, const char *app)
|
||||
{
|
||||
char str[1024];
|
||||
|
||||
strcpy(str, "any of ");
|
||||
for (int n = 0; n < tbl_sz; n++) {
|
||||
if (!strcmp(tbl[n].str, optarg))
|
||||
return tbl[n].val;
|
||||
|
||||
if (n) {
|
||||
if (n < tbl_sz - 1)
|
||||
strcat(str, ", ");
|
||||
else
|
||||
strcat(str, " or ");
|
||||
}
|
||||
strcat(str, tbl[n].str);
|
||||
}
|
||||
|
||||
char *end;
|
||||
unsigned res;
|
||||
if (!strncmp(optarg, "0x", 2)) {
|
||||
res = (unsigned) strtoul(&optarg[2], &end, 16);
|
||||
} else {
|
||||
res = (unsigned) strtoul(optarg, &end, 0);
|
||||
}
|
||||
|
||||
if (*end || end == optarg) {
|
||||
strcat(str, ", a hexadecimal (starting with 0x), or an integer");
|
||||
error(app, optarg, option, str);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void parse(const int argc, char *const *const argv,
|
||||
CLISettings *const cli_settings, Dav1dSettings *const lib_settings)
|
||||
{
|
||||
int o;
|
||||
|
||||
memset(cli_settings, 0, sizeof(*cli_settings));
|
||||
dav1d_default_settings(lib_settings);
|
||||
int grain_specified = 0;
|
||||
|
||||
while ((o = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||
switch (o) {
|
||||
case 'o':
|
||||
cli_settings->outputfile = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
cli_settings->inputfile = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
cli_settings->quiet = 1;
|
||||
break;
|
||||
case 'l':
|
||||
cli_settings->limit = parse_unsigned(optarg, 'l', argv[0]);
|
||||
break;
|
||||
case 's':
|
||||
cli_settings->skip = parse_unsigned(optarg, 's', argv[0]);
|
||||
break;
|
||||
case ARG_DEMUXER:
|
||||
cli_settings->demuxer = optarg;
|
||||
break;
|
||||
case ARG_MUXER:
|
||||
cli_settings->muxer = optarg;
|
||||
break;
|
||||
case ARG_FRAME_TIMES:
|
||||
cli_settings->frametimes = optarg;
|
||||
break;
|
||||
case ARG_REALTIME:
|
||||
// workaround to parse an optional argument of the form `--a b`
|
||||
// (getopt only allows `--a=b`)
|
||||
if (optarg == NULL && optind < argc && argv[optind] != NULL &&
|
||||
argv[optind][0] != '-')
|
||||
{
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
cli_settings->realtime = 1 + parse_optional_fraction(optarg,
|
||||
ARG_REALTIME, argv[0], &cli_settings->realtime_fps);
|
||||
break;
|
||||
case ARG_REALTIME_CACHE:
|
||||
cli_settings->realtime_cache =
|
||||
parse_unsigned(optarg, ARG_REALTIME_CACHE, argv[0]);
|
||||
break;
|
||||
case ARG_FRAME_THREADS:
|
||||
lib_settings->n_frame_threads =
|
||||
parse_unsigned(optarg, ARG_FRAME_THREADS, argv[0]);
|
||||
break;
|
||||
case ARG_TILE_THREADS:
|
||||
lib_settings->n_tile_threads =
|
||||
parse_unsigned(optarg, ARG_TILE_THREADS, argv[0]);
|
||||
break;
|
||||
case ARG_POSTFILTER_THREADS:
|
||||
lib_settings->n_postfilter_threads =
|
||||
parse_unsigned(optarg, ARG_POSTFILTER_THREADS, argv[0]);
|
||||
break;
|
||||
case ARG_VERIFY:
|
||||
cli_settings->verify = optarg;
|
||||
break;
|
||||
case ARG_FILM_GRAIN:
|
||||
lib_settings->apply_grain =
|
||||
!!parse_unsigned(optarg, ARG_FILM_GRAIN, argv[0]);
|
||||
grain_specified = 1;
|
||||
break;
|
||||
case ARG_OPPOINT:
|
||||
lib_settings->operating_point =
|
||||
parse_unsigned(optarg, ARG_OPPOINT, argv[0]);
|
||||
break;
|
||||
case ARG_ALL_LAYERS:
|
||||
lib_settings->all_layers =
|
||||
!!parse_unsigned(optarg, ARG_ALL_LAYERS, argv[0]);
|
||||
break;
|
||||
case ARG_SIZE_LIMIT: {
|
||||
char *arg = optarg, *end;
|
||||
uint64_t res = strtoul(arg, &end, 0);
|
||||
if (*end == 'x') // NxM
|
||||
res *= strtoul((arg = end + 1), &end, 0);
|
||||
if (*end || end == arg || res >= UINT_MAX)
|
||||
error(argv[0], optarg, ARG_SIZE_LIMIT, "an integer or dimension");
|
||||
lib_settings->frame_size_limit = (unsigned) res;
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
fprintf(stderr, "%s\n", dav1d_version());
|
||||
exit(0);
|
||||
case ARG_CPU_MASK:
|
||||
dav1d_set_cpu_flags_mask(parse_enum(optarg, cpu_mask_tbl, ARRAY_SIZE(cpu_mask_tbl),
|
||||
ARG_CPU_MASK, argv[0]));
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
usage(argv[0], "Extra/unused arguments found, e.g. '%s'\n", argv[optind]);
|
||||
if (cli_settings->verify) {
|
||||
if (cli_settings->outputfile)
|
||||
usage(argv[0], "Verification (--verify) requires output file (-o/--output) to not set");
|
||||
if (cli_settings->muxer && strcmp(cli_settings->muxer, "md5") &&
|
||||
strcmp(cli_settings->muxer, "xxh3"))
|
||||
{
|
||||
usage(argv[0], "Verification (--verify) requires a checksum muxer (md5 or xxh3)");
|
||||
}
|
||||
|
||||
cli_settings->outputfile = "-";
|
||||
if (!cli_settings->muxer)
|
||||
cli_settings->muxer = "md5";
|
||||
}
|
||||
|
||||
if (!grain_specified && cli_settings->muxer &&
|
||||
(!strcmp(cli_settings->muxer, "md5") ||
|
||||
!strcmp(cli_settings->muxer, "xxh3")))
|
||||
{
|
||||
lib_settings->apply_grain = 0;
|
||||
}
|
||||
|
||||
if (!cli_settings->inputfile)
|
||||
usage(argv[0], "Input file (-i/--input) is required");
|
||||
if ((!cli_settings->muxer || strcmp(cli_settings->muxer, "null")) &&
|
||||
!cli_settings->outputfile)
|
||||
{
|
||||
usage(argv[0], "Output file (-o/--output) is required");
|
||||
}
|
||||
}
|
54
third_party/dav1d/tools/dav1d_cli_parse.h
vendored
54
third_party/dav1d/tools/dav1d_cli_parse.h
vendored
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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_CLI_PARSE_H
|
||||
#define DAV1D_CLI_PARSE_H
|
||||
|
||||
#include "dav1d/dav1d.h"
|
||||
|
||||
typedef struct {
|
||||
const char *outputfile;
|
||||
const char *inputfile;
|
||||
const char *demuxer;
|
||||
const char *muxer;
|
||||
const char *frametimes;
|
||||
const char *verify;
|
||||
unsigned limit, skip;
|
||||
int quiet;
|
||||
enum {
|
||||
REALTIME_DISABLE = 0,
|
||||
REALTIME_INPUT,
|
||||
REALTIME_CUSTOM,
|
||||
} realtime;
|
||||
double realtime_fps;
|
||||
unsigned realtime_cache;
|
||||
} CLISettings;
|
||||
|
||||
void parse(const int argc, char *const *const argv,
|
||||
CLISettings *const cli_settings, Dav1dSettings *const lib_settings);
|
||||
|
||||
#endif /* DAV1D_CLI_PARSE_H */
|
196
third_party/dav1d/tools/input/annexb.c
vendored
196
third_party/dav1d/tools/input/annexb.c
vendored
@ -1,196 +0,0 @@
|
||||
/*
|
||||
* 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,
|
||||
.seek = NULL,
|
||||
.close = annexb_close,
|
||||
};
|
46
third_party/dav1d/tools/input/demuxer.h
vendored
46
third_party/dav1d/tools/input/demuxer.h
vendored
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
int (*seek)(DemuxerPriv *ctx, uint64_t pts);
|
||||
void (*close)(DemuxerPriv *ctx);
|
||||
} Demuxer;
|
||||
|
||||
#endif /* DAV1D_INPUT_DEMUXER_H */
|
138
third_party/dav1d/tools/input/input.c
vendored
138
third_party/dav1d/tools/input/input.c
vendored
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
int input_seek(DemuxerContext *const ctx, const uint64_t pts) {
|
||||
return ctx->impl->seek ? ctx->impl->seek(ctx->data, pts) : -1;
|
||||
}
|
||||
|
||||
void input_close(DemuxerContext *const ctx) {
|
||||
ctx->impl->close(ctx->data);
|
||||
free(ctx);
|
||||
}
|
42
third_party/dav1d/tools/input/input.h
vendored
42
third_party/dav1d/tools/input/input.h
vendored
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
int input_seek(DemuxerContext *ctx, uint64_t pts);
|
||||
void input_close(DemuxerContext *ctx);
|
||||
|
||||
#endif /* DAV1D_INPUT_INPUT_H */
|
203
third_party/dav1d/tools/input/ivf.c
vendored
203
third_party/dav1d/tools/input/ivf.c
vendored
@ -1,203 +0,0 @@
|
||||
/*
|
||||
* 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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "input/demuxer.h"
|
||||
|
||||
typedef struct DemuxerPriv {
|
||||
FILE *f;
|
||||
int broken;
|
||||
double timebase;
|
||||
uint64_t last_ts;
|
||||
uint64_t step;
|
||||
} 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])
|
||||
{
|
||||
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 (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[8];
|
||||
c->broken = 0;
|
||||
for (*num_frames = 0;; (*num_frames)++) {
|
||||
if (fread(data, 4, 1, c->f) != 1) break; // EOF
|
||||
size_t sz = rl32(data);
|
||||
if (fread(data, 8, 1, c->f) != 1) break; // EOF
|
||||
const uint64_t ts = rl64(data);
|
||||
if (*num_frames && ts <= c->last_ts)
|
||||
c->broken = 1;
|
||||
c->last_ts = ts;
|
||||
fseeko(c->f, sz, 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;
|
||||
}
|
||||
c->timebase = (double)timebase[0] / timebase[1];
|
||||
c->step = duration / *num_frames;
|
||||
|
||||
fseeko(c->f, 32, SEEK_SET);
|
||||
c->last_ts = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ivf_read_header(IvfInputContext *const c, ptrdiff_t *const sz,
|
||||
int64_t *const off_, uint64_t *const ts)
|
||||
{
|
||||
uint8_t data[8];
|
||||
int64_t const off = ftello(c->f);
|
||||
if (off_) *off_ = off;
|
||||
if (fread(data, 4, 1, c->f) != 1) return -1; // EOF
|
||||
*sz = rl32(data);
|
||||
if (!c->broken) {
|
||||
if (fread(data, 8, 1, c->f) != 1) return -1;
|
||||
*ts = rl64(data);
|
||||
} else {
|
||||
if (fseeko(c->f, 8, SEEK_CUR)) return -1;
|
||||
*ts = off > 32 ? c->last_ts + c->step : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ivf_read(IvfInputContext *const c, Dav1dData *const buf) {
|
||||
uint8_t *ptr;
|
||||
ptrdiff_t sz;
|
||||
int64_t off;
|
||||
uint64_t ts;
|
||||
if (ivf_read_header(c, &sz, &off, &ts)) return -1;
|
||||
if (!(ptr = dav1d_data_create(buf, sz))) return -1;
|
||||
if (fread(ptr, sz, 1, c->f) != 1) {
|
||||
fprintf(stderr, "Failed to read frame data: %s\n", strerror(errno));
|
||||
dav1d_data_unref(buf);
|
||||
return -1;
|
||||
}
|
||||
buf->m.offset = off;
|
||||
buf->m.timestamp = ts;
|
||||
c->last_ts = ts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ivf_seek(IvfInputContext *const c, const uint64_t pts) {
|
||||
uint64_t cur;
|
||||
const uint64_t ts = llround((pts * c->timebase) / 1000000000.0);
|
||||
if (ts <= c->last_ts)
|
||||
if (fseeko(c->f, 32, SEEK_SET)) goto error;
|
||||
while (1) {
|
||||
ptrdiff_t sz;
|
||||
if (ivf_read_header(c, &sz, NULL, &cur)) goto error;
|
||||
if (cur >= ts) break;
|
||||
if (fseeko(c->f, sz, SEEK_CUR)) goto error;
|
||||
c->last_ts = cur;
|
||||
}
|
||||
if (fseeko(c->f, -12, SEEK_CUR)) goto error;
|
||||
return 0;
|
||||
error:
|
||||
fprintf(stderr, "Failed to seek: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
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,
|
||||
.seek = ivf_seek,
|
||||
.close = ivf_close,
|
||||
};
|
109
third_party/dav1d/tools/input/parse.h
vendored
109
third_party/dav1d/tools/input/parse.h
vendored
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
186
third_party/dav1d/tools/input/section5.c
vendored
186
third_party/dav1d/tools/input/section5.c
vendored
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* 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,
|
||||
.seek = NULL,
|
||||
.close = section5_close,
|
||||
};
|
123
third_party/dav1d/tools/meson.build
vendored
123
third_party/dav1d/tools/meson.build
vendored
@ -1,123 +0,0 @@
|
||||
# Copyright © 2018, VideoLAN and dav1d authors
|
||||
# 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.
|
||||
|
||||
# Common source files used by tools and examples
|
||||
|
||||
dav1d_input_sources = files(
|
||||
'input/input.c',
|
||||
'input/annexb.c',
|
||||
'input/ivf.c',
|
||||
'input/section5.c',
|
||||
)
|
||||
|
||||
dav1d_output_sources = files(
|
||||
'output/md5.c',
|
||||
'output/null.c',
|
||||
'output/output.c',
|
||||
'output/y4m2.c',
|
||||
'output/yuv.c',
|
||||
)
|
||||
|
||||
# hacky check for xxhash.h to allow copying it to tools/output
|
||||
if not get_option('xxhash_muxer').disabled()
|
||||
xxhash_include = '-I' + meson.current_source_dir() / 'output'
|
||||
if cc.has_header_symbol('xxhash.h', 'XXH3_createState', args : xxhash_include)
|
||||
dav1d_output_sources += 'output/xxhash.c'
|
||||
xxh3_found = true
|
||||
elif get_option('xxhash_muxer').enabled()
|
||||
# manual error since 'required' kw arg in has_header_symbol() was only added in meson 0.50
|
||||
error( 'C symbol XXH3_createState not found in header xxhash.h')
|
||||
endif
|
||||
endif
|
||||
|
||||
dav1d_input_objs = static_library('dav1d_input',
|
||||
dav1d_input_sources,
|
||||
|
||||
include_directories : dav1d_inc_dirs,
|
||||
install : false,
|
||||
build_by_default : false,
|
||||
)
|
||||
|
||||
dav1d_output_objs = static_library('dav1d_output',
|
||||
dav1d_output_sources,
|
||||
|
||||
include_directories : dav1d_inc_dirs,
|
||||
install : false,
|
||||
build_by_default : false,
|
||||
)
|
||||
|
||||
|
||||
# Leave subdir if tools are disabled
|
||||
if not get_option('enable_tools')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Build definition for the dav1d tools
|
||||
#
|
||||
|
||||
# Configuratin data for cli_config.h
|
||||
cli_cdata = configuration_data()
|
||||
|
||||
cli_cdata.set10('HAVE_XXHASH_H', get_variable('xxh3_found', false))
|
||||
|
||||
cli_config_h_target = configure_file(output: 'cli_config.h', configuration: cli_cdata)
|
||||
|
||||
# dav1d cli tool sources
|
||||
dav1d_sources = files(
|
||||
'dav1d.c',
|
||||
'dav1d_cli_parse.c',
|
||||
)
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
rc_file = configure_file(
|
||||
input : 'dav1d.rc.in',
|
||||
output : 'dav1d.rc',
|
||||
configuration : rc_data
|
||||
)
|
||||
|
||||
dav1d_rc_obj = winmod.compile_resources(rc_file,
|
||||
depend_files : files('dav1d.manifest'),
|
||||
include_directories : include_directories('.')
|
||||
)
|
||||
else
|
||||
dav1d_rc_obj = []
|
||||
endif
|
||||
|
||||
dav1d = executable('dav1d',
|
||||
dav1d_sources,
|
||||
dav1d_rc_obj,
|
||||
rev_target, cli_config_h_target,
|
||||
|
||||
link_with : [libdav1d, dav1d_input_objs, dav1d_output_objs],
|
||||
include_directories : [dav1d_inc_dirs],
|
||||
dependencies : [
|
||||
getopt_dependency,
|
||||
thread_dependency,
|
||||
rt_dependency,
|
||||
libm_dependency,
|
||||
],
|
||||
install : true,
|
||||
)
|
315
third_party/dav1d/tools/output/md5.c
vendored
315
third_party/dav1d/tools/output/md5.c
vendored
@ -1,315 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/stat.h>
|
||||
|
||||
#include "common/intops.h"
|
||||
|
||||
#include "output/muxer.h"
|
||||
|
||||
static const uint32_t k[64] = {
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
};
|
||||
|
||||
#if ENDIANNESS_BIG
|
||||
#define NE2LE_32(x) (((x & 0x00ff) << 24) |\
|
||||
((x & 0xff00) << 8) |\
|
||||
((x >> 8) & 0xff00) |\
|
||||
((x >> 24) & 0x00ff))
|
||||
|
||||
#define NE2LE_64(x) (((x & 0x000000ff) << 56) |\
|
||||
((x & 0x0000ff00) << 40) |\
|
||||
((x & 0x00ff0000) << 24) |\
|
||||
((x & 0xff000000) << 8) |\
|
||||
((x >> 8) & 0xff000000) |\
|
||||
((x >> 24) & 0x00ff0000) |\
|
||||
((x >> 40) & 0x0000ff00) |\
|
||||
((x >> 56) & 0x000000ff))
|
||||
|
||||
#else
|
||||
#define NE2LE_32(x) (x)
|
||||
#define NE2LE_64(x) (x)
|
||||
#endif
|
||||
|
||||
typedef struct MuxerPriv {
|
||||
uint32_t abcd[4];
|
||||
union {
|
||||
uint8_t data[64];
|
||||
uint32_t data32[16];
|
||||
};
|
||||
uint64_t len;
|
||||
FILE *f;
|
||||
#if ENDIANNESS_BIG
|
||||
uint8_t *bswap;
|
||||
int bswap_w;
|
||||
#endif
|
||||
} MD5Context;
|
||||
|
||||
static int md5_open(MD5Context *const md5, const char *const file,
|
||||
const Dav1dPictureParameters *const p,
|
||||
const unsigned fps[2])
|
||||
{
|
||||
if (!strcmp(file, "-")) {
|
||||
md5->f = stdout;
|
||||
} else if (!(md5->f = fopen(file, "wb"))) {
|
||||
fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if ENDIANNESS_BIG
|
||||
md5->bswap = NULL;
|
||||
md5->bswap_w = 0;
|
||||
#endif
|
||||
|
||||
md5->abcd[0] = 0x67452301;
|
||||
md5->abcd[1] = 0xefcdab89;
|
||||
md5->abcd[2] = 0x98badcfe;
|
||||
md5->abcd[3] = 0x10325476;
|
||||
md5->len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t leftrotate(const uint32_t x, const int c) {
|
||||
return (x << c) | (x >> (32 - c));
|
||||
}
|
||||
|
||||
#define F(i) do { \
|
||||
a = b + leftrotate(a + ((b & c) | (~b & d)) + k[i + 0] + NE2LE_32(data[i + 0]), 7); \
|
||||
d = a + leftrotate(d + ((a & b) | (~a & c)) + k[i + 1] + NE2LE_32(data[i + 1]), 12); \
|
||||
c = d + leftrotate(c + ((d & a) | (~d & b)) + k[i + 2] + NE2LE_32(data[i + 2]), 17); \
|
||||
b = c + leftrotate(b + ((c & d) | (~c & a)) + k[i + 3] + NE2LE_32(data[i + 3]), 22); \
|
||||
} while (0)
|
||||
|
||||
#define G(i) do { \
|
||||
a = b + leftrotate(a + ((d & b) | (~d & c)) + k[i + 0] + NE2LE_32(data[(i + 1) & 15]), 5); \
|
||||
d = a + leftrotate(d + ((c & a) | (~c & b)) + k[i + 1] + NE2LE_32(data[(i + 6) & 15]), 9); \
|
||||
c = d + leftrotate(c + ((b & d) | (~b & a)) + k[i + 2] + NE2LE_32(data[(i + 11) & 15]), 14); \
|
||||
b = c + leftrotate(b + ((a & c) | (~a & d)) + k[i + 3] + NE2LE_32(data[(i + 0) & 15]), 20); \
|
||||
} while (0)
|
||||
|
||||
#define H(i) do { \
|
||||
a = b + leftrotate(a + (b ^ c ^ d) + k[i + 0] + NE2LE_32(data[( 5 - i) & 15]), 4); \
|
||||
d = a + leftrotate(d + (a ^ b ^ c) + k[i + 1] + NE2LE_32(data[( 8 - i) & 15]), 11); \
|
||||
c = d + leftrotate(c + (d ^ a ^ b) + k[i + 2] + NE2LE_32(data[(11 - i) & 15]), 16); \
|
||||
b = c + leftrotate(b + (c ^ d ^ a) + k[i + 3] + NE2LE_32(data[(14 - i) & 15]), 23); \
|
||||
} while (0)
|
||||
|
||||
#define I(i) do { \
|
||||
a = b + leftrotate(a + (c ^ (b | ~d)) + k[i + 0] + NE2LE_32(data[( 0 - i) & 15]), 6); \
|
||||
d = a + leftrotate(d + (b ^ (a | ~c)) + k[i + 1] + NE2LE_32(data[( 7 - i) & 15]), 10); \
|
||||
c = d + leftrotate(c + (a ^ (d | ~b)) + k[i + 2] + NE2LE_32(data[(14 - i) & 15]), 15); \
|
||||
b = c + leftrotate(b + (d ^ (c | ~a)) + k[i + 3] + NE2LE_32(data[( 5 - i) & 15]), 21); \
|
||||
} while (0)
|
||||
|
||||
static void md5_body(MD5Context *const md5, const uint32_t *const data) {
|
||||
uint32_t a = md5->abcd[0];
|
||||
uint32_t b = md5->abcd[1];
|
||||
uint32_t c = md5->abcd[2];
|
||||
uint32_t d = md5->abcd[3];
|
||||
|
||||
F( 0); F( 4); F( 8); F(12);
|
||||
G(16); G(20); G(24); G(28);
|
||||
H(32); H(36); H(40); H(44);
|
||||
I(48); I(52); I(56); I(60);
|
||||
|
||||
md5->abcd[0] += a;
|
||||
md5->abcd[1] += b;
|
||||
md5->abcd[2] += c;
|
||||
md5->abcd[3] += d;
|
||||
}
|
||||
|
||||
static void md5_update(MD5Context *const md5, const uint8_t *data, unsigned len) {
|
||||
if (!len) return;
|
||||
|
||||
if (md5->len & 63) {
|
||||
const unsigned tmp = umin(len, 64 - (md5->len & 63));
|
||||
|
||||
memcpy(&md5->data[md5->len & 63], data, tmp);
|
||||
len -= tmp;
|
||||
data += tmp;
|
||||
md5->len += tmp;
|
||||
if (!(md5->len & 63))
|
||||
md5_body(md5, md5->data32);
|
||||
}
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(md5->data, data, 64);
|
||||
md5_body(md5, md5->data32);
|
||||
md5->len += 64;
|
||||
data += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(md5->data, data, len);
|
||||
md5->len += len;
|
||||
}
|
||||
}
|
||||
|
||||
static int md5_write(MD5Context *const md5, Dav1dPicture *const p) {
|
||||
const int hbd = p->p.bpc > 8;
|
||||
const int w = p->p.w, h = p->p.h;
|
||||
uint8_t *yptr = p->data[0];
|
||||
|
||||
#if ENDIANNESS_BIG
|
||||
if (hbd && (!md5->bswap || md5->bswap_w < p->p.w)) {
|
||||
free(md5->bswap);
|
||||
md5->bswap_w = 0;
|
||||
md5->bswap = malloc(p->p.w << 1);
|
||||
if (!md5->bswap) return -1;
|
||||
md5->bswap_w = p->p.w;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
#if ENDIANNESS_BIG
|
||||
if (hbd) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
md5->bswap[2 * x + 1] = yptr[2 * x];
|
||||
md5->bswap[2 * x] = yptr[2 * x + 1];
|
||||
}
|
||||
md5_update(md5, md5->bswap, w << hbd);
|
||||
} else
|
||||
#endif
|
||||
md5_update(md5, yptr, w << hbd);
|
||||
yptr += p->stride[0];
|
||||
}
|
||||
|
||||
if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
|
||||
const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int cw = (w + ss_hor) >> ss_hor;
|
||||
const int ch = (h + ss_ver) >> ss_ver;
|
||||
for (int pl = 1; pl <= 2; pl++) {
|
||||
uint8_t *uvptr = p->data[pl];
|
||||
|
||||
for (int y = 0; y < ch; y++) {
|
||||
#if ENDIANNESS_BIG
|
||||
if (hbd) {
|
||||
for (int x = 0; x < cw; x++){
|
||||
md5->bswap[2 * x + 1] = uvptr[2 * x];
|
||||
md5->bswap[2 * x] = uvptr[2 * x + 1];
|
||||
}
|
||||
md5_update(md5, md5->bswap, cw << hbd);
|
||||
} else
|
||||
#endif
|
||||
md5_update(md5, uvptr, cw << hbd);
|
||||
uvptr += p->stride[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dav1d_picture_unref(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void md5_finish(MD5Context *const md5) {
|
||||
static const uint8_t bit[2] = { 0x80, 0x00 };
|
||||
const uint64_t len = NE2LE_64(md5->len << 3);
|
||||
|
||||
md5_update(md5, &bit[0], 1);
|
||||
while ((md5->len & 63) != 56)
|
||||
md5_update(md5, &bit[1], 1);
|
||||
md5_update(md5, (const uint8_t *) &len, 8);
|
||||
}
|
||||
|
||||
static void md5_close(MD5Context *const md5) {
|
||||
md5_finish(md5);
|
||||
for (int i = 0; i < 4; i++)
|
||||
fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
|
||||
md5->abcd[i] & 0xff,
|
||||
(md5->abcd[i] >> 8) & 0xff,
|
||||
(md5->abcd[i] >> 16) & 0xff,
|
||||
md5->abcd[i] >> 24);
|
||||
fprintf(md5->f, "\n");
|
||||
|
||||
#if ENDIANNESS_BIG
|
||||
free(md5->bswap);
|
||||
md5->bswap_w = 0;
|
||||
#endif
|
||||
|
||||
if (md5->f != stdout)
|
||||
fclose(md5->f);
|
||||
}
|
||||
|
||||
static int md5_verify(MD5Context *const md5, const char *md5_str) {
|
||||
md5_finish(md5);
|
||||
|
||||
if (strlen(md5_str) < 32)
|
||||
return -1;
|
||||
|
||||
uint32_t abcd[4] = { 0 };
|
||||
char t[3] = { 0 };
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 32; j += 8) {
|
||||
char *ignore;
|
||||
memcpy(t, md5_str, 2);
|
||||
md5_str += 2;
|
||||
abcd[i] |= (uint32_t) strtoul(t, &ignore, 16) << j;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENDIANNESS_BIG
|
||||
free(md5->bswap);
|
||||
md5->bswap_w = 0;
|
||||
#endif
|
||||
|
||||
return !!memcmp(abcd, md5->abcd, sizeof(abcd));
|
||||
}
|
||||
|
||||
const Muxer md5_muxer = {
|
||||
.priv_data_size = sizeof(MD5Context),
|
||||
.name = "md5",
|
||||
.extension = "md5",
|
||||
.write_header = md5_open,
|
||||
.write_picture = md5_write,
|
||||
.write_trailer = md5_close,
|
||||
.verify = md5_verify,
|
||||
};
|
52
third_party/dav1d/tools/output/muxer.h
vendored
52
third_party/dav1d/tools/output/muxer.h
vendored
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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_OUTPUT_MUXER_H
|
||||
#define DAV1D_OUTPUT_MUXER_H
|
||||
|
||||
#include "picture.h"
|
||||
|
||||
typedef struct MuxerPriv MuxerPriv;
|
||||
typedef struct Muxer {
|
||||
int priv_data_size;
|
||||
const char *name;
|
||||
const char *extension;
|
||||
int (*write_header)(MuxerPriv *ctx, const char *filename,
|
||||
const Dav1dPictureParameters *p, const unsigned fps[2]);
|
||||
int (*write_picture)(MuxerPriv *ctx, Dav1dPicture *p);
|
||||
void (*write_trailer)(MuxerPriv *ctx);
|
||||
/**
|
||||
* Verifies the muxed data (for example in the md5 muxer). Replaces write_trailer.
|
||||
*
|
||||
* @param hash_string Muxer specific reference value.
|
||||
*
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int (*verify)(MuxerPriv *ctx, const char *hash_string);
|
||||
} Muxer;
|
||||
|
||||
#endif /* DAV1D_OUTPUT_MUXER_H */
|
44
third_party/dav1d/tools/output/null.c
vendored
44
third_party/dav1d/tools/output/null.c
vendored
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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 "output/muxer.h"
|
||||
|
||||
typedef struct MuxerPriv NullOutputContext;
|
||||
|
||||
static int null_write(NullOutputContext *const c, Dav1dPicture *const p) {
|
||||
dav1d_picture_unref(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Muxer null_muxer = {
|
||||
.priv_data_size = 0,
|
||||
.name = "null",
|
||||
.extension = "null",
|
||||
.write_picture = null_write,
|
||||
};
|
150
third_party/dav1d/tools/output/output.c
vendored
150
third_party/dav1d/tools/output/output.c
vendored
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* 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 "cli_config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/attributes.h"
|
||||
|
||||
#include "output/output.h"
|
||||
#include "output/muxer.h"
|
||||
|
||||
struct MuxerContext {
|
||||
MuxerPriv *data;
|
||||
const Muxer *impl;
|
||||
};
|
||||
|
||||
extern const Muxer null_muxer;
|
||||
extern const Muxer md5_muxer;
|
||||
extern const Muxer xxh3_muxer;
|
||||
extern const Muxer yuv_muxer;
|
||||
extern const Muxer y4m2_muxer;
|
||||
static const Muxer *muxers[] = {
|
||||
&null_muxer,
|
||||
&md5_muxer,
|
||||
#if HAVE_XXHASH_H
|
||||
&xxh3_muxer,
|
||||
#endif
|
||||
&yuv_muxer,
|
||||
&y4m2_muxer,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *find_extension(const char *const f) {
|
||||
const size_t l = strlen(f);
|
||||
|
||||
if (l == 0) return NULL;
|
||||
|
||||
const char *const end = &f[l - 1], *step = end;
|
||||
while ((*step >= 'a' && *step <= 'z') ||
|
||||
(*step >= 'A' && *step <= 'Z') ||
|
||||
(*step >= '0' && *step <= '9'))
|
||||
{
|
||||
step--;
|
||||
}
|
||||
|
||||
return (step < end && step > f && *step == '.' && step[-1] != '/') ?
|
||||
&step[1] : NULL;
|
||||
}
|
||||
|
||||
int output_open(MuxerContext **const c_out,
|
||||
const char *const name, const char *const filename,
|
||||
const Dav1dPictureParameters *const p, const unsigned fps[2])
|
||||
{
|
||||
const Muxer *impl;
|
||||
MuxerContext *c;
|
||||
unsigned i;
|
||||
int res;
|
||||
|
||||
if (name) {
|
||||
for (i = 0; muxers[i]; i++) {
|
||||
if (!strcmp(muxers[i]->name, name)) {
|
||||
impl = muxers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!muxers[i]) {
|
||||
fprintf(stderr, "Failed to find muxer named \"%s\"\n", name);
|
||||
return DAV1D_ERR(ENOPROTOOPT);
|
||||
}
|
||||
} else if (!strcmp(filename, "/dev/null")) {
|
||||
impl = muxers[0];
|
||||
} else {
|
||||
const char *const ext = find_extension(filename);
|
||||
if (!ext) {
|
||||
fprintf(stderr, "No extension found for file %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; muxers[i]; i++) {
|
||||
if (!strcmp(muxers[i]->extension, ext)) {
|
||||
impl = muxers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!muxers[i]) {
|
||||
fprintf(stderr, "Failed to find muxer for extension \"%s\"\n", ext);
|
||||
return DAV1D_ERR(ENOPROTOOPT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(c = malloc(sizeof(MuxerContext) + impl->priv_data_size))) {
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
return DAV1D_ERR(ENOMEM);
|
||||
}
|
||||
c->impl = impl;
|
||||
c->data = (MuxerPriv *) &c[1];
|
||||
if (impl->write_header && (res = impl->write_header(c->data, filename, p, fps)) < 0) {
|
||||
free(c);
|
||||
return res;
|
||||
}
|
||||
*c_out = c;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int output_write(MuxerContext *const ctx, Dav1dPicture *const p) {
|
||||
const int res = ctx->impl->write_picture(ctx->data, p);
|
||||
return res < 0 ? res : 0;
|
||||
}
|
||||
|
||||
void output_close(MuxerContext *const ctx) {
|
||||
if (ctx->impl->write_trailer)
|
||||
ctx->impl->write_trailer(ctx->data);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int output_verify(MuxerContext *const ctx, const char *const md5_str) {
|
||||
const int res = ctx->impl->verify ?
|
||||
ctx->impl->verify(ctx->data, md5_str) : 0;
|
||||
free(ctx);
|
||||
return res;
|
||||
}
|
48
third_party/dav1d/tools/output/output.h
vendored
48
third_party/dav1d/tools/output/output.h
vendored
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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_OUTPUT_OUTPUT_H
|
||||
#define DAV1D_OUTPUT_OUTPUT_H
|
||||
|
||||
#include "picture.h"
|
||||
|
||||
typedef struct MuxerContext MuxerContext;
|
||||
|
||||
int output_open(MuxerContext **c, const char *name, const char *filename,
|
||||
const Dav1dPictureParameters *p, const unsigned fps[2]);
|
||||
int output_write(MuxerContext *ctx, Dav1dPicture *pic);
|
||||
void output_close(MuxerContext *ctx);
|
||||
/**
|
||||
* Verifies the muxed data (for example in the md5 muxer). Replaces output_close.
|
||||
*
|
||||
* @param hash_string Muxer specific reference value.
|
||||
*
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int output_verify(MuxerContext *ctx, const char *hash_string);
|
||||
|
||||
#endif /* DAV1D_OUTPUT_OUTPUT_H */
|
142
third_party/dav1d/tools/output/xxhash.c
vendored
142
third_party/dav1d/tools/output/xxhash.c
vendored
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018-2021, VideoLAN and dav1d authors
|
||||
* Copyright © 2018-2021, 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>
|
||||
|
||||
#define XXH_INLINE_ALL
|
||||
#include "xxhash.h"
|
||||
|
||||
#include "output/muxer.h"
|
||||
|
||||
typedef struct MuxerPriv {
|
||||
XXH3_state_t* state;
|
||||
FILE *f;
|
||||
} xxh3Context;
|
||||
|
||||
static int xxh3_open(xxh3Context *const xxh3, const char *const file,
|
||||
const Dav1dPictureParameters *const p,
|
||||
const unsigned fps[2])
|
||||
{
|
||||
xxh3->state = XXH3_createState();
|
||||
if (!xxh3->state) return DAV1D_ERR(ENOMEM);
|
||||
XXH_errorcode err = XXH3_128bits_reset(xxh3->state);
|
||||
if (err != XXH_OK) {
|
||||
XXH3_freeState(xxh3->state);
|
||||
xxh3->state = NULL;
|
||||
return DAV1D_ERR(ENOMEM);
|
||||
}
|
||||
|
||||
if (!strcmp(file, "-")) {
|
||||
xxh3->f = stdout;
|
||||
} else if (!(xxh3->f = fopen(file, "wb"))) {
|
||||
XXH3_freeState(xxh3->state);
|
||||
xxh3->state = NULL;
|
||||
fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xxh3_write(xxh3Context *const xxh3, Dav1dPicture *const p) {
|
||||
const int hbd = p->p.bpc > 8;
|
||||
const int w = p->p.w, h = p->p.h;
|
||||
uint8_t *yptr = p->data[0];
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
XXH3_128bits_update(xxh3->state, yptr, w << hbd);
|
||||
yptr += p->stride[0];
|
||||
}
|
||||
|
||||
if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
|
||||
const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int cw = (w + ss_hor) >> ss_hor;
|
||||
const int ch = (h + ss_ver) >> ss_ver;
|
||||
for (int pl = 1; pl <= 2; pl++) {
|
||||
uint8_t *uvptr = p->data[pl];
|
||||
|
||||
for (int y = 0; y < ch; y++) {
|
||||
XXH3_128bits_update(xxh3->state, uvptr, cw << hbd);
|
||||
uvptr += p->stride[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dav1d_picture_unref(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xxh3_close(xxh3Context *const xxh3) {
|
||||
XXH128_hash_t hash = XXH3_128bits_digest(xxh3->state);
|
||||
XXH3_freeState(xxh3->state);
|
||||
XXH128_canonical_t c;
|
||||
XXH128_canonicalFromHash(&c, hash);
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
fprintf(xxh3->f, "%2.2x", c.digest[i]);
|
||||
fprintf(xxh3->f, "\n");
|
||||
|
||||
if (xxh3->f != stdout)
|
||||
fclose(xxh3->f);
|
||||
}
|
||||
|
||||
static int xxh3_verify(xxh3Context *const xxh3, const char * xxh3_str) {
|
||||
XXH128_hash_t hash = XXH3_128bits_digest(xxh3->state);
|
||||
XXH3_freeState(xxh3->state);
|
||||
|
||||
if (strlen(xxh3_str) < 32)
|
||||
return -1;
|
||||
|
||||
XXH128_canonical_t c;
|
||||
char t[3] = { 0 };
|
||||
for (int i = 0; i < 16; i++) {
|
||||
char *ignore;
|
||||
memcpy(t, xxh3_str, 2);
|
||||
xxh3_str += 2;
|
||||
c.digest[i] = (unsigned char) strtoul(t, &ignore, 16);
|
||||
}
|
||||
XXH128_hash_t verify = XXH128_hashFromCanonical(&c);
|
||||
|
||||
return !XXH128_isEqual(hash, verify);
|
||||
}
|
||||
|
||||
const Muxer xxh3_muxer = {
|
||||
.priv_data_size = sizeof(xxh3Context),
|
||||
.name = "xxh3",
|
||||
.extension = "xxh3",
|
||||
.write_header = xxh3_open,
|
||||
.write_picture = xxh3_write,
|
||||
.write_trailer = xxh3_close,
|
||||
.verify = xxh3_verify,
|
||||
};
|
151
third_party/dav1d/tools/output/y4m2.c
vendored
151
third_party/dav1d/tools/output/y4m2.c
vendored
@ -1,151 +0,0 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "output/muxer.h"
|
||||
|
||||
typedef struct MuxerPriv {
|
||||
FILE *f;
|
||||
int first;
|
||||
unsigned fps[2];
|
||||
} Y4m2OutputContext;
|
||||
|
||||
static int y4m2_open(Y4m2OutputContext *const c, const char *const file,
|
||||
const Dav1dPictureParameters *p, const unsigned fps[2])
|
||||
{
|
||||
if (!strcmp(file, "-")) {
|
||||
c->f = stdout;
|
||||
} else if (!(c->f = fopen(file, "wb"))) {
|
||||
fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
c->first = 1;
|
||||
c->fps[0] = fps[0];
|
||||
c->fps[1] = fps[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_header(Y4m2OutputContext *const c, const Dav1dPicture *const p) {
|
||||
static const char *const ss_names[][3] = {
|
||||
[DAV1D_PIXEL_LAYOUT_I400] = { "mono", "mono10", "mono12" },
|
||||
[DAV1D_PIXEL_LAYOUT_I420] = { NULL, "420p10", "420p12" },
|
||||
[DAV1D_PIXEL_LAYOUT_I422] = { "422", "422p10", "422p12" },
|
||||
[DAV1D_PIXEL_LAYOUT_I444] = { "444", "444p10", "444p12" }
|
||||
};
|
||||
|
||||
static const char *const chr_names_8bpc_i420[] = {
|
||||
[DAV1D_CHR_UNKNOWN] = "420jpeg",
|
||||
[DAV1D_CHR_VERTICAL] = "420mpeg2",
|
||||
[DAV1D_CHR_COLOCATED] = "420"
|
||||
};
|
||||
|
||||
const char *const ss_name =
|
||||
p->p.layout == DAV1D_PIXEL_LAYOUT_I420 && p->p.bpc == 8 ?
|
||||
chr_names_8bpc_i420[p->seq_hdr->chr > 2 ? DAV1D_CHR_UNKNOWN : p->seq_hdr->chr] :
|
||||
ss_names[p->p.layout][p->seq_hdr->hbd];
|
||||
|
||||
const unsigned fw = p->p.w;
|
||||
const unsigned fh = p->p.h;
|
||||
uint64_t aw = (uint64_t)fh * p->frame_hdr->render_width;
|
||||
uint64_t ah = (uint64_t)fw * p->frame_hdr->render_height;
|
||||
uint64_t gcd = ah;
|
||||
for (uint64_t a = aw, b; (b = a % gcd); a = gcd, gcd = b);
|
||||
aw /= gcd;
|
||||
ah /= gcd;
|
||||
|
||||
fprintf(c->f, "YUV4MPEG2 W%u H%u F%u:%u Ip A%"PRIu64":%"PRIu64" C%s\n",
|
||||
fw, fh, c->fps[0], c->fps[1], aw, ah, ss_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int y4m2_write(Y4m2OutputContext *const c, Dav1dPicture *const p) {
|
||||
if (c->first) {
|
||||
c->first = 0;
|
||||
const int res = write_header(c, p);
|
||||
if (res < 0) return res;
|
||||
}
|
||||
fprintf(c->f, "FRAME\n");
|
||||
|
||||
uint8_t *ptr;
|
||||
const int hbd = p->p.bpc > 8;
|
||||
|
||||
ptr = p->data[0];
|
||||
for (int y = 0; y < p->p.h; y++) {
|
||||
if (fwrite(ptr, p->p.w << hbd, 1, c->f) != 1)
|
||||
goto error;
|
||||
ptr += p->stride[0];
|
||||
}
|
||||
|
||||
if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
|
||||
// u/v
|
||||
const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int cw = (p->p.w + ss_hor) >> ss_hor;
|
||||
const int ch = (p->p.h + ss_ver) >> ss_ver;
|
||||
for (int pl = 1; pl <= 2; pl++) {
|
||||
ptr = p->data[pl];
|
||||
for (int y = 0; y < ch; y++) {
|
||||
if (fwrite(ptr, cw << hbd, 1, c->f) != 1)
|
||||
goto error;
|
||||
ptr += p->stride[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dav1d_picture_unref(p);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
dav1d_picture_unref(p);
|
||||
fprintf(stderr, "Failed to write frame data: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void y4m2_close(Y4m2OutputContext *const c) {
|
||||
if (c->f != stdout)
|
||||
fclose(c->f);
|
||||
}
|
||||
|
||||
const Muxer y4m2_muxer = {
|
||||
.priv_data_size = sizeof(Y4m2OutputContext),
|
||||
.name = "yuv4mpeg2",
|
||||
.extension = "y4m",
|
||||
.write_header = y4m2_open,
|
||||
.write_picture = y4m2_write,
|
||||
.write_trailer = y4m2_close,
|
||||
};
|
104
third_party/dav1d/tools/output/yuv.c
vendored
104
third_party/dav1d/tools/output/yuv.c
vendored
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* 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 <sys/stat.h>
|
||||
|
||||
#include "output/muxer.h"
|
||||
|
||||
typedef struct MuxerPriv {
|
||||
FILE *f;
|
||||
} YuvOutputContext;
|
||||
|
||||
static int yuv_open(YuvOutputContext *const c, const char *const file,
|
||||
const Dav1dPictureParameters *const p,
|
||||
const unsigned fps[2])
|
||||
{
|
||||
if (!strcmp(file, "-")) {
|
||||
c->f = stdout;
|
||||
} else if (!(c->f = fopen(file, "wb"))) {
|
||||
fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yuv_write(YuvOutputContext *const c, Dav1dPicture *const p) {
|
||||
uint8_t *ptr;
|
||||
const int hbd = p->p.bpc > 8;
|
||||
|
||||
ptr = p->data[0];
|
||||
for (int y = 0; y < p->p.h; y++) {
|
||||
if (fwrite(ptr, p->p.w << hbd, 1, c->f) != 1)
|
||||
goto error;
|
||||
ptr += p->stride[0];
|
||||
}
|
||||
|
||||
if (p->p.layout != DAV1D_PIXEL_LAYOUT_I400) {
|
||||
// u/v
|
||||
const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
|
||||
const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
|
||||
const int cw = (p->p.w + ss_hor) >> ss_hor;
|
||||
const int ch = (p->p.h + ss_ver) >> ss_ver;
|
||||
for (int pl = 1; pl <= 2; pl++) {
|
||||
ptr = p->data[pl];
|
||||
for (int y = 0; y < ch; y++) {
|
||||
if (fwrite(ptr, cw << hbd, 1, c->f) != 1)
|
||||
goto error;
|
||||
ptr += p->stride[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dav1d_picture_unref(p);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
dav1d_picture_unref(p);
|
||||
fprintf(stderr, "Failed to write frame data: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void yuv_close(YuvOutputContext *const c) {
|
||||
if (c->f != stdout)
|
||||
fclose(c->f);
|
||||
}
|
||||
|
||||
const Muxer yuv_muxer = {
|
||||
.priv_data_size = sizeof(YuvOutputContext),
|
||||
.name = "yuv",
|
||||
.extension = "yuv",
|
||||
.write_header = yuv_open,
|
||||
.write_picture = yuv_write,
|
||||
.write_trailer = yuv_close,
|
||||
};
|
Loading…
Reference in New Issue
Block a user