/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 | 166 | vlc_module_begin () |
61 | 83 | set_shortname("dav1d") |
62 | 83 | set_description(N_("Dav1d video decoder")) |
63 | 83 | set_capability("video decoder", 10000) |
64 | 166 | set_callbacks(OpenDecoder, CloseDecoder) |
65 | 83 | set_subcategory(SUBCAT_INPUT_VCODEC) |
66 | | |
67 | 83 | #if DAV1D_API_VERSION_MAJOR >= 6 |
68 | 83 | add_integer_with_range("dav1d-thread-frames", 0, 0, DAV1D_MAX_THREADS, |
69 | 83 | THREAD_FRAMES_TEXT, THREAD_FRAMES_LONGTEXT) |
70 | 83 | 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 | 83 | add_bool( "dav1d-all-layers", false, "Display all spatial layers", NULL ) |
78 | 83 | 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 | 96.5k | { |
97 | 96.5k | VLC_UNUSED(p); |
98 | 96.5k | free(userdata); |
99 | 96.5k | } |
100 | | |
101 | | static vlc_fourcc_t FindVlcChroma(const Dav1dPicture *img) |
102 | 4.15k | { |
103 | 4.15k | static const vlc_fourcc_t chroma_table_rgb[] = { VLC_CODEC_GBR_PLANAR, VLC_CODEC_GBR_PLANAR_10L, VLC_CODEC_GBR_PLANAR_12L }; |
104 | 4.15k | static const vlc_fourcc_t chroma_table[][3] = { |
105 | 4.15k | [DAV1D_PIXEL_LAYOUT_I400] = { VLC_CODEC_GREY, VLC_CODEC_GREY_10L, VLC_CODEC_GREY_12L }, |
106 | 4.15k | [DAV1D_PIXEL_LAYOUT_I420] = { VLC_CODEC_I420, VLC_CODEC_I420_10L, VLC_CODEC_I420_12L }, |
107 | 4.15k | [DAV1D_PIXEL_LAYOUT_I422] = { VLC_CODEC_I422, VLC_CODEC_I422_10L, VLC_CODEC_I422_12L }, |
108 | 4.15k | [DAV1D_PIXEL_LAYOUT_I444] = { VLC_CODEC_I444, VLC_CODEC_I444_10L, VLC_CODEC_I444_12L }, |
109 | 4.15k | }; |
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 | 4.15k | if( img->p.layout == DAV1D_PIXEL_LAYOUT_I444 && |
114 | 435 | img->seq_hdr->mtrx == DAV1D_MC_IDENTITY && |
115 | 48 | img->seq_hdr->pri == DAV1D_COLOR_PRI_BT709 && |
116 | 40 | img->seq_hdr->trc == DAV1D_TRC_SRGB ) |
117 | 40 | { |
118 | 40 | if( img->seq_hdr->hbd >= (int)ARRAY_SIZE(chroma_table_rgb) ) |
119 | 0 | return 0; |
120 | 40 | return chroma_table_rgb[img->seq_hdr->hbd]; |
121 | 40 | } |
122 | | |
123 | 4.11k | if( img->seq_hdr->layout < 0 || img->seq_hdr->layout >= (int)ARRAY_SIZE(chroma_table) ) |
124 | 0 | return 0; |
125 | 4.11k | if( img->seq_hdr->hbd >= (int)ARRAY_SIZE(chroma_table[0]) ) |
126 | 0 | return 0; |
127 | | |
128 | 4.11k | return chroma_table[img->seq_hdr->layout][img->seq_hdr->hbd]; |
129 | 4.11k | } |
130 | | |
131 | | static void UpdateDecoderOutput(decoder_t *dec, const Dav1dSequenceHeader *seq_hdr) |
132 | 4.15k | { |
133 | 4.15k | video_format_t *v = &dec->fmt_out.video; |
134 | | |
135 | 4.15k | if( !v->i_sar_num || !v->i_sar_den ) |
136 | 7 | { |
137 | 7 | v->i_sar_num = 1; |
138 | 7 | v->i_sar_den = 1; |
139 | 7 | } |
140 | | |
141 | 4.15k | if(dec->fmt_in->video.primaries == COLOR_PRIMARIES_UNDEF && seq_hdr) |
142 | 3.65k | { |
143 | 3.65k | v->primaries = iso_23001_8_cp_to_vlc_primaries(seq_hdr->pri); |
144 | 3.65k | v->transfer = iso_23001_8_tc_to_vlc_xfer(seq_hdr->trc); |
145 | 3.65k | v->space = iso_23001_8_mc_to_vlc_coeffs(seq_hdr->mtrx); |
146 | 3.65k | v->color_range = seq_hdr->color_range ? COLOR_RANGE_FULL : COLOR_RANGE_LIMITED; |
147 | 3.65k | } |
148 | 4.15k | } |
149 | | |
150 | | static int NewPicture(Dav1dPicture *img, void *cookie) |
151 | 4.15k | { |
152 | 4.15k | decoder_t *dec = cookie; |
153 | 4.15k | decoder_sys_t *p_sys = dec->p_sys; |
154 | | |
155 | 4.15k | video_format_t *v = &dec->fmt_out.video; |
156 | | |
157 | 4.15k | v->i_visible_width = img->seq_hdr->max_width; |
158 | 4.15k | v->i_visible_height = img->seq_hdr->max_height; |
159 | | |
160 | 4.15k | UpdateDecoderOutput(dec, img->seq_hdr); |
161 | | |
162 | 4.15k | const Dav1dMasteringDisplay *md = img->mastering_display; |
163 | 4.15k | 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 | 4.15k | const Dav1dContentLightLevel *cll = img->content_light; |
183 | 4.15k | 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 | 4.15k | v->projection_mode = dec->fmt_in->video.projection_mode; |
190 | 4.15k | v->multiview_mode = dec->fmt_in->video.multiview_mode; |
191 | 4.15k | v->pose = dec->fmt_in->video.pose; |
192 | 4.15k | dec->fmt_out.i_codec = FindVlcChroma(img); |
193 | 4.15k | if (unlikely(dec->fmt_out.i_codec == 0)) |
194 | 0 | return -1; |
195 | | |
196 | 4.15k | v->i_width = (img->seq_hdr->max_width + 0x7F) & ~0x7F; |
197 | 4.15k | v->i_height = (img->seq_hdr->max_height + 0x7F) & ~0x7F; |
198 | 4.15k | v->i_chroma = dec->fmt_out.i_codec; |
199 | | |
200 | 4.15k | #if DAV1D_API_VERSION_MAJOR >= 6 |
201 | 4.15k | 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 | 4.15k | if (img->seq_hdr->super_res) |
206 | | // dav1d seems to buffer more pictures when using super resolution |
207 | 1.05k | dec->i_extra_picture_buffers += dec->i_extra_picture_buffers > 1 ? 2 : 1; |
208 | | |
209 | 4.15k | if (decoder_UpdateVideoFormat(dec) == 0) |
210 | 4.15k | { |
211 | 4.15k | picture_t *pic; |
212 | 4.15k | pic = decoder_NewPicture(dec); |
213 | 4.15k | if (unlikely(pic == NULL)) |
214 | 3 | return -1; |
215 | | |
216 | 4.15k | img->data[0] = pic->p[0].p_pixels; |
217 | 4.15k | img->stride[0] = pic->p[0].i_pitch; |
218 | 4.15k | img->data[1] = pic->p[1].p_pixels; |
219 | 4.15k | img->data[2] = pic->p[2].p_pixels; |
220 | 4.15k | assert(pic->p[1].i_pitch == pic->p[2].i_pitch); |
221 | 4.15k | img->stride[1] = pic->p[1].i_pitch; |
222 | | |
223 | 4.15k | img->allocator_data = pic; |
224 | 4.15k | return 0; |
225 | 4.15k | } |
226 | 0 | return -1; |
227 | 4.15k | } |
228 | | |
229 | | static void ExtractCaptions(decoder_t *dec, const Dav1dPicture *img) |
230 | 2.04k | { |
231 | 2.04k | decoder_sys_t *p_sys = dec->p_sys; |
232 | 2.04k | const struct user_data_s *userdata = (struct user_data_s *) img->m.user_data.data; |
233 | 2.04k | const Dav1dITUTT35 *itu_t35 = img->itut_t35; |
234 | 2.04k | 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 | 2.04k | } |
260 | | |
261 | | static void FreePicture(Dav1dPicture *data, void *cookie) |
262 | 4.15k | { |
263 | 4.15k | picture_t *pic = data->allocator_data; |
264 | 4.15k | decoder_t *dec = cookie; |
265 | 4.15k | VLC_UNUSED(dec); |
266 | 4.15k | picture_Release(pic); |
267 | 4.15k | } |
268 | | |
269 | | /**************************************************************************** |
270 | | * Flush: clears decoder between seeks |
271 | | ****************************************************************************/ |
272 | | |
273 | | static void FlushDecoder(decoder_t *dec) |
274 | 5.13k | { |
275 | 5.13k | decoder_sys_t *p_sys = dec->p_sys; |
276 | 5.13k | dav1d_flush(p_sys->c); |
277 | 5.13k | cc_Flush(&p_sys->cc); |
278 | 5.13k | } |
279 | | |
280 | | static void release_block(const uint8_t *buf, void *b) |
281 | 401k | { |
282 | 401k | VLC_UNUSED(buf); |
283 | 401k | block_t *block = b; |
284 | 401k | block_Release(block); |
285 | 401k | } |
286 | | |
287 | | /**************************************************************************** |
288 | | * Decode: the whole thing |
289 | | ****************************************************************************/ |
290 | | static int Decode(decoder_t *dec, block_t *block) |
291 | 854k | { |
292 | 854k | decoder_sys_t *p_sys = dec->p_sys; |
293 | | |
294 | 854k | if (block && block->i_flags & (BLOCK_FLAG_CORRUPTED)) |
295 | 0 | { |
296 | 0 | block_Release(block); |
297 | 0 | return VLCDEC_SUCCESS; |
298 | 0 | } |
299 | | |
300 | 854k | bool b_eos = false; |
301 | 854k | Dav1dData data; |
302 | 854k | Dav1dData *p_data = NULL; |
303 | | |
304 | 854k | if (block) |
305 | 401k | { |
306 | 401k | p_data = &data; |
307 | 401k | if (unlikely(dav1d_data_wrap(&data, block->p_buffer, block->i_buffer, |
308 | 401k | release_block, block) != 0)) |
309 | 0 | { |
310 | 0 | block_Release(block); |
311 | 0 | return VLCDEC_ECRITICAL; |
312 | 0 | } |
313 | | |
314 | 401k | p_data->m.timestamp = block->i_pts == VLC_TICK_INVALID ? block->i_dts : block->i_pts; |
315 | 401k | if(block->i_dts != p_data->m.timestamp) |
316 | 96.5k | { |
317 | 96.5k | struct user_data_s *userdata = malloc(sizeof(*userdata)); |
318 | 96.5k | if(unlikely(userdata == NULL || |
319 | 96.5k | 0 != dav1d_data_wrap_user_data(&data, (const uint8_t *) userdata, |
320 | 96.5k | FreeUserData_Handler, userdata))) |
321 | 0 | { |
322 | 0 | free(userdata); |
323 | 0 | dav1d_data_unref(&data); |
324 | 0 | return VLCDEC_ECRITICAL; |
325 | 0 | } |
326 | 96.5k | userdata->dts = block->i_dts; |
327 | 96.5k | } |
328 | | |
329 | 401k | b_eos = (block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE); |
330 | 401k | } |
331 | | |
332 | 854k | bool b_draining = false; |
333 | 854k | int i_ret = VLCDEC_SUCCESS; |
334 | 854k | int res; |
335 | 1.30M | do { |
336 | 1.30M | if( p_data ) |
337 | 402k | { |
338 | 402k | res = dav1d_send_data(p_sys->c, p_data); |
339 | 402k | if (res < 0 && res != DAV1D_ERR(EAGAIN)) |
340 | 46.4k | { |
341 | 46.4k | 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 | 46.4k | i_ret = res == DAV1D_ERR(EINVAL) ? VLCDEC_SUCCESS : VLCDEC_ECRITICAL; |
354 | 46.4k | break; |
355 | 46.4k | } |
356 | 402k | } |
357 | | |
358 | 1.30M | bool b_output_error = false; |
359 | 1.25M | do |
360 | 1.26M | { |
361 | 1.26M | Dav1dPicture img = { 0 }; |
362 | 1.26M | res = dav1d_get_picture(p_sys->c, &img); |
363 | 1.26M | if (res == 0) |
364 | 2.04k | { |
365 | 2.04k | picture_t *_pic = img.allocator_data; |
366 | 2.04k | picture_t *pic = picture_Clone(_pic); |
367 | 2.04k | 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 | 2.04k | pic->b_progressive = true; /* codec does not support interlacing */ |
375 | 2.04k | pic->date = img.m.timestamp; |
376 | 2.04k | decoder_QueueVideo(dec, pic); |
377 | 2.04k | ExtractCaptions(dec, &img); |
378 | 2.04k | 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 | 2.04k | if(p_data != NULL && !b_eos) |
384 | 772 | break; |
385 | 2.04k | } |
386 | 1.25M | else if (res == DAV1D_ERR(EAGAIN)) |
387 | 1.25M | { |
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 | 1.25M | if (p_data && p_data->sz != 0) |
392 | 4 | res = 0; |
393 | 1.25M | break; |
394 | 1.25M | } |
395 | 1.54k | else |
396 | 1.54k | { |
397 | 1.54k | msg_Warn(dec, "Decoder error %d!", res); |
398 | 1.54k | b_output_error = true; |
399 | 1.54k | break; |
400 | 1.54k | } |
401 | 1.26M | } while(res == 0); |
402 | | |
403 | 1.25M | if(b_output_error) |
404 | 1.54k | break; |
405 | | |
406 | | /* on drain, we must ignore the 1st EAGAIN */ |
407 | 1.25M | if(!b_draining && (res == DAV1D_ERR(EAGAIN) || res == 0) |
408 | 806k | && (p_data == NULL||b_eos)) |
409 | 451k | { |
410 | 451k | b_draining = true; |
411 | 451k | res = 0; |
412 | 451k | } |
413 | 1.25M | } while (res == 0 && ((p_data && p_data->sz != 0) || b_draining)); |
414 | | |
415 | 854k | if(p_data && p_data->sz > 0) |
416 | 46.5k | dav1d_data_unref(p_data); |
417 | | |
418 | 854k | return i_ret; |
419 | 854k | } |
420 | | |
421 | | /***************************************************************************** |
422 | | * OpenDecoder: probe the decoder |
423 | | *****************************************************************************/ |
424 | | static int OpenDecoder(vlc_object_t *p_this) |
425 | 217k | { |
426 | 217k | decoder_t *dec = (decoder_t *)p_this; |
427 | | |
428 | 217k | if (dec->fmt_in->i_codec != VLC_CODEC_AV1) |
429 | 212k | return VLC_EGENERIC; |
430 | | |
431 | 5.13k | decoder_sys_t *p_sys = vlc_obj_malloc(p_this, sizeof(*p_sys)); |
432 | 5.13k | if (!p_sys) |
433 | 0 | return VLC_ENOMEM; |
434 | | |
435 | 5.13k | dav1d_default_settings(&p_sys->s); |
436 | 5.13k | #if DAV1D_API_VERSION_MAJOR >= 6 |
437 | 5.13k | p_sys->s.n_threads = var_InheritInteger(p_this, "dav1d-thread-frames"); |
438 | 5.13k | if (p_sys->s.n_threads == 0) |
439 | 5.13k | p_sys->s.n_threads = __MAX(1, vlc_GetCPUCount()); |
440 | | |
441 | 5.13k | #if DAV1D_API_VERSION_MAJOR > 6 || DAV1D_API_VERSION_MINOR >= 7 |
442 | | // after dav1d 1.0.0 |
443 | 5.13k | 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 | 5.13k | p_sys->s.all_layers = var_InheritBool( p_this, "dav1d-all-layers" ); |
470 | 5.13k | p_sys->s.allocator.cookie = dec; |
471 | 5.13k | p_sys->s.allocator.alloc_picture_callback = NewPicture; |
472 | 5.13k | p_sys->s.allocator.release_picture_callback = FreePicture; |
473 | | |
474 | 5.13k | av1_OBU_sequence_header_t *sequence_hdr = NULL; |
475 | 5.13k | if (dec->fmt_in->i_extra > 4) |
476 | 4.10k | { |
477 | | // in ISOBMFF/WebM/Matroska the first 4 bytes are from the AV1CodecConfigurationRecord |
478 | | // and then one or more OBU |
479 | 4.10k | const uint8_t *obu_start = ((const uint8_t*) dec->fmt_in->p_extra) + 4; |
480 | 4.10k | int obu_size = dec->fmt_in->i_extra - 4; |
481 | 4.10k | if (AV1_OBUIsValid(obu_start, obu_size) && AV1_OBUGetType(obu_start) == AV1_OBU_SEQUENCE_HEADER) |
482 | 4.09k | sequence_hdr = AV1_OBU_parse_sequence_header(obu_start, obu_size); |
483 | 4.10k | } |
484 | | |
485 | 5.13k | dec->fmt_out.video.i_frame_rate = dec->fmt_in->video.i_frame_rate; |
486 | 5.13k | dec->fmt_out.video.i_frame_rate_base = dec->fmt_in->video.i_frame_rate_base; |
487 | | |
488 | 5.13k | bool super_res = false; |
489 | 5.13k | if (!sequence_hdr) |
490 | 1.10k | { |
491 | 1.10k | dec->fmt_out.i_codec = VLC_CODEC_I420; |
492 | 1.10k | dec->fmt_out.video.i_width = dec->fmt_in->video.i_width; |
493 | 1.10k | dec->fmt_out.video.i_height = dec->fmt_in->video.i_height; |
494 | 1.10k | } |
495 | 4.02k | else |
496 | 4.02k | { |
497 | | // use the sequence header to get a better chroma to start with |
498 | 4.02k | dec->fmt_out.i_codec = AV1_get_chroma(sequence_hdr); |
499 | | |
500 | 4.02k | AV1_get_frame_max_dimensions(sequence_hdr, &dec->fmt_out.video.i_width, &dec->fmt_out.video.i_height); |
501 | | |
502 | 4.02k | if (dec->fmt_out.video.transfer == TRANSFER_FUNC_UNDEF) |
503 | 4.02k | AV1_get_colorimetry(sequence_hdr, &dec->fmt_out.video.primaries, &dec->fmt_out.video.transfer, |
504 | 4.02k | &dec->fmt_out.video.space, &dec->fmt_out.video.color_range); |
505 | 4.02k | super_res = AV1_get_super_res(sequence_hdr); |
506 | 4.02k | } |
507 | 5.13k | dec->fmt_out.video.i_visible_width = dec->fmt_out.video.i_width; |
508 | 5.13k | dec->fmt_out.video.i_visible_height = dec->fmt_out.video.i_height; |
509 | | |
510 | 5.13k | 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 | 5.13k | #if DAV1D_API_VERSION_MAJOR >= 6 |
517 | 5.13k | msg_Dbg(p_this, "Using dav1d version %s with %d threads", |
518 | 5.13k | dav1d_version(), p_sys->s.n_threads); |
519 | | |
520 | 5.13k | 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 | 5.13k | if (super_res) |
528 | | // dav1d seems to buffer more pictures when using super resolution |
529 | 697 | dec->i_extra_picture_buffers += dec->i_extra_picture_buffers > 1 ? 2 : 1; |
530 | 5.13k | dec->fmt_out.video.i_width = (dec->fmt_out.video.i_width + 0x7F) & ~0x7F; |
531 | 5.13k | dec->fmt_out.video.i_height = (dec->fmt_out.video.i_height + 0x7F) & ~0x7F; |
532 | | |
533 | 5.13k | dec->p_sys = p_sys; |
534 | | |
535 | 5.13k | if (dec->fmt_in->video.i_sar_num > 0 && dec->fmt_in->video.i_sar_den > 0) { |
536 | 738 | dec->fmt_out.video.i_sar_num = dec->fmt_in->video.i_sar_num; |
537 | 738 | dec->fmt_out.video.i_sar_den = dec->fmt_in->video.i_sar_den; |
538 | 738 | } |
539 | 5.13k | dec->fmt_out.video.primaries = dec->fmt_in->video.primaries; |
540 | 5.13k | dec->fmt_out.video.transfer = dec->fmt_in->video.transfer; |
541 | 5.13k | dec->fmt_out.video.space = dec->fmt_in->video.space; |
542 | 5.13k | dec->fmt_out.video.color_range = dec->fmt_in->video.color_range; |
543 | 5.13k | dec->fmt_out.video.mastering = dec->fmt_in->video.mastering; |
544 | 5.13k | dec->fmt_out.video.lighting = dec->fmt_in->video.lighting; |
545 | | |
546 | 5.13k | if (sequence_hdr != NULL) |
547 | 4.02k | { |
548 | | // we have the proper chroma, make sure we can use it |
549 | 4.02k | AV1_release_sequence_header(sequence_hdr); |
550 | | |
551 | 4.02k | if (decoder_UpdateVideoFormat(dec) != 0) |
552 | 0 | { |
553 | 0 | CloseDecoder(VLC_OBJECT(dec)); |
554 | 0 | return VLC_EGENERIC; |
555 | 0 | } |
556 | 4.02k | } |
557 | 5.13k | dec->pf_decode = Decode; |
558 | 5.13k | dec->pf_flush = FlushDecoder; |
559 | | |
560 | 5.13k | cc_Init(&p_sys->cc); |
561 | | |
562 | 5.13k | return VLC_SUCCESS; |
563 | 5.13k | } |
564 | | |
565 | | /***************************************************************************** |
566 | | * CloseDecoder: decoder destruction |
567 | | *****************************************************************************/ |
568 | | static void CloseDecoder(vlc_object_t *p_this) |
569 | 5.13k | { |
570 | 5.13k | decoder_t *dec = (decoder_t *)p_this; |
571 | 5.13k | decoder_sys_t *p_sys = dec->p_sys; |
572 | | |
573 | | /* Flush decoder */ |
574 | 5.13k | FlushDecoder(dec); |
575 | | |
576 | 5.13k | dav1d_close(&p_sys->c); |
577 | 5.13k | } |