330 lines · 12.3 KB · C
RawDownload
/* * 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" #include <errno.h>#include <stdint.h>#ifndef __plan9__#include <stdio.h>#endif#include <stdlib.h>#include <string.h> #include "common/intops.h"#include "common/validate.h" #include "src/internal.h"#include "src/log.h"#include "src/picture.h"#include "src/ref.h"#include "src/thread.h"#include "src/thread_task.h" int dav1d_default_picture_alloc(Dav1dPicture *const p, void *const cookie) {    assert(sizeof(Dav1dMemPoolBuffer) <= DAV1D_PICTURE_ALIGNMENT);    const int hbd = p->p.bpc > 8;    const int aligned_w = (p->p.w + 127) & ~127;    const int aligned_h = (p->p.h + 127) & ~127;    const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;    const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;    const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;    ptrdiff_t y_stride = aligned_w << hbd;    ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0;    /* Due to how mapping of addresses to sets works in most L1 and L2 cache     * implementations, strides of multiples of certain power-of-two numbers     * may cause multiple rows of the same superblock to map to the same set,     * causing evictions of previous rows resulting in a reduction in cache     * hit rate. Avoid that by slightly padding the stride when necessary. */    if (!(y_stride & 1023))        y_stride += DAV1D_PICTURE_ALIGNMENT;    if (!(uv_stride & 1023) && has_chroma)        uv_stride += DAV1D_PICTURE_ALIGNMENT;    p->stride[0] = y_stride;    p->stride[1] = uv_stride;    const size_t y_sz = y_stride * aligned_h;    const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);    const size_t pic_size = y_sz + 2 * uv_sz;     Dav1dMemPoolBuffer *const buf = dav1d_mem_pool_pop(cookie, pic_size +                                                       DAV1D_PICTURE_ALIGNMENT -                                                       sizeof(Dav1dMemPoolBuffer));    if (!buf) return DAV1D_ERR(ENOMEM);    p->allocator_data = buf;     uint8_t *const data = buf->data;    p->data[0] = data;    p->data[1] = has_chroma ? data + y_sz : NULL;    p->data[2] = has_chroma ? data + y_sz + uv_sz : NULL;     return 0;} void dav1d_default_picture_release(Dav1dPicture *const p, void *const cookie) {    dav1d_mem_pool_push(cookie, p->allocator_data);} struct pic_ctx_context {    Dav1dPicAllocator allocator;    Dav1dPicture pic;    void *extra_ptr; /* MUST BE AT THE END */}; static void free_buffer(const uint8_t *const data, void *const user_data) {    struct pic_ctx_context *pic_ctx = user_data;     pic_ctx->allocator.release_picture_callback(&pic_ctx->pic,                                                pic_ctx->allocator.cookie);    free(pic_ctx);} static int picture_alloc_with_edges(Dav1dContext *const c,                                    Dav1dPicture *const p,                                    const int w, const int h,                                    Dav1dSequenceHeader *const seq_hdr, Dav1dRef *const seq_hdr_ref,                                    Dav1dFrameHeader *const frame_hdr, Dav1dRef *const frame_hdr_ref,                                    Dav1dContentLightLevel *const content_light, Dav1dRef *const content_light_ref,                                    Dav1dMasteringDisplay *const mastering_display, Dav1dRef *const mastering_display_ref,                                    Dav1dITUTT35 *const itut_t35, Dav1dRef *const itut_t35_ref,                                    const int bpc,                                    const Dav1dDataProps *const props,                                    Dav1dPicAllocator *const p_allocator,                                    const size_t extra, void **const extra_ptr){    if (p->data[0]) {        dav1d_log(c, "Picture already allocated!\n");        return -1;    }    assert(bpc > 0 && bpc <= 16);     struct pic_ctx_context *pic_ctx = malloc(extra + sizeof(struct pic_ctx_context));    if (pic_ctx == NULL)        return DAV1D_ERR(ENOMEM);     p->p.w = w;    p->p.h = h;    p->seq_hdr = seq_hdr;    p->frame_hdr = frame_hdr;    p->content_light = content_light;    p->mastering_display = mastering_display;    p->itut_t35 = itut_t35;    p->p.layout = seq_hdr->layout;    p->p.bpc = bpc;    dav1d_data_props_set_defaults(&p->m);    const int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);    if (res < 0) {        free(pic_ctx);        return res;    }     pic_ctx->allocator = *p_allocator;    pic_ctx->pic = *p;     if (!(p->ref = dav1d_ref_wrap(p->data[0], free_buffer, pic_ctx))) {        p_allocator->release_picture_callback(p, p_allocator->cookie);        free(pic_ctx);#ifndef __plan9__        dav1d_log(c, "Failed to wrap picture: %s\n", strerror(errno));#else        dav1d_log(c, "Failed to wrap picture\n");#endif        return DAV1D_ERR(ENOMEM);    }     p->seq_hdr_ref = seq_hdr_ref;    if (seq_hdr_ref) dav1d_ref_inc(seq_hdr_ref);     p->frame_hdr_ref = frame_hdr_ref;    if (frame_hdr_ref) dav1d_ref_inc(frame_hdr_ref);     dav1d_data_props_copy(&p->m, props);     if (extra && extra_ptr)        *extra_ptr = &pic_ctx->extra_ptr;     p->content_light_ref = content_light_ref;    if (content_light_ref) dav1d_ref_inc(content_light_ref);     p->mastering_display_ref = mastering_display_ref;    if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref);     p->itut_t35_ref = itut_t35_ref;    if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref);     return 0;} int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f,                               const int bpc){    Dav1dThreadPicture *const p = &f->sr_cur;    p->t = c->n_fc > 1 ? &f->frame_thread.td : NULL;     const int res =        picture_alloc_with_edges(c, &p->p, f->frame_hdr->width[1], f->frame_hdr->height,                                 f->seq_hdr, f->seq_hdr_ref,                                 f->frame_hdr, f->frame_hdr_ref,                                 c->content_light, c->content_light_ref,                                 c->mastering_display, c->mastering_display_ref,                                 c->itut_t35, c->itut_t35_ref,                                 bpc, &f->tile[0].data.m, &c->allocator,                                 p->t != NULL ? sizeof(atomic_int) * 2 : 0,                                 (void **) &p->progress);    if (res) return res;     // Must be removed from the context after being attached to the frame    dav1d_ref_dec(&c->itut_t35_ref);    c->itut_t35 = NULL;     p->visible = f->frame_hdr->show_frame;    if (p->t) {        atomic_init(&p->progress[0], 0);        atomic_init(&p->progress[1], 0);    }    return res;} int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, const int w,                             const Dav1dPicture *const src){    struct pic_ctx_context *const pic_ctx = src->ref->user_data;    const int res = picture_alloc_with_edges(c, dst, w, src->p.h,                                             src->seq_hdr, src->seq_hdr_ref,                                             src->frame_hdr, src->frame_hdr_ref,                                             src->content_light, src->content_light_ref,                                             src->mastering_display, src->mastering_display_ref,                                             src->itut_t35, src->itut_t35_ref,                                             src->p.bpc, &src->m, &pic_ctx->allocator,                                             0, NULL);    return res;} void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) {    validate_input(dst != NULL);    validate_input(dst->data[0] == NULL);    validate_input(src != NULL);     if (src->ref) {        validate_input(src->data[0] != NULL);        dav1d_ref_inc(src->ref);        if (src->frame_hdr_ref) dav1d_ref_inc(src->frame_hdr_ref);        if (src->seq_hdr_ref) dav1d_ref_inc(src->seq_hdr_ref);        if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);        if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref);        if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref);        if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref);    }    *dst = *src;} void dav1d_picture_move_ref(Dav1dPicture *const dst, Dav1dPicture *const src) {    validate_input(dst != NULL);    validate_input(dst->data[0] == NULL);    validate_input(src != NULL);     if (src->ref)        validate_input(src->data[0] != NULL);     *dst = *src;    memset(src, 0, sizeof(*src));} void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst,                              const Dav1dThreadPicture *const src){    dav1d_picture_ref(&dst->p, &src->p);    dst->t = src->t;    dst->visible = src->visible;    dst->progress = src->progress;} void dav1d_picture_unref_internal(Dav1dPicture *p) {    validate_input(p != NULL);     if (p->ref) {        validate_input(p->data[0] != NULL);        dav1d_ref_dec(&p->ref);        dav1d_ref_dec(&p->seq_hdr_ref);        dav1d_ref_dec(&p->frame_hdr_ref);        dav1d_ref_dec(&p->m.user_data.ref);        dav1d_ref_dec(&p->content_light_ref);        dav1d_ref_dec(&p->mastering_display_ref);        dav1d_ref_dec(&p->itut_t35_ref);    }    memset(p, 0, sizeof(*p));} void dav1d_thread_picture_unref(Dav1dThreadPicture *const p) {    dav1d_picture_unref_internal(&p->p);     p->t = NULL;    p->progress = NULL;} int dav1d_thread_picture_wait(const Dav1dThreadPicture *const p,                              int y_unclipped, const enum PlaneType plane_type){    assert(plane_type != PLANE_TYPE_ALL);     if (!p->t)        return 0;     // convert to luma units; include plane delay from loopfilters; clip    const int ss_ver = p->p.p.layout == DAV1D_PIXEL_LAYOUT_I420;    y_unclipped *= 1 << (plane_type & ss_ver); // we rely here on PLANE_TYPE_UV being 1    y_unclipped += (plane_type != PLANE_TYPE_BLOCK) * 8; // delay imposed by loopfilter    const unsigned y = iclip(y_unclipped, 1, p->p.p.h);    atomic_uint *const progress = &p->progress[plane_type != PLANE_TYPE_BLOCK];    unsigned state;     if ((state = atomic_load_explicit(progress, memory_order_acquire)) >= y)        return state == FRAME_ERROR;     pthread_mutex_lock(&p->t->lock);    while ((state = atomic_load_explicit(progress, memory_order_relaxed)) < y)        pthread_cond_wait(&p->t->cond, &p->t->lock);    pthread_mutex_unlock(&p->t->lock);    return state == FRAME_ERROR;} void dav1d_thread_picture_signal(const Dav1dThreadPicture *const p,                                 const int y, // in pixel units                                 const enum PlaneType plane_type){    assert(plane_type != PLANE_TYPE_UV);     if (!p->t)        return;     pthread_mutex_lock(&p->t->lock);    if (plane_type != PLANE_TYPE_Y)        atomic_store(&p->progress[0], y);    if (plane_type != PLANE_TYPE_BLOCK)        atomic_store(&p->progress[1], y);    pthread_cond_broadcast(&p->t->cond);    pthread_mutex_unlock(&p->t->lock);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t