• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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__) && defined(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__) && defined(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         dav1d_refmvs_init(&f->rf);
267     }
268 
269     for (unsigned m = 0; m < c->n_tc; m++) {
270         Dav1dTaskContext *const t = &c->tc[m];
271         t->f = &c->fc[0];
272         t->task_thread.ttd = &c->task_thread;
273         t->c = c;
274         memset(t->cf_16bpc, 0, sizeof(t->cf_16bpc));
275         if (c->n_tc > 1) {
276             if (pthread_mutex_init(&t->task_thread.td.lock, NULL)) goto error;
277             if (pthread_cond_init(&t->task_thread.td.cond, NULL)) {
278                 pthread_mutex_destroy(&t->task_thread.td.lock);
279                 goto error;
280             }
281             if (pthread_create(&t->task_thread.td.thread, &thread_attr, dav1d_worker_task, t)) {
282                 pthread_cond_destroy(&t->task_thread.td.cond);
283                 pthread_mutex_destroy(&t->task_thread.td.lock);
284                 goto error;
285             }
286             t->task_thread.td.inited = 1;
287         }
288     }
289     dav1d_pal_dsp_init(&c->pal_dsp);
290     dav1d_refmvs_dsp_init(&c->refmvs_dsp);
291 
292     pthread_attr_destroy(&thread_attr);
293 
294     return 0;
295 
296 error:
297     if (c) close_internal(c_out, 0);
298     pthread_attr_destroy(&thread_attr);
299     return DAV1D_ERR(ENOMEM);
300 }
301 
has_grain(const Dav1dPicture * const pic)302 static int has_grain(const Dav1dPicture *const pic)
303 {
304     const Dav1dFilmGrainData *fgdata = &pic->frame_hdr->film_grain.data;
305     return fgdata->num_y_points || fgdata->num_uv_points[0] ||
306            fgdata->num_uv_points[1] || (fgdata->clip_to_restricted_range &&
307                                         fgdata->chroma_scaling_from_luma);
308 }
309 
output_image(Dav1dContext * const c,Dav1dPicture * const out)310 static int output_image(Dav1dContext *const c, Dav1dPicture *const out)
311 {
312     int res = 0;
313 
314     Dav1dThreadPicture *const in = (c->all_layers || !c->max_spatial_id)
315                                    ? &c->out : &c->cache;
316     if (!c->apply_grain || !has_grain(&in->p)) {
317         dav1d_picture_move_ref(out, &in->p);
318         dav1d_thread_picture_unref(in);
319         goto end;
320     }
321 
322     res = dav1d_apply_grain(c, out, &in->p);
323     dav1d_thread_picture_unref(in);
324 end:
325     if (!c->all_layers && c->max_spatial_id && c->out.p.data[0]) {
326         dav1d_thread_picture_move_ref(in, &c->out);
327     }
328     return res;
329 }
330 
output_picture_ready(Dav1dContext * const c,const int drain)331 static int output_picture_ready(Dav1dContext *const c, const int drain) {
332     if (c->cached_error) return 1;
333     if (!c->all_layers && c->max_spatial_id) {
334         if (c->out.p.data[0] && c->cache.p.data[0]) {
335             if (c->max_spatial_id == c->cache.p.frame_hdr->spatial_id ||
336                 c->out.flags & PICTURE_FLAG_NEW_TEMPORAL_UNIT)
337                 return 1;
338             dav1d_thread_picture_unref(&c->cache);
339             dav1d_thread_picture_move_ref(&c->cache, &c->out);
340             return 0;
341         } else if (c->cache.p.data[0] && drain) {
342             return 1;
343         } else if (c->out.p.data[0]) {
344             dav1d_thread_picture_move_ref(&c->cache, &c->out);
345             return 0;
346         }
347     }
348 
349     return !!c->out.p.data[0];
350 }
351 
drain_picture(Dav1dContext * const c,Dav1dPicture * const out)352 static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) {
353     unsigned drain_count = 0;
354     int drained = 0;
355     do {
356         const unsigned next = c->frame_thread.next;
357         Dav1dFrameContext *const f = &c->fc[next];
358         pthread_mutex_lock(&c->task_thread.lock);
359         while (f->n_tile_data > 0)
360             pthread_cond_wait(&f->task_thread.cond,
361                               &f->task_thread.ttd->lock);
362         Dav1dThreadPicture *const out_delayed =
363             &c->frame_thread.out_delayed[next];
364         if (out_delayed->p.data[0] || atomic_load(&f->task_thread.error)) {
365             unsigned first = atomic_load(&c->task_thread.first);
366             if (first + 1U < c->n_fc)
367                 atomic_fetch_add(&c->task_thread.first, 1U);
368             else
369                 atomic_store(&c->task_thread.first, 0);
370             atomic_compare_exchange_strong(&c->task_thread.reset_task_cur,
371                                            &first, UINT_MAX);
372             if (c->task_thread.cur && c->task_thread.cur < c->n_fc)
373                 c->task_thread.cur--;
374             drained = 1;
375         } else if (drained) {
376             pthread_mutex_unlock(&c->task_thread.lock);
377             break;
378         }
379         if (++c->frame_thread.next == c->n_fc)
380             c->frame_thread.next = 0;
381         pthread_mutex_unlock(&c->task_thread.lock);
382         const int error = f->task_thread.retval;
383         if (error) {
384             f->task_thread.retval = 0;
385             dav1d_data_props_copy(&c->cached_error_props, &out_delayed->p.m);
386             dav1d_thread_picture_unref(out_delayed);
387             return error;
388         }
389         if (out_delayed->p.data[0]) {
390             const unsigned progress =
391                 atomic_load_explicit(&out_delayed->progress[1],
392                                      memory_order_relaxed);
393             if ((out_delayed->visible || c->output_invisible_frames) &&
394                 progress != FRAME_ERROR)
395             {
396                 dav1d_thread_picture_ref(&c->out, out_delayed);
397                 c->event_flags |= dav1d_picture_get_event_flags(out_delayed);
398             }
399             dav1d_thread_picture_unref(out_delayed);
400             if (output_picture_ready(c, 0))
401                 return output_image(c, out);
402         }
403     } while (++drain_count < c->n_fc);
404 
405     if (output_picture_ready(c, 1))
406         return output_image(c, out);
407 
408     return DAV1D_ERR(EAGAIN);
409 }
410 
gen_picture(Dav1dContext * const c)411 static int gen_picture(Dav1dContext *const c)
412 {
413     Dav1dData *const in = &c->in;
414 
415     if (output_picture_ready(c, 0))
416         return 0;
417 
418     while (in->sz > 0) {
419         const ptrdiff_t res = dav1d_parse_obus(c, in);
420         if (res < 0) {
421             dav1d_data_unref_internal(in);
422         } else {
423             assert((size_t)res <= in->sz);
424             in->sz -= res;
425             in->data += res;
426             if (!in->sz) dav1d_data_unref_internal(in);
427         }
428         if (output_picture_ready(c, 0))
429             break;
430         if (res < 0)
431             return (int)res;
432     }
433 
434     return 0;
435 }
436 
dav1d_send_data(Dav1dContext * const c,Dav1dData * const in)437 int dav1d_send_data(Dav1dContext *const c, Dav1dData *const in)
438 {
439     validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
440     validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
441 
442     if (in->data) {
443         validate_input_or_ret(in->sz > 0 && in->sz <= SIZE_MAX / 2, DAV1D_ERR(EINVAL));
444         c->drain = 0;
445     }
446     if (c->in.data)
447         return DAV1D_ERR(EAGAIN);
448     dav1d_data_ref(&c->in, in);
449 
450     int res = gen_picture(c);
451     if (!res)
452         dav1d_data_unref_internal(in);
453 
454     return res;
455 }
456 
dav1d_get_picture(Dav1dContext * const c,Dav1dPicture * const out)457 int dav1d_get_picture(Dav1dContext *const c, Dav1dPicture *const out)
458 {
459     validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
460     validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
461 
462     const int drain = c->drain;
463     c->drain = 1;
464 
465     int res = gen_picture(c);
466     if (res < 0)
467         return res;
468 
469     if (c->cached_error) {
470         const int res = c->cached_error;
471         c->cached_error = 0;
472         return res;
473     }
474 
475     if (output_picture_ready(c, c->n_fc == 1))
476         return output_image(c, out);
477 
478     if (c->n_fc > 1 && drain)
479         return drain_picture(c, out);
480 
481     return DAV1D_ERR(EAGAIN);
482 }
483 
dav1d_apply_grain(Dav1dContext * const c,Dav1dPicture * const out,const Dav1dPicture * const in)484 int dav1d_apply_grain(Dav1dContext *const c, Dav1dPicture *const out,
485                       const Dav1dPicture *const in)
486 {
487     validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
488     validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
489     validate_input_or_ret(in != NULL, DAV1D_ERR(EINVAL));
490 
491     if (!has_grain(in)) {
492         dav1d_picture_ref(out, in);
493         return 0;
494     }
495 
496     int res = dav1d_picture_alloc_copy(c, out, in->p.w, in);
497     if (res < 0) goto error;
498 
499     if (c->n_tc > 1) {
500         dav1d_task_delayed_fg(c, out, in);
501     } else {
502         switch (out->p.bpc) {
503 #if CONFIG_8BPC
504         case 8:
505             dav1d_apply_grain_8bpc(&c->dsp[0].fg, out, in);
506             break;
507 #endif
508 #if CONFIG_16BPC
509         case 10:
510         case 12:
511             dav1d_apply_grain_16bpc(&c->dsp[(out->p.bpc >> 1) - 4].fg, out, in);
512             break;
513 #endif
514         default: abort();
515         }
516     }
517 
518     return 0;
519 
520 error:
521     dav1d_picture_unref_internal(out);
522     return res;
523 }
524 
dav1d_flush(Dav1dContext * const c)525 void dav1d_flush(Dav1dContext *const c) {
526     dav1d_data_unref_internal(&c->in);
527     if (c->out.p.frame_hdr)
528         dav1d_thread_picture_unref(&c->out);
529     if (c->cache.p.frame_hdr)
530         dav1d_thread_picture_unref(&c->cache);
531 
532     c->drain = 0;
533     c->cached_error = 0;
534 
535     for (int i = 0; i < 8; i++) {
536         if (c->refs[i].p.p.frame_hdr)
537             dav1d_thread_picture_unref(&c->refs[i].p);
538         dav1d_ref_dec(&c->refs[i].segmap);
539         dav1d_ref_dec(&c->refs[i].refmvs);
540         dav1d_cdf_thread_unref(&c->cdf[i]);
541     }
542     c->frame_hdr = NULL;
543     c->seq_hdr = NULL;
544     dav1d_ref_dec(&c->seq_hdr_ref);
545 
546     c->mastering_display = NULL;
547     c->content_light = NULL;
548     c->itut_t35 = NULL;
549     c->n_itut_t35 = 0;
550     dav1d_ref_dec(&c->mastering_display_ref);
551     dav1d_ref_dec(&c->content_light_ref);
552     dav1d_ref_dec(&c->itut_t35_ref);
553 
554     dav1d_data_props_unref_internal(&c->cached_error_props);
555 
556     if (c->n_fc == 1 && c->n_tc == 1) return;
557     atomic_store(c->flush, 1);
558 
559     // stop running tasks in worker threads
560     if (c->n_tc > 1) {
561         pthread_mutex_lock(&c->task_thread.lock);
562         for (unsigned i = 0; i < c->n_tc; i++) {
563             Dav1dTaskContext *const tc = &c->tc[i];
564             while (!tc->task_thread.flushed) {
565                 pthread_cond_wait(&tc->task_thread.td.cond, &c->task_thread.lock);
566             }
567         }
568         for (unsigned i = 0; i < c->n_fc; i++) {
569             c->fc[i].task_thread.task_head = NULL;
570             c->fc[i].task_thread.task_tail = NULL;
571             c->fc[i].task_thread.task_cur_prev = NULL;
572             c->fc[i].task_thread.pending_tasks.head = NULL;
573             c->fc[i].task_thread.pending_tasks.tail = NULL;
574             atomic_init(&c->fc[i].task_thread.pending_tasks.merge, 0);
575         }
576         atomic_init(&c->task_thread.first, 0);
577         c->task_thread.cur = c->n_fc;
578         atomic_store(&c->task_thread.reset_task_cur, UINT_MAX);
579         atomic_store(&c->task_thread.cond_signaled, 0);
580         pthread_mutex_unlock(&c->task_thread.lock);
581     }
582 
583     // wait for threads to complete flushing
584     if (c->n_fc > 1) {
585         for (unsigned n = 0, next = c->frame_thread.next; n < c->n_fc; n++, next++) {
586             if (next == c->n_fc) next = 0;
587             Dav1dFrameContext *const f = &c->fc[next];
588             dav1d_decode_frame_exit(f, -1);
589             f->n_tile_data = 0;
590             f->task_thread.retval = 0;
591             Dav1dThreadPicture *out_delayed = &c->frame_thread.out_delayed[next];
592             if (out_delayed->p.frame_hdr) {
593                 dav1d_thread_picture_unref(out_delayed);
594             }
595         }
596         c->frame_thread.next = 0;
597     }
598     atomic_store(c->flush, 0);
599 }
600 
dav1d_close(Dav1dContext ** const c_out)601 COLD void dav1d_close(Dav1dContext **const c_out) {
602     validate_input(c_out != NULL);
603 #if TRACK_HEAP_ALLOCATIONS
604     dav1d_log_alloc_stats(*c_out);
605 #endif
606     close_internal(c_out, 1);
607 }
608 
close_internal(Dav1dContext ** const c_out,int flush)609 static COLD void close_internal(Dav1dContext **const c_out, int flush) {
610     Dav1dContext *const c = *c_out;
611     if (!c) return;
612 
613     if (flush) dav1d_flush(c);
614 
615     if (c->tc) {
616         struct TaskThreadData *ttd = &c->task_thread;
617         if (ttd->inited) {
618             pthread_mutex_lock(&ttd->lock);
619             for (unsigned n = 0; n < c->n_tc && c->tc[n].task_thread.td.inited; n++)
620                 c->tc[n].task_thread.die = 1;
621             pthread_cond_broadcast(&ttd->cond);
622             pthread_mutex_unlock(&ttd->lock);
623             for (unsigned n = 0; n < c->n_tc; n++) {
624                 Dav1dTaskContext *const pf = &c->tc[n];
625                 if (!pf->task_thread.td.inited) break;
626                 pthread_join(pf->task_thread.td.thread, NULL);
627                 pthread_cond_destroy(&pf->task_thread.td.cond);
628                 pthread_mutex_destroy(&pf->task_thread.td.lock);
629             }
630             pthread_cond_destroy(&ttd->delayed_fg.cond);
631             pthread_cond_destroy(&ttd->cond);
632             pthread_mutex_destroy(&ttd->lock);
633         }
634         dav1d_free_aligned(c->tc);
635     }
636 
637     for (unsigned n = 0; c->fc && n < c->n_fc; n++) {
638         Dav1dFrameContext *const f = &c->fc[n];
639 
640         // clean-up threading stuff
641         if (c->n_fc > 1) {
642             dav1d_free(f->tile_thread.lowest_pixel_mem);
643             dav1d_free(f->frame_thread.b);
644             dav1d_free_aligned(f->frame_thread.cbi);
645             dav1d_free_aligned(f->frame_thread.pal_idx);
646             dav1d_free_aligned(f->frame_thread.cf);
647             dav1d_free(f->frame_thread.tile_start_off);
648             dav1d_free_aligned(f->frame_thread.pal);
649         }
650         if (c->n_tc > 1) {
651             pthread_mutex_destroy(&f->task_thread.pending_tasks.lock);
652             pthread_cond_destroy(&f->task_thread.cond);
653             pthread_mutex_destroy(&f->task_thread.lock);
654         }
655         dav1d_free(f->frame_thread.frame_progress);
656         dav1d_free(f->task_thread.tasks);
657         dav1d_free(f->task_thread.tile_tasks[0]);
658         dav1d_free_aligned(f->ts);
659         dav1d_free_aligned(f->ipred_edge[0]);
660         dav1d_free(f->a);
661         dav1d_free(f->tile);
662         dav1d_free(f->lf.mask);
663         dav1d_free(f->lf.level);
664         dav1d_free(f->lf.lr_mask);
665         dav1d_free(f->lf.tx_lpf_right_edge[0]);
666         dav1d_free(f->lf.start_of_tile_row);
667         dav1d_refmvs_clear(&f->rf);
668         dav1d_free_aligned(f->lf.cdef_line_buf);
669         dav1d_free_aligned(f->lf.lr_line_buf);
670     }
671     dav1d_free_aligned(c->fc);
672     if (c->n_fc > 1 && c->frame_thread.out_delayed) {
673         for (unsigned n = 0; n < c->n_fc; n++)
674             if (c->frame_thread.out_delayed[n].p.frame_hdr)
675                 dav1d_thread_picture_unref(&c->frame_thread.out_delayed[n]);
676         dav1d_free(c->frame_thread.out_delayed);
677     }
678     for (int n = 0; n < c->n_tile_data; n++)
679         dav1d_data_unref_internal(&c->tile[n].data);
680     dav1d_free(c->tile);
681     for (int n = 0; n < 8; n++) {
682         dav1d_cdf_thread_unref(&c->cdf[n]);
683         if (c->refs[n].p.p.frame_hdr)
684             dav1d_thread_picture_unref(&c->refs[n].p);
685         dav1d_ref_dec(&c->refs[n].refmvs);
686         dav1d_ref_dec(&c->refs[n].segmap);
687     }
688     dav1d_ref_dec(&c->seq_hdr_ref);
689     dav1d_ref_dec(&c->frame_hdr_ref);
690 
691     dav1d_ref_dec(&c->mastering_display_ref);
692     dav1d_ref_dec(&c->content_light_ref);
693     dav1d_ref_dec(&c->itut_t35_ref);
694 
695     dav1d_mem_pool_end(c->seq_hdr_pool);
696     dav1d_mem_pool_end(c->frame_hdr_pool);
697     dav1d_mem_pool_end(c->segmap_pool);
698     dav1d_mem_pool_end(c->refmvs_pool);
699     dav1d_mem_pool_end(c->cdf_pool);
700     dav1d_mem_pool_end(c->picture_pool);
701     dav1d_mem_pool_end(c->pic_ctx_pool);
702 
703     dav1d_freep_aligned(c_out);
704 }
705 
dav1d_get_event_flags(Dav1dContext * const c,enum Dav1dEventFlags * const flags)706 int dav1d_get_event_flags(Dav1dContext *const c, enum Dav1dEventFlags *const flags) {
707     validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
708     validate_input_or_ret(flags != NULL, DAV1D_ERR(EINVAL));
709 
710     *flags = c->event_flags;
711     c->event_flags = 0;
712     return 0;
713 }
714 
dav1d_get_decode_error_data_props(Dav1dContext * const c,Dav1dDataProps * const out)715 int dav1d_get_decode_error_data_props(Dav1dContext *const c, Dav1dDataProps *const out) {
716     validate_input_or_ret(c != NULL, DAV1D_ERR(EINVAL));
717     validate_input_or_ret(out != NULL, DAV1D_ERR(EINVAL));
718 
719     dav1d_data_props_unref_internal(out);
720     *out = c->cached_error_props;
721     dav1d_data_props_set_defaults(&c->cached_error_props);
722 
723     return 0;
724 }
725 
dav1d_picture_unref(Dav1dPicture * const p)726 void dav1d_picture_unref(Dav1dPicture *const p) {
727     dav1d_picture_unref_internal(p);
728 }
729 
dav1d_data_create(Dav1dData * const buf,const size_t sz)730 uint8_t *dav1d_data_create(Dav1dData *const buf, const size_t sz) {
731     return dav1d_data_create_internal(buf, sz);
732 }
733 
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)734 int dav1d_data_wrap(Dav1dData *const buf, const uint8_t *const ptr,
735                     const size_t sz,
736                     void (*const free_callback)(const uint8_t *data,
737                                                 void *user_data),
738                     void *const user_data)
739 {
740     return dav1d_data_wrap_internal(buf, ptr, sz, free_callback, user_data);
741 }
742 
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)743 int dav1d_data_wrap_user_data(Dav1dData *const buf,
744                               const uint8_t *const user_data,
745                               void (*const free_callback)(const uint8_t *user_data,
746                                                           void *cookie),
747                               void *const cookie)
748 {
749     return dav1d_data_wrap_user_data_internal(buf,
750                                               user_data,
751                                               free_callback,
752                                               cookie);
753 }
754 
dav1d_data_unref(Dav1dData * const buf)755 void dav1d_data_unref(Dav1dData *const buf) {
756     dav1d_data_unref_internal(buf);
757 }
758 
dav1d_data_props_unref(Dav1dDataProps * const props)759 void dav1d_data_props_unref(Dav1dDataProps *const props) {
760     dav1d_data_props_unref_internal(props);
761 }
762