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