/work/dav1d/src/picture.c
Line | Count | Source |
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 | | |
46 | 0 | int dav1d_default_picture_alloc(Dav1dPicture *const p, void *const cookie) { |
47 | 0 | const int hbd = p->p.bpc > 8; |
48 | 0 | const int aligned_w = (p->p.w + 127) & ~127; |
49 | 0 | const int aligned_h = (p->p.h + 127) & ~127; |
50 | 0 | const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400; |
51 | 0 | const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420; |
52 | 0 | const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444; |
53 | 0 | ptrdiff_t y_stride = aligned_w << hbd; |
54 | 0 | ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0; |
55 | | /* Due to how mapping of addresses to sets works in most L1 and L2 cache |
56 | | * implementations, strides of multiples of certain power-of-two numbers |
57 | | * may cause multiple rows of the same superblock to map to the same set, |
58 | | * causing evictions of previous rows resulting in a reduction in cache |
59 | | * hit rate. Avoid that by slightly padding the stride when necessary. */ |
60 | 0 | if (!(y_stride & 1023)) |
61 | 0 | y_stride += DAV1D_PICTURE_ALIGNMENT; |
62 | 0 | if (!(uv_stride & 1023) && has_chroma) |
63 | 0 | uv_stride += DAV1D_PICTURE_ALIGNMENT; |
64 | 0 | p->stride[0] = y_stride; |
65 | 0 | p->stride[1] = uv_stride; |
66 | 0 | const size_t y_sz = y_stride * aligned_h; |
67 | 0 | const size_t uv_sz = uv_stride * (aligned_h >> ss_ver); |
68 | 0 | const size_t pic_size = y_sz + 2 * uv_sz; |
69 | |
|
70 | 0 | uint8_t *const buf = dav1d_mem_pool_pop(cookie, pic_size + DAV1D_PICTURE_ALIGNMENT); |
71 | 0 | if (!buf) return DAV1D_ERR(ENOMEM); |
72 | 0 | p->allocator_data = buf; |
73 | 0 | p->data[0] = buf; |
74 | 0 | p->data[1] = has_chroma ? buf + y_sz : NULL; |
75 | 0 | p->data[2] = has_chroma ? buf + y_sz + uv_sz : NULL; |
76 | |
|
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | 0 | void dav1d_default_picture_release(Dav1dPicture *const p, void *const cookie) { |
81 | 0 | dav1d_mem_pool_push(cookie, p->allocator_data); |
82 | 0 | } |
83 | | |
84 | | struct pic_ctx_context { |
85 | | Dav1dPicAllocator allocator; |
86 | | Dav1dPicture pic; |
87 | | Dav1dRef ref; |
88 | | void *extra_data[]; |
89 | | }; |
90 | | |
91 | 0 | static void free_buffer(const uint8_t *const data, void *const user_data) { |
92 | 0 | struct pic_ctx_context *pic_ctx = (struct pic_ctx_context*)data; |
93 | |
|
94 | 0 | pic_ctx->allocator.release_picture_callback(&pic_ctx->pic, |
95 | 0 | pic_ctx->allocator.cookie); |
96 | 0 | dav1d_mem_pool_push(user_data, pic_ctx); |
97 | 0 | } |
98 | | |
99 | 0 | void dav1d_picture_free_itut_t35(const uint8_t *const data, void *const user_data) { |
100 | 0 | struct itut_t35_ctx_context *itut_t35_ctx = user_data; |
101 | |
|
102 | 0 | for (size_t i = 0; i < itut_t35_ctx->n_itut_t35; i++) |
103 | 0 | dav1d_free(itut_t35_ctx->itut_t35[i].payload); |
104 | 0 | dav1d_free(itut_t35_ctx->itut_t35); |
105 | 0 | dav1d_free(itut_t35_ctx); |
106 | 0 | } |
107 | | |
108 | | static int picture_alloc(Dav1dContext *const c, |
109 | | Dav1dPicture *const p, |
110 | | const int w, const int h, |
111 | | Dav1dSequenceHeader *const seq_hdr, Dav1dRef *const seq_hdr_ref, |
112 | | Dav1dFrameHeader *const frame_hdr, Dav1dRef *const frame_hdr_ref, |
113 | | const int bpc, |
114 | | const Dav1dDataProps *const props, |
115 | | Dav1dPicAllocator *const p_allocator, |
116 | | void **const extra_ptr) |
117 | 0 | { |
118 | 0 | if (p->data[0]) { |
119 | 0 | dav1d_log(c, "Picture already allocated!\n"); |
120 | 0 | return -1; |
121 | 0 | } |
122 | 0 | assert(bpc > 0 && bpc <= 16); |
123 | | |
124 | 0 | size_t extra = c->n_fc > 1 ? sizeof(atomic_int) * 2 : 0; |
125 | 0 | struct pic_ctx_context *pic_ctx = dav1d_mem_pool_pop(c->pic_ctx_pool, extra + |
126 | 0 | sizeof(struct pic_ctx_context)); |
127 | 0 | if (!pic_ctx) |
128 | 0 | return DAV1D_ERR(ENOMEM); |
129 | | |
130 | 0 | p->p.w = w; |
131 | 0 | p->p.h = h; |
132 | 0 | p->seq_hdr = seq_hdr; |
133 | 0 | p->frame_hdr = frame_hdr; |
134 | 0 | p->p.layout = seq_hdr->layout; |
135 | 0 | p->p.bpc = bpc; |
136 | 0 | dav1d_data_props_set_defaults(&p->m); |
137 | 0 | const int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie); |
138 | 0 | if (res < 0) { |
139 | 0 | dav1d_mem_pool_push(c->pic_ctx_pool, pic_ctx); |
140 | 0 | return res; |
141 | 0 | } |
142 | | |
143 | 0 | pic_ctx->allocator = *p_allocator; |
144 | 0 | pic_ctx->pic = *p; |
145 | 0 | p->ref = dav1d_ref_init(&pic_ctx->ref, pic_ctx, free_buffer, c->pic_ctx_pool, 0); |
146 | |
|
147 | 0 | p->seq_hdr_ref = seq_hdr_ref; |
148 | 0 | if (seq_hdr_ref) dav1d_ref_inc(seq_hdr_ref); |
149 | |
|
150 | 0 | p->frame_hdr_ref = frame_hdr_ref; |
151 | 0 | if (frame_hdr_ref) dav1d_ref_inc(frame_hdr_ref); |
152 | |
|
153 | 0 | if (extra && extra_ptr) |
154 | 0 | *extra_ptr = &pic_ctx->extra_data; |
155 | |
|
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | | void dav1d_picture_copy_props(Dav1dPicture *const p, |
160 | | Dav1dContentLightLevel *const content_light, Dav1dRef *const content_light_ref, |
161 | | Dav1dMasteringDisplay *const mastering_display, Dav1dRef *const mastering_display_ref, |
162 | | Dav1dITUTT35 *const itut_t35, Dav1dRef *itut_t35_ref, size_t n_itut_t35, |
163 | | const Dav1dDataProps *const props) |
164 | 0 | { |
165 | 0 | dav1d_data_props_copy(&p->m, props); |
166 | |
|
167 | 0 | dav1d_ref_dec(&p->content_light_ref); |
168 | 0 | p->content_light_ref = content_light_ref; |
169 | 0 | p->content_light = content_light; |
170 | 0 | if (content_light_ref) dav1d_ref_inc(content_light_ref); |
171 | |
|
172 | 0 | dav1d_ref_dec(&p->mastering_display_ref); |
173 | 0 | p->mastering_display_ref = mastering_display_ref; |
174 | 0 | p->mastering_display = mastering_display; |
175 | 0 | if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref); |
176 | |
|
177 | 0 | dav1d_ref_dec(&p->itut_t35_ref); |
178 | 0 | p->itut_t35_ref = itut_t35_ref; |
179 | 0 | p->itut_t35 = itut_t35; |
180 | 0 | p->n_itut_t35 = n_itut_t35; |
181 | 0 | if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref); |
182 | 0 | } |
183 | | |
184 | | int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f, |
185 | | const int bpc) |
186 | 0 | { |
187 | 0 | Dav1dThreadPicture *const p = &f->sr_cur; |
188 | |
|
189 | 0 | const int res = picture_alloc(c, &p->p, f->frame_hdr->width[1], f->frame_hdr->height, |
190 | 0 | f->seq_hdr, f->seq_hdr_ref, |
191 | 0 | f->frame_hdr, f->frame_hdr_ref, |
192 | 0 | bpc, &f->tile[0].data.m, &c->allocator, |
193 | 0 | (void **) &p->progress); |
194 | 0 | if (res) return res; |
195 | | |
196 | | // Don't clear these flags from c->frame_flags if the frame is not going to be output. |
197 | | // This way they will be added to the next visible frame too. |
198 | 0 | const int flags_mask = ((f->frame_hdr->show_frame || c->output_invisible_frames) && |
199 | 0 | c->max_spatial_id == f->frame_hdr->spatial_id) |
200 | 0 | ? 0 : (PICTURE_FLAG_NEW_SEQUENCE | PICTURE_FLAG_NEW_OP_PARAMS_INFO); |
201 | 0 | p->flags = c->frame_flags; |
202 | 0 | c->frame_flags &= flags_mask; |
203 | |
|
204 | 0 | p->visible = f->frame_hdr->show_frame; |
205 | 0 | p->showable = f->frame_hdr->showable_frame; |
206 | |
|
207 | 0 | if (p->visible) { |
208 | | // Only add HDR10+ and T35 metadata when show frame flag is enabled |
209 | 0 | dav1d_picture_copy_props(&p->p, c->content_light, c->content_light_ref, |
210 | 0 | c->mastering_display, c->mastering_display_ref, |
211 | 0 | c->itut_t35, c->itut_t35_ref, c->n_itut_t35, |
212 | 0 | &f->tile[0].data.m); |
213 | | |
214 | | // Must be removed from the context after being attached to the frame |
215 | 0 | dav1d_ref_dec(&c->itut_t35_ref); |
216 | 0 | c->itut_t35 = NULL; |
217 | 0 | c->n_itut_t35 = 0; |
218 | 0 | } else { |
219 | 0 | dav1d_data_props_copy(&p->p.m, &f->tile[0].data.m); |
220 | 0 | } |
221 | |
|
222 | 0 | if (c->n_fc > 1) { |
223 | 0 | atomic_init(&p->progress[0], 0); |
224 | 0 | atomic_init(&p->progress[1], 0); |
225 | 0 | } |
226 | 0 | return res; |
227 | 0 | } |
228 | | |
229 | | int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, const int w, |
230 | | const Dav1dPicture *const src) |
231 | 0 | { |
232 | 0 | struct pic_ctx_context *const pic_ctx = (struct pic_ctx_context*)src->ref->const_data; |
233 | 0 | const int res = picture_alloc(c, dst, w, src->p.h, |
234 | 0 | src->seq_hdr, src->seq_hdr_ref, |
235 | 0 | src->frame_hdr, src->frame_hdr_ref, |
236 | 0 | src->p.bpc, &src->m, &pic_ctx->allocator, |
237 | 0 | NULL); |
238 | 0 | if (res) return res; |
239 | | |
240 | 0 | dav1d_picture_copy_props(dst, src->content_light, src->content_light_ref, |
241 | 0 | src->mastering_display, src->mastering_display_ref, |
242 | 0 | src->itut_t35, src->itut_t35_ref, src->n_itut_t35, |
243 | 0 | &src->m); |
244 | |
|
245 | 0 | return 0; |
246 | 0 | } |
247 | | |
248 | 0 | void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) { |
249 | 0 | assert(dst != NULL); |
250 | 0 | assert(dst->data[0] == NULL); |
251 | 0 | assert(src != NULL); |
252 | | |
253 | 0 | if (src->ref) { |
254 | 0 | assert(src->data[0] != NULL); |
255 | 0 | dav1d_ref_inc(src->ref); |
256 | 0 | } |
257 | 0 | if (src->frame_hdr_ref) dav1d_ref_inc(src->frame_hdr_ref); |
258 | 0 | if (src->seq_hdr_ref) dav1d_ref_inc(src->seq_hdr_ref); |
259 | 0 | if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref); |
260 | 0 | if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref); |
261 | 0 | if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref); |
262 | 0 | if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref); |
263 | 0 | *dst = *src; |
264 | 0 | } |
265 | | |
266 | 0 | void dav1d_picture_move_ref(Dav1dPicture *const dst, Dav1dPicture *const src) { |
267 | 0 | assert(dst != NULL); |
268 | 0 | assert(dst->data[0] == NULL); |
269 | 0 | assert(src != NULL); |
270 | | |
271 | 0 | if (src->ref) |
272 | 0 | assert(src->data[0] != NULL); |
273 | | |
274 | 0 | *dst = *src; |
275 | 0 | memset(src, 0, sizeof(*src)); |
276 | 0 | } |
277 | | |
278 | | void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst, |
279 | | const Dav1dThreadPicture *const src) |
280 | 0 | { |
281 | 0 | dav1d_picture_ref(&dst->p, &src->p); |
282 | 0 | dst->visible = src->visible; |
283 | 0 | dst->showable = src->showable; |
284 | 0 | dst->progress = src->progress; |
285 | 0 | dst->flags = src->flags; |
286 | 0 | } |
287 | | |
288 | | void dav1d_thread_picture_move_ref(Dav1dThreadPicture *const dst, |
289 | | Dav1dThreadPicture *const src) |
290 | 0 | { |
291 | 0 | dav1d_picture_move_ref(&dst->p, &src->p); |
292 | 0 | dst->visible = src->visible; |
293 | 0 | dst->showable = src->showable; |
294 | 0 | dst->progress = src->progress; |
295 | 0 | dst->flags = src->flags; |
296 | 0 | memset(src, 0, sizeof(*src)); |
297 | 0 | } |
298 | | |
299 | 0 | void dav1d_picture_unref_internal(Dav1dPicture *const p) { |
300 | 0 | validate_input(p != NULL); |
301 | |
|
302 | 0 | if (p->ref) { |
303 | 0 | validate_input(p->data[0] != NULL); |
304 | 0 | dav1d_ref_dec(&p->ref); |
305 | 0 | } |
306 | 0 | dav1d_ref_dec(&p->seq_hdr_ref); |
307 | 0 | dav1d_ref_dec(&p->frame_hdr_ref); |
308 | 0 | dav1d_ref_dec(&p->m.user_data.ref); |
309 | 0 | dav1d_ref_dec(&p->content_light_ref); |
310 | 0 | dav1d_ref_dec(&p->mastering_display_ref); |
311 | 0 | dav1d_ref_dec(&p->itut_t35_ref); |
312 | 0 | memset(p, 0, sizeof(*p)); |
313 | 0 | dav1d_data_props_set_defaults(&p->m); |
314 | 0 | } |
315 | | |
316 | 0 | void dav1d_thread_picture_unref(Dav1dThreadPicture *const p) { |
317 | 0 | dav1d_picture_unref_internal(&p->p); |
318 | |
|
319 | 0 | p->progress = NULL; |
320 | 0 | } |
321 | | |
322 | 0 | enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *const p) { |
323 | 0 | if (!p->flags) |
324 | 0 | return 0; |
325 | | |
326 | 0 | enum Dav1dEventFlags flags = 0; |
327 | 0 | if (p->flags & PICTURE_FLAG_NEW_SEQUENCE) |
328 | 0 | flags |= DAV1D_EVENT_FLAG_NEW_SEQUENCE; |
329 | 0 | if (p->flags & PICTURE_FLAG_NEW_OP_PARAMS_INFO) |
330 | 0 | flags |= DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO; |
331 | |
|
332 | 0 | return flags; |
333 | 0 | } |