Coverage Report

Created: 2026-10-28 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/dovi_rpudec.c
Line
Count
Source
1
/*
2
 * Dolby Vision RPU decoder
3
 *
4
 * Copyright (C) 2021 Jan Ekström
5
 * Copyright (C) 2021-2024 Niklas Haas
6
 *
7
 * This file is part of FFmpeg.
8
 *
9
 * FFmpeg is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * FFmpeg 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 GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with FFmpeg; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
 */
23
24
#include "libavutil/mem.h"
25
#include "libavutil/crc.h"
26
27
#include "avcodec.h"
28
#include "dovi_rpu.h"
29
#include "golomb.h"
30
#include "get_bits.h"
31
#include "libavutil/refstruct.h"
32
33
int ff_dovi_get_metadata(DOVIContext *s, AVDOVIMetadata **out_metadata)
34
50.6k
{
35
50.6k
    AVDOVIMetadata *dovi;
36
50.6k
    size_t dovi_size;
37
38
50.6k
    if (!s->mapping || !s->color)
39
50.5k
        return 0; /* incomplete dovi metadata */
40
41
81
    dovi = av_dovi_metadata_alloc(&dovi_size);
42
81
    if (!dovi)
43
0
        return AVERROR(ENOMEM);
44
45
    /* Copy only the parts of these structs known to us at compiler-time. */
46
243
#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last))
47
81
    COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, ext_mapping_idc_5_7);
48
81
    COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq_pivots);
49
81
    COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal);
50
51
81
    if (s->ext_blocks) {
52
60
        const DOVIExt *ext = s->ext_blocks;
53
60
        size_t ext_sz = FFMIN(sizeof(AVDOVIDmData), dovi->ext_block_size);
54
60
        for (int i = 0; i < ext->num_static; i++)
55
0
            memcpy(av_dovi_get_ext(dovi, dovi->num_ext_blocks++), &ext->dm_static[i], ext_sz);
56
375
        for (int i = 0; i < ext->num_dynamic; i++)
57
315
            memcpy(av_dovi_get_ext(dovi, dovi->num_ext_blocks++), &ext->dm_dynamic[i], ext_sz);
58
60
    }
59
60
81
    *out_metadata = dovi;
61
81
    return dovi_size;
62
81
}
63
64
int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame)
65
50.6k
{
66
50.6k
    AVFrameSideData *sd;
67
50.6k
    AVDOVIMetadata *dovi;
68
50.6k
    AVBufferRef *buf;
69
50.6k
    int size;
70
71
50.6k
    size = ff_dovi_get_metadata(s, &dovi);
72
50.6k
    if (size <= 0)
73
50.5k
        return size;
74
75
81
    buf = av_buffer_create((uint8_t *) dovi, size, NULL, NULL, 0);
76
81
    if (!buf) {
77
0
        av_free(dovi);
78
0
        return AVERROR(ENOMEM);
79
0
    }
80
81
81
    sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf);
82
81
    if (!sd) {
83
0
        av_buffer_unref(&buf);
84
0
        return AVERROR(ENOMEM);
85
0
    }
86
87
81
    return 0;
88
81
}
89
90
static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
91
20.1k
{
92
20.1k
    uint64_t ipart;
93
20.1k
    union { uint32_t u32; float f32; } fpart;
94
95
20.1k
    switch (hdr->coef_data_type) {
96
540
    case RPU_COEFF_FIXED:
97
540
        ipart = get_ue_golomb_long(gb);
98
540
        fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
99
540
        return (ipart << hdr->coef_log2_denom) | fpart.u32;
100
101
19.6k
    case RPU_COEFF_FLOAT:
102
19.6k
        fpart.u32 = get_bits_long(gb, 32);
103
19.6k
        return fpart.f32 * (1LL << hdr->coef_log2_denom);
104
20.1k
    }
105
106
0
    return 0; /* unreachable */
107
20.1k
}
108
109
static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr)
110
74.4k
{
111
74.4k
    int64_t ipart;
112
74.4k
    union { uint32_t u32; float f32; } fpart;
113
114
74.4k
    switch (hdr->coef_data_type) {
115
13.8k
    case RPU_COEFF_FIXED:
116
13.8k
        ipart = get_se_golomb_long(gb);
117
13.8k
        fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom);
118
13.8k
        return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32;
119
120
60.5k
    case RPU_COEFF_FLOAT:
121
60.5k
        fpart.u32 = get_bits_long(gb, 32);
122
60.5k
        return fpart.f32 * (1LL << hdr->coef_log2_denom);
123
74.4k
    }
124
125
0
    return 0; /* unreachable */
