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 
30 #include <errno.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "common/intops.h"
37 #include "common/validate.h"
38 
39 #include "src/internal.h"
40 #include "src/log.h"
41 #include "src/picture.h"
42 #include "src/ref.h"
43 #include "src/thread.h"
44 #include "src/thread_task.h"
45 
dav1d_default_picture_alloc(Dav1dPicture * const p,void * const cookie)46 int dav1d_default_picture_alloc(Dav1dPicture *const p, void *const cookie) {
47     assert(sizeof(Dav1dMemPoolBuffer) <= DAV1D_PICTURE_ALIGNMENT);
48     const int hbd = p->p.bpc > 8;
49     const int aligned_w = (p->p.w + 127) & ~127;
50     const int aligned_h = (p->p.h + 127) & ~127;
51     const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
52     const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
53     const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
54     ptrdiff_t y_stride = aligned_w << hbd;
55     ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0;
56     /* Due to how mapping of addresses to sets works in most L1 and L2 cache
57      * implementations, strides of multiples of certain power-of-two numbers
58      * may cause multiple rows of the same superblock to map to the same set,
59      * causing evictions of previous rows resulting in a reduction in cache
60      * hit rate. Avoid that by slightly padding the stride when necessary. */
61     if (!(y_stride & 1023))
62         y_stride += DAV1D_PICTURE_ALIGNMENT;
63     if (!(uv_stride & 1023) && has_chroma)
64         uv_stride += DAV1D_PICTURE_ALIGNMENT;
65     p->stride[0] = y_stride;
66     p->stride[1] = uv_stride;
67     const size_t y_sz = y_stride * aligned_h;
68     const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);
69     const size_t pic_size = y_sz + 2 * uv_sz;
70 
71     Dav1dMemPoolBuffer *const buf = dav1d_mem_pool_pop(cookie, pic_size +
72                                                        DAV1D_PICTURE_ALIGNMENT -
73                                                        sizeof(Dav1dMemPoolBuffer));
74     if (!buf) return DAV1D_ERR(ENOMEM);
75     p->allocator_data = buf;
76 
77     uint8_t *const data = buf->data;
78     p->data[0] = data;
79     p->data[1] = has_chroma ? data + y_sz : NULL;
80     p->data[2] = has_chroma ? data + y_sz + uv_sz : NULL;
81 
82     return 0;
83 }
84 
dav1d_default_picture_release(Dav1dPicture * const p,void * const cookie)85 void dav1d_default_picture_release(Dav1dPicture *const p, void *const cookie) {
86     dav1d_mem_pool_push(cookie, p->allocator_data);
87 }
88 
89 struct pic_ctx_context {
90     Dav1dPicAllocator allocator;
91     Dav1dPicture pic;
92     void *extra_ptr; /* MUST BE AT THE END */
93 };
94 
free_buffer(const uint8_t * const data,void * const user_data)95 static void free_buffer(const uint8_t *const data, void *const user_data) {
96     struct pic_ctx_context *pic_ctx = user_data;
97 
98     pic_ctx->allocator.release_picture_callback(&pic_ctx->pic,
99                                                 pic_ctx->allocator.cookie);
100     free(pic_ctx);
101 }
102 
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)103 static int picture_alloc_with_edges(Dav1dContext *const c,
104                                     Dav1dPicture *const p,
105                                     const int w, const int h,
106                                     Dav1dSequenceHeader *const seq_hdr, Dav1dRef *const seq_hdr_ref,
107                                     Dav1dFrameHeader *const frame_hdr, Dav1dRef *const frame_hdr_ref,
108                                     Dav1dContentLightLevel *const content_light, Dav1dRef *const content_light_ref,
109                                     Dav1dMasteringDisplay *const mastering_display, Dav1dRef *const mastering_display_ref,
110                                     Dav1dITUTT35 *const itut_t35, Dav1dRef *const itut_t35_ref,
111                                     const int bpc,
112                                     const Dav1dDataProps *const props,
113                                     Dav1dPicAllocator *const p_allocator,
114                                     const size_t extra, void **const extra_ptr)
115 {
116     if (p->data[0]) {
117         dav1d_log(c, "Picture already allocated!\n");
118         return -1;
119     }
120     assert(bpc > 0 && bpc <= 16);
121 
122     struct pic_ctx_context *pic_ctx = malloc(extra + sizeof(struct pic_ctx_context));
123     if (pic_ctx == NULL)
124         return DAV1D_ERR(ENOMEM);
125 
126     p->p.w = w;
127     p->p.h = h;
128     p->seq_hdr = seq_hdr;
129     p->frame_hdr = frame_hdr;
130     p->content_light = content_light;
131     p->mastering_display = mastering_display;
132     p->itut_t35 = itut_t35;
133     p->p.layout = seq_hdr->layout;
134     p->p.bpc = bpc;
135     dav1d_data_props_set_defaults(&p->m);
136     const int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);
137     if (res < 0) {
138         free(pic_ctx);
139         return res;
140     }
141 
142     pic_ctx->allocator = *p_allocator;
143     pic_ctx->pic = *p;
144 
145     if (!(p->ref = dav1d_ref_wrap(p->data[0], free_buffer, pic_ctx))) {
146         p_allocator->release_picture_callback(p, p_allocator->cookie);
147         free(pic_ctx);
148         dav1d_log(c, "Failed to wrap picture: %s\n", strerror(errno));
149         return DAV1D_ERR(ENOMEM);
150     }
151 
152     p->seq_hdr_ref = seq_hdr_ref;
153     if (seq_hdr_ref) dav1d_ref_inc(seq_hdr_ref);
154 
155     p->frame_hdr_ref = frame_hdr_ref;
156     if (frame_hdr_ref) dav1d_ref_inc(frame_hdr_ref);
157 
158     dav1d_data_props_copy(&p->m, props);
159 
160     if (extra && extra_ptr)
161         *extra_ptr = &pic_ctx->extra_ptr;
162 
163     p->content_light_ref = content_light_ref;
164     if (content_light_ref) dav1d_ref_inc(content_light_ref);
165 
166     p->mastering_display_ref = mastering_display_ref;
167     if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref);
168 
169     p->itut_t35_ref = itut_t35_ref;
170     if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref);
171 
172     return 0;
173 }
174 
dav1d_thread_picture_alloc(Dav1dContext * const c,Dav1dFrameContext * const f,const int bpc)175 int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f,
176                                const int bpc)
177 {
178     Dav1dThreadPicture *const p = &f->sr_cur;
179     p->t = c->n_fc > 1 ? &f->frame_thread.td : NULL;
180 
181     const int res =
182         picture_alloc_with_edges(c, &p->p, f->frame_hdr->width[1], f->frame_hdr->height,
183                                  f->seq_hdr, f->seq_hdr_ref,
184                                  f->frame_hdr, f->frame_hdr_ref,
185                                  c->content_light, c->content_light_ref,
186                                  c->mastering_display, c->mastering_display_ref,
187                                  c->itut_t35, c->itut_t35_ref,
188                                  bpc, &f->tile[0].data.m, &c->allocator,
189                                  p->t != NULL ? sizeof(atomic_int) * 2 : 0,
190                                  (void **) &p->progress);
191     if (res) return res;
192 
193     // Must be removed from the context after being attached to the frame
194     dav1d_ref_dec(&c->itut_t35_ref);
195     c->itut_t35 = NULL;
196 
197     p->flags = c->frame_flags;
198     c->frame_flags = 0;
199 
200     p->visible = f->frame_hdr->show_frame;
201     if (p->t) {
202         atomic_init(&p->progress[0], 0);
203         atomic_init(&p->progress[1], 0);
204     }
205     return res;
206 }
207 
dav1d_picture_alloc_copy(Dav1dContext * const c,Dav1dPicture * const dst,const int w,const Dav1dPicture * const src)208 int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, const int w,
209                              const Dav1dPicture *const src)
210 {
211     struct pic_ctx_context *const pic_ctx = src->ref->user_data;
212     const int res = picture_alloc_with_edges(c, dst, w, src->p.h,
213                                              src->seq_hdr, src->seq_hdr_ref,
214                                              src->frame_hdr, src->frame_hdr_ref,
215                                              src->content_light, src->content_light_ref,
216                                              src->mastering_display, src->mastering_display_ref,
217                                              src->itut_t35, src->itut_t35_ref,
218                                              src->p.bpc, &src->m, &pic_ctx->allocator,
219                                              0, NULL);
220     return res;
221 }
222 
dav1d_picture_ref(Dav1dPicture * const dst,const Dav1dPicture * const src)223 void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) {
224     validate_input(dst != NULL);
225     validate_input(dst->data[0] == NULL);
226     validate_input(src != NULL);
227 
228     if (src->ref) {
229         validate_input(src->data[0] != NULL);
230         dav1d_ref_inc(src->ref);
231         if (src->frame_hdr_ref) dav1d_ref_inc(src->frame_hdr_ref);
232         if (src->seq_hdr_ref) dav1d_ref_inc(src->seq_hdr_ref);
233         if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);
234         if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref);
235         if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref);
236         if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref);
237     }
238     *dst = *src;
239 }
240 
dav1d_picture_move_ref(Dav1dPicture * const dst,Dav1dPicture * const src)241 void dav1d_picture_move_ref(Dav1dPicture *const dst, Dav1dPicture *const src) {
242     validate_input(dst != NULL);
243     validate_input(dst->data[0] == NULL);
244     validate_input(src != NULL);
245 
246     if (src->ref)
247         validate_input(src->data[0] != NULL);
248 
249     *dst = *src;
250     memset(src, 0, sizeof(*src));
251 }
252 
dav1d_thread_picture_ref(Dav1dThreadPicture * const dst,const Dav1dThreadPicture * const src)253 void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst,
254                               const Dav1dThreadPicture *const src)
255 {
256     dav1d_picture_ref(&dst->p, &src->p);
257     dst->t = src->t;
258     dst->visible = src->visible;
259     dst->progress = src->progress;
260     dst->flags = src->flags;
261 }
262 
dav1d_picture_unref_internal(Dav1dPicture * const p)263 void dav1d_picture_unref_internal(Dav1dPicture *const p) {
264     validate_input(p != NULL);
265 
266     if (p->ref) {
267         validate_input(p->data[0] != NULL);
268         dav1d_ref_dec(&p->ref);
269         dav1d_ref_dec(&p->seq_hdr_ref);
270         dav1d_ref_dec(&p->frame_hdr_ref);
271         dav1d_ref_dec(&p->m.user_data.ref);
272         dav1d_ref_dec(&p->content_light_ref);
273         dav1d_ref_dec(&p->mastering_display_ref);
274         dav1d_ref_dec(&p->itut_t35_ref);
275     }
276     memset(p, 0, sizeof(*p));
277 }
278 
dav1d_thread_picture_unref(Dav1dThreadPicture * const p)279 void dav1d_thread_picture_unref(Dav1dThreadPicture *const p) {
280     dav1d_picture_unref_internal(&p->p);
281 
282     p->t = NULL;
283     p->progress = NULL;
284 }
285 
dav1d_thread_picture_wait(const Dav1dThreadPicture * const p,int y_unclipped,const enum PlaneType plane_type)286 int dav1d_thread_picture_wait(const Dav1dThreadPicture *const p,
287                               int y_unclipped, const enum PlaneType plane_type)
288 {
289     assert(plane_type != PLANE_TYPE_ALL);
290 
291     if (!p->t)
292         return 0;
293 
294     // convert to luma units; include plane delay from loopfilters; clip
295     const int ss_ver = p->p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
296     y_unclipped *= 1 << (plane_type & ss_ver); // we rely here on PLANE_TYPE_UV being 1
297     y_unclipped += (plane_type != PLANE_TYPE_BLOCK) * 8; // delay imposed by loopfilter
298     const unsigned y = iclip(y_unclipped, 1, p->p.p.h);
299     atomic_uint *const progress = &p->progress[plane_type != PLANE_TYPE_BLOCK];
300     unsigned state;
301 
302     if ((state = atomic_load_explicit(progress, memory_order_acquire)) >= y)
303         return state == FRAME_ERROR;
304 
305     pthread_mutex_lock(&p->t->lock);
306     while ((state = atomic_load_explicit(progress, memory_order_relaxed)) < y)
307         pthread_cond_wait(&p->t->cond, &p->t->lock);
308     pthread_mutex_unlock(&p->t->lock);
309     return state == FRAME_ERROR;
310 }
311 
dav1d_thread_picture_signal(const Dav1dThreadPicture * const p,const int y,const enum PlaneType plane_type)312 void dav1d_thread_picture_signal(const Dav1dThreadPicture *const p,
313                                  const int y, // in pixel units
314                                  const enum PlaneType plane_type)
315 {
316     assert(plane_type != PLANE_TYPE_UV);
317 
318     if (!p->t)
319         return;
320 
321     pthread_mutex_lock(&p->t->lock);
322     if (plane_type != PLANE_TYPE_Y)
323         atomic_store(&p->progress[0], y);
324     if (plane_type != PLANE_TYPE_BLOCK)
325         atomic_store(&p->progress[1], y);
326     pthread_cond_broadcast(&p->t->cond);
327     pthread_mutex_unlock(&p->t->lock);
328 }
329 
dav1d_picture_get_event_flags(const Dav1dThreadPicture * const p)330 enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *const p) {
331     if (!p->flags)
332         return 0;
333 
334     enum Dav1dEventFlags flags = 0;
335     if (p->flags & PICTURE_FLAG_NEW_SEQUENCE)
336        flags |= DAV1D_EVENT_FLAG_NEW_SEQUENCE;
337     if (p->flags & PICTURE_FLAG_NEW_OP_PARAMS_INFO)
338        flags |= DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO;
339 
340     return flags;
341 }
342