tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.c (27368B)


      1 /*
      2 * Copyright © 2018, VideoLAN and dav1d authors
      3 * Copyright © 2018, Two Orioles, LLC
      4 * All rights reserved.
      5 *
      6 * Redistribution and use in source and binary forms, with or without
      7 * modification, are permitted provided that the following conditions are met:
      8 *
      9 * 1. Redistributions of source code must retain the above copyright notice, this
     10 *    list of conditions and the following disclaimer.
     11 *
     12 * 2. Redistributions in binary form must reproduce the above copyright notice,
     13 *    this list of conditions and the following disclaimer in the documentation
     14 *    and/or other materials provided with the distribution.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27 
     28 #include "config.h"
     29 #include "vcs_version.h"
     30 
     31 #include <errno.h>
     32 #include <string.h>
     33 
     34 #if defined(__linux__) && HAVE_DLSYM
     35 #include <dlfcn.h>
     36 #endif
     37 
     38 #include "dav1d/dav1d.h"
     39 #include "dav1d/data.h"
     40 
     41 #include "common/validate.h"
     42 
     43 #include "src/cpu.h"
     44 #include "src/fg_apply.h"
     45 #include "src/internal.h"
     46 #include "src/log.h"
     47 #include "src/obu.h"
     48 #include "src/qm.h"
     49 #include "src/ref.h"
     50 #include "src/thread_task.h"
     51 #include "src/wedge.h"
     52 
     53 static COLD void init_internal(void) {
     54    dav1d_init_cpu();
     55    dav1d_init_ii_wedge_masks();
     56    dav1d_init_intra_edge_tree();
     57    dav1d_init_qm_tables();
     58    dav1d_init_thread();
     59 }
     60 
     61 COLD const char *dav1d_version(void) {
     62    return DAV1D_VERSION;
     63 }
     64 
     65 COLD unsigned dav1d_version_api(void) {
     66    return (DAV1D_API_VERSION_MAJOR << 16) |
     67           (DAV1D_API_VERSION_MINOR <<  8) |
     68           (DAV1D_API_VERSION_PATCH <<  0);
     69 }
     70 
     71 COLD void dav1d_default_settings(Dav1dSettings *const s) {
     72    s->n_threads = 0;
     73    s->max_frame_delay = 0;
     74    s->apply_grain = 1;
     75    s->allocator.cookie = NULL;
     76    s->allocator.alloc_picture_callback = dav1d_default_picture_alloc;
     77    s->allocator.release_picture_callback = dav1d_default_picture_release;
     78    s->logger.cookie = NULL;
     79    s->logger.callback = dav1d_log_default_callback;
     80    s->operating_point = 0;
     81    s->all_layers = 1; // just until the tests are adjusted
     82    s->frame_size_limit = 0;
     83    s->strict_std_compliance = 0;
     84    s->output_invisible_frames = 0;
     85    s->inloop_filters = DAV1D_INLOOPFILTER_ALL;
     86    s->decode_frame_type = DAV1D_DECODEFRAMETYPE_ALL;
     87 }
     88 
     89 static void close_internal(Dav1dContext **const c_out, int flush);
     90 
     91 NO_SANITIZE("cfi-icall") // CFI is broken with dlsym()
     92 static COLD size_t get_stack_size_internal(const pthread_attr_t *const thread_attr) {
     93 #if defined(__linux__) && HAVE_DLSYM && defined(__GLIBC__)
     94    /* glibc has an issue where the size of the TLS is subtracted from the stack
     95     * size instead of allocated separately. As a result the specified stack
     96     * size may be insufficient when used in an application with large amounts
     97     * of TLS data. The following is a workaround to compensate for that.
     98     * See https://sourceware.org/bugzilla/show_bug.cgi?id=11787 */
     99    size_t (*const get_minstack)(const pthread_attr_t*) =
    100        dlsym(RTLD_DEFAULT, "__pthread_get_minstack");
    101    if (get_minstack)
    102        return get_minstack(thread_attr) - PTHREAD_STACK_MIN;
    103 #endif
    104    return 0;
    105 }
    106 
    107 static COLD void get_num_threads(Dav1dContext *const c, const Dav1dSettings *const s,
    108                                 unsigned *n_tc, unsigned *n_fc)
    109 {
    110    /* ceil(sqrt(n)) */
    111    static const uint8_t fc_lut[49] = {
    112        1,                                     /*     1 */
    113        2, 2, 2,                               /*  2- 4 */
    114        3, 3, 3, 3, 3,                         /*  5- 9 */
    115        4, 4, 4, 4, 4, 4, 4,                   /* 10-16 */
    116        5, 5, 5, 5, 5, 5, 5, 5, 5,             /* 17-25 */
    117        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,       /* 26-36 */
    118        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 37-49 */
    119    };
    120    *n_tc = s->n_threads ? s->n_threads :
    121        iclip(dav1d_num_logical_processors(c), 1, DAV1D_MAX_THREADS);
    122    *n_fc = s->max_frame_delay ? umin(s->max_frame_delay, *n_tc) :
    123            *n_tc < 50 ? fc_lut[*n_tc - 1] : 8; // min(8, ceil(sqrt(n)))
    124 }
    125 
    126 COLD int dav1d_get_frame_delay(const Dav1dSettings *const s) {
    127    unsigned n_tc, n_fc;
    128    validate_input_or_ret(s != NULL, DAV1D_ERR(EINVAL));
    129    validate_input_or_ret(s->n_threads >= 0 &&
    130                          s->n_threads <= DAV1D_MAX_THREADS, DAV1D_ERR(EINVAL));
    131    validate_input_or_ret(s->max_frame_delay >= 0 &&
    132                          s->max_frame_delay <= DAV1D_MAX_FRAME_DELAY, DAV1D_ERR(EINVAL));
    133 
    134    get_num_threads(NULL, s, &n_tc, &n_fc);
    135    return n_fc;
    136 }
    137 
    138 COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
    139    static pthread_once_t initted = PTHREAD_ONCE_INIT;
    140    pthread_once(&initted, init_internal);
    141 
    142    validate_input_or_ret(c_out != NULL, DAV1D_ERR(EINVAL));
    143    validate_input_or_ret(s != NULL, DAV1D_ERR(EINVAL));
    144    validate_input_or_ret(s->n_threads >= 0 &&
    145                          s->n_threads <= DAV1D_MAX_THREADS, DAV1D_ERR(EINVAL));
    146    validate_input_or_ret(s->max_frame_delay >= 0 &&
    147                          s->max_frame_delay <= DAV1D_MAX_FRAME_DELAY, DAV1D_ERR(EINVAL));
    148    validate_input_or_ret(s->allocator.alloc_picture_callback != NULL,
    149                          DAV1D_ERR(EINVAL));
    150    validate_input_or_ret(s->allocator.release_picture_callback != NULL,
    151                          DAV1D_ERR(EINVAL));
    152    validate_input_or_ret(s->operating_point >= 0 &&
    153                          s->operating_point <= 31, DAV1D_ERR(EINVAL));
    154    validate_input_or_ret(s->decode_frame_type >= DAV1D_DECODEFRAMETYPE_ALL &&
    155                          s->decode_frame_type <= DAV1D_DECODEFRAMETYPE_KEY, DAV1D_ERR(EINVAL));
    156 
    157    pthread_attr_t thread_attr;
    158    if (pthread_attr_init(&thread_attr)) return DAV1D_ERR(ENOMEM);
    159    size_t stack_size = 1024 * 1024 + get_stack_size_internal(&thread_attr);
    160 
    161    pthread_attr_setstacksize(&thread_attr, stack_size);
    162 
    163    Dav1dContext *const c = *c_out = dav1d_alloc_aligned(ALLOC_COMMON_CTX, sizeof(*c), 64);
    164    if (!c) goto error;
    165    memset(c, 0, sizeof(*c));
    166 
    167    c->allocator = s->allocator;
    168    c->logger = s->logger;
    169    c->apply_grain = s->apply_grain;
    170    c->operating_point = s->operating_point;
    171    c->all_layers = s->all_layers;
    172    c->frame_size_limit = s->frame_size_limit;
    173    c->strict_std_compliance = s->strict_std_compliance;
    174    c->output_invisible_frames = s->output_invisible_frames;
    175    c->inloop_filters = s->inloop_filters;
    176    c->decode_frame_type = s->decode_frame_type;
    177 
    178    dav1d_data_props_set_defaults(&c->cached_error_props);
    179 
    180    if (dav1d_mem_pool_init(ALLOC_OBU_HDR, &c->seq_hdr_pool) ||
    181        dav1d_mem_pool_init(ALLOC_OBU_HDR, &c->frame_hdr_pool) ||
    182        dav1d_mem_pool_init(ALLOC_SEGMAP, &c->segmap_pool) ||
    183        dav1d_mem_pool_init(ALLOC_REFMVS, &c->refmvs_pool) ||
    184        dav1d_mem_pool_init(ALLOC_PIC_CTX, &c->pic_ctx_pool) ||
    185        dav1d_mem_pool_init(ALLOC_CDF, &c->cdf_pool))
    186    {
    187        goto error;
    188    }
    189 
    190    if (c->allocator.alloc_picture_callback   == dav1d_default_picture_alloc &&
    191        c->allocator.release_picture_callback == dav1d_default_picture_release)
    192    {
    193        if (c->allocator.cookie) goto error;
    194        if (dav1d_mem_pool_init(ALLOC_PIC, &c->picture_pool)) goto error;
    195        c->allocator.cookie = c->picture_pool;
    196    } else if (c->allocator.alloc_picture_callback   == dav1d_default_picture_alloc ||
    197               c->allocator.release_picture_callback == dav1d_default_picture_release)
    198    {
    199        goto error;
    200    }
    201 
    202    /* On 32-bit systems extremely large frame sizes can cause overflows in
    203     * dav1d_decode_frame() malloc size calculations. Prevent that from occuring
    204     * by enforcing a maximum frame size limit, chosen to roughly correspond to
    205     * the largest size possible to decode without exhausting virtual memory. */
    206    if (sizeof(size_t) < 8 && s->frame_size_limit - 1 >= 8192 * 8192) {
    207        c->frame_size_limit = 8192 * 8192;
    208        if (s->frame_size_limit)
    209            dav1d_log(c, "Frame size limit reduced from %u to %u.\n",
    210                      s->frame_size_limit, c->frame_size_limit);
    211    }
    212 
    213    c->flush = &c->flush_mem;
    214    atomic_init(c->flush, 0);
    215 
    216    get_num_threads(c, s, &c->n_tc, &c->n_fc);
    217 
    218    c->fc = dav1d_alloc_aligned(ALLOC_THREAD_CTX, sizeof(*c->fc) * c->n_fc, 32);
    219    if (!c->fc) goto error;
    220    memset(c->fc, 0, sizeof(*c->fc) * c->n_fc);
    221 
    222    c->tc = dav1d_alloc_aligned(ALLOC_THREAD_CTX, sizeof(*c->tc) * c->n_tc, 64);
    223    if (!c->tc) goto error;
    224    memset(c->tc, 0, sizeof(*c->tc) * c->n_tc);
    225    if (c->n_tc > 1) {
    226        if (pthread_mutex_init(&c->task_thread.lock, NULL)) goto error;
    227        if (pthread_cond_init(&c->task_thread.cond, NULL)) {
    228            pthread_mutex_destroy(&c->task_thread.lock);
    229            goto error;
    230        }
    231        if (pthread_cond_init(&c->task_thread.delayed_fg.cond, NULL)) {
    232            pthread_cond_destroy(&c->task_thread.cond);
    233            pthread_mutex_destroy(&c->task_thread.lock);
    234            goto error;
    235        }
    236        c->task_thread.cur = c->n_fc;
    237        atomic_init(&c->task_thread.reset_task_cur, UINT_MAX);
    238        atomic_init(&c->task_thread.cond_signaled, 0);
    239        c->task_thread.inited = 1;
    240    }
    241 
    242    if (c->n_fc > 1) {
    243        const size_t out_delayed_sz = sizeof(*c->frame_thread.out_delayed) * c->n_fc;
    244        c->frame_thread.out_delayed =
    245            dav1d_malloc(ALLOC_THREAD_CTX, out_delayed_sz);
    246        if (!c->frame_thread.out_delayed) goto error;
    247        memset(c->frame_thread.out_delayed, 0, out_delayed_sz);
    248    }
    249    for (unsigned n = 0; n < c->n_fc; n++) {
    250        Dav1dFrameContext *const f = &c->fc[n];
    251        if (c->n_tc > 1) {
    252            if (pthread_mutex_init(&f->task_thread.lock, NULL)) goto error;
    253            if (pthread_cond_init(&f->task_thread.cond, NULL)) {
    254                pthread_mutex_destroy(&f->task_thread.lock);
    255                goto error;
    256            }
    257            if (pthread_mutex_init(&f->task_thread.pending_tasks.lock, NULL)) {
    258                pthread_cond_destroy(&f->task_thread.cond);
    259                pthread_mutex_destroy(&f->task_thread.lock);
    260                goto error;
    261            }
    262        }
    263        f->c = c;
    264        f->task_thread.ttd = &c->task_thread;
    265        f->lf.last_sharpness = -1;
    266    }
    267 
    268    for (unsigned m = 0; m < c->n_tc; m++) {
    269        Dav1dTaskContext *const t = &c->tc[m];
    270        t->f = &c->fc[0];
    271        t->task_thread.ttd = &c->task_thread;
    272        t->c = c;
    273        memset(t->cf_16bpc, 0, sizeof(t->cf_16bpc));
    274        if (c->n_tc > 1) {
    275            if (pthread_mutex_init(&t->task_thread.td.lock, NULL)) goto error;
    276            if (pthread_cond_init(&t->task_thread.td.cond, NULL)) {
    277                pthread_mutex_destroy(&t->task_thread.td.lock);
    278                goto error;
    279            }
    280            if (pthread_create(&t->task_thread.td.thread, &thread_attr, dav1d_worker_task, t)) {
    281                pthread_cond_destroy(&t->task_thread.td.cond);
    282                pthread_mutex_destroy(&t->task_thread.td.lock);
    283                goto error;
    284            }
    285            t->task_thread.td.inited = 1;
    286        }
    287    }
    288    dav1d_pal_dsp_init(&c->pal_dsp);
    289    dav1d_refmvs_dsp_init(&c->refmvs_dsp);
    290 
    291    pthread_attr_destroy(&thread_attr);
    292 
    293    return 0;
    294 
    295 error:
    296    if (c) close_internal(c_out, 0);
    297    pthread_attr_destroy(&thread_attr);
    298    return DAV1D_ERR(ENOMEM);
    299 }
    300 
    301 static int has_grain(const Dav1dPicture *const pic)
    302 {
    303    const Dav1dFilmGrainData *fgdata = &pic->frame_hdr->film_grain.data;
    304    return fgdata->num_y_points || fgdata->num_uv_points[0] ||
    305           fgdata->num_uv_points[1] || (fgdata->clip_to_restricted_range &&
    306                                        fgdata->chroma_scaling_from_luma);
    307 }
    308 
    309 static int output_image(Dav1dContext *const c, Dav1dPicture *const out)
    310 {
    311    int res = 0;
    312 
    313    Dav1dThreadPicture *const in = (c->all_layers || !c->max_spatial_id)
    314                                   ? &c->out : &c->cache;
    315    if (!c->apply_grain || !has_grain(&in->p)) {
    316        dav1d_picture_move_ref(out, &in->p);
    317        dav1d_thread_picture_unref(in);
    318        goto end;
    319    }
    320 
    321    res = dav1d_apply_grain(c, out, &in->p);
    322    dav1d_thread_picture_unref(in);
    323 end:
    324    if (!c->all_layers && c->max_spatial_id && c->out.p.data[0]) {
    325        dav1d_thread_picture_move_ref(in, &c->out);
    326    }
    327    return res;
    328 }
    329 
    330 static int output_picture_ready(Dav1dContext *const c, const int drain) {
    331    if (c->cached_error) return 1;
    332    if (!c->all_layers && c->max_spatial_id) {
    333        if (c->out.p.data[0] && c->cache.p.data[0]) {
    334            if (c->max_spatial_id == c->cache.p.frame_hdr->spatial_id ||
    335                c->out.flags & PICTURE_FLAG_NEW_TEMPORAL_UNIT)
    336                return 1;
    337            dav1d_thread_picture_unref(&c->cache);
    338            dav1d_thread_picture_move_ref(&c->cache, &c->out);
    339            return 0;
    340        } else if (c->cache.p.data[0] && drain) {
    341            return 1;
    342        } else if (c->out.p.data[0]) {
    343            dav1d_thread_picture_move_ref(&c->cache, &c->out);
    344            return 0;
    345        }
    346    }
    347 
    348    return !!c->out.p.data[0];
    349 }
    350 
    351 static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) {
    352    unsigned drain_count = 0;
    353    int drained = 0;
    354    do {
    355        const unsigned next = c->frame_thread.next;
    356        Dav1dFrameContext *const f = &c->fc[next];
    357        pthread_mutex_lock(&c->task_thread.lock);
    358        while (f->n_tile_data > 0)
    359            pthread_cond_wait(&f->task_thread.cond,
    360                              &f->task_thread.ttd->lock);
    361        Dav1dThreadPicture *const out_delayed =
    362            &c->frame_thread.out_delayed[next];
    363        if (out_delayed->p.data[0] || atomic_load(&f->task_thread.error)) {
    364            unsigned first = atomic_load(&c->task_thread.first);
    365            if (first + 1U < c->n_fc)
    366                atomic_fetch_add(&c->task_thread.first, 1U);
    367            else
    368                atomic_store(&c->task_thread.first, 0);
    369            atomic_compare_exchange_strong(&c->task_thread.reset_task_cur,
    370                                           &first, UINT_MAX);
    371            if (c->task_thread.cur && c->task_thread.cur < c->n_fc)
    372                c->task_thread.cur--;
    373            drained = 1;
    374        } else if (drained) {
    375            pthread_mutex_unlock(&c->task_thread.lock);
    376            break;
    377        }
    378        if (++c->frame_thread.next == c->n_fc)
    379            c->frame_thread.next = 0;
    380        pthread_mutex_unlock(&c->task_thread.lock);
    381        const int error = f->task_thread.retval;
    382        if (error) {
    383            f->task_thread.retval = 0;
    384            dav1d_data_props_copy(&c->cached_error_props, &out_delayed->p.m);
    385            dav1d_thread_picture_unref(out_delayed);
    386            return error;
    387        }
    388        if (out_delayed->p.data[0]) {
    389            const unsigned progress =
    390                atomic_load_explicit(&out_delayed->progress[1],
    391                                     memory_order_relaxed);
    392            if ((out_delayed->visible || c->output_invisible_frames) &&
    393                progress != FRAME_ERROR)
    394            {
    395                dav1d_thread_picture_ref(&c->out, out_delayed);
    396                c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
    397            }
    398            dav1d_thread_picture_unref(out_delayed);
    399            if (output_picture_ready(c, 0))
    400                return output_image(c, out);
    401        }
    402    } while (++drain_count < c->n_fc);
    403 
    404    if (output_picture_ready(c, 1))
    405        return output_image(c, out);
    406 
    407    return DAV1D_ERR(EAGAIN);
    408 }
    409 
    410 static int gen_picture(Dav1dContext *const c)
    411 {
    412    Dav1dData *const in = &c->in;
    413 
    414    if (output_picture_ready(c, 0))
    415        return 0;
    416 
    417    while (in->sz > 0) {
    418        const ptrdiff_t res = dav1d_parse_obus(c, in);
    419        if (res < 0) {
    420            dav1d_data_unref_internal(in);
    421        } else {
    422            assert((size_t)res <= in->sz);
    423            in->sz -= res;
    424            in->data += res;
    425            if (!in->sz) dav1d_data_unref_internal(in);
    426        }
    427        if (output_picture_ready(c, 0))
    428            break;
    429        if (res < 0)
    430            return (int)res;
    431    }
    432 
    433    return 0;
    434 }
    435 
    436 int dav1d_send_data(Dav1dContext *const c, Dav1dData *const in)
    437 {
    438    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
    439    validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
    440 
    441    if (in->data) {
    442        validate_input_or_ret(in->sz > 0 && in->sz <= SIZE_MAX / 2, DAV1D_ERR(EINVAL));
    443        c->drain = 0;
    444    }
    445    if (c->in.data)
    446        return DAV1D_ERR(EAGAIN);
    447    dav1d_data_ref(&c->in, in);
    448 
    449    int res = gen_picture(c);
    450    if (!res)
    451        dav1d_data_unref_internal(in);
    452 
    453    return res;
    454 }
    455 
    456 int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
    457 {
    458    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
    459    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
    460 
    461    const int drain = c->drain;
    462    c->drain = 1;
    463 
    464    int res = gen_picture(c);
    465    if (res < 0)
    466        return res;
    467 
    468    if (c->cached_error) {
    469        const int res = c->cached_error;
    470        c->cached_error = 0;
    471        return res;
    472    }
    473 
    474    if (output_picture_ready(c, c->n_fc == 1))
    475        return output_image(c, out);
    476 
    477    if (c->n_fc > 1 && drain)
    478        return drain_picture(c, out);
    479 
    480    return DAV1D_ERR(EAGAIN);
    481 }
    482 
    483 int dav1d_apply_grain(Dav1dContext *const c, Dav1dPicture *const out,
    484                      const Dav1dPicture *const in)
    485 {
    486    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
    487    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
    488    validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
    489 
    490    if (!has_grain(in)) {
    491        dav1d_picture_ref(out, in);
    492        return 0;
    493    }
    494 
    495    int res = dav1d_picture_alloc_copy(c, out, in->p.w, in);
    496    if (res < 0) goto error;
    497 
    498    if (c->n_tc > 1) {
    499        dav1d_task_delayed_fg(c, out, in);
    500    } else {
    501        switch (out->p.bpc) {
    502 #if CONFIG_8BPC
    503        case 8:
    504            dav1d_apply_grain_8bpc(&c->dsp[0].fg, out, in);
    505            break;
    506 #endif
    507 #if CONFIG_16BPC
    508        case 10:
    509        case 12:
    510            dav1d_apply_grain_16bpc(&c->dsp[(out->p.bpc >> 1) - 4].fg, out, in);
    511            break;
    512 #endif
    513        default: abort();
    514        }
    515    }
    516 
    517    return 0;
    518 
    519 error:
    520    dav1d_picture_unref_internal(out);
    521    return res;
    522 }
    523 
    524 void dav1d_flush(Dav1dContext *const c) {
    525    dav1d_data_unref_internal(&c->in);
    526    if (c->out.p.frame_hdr)
    527        dav1d_thread_picture_unref(&c->out);
    528    if (c->cache.p.frame_hdr)
    529        dav1d_thread_picture_unref(&c->cache);
    530 
    531    c->drain = 0;
    532    c->cached_error = 0;
    533 
    534    for (int i = 0; i < 8; i++) {
    535        if (c->refs[i].p.p.frame_hdr)
    536            dav1d_thread_picture_unref(&c->refs[i].p);
    537        dav1d_ref_dec(&c->refs[i].segmap);
    538        dav1d_ref_dec(&c->refs[i].refmvs);
    539        dav1d_cdf_thread_unref(&c->cdf[i]);
    540    }
    541    c->frame_hdr = NULL;
    542    c->seq_hdr = NULL;
    543    dav1d_ref_dec(&c->seq_hdr_ref);
    544 
    545    c->mastering_display = NULL;
    546    c->content_light = NULL;
    547    c->itut_t35 = NULL;
    548    c->n_itut_t35 = 0;
    549    dav1d_ref_dec(&c->mastering_display_ref);
    550    dav1d_ref_dec(&c->content_light_ref);
    551    dav1d_ref_dec(&c->itut_t35_ref);
    552 
    553    dav1d_data_props_unref_internal(&c->cached_error_props);
    554 
    555    if (c->n_fc == 1 && c->n_tc == 1) return;
    556    atomic_store(c->flush, 1);
    557 
    558    if (c->n_tc > 1) {
    559        pthread_mutex_lock(&c->task_thread.lock);
    560        // stop running tasks in worker threads
    561        for (unsigned i = 0; i < c->n_tc; i++) {
    562            Dav1dTaskContext *const tc = &c->tc[i];
    563            while (!tc->task_thread.flushed) {
    564                pthread_cond_wait(&tc->task_thread.td.cond, &c->task_thread.lock);
    565            }
    566        }
    567        for (unsigned i = 0; i < c->n_fc; i++) {
    568            c->fc[i].task_thread.task_head = NULL;
    569            c->fc[i].task_thread.task_tail = NULL;
    570            c->fc[i].task_thread.task_cur_prev = NULL;
    571            c->fc[i].task_thread.pending_tasks.head = NULL;
    572            c->fc[i].task_thread.pending_tasks.tail = NULL;
    573            atomic_init(&c->fc[i].task_thread.pending_tasks.merge, 0);
    574        }
    575        atomic_init(&c->task_thread.first, 0);
    576        c->task_thread.cur = c->n_fc;
    577        atomic_store(&c->task_thread.reset_task_cur, UINT_MAX);
    578        atomic_store(&c->task_thread.cond_signaled, 0);
    579        pthread_mutex_unlock(&c->task_thread.lock);
    580    }
    581 
    582    if (c->n_fc > 1) {
    583        for (unsigned n = 0, next = c->frame_thread.next; n < c->n_fc; n++, next++) {
    584            if (next == c->n_fc) next = 0;
    585            Dav1dFrameContext *const f = &c->fc[next];
    586            dav1d_decode_frame_exit(f, -1);
    587            f->n_tile_data = 0;
    588            f->task_thread.retval = 0;
    589            f->task_thread.error = 0;
    590            Dav1dThreadPicture *out_delayed = &c->frame_thread.out_delayed[next];
    591            if (out_delayed->p.frame_hdr) {
    592                dav1d_thread_picture_unref(out_delayed);
    593            }
    594        }
    595        c->frame_thread.next = 0;
    596    }
    597    atomic_store(c->flush, 0);
    598 }
    599 
    600 COLD void dav1d_close(Dav1dContext **const c_out) {
    601    validate_input(c_out != NULL);
    602 #if TRACK_HEAP_ALLOCATIONS
    603    dav1d_log_alloc_stats(*c_out);
    604 #endif
    605    close_internal(c_out, 1);
    606 }
    607 
    608 static COLD void close_internal(Dav1dContext **const c_out, int flush) {
    609    Dav1dContext *const c = *c_out;
    610    if (!c) return;
    611 
    612    if (flush) dav1d_flush(c);
    613 
    614    if (c->tc) {
    615        struct TaskThreadData *ttd = &c->task_thread;
    616        if (ttd->inited) {
    617            pthread_mutex_lock(&ttd->lock);
    618            for (unsigned n = 0; n < c->n_tc && c->tc[n].task_thread.td.inited; n++)
    619                c->tc[n].task_thread.die = 1;
    620            pthread_cond_broadcast(&ttd->cond);
    621            pthread_mutex_unlock(&ttd->lock);
    622            for (unsigned n = 0; n < c->n_tc; n++) {
    623                Dav1dTaskContext *const pf = &c->tc[n];
    624                if (!pf->task_thread.td.inited) break;
    625                pthread_join(pf->task_thread.td.thread, NULL);
    626                pthread_cond_destroy(&pf->task_thread.td.cond);
    627                pthread_mutex_destroy(&pf->task_thread.td.lock);
    628            }
    629            pthread_cond_destroy(&ttd->delayed_fg.cond);
    630            pthread_cond_destroy(&ttd->cond);
    631            pthread_mutex_destroy(&ttd->lock);
    632        }
    633        dav1d_free_aligned(c->tc);
    634    }
    635 
    636    for (unsigned n = 0; c->fc && n < c->n_fc; n++) {
    637        Dav1dFrameContext *const f = &c->fc[n];
    638 
    639        // clean-up threading stuff
    640        if (c->n_fc > 1) {
    641            dav1d_free(f->tile_thread.lowest_pixel_mem);
    642            dav1d_free(f->frame_thread.b);
    643            dav1d_free_aligned(f->frame_thread.cbi);
    644            dav1d_free_aligned(f->frame_thread.pal_idx);
    645            dav1d_free_aligned(f->frame_thread.cf);
    646            dav1d_free(f->frame_thread.tile_start_off);
    647            dav1d_free_aligned(f->frame_thread.pal);
    648        }
    649        if (c->n_tc > 1) {
    650            pthread_mutex_destroy(&f->task_thread.pending_tasks.lock);
    651            pthread_cond_destroy(&f->task_thread.cond);
    652            pthread_mutex_destroy(&f->task_thread.lock);
    653        }
    654        dav1d_free(f->frame_thread.frame_progress);
    655        dav1d_free(f->task_thread.tasks);
    656        dav1d_free(f->task_thread.tile_tasks[0]);
    657        dav1d_free_aligned(f->ts);
    658        dav1d_free_aligned(f->ipred_edge[0]);
    659        dav1d_free(f->a);
    660        dav1d_free(f->tile);
    661        dav1d_free(f->lf.mask);
    662        dav1d_free(f->lf.level);
    663        dav1d_free(f->lf.lr_mask);
    664        dav1d_free(f->lf.tx_lpf_right_edge[0]);
    665        dav1d_free(f->lf.start_of_tile_row);
    666        dav1d_free_aligned(f->rf.r);
    667        dav1d_free_aligned(f->lf.cdef_line_buf);
    668        dav1d_free_aligned(f->lf.lr_line_buf);
    669    }
    670    dav1d_free_aligned(c->fc);
    671    if (c->n_fc > 1 && c->frame_thread.out_delayed) {
    672        for (unsigned n = 0; n < c->n_fc; n++)
    673            if (c->frame_thread.out_delayed[n].p.frame_hdr)
    674                dav1d_thread_picture_unref(&c->frame_thread.out_delayed[n]);
    675        dav1d_free(c->frame_thread.out_delayed);
    676    }
    677    for (int n = 0; n < c->n_tile_data; n++)
    678        dav1d_data_unref_internal(&c->tile[n].data);
    679    dav1d_free(c->tile);
    680    for (int n = 0; n < 8; n++) {
    681        dav1d_cdf_thread_unref(&c->cdf[n]);
    682        if (c->refs[n].p.p.frame_hdr)
    683            dav1d_thread_picture_unref(&c->refs[n].p);
    684        dav1d_ref_dec(&c->refs[n].refmvs);
    685        dav1d_ref_dec(&c->refs[n].segmap);
    686    }
    687    dav1d_ref_dec(&c->seq_hdr_ref);
    688    dav1d_ref_dec(&c->frame_hdr_ref);
    689 
    690    dav1d_ref_dec(&c->mastering_display_ref);
    691    dav1d_ref_dec(&c->content_light_ref);
    692    dav1d_ref_dec(&c->itut_t35_ref);
    693 
    694    dav1d_mem_pool_end(c->seq_hdr_pool);
    695    dav1d_mem_pool_end(c->frame_hdr_pool);
    696    dav1d_mem_pool_end(c->segmap_pool);
    697    dav1d_mem_pool_end(c->refmvs_pool);
    698    dav1d_mem_pool_end(c->cdf_pool);
    699    dav1d_mem_pool_end(c->picture_pool);
    700    dav1d_mem_pool_end(c->pic_ctx_pool);
    701 
    702    dav1d_freep_aligned(c_out);
    703 }
    704 
    705 int dav1d_get_event_flags(Dav1dContext *const c, enum Dav1dEventFlags *const flags) {
    706    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
    707    validate_input_or_ret(flags != NULL, DAV1D_ERR(EINVAL));
    708 
    709    *flags = c->event_flags;
    710    c->event_flags = 0;
    711    return 0;
    712 }
    713 
    714 int dav1d_get_decode_error_data_props(Dav1dContext *const c, Dav1dDataProps *const out) {
    715    validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
    716    validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
    717 
    718    dav1d_data_props_unref_internal(out);
    719    *out = c->cached_error_props;
    720    dav1d_data_props_set_defaults(&c->cached_error_props);
    721 
    722    return 0;
    723 }
    724 
    725 void dav1d_picture_unref(Dav1dPicture *const p) {
    726    dav1d_picture_unref_internal(p);
    727 }
    728 
    729 uint8_t *dav1d_data_create(Dav1dData *const buf, const size_t sz) {
    730    return dav1d_data_create_internal(buf, sz);
    731 }
    732 
    733 int dav1d_data_wrap(Dav1dData *const buf, const uint8_t *const ptr,
    734                    const size_t sz,
    735                    void (*const free_callback)(const uint8_t *data,
    736                                                void *user_data),
    737                    void *const user_data)
    738 {
    739    return dav1d_data_wrap_internal(buf, ptr, sz, free_callback, user_data);
    740 }
    741 
    742 int dav1d_data_wrap_user_data(Dav1dData *const buf,
    743                              const uint8_t *const user_data,
    744                              void (*const free_callback)(const uint8_t *user_data,
    745                                                          void *cookie),
    746                              void *const cookie)
    747 {
    748    return dav1d_data_wrap_user_data_internal(buf,
    749                                              user_data,
    750                                              free_callback,
    751                                              cookie);
    752 }
    753 
    754 void dav1d_data_unref(Dav1dData *const buf) {
    755    dav1d_data_unref_internal(buf);
    756 }
    757 
    758 void dav1d_data_props_unref(Dav1dDataProps *const props) {
    759    dav1d_data_props_unref_internal(props);
    760 }