126
74.4k
}
127
128
static inline unsigned get_variable_bits(GetBitContext *gb, int n)
129
0
{
130
0
    unsigned int value = get_bits(gb, n);
131
0
    int read_more = get_bits1(gb);
132
0
    while (read_more) {
133
0
        value = (value + 1) << n;
134
0
        value |= get_bits(gb, n);
135
0
        read_more = get_bits1(gb);
136
0
    }
137
0
    return value;
138
0
}
139
140
#define VALIDATE(VAR, MIN, MAX)                                                 \
141
173k
    do {                                                                        \
142
173k
        if (VAR < MIN || VAR > MAX) {                                           \
143
8.83k
            av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: "           \
144
8.83k
                   #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR);               \
145
8.83k
            ff_dovi_ctx_unref(s);                                               \
146
8.83k
            return AVERROR_INVALIDDATA;                                         \
147
8.83k
        }                                                                       \
148
173k
    } while (0)
149
150
static int parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm)
151
11.9k
{
152
11.9k
    switch (dm->level) {
153
7
    case 1:
154
7
        dm->l1.min_pq = get_bits(gb, 12);
155
7
        dm->l1.max_pq = get_bits(gb, 12);
156
7
        dm->l1.avg_pq = get_bits(gb, 12);
157
7
        break;
158
24
    case 2:
159
24
        dm->l2.target_max_pq = get_bits(gb, 12);
160
24
        dm->l2.trim_slope = get_bits(gb, 12);
161
24
        dm->l2.trim_offset = get_bits(gb, 12);
162
24
        dm->l2.trim_power = get_bits(gb, 12);
163
24
        dm->l2.trim_chroma_weight = get_bits(gb, 12);
164
24
        dm->l2.trim_saturation_gain = get_bits(gb, 12);
165
24
        dm->l2.ms_weight = get_sbits(gb, 13);
166
24
        VALIDATE(dm->l2.ms_weight, -1, 4095);
167
17
        break;
168
33
    case 4:
169
33
        dm->l4.anchor_pq = get_bits(gb, 12);
170
33
        dm->l4.anchor_power = get_bits(gb, 12);
171
33
        break;
172
4
    case 5:
173
4
        dm->l5.left_offset = get_bits(gb, 13);
174
4
        dm->l5.right_offset = get_bits(gb, 13);
175
4
        dm->l5.top_offset = get_bits(gb, 13);
176
4
        dm->l5.bottom_offset = get_bits(gb, 13);
177
4
        break;
178
8
    case 6:
179
8
        dm->l6.max_luminance = get_bits(gb, 16);
180
8
        dm->l6.min_luminance = get_bits(gb, 16);
181
8
        dm->l6.max_cll = get_bits(gb, 16);
182
8
        dm->l6.max_fall = get_bits(gb, 16);
183
8
        break;
184
309
    case 255:
185
309
        dm->l255.dm_run_mode = get_bits(gb, 8);
186
309
        dm->l255.dm_run_version = get_bits(gb, 8);
187
1.54k
        for (int i = 0; i < 4; i++)
188
1.23k
            dm->l255.dm_debug[i] = get_bits(gb, 8);
189
309
        break;
190
11.5k
    default:
191
11.5k
        avpriv_request_sample(s->logctx, "Dolby Vision DM v1 level %u", dm->level);
192
11.9k
    }
193
194
11.9k
    return 0;
195
11.9k
}
196
197
static AVCIExy get_cie_xy(GetBitContext *gb)
198
412
{
199
412
    AVCIExy xy;
200
412
    const int denom = 32767;
201
412
    xy.x = av_make_q(get_sbits(gb, 16), denom);
202
412
    xy.y = av_make_q(get_sbits(gb, 16), denom);
203
412
    return xy;
204
412
}
205
206
static int parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm,
207
                        int ext_block_length)
