lib.c 15.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

#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"
46
#include "src/film_grain.h"
47

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

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;
61
    s->apply_grain = 1;
62
63
64
    s->allocator.cookie = NULL;
    s->allocator.alloc_picture_callback = default_picture_allocator;
    s->allocator.release_picture_callback = default_picture_release;
65
    s->operating_point = 0;
66
    s->all_layers = 1; // just until the tests are adjusted
67
68
69
70
71
}

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

75
76
77
    validate_input_or_ret(c_out != NULL, -EINVAL);
    validate_input_or_ret(s != NULL, -EINVAL);
    validate_input_or_ret(s->n_tile_threads >= 1 &&
78
                          s->n_tile_threads <= DAV1D_MAX_TILE_THREADS, -EINVAL);
79
    validate_input_or_ret(s->n_frame_threads >= 1 &&
80
                          s->n_frame_threads <= DAV1D_MAX_FRAME_THREADS, -EINVAL);
81
82
83
84
    validate_input_or_ret(s->allocator.alloc_picture_callback != NULL,
                          -EINVAL);
    validate_input_or_ret(s->allocator.release_picture_callback != NULL,
                          -EINVAL);
85
86
    validate_input_or_ret(s->operating_point >= 0 &&
                          s->operating_point <= 31, -EINVAL);
87
88
89
90
91

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

92
    c->allocator = s->allocator;
93
    c->apply_grain = s->apply_grain;
94
    c->operating_point = s->operating_point;
95
    c->all_layers = s->all_layers;
96
97
    c->frame_thread.flush = &c->frame_thread.flush_mem;
    atomic_init(c->frame_thread.flush, 0);
98
99
100
101
102
103
104
    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);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
105
        if (!c->frame_thread.out_delayed) goto error;
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
        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 =
131
                dav1d_alloc_aligned(320 * (256 + 7) * sizeof(uint16_t), 32);
132
133
134
135
136
137
138
139
140
            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();
141
        if (!f->libaom_cm) goto error;
142
143
144
145
146
147
148
149
150
        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;
151
    dav1d_init_mode_tree(c->intra_edge.root[BL_128X128], c->intra_edge.tip_sb128, 1);
152
    c->intra_edge.root[BL_64X64] = &c->intra_edge.branch_sb64[0].node;
153
    dav1d_init_mode_tree(c->intra_edge.root[BL_64X64], c->intra_edge.tip_sb64, 0);
154
155
156
157
158
159

    return 0;

error:
    if (c) {
        if (c->fc) {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
160
            for (unsigned n = 0; n < c->n_fc; n++)
161
                if (c->fc[n].tc)
162
163
                    dav1d_free_aligned(c->fc[n].tc);
            dav1d_free_aligned(c->fc);
164
        }
165
        dav1d_freep_aligned(c_out);
166
167
168
169
170
    }
    fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
    return -ENOMEM;
}

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
static void dummy_free(const uint8_t *const data, void *const user_data) {
    assert(data && !user_data);
}

int dav1d_parse_sequence_header(Dav1dSequenceHeader *const out,
                                const uint8_t *const ptr, const size_t sz)
{
    Dav1dData buf = { 0 };
    int res;

    validate_input_or_ret(out != NULL, -EINVAL);

    Dav1dSettings s;
    dav1d_default_settings(&s);

    Dav1dContext *c;
    res	= dav1d_open(&c, &s);
    if (res < 0) return res;

    if (ptr) {
        res = dav1d_data_wrap(&buf, ptr, sz, dummy_free, NULL);
        if (res < 0) goto error;
    }

    while (buf.sz > 0) {
        res = dav1d_parse_obus(c, &buf, 1);
        if (res < 0) goto error;

        assert((size_t)res <= buf.sz);
        buf.sz -= res;
        buf.data += res;
    }

    if (!c->seq_hdr) {
        res = -EINVAL;
        goto error;
    }

    memcpy(out, c->seq_hdr, sizeof(*out));

    res = 0;
error:
    dav1d_data_unref(&buf);
    dav1d_close(&c);

    return res;
}

James Almer's avatar
James Almer committed
219
220
221
222
223
224
225
226
227
228
229
230
231
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;
}

232
233
234
static int output_image(Dav1dContext *const c, Dav1dPicture *const out,
                        Dav1dPicture *const in)
{
235
    const Dav1dFilmGrainData *fgdata = &in->frame_hdr->film_grain.data;
236
237
238
    int has_grain = fgdata->num_y_points || fgdata->num_uv_points[0] ||
                    fgdata->num_uv_points[1];

239
240
241
    // skip lower spatial layers
    if (c->operating_point_idc && !c->all_layers) {
        const int max_spatial_id = ulog2(c->operating_point_idc >> 8);
242
        if (max_spatial_id > in->frame_hdr->spatial_id) {
243
244
245
246
247
            dav1d_picture_unref(in);
            return 0;
        }
    }

248
249
250
251
252
253
254
    // If there is nothing to be done, skip the allocation/copy
    if (!c->apply_grain || !has_grain) {
        dav1d_picture_move_ref(out, in);
        return 0;
    }

    // Apply film grain to a new copy of the image to avoid corrupting refs
255
    int res = dav1d_picture_alloc_copy(out, in->p.w, in);
256
257
258
259
    if (res < 0)
        return res;

    switch (out->p.bpc) {
260
#if CONFIG_8BPC
261
262
263
    case 8:
        dav1d_apply_grain_8bpc(out, in);
        break;
264
265
#endif
#if CONFIG_10BPC
266
267
268
    case 10:
        dav1d_apply_grain_10bpc(out, in);
        break;
269
#endif
270
    default:
271
        assert(0);
272
273
274
275
276
277
    }

    dav1d_picture_unref(in);
    return 0;
}

