Coverage Report

Created: 2026-08-13 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/dav1d.c
Line
Count
Source
1
/*****************************************************************************
2
 * dav1d.c: dav1d decoder (AV1) module
3
 *****************************************************************************
4
 * Copyright (C) 2016 VLC authors and VideoLAN
5
 *
6
 * Authors: Adrien Maglo <magsoft@videolan.org>
7
 * Based on aom.c by: Tristan Matthews <tmatth@videolan.org>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
/*****************************************************************************
25
 * Preamble
26
 *****************************************************************************/
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
34
#include <vlc_codec.h>
35
#include <vlc_timestamp_helper.h>
36
37
#include <errno.h>
38
#include <dav1d/dav1d.h>
39
40
#include "../packetizer/iso_color_tables.h"
41
#include "../packetizer/av1_obu.h"
42
#include "cc.h"
43
44
/****************************************************************************
45
 * Local prototypes
46
 ****************************************************************************/
47
static int OpenDecoder(vlc_object_t *);
48
static void CloseDecoder(vlc_object_t *);
49
50
/*****************************************************************************
51
 * Module descriptor
52
 *****************************************************************************/
53
54
#define THREAD_FRAMES_TEXT N_("Frames Threads")
55
#define THREAD_FRAMES_LONGTEXT N_( "Max number of threads used for frame decoding, default 0=auto" )
56
#define THREAD_TILES_TEXT N_("Tiles Threads")
57
#define THREAD_TILES_LONGTEXT N_( "Max number of threads used for tile decoding, default 0=auto" )
58
59
60
168
vlc_module_begin ()
61
84
    set_shortname("dav1d")
62
84
    set_description(N_("Dav1d video decoder"))
63
84
    set_capability("video decoder", 10000)
64
168
    set_callbacks(OpenDecoder, CloseDecoder)
65
84
    set_subcategory(SUBCAT_INPUT_VCODEC)
66
67
84
#if DAV1D_API_VERSION_MAJOR >= 6
68
84
    add_integer_with_range("dav1d-thread-frames", 0, 0, DAV1D_MAX_THREADS,
69
84
                THREAD_FRAMES_TEXT, THREAD_FRAMES_LONGTEXT)
70
84
    add_obsolete_string("dav1d-thread-tiles") // unused with dav1d 1.0
71
#else
72
    add_integer_with_range("dav1d-thread-frames", 0, 0, DAV1D_MAX_FRAME_THREADS,
73
                THREAD_FRAMES_TEXT, THREAD_FRAMES_LONGTEXT)
74
    add_integer_with_range("dav1d-thread-tiles", 0, 0, DAV1D_MAX_TILE_THREADS,
75
                THREAD_TILES_TEXT, THREAD_TILES_LONGTEXT)
76
#endif
77
84
    add_bool( "dav1d-all-layers", false, "Display all spatial layers", NULL )
78
84
vlc_module_end ()
79
80
/*****************************************************************************
81
 * decoder_sys_t: libaom decoder descriptor
82
 *****************************************************************************/