208
22.8k
{
209
22.8k
    switch (dm->level) {
210
236
    case 3:
211
236
        dm->l3.min_pq_offset = get_bits(gb, 12);
212
236
        dm->l3.max_pq_offset = get_bits(gb, 12);
213
236
        dm->l3.avg_pq_offset = get_bits(gb, 12);
214
236
        break;
215
867
    case 8:
216
867
        dm->l8.target_display_index = get_bits(gb, 8);
217
867
        dm->l8.trim_slope = get_bits(gb, 12);
218
867
        dm->l8.trim_offset = get_bits(gb, 12);
219
867
        dm->l8.trim_power = get_bits(gb, 12);
220
867
        dm->l8.trim_chroma_weight = get_bits(gb, 12);
221
867
        dm->l8.trim_saturation_gain = get_bits(gb, 12);
222
867
        dm->l8.ms_weight = get_bits(gb, 12);
223
867
        if (ext_block_length < 12)
224
4
            break;
225
863
        dm->l8.target_mid_contrast = get_bits(gb, 12);
226
863
        if (ext_block_length < 13)
227
1
            break;
228
862
        dm->l8.clip_trim = get_bits(gb, 12);
229
862
        if (ext_block_length < 19)
230
4
            break;
231
6.00k
        for (int i = 0; i < 6; i++)
232
5.14k
            dm->l8.saturation_vector_field[i] = get_bits(gb, 8);
233
858
        if (ext_block_length < 25)
234
4
            break;
235
5.97k
        for (int i = 0; i < 6; i++)
236
5.12k
            dm->l8.hue_vector_field[i] = get_bits(gb, 8);
237
854
        break;
238
298
    case 9:
239
298
        dm->l9.source_primary_index = get_bits(gb, 8);
240
298
        if (ext_block_length < 17)
241
294
            break;
242
4
        dm->l9.source_display_primaries.prim.r = get_cie_xy(gb);
243
4
        dm->l9.source_display_primaries.prim.g = get_cie_xy(gb);
244
4
        dm->l9.source_display_primaries.prim.b = get_cie_xy(gb);
245
4
        dm->l9.source_display_primaries.wp = get_cie_xy(gb);
246
4
        break;
247
130
    case 10:
248
130
        dm->l10.target_display_index = get_bits(gb, 8);
249
130
        dm->l10.target_max_pq = get_bits(gb, 12);
250
130
        dm->l10.target_min_pq = get_bits(gb, 12);
251
130
        dm->l10.target_primary_index = get_bits(gb, 8);
252
130
        if (ext_block_length < 21)
253
31
            break;
254
99
        dm->l10.target_display_primaries.prim.r = get_cie_xy(gb);
255
99
        dm->l10.target_display_primaries.prim.g = get_cie_xy(gb);
256
99
        dm->l10.target_display_primaries.prim.b = get_cie_xy(gb);
257
99
        dm->l10.target_display_primaries.wp = get_cie_xy(gb);
258
99
        break;
259
23
    case 11:
260
23
        dm->l11.content_type = get_bits(gb, 8);
261
23
        dm->l11.whitepoint = get_bits(gb, 4);
262
23
        dm->l11.reference_mode_flag = get_bits1(gb);
263
23
        skip_bits(gb, 3); /* reserved */
264
23
        skip_bits(gb, 8); /* reserved */
265
23
        skip_bits(gb, 8); /* reserved */
266
23
        break;
267
5
    case 254:
268
5
        dm->l254.dm_mode = get_bits(gb, 8);
269
5
        dm->l254.dm_version_index = get_bits(gb, 8);
270
5
        break;
271
21.3k
    default:
272
21.3k
        avpriv_request_sample(s->logctx, "Dolby Vision DM v2 level %u", dm->level);
273
22.8k
    }
274
275
22.8k
    return 0;
276
22.8k
}
277
278
static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver,
279
                            int compression, int err_recognition)
280
4.01k
{
281
4.01k
    int num_ext_blocks, ext_block_length, start_pos, parsed_bits, ret;
282
4.01k
    DOVIExt *ext = s->ext_blocks;
283
284
4.01k
    num_ext_blocks = get_ue_golomb_31(gb);
285
4.01k
    align_get_bits(gb);
286
287
4.01k
    if (num_ext_blocks && !ext) {
288
2.04k
        ext = s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks));
289
2.04k
        if (!ext)
290
0
            return AVERROR(ENOMEM);
291
2.04k
    }
292
293
38.3k
    while (num_ext_blocks--) {
294
35.6k
        AVDOVIDmData dummy;
295
35.6k
        AVDOVIDmData *dm;
296
35.6k
        uint8_t level;
297
298
35.6k
        ext_block_length = get_ue_golomb_31(gb);
299
35.6k
        level = get_bits(gb, 8);
300
35.6k
        start_pos = get_bits_count(gb);
301
302
35.6k
        if (ff_dovi_rpu_extension_is_static(level)) {
303
2.78k
            if (compression) {
304
2.74k
                av_log(s->logctx, AV_LOG_WARNING, "Compressed DM RPU contains "
305
2.74k
                       "static extension block level %d\n", level);
306
2.74k
                if (err_recognition & (AV_EF_AGGRESSIVE | AV_EF_EXPLODE))
307
0
                    return AVERROR_INVALIDDATA;
308
2.74k
                dm = &dummy;
309
2.74k
            } else {
310
33
                if (ext->num_static >= FF_ARRAY_ELEMS(ext->dm_static))
311
1
                    return AVERROR_INVALIDDATA;
312
32
                dm = &ext->dm_static[ext->num_static++];
313
32
            }
314
32.9k
        } else {
315
32.9k
            if (ext->num_dynamic >= FF_ARRAY_ELEMS(ext->dm_dynamic))
316
897
                return AVERROR_INVALIDDATA;
317
32.0k
            dm = &ext->dm_dynamic[ext->num_dynamic++];
318
32.0k
        }
319
320
34.7k
        memset(dm, 0, sizeof(*dm));
321
34.7k
        dm->level = level;
322
34.7k
        switch (ver) {
323
11.9k
        case 1: ret = parse_ext_v1(s, gb, dm); break;
324
22.8k
        case 2: ret = parse_ext_v2(s, gb, dm, ext_block_length); break;
325
0
        default:
326
0
            avpriv_request_sample(s->logctx, "Dolby Vision DM v%d", ver);
327
0
            goto skip;
328
34.7k
        }
329
330
34.7k
        if (ret < 0)
331
7
            return ret;
332
333
34.7k
skip:
334
34.7k
        parsed_bits = get_bits_count(gb) - start_pos;
335
34.7k
        if (parsed_bits > ext_block_length * 8)
336
410
            return AVERROR_INVALIDDATA;
337
34.3k
        skip_bits(gb, ext_block_length * 8 - parsed_bits);
338
34.3k
    }