James Almer's avatar
James Almer committed
278
int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
279
280
281
282
283
284
{
    int res;

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

James Almer's avatar
James Almer committed
285
286
    Dav1dData *const in = &c->in;
    if (!in->data) {
287
288
289
        if (c->n_fc == 1) return -EAGAIN;

        // flush
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
290
        unsigned flush_count = 0;
291
292
293
294
295
296
297
298
299
300
301
        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];
302
303
            if (++c->frame_thread.next == c->n_fc)
                c->frame_thread.next = 0;
304
            if (out_delayed->p.data[0]) {
305
306
                const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
                                                               memory_order_relaxed);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
307
                if (out_delayed->visible && progress != FRAME_ERROR)
308
                    dav1d_picture_ref(&c->out, &out_delayed->p);
309
                dav1d_thread_picture_unref(out_delayed);
310
311
                if (c->out.data[0])
                    return output_image(c, out, &c->out);
312
            }
313
314
        } while (++flush_count < c->n_fc);
        return -EAGAIN;
315
316
317
    }

    while (in->sz > 0) {
318
        if ((res = dav1d_parse_obus(c, in, 0)) < 0) {
James Almer's avatar
James Almer committed
319
            dav1d_data_unref(in);
320
            return res;
James Almer's avatar
James Almer committed
321
        }
322

323
        assert((size_t)res <= in->sz);
324
325
        in->sz -= res;
        in->data += res;
326
        if (!in->sz) dav1d_data_unref(in);
327
328
        if (c->out.data[0])
            break;
329
330
    }

331
332
    if (c->out.data[0])
        return output_image(c, out, &c->out);
333
334
335
336

    return -EAGAIN;
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
337
void dav1d_flush(Dav1dContext *const c) {
James Almer's avatar
James Almer committed
338
339
    dav1d_data_unref(&c->in);

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

Ronald S. Bultje's avatar
Ronald S. Bultje committed
342
343
    // mark each currently-running frame as flushing, so that we
    // exit out as quickly as the running thread checks this flag
344
    atomic_store(c->frame_thread.flush, 1);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
    for (unsigned n = 0, next = c->frame_thread.next; n < c->n_fc; n++, next++) {
        if (next == c->n_fc) next = 0;
        Dav1dFrameContext *const f = &c->fc[next];
        pthread_mutex_lock(&f->frame_thread.td.lock);
        if (f->n_tile_data > 0) {
            while (f->n_tile_data > 0)
                pthread_cond_wait(&f->frame_thread.td.cond,
                                  &f->frame_thread.td.lock);
            assert(!f->cur.data[0]);
        }
        pthread_mutex_unlock(&f->frame_thread.td.lock);
        Dav1dThreadPicture *const out_delayed = &c->frame_thread.out_delayed[next];
        if (out_delayed->p.data[0])
            dav1d_thread_picture_unref(out_delayed);
    }
360
    atomic_store(c->frame_thread.flush, 0);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
361
362

    c->frame_thread.next = 0;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
363
364
}

365
366
367
368
369
void dav1d_close(Dav1dContext **const c_out) {
    validate_input(c_out != NULL);

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

Ronald S. Bultje's avatar
Ronald S. Bultje committed
371
    dav1d_flush(c);
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
372
    for (unsigned n = 0; n < c->n_fc; n++) {
373
374
375
376
377
378
379
380
381
382
        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);
            freep(&f->frame_thread.b);
383
384
            dav1d_freep_aligned(&f->frame_thread.pal_idx);
            dav1d_freep_aligned(&f->frame_thread.cf);
385
386
387
388
389
390
391
392
393
394
395
396
397
            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);
398
            while (f->tile_thread.available != ~0ULL >> (64 - f->n_tc))
399
400
401
402
403
404
405
406
407
408
409
410
411
412
                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);
413
            freep(&f->tile_thread.task_idx_to_sby_and_tile_idx);
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
        }
        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);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
431
        free(f->lf.lr_mask);
432
433
434
435
436
437
438
        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);
James Almer's avatar
James Almer committed
439
    dav1d_data_unref(&c->in);
440
    if (c->n_fc > 1) {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
441
        for (unsigned n = 0; n < c->n_fc; n++)
442
443
444
445
446
447
448
449
            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)
450
            dav1d_cdf_thread_unref(&c->cdf[n]);
451
452
        if (c->refs[n].p.p.data[0])
            dav1d_thread_picture_unref(&c->refs[n].p);
453
454
        dav1d_ref_dec(&c->refs[n].refmvs);
        dav1d_ref_dec(&c->refs[n].segmap);
455
    }
456
457
458
    dav1d_ref_dec(&c->seq_hdr_ref);
    dav1d_ref_dec(&c->frame_hdr_ref);

459
    dav1d_freep_aligned(c_out);
460
}