Coverage Report

Created: 2026-05-30 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
69.4k
int dav1d_default_picture_alloc(Dav1dPicture *const p, void *const cookie) {
47
69.4k
    const int hbd = p->p.bpc > 8;
48
69.4k
    const int aligned_w = (p->p.w + 127) & ~127;
49
69.4k
    const int aligned_h = (p->p.h + 127) & ~127;
50
69.4k
    const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
51
69.4k
    const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
52
69.4k
    const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
53
69.4k
    ptrdiff_t y_stride = aligned_w << hbd;
54
69.4k
    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
69.4k
    if (!(y_stride & 1023))
61
2.37k
        y_stride += DAV1D_PICTURE_ALIGNMENT;
62
69.4k
    if (!(uv_stride & 1023) && has_chroma)
63
2.04k
        uv_stride += DAV1D_PICTURE_ALIGNMENT;
64
69.4k
    p->stride[0] = y_stride;
65
69.4k
    p->stride[1] = uv_stride;
66
69.4k
    const size_t y_sz = y_stride * aligned_h;
67
69.4k
    const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);
68
69.4k
    const size_t pic_size = y_sz + 2 * uv_sz;
69
70
69.4k
    uint8_t *const buf = dav1d_mem_pool_pop(cookie, pic_size + DAV1D_PICTURE_ALIGNMENT);
71
69.4k
    if (!buf) return DAV1D_ERR(ENOMEM);
72
69.4k
    p->allocator_data = buf;
73
69.4k
    p->data[0] = buf;
74
69.4k
    p->data[1] = has_chroma ? buf + y_sz : NULL;
75
69.4k
    p->data[2] = has_chroma ? buf + y_sz + uv_sz : NULL;
76
77
69.4k
    return 0;
78
69.4k
}
79
80
69.4k
void dav1d_default_picture_release(Dav1dPicture *const p, void *const cookie) {
81
69.4k
    dav1d_mem_pool_push(cookie, p->allocator_data);
82
69.4k
}
83
84
struct pic_ctx_context {
85
    Dav1dPicAllocator allocator;
86
    Dav1dPicture pic;
87
    Dav1dRef ref;
88
    void *extra_data[];
89
};
90
91
69.4k
static void free_buffer(const uint8_t *const data, void *const user_data) {
92
69.4k
    struct pic_ctx_context *pic_ctx = (struct pic_ctx_context*)data;
93
94
69.4k
    pic_ctx->allocator.release_picture_callback(&pic_ctx->pic,
95
69.4k
                                                pic_ctx->allocator.cookie);
96
69.4k
    dav1d_mem_pool_push(user_data, pic_ctx);
97
69.4k
}
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
69.4k
{
118
69.4k
    if (p->data[0]) {
119
0
        dav1d_log(c, "Picture already allocated!\n");
120
0
        return -1;
121
0
    }
122
69.4k
    assert(bpc > 0 && bpc <= 16);
123
124
69.4k
    size_t extra = c->n_fc > 1 ? sizeof(atomic_int) * 2 : 0;
125
69.4k
    struct pic_ctx_context *pic_ctx = dav1d_mem_pool_pop(c->pic_ctx_pool, extra +
126
69.4k
                                                         sizeof(struct pic_ctx_context));
127
69.4k
    if (!pic_ctx)
128
0
        return DAV1D_ERR(ENOMEM);
129
130
69.4k
    p->p.w = w;
131
69.4k
    p->p.h = h;
132
69.4k
    p->seq_hdr = seq_hdr;
133
69.4k
    p->frame_hdr = frame_hdr;
134
69.4k
    p->p.layout = seq_hdr->layout;
135
69.4k
    p->p.bpc = bpc;
136
69.4k
    dav1d_data_props_set_defaults(&p->m);
137
69.4k
    const int res = p_allocator->alloc_picture_callback(p, p_allocator->cookie);
138
69.4k
    if (res < 0) {
139
0
        dav1d_mem_pool_push(c->pic_ctx_pool, pic_ctx);
140
0
        return res;
141
0
    }
142
143
69.4k
    pic_ctx->allocator = *p_allocator;
144
69.4k
    pic_ctx->pic = *p;
145
69.4k
    p->ref = dav1d_ref_init(&pic_ctx->ref, pic_ctx, free_buffer, c->pic_ctx_pool, 0);
146
147
69.4k
    p->seq_hdr_ref = seq_hdr_ref;
148
69.4k
    if (seq_hdr_ref) dav1d_ref_inc(seq_hdr_ref);
149
150
69.4k
    p->frame_hdr_ref = frame_hdr_ref;
151
69.4k
    if (frame_hdr_ref) dav1d_ref_inc(frame_hdr_ref);
152
153
69.4k
    if (extra && extra_ptr)
154
56.2k
        *extra_ptr = &pic_ctx->extra_data;
155
156
69.4k
    return 0;
157
69.4k
}
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
64.3k
{
165
64.3k
    dav1d_data_props_copy(&p->m, props);
166
167
64.3k
    dav1d_ref_dec(&p->content_light_ref);
168
64.3k
    p->content_light_ref = content_light_ref;
169
64.3k
    p->content_light = content_light;
170
64.3k
    if (content_light_ref) dav1d_ref_inc(content_light_ref);
171
172
64.3k
    dav1d_ref_dec(&p->mastering_display_ref);
173
64.3k
    p->mastering_display_ref = mastering_display_ref;
174
64.3k
    p->mastering_display = mastering_display;
175
64.3k
    if (mastering_display_ref) dav1d_ref_inc(mastering_display_ref);
176
177
64.3k
    dav1d_ref_dec(&p->itut_t35_ref);
178
64.3k
    p->itut_t35_ref = itut_t35_ref;
179
64.3k
    p->itut_t35 = itut_t35;
180
64.3k
    p->n_itut_t35 = n_itut_t35;
181
64.3k
    if (itut_t35_ref) dav1d_ref_inc(itut_t35_ref);
182
64.3k
}
183
184
int dav1d_thread_picture_alloc(Dav1dContext *const c, Dav1dFrameContext *const f,
185
                               const int bpc)