339
340
2.69k
    return 0;
341
4.01k
}
342
343
int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
344
                      int err_recognition)
345
14.4k
{
346
14.4k
    AVDOVIRpuDataHeader *hdr = &s->header;
347
14.4k
    GetBitContext *gb = &(GetBitContext){0};
348
14.4k
    int ret;
349
350
14.4k
    uint8_t rpu_type;
351
14.4k
    uint8_t vdr_seq_info_present;
352
14.4k
    uint8_t vdr_dm_metadata_present;
353
14.4k
    uint8_t dm_compression = 0;
354
14.4k
    uint8_t use_prev_vdr_rpu;
355
14.4k
    uint8_t use_nlq;
356
14.4k
    uint8_t profile;
357
14.4k
    uint8_t compression = s->cfg.dv_profile ? s->cfg.dv_md_compression : 0;
358
359
14.4k
    if (rpu_size < 5)
360
87
        return AVERROR_INVALIDDATA;
361
362
    /* Container */
363
14.3k
    if (s->cfg.dv_profile == 10 /* dav1.10 */) {
364
        /* DV inside AV1 reuses an EMDF container skeleton, but with fixed
365
         * values - so we can effectively treat this as a magic byte sequence.
366
         *
367
         * The exact fields are, as follows:
368
         *   emdf_version            : f(2) = 0
369
         *   key_id                  : f(3) = 6
370
         *   emdf_payload_id         : f(5) = 31
371
         *   emdf_payload_id_ext     : var(5) = 225
372
         *   smploffste              : f(1) = 0
373
         *   duratione               : f(1) = 0
374
         *   groupide                : f(1) = 0
375
         *   codecdatae              : f(1) = 0
376
         *   discard_unknown_payload : f(1) = 1
377
         */
378
0
        const unsigned header_magic = 0x01be6841u;
379
0
        unsigned emdf_header, emdf_payload_size, emdf_protection;
380
0
        if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0)
381
0
            return ret;
382
0
        emdf_header = get_bits_long(gb, 27);
383
0
        VALIDATE(emdf_header, header_magic, header_magic);
384
0
        emdf_payload_size = get_variable_bits(gb, 8);
385
0
        VALIDATE(emdf_payload_size, 6, 512);
386
0
        if (emdf_payload_size * 8 > get_bits_left(gb))
387
0
            return AVERROR_INVALIDDATA;
388
389
        /* The payload is not byte-aligned (off by *one* bit, curse Dolby),
390
         * so copy into a fresh buffer to preserve byte alignment of the
391
         * RPU struct */
392
0
        av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, emdf_payload_size);
393
0
        if (!s->rpu_buf)
394
0
            return AVERROR(ENOMEM);
395
0
        for (int i = 0; i < emdf_payload_size; i++)
396
0
            s->rpu_buf[i] = get_bits(gb, 8);
397
0
        rpu = s->rpu_buf;
398
0
        rpu_size = emdf_payload_size;
399
400
        /* Validate EMDF footer */
401
0
        emdf_protection = get_bits(gb, 5 + 12);
402
0
        VALIDATE(emdf_protection, 0x400, 0x400);
403
14.3k
    } else {
404
        /* NAL unit with prefix and trailing zeroes */
405
14.3k
        VALIDATE(rpu[0], 25, 25); /* NAL prefix */
406
12.4k
        rpu++;
407
12.4k
        rpu_size--;
408
        /* Strip trailing padding zero bytes */
409
239k
        while (rpu_size && !rpu[rpu_size - 1])
410
227k
            rpu_size--;
411
12.4k
    }
412
413
12.4k
    if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0)
414
0
        return ret;
415
416
    /* RPU header */
417
12.4k
    rpu_type = get_bits(gb, 6);
418
12.4k
    if (rpu_type != 2) {
419
1.17k
        av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type "
420
1.17k
               "%"PRIu8", ignoring\n", rpu_type);