83
typedef struct
84
{
85
    Dav1dSettings s;
86
    Dav1dContext *c;
87
    cc_data_t cc;
88
} decoder_sys_t;
89
90
struct user_data_s
91
{
92
    vlc_tick_t dts;
93
};
94
95
static void FreeUserData_Handler(const uint8_t *p, void *userdata)
96
0
{
97
0
    VLC_UNUSED(p);
98
0
    free(userdata);
99
0
}
100
101
static vlc_fourcc_t FindVlcChroma(const Dav1dPicture *img)
102
3.30k
{
103
3.30k
    static const vlc_fourcc_t chroma_table_rgb[] = { VLC_CODEC_GBR_PLANAR, VLC_CODEC_GBR_PLANAR_10L, VLC_CODEC_GBR_PLANAR_12L };
104
3.30k
    static const vlc_fourcc_t chroma_table[][3] = {
105
3.30k
        [DAV1D_PIXEL_LAYOUT_I400] = { VLC_CODEC_GREY, VLC_CODEC_GREY_10L, VLC_CODEC_GREY_12L },
106
3.30k
        [DAV1D_PIXEL_LAYOUT_I420] = { VLC_CODEC_I420, VLC_CODEC_I420_10L,  VLC_CODEC_I420_12L },
107
3.30k
        [DAV1D_PIXEL_LAYOUT_I422] = { VLC_CODEC_I422, VLC_CODEC_I422_10L,  VLC_CODEC_I422_12L },
108
3.30k
        [DAV1D_PIXEL_LAYOUT_I444] = { VLC_CODEC_I444, VLC_CODEC_I444_10L,  VLC_CODEC_I444_12L },
109
3.30k
    };
110
111
    // AV1 signals RGB with the combination of the identity matrix, the BT.709 primaries and the sRGB/YCC transfer function.
112
    // See: "5.5.2. Color config syntax" from https://aomediacodec.github.io/av1-spec/av1-spec.pdf
113
3.30k
    if( img->p.layout == DAV1D_PIXEL_LAYOUT_I444 &&
114
465
        img->seq_hdr->mtrx == DAV1D_MC_IDENTITY &&
115
48
        img->seq_hdr->pri == DAV1D_COLOR_PRI_BT709 &&
116
48
        img->seq_hdr->trc == DAV1D_TRC_SRGB )
117
48
    {
118
48
        if( img->seq_hdr->hbd >= (int)ARRAY_SIZE(chroma_table_rgb) )
119
0
            return 0;
120
48
        return chroma_table_rgb[img->seq_hdr->hbd];
121
48
    }
122
123
3.25k
    if( img->seq_hdr->layout < 0 || img->seq_hdr->layout >= (int)ARRAY_SIZE(chroma_table) )
124
0
        return 0;
125
3.25k
    if( img->seq_hdr->hbd >= (int)ARRAY_SIZE(chroma_table[0]) )
126
0
        return 0;
127
128
3.25k
    return chroma_table[img->seq_hdr->layout][img->seq_hdr->hbd];
129
3.25k
}
130
131
static void UpdateDecoderOutput(decoder_t *dec, const Dav1dSequenceHeader *seq_hdr)
132
3.30k
{
133
3.30k
    video_format_t *v = &dec->fmt_out.video;
134
135
3.30k
    if( !v->i_sar_num || !v->i_sar_den )
136
3
    {
137
3
        v->i_sar_num = 1;
138
3
        v->i_sar_den = 1;
139
3
    }
140
141
3.30k
    if(dec->fmt_in->video.primaries == COLOR_PRIMARIES_UNDEF && seq_hdr)
142
3.01k
    {
143
3.01k
        v->primaries = iso_23001_8_cp_to_vlc_primaries(seq_hdr->pri);
144
3.01k
        v->transfer = iso_23001_8_tc_to_vlc_xfer(seq_hdr->trc);
145
3.01k
        v->space = iso_23001_8_mc_to_vlc_coeffs(seq_hdr->mtrx);
146
3.01k
        v->color_range = seq_hdr->color_range ? COLOR_RANGE_FULL : COLOR_RANGE_LIMITED;
147
3.01k
    }
148
3.30k
}
149
150
static int NewPicture(Dav1dPicture *img, void *cookie)
151
3.30k
{
152
3.30k
    decoder_t *dec = cookie;
153
3.30k
    decoder_sys_t *p_sys = dec->p_sys;
154
155
3.30k
    video_format_t *v = &dec->fmt_out.video;
156
157
3.30k
    v->i_visible_width  = img->seq_hdr->max_width;
158
3.30k
    v->i_visible_height = img->seq_hdr->max_height;
159
160
3.30k
    UpdateDecoderOutput(dec, img->seq_hdr);
161
162
3.30k
    const Dav1dMasteringDisplay *md = img->mastering_display;
163
3.30k
    if( dec->fmt_in->video.mastering.max_luminance == 0 && md )
164
0
    {
165
0
        const uint8_t RGB2GBR[3] = {2,0,1};
166
0
        for( size_t i=0;i<6; i++ )
167
0
        {
168
0
            v->mastering.primaries[i] =
169
0
                    50000 * (double) md->primaries[RGB2GBR[i >> 1]][i % 2]
170
0
                          / (double)(1 << 16);
171
0
        }
172
0
        v->mastering.min_luminance = 10000 * (double)md->min_luminance
173
0
                                           / (double) (1<<14);
174
0
        v->mastering.max_luminance = 10000 * (double) md->max_luminance
175
0
                                           / (double) (1<<8);
176
0
        v->mastering.white_point[0] = 50000 * (double)md->white_point[0]
177
0
                                            / (double) (1<<16);
178
0
        v->mastering.white_point[1] = 50000 * (double)md->white_point[1]
179
0
                                            / (double) (1<<16);
180
0
    }
181
182
3.30k
    const Dav1dContentLightLevel *cll = img->content_light;
183
3.30k
    if( dec->fmt_in->video.lighting.MaxCLL == 0 && cll )
184
0
    {
185
0
        v->lighting.MaxCLL = cll->max_content_light_level;
186
0
        v->lighting.MaxFALL = cll->max_frame_average_light_level;
187
0
    }
188
189
3.30k
    v->projection_mode = dec->fmt_in->video.projection_mode;
190
3.30k
    v->multiview_mode = dec->fmt_in->video.multiview_mode;
191
3.30k
    v->pose = dec->fmt_in->video.pose;
192
3.30k
    dec->fmt_out.i_codec = FindVlcChroma(img);
193
3.30k
    if (unlikely(dec->fmt_out.i_codec == 0))
194
0
        return -1;
195
196
3.30k
    v->i_width  = (img->seq_hdr->max_width + 0x7F) & ~0x7F;
197
3.30k
    v->i_height = (img->seq_hdr->max_height + 0x7F) & ~0x7F;
198
3.30k
    v->i_chroma = dec->fmt_out.i_codec;
199
200
3.30k
#if DAV1D_API_VERSION_MAJOR >= 6
201
3.30k
    dec->i_extra_picture_buffers = p_sys->s.max_frame_delay;
202
#else
203
    dec->i_extra_picture_buffers = (p_sys->s.n_frame_threads - 1);
204
#endif
205
3.30k
    if (img->seq_hdr->super_res)
206
        // dav1d seems to buffer more pictures when using super resolution
207
745
        dec->i_extra_picture_buffers += dec->i_extra_picture_buffers > 1 ? 2 : 1;
208
209
3.30k
    if (decoder_UpdateVideoFormat(dec) == 0)
210
3.30k
    {
211
3.30k
        picture_t *pic;
212
3.30k
        pic = decoder_NewPicture(dec);
213
3.30k
        if (unlikely(pic == NULL))
214
2
            return -1;
215
216
3.30k
        img->data[0] = pic->p[0].p_pixels;
217
3.30k
        img->stride[0] = pic->p[0].i_pitch;
218
3.30k
        img->data[1] = pic->p[1].p_pixels;
219
3.30k
        img->data[2] = pic->p[2].p_pixels;
220
3.30k
        assert(pic->p[1].i_pitch == pic->p[2].i_pitch);
221
3.30k
        img->stride[1] = pic->p[1].i_pitch;
222
223
3.30k
        img->allocator_data = pic;
224
3.30k
        return 0;
225
3.30k
    }
226
0
    return -1;
227
3.30k
}
228
229
static void ExtractCaptions(decoder_t *dec, const Dav1dPicture *img)
230
1.86k
{
231
1.86k
    decoder_sys_t *p_sys = dec->p_sys;
232
1.86k
    const struct user_data_s *userdata = (struct user_data_s *) img->m.user_data.data;
233
1.86k
    const Dav1dITUTT35 *itu_t35 = img->itut_t35;
234
1.86k
    if(itu_t35 && itu_t35->country_code == 0xb5 &&
235
0
       itu_t35->payload_size > 9 &&
236
0
       !memcmp(itu_t35->payload, "\x00\x0x31GA94\x03", 7))
237
0
    {
238
0
        cc_Extract(&p_sys->cc, CC_PAYLOAD_GA94, true,
239
0
                   &itu_t35->payload[7], itu_t35->payload_size - 7);
240
0
        if(p_sys->cc.b_reorder || p_sys->cc.i_data)
241
0
        {
242
0
            block_t *p_cc = block_Alloc(p_sys->cc.i_data);
243
0
            if(p_cc)
244
0
            {
245
0
                memcpy(p_cc->p_buffer, p_sys->cc.p_data, p_sys->cc.i_data);
246
0
                if(p_sys->cc.b_reorder || userdata == NULL)
247
0
                    p_cc->i_dts = p_cc->i_pts = img->m.timestamp;
248
0
                else
249
0
                    p_cc->i_pts = p_cc->i_dts = userdata->dts;
250
0
                decoder_cc_desc_t desc;
251
0
                desc.i_608_channels = p_sys->cc.i_608channels;
252
0
                desc.i_708_channels = p_sys->cc.i_708channels;
253
0
                desc.i_reorder_depth = 4;
254
0
                decoder_QueueCc(dec, p_cc, &desc);
255
0
            }
256
0
            cc_Flush(&p_sys->cc);
257
0
        }
258
0
    }
259
1.86k
}
260
261
static void FreePicture(Dav1dPicture *data, void *cookie)
262
3.30k
{
263
3.30k
    picture_t *pic = data->allocator_data;
264
3.30k
    decoder_t *dec = cookie;
265
3.30k
    VLC_UNUSED(dec);
266
3.30k
    picture_Release(pic);
267
3.30k
}
268
269
/****************************************************************************
270
 * Flush: clears decoder between seeks
271
 ****************************************************************************/