186
56.2k
{
187
56.2k
    Dav1dThreadPicture *const p = &f->sr_cur;
188
189
56.2k
    const int res = picture_alloc(c, &p->p, f->frame_hdr->width[1], f->frame_hdr->height,
190
56.2k
                                  f->seq_hdr, f->seq_hdr_ref,
191
56.2k
                                  f->frame_hdr, f->frame_hdr_ref,
192
56.2k
                                  bpc, &f->tile[0].data.m, &c->allocator,
193
56.2k
                                  (void **) &p->progress);
194
56.2k
    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
56.2k
    const int flags_mask = ((f->frame_hdr->show_frame || c->output_invisible_frames) &&
199
50.9k
                            c->max_spatial_id == f->frame_hdr->spatial_id)
200
56.2k
                           ? 0 : (PICTURE_FLAG_NEW_SEQUENCE | PICTURE_FLAG_NEW_OP_PARAMS_INFO);
201
56.2k
    p->flags = c->frame_flags;
202
56.2k
    c->frame_flags &= flags_mask;
203
204
56.2k
    p->visible = f->frame_hdr->show_frame;
205
56.2k
    p->showable = f->frame_hdr->showable_frame;
206
207
56.2k
    if (p->visible) {
208
        // Only add HDR10+ and T35 metadata when show frame flag is enabled
209
50.9k
        dav1d_picture_copy_props(&p->p, c->content_light, c->content_light_ref,
210
50.9k
                                 c->mastering_display, c->mastering_display_ref,
211
50.9k
                                 c->itut_t35, c->itut_t35_ref, c->n_itut_t35,
212
50.9k
                                 &f->tile[0].data.m);
213
214
        // Must be removed from the context after being attached to the frame
215
50.9k
        dav1d_ref_dec(&c->itut_t35_ref);
216
50.9k
        c->itut_t35 = NULL;
217
50.9k
        c->n_itut_t35 = 0;
218
50.9k
    } else {
219
5.26k
        dav1d_data_props_copy(&p->p.m, &f->tile[0].data.m);
220
5.26k
    }
221
222
56.2k
    if (c->n_fc > 1) {
223
56.2k
        atomic_init(&p->progress[0], 0);
224
56.2k
        atomic_init(&p->progress[1], 0);
225
56.2k
    }
226
56.2k
    return res;
227
56.2k
}
228
229
int dav1d_picture_alloc_copy(Dav1dContext *const c, Dav1dPicture *const dst, const int w,
230
                             const Dav1dPicture *const src)