421
1.17k
        return 0;
422
1.17k
    }
423
424
11.2k
    hdr->rpu_type = rpu_type;
425
11.2k
    hdr->rpu_format = get_bits(gb, 11);
426
427
    /* Values specific to RPU type 2 */
428
11.2k
    hdr->vdr_rpu_profile = get_bits(gb, 4);
429
11.2k
    hdr->vdr_rpu_level = get_bits(gb, 4);
430
431
11.2k
    vdr_seq_info_present = get_bits1(gb);
432
11.2k
    if (vdr_seq_info_present) {
433
11.1k
        hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb);
434
11.1k
        hdr->coef_data_type = get_bits(gb, 2);
435
11.1k
        VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT);
436
11.0k
        switch (hdr->coef_data_type) {
437
6.63k
        case RPU_COEFF_FIXED:
438
6.63k
            hdr->coef_log2_denom = get_ue_golomb(gb);
439
6.63k
            VALIDATE(hdr->coef_log2_denom, 13, 32);
440
6.28k
            break;
441
6.28k
        case RPU_COEFF_FLOAT:
442
4.37k
            hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */
443
4.37k
            break;
444
11.0k
        }
445
446
10.6k
        hdr->vdr_rpu_normalized_idc = get_bits(gb, 2);
447
10.6k
        hdr->bl_video_full_range_flag = get_bits1(gb);
448
449
10.6k
        if ((hdr->rpu_format & 0x700) == 0) {
450
10.6k
            int bl_bit_depth_minus8 = get_ue_golomb_31(gb);
451
10.6k
            int el_bit_depth_minus8 = get_ue_golomb_long(gb);
452
10.6k
            int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);
453
            /* ext_mapping_idc is in the upper 8 bits of el_bit_depth_minus8 */
454
10.6k
            int ext_mapping_idc = el_bit_depth_minus8 >> 8;
455
10.6k
            el_bit_depth_minus8 = el_bit_depth_minus8 & 0xFF;
456
10.6k
            VALIDATE(bl_bit_depth_minus8, 0, 8);
457
10.3k
            VALIDATE(el_bit_depth_minus8, 0, 8);
458
10.3k
            VALIDATE(ext_mapping_idc, 0, 0xFF);
459
10.3k
            VALIDATE(vdr_bit_depth_minus8, 0, 8);
460
10.2k
            hdr->bl_bit_depth = bl_bit_depth_minus8 + 8;
461
10.2k
            hdr->el_bit_depth = el_bit_depth_minus8 + 8;
462
10.2k
            hdr->ext_mapping_idc_0_4 = ext_mapping_idc & 0x1f; /* 5 bits */
463
10.2k
            hdr->ext_mapping_idc_5_7 = ext_mapping_idc >> 5;
464
10.2k
            hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;
465
10.2k
            hdr->spatial_resampling_filter_flag = get_bits1(gb);
466
10.2k
            dm_compression = get_bits(gb, 3);
467
10.2k
            hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
468
10.2k
            hdr->disable_residual_flag = get_bits1(gb);
469
10.2k
        } else {
470
55
            avpriv_request_sample(s->logctx, "Unsupported RPU format 0x%x\n", hdr->rpu_format);
471
55
            ff_dovi_ctx_unref(s);
472
55
            return AVERROR_PATCHWELCOME;
473
55
        }
474
10.6k
    } else {
475
        /* lack of documentation/samples */
476
178
        avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n");
477
178
        ff_dovi_ctx_unref(s);
478
178
        return AVERROR_PATCHWELCOME;
479
178
    }
480
481
10.2k
    vdr_dm_metadata_present = get_bits1(gb);
482
10.2k
    if (dm_compression > 1) {
483
        /* It seems no device supports this */
484
725
        av_log(s->logctx, AV_LOG_ERROR, "Dynamic metadata compression is not "
485
725
               "yet implemented");
486
725
        return AVERROR_PATCHWELCOME;
487
9.55k
    } else if (dm_compression && !vdr_dm_metadata_present) {
488
15
        av_log(s->logctx, AV_LOG_ERROR, "Nonzero DM metadata compression method "
489
15
               "but no DM metadata present");
490
15
        return AVERROR_INVALIDDATA;
491
15
    }
492
493
9.53k
    use_prev_vdr_rpu = get_bits1(gb);
494
9.53k
    use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
495
496
9.53k
    profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr);
497
9.53k
    if (profile == 5 && use_nlq) {
498
3
        av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n");
499
3
        ff_dovi_ctx_unref(s);
500
3
        return AVERROR_INVALIDDATA;
501
3
    }
