lib.c 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * 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"
Marvin Scholz's avatar
Marvin Scholz committed
29
#include "version.h"
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

#include <errno.h>
#include <string.h>

#include "dav1d/dav1d.h"
#include "dav1d/data.h"

#include "common/mem.h"
#include "common/validate.h"

#include "src/internal.h"
#include "src/obu.h"
#include "src/qm.h"
#include "src/ref.h"
#include "src/thread_task.h"
#include "src/wedge.h"

47
static void init_internal(void) {
48 49 50
    dav1d_init_wedge_masks();
    dav1d_init_interintra_masks();
    dav1d_init_qm_tables();
51 52 53 54 55 56 57 58 59
}

const char *dav1d_version(void) {
    return DAV1D_VERSION;
}

void dav1d_default_settings(Dav1dSettings *const s) {
    s->n_frame_threads = 1;
    s->n_tile_threads = 1;
60 61 62
    s->allocator.cookie = NULL;
    s->allocator.alloc_picture_callback = default_picture_allocator;
    s->allocator.release_picture_callback = default_picture_release;
63 64 65 66 67
}

int dav1d_open(Dav1dContext **const c_out,
               const Dav1dSettings *const s)
{
Henrik Gramner's avatar
Henrik Gramner committed
68 69 70
    static pthread_once_t initted = PTHREAD_ONCE_INIT;
    pthread_once(&initted, init_internal);

71 72 73 74 75 76
    validate_input_or_ret(c_out != NULL, -EINVAL);
    validate_input_or_ret(s != NULL, -EINVAL);
    validate_input_or_ret(s->n_tile_threads >= 1 &&
                          s->n_tile_threads <= 64, -EINVAL);
    validate_input_or_ret(s->n_frame_threads >= 1 &&
                          s->n_frame_threads <= 256, -EINVAL);
77 78 79 80
    validate_input_or_ret(s->allocator.alloc_picture_callback != NULL,
                          -EINVAL);
    validate_input_or_ret(s->allocator.release_picture_callback != NULL,
                          -EINVAL);
81 82 83 84 85

    Dav1dContext *const c = *c_out = dav1d_alloc_aligned(sizeof(*c), 32);
    if (!c) goto error;
    memset(c, 0, sizeof(*c));

86
    c->allocator = s->allocator;
87 88 89 90 91 92 93
    c->n_fc = s->n_frame_threads;
    c->fc = dav1d_alloc_aligned(sizeof(*c->fc) * s->n_frame_threads, 32);
    if (!c->fc) goto error;
    memset(c->fc, 0, sizeof(*c->fc) * s->n_frame_threads);
    if (c->n_fc > 1) {
        c->frame_thread.out_delayed =
            malloc(sizeof(*c->frame_thread.out_delayed) * c->n_fc);
94
        if (!c->frame_thread.out_delayed) goto error;
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
        memset(c->frame_thread.out_delayed, 0,
               sizeof(*c->frame_thread.out_delayed) * c->n_fc);
    }
    for (int n = 0; n < s->n_frame_threads; n++) {
        Dav1dFrameContext *const f = &c->fc[n];
        f->c = c;
        f->lf.last_sharpness = -1;
        f->n_tc = s->n_tile_threads;
        f->tc = dav1d_alloc_aligned(sizeof(*f->tc) * s->n_tile_threads, 32);
        if (!f->tc) goto error;
        memset(f->tc, 0, sizeof(*f->tc) * s->n_tile_threads);
        if (f->n_tc > 1) {
            pthread_mutex_init(&f->tile_thread.lock, NULL);
            pthread_cond_init(&f->tile_thread.cond, NULL);
            pthread_cond_init(&f->tile_thread.icond, NULL);
        }
        for (int m = 0; m < s->n_tile_threads; m++) {
            Dav1dTileContext *const t = &f->tc[m];
            t->f = f;
            t->cf = dav1d_alloc_aligned(32 * 32 * sizeof(int32_t), 32);
            if (!t->cf) goto error;
            t->scratch.mem = dav1d_alloc_aligned(128 * 128 * 8, 32);
            if (!t->scratch.mem) goto error;
            memset(t->cf, 0, 32 * 32 * sizeof(int32_t));
            t->emu_edge =
120
                dav1d_alloc_aligned(320 * (256 + 7) * sizeof(uint16_t), 32);
121 122 123 124 125 126 127 128 129
            if (!t->emu_edge) goto error;
            if (f->n_tc > 1) {
                pthread_mutex_init(&t->tile_thread.td.lock, NULL);
                pthread_cond_init(&t->tile_thread.td.cond, NULL);
                t->tile_thread.fttd = &f->tile_thread;
                pthread_create(&t->tile_thread.td.thread, NULL, dav1d_tile_task, t);
            }
        }
        f->libaom_cm = av1_alloc_ref_mv_common();
130
        if (!f->libaom_cm) goto error;
131 132 133 134 135 136 137 138 139
        if (c->n_fc > 1) {
            pthread_mutex_init(&f->frame_thread.td.lock, NULL);
            pthread_cond_init(&f->frame_thread.td.cond, NULL);
            pthread_create(&f->frame_thread.td.thread, NULL, dav1d_frame_task, f);
        }
    }

    // intra edge tree
    c->intra_edge.root[BL_128X128] = &c->intra_edge.branch_sb128[0].node;
140
    dav1d_init_mode_tree(c->intra_edge.root[BL_128X128], c->intra_edge.tip_sb128, 1);
141
    c->intra_edge.root[BL_64X64] = &c->intra_edge.branch_sb64[0].node;
142
    dav1d_init_mode_tree(c->intra_edge.root[BL_64X64], c->intra_edge.tip_sb64, 0);
143 144 145 146 147 148

    return 0;

error:
    if (c) {
        if (c->fc) {
149
            for (unsigned n = 0; n < c->n_fc; n++)
150
                if (c->fc[n].tc)
151 152
                    dav1d_free_aligned(c->fc[n].tc);
            dav1d_free_aligned(c->fc);
153
        }
154
        dav1d_freep_aligned(c_out);
155 156 157 158 159
    }
    fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
    return -ENOMEM;
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173
int dav1d_send_data(Dav1dContext *const c, Dav1dData *const in)
{
    validate_input_or_ret(c != NULL, -EINVAL);
    validate_input_or_ret(in != NULL, -EINVAL);
    validate_input_or_ret(in->data == NULL || in->sz, -EINVAL);

    if (c->in.data)
        return -EAGAIN;
    dav1d_data_move_ref(&c->in, in);

    return 0;
}

int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
174 175 176 177 178 179
{
    int res;

    validate_input_or_ret(c != NULL, -EINVAL);
    validate_input_or_ret(out != NULL, -EINVAL);

180 181
    Dav1dData *const in = &c->in;
    if (!in->data) {
182 183 184
        if (c->n_fc == 1) return -EAGAIN;

        // flush
185
        unsigned flush_count = 0;
186 187 188 189 190 191 192 193 194 195 196
        do {
            const unsigned next = c->frame_thread.next;
            Dav1dFrameContext *const f = &c->fc[next];

            pthread_mutex_lock(&f->frame_thread.td.lock);
            while (f->n_tile_data > 0)
                pthread_cond_wait(&f->frame_thread.td.cond,
                                  &f->frame_thread.td.lock);
            pthread_mutex_unlock(&f->frame_thread.td.lock);
            Dav1dThreadPicture *const out_delayed =
                &c->frame_thread.out_delayed[next];
197 198
            if (++c->frame_thread.next == c->n_fc)
                c->frame_thread.next = 0;
199
            if (out_delayed->p.data[0]) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
200
                if (out_delayed->visible && !out_delayed->flushed) {
201 202 203 204 205 206 207
                    dav1d_picture_ref(out, &out_delayed->p);
                }
                dav1d_thread_picture_unref(out_delayed);
                if (out->data[0]) {
                    return 0;
                }
                // else continue
208
            }
209 210
        } while (++flush_count < c->n_fc);
        return -EAGAIN;
211 212 213
    }

    while (in->sz > 0) {
214 215
        if ((res = dav1d_parse_obus(c, in)) < 0) {
            dav1d_data_unref(in);
216
            return res;
217
        }
218

219
        assert((size_t)res <= in->sz);
220 221
        in->sz -= res;
        in->data += res;
222
        if (!in->sz) dav1d_data_unref(in);
223
        if (c->out.data[0]) {
224
            dav1d_picture_move_ref(out, &c->out);
225 226 227 228 229
            return 0;
        }
    }

    if (c->out.data[0]) {
230
        dav1d_picture_move_ref(out, &c->out);
231 232 233 234 235 236
        return 0;
    }

    return -EAGAIN;
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
237
void dav1d_flush(Dav1dContext *const c) {
238 239
    dav1d_data_unref(&c->in);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
240 241
    if (c->n_fc == 1) return;

242
    for (unsigned n = 0; n < c->n_fc; n++)
Ronald S. Bultje's avatar
Ronald S. Bultje committed
243 244 245
        c->frame_thread.out_delayed[n].flushed = 1;
}

246 247 248 249 250
void dav1d_close(Dav1dContext **const c_out) {
    validate_input(c_out != NULL);

    Dav1dContext *const c = *c_out;
    if (!c) return;
251

252
    for (unsigned n = 0; n < c->n_fc; n++) {
253 254 255 256 257 258 259 260 261
        Dav1dFrameContext *const f = &c->fc[n];

        // clean-up threading stuff
        if (c->n_fc > 1) {
            pthread_mutex_lock(&f->frame_thread.td.lock);
            f->frame_thread.die = 1;
            pthread_cond_signal(&f->frame_thread.td.cond);
            pthread_mutex_unlock(&f->frame_thread.td.lock);
            pthread_join(f->frame_thread.td.thread, NULL);
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
            // free references from dav1d_submit_frame() usually freed by
            // dav1d_decode_frame
            for (int i = 0; i < 7; i++) {
                if (f->refp[i].p.data[0])
                    dav1d_thread_picture_unref(&f->refp[i]);
                dav1d_ref_dec(&f->ref_mvs_ref[i]);
            }
            dav1d_thread_picture_unref(&f->cur);
            dav1d_cdf_thread_unref(&f->in_cdf);
            if (f->frame_hdr.refresh_context)
                dav1d_cdf_thread_unref(&f->out_cdf);
            dav1d_ref_dec(&f->cur_segmap_ref);
            dav1d_ref_dec(&f->prev_segmap_ref);
            dav1d_ref_dec(&f->mvs_ref);
            for (int i = 0; i < f->n_tile_data; i++)
                dav1d_data_unref(&f->tile[i].data);
278
            freep(&f->frame_thread.b);
279 280
            dav1d_freep_aligned(&f->frame_thread.pal_idx);
            dav1d_freep_aligned(&f->frame_thread.cf);
281 282 283 284 285 286 287 288 289 290 291 292 293
            freep(&f->frame_thread.tile_start_off);
            freep(&f->frame_thread.pal);
            freep(&f->frame_thread.cbi);
            pthread_mutex_destroy(&f->frame_thread.td.lock);
            pthread_cond_destroy(&f->frame_thread.td.cond);
        }
        if (f->n_tc > 1) {
            pthread_mutex_lock(&f->tile_thread.lock);
            for (int m = 0; m < f->n_tc; m++) {
                Dav1dTileContext *const t = &f->tc[m];
                t->tile_thread.die = 1;
            }
            pthread_cond_broadcast(&f->tile_thread.cond);
294
            while (f->tile_thread.available != ~0ULL >> (64 - f->n_tc))
295 296 297 298 299 300 301 302 303 304 305 306 307 308
                pthread_cond_wait(&f->tile_thread.icond,
                                  &f->tile_thread.lock);
            pthread_mutex_unlock(&f->tile_thread.lock);
            for (int m = 0; m < f->n_tc; m++) {
                Dav1dTileContext *const t = &f->tc[m];
                if (f->n_tc > 1) {
                    pthread_join(t->tile_thread.td.thread, NULL);
                    pthread_mutex_destroy(&t->tile_thread.td.lock);
                    pthread_cond_destroy(&t->tile_thread.td.cond);
                }
            }
            pthread_mutex_destroy(&f->tile_thread.lock);
            pthread_cond_destroy(&f->tile_thread.cond);
            pthread_cond_destroy(&f->tile_thread.icond);
309
            freep(&f->tile_thread.task_idx_to_sby_and_tile_idx);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
        }
        for (int m = 0; m < f->n_tc; m++) {
            Dav1dTileContext *const t = &f->tc[m];
            dav1d_free_aligned(t->cf);
            dav1d_free_aligned(t->scratch.mem);
            dav1d_free_aligned(t->emu_edge);
        }
        for (int m = 0; m < f->n_ts; m++) {
            Dav1dTileState *const ts = &f->ts[m];
            pthread_cond_destroy(&ts->tile_thread.cond);
            pthread_mutex_destroy(&ts->tile_thread.lock);
        }
        free(f->ts);
        dav1d_free_aligned(f->tc);
        dav1d_free_aligned(f->ipred_edge[0]);
        free(f->a);
        free(f->lf.mask);
        free(f->lf.level);
        free(f->lf.tx_lpf_right_edge[0]);
        av1_free_ref_mv_common(f->libaom_cm);
        dav1d_free_aligned(f->lf.cdef_line);
        dav1d_free_aligned(f->lf.lr_lpf_line);
    }
    dav1d_free_aligned(c->fc);
334
    dav1d_data_unref(&c->in);
335
    if (c->n_fc > 1) {
336
        for (unsigned n = 0; n < c->n_fc; n++)
337 338 339 340 341 342 343 344
            if (c->frame_thread.out_delayed[n].p.data[0])
                dav1d_thread_picture_unref(&c->frame_thread.out_delayed[n]);
        free(c->frame_thread.out_delayed);
    }
    for (int n = 0; n < c->n_tile_data; n++)
        dav1d_data_unref(&c->tile[n].data);
    for (int n = 0; n < 8; n++) {
        if (c->cdf[n].cdf)
345
            dav1d_cdf_thread_unref(&c->cdf[n]);
346 347
        if (c->refs[n].p.p.data[0])
            dav1d_thread_picture_unref(&c->refs[n].p);
348 349
        dav1d_ref_dec(&c->refs[n].refmvs);
        dav1d_ref_dec(&c->refs[n].segmap);
350
    }
351
    dav1d_freep_aligned(c_out);
352
}