272
273
static void FlushDecoder(decoder_t *dec)
274
1.97k
{
275
1.97k
    decoder_sys_t *p_sys = dec->p_sys;
276
1.97k
    dav1d_flush(p_sys->c);
277
1.97k
    cc_Flush(&p_sys->cc);
278
1.97k
}
279
280
static void release_block(const uint8_t *buf, void *b)
281
76.4k
{
282
76.4k
    VLC_UNUSED(buf);
283
76.4k
    block_t *block = b;
284
76.4k
    block_Release(block);
285
76.4k
}
286
287
/****************************************************************************
288
 * Decode: the whole thing
289
 ****************************************************************************/
290
static int Decode(decoder_t *dec, block_t *block)
291
166k
{
292
166k
    decoder_sys_t *p_sys = dec->p_sys;
293
294
166k
    if (block && block->i_flags & (BLOCK_FLAG_CORRUPTED))
295
0
    {
296
0
        block_Release(block);
297
0
        return VLCDEC_SUCCESS;
298
0
    }
299
300
166k
    bool b_eos = false;
301
166k
    Dav1dData data;
302
166k
    Dav1dData *p_data = NULL;
303
304
166k
    if (block)
305
76.4k
    {
306
76.4k
        p_data = &data;
307
76.4k
        if (unlikely(dav1d_data_wrap(&data, block->p_buffer, block->i_buffer,
308
76.4k
                                     release_block, block) != 0))
309
0
        {
310
0
            block_Release(block);
311
0
            return VLCDEC_ECRITICAL;
312
0
        }
313
314
76.4k
        p_data->m.timestamp = block->i_pts == VLC_TICK_INVALID ? block->i_dts : block->i_pts;
315
76.4k
        if(block->i_dts != p_data->m.timestamp)
316
0
        {
317
0
            struct user_data_s *userdata = malloc(sizeof(*userdata));
318
0
            if(unlikely(userdata == NULL ||
319
0
                        0 != dav1d_data_wrap_user_data(&data, (const uint8_t *) userdata,
320
0
                                                       FreeUserData_Handler, userdata)))
321
0
            {
322
0
                free(userdata);
323
0
                dav1d_data_unref(&data);
324
0
                return VLCDEC_ECRITICAL;
325
0
            }
326
0
            userdata->dts = block->i_dts;
327
0
        }
328
329
76.4k
        b_eos = (block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE);
330
76.4k
    }
331
332
166k
    bool b_draining = false;
333
166k
    int i_ret = VLCDEC_SUCCESS;
334
166k
    int res;
335
255k
    do {
336
255k
        if( p_data )
337
76.6k
        {
338
76.6k
            res = dav1d_send_data(p_sys->c, p_data);
339
76.6k
            if (res < 0 && res != DAV1D_ERR(EAGAIN))
340
11.9k
            {
341
11.9k
                msg_Err(dec, "Decoder feed error %d!", res);
342
                /* bitstream decoding errors (typically DAV1D_ERR(EINVAL), are assumed
343
                 * to be recoverable. Other errors returned from this function are either
344
                 * unexpected within the VLC configuration, or considered critical failures:
345
                 * - EAGAIN is handled above.
346
                 * - ENOMEM means out-of-memory and is unrecoverable.
347
                 * - ENOPROTOOPT is a build or configuration error (invalid demuxer/muxer or unsupported bitdepth) and is unrecoverable.
348
                 * - ERANGE means frame size limits exceeded. VLC doesn't use this so we can ignore this, but unless size changes, it would be unrecoverable.
349
                 * - EINVAL is any other bitstream error which is basically what this is about.
350
                 * - EIO means file count not be opened and is unrecoverable.
351
                 * - ENOENT  is actually only returned by dav1d_parse_sequence_header(), which is outside this context (I think?).
352
                 * - read() can return other values but it's OK to consider these critical for now. */
353
11.9k
                i_ret = res == DAV1D_ERR(EINVAL) ? VLCDEC_SUCCESS : VLCDEC_ECRITICAL;
354
11.9k
                break;
355
11.9k
            }
356
76.6k
        }
357
358
255k
        bool b_output_error = false;
359
243k
        do
360
245k
        {
361
245k
            Dav1dPicture img = { 0 };
362
245k
            res = dav1d_get_picture(p_sys->c, &img);
363
245k
            if (res == 0)
364
1.86k
            {
365
1.86k
                picture_t *_pic = img.allocator_data;
366
1.86k
                picture_t *pic = picture_Clone(_pic);
367
1.86k
                if (unlikely(pic == NULL))
368
0
                {
369
0
                    i_ret = VLC_EGENERIC;
370
0
                    picture_Release(_pic);
371
0
                    b_output_error = true;
372
0
                    break;
373
0
                }
374
1.86k
                pic->b_progressive = true; /* codec does not support interlacing */
375
1.86k
                pic->date = img.m.timestamp;
376
1.86k
                decoder_QueueVideo(dec, pic);
377
1.86k
                ExtractCaptions(dec, &img);
378
1.86k
                dav1d_picture_unref(&img);
379
380
                /* if not draining then break here and don't get further
381
                 * decoded frames. this allows for proper frame threading
382
                 * as otherwise all frames would be drained directly */
383
1.86k
                if(p_data != NULL && !b_eos)
384
772
                    break;
385
1.86k
            }
386
243k
            else if (res == DAV1D_ERR(EAGAIN))
387
242k
            {
388
                /* the decoder needs more data to be able to output something.
389
                 * if there is more data pending, continue the loop below or
390
                 * otherwise break and first read more data */
391
242k
                if (p_data && p_data->sz != 0)
392
4
                    res = 0;
393
242k
                break;
394
242k
            }
395
929
            else
396
929
            {
397
929
                msg_Warn(dec, "Decoder error %d!", res);
398
929
                b_output_error = true;
399
929
                break;
400
929
            }
401
245k
        } while(res == 0);
402
403
243k
        if(b_output_error)
404
929
            break;
405
406
        /* on drain, we must ignore the 1st EAGAIN */
407
243k
        if(!b_draining && (res == DAV1D_ERR(EAGAIN) || res == 0)
408
153k
                       && (p_data == NULL||b_eos))
409
89.2k
        {
410
89.2k
            b_draining = true;
411
89.2k
            res = 0;
412
89.2k
        }
413
243k
    } while (res == 0 && ((p_data && p_data->sz != 0) || b_draining));
414
415
166k
    if(p_data && p_data->sz > 0)
416
12.0k
        dav1d_data_unref(p_data);
417
418
166k
    return i_ret;
419
166k
}
420
421
/*****************************************************************************
422
 * OpenDecoder: probe the decoder
423
 *****************************************************************************/