502
503
9.53k
    if (err_recognition & (AV_EF_COMPLIANT | AV_EF_CAREFUL)) {
504
3.43k
        if (profile < 8 && compression) {
505
0
            av_log(s->logctx, AV_LOG_ERROR, "Profile %d RPUs should not use "
506
0
                   "metadata compression.", profile);
507
0
            return AVERROR_INVALIDDATA;
508
0
        }
509
510
3.43k
        if (use_prev_vdr_rpu && !compression) {
511
104
            av_log(s->logctx, AV_LOG_ERROR, "Uncompressed RPUs should not have "
512
104
                   "use_prev_vdr_rpu=1\n");
513
104
            return AVERROR_INVALIDDATA;
514
104
        }
515
516
3.32k
        if (dm_compression && !compression) {
517
130
            av_log(s->logctx, AV_LOG_ERROR, "Uncompressed RPUs should not use "
518
130
                   "dm_compression=%d\n", dm_compression);
519
130
            return AVERROR_INVALIDDATA;
520
130
        }
521
3.32k
    }
522
523
9.30k
    if (use_prev_vdr_rpu) {
524
271
        int prev_vdr_rpu_id = get_ue_golomb_31(gb);
525
271
        VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID);
526
224
        if (!s->vdr[prev_vdr_rpu_id])
527
218
            prev_vdr_rpu_id = 0;
528
224
        if (!s->vdr[prev_vdr_rpu_id]) {
529
            /* FIXME: Technically, the spec says that in this case we should
530
             * synthesize "neutral" vdr metadata, but easier to just error
531
             * out as this corner case is not hit in practice */
532
217
            av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n",
533
217
                   prev_vdr_rpu_id);
534
217
            ff_dovi_ctx_unref(s);
535
217
            return AVERROR_INVALIDDATA;
536
217
        }
537
7
        s->mapping = s->vdr[prev_vdr_rpu_id];
538
9.03k
    } else {
539
9.03k
        AVDOVIDataMapping *mapping;
540
9.03k
        int vdr_rpu_id = get_ue_golomb_31(gb);
541
9.03k
        VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID);
542
8.99k
        if (!s->vdr[vdr_rpu_id]) {
543
8.87k
            s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping));
544
8.87k
            if (!s->vdr[vdr_rpu_id]) {
545
0
                ff_dovi_ctx_unref(s);
546
0
                return AVERROR(ENOMEM);
547
0
            }
548
8.87k
        }
549
550
8.99k
        s->mapping = mapping = s->vdr[vdr_rpu_id];
551
8.99k
        mapping->vdr_rpu_id = vdr_rpu_id;
552
8.99k
        mapping->mapping_color_space = get_ue_golomb_31(gb);
553
8.99k
        mapping->mapping_chroma_format_idc = get_ue_golomb_31(gb);
554
555
35.0k
        for (int c = 0; c < 3; c++) {
556
26.4k
            AVDOVIReshapingCurve *curve = &mapping->curves[c];
557
26.4k
            int num_pivots_minus_2 = get_ue_golomb_31(gb);
558
26.4k
            int pivot = 0;
559
560
26.4k
            VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1);
561
26.0k
            curve->num_pivots = num_pivots_minus_2 + 2;
562
124k
            for (int i = 0; i < curve->num_pivots; i++) {
563
98.2k
                pivot += get_bits(gb, hdr->bl_bit_depth);
564
98.2k
                curve->pivots[i] = av_clip_uint16(pivot);
565
98.2k
            }
566
26.0k
        }
567
568
8.57k
        if (use_nlq) {
569
7.63k
            int nlq_pivot = 0;
570
7.63k
            mapping->nlq_method_idc = get_bits(gb, 3);
571
572
22.8k
            for (int i = 0; i < 2; i++) {
573
15.2k
                nlq_pivot += get_bits(gb, hdr->bl_bit_depth);
574
15.2k
                mapping->nlq_pivots[i] = av_clip_uint16(nlq_pivot);
575
15.2k
            }
576
577
            /**
578
             * The patent mentions another legal value, NLQ_MU_LAW, but it's
579
             * not documented anywhere how to parse or apply that type of NLQ.
580
             */
581
7.63k
            VALIDATE(mapping->nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ);
582
7.63k
        } else {
583
948
            mapping->nlq_method_idc = AV_DOVI_NLQ_NONE;
584
948
        }
585
586
5.67k
        mapping->num_x_partitions = get_ue_golomb_long(gb) + 1;
587
5.67k
        mapping->num_y_partitions = get_ue_golomb_long(gb) + 1;
588
5.67k
        VALIDATE(mapping->num_x_partitions, 1, 0xFFFF);
589
5.45k
        VALIDATE(mapping->num_y_partitions, 1, 0xFFFF);
590
        /* End of rpu_data_header(), start of vdr_rpu_data_payload() */