231
13.2k
{
232
13.2k
    struct pic_ctx_context *const pic_ctx = (struct pic_ctx_context*)src->ref->const_data;
233
13.2k
    const int res = picture_alloc(c, dst, w, src->p.h,
234
13.2k
                                  src->seq_hdr, src->seq_hdr_ref,
235
13.2k
                                  src->frame_hdr, src->frame_hdr_ref,
236
13.2k
                                  src->p.bpc, &src->m, &pic_ctx->allocator,
237
13.2k
                                  NULL);
238
13.2k
    if (res) return res;
239
240
13.2k
    dav1d_picture_copy_props(dst, src->content_light, src->content_light_ref,
241
13.2k
                             src->mastering_display, src->mastering_display_ref,
242
13.2k
                             src->itut_t35, src->itut_t35_ref, src->n_itut_t35,
243
13.2k
                             &src->m);
244
245
13.2k
    return 0;
246
13.2k
}
247
248
633k
void dav1d_picture_ref(Dav1dPicture *const dst, const Dav1dPicture *const src) {
249
633k
    assert(dst != NULL);
250
633k
    assert(dst->data[0] == NULL);
251
633k
    assert(src != NULL);
252
253
633k
    if (src->ref) {
254
633k
        assert(src->data[0] != NULL);
255
633k
        dav1d_ref_inc(src->ref);
256
633k
    }
257
633k
    if (src->frame_hdr_ref) dav1d_ref_inc(src->frame_hdr_ref);
258
633k
    if (src->seq_hdr_ref) dav1d_ref_inc(src->seq_hdr_ref);
259
633k
    if (src->m.user_data.ref) dav1d_ref_inc(src->m.user_data.ref);
260
633k
    if (src->content_light_ref) dav1d_ref_inc(src->content_light_ref);
261
633k
    if (src->mastering_display_ref) dav1d_ref_inc(src->mastering_display_ref);
262
633k
    if (src->itut_t35_ref) dav1d_ref_inc(src->itut_t35_ref);
263
633k
    *dst = *src;
264
633k
}
265
266
30.7k
void dav1d_picture_move_ref(Dav1dPicture *const dst, Dav1dPicture *const src) {
267
30.7k
    assert(dst != NULL);
268
30.7k
    assert(dst->data[0] == NULL);
269
30.7k
    assert(src != NULL);
270
271
30.7k
    if (src->ref)
272
30.7k
        assert(src->data[0] != NULL);
273
274
30.7k
    *dst = *src;
275
30.7k
    memset(src, 0, sizeof(*src));
276
30.7k
}
277
278
void dav1d_thread_picture_ref(Dav1dThreadPicture *const dst,
279
                              const Dav1dThreadPicture *const src)
280
587k
{
281
587k
    dav1d_picture_ref(&dst->p, &src->p);
282
587k
    dst->visible = src->visible;
283
587k
    dst->showable = src->showable;
284
587k
    dst->progress = src->progress;
285
587k
    dst->flags = src->flags;
286
587k
}
287
288
void dav1d_thread_picture_move_ref(Dav1dThreadPicture *const dst,
289
                                   Dav1dThreadPicture *const src)
290
9.71k
{
291
9.71k
    dav1d_picture_move_ref(&dst->p, &src->p);
292
9.71k
    dst->visible = src->visible;
293
9.71k
    dst->showable = src->showable;
294
9.71k
    dst->progress = src->progress;
295
9.71k
    dst->flags = src->flags;
296
9.71k
    memset(src, 0, sizeof(*src));
297
9.71k
}
298
299
1.18M
void dav1d_picture_unref_internal(Dav1dPicture *const p) {
300
1.18M
    validate_input(p != NULL);
301
302
1.18M
    if (p->ref) {
303
702k
        validate_input(p->data[0] != NULL);
304
702k
        dav1d_ref_dec(&p->ref);
305
702k
    }
306
1.18M
    dav1d_ref_dec(&p->seq_hdr_ref);
307
1.18M
    dav1d_ref_dec(&p->frame_hdr_ref);
308
1.18M
    dav1d_ref_dec(&p->m.user_data.ref);
309
1.18M
    dav1d_ref_dec(&p->content_light_ref);
310
1.18M
    dav1d_ref_dec(&p->mastering_display_ref);
311
1.18M
    dav1d_ref_dec(&p->itut_t35_ref);
312
1.18M
    memset(p, 0, sizeof(*p));
313
1.18M
    dav1d_data_props_set_defaults(&p->m);
314
1.18M
}
315
316
873k
void dav1d_thread_picture_unref(Dav1dThreadPicture *const p) {
317
873k
    dav1d_picture_unref_internal(&p->p);
318
319
873k
    p->progress = NULL;
320
873k
}
321
322
29.9k
enum Dav1dEventFlags dav1d_picture_get_event_flags(const Dav1dThreadPicture *const p) {
323
29.9k
    if (!p->flags)
324
3
        return 0;
325
326
29.9k
    enum Dav1dEventFlags flags = 0;
327
29.9k
    if (p->flags & PICTURE_FLAG_NEW_SEQUENCE)
328
29.9k
       flags |= DAV1D_EVENT_FLAG_NEW_SEQUENCE;
329
29.9k
    if (p->flags & PICTURE_FLAG_NEW_OP_PARAMS_INFO)
330
0
       flags |= DAV1D_EVENT_FLAG_NEW_OP_PARAMS_INFO;
331
332
29.9k
    return flags;
333
29.9k
}