424
static int OpenDecoder(vlc_object_t *p_this)
425
258k
{
426
258k
    decoder_t *dec = (decoder_t *)p_this;
427
428
258k
    if (dec->fmt_in->i_codec != VLC_CODEC_AV1)
429
256k
        return VLC_EGENERIC;
430
431
1.97k
    decoder_sys_t *p_sys = vlc_obj_malloc(p_this, sizeof(*p_sys));
432
1.97k
    if (!p_sys)
433
0
        return VLC_ENOMEM;
434
435
1.97k
    dav1d_default_settings(&p_sys->s);
436
1.97k
#if DAV1D_API_VERSION_MAJOR >= 6
437
1.97k
    p_sys->s.n_threads = var_InheritInteger(p_this, "dav1d-thread-frames");
438
1.97k
    if (p_sys->s.n_threads == 0)
439
1.97k
        p_sys->s.n_threads = __MAX(1, vlc_GetCPUCount());
440
441
1.97k
#if DAV1D_API_VERSION_MAJOR > 6 || DAV1D_API_VERSION_MINOR >= 7
442
    // after dav1d 1.0.0
443
1.97k
    p_sys->s.max_frame_delay = dav1d_get_frame_delay( &p_sys->s );
444
#else // 1.0.0
445
    // corresponds to c->n_fc when max_frame_delay is 0 in dav1d 1.0.0
446
    static const uint8_t fc_lut[49] = {
447
        1,                                     /*     1 */
448
        2, 2, 2,                               /*  2- 4 */
449
        3, 3, 3, 3, 3,                         /*  5- 9 */
450
        4, 4, 4, 4, 4, 4, 4,                   /* 10-16 */
451
        5, 5, 5, 5, 5, 5, 5, 5, 5,             /* 17-25 */
452
        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,       /* 26-36 */
453
        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 37-49 */
454
    };
455
    if (p_sys->s.n_threads >= 50)
456
        p_sys->s.max_frame_delay = 8;
457
    else
458
        p_sys->s.max_frame_delay = fc_lut[p_sys->s.n_threads - 1];
459
#endif
460
461
#else // before dav1d 1.0.0
462
    p_sys->s.n_tile_threads = var_InheritInteger(p_this, "dav1d-thread-tiles");
463
    if (p_sys->s.n_tile_threads == 0)
464
        p_sys->s.n_tile_threads = VLC_CLIP(vlc_GetCPUCount(), 1, 4);
465
    p_sys->s.n_frame_threads = var_InheritInteger(p_this, "dav1d-thread-frames");
466
    if (p_sys->s.n_frame_threads == 0)
467
        p_sys->s.n_frame_threads = __MAX(1, vlc_GetCPUCount());
468
#endif
469
1.97k
    p_sys->s.all_layers = var_InheritBool( p_this, "dav1d-all-layers" );
470
1.97k
    p_sys->s.allocator.cookie = dec;
471
1.97k
    p_sys->s.allocator.alloc_picture_callback = NewPicture;
472
1.97k
    p_sys->s.allocator.release_picture_callback = FreePicture;
473
474
1.97k
    av1_OBU_sequence_header_t *sequence_hdr = NULL;
475
1.97k
    if (dec->fmt_in->i_extra > 4)
476
1.41k
    {
477
        // in ISOBMFF/WebM/Matroska the first 4 bytes are from the AV1CodecConfigurationRecord
478
        // and then one or more OBU
479
1.41k
        const uint8_t *obu_start = ((const uint8_t*) dec->fmt_in->p_extra) + 4;
480
1.41k
        int obu_size = dec->fmt_in->i_extra - 4;
481
1.41k
        if (AV1_OBUIsValid(obu_start, obu_size) && AV1_OBUGetType(obu_start) == AV1_OBU_SEQUENCE_HEADER)
482
1.40k
            sequence_hdr = AV1_OBU_parse_sequence_header(obu_start, obu_size);
483
1.41k
    }
484
485
1.97k
    dec->fmt_out.video.i_frame_rate = dec->fmt_in->video.i_frame_rate;
486
1.97k
    dec->fmt_out.video.i_frame_rate_base = dec->fmt_in->video.i_frame_rate_base;
487
488
1.97k
    bool super_res = false;
489
1.97k
    if (!sequence_hdr)
490
577
    {
491
577
        dec->fmt_out.i_codec = VLC_CODEC_I420;
492
577
        dec->fmt_out.video.i_width = dec->fmt_in->video.i_width;
493
577
        dec->fmt_out.video.i_height = dec->fmt_in->video.i_height;
494
577
    }
495
1.39k
    else
496
1.39k
    {
497
        // use the sequence header to get a better chroma to start with
498
1.39k
        dec->fmt_out.i_codec = AV1_get_chroma(sequence_hdr);
499
500
1.39k
        AV1_get_frame_max_dimensions(sequence_hdr, &dec->fmt_out.video.i_width, &dec->fmt_out.video.i_height);
501
502
1.39k
        if (dec->fmt_out.video.transfer == TRANSFER_FUNC_UNDEF)
503
1.39k
            AV1_get_colorimetry(sequence_hdr, &dec->fmt_out.video.primaries, &dec->fmt_out.video.transfer,
504
1.39k
                                &dec->fmt_out.video.space, &dec->fmt_out.video.color_range);
505
1.39k
        super_res = AV1_get_super_res(sequence_hdr);
506
1.39k
    }
507
1.97k
    dec->fmt_out.video.i_visible_width  = dec->fmt_out.video.i_width;
508
1.97k
    dec->fmt_out.video.i_visible_height = dec->fmt_out.video.i_height;
509
510
1.97k
    if (dav1d_open(&p_sys->c, &p_sys->s) < 0)
511
0
    {
512
0
        msg_Err(p_this, "Could not open the Dav1d decoder");
513
0
        return VLC_EGENERIC;
514
0
    }
515
516
1.97k
#if DAV1D_API_VERSION_MAJOR >= 6
517
1.97k
    msg_Dbg(p_this, "Using dav1d version %s with %d threads",
518
1.97k
            dav1d_version(), p_sys->s.n_threads);
519
520
1.97k
    dec->i_extra_picture_buffers = p_sys->s.max_frame_delay;
521
#else
522
    msg_Dbg(p_this, "Using dav1d version %s with %d/%d frame/tile threads",
523
            dav1d_version(), p_sys->s.n_frame_threads, p_sys->s.n_tile_threads);
524
525
    dec->i_extra_picture_buffers = (p_sys->s.n_frame_threads - 1);
526
#endif
527
1.97k
    if (super_res)
528
        // dav1d seems to buffer more pictures when using super resolution
529
223
        dec->i_extra_picture_buffers += dec->i_extra_picture_buffers > 1 ? 2 : 1;
530
1.97k
    dec->fmt_out.video.i_width  = (dec->fmt_out.video.i_width + 0x7F) & ~0x7F;
531
1.97k
    dec->fmt_out.video.i_height = (dec->fmt_out.video.i_height + 0x7F) & ~0x7F;
532
533
1.97k
    dec->p_sys = p_sys;
534
535
1.97k
    if (dec->fmt_in->video.i_sar_num > 0 && dec->fmt_in->video.i_sar_den > 0) {
536
16
        dec->fmt_out.video.i_sar_num = dec->fmt_in->video.i_sar_num;
537
16
        dec->fmt_out.video.i_sar_den = dec->fmt_in->video.i_sar_den;
538
16
    }
539
1.97k
    dec->fmt_out.video.primaries   = dec->fmt_in->video.primaries;
540
1.97k
    dec->fmt_out.video.transfer    = dec->fmt_in->video.transfer;
541
1.97k
    dec->fmt_out.video.space       = dec->fmt_in->video.space;
542
1.97k
    dec->fmt_out.video.color_range = dec->fmt_in->video.color_range;
543
1.97k
    dec->fmt_out.video.mastering   = dec->fmt_in->video.mastering;
544
1.97k
    dec->fmt_out.video.lighting    = dec->fmt_in->video.lighting;
545
546
1.97k
    if (sequence_hdr != NULL)
547
1.39k
    {
548
        // we have the proper chroma, make sure we can use it
549
1.39k
        AV1_release_sequence_header(sequence_hdr);
550
551
1.39k
        if (decoder_UpdateVideoFormat(dec) != 0)
552
0
        {
553
0
            CloseDecoder(VLC_OBJECT(dec));
554
0
            return VLC_EGENERIC;
555
0
        }
556
1.39k
    }
557
1.97k
    dec->pf_decode = Decode;
558
1.97k
    dec->pf_flush = FlushDecoder;
559
560
1.97k
    cc_Init(&p_sys->cc);
561
562
1.97k
    return VLC_SUCCESS;
563
1.97k
}
564
565
/*****************************************************************************
566
 * CloseDecoder: decoder destruction
567
 *****************************************************************************/
568
static void CloseDecoder(vlc_object_t *p_this)
569
1.97k
{
570
1.97k
    decoder_t *dec = (decoder_t *)p_this;
571
1.97k
    decoder_sys_t *p_sys = dec->p_sys;
572
573
    /* Flush decoder */
574
1.97k
    FlushDecoder(dec);
575
576
1.97k
    dav1d_close(&p_sys->c);
577
1.97k
}