591
592
15.0k
        for (int c = 0; c < 3; c++) {
593
11.8k
            AVDOVIReshapingCurve *curve = &mapping->curves[c];
594
30.0k
            for (int i = 0; i < curve->num_pivots - 1; i++) {
595
20.4k
                int mapping_idc = get_ue_golomb_31(gb);
596
20.4k
                VALIDATE(mapping_idc, 0, 1);
597
18.5k
                curve->mapping_idc[i] = mapping_idc;
598
18.5k
                switch (mapping_idc) {
599
12.8k
                case AV_DOVI_MAPPING_POLYNOMIAL: {
600
12.8k
                    int poly_order_minus1 = get_ue_golomb_31(gb);
601
12.8k
                    VALIDATE(poly_order_minus1, 0, 1);
602
12.7k
                    curve->poly_order[i] = poly_order_minus1 + 1;
603
12.7k
                    if (poly_order_minus1 == 0) {
604
11.6k
                        int linear_interp_flag = get_bits1(gb);
605
11.6k
                        if (linear_interp_flag) {
606
                            /* lack of documentation/samples */
607
242
                            avpriv_request_sample(s->logctx, "Dolby Vision "
608
242
                                                  "linear interpolation");
609
242
                            ff_dovi_ctx_unref(s);
610
242
                            return AVERROR_PATCHWELCOME;
611
242
                        }
612
11.6k
                    }
613
38.5k
                    for (int k = 0; k <= curve->poly_order[i]; k++)
614
26.0k
                        curve->poly_coef[i][k] = get_se_coef(gb, hdr);
615
12.4k
                    break;
616
12.7k
                }
617
5.70k
                case AV_DOVI_MAPPING_MMR: {
618
5.70k
                    int mmr_order_minus1 = get_bits(gb, 2);
619
5.70k
                    VALIDATE(mmr_order_minus1, 0, 2);
620
5.67k
                    curve->mmr_order[i] = mmr_order_minus1 + 1;
621
5.67k
                    curve->mmr_constant[i] = get_se_coef(gb, hdr);
622
11.7k
                    for (int j = 0; j < curve->mmr_order[i]; j++) {
623
48.8k
                        for (int k = 0; k < 7; k++)
624
42.7k
                            curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr);
625
6.10k
                    }
626
5.67k
                    break;
627
5.70k
                }
628
18.5k
                }
629
18.5k
            }
630
11.8k
        }
631
632
3.13k
        if (use_nlq) {
633
8.96k
            for (int c = 0; c < 3; c++) {
634
6.72k
                AVDOVINLQParams *nlq = &mapping->nlq[c];
635
6.72k
                nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth);
636
6.72k
                nlq->vdr_in_max = get_ue_coef(gb, hdr);
637
6.72k
                switch (mapping->nlq_method_idc) {
638
6.72k
                case AV_DOVI_NLQ_LINEAR_DZ:
639
6.72k
                    nlq->linear_deadzone_slope = get_ue_coef(gb, hdr);
640
6.72k
                    nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr);
641
6.72k
                    break;
642
6.72k
                }
643
6.72k
            }
644
2.24k
        }
645
3.13k
    }
646
647
3.13k
    if (vdr_dm_metadata_present) {
648
2.92k
        AVDOVIColorMetadata *color;
649
2.92k
        int affected_dm_id = get_ue_golomb_31(gb);
650
2.92k
        int current_dm_id = get_ue_golomb_31(gb);
651
2.92k
        VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID);
652
2.74k
        VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID);
653
2.73k
        if (affected_dm_id != current_dm_id) {
654
            /* The spec does not explain these fields at all, and there is
655
             * a lack of samples to understand how they're supposed to work,
656
             * so just assert them being equal for now */
657
78
            avpriv_request_sample(s->logctx, "affected/current_dm_metadata_id "
658
78
                "mismatch? %u != %u\n", affected_dm_id, current_dm_id);
659
78
            ff_dovi_ctx_unref(s);
660
78
            return AVERROR_PATCHWELCOME;
661
78
        }
662
663
2.65k
        if (!s->dm) {
664
2.54k
            s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata));
665
2.54k
            if (!s->dm) {
666
0
                ff_dovi_ctx_unref(s);
667
0
                return AVERROR(ENOMEM);
668
0
            }
669
2.54k
        }
670
671
2.65k
        s->color = color = s->dm;
672
2.65k
        color->dm_metadata_id = affected_dm_id;
673
2.65k
        color->scene_refresh_flag = get_ue_golomb_31(gb);
674
2.65k
        if (!dm_compression) {
675
6.12k
            for (int i = 0; i < 9; i++)
676
5.50k
                color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
677
2.44k
            for (int i = 0; i < 3; i++) {
678
1.83k
                int denom = profile == 4 ? (1 << 30) : (1 << 28);
679
1.83k
                unsigned offset = get_bits_long(gb, 32);
680
1.83k
                if (offset > INT_MAX) {
681
                    /* Ensure the result fits inside AVRational */
682
619
                    offset >>= 1;
683
619
                    denom >>= 1;
684
619
                }
685
1.83k
                color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
686
1.83k
            }
687
6.12k
            for (int i = 0; i < 9; i++)
688
5.50k
                color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14);
689
690
612
            color->signal_eotf = get_bits(gb, 16);
691
612
            color->signal_eotf_param0 = get_bits(gb, 16);
692
612
            color->signal_eotf_param1 = get_bits(gb, 16);
693
612
            color->signal_eotf_param2 = get_bits_long(gb, 32);
694
612
            color->signal_bit_depth = get_bits(gb, 5);
695
612
            VALIDATE(color->signal_bit_depth, 8, 16);
696
314
            color->signal_color_space = get_bits(gb, 2);
697
314
            color->signal_chroma_format = get_bits(gb, 2);
698
314
            color->signal_full_range_flag = get_bits(gb, 2);
699
314
            color->source_min_pq = get_bits(gb, 12);
700
314
            color->source_max_pq = get_bits(gb, 12);
701
314
            color->source_diagonal = get_bits(gb, 10);
702
314
        }
703
704
        /* Parse extension blocks */
705
2.36k
        if (s->ext_blocks) {
706
58
            DOVIExt *ext = s->ext_blocks;
707
58
            if (!dm_compression)
708
0
                ext->num_static = 0;
709
58
            ext->num_dynamic = 0;
710
58
        }
711
2.36k
        if ((ret = parse_ext_blocks(s, gb, 1, dm_compression, err_recognition)) < 0) {
712
195
            ff_dovi_ctx_unref(s);
713
195
            return ret;
714
195
        }
715
716
        /* ue(1) + ue(0) + level + CRC32 + terminator */
717
2.16k
        if (get_bits_left(gb) >= 3 + 1 + 8 + 32 + 8) {
718
1.65k
            if ((ret = parse_ext_blocks(s, gb, 2, dm_compression, err_recognition)) < 0) {
719
1.12k
                ff_dovi_ctx_unref(s);
720
1.12k
                return ret;
721
1.12k
            }
722
1.65k
        }
723
2.16k
    } else {
724
211
        s->color = &ff_dovi_color_default;
725
211
        av_refstruct_unref(&s->ext_blocks);
726
211
    }
727
728
1.25k
    int aligned = get_bits_count(gb) % 8 == 0;
729
1.25k
    align_get_bits(gb);
730
731
    /* The payload is followed by a CRC32 and a 0x80 terminator. Some encoders
732
     * emit an extra zero padding byte before the CRC32 when the payload already
733
     * ended on a byte boundary. A leading zero byte is then ambiguous: it may
734
     * be that padding, or simply a CRC32 that starts with a zero byte. If only
735
     * the padded position holds the terminator, assume the padding is real. If
736
     * both do (the last CRC32 byte is 0x80 or there is stray 0x80 after real
737
     * payload) the terminator position is ambiguous. Calculate CRC twice when
738
     * AV_EF_CRCCHECK is requested. Note that this situation is extremely
739
     * unlikely, there shouldn't be non-zero data after payload. */
740
1.25k
    int pad = aligned && show_bits(gb, 8) == 0;
741
1.25k
    skip_bits(gb, 32); /* CRC32 */
742
1.25k
    int term_unpadded = get_bits(gb, 8) == 0x80;       /* terminator w/o padding */
743
1.25k
    int term_padded = pad && show_bits(gb, 8) == 0x80; /* terminator w/ padding */
744
745
1.25k
    if (!term_unpadded && !term_padded) {
746
1.05k
        avpriv_request_sample(s->logctx, "Unexpected RPU format");
747
1.05k
        ff_dovi_ctx_unref(s);
748
1.05k
        return AVERROR_PATCHWELCOME;
749
1.05k
    }
750
751
200
    if (err_recognition & AV_EF_CRCCHECK) {
752
106
        if (term_padded && !term_unpadded)
753
0
            skip_bits(gb, 8); /* unambiguously padded */
754
106
        rpu_size = get_bits_count(gb) / 8;
755
106
        uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE),
756
106
                                  -1, rpu, rpu_size - 1)); /* exclude 0x80 */
757
106
        if (crc && term_padded && term_unpadded) {
758
0
            crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE),
759
0
                                    -1, rpu, rpu_size)); /* include padding byte */
760
0
        }
761
106
        if (crc) {
762
106
            av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc);
763
106
            if (err_recognition & AV_EF_EXPLODE) {
764
0
                ff_dovi_ctx_unref(s);
765
0
                return AVERROR_INVALIDDATA;
766
0
            }
767
106
        }
768
106
    }
769
770
200
    return 0;
771
200
}