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
init_internal(void)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
dav1d_version(void)61 COLD const char *dav1d_version(void) {
62 return DAV1D_VERSION;
63 }
64
dav1d_version_api(void)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
dav1d_default_settings(Dav1dSettings * const s)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()
get_stack_size_internal(const pthread_attr_t * const thread_attr)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
get_num_threads(Dav1dContext * const c,const Dav1dSettings * const s,unsigned * n_tc,unsigned * n_fc)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
dav1d_get_frame_delay(const Dav1dSettings * const s)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
dav1d_open(Dav1dContext ** const c_out,const Dav1dSettings * const s)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
has_grain(const Dav1dPicture * const pic)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
output_image(Dav1dContext * const c,Dav1dPicture * const out)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
output_picture_ready(Dav1dContext * const c,const int drain)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
drain_picture(Dav1dContext * const c,Dav1dPicture * const out)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
gen_picture(Dav1dContext * const c)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
dav1d_send_data(Dav1dContext * const c,Dav1dData * const in)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
dav1d_get_picture(Dav1dContext * const c,Dav1dPicture * const out)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
dav1d_apply_grain(Dav1dContext * const c,Dav1dPicture * const out,const Dav1dPicture * const in)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
dav1d_flush(Dav1dContext * const c)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 // stop running tasks in worker threads
559 if (c->n_tc > 1) {
560 pthread_mutex_lock(&c->task_thread.lock);
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 // wait for threads to complete flushing
583 if (c->n_fc > 1) {
584 for (unsigned n = 0, next = c->frame_thread.next; n < c->n_fc; n++, next++) {
585 if (next == c->n_fc) next = 0;
586 Dav1dFrameContext *const f = &c->fc[next];
587 dav1d_decode_frame_exit(f, -1);
588 f->n_tile_data = 0;
589 f->task_thread.retval = 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
dav1d_close(Dav1dContext ** const c_out)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
close_internal(Dav1dContext ** const c_out,int flush)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
dav1d_get_event_flags(Dav1dContext * const c,enum Dav1dEventFlags * const flags)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
dav1d_get_decode_error_data_props(Dav1dContext * const c,Dav1dDataProps * const out)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
dav1d_picture_unref(Dav1dPicture * const p)725 void dav1d_picture_unref(Dav1dPicture *const p) {
726 dav1d_picture_unref_internal(p);
727 }
728
dav1d_data_create(Dav1dData * const buf,const size_t sz)729 uint8_t *dav1d_data_create(Dav1dData *const buf, const size_t sz) {
730 return dav1d_data_create_internal(buf, sz);
731 }
732
dav1d_data_wrap(Dav1dData * const buf,const uint8_t * const ptr,const size_t sz,void (* const free_callback)(const uint8_t * data,void * user_data),void * const user_data)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
dav1d_data_wrap_user_data(Dav1dData * const buf,const uint8_t * const user_data,void (* const free_callback)(const uint8_t * user_data,void * cookie),void * const cookie)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
dav1d_data_unref(Dav1dData * const buf)754 void dav1d_data_unref(Dav1dData *const buf) {
755 dav1d_data_unref_internal(buf);
756 }
757
dav1d_data_props_unref(Dav1dDataProps * const props)758 void dav1d_data_props_unref(Dav1dDataProps *const props) {
759 dav1d_data_props_unref_internal(props);
760 }
761