Line |
Branch |
Exec |
Source |
1 |
|
|
/* |
2 |
|
|
* Dolby Vision RPU encoder |
3 |
|
|
* |
4 |
|
|
* Copyright (C) 2024 Niklas Haas |
5 |
|
|
* |
6 |
|
|
* This file is part of FFmpeg. |
7 |
|
|
* |
8 |
|
|
* FFmpeg is free software; you can redistribute it and/or |
9 |
|
|
* modify it under the terms of the GNU Lesser General Public |
10 |
|
|
* License as published by the Free Software Foundation; either |
11 |
|
|
* version 2.1 of the License, or (at your option) any later version. |
12 |
|
|
* |
13 |
|
|
* FFmpeg is distributed in the hope that it will be useful, |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 |
|
|
* Lesser General Public License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU Lesser General Public |
19 |
|
|
* License along with FFmpeg; if not, write to the Free Software |
20 |
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 |
|
|
*/ |
22 |
|
|
|
23 |
|
|
#include "libavutil/attributes.h" |
24 |
|
|
#include "libavutil/avassert.h" |
25 |
|
|
#include "libavutil/crc.h" |
26 |
|
|
#include "libavutil/mem.h" |
27 |
|
|
#include "libavutil/refstruct.h" |
28 |
|
|
|
29 |
|
|
#include "avcodec.h" |
30 |
|
|
#include "dovi_rpu.h" |
31 |
|
|
#include "itut35.h" |
32 |
|
|
#include "put_bits.h" |
33 |
|
|
#include "put_golomb.h" |
34 |
|
|
|
35 |
|
|
static const struct { |
36 |
|
|
uint64_t pps; // maximum pixels per second |
37 |
|
|
int width; // maximum width |
38 |
|
|
int main; // maximum bitrate in main tier |
39 |
|
|
int high; // maximum bitrate in high tier |
40 |
|
|
} dv_levels[] = { |
41 |
|
|
[1] = {1280*720*24, 1280, 20, 50}, |
42 |
|
|
[2] = {1280*720*30, 1280, 20, 50}, |
43 |
|
|
[3] = {1920*1080*24, 1920, 20, 70}, |
44 |
|
|
[4] = {1920*1080*30, 2560, 20, 70}, |
45 |
|
|
[5] = {1920*1080*60, 3840, 20, 70}, |
46 |
|
|
[6] = {3840*2160*24, 3840, 25, 130}, |
47 |
|
|
[7] = {3840*2160*30, 3840, 25, 130}, |
48 |
|
|
[8] = {3840*2160*48, 3840, 40, 130}, |
49 |
|
|
[9] = {3840*2160*60, 3840, 40, 130}, |
50 |
|
|
[10] = {3840*2160*120, 3840, 60, 240}, |
51 |
|
|
[11] = {3840*2160*120, 7680, 60, 240}, |
52 |
|
|
[12] = {7680*4320*60, 7680, 120, 450}, |
53 |
|
|
[13] = {7680*4320*120u, 7680, 240, 800}, |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
✗ |
static av_cold int dovi_configure_ext(DOVIContext *s, enum AVCodecID codec_id, |
57 |
|
|
const AVDOVIMetadata *metadata, |
58 |
|
|
enum AVDOVICompression compression, |
59 |
|
|
int strict_std_compliance, |
60 |
|
|
int width, int height, |
61 |
|
|
AVRational framerate, |
62 |
|
|
enum AVPixelFormat pix_format, |
63 |
|
|
enum AVColorSpace color_space, |
64 |
|
|
enum AVColorPrimaries color_primaries, |
65 |
|
|
enum AVColorTransferCharacteristic color_trc, |
66 |
|
|
AVPacketSideData **coded_side_data, |
67 |
|
|
int *nb_coded_side_data) |
68 |
|
|
{ |
69 |
|
|
AVDOVIDecoderConfigurationRecord *cfg; |
70 |
|
✗ |
const AVDOVIRpuDataHeader *hdr = NULL; |
71 |
|
✗ |
int dv_profile, dv_level, bl_compat_id = -1; |
72 |
|
|
size_t cfg_size; |
73 |
|
|
uint64_t pps; |
74 |
|
|
|
75 |
|
✗ |
if (!s->enable) |
76 |
|
✗ |
goto skip; |
77 |
|
|
|
78 |
|
✗ |
if (metadata) |
79 |
|
✗ |
hdr = av_dovi_get_header(metadata); |
80 |
|
|
|
81 |
|
✗ |
if (s->enable == FF_DOVI_AUTOMATIC && !hdr) |
82 |
|
✗ |
goto skip; |
83 |
|
|
|
84 |
|
✗ |
if (compression == AV_DOVI_COMPRESSION_RESERVED || |
85 |
|
|
compression > AV_DOVI_COMPRESSION_EXTENDED) |
86 |
|
✗ |
return AVERROR(EINVAL); |
87 |
|
|
|
88 |
|
✗ |
switch (codec_id) { |
89 |
|
✗ |
case AV_CODEC_ID_AV1: dv_profile = 10; break; |
90 |
|
✗ |
case AV_CODEC_ID_H264: dv_profile = 9; break; |
91 |
|
✗ |
case AV_CODEC_ID_HEVC: |
92 |
|
✗ |
if (hdr) { |
93 |
|
✗ |
dv_profile = ff_dovi_guess_profile_hevc(hdr); |
94 |
|
✗ |
break; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
/* This is likely to be proprietary IPTPQc2 */ |
98 |
|
✗ |
if (color_space == AVCOL_SPC_IPT_C2 || |
99 |
|
✗ |
(color_space == AVCOL_SPC_UNSPECIFIED && |
100 |
|
|
color_trc == AVCOL_TRC_UNSPECIFIED)) |
101 |
|
✗ |
dv_profile = 5; |
102 |
|
|
else |
103 |
|
✗ |
dv_profile = 8; |
104 |
|
✗ |
break; |
105 |
|
✗ |
default: |
106 |
|
✗ |
av_unreachable("ff_dovi_configure only used with AV1, H.264 and HEVC"); |
107 |
|
|
} |
108 |
|
|
|
109 |
|
✗ |
if (strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { |
110 |
|
✗ |
if (dv_profile == 9) { |
111 |
|
✗ |
if (pix_format != AV_PIX_FMT_YUV420P) |
112 |
|
✗ |
dv_profile = 0; |
113 |
|
|
} else { |
114 |
|
✗ |
if (pix_format != AV_PIX_FMT_YUV420P10) |
115 |
|
✗ |
dv_profile = 0; |
116 |
|
|
} |
117 |
|
|
} |
118 |
|
|
|
119 |
|
✗ |
switch (dv_profile) { |
120 |
|
✗ |
case 4: /* HEVC with enhancement layer */ |
121 |
|
|
case 7: |
122 |
|
✗ |
if (s->enable > 0) { |
123 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Coding of Dolby Vision enhancement " |
124 |
|
|
"layers is currently unsupported."); |
125 |
|
✗ |
return AVERROR_PATCHWELCOME; |
126 |
|
|
} else { |
127 |
|
✗ |
goto skip; |
128 |
|
|
} |
129 |
|
✗ |
case 5: /* HEVC with proprietary IPTPQc2 */ |
130 |
|
✗ |
bl_compat_id = 0; |
131 |
|
✗ |
break; |
132 |
|
✗ |
case 10: |
133 |
|
|
/* FIXME: check for proper H.273 tags once those are added */ |
134 |
|
✗ |
if (hdr && hdr->bl_video_full_range_flag) { |
135 |
|
|
/* AV1 with proprietary IPTPQc2 */ |
136 |
|
✗ |
bl_compat_id = 0; |
137 |
|
✗ |
break; |
138 |
|
|
} |
139 |
|
|
/* fall through */ |
140 |
|
|
case 8: /* HEVC (or AV1) with BL compatibility */ |
141 |
|
✗ |
if (color_space == AVCOL_SPC_BT2020_NCL && |
142 |
|
✗ |
color_primaries == AVCOL_PRI_BT2020 && |
143 |
|
|
color_trc == AVCOL_TRC_SMPTE2084) { |
144 |
|
✗ |
bl_compat_id = 1; |
145 |
|
✗ |
} else if (color_space == AVCOL_SPC_BT2020_NCL && |
146 |
|
✗ |
color_primaries == AVCOL_PRI_BT2020 && |
147 |
|
|
color_trc == AVCOL_TRC_ARIB_STD_B67) { |
148 |
|
✗ |
bl_compat_id = 4; |
149 |
|
✗ |
} else if (color_space == AVCOL_SPC_BT709 && |
150 |
|
✗ |
color_primaries == AVCOL_PRI_BT709 && |
151 |
|
|
color_trc == AVCOL_TRC_BT709) { |
152 |
|
✗ |
bl_compat_id = 2; |
153 |
|
|
} |
154 |
|
|
} |
155 |
|
|
|
156 |
|
✗ |
if (!dv_profile || bl_compat_id < 0) { |
157 |
|
✗ |
if (s->enable > 0) { |
158 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision enabled, but could " |
159 |
|
|
"not determine profile and compatibility mode. Double-check " |
160 |
|
|
"colorspace and format settings for compatibility?\n"); |
161 |
|
✗ |
return AVERROR(EINVAL); |
162 |
|
|
} |
163 |
|
✗ |
goto skip; |
164 |
|
|
} |
165 |
|
|
|
166 |
|
✗ |
if (compression != AV_DOVI_COMPRESSION_NONE) { |
167 |
|
✗ |
if (dv_profile < 8 && strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { |
168 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision metadata compression " |
169 |
|
|
"is not permitted for profiles 7 and earlier. (dv_profile: %d, " |
170 |
|
|
"compression: %d)\n", dv_profile, compression); |
171 |
|
✗ |
return AVERROR(EINVAL); |
172 |
|
✗ |
} else if (compression == AV_DOVI_COMPRESSION_EXTENDED && |
173 |
|
|
strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { |
174 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision extended metadata " |
175 |
|
|
"compression is experimental and not supported by " |
176 |
|
|
"devices."); |
177 |
|
✗ |
return AVERROR(EINVAL); |
178 |
|
✗ |
} else if (dv_profile == 8) { |
179 |
|
✗ |
av_log(s->logctx, AV_LOG_WARNING, "Dolby Vision metadata compression " |
180 |
|
|
"for profile 8 is known to be unsupported by many devices, " |
181 |
|
|
"use with caution.\n"); |
182 |
|
|
} |
183 |
|
|
} |
184 |
|
|
|
185 |
|
✗ |
pps = width * height; |
186 |
|
✗ |
if (framerate.num) { |
187 |
|
✗ |
pps = pps * framerate.num / framerate.den; |
188 |
|
|
} else { |
189 |
|
✗ |
pps *= 25; /* sanity fallback */ |
190 |
|
|
} |
191 |
|
|
|
192 |
|
✗ |
dv_level = 0; |
193 |
|
✗ |
for (int i = 1; i < FF_ARRAY_ELEMS(dv_levels); i++) { |
194 |
|
✗ |
if (pps > dv_levels[i].pps) |
195 |
|
✗ |
continue; |
196 |
|
✗ |
if (width > dv_levels[i].width) |
197 |
|
✗ |
continue; |
198 |
|
|
/* In theory, we should also test the bitrate when known, and |
199 |
|
|
* distinguish between main and high tier. In practice, just ignore |
200 |
|
|
* the bitrate constraints and hope they work out. This would ideally |
201 |
|
|
* be handled by either the encoder or muxer directly. */ |
202 |
|
✗ |
dv_level = i; |
203 |
|
✗ |
break; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
✗ |
if (!dv_level) { |
207 |
|
✗ |
if (strict_std_compliance >= FF_COMPLIANCE_STRICT) { |
208 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Coded PPS (%"PRIu64") and width (%d) " |
209 |
|
|
"exceed Dolby Vision limitations\n", pps, width); |
210 |
|
✗ |
return AVERROR(EINVAL); |
211 |
|
|
} else { |
212 |
|
✗ |
av_log(s->logctx, AV_LOG_WARNING, "Coded PPS (%"PRIu64") and width (%d) " |
213 |
|
|
"exceed Dolby Vision limitations. Ignoring, resulting file " |
214 |
|
|
"may be non-conforming.\n", pps, width); |
215 |
|
✗ |
dv_level = FF_ARRAY_ELEMS(dv_levels) - 1; |
216 |
|
|
} |
217 |
|
|
} |
218 |
|
|
|
219 |
|
✗ |
cfg = av_dovi_alloc(&cfg_size); |
220 |
|
✗ |
if (!cfg) |
221 |
|
✗ |
return AVERROR(ENOMEM); |
222 |
|
|
|
223 |
|
✗ |
if (!av_packet_side_data_add(coded_side_data, |
224 |
|
|
nb_coded_side_data, |
225 |
|
|
AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) { |
226 |
|
✗ |
av_free(cfg); |
227 |
|
✗ |
return AVERROR(ENOMEM); |
228 |
|
|
} |
229 |
|
|
|
230 |
|
✗ |
cfg->dv_version_major = 1; |
231 |
|
✗ |
cfg->dv_version_minor = 0; |
232 |
|
✗ |
cfg->dv_profile = dv_profile; |
233 |
|
✗ |
cfg->dv_level = dv_level; |
234 |
|
✗ |
cfg->rpu_present_flag = 1; |
235 |
|
✗ |
cfg->el_present_flag = 0; |
236 |
|
✗ |
cfg->bl_present_flag = 1; |
237 |
|
✗ |
cfg->dv_bl_signal_compatibility_id = bl_compat_id; |
238 |
|
✗ |
cfg->dv_md_compression = compression; |
239 |
|
|
|
240 |
|
✗ |
s->cfg = *cfg; |
241 |
|
✗ |
return 0; |
242 |
|
|
|
243 |
|
✗ |
skip: |
244 |
|
✗ |
s->cfg = (AVDOVIDecoderConfigurationRecord) {0}; |
245 |
|
✗ |
return 0; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
✗ |
av_cold int ff_dovi_configure_from_codedpar(DOVIContext *s, AVCodecParameters *par, |
249 |
|
|
const AVDOVIMetadata *metadata, |
250 |
|
|
enum AVDOVICompression compression, |
251 |
|
|
int strict_std_compliance) |
252 |
|
|
{ |
253 |
|
✗ |
return dovi_configure_ext(s, par->codec_id, metadata, compression, |
254 |
|
|
strict_std_compliance, par->width, par->height, |
255 |
|
✗ |
par->framerate, par->format, par->color_space, |
256 |
|
|
par->color_primaries, par->color_trc, |
257 |
|
|
&par->coded_side_data, &par->nb_coded_side_data); |
258 |
|
|
} |
259 |
|
|
|
260 |
|
✗ |
av_cold int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) |
261 |
|
|
{ |
262 |
|
✗ |
const AVDOVIMetadata *metadata = NULL; |
263 |
|
|
const AVFrameSideData *sd; |
264 |
|
✗ |
sd = av_frame_side_data_get(avctx->decoded_side_data, |
265 |
|
|
avctx->nb_decoded_side_data, |
266 |
|
|
AV_FRAME_DATA_DOVI_METADATA); |
267 |
|
✗ |
if (sd) |
268 |
|
✗ |
metadata = (const AVDOVIMetadata *) sd->data; |
269 |
|
|
|
270 |
|
|
/* Current encoders cannot handle metadata compression during encoding */ |
271 |
|
✗ |
return dovi_configure_ext(s, avctx->codec_id, metadata, AV_DOVI_COMPRESSION_NONE, |
272 |
|
|
avctx->strict_std_compliance, avctx->width, |
273 |
|
|
avctx->height, avctx->framerate, avctx->pix_fmt, |
274 |
|
|
avctx->colorspace, avctx->color_primaries, avctx->color_trc, |
275 |
|
|
&avctx->coded_side_data, &avctx->nb_coded_side_data); |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
/* Compares only the static DM metadata parts of AVDOVIColorMetadata (excluding |
279 |
|
|
* dm_metadata_id and scene_refresh_flag) */ |
280 |
|
✗ |
static int cmp_dm_level0(const AVDOVIColorMetadata *dm1, |
281 |
|
|
const AVDOVIColorMetadata *dm2) |
282 |
|
|
{ |
283 |
|
|
int ret; |
284 |
|
✗ |
for (int i = 0; i < FF_ARRAY_ELEMS(dm1->ycc_to_rgb_matrix); i++) { |
285 |
|
✗ |
if ((ret = av_cmp_q(dm1->ycc_to_rgb_matrix[i], dm2->ycc_to_rgb_matrix[i]))) |
286 |
|
✗ |
return ret; |
287 |
|
|
} |
288 |
|
|
|
289 |
|
✗ |
for (int i = 0; i < FF_ARRAY_ELEMS(dm1->ycc_to_rgb_offset); i++) { |
290 |
|
✗ |
if ((ret = av_cmp_q(dm1->ycc_to_rgb_offset[i], dm2->ycc_to_rgb_offset[i]))) |
291 |
|
✗ |
return ret; |
292 |
|
|
} |
293 |
|
|
|
294 |
|
✗ |
for (int i = 0; i < FF_ARRAY_ELEMS(dm1->rgb_to_lms_matrix); i++) { |
295 |
|
✗ |
if ((ret = av_cmp_q(dm1->rgb_to_lms_matrix[i], dm2->rgb_to_lms_matrix[i]))) |
296 |
|
✗ |
return ret; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
✗ |
return memcmp(&dm1->signal_eotf, &dm2->signal_eotf, |
300 |
|
|
sizeof(AVDOVIColorMetadata) -offsetof(AVDOVIColorMetadata, signal_eotf)); |
301 |
|
|
} |
302 |
|
|
|
303 |
|
|
/* Tries to re-use the static ext blocks. May reorder `ext->dm_static` */ |
304 |
|
✗ |
static int try_reuse_ext(DOVIExt *ext, const AVDOVIMetadata *metadata) |
305 |
|
|
{ |
306 |
|
✗ |
int i, j, idx = 0; |
307 |
|
|
|
308 |
|
✗ |
for (i = 0; i < metadata->num_ext_blocks; i++) { |
309 |
|
✗ |
const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); |
310 |
|
✗ |
if (!ff_dovi_rpu_extension_is_static(dm->level)) |
311 |
|
✗ |
continue; |
312 |
|
|
|
313 |
|
|
/* Find the first matching ext block and move it to [idx] */ |
314 |
|
✗ |
for (j = idx; j < ext->num_static; j++) { |
315 |
|
✗ |
if (!memcmp(&ext->dm_static[j], dm, sizeof(*dm))) { |
316 |
|
✗ |
if (j != idx) |
317 |
|
✗ |
FFSWAP(AVDOVIDmData, ext->dm_static[j], ext->dm_static[idx]); |
318 |
|
✗ |
idx++; |
319 |
|
✗ |
break; |
320 |
|
|
} |
321 |
|
|
} |
322 |
|
|
|
323 |
|
✗ |
if (j == ext->num_static) { |
324 |
|
|
/* Found no matching ext block */ |
325 |
|
✗ |
return 0; |
326 |
|
|
} |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
/* If idx is less than ext->num_static, then there are extra unmatched |
330 |
|
|
* ext blocks inside ext->dm_static */ |
331 |
|
✗ |
return idx == ext->num_static; |
332 |
|
|
} |
333 |
|
|
|
334 |
|
✗ |
static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, |
335 |
|
|
uint64_t coef) |
336 |
|
|
{ |
337 |
|
|
union { uint32_t u32; float f32; } fpart; |
338 |
|
|
|
339 |
|
✗ |
switch (hdr->coef_data_type) { |
340 |
|
✗ |
case RPU_COEFF_FIXED: |
341 |
|
✗ |
set_ue_golomb(pb, coef >> hdr->coef_log2_denom); |
342 |
|
✗ |
put_bits63(pb, hdr->coef_log2_denom, |
343 |
|
✗ |
coef & ((1LL << hdr->coef_log2_denom) - 1)); |
344 |
|
✗ |
break; |
345 |
|
✗ |
case RPU_COEFF_FLOAT: |
346 |
|
✗ |
fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); |
347 |
|
✗ |
put_bits63(pb, hdr->coef_log2_denom, fpart.u32); |
348 |
|
✗ |
break; |
349 |
|
|
} |
350 |
|
✗ |
} |
351 |
|
|
|
352 |
|
✗ |
static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, |
353 |
|
|
uint64_t coef) |
354 |
|
|
{ |
355 |
|
|
union { uint32_t u32; float f32; } fpart; |
356 |
|
|
|
357 |
|
✗ |
switch (hdr->coef_data_type) { |
358 |
|
✗ |
case RPU_COEFF_FIXED: |
359 |
|
✗ |
set_se_golomb(pb, coef >> hdr->coef_log2_denom); |
360 |
|
✗ |
put_bits63(pb, hdr->coef_log2_denom, |
361 |
|
✗ |
coef & ((1LL << hdr->coef_log2_denom) - 1)); |
362 |
|
✗ |
break; |
363 |
|
✗ |
case RPU_COEFF_FLOAT: |
364 |
|
✗ |
fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); |
365 |
|
✗ |
put_bits63(pb, hdr->coef_log2_denom, fpart.u32); |
366 |
|
✗ |
break; |
367 |
|
|
} |
368 |
|
✗ |
} |
369 |
|
|
|
370 |
|
✗ |
static int av_q2den(AVRational q, int den) |
371 |
|
|
{ |
372 |
|
✗ |
if (!q.den || q.den == den) |
373 |
|
✗ |
return q.num; |
374 |
|
✗ |
q = av_mul_q(q, av_make_q(den, 1)); |
375 |
|
✗ |
return (q.num + (q.den >> 1)) / q.den; |
376 |
|
|
} |
377 |
|
|
|
378 |
|
✗ |
static void generate_ext_v1(PutBitContext *pb, const AVDOVIDmData *dm) |
379 |
|
|
{ |
380 |
|
|
int ext_block_length, start_pos, pad_bits; |
381 |
|
|
|
382 |
|
✗ |
switch (dm->level) { |
383 |
|
✗ |
case 1: ext_block_length = 5; break; |
384 |
|
✗ |
case 2: ext_block_length = 11; break; |
385 |
|
✗ |
case 4: ext_block_length = 3; break; |
386 |
|
✗ |
case 5: ext_block_length = 7; break; |
387 |
|
✗ |
case 6: ext_block_length = 8; break; |
388 |
|
✗ |
case 255: ext_block_length = 6; break; |
389 |
|
✗ |
default: return; |
390 |
|
|
} |
391 |
|
|
|
392 |
|
✗ |
set_ue_golomb(pb, ext_block_length); |
393 |
|
✗ |
put_bits(pb, 8, dm->level); |
394 |
|
✗ |
start_pos = put_bits_count(pb); |
395 |
|
|
|
396 |
|
✗ |
switch (dm->level) { |
397 |
|
✗ |
case 1: |
398 |
|
✗ |
put_bits(pb, 12, dm->l1.min_pq); |
399 |
|
✗ |
put_bits(pb, 12, dm->l1.max_pq); |
400 |
|
✗ |
put_bits(pb, 12, dm->l1.avg_pq); |
401 |
|
✗ |
break; |
402 |
|
✗ |
case 2: |
403 |
|
✗ |
put_bits(pb, 12, dm->l2.target_max_pq); |
404 |
|
✗ |
put_bits(pb, 12, dm->l2.trim_slope); |
405 |
|
✗ |
put_bits(pb, 12, dm->l2.trim_offset); |
406 |
|
✗ |
put_bits(pb, 12, dm->l2.trim_power); |
407 |
|
✗ |
put_bits(pb, 12, dm->l2.trim_chroma_weight); |
408 |
|
✗ |
put_bits(pb, 12, dm->l2.trim_saturation_gain); |
409 |
|
✗ |
put_sbits(pb, 13, dm->l2.ms_weight); |
410 |
|
✗ |
break; |
411 |
|
✗ |
case 4: |
412 |
|
✗ |
put_bits(pb, 12, dm->l4.anchor_pq); |
413 |
|
✗ |
put_bits(pb, 12, dm->l4.anchor_power); |
414 |
|
✗ |
break; |
415 |
|
✗ |
case 5: |
416 |
|
✗ |
put_bits(pb, 13, dm->l5.left_offset); |
417 |
|
✗ |
put_bits(pb, 13, dm->l5.right_offset); |
418 |
|
✗ |
put_bits(pb, 13, dm->l5.top_offset); |
419 |
|
✗ |
put_bits(pb, 13, dm->l5.bottom_offset); |
420 |
|
✗ |
break; |
421 |
|
✗ |
case 6: |
422 |
|
✗ |
put_bits(pb, 16, dm->l6.max_luminance); |
423 |
|
✗ |
put_bits(pb, 16, dm->l6.min_luminance); |
424 |
|
✗ |
put_bits(pb, 16, dm->l6.max_cll); |
425 |
|
✗ |
put_bits(pb, 16, dm->l6.max_fall); |
426 |
|
✗ |
break; |
427 |
|
✗ |
case 255: |
428 |
|
✗ |
put_bits(pb, 8, dm->l255.dm_run_mode); |
429 |
|
✗ |
put_bits(pb, 8, dm->l255.dm_run_version); |
430 |
|
✗ |
for (int i = 0; i < 4; i++) |
431 |
|
✗ |
put_bits(pb, 8, dm->l255.dm_debug[i]); |
432 |
|
✗ |
break; |
433 |
|
|
} |
434 |
|
|
|
435 |
|
✗ |
pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); |
436 |
|
|
av_assert1(pad_bits >= 0); |
437 |
|
✗ |
put_bits(pb, pad_bits, 0); |
438 |
|
|
} |
439 |
|
|
|
440 |
|
✗ |
static void put_cie_xy(PutBitContext *pb, AVCIExy xy) |
441 |
|
|
{ |
442 |
|
✗ |
const int denom = 32767; |
443 |
|
✗ |
put_sbits(pb, 16, av_q2den(xy.x, denom)); |
444 |
|
✗ |
put_sbits(pb, 16, av_q2den(xy.y, denom)); |
445 |
|
✗ |
} |
446 |
|
|
|
447 |
|
|
#define ANY6(arr) (arr[0] || arr[1] || arr[2] || arr[3] || arr[4] || arr[5]) |
448 |
|
|
#define ANY_XY(xy) (xy.x.num || xy.y.num) |
449 |
|
|
#define ANY_CSP(csp) (ANY_XY(csp.prim.r) || ANY_XY(csp.prim.g) || \ |
450 |
|
|
ANY_XY(csp.prim.b) || ANY_XY(csp.wp)) |
451 |
|
|
|
452 |
|
✗ |
static void generate_ext_v2(PutBitContext *pb, const AVDOVIDmData *dm) |
453 |
|
|
{ |
454 |
|
|
int ext_block_length, start_pos, pad_bits; |
455 |
|
|
|
456 |
|
✗ |
switch (dm->level) { |
457 |
|
✗ |
case 3: ext_block_length = 5; break; |
458 |
|
✗ |
case 8: |
459 |
|
✗ |
if (ANY6(dm->l8.hue_vector_field)) { |
460 |
|
✗ |
ext_block_length = 25; |
461 |
|
✗ |
} else if (ANY6(dm->l8.saturation_vector_field)) { |
462 |
|
✗ |
ext_block_length = 19; |
463 |
|
✗ |
} else if (dm->l8.clip_trim) { |
464 |
|
✗ |
ext_block_length = 13; |
465 |
|
✗ |
} else if (dm->l8.target_mid_contrast) { |
466 |
|
✗ |
ext_block_length = 12; |
467 |
|
|
} else { |
468 |
|
✗ |
ext_block_length = 10; |
469 |
|
|
} |
470 |
|
✗ |
break; |
471 |
|
✗ |
case 9: |
472 |
|
✗ |
if (ANY_CSP(dm->l9.source_display_primaries)) { |
473 |
|
✗ |
ext_block_length = 17; |
474 |
|
|
} else { |
475 |
|
✗ |
ext_block_length = 1; |
476 |
|
|
} |
477 |
|
✗ |
break; |
478 |
|
✗ |
case 10: |
479 |
|
✗ |
if (ANY_CSP(dm->l10.target_display_primaries)) { |
480 |
|
✗ |
ext_block_length = 21; |
481 |
|
|
} else { |
482 |
|
✗ |
ext_block_length = 5; |
483 |
|
|
} |
484 |
|
✗ |
break; |
485 |
|
✗ |
case 11: ext_block_length = 4; break; |
486 |
|
✗ |
case 254: ext_block_length = 2; break; |
487 |
|
✗ |
default: return; |
488 |
|
|
} |
489 |
|
|
|
490 |
|
✗ |
set_ue_golomb(pb, ext_block_length); |
491 |
|
✗ |
put_bits(pb, 8, dm->level); |
492 |
|
✗ |
start_pos = put_bits_count(pb); |
493 |
|
|
|
494 |
|
✗ |
switch (dm->level) { |
495 |
|
✗ |
case 3: |
496 |
|
✗ |
put_bits(pb, 12, dm->l3.min_pq_offset); |
497 |
|
✗ |
put_bits(pb, 12, dm->l3.max_pq_offset); |
498 |
|
✗ |
put_bits(pb, 12, dm->l3.avg_pq_offset); |
499 |
|
✗ |
break; |
500 |
|
✗ |
case 8: |
501 |
|
✗ |
put_bits(pb, 8, dm->l8.target_display_index); |
502 |
|
✗ |
put_bits(pb, 12, dm->l8.trim_slope); |
503 |
|
✗ |
put_bits(pb, 12, dm->l8.trim_offset); |
504 |
|
✗ |
put_bits(pb, 12, dm->l8.trim_power); |
505 |
|
✗ |
put_bits(pb, 12, dm->l8.trim_chroma_weight); |
506 |
|
✗ |
put_bits(pb, 12, dm->l8.trim_saturation_gain); |
507 |
|
✗ |
put_bits(pb, 12, dm->l8.ms_weight); |
508 |
|
✗ |
if (ext_block_length < 12) |
509 |
|
✗ |
break; |
510 |
|
✗ |
put_bits(pb, 12, dm->l8.target_mid_contrast); |
511 |
|
✗ |
if (ext_block_length < 13) |
512 |
|
✗ |
break; |
513 |
|
✗ |
put_bits(pb, 12, dm->l8.clip_trim); |
514 |
|
✗ |
if (ext_block_length < 19) |
515 |
|
✗ |
break; |
516 |
|
✗ |
for (int i = 0; i < 6; i++) |
517 |
|
✗ |
put_bits(pb, 8, dm->l8.saturation_vector_field[i]); |
518 |
|
✗ |
if (ext_block_length < 25) |
519 |
|
✗ |
break; |
520 |
|
✗ |
for (int i = 0; i < 6; i++) |
521 |
|
✗ |
put_bits(pb, 8, dm->l8.hue_vector_field[i]); |
522 |
|
✗ |
break; |
523 |
|
✗ |
case 9: |
524 |
|
✗ |
put_bits(pb, 8, dm->l9.source_primary_index); |
525 |
|
✗ |
if (ext_block_length < 17) |
526 |
|
✗ |
break; |
527 |
|
✗ |
put_cie_xy(pb, dm->l9.source_display_primaries.prim.r); |
528 |
|
✗ |
put_cie_xy(pb, dm->l9.source_display_primaries.prim.g); |
529 |
|
✗ |
put_cie_xy(pb, dm->l9.source_display_primaries.prim.b); |
530 |
|
✗ |
put_cie_xy(pb, dm->l9.source_display_primaries.wp); |
531 |
|
✗ |
break; |
532 |
|
✗ |
case 10: |
533 |
|
✗ |
put_bits(pb, 8, dm->l10.target_display_index); |
534 |
|
✗ |
put_bits(pb, 12, dm->l10.target_max_pq); |
535 |
|
✗ |
put_bits(pb, 12, dm->l10.target_min_pq); |
536 |
|
✗ |
put_bits(pb, 8, dm->l10.target_primary_index); |
537 |
|
✗ |
if (ext_block_length < 21) |
538 |
|
✗ |
break; |
539 |
|
✗ |
put_cie_xy(pb, dm->l10.target_display_primaries.prim.r); |
540 |
|
✗ |
put_cie_xy(pb, dm->l10.target_display_primaries.prim.g); |
541 |
|
✗ |
put_cie_xy(pb, dm->l10.target_display_primaries.prim.b); |
542 |
|
✗ |
put_cie_xy(pb, dm->l10.target_display_primaries.wp); |
543 |
|
✗ |
break; |
544 |
|
✗ |
case 11: |
545 |
|
✗ |
put_bits(pb, 8, dm->l11.content_type); |
546 |
|
✗ |
put_bits(pb, 4, dm->l11.whitepoint); |
547 |
|
✗ |
put_bits(pb, 1, dm->l11.reference_mode_flag); |
548 |
|
✗ |
put_bits(pb, 3, 0); /* reserved */ |
549 |
|
✗ |
put_bits(pb, 2, dm->l11.sharpness); |
550 |
|
✗ |
put_bits(pb, 2, dm->l11.noise_reduction); |
551 |
|
✗ |
put_bits(pb, 2, dm->l11.mpeg_noise_reduction); |
552 |
|
✗ |
put_bits(pb, 2, dm->l11.frame_rate_conversion); |
553 |
|
✗ |
put_bits(pb, 2, dm->l11.brightness); |
554 |
|
✗ |
put_bits(pb, 2, dm->l11.color); |
555 |
|
✗ |
break; |
556 |
|
✗ |
case 254: |
557 |
|
✗ |
put_bits(pb, 8, dm->l254.dm_mode); |
558 |
|
✗ |
put_bits(pb, 8, dm->l254.dm_version_index); |
559 |
|
✗ |
break; |
560 |
|
|
} |
561 |
|
|
|
562 |
|
✗ |
pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); |
563 |
|
|
av_assert1(pad_bits >= 0); |
564 |
|
✗ |
put_bits(pb, pad_bits, 0); |
565 |
|
|
} |
566 |
|
|
|
567 |
|
✗ |
int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, |
568 |
|
|
int flags, uint8_t **out_rpu, int *out_size) |
569 |
|
|
{ |
570 |
|
✗ |
PutBitContext *pb = &(PutBitContext){0}; |
571 |
|
|
const AVDOVIRpuDataHeader *hdr; |
572 |
|
|
const AVDOVIDataMapping *mapping; |
573 |
|
|
const AVDOVIColorMetadata *color; |
574 |
|
|
int vdr_dm_metadata_present, vdr_rpu_id, use_prev_vdr_rpu, profile, |
575 |
|
|
buffer_size, rpu_size, pad, zero_run, dm_compression; |
576 |
|
|
int num_ext_blocks_v1, num_ext_blocks_v2; |
577 |
|
✗ |
int dv_md_compression = s->cfg.dv_md_compression; |
578 |
|
|
uint32_t crc; |
579 |
|
|
uint8_t *dst; |
580 |
|
✗ |
if (!metadata) { |
581 |
|
✗ |
*out_rpu = NULL; |
582 |
|
✗ |
*out_size = 0; |
583 |
|
✗ |
return 0; |
584 |
|
|
} |
585 |
|
|
|
586 |
|
✗ |
hdr = av_dovi_get_header(metadata); |
587 |
|
✗ |
mapping = av_dovi_get_mapping(metadata); |
588 |
|
✗ |
color = av_dovi_get_color(metadata); |
589 |
|
✗ |
av_assert0(s->cfg.dv_profile); |
590 |
|
|
|
591 |
|
✗ |
if (!(flags & FF_DOVI_COMPRESS_RPU)) |
592 |
|
✗ |
dv_md_compression = AV_DOVI_COMPRESSION_NONE; |
593 |
|
✗ |
else if (dv_md_compression == AV_DOVI_COMPRESSION_RESERVED) |
594 |
|
✗ |
return AVERROR(EINVAL); |
595 |
|
|
|
596 |
|
✗ |
if (hdr->rpu_type != 2) { |
597 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Unhandled RPU type %"PRIu8"\n", |
598 |
|
✗ |
hdr->rpu_type); |
599 |
|
✗ |
return AVERROR_INVALIDDATA; |
600 |
|
|
} |
601 |
|
|
|
602 |
|
✗ |
if (!(flags & FF_DOVI_COMPRESS_RPU)) |
603 |
|
✗ |
dv_md_compression = AV_DOVI_COMPRESSION_NONE; |
604 |
|
|
|
605 |
|
✗ |
vdr_rpu_id = mapping->vdr_rpu_id; |
606 |
|
✗ |
use_prev_vdr_rpu = 0; |
607 |
|
|
|
608 |
|
✗ |
if (!s->vdr[vdr_rpu_id]) { |
609 |
|
✗ |
s->vdr[vdr_rpu_id] = av_refstruct_allocz(sizeof(AVDOVIDataMapping)); |
610 |
|
✗ |
if (!s->vdr[vdr_rpu_id]) |
611 |
|
✗ |
return AVERROR(ENOMEM); |
612 |
|
|
} |
613 |
|
|
|
614 |
|
✗ |
switch (dv_md_compression) { |
615 |
|
✗ |
case AV_DOVI_COMPRESSION_LIMITED: |
616 |
|
|
/* Limited metadata compression requires vdr_rpi_id == 0 */ |
617 |
|
✗ |
if (vdr_rpu_id != 0) |
618 |
|
✗ |
break; |
619 |
|
|
/* fall through */ |
620 |
|
|
case AV_DOVI_COMPRESSION_EXTENDED: |
621 |
|
✗ |
if (s->vdr[vdr_rpu_id]) |
622 |
|
✗ |
use_prev_vdr_rpu = !memcmp(s->vdr[vdr_rpu_id], mapping, sizeof(*mapping)); |
623 |
|
✗ |
break; |
624 |
|
✗ |
case AV_DOVI_COMPRESSION_RESERVED: |
625 |
|
✗ |
return AVERROR(EINVAL); |
626 |
|
|
} |
627 |
|
|
|
628 |
|
✗ |
if (s->cfg.dv_md_compression != AV_DOVI_COMPRESSION_EXTENDED) { |
629 |
|
|
/* Flush VDRs to avoid leaking old state; maintaining multiple VDR |
630 |
|
|
* references requires extended compression */ |
631 |
|
✗ |
for (int i = 0; i <= DOVI_MAX_DM_ID; i++) { |
632 |
|
✗ |
if (i != vdr_rpu_id) |
633 |
|
✗ |
av_refstruct_unref(&s->vdr[i]); |
634 |
|
|
} |
635 |
|
|
} |
636 |
|
|
|
637 |
|
✗ |
if (metadata->num_ext_blocks && !s->ext_blocks) { |
638 |
|
✗ |
s->ext_blocks = av_refstruct_allocz(sizeof(*s->ext_blocks)); |
639 |
|
✗ |
if (!s->ext_blocks) |
640 |
|
✗ |
return AVERROR(ENOMEM); |
641 |
|
|
} |
642 |
|
|
|
643 |
|
✗ |
vdr_dm_metadata_present = memcmp(color, &ff_dovi_color_default, sizeof(*color)); |
644 |
|
✗ |
if (metadata->num_ext_blocks) |
645 |
|
✗ |
vdr_dm_metadata_present = 1; |
646 |
|
|
|
647 |
|
✗ |
if (vdr_dm_metadata_present && !s->dm) { |
648 |
|
✗ |
s->dm = av_refstruct_allocz(sizeof(AVDOVIColorMetadata)); |
649 |
|
✗ |
if (!s->dm) |
650 |
|
✗ |
return AVERROR(ENOMEM); |
651 |
|
|
} |
652 |
|
|
|
653 |
|
✗ |
dm_compression = 0; |
654 |
|
✗ |
if (dv_md_compression != AV_DOVI_COMPRESSION_NONE) { |
655 |
|
✗ |
if (!cmp_dm_level0(s->dm, color) && try_reuse_ext(s->ext_blocks, metadata)) |
656 |
|
✗ |
dm_compression = 1; |
657 |
|
|
} |
658 |
|
|
|
659 |
|
✗ |
num_ext_blocks_v1 = num_ext_blocks_v2 = 0; |
660 |
|
✗ |
for (int i = 0; i < metadata->num_ext_blocks; i++) { |
661 |
|
✗ |
const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); |
662 |
|
✗ |
if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) |
663 |
|
✗ |
continue; |
664 |
|
|
|
665 |
|
✗ |
switch (dm->level) { |
666 |
|
✗ |
case 1: |
667 |
|
|
case 2: |
668 |
|
|
case 4: |
669 |
|
|
case 5: |
670 |
|
|
case 6: |
671 |
|
|
case 255: |
672 |
|
✗ |
num_ext_blocks_v1++; |
673 |
|
✗ |
break; |
674 |
|
✗ |
case 3: |
675 |
|
|
case 8: |
676 |
|
|
case 9: |
677 |
|
|
case 10: |
678 |
|
|
case 11: |
679 |
|
|
case 254: |
680 |
|
✗ |
num_ext_blocks_v2++; |
681 |
|
✗ |
break; |
682 |
|
✗ |
default: |
683 |
|
✗ |
av_log(s->logctx, AV_LOG_ERROR, "Invalid ext block level %d\n", |
684 |
|
✗ |
dm->level); |
685 |
|
✗ |
return AVERROR_INVALIDDATA; |
686 |
|
|
} |
687 |
|
|
} |
688 |
|
|
|
689 |
|
✗ |
buffer_size = 12 /* vdr seq info */ + 5 /* CRC32 + terminator */; |
690 |
|
✗ |
buffer_size += num_ext_blocks_v1 * 13; |
691 |
|
✗ |
buffer_size += num_ext_blocks_v2 * 28; |
692 |
|
✗ |
if (!use_prev_vdr_rpu) { |
693 |
|
✗ |
buffer_size += 160; |
694 |
|
✗ |
for (int c = 0; c < 3; c++) { |
695 |
|
✗ |
for (int i = 0; i < mapping->curves[c].num_pivots - 1; i++) { |
696 |
|
✗ |
switch (mapping->curves[c].mapping_idc[i]) { |
697 |
|
✗ |
case AV_DOVI_MAPPING_POLYNOMIAL: buffer_size += 26; break; |
698 |
|
✗ |
case AV_DOVI_MAPPING_MMR: buffer_size += 177; break; |
699 |
|
|
} |
700 |
|
|
} |
701 |
|
|
} |
702 |
|
|
} |
703 |
|
✗ |
if (vdr_dm_metadata_present) |
704 |
|
✗ |
buffer_size += 67; |
705 |
|
|
|
706 |
|
✗ |
av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, buffer_size); |
707 |
|
✗ |
if (!s->rpu_buf) |
708 |
|
✗ |
return AVERROR(ENOMEM); |
709 |
|
✗ |
init_put_bits(pb, s->rpu_buf, s->rpu_buf_sz); |
710 |
|
|
|
711 |
|
|
/* RPU header */ |
712 |
|
✗ |
put_bits(pb, 6, hdr->rpu_type); |
713 |
|
✗ |
put_bits(pb, 11, hdr->rpu_format); |
714 |
|
✗ |
put_bits(pb, 4, hdr->vdr_rpu_profile); |
715 |
|
✗ |
put_bits(pb, 4, hdr->vdr_rpu_level); |
716 |
|
✗ |
put_bits(pb, 1, 1); /* vdr_seq_info_present */ |
717 |
|
✗ |
put_bits(pb, 1, hdr->chroma_resampling_explicit_filter_flag); |
718 |
|
✗ |
put_bits(pb, 2, hdr->coef_data_type); |
719 |
|
✗ |
if (hdr->coef_data_type == RPU_COEFF_FIXED) |
720 |
|
✗ |
set_ue_golomb(pb, hdr->coef_log2_denom); |
721 |
|
✗ |
put_bits(pb, 2, hdr->vdr_rpu_normalized_idc); |
722 |
|
✗ |
put_bits(pb, 1, hdr->bl_video_full_range_flag); |
723 |
|
✗ |
if ((hdr->rpu_format & 0x700) == 0) { |
724 |
|
✗ |
int ext_mapping_idc = (hdr->ext_mapping_idc_5_7 << 5) | hdr->ext_mapping_idc_0_4; |
725 |
|
✗ |
set_ue_golomb(pb, hdr->bl_bit_depth - 8); |
726 |
|
✗ |
set_ue_golomb(pb, (ext_mapping_idc << 8) | (hdr->el_bit_depth - 8)); |
727 |
|
✗ |
set_ue_golomb(pb, hdr->vdr_bit_depth - 8); |
728 |
|
✗ |
put_bits(pb, 1, hdr->spatial_resampling_filter_flag); |
729 |
|
✗ |
put_bits(pb, 3, dm_compression); |
730 |
|
✗ |
put_bits(pb, 1, hdr->el_spatial_resampling_filter_flag); |
731 |
|
✗ |
put_bits(pb, 1, hdr->disable_residual_flag); |
732 |
|
|
} |
733 |
|
✗ |
s->header = *hdr; |
734 |
|
|
|
735 |
|
✗ |
put_bits(pb, 1, vdr_dm_metadata_present); |
736 |
|
✗ |
put_bits(pb, 1, use_prev_vdr_rpu); |
737 |
|
✗ |
set_ue_golomb(pb, vdr_rpu_id); |
738 |
|
✗ |
s->mapping = s->vdr[vdr_rpu_id]; |
739 |
|
|
|
740 |
|
✗ |
profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); |
741 |
|
|
|
742 |
|
✗ |
if (!use_prev_vdr_rpu) { |
743 |
|
✗ |
set_ue_golomb(pb, mapping->mapping_color_space); |
744 |
|
✗ |
set_ue_golomb(pb, mapping->mapping_chroma_format_idc); |
745 |
|
✗ |
for (int c = 0; c < 3; c++) { |
746 |
|
✗ |
const AVDOVIReshapingCurve *curve = &mapping->curves[c]; |
747 |
|
✗ |
int prev = 0; |
748 |
|
✗ |
set_ue_golomb(pb, curve->num_pivots - 2); |
749 |
|
✗ |
for (int i = 0; i < curve->num_pivots; i++) { |
750 |
|
✗ |
put_bits(pb, hdr->bl_bit_depth, curve->pivots[i] - prev); |
751 |
|
✗ |
prev = curve->pivots[i]; |
752 |
|
|
} |
753 |
|
|
} |
754 |
|
|
|
755 |
|
✗ |
if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { |
756 |
|
✗ |
put_bits(pb, 3, mapping->nlq_method_idc); |
757 |
|
✗ |
put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[0]); |
758 |
|
✗ |
put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[1] - mapping->nlq_pivots[0]); |
759 |
|
|
} |
760 |
|
|
|
761 |
|
✗ |
set_ue_golomb(pb, mapping->num_x_partitions - 1); |
762 |
|
✗ |
set_ue_golomb(pb, mapping->num_y_partitions - 1); |
763 |
|
|
|
764 |
|
✗ |
for (int c = 0; c < 3; c++) { |
765 |
|
✗ |
const AVDOVIReshapingCurve *curve = &mapping->curves[c]; |
766 |
|
✗ |
for (int i = 0; i < curve->num_pivots - 1; i++) { |
767 |
|
✗ |
set_ue_golomb(pb, curve->mapping_idc[i]); |
768 |
|
✗ |
switch (curve->mapping_idc[i]) { |
769 |
|
✗ |
case AV_DOVI_MAPPING_POLYNOMIAL: { |
770 |
|
✗ |
set_ue_golomb(pb, curve->poly_order[i] - 1); |
771 |
|
✗ |
if (curve->poly_order[i] == 1) |
772 |
|
✗ |
put_bits(pb, 1, 0); /* linear_interp_flag */ |
773 |
|
✗ |
for (int k = 0; k <= curve->poly_order[i]; k++) |
774 |
|
✗ |
put_se_coef(pb, hdr, curve->poly_coef[i][k]); |
775 |
|
✗ |
break; |
776 |
|
|
} |
777 |
|
✗ |
case AV_DOVI_MAPPING_MMR: { |
778 |
|
✗ |
put_bits(pb, 2, curve->mmr_order[i] - 1); |
779 |
|
✗ |
put_se_coef(pb, hdr, curve->mmr_constant[i]); |
780 |
|
✗ |
for (int j = 0; j < curve->mmr_order[i]; j++) { |
781 |
|
✗ |
for (int k = 0; k < 7; k++) |
782 |
|
✗ |
put_se_coef(pb, hdr, curve->mmr_coef[i][j][k]); |
783 |
|
|
} |
784 |
|
✗ |
break; |
785 |
|
|
} |
786 |
|
|
} |
787 |
|
|
} |
788 |
|
|
} |
789 |
|
|
|
790 |
|
✗ |
if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { |
791 |
|
✗ |
for (int c = 0; c < 3; c++) { |
792 |
|
✗ |
const AVDOVINLQParams *nlq = &mapping->nlq[c]; |
793 |
|
✗ |
put_bits(pb, hdr->el_bit_depth, nlq->nlq_offset); |
794 |
|
✗ |
put_ue_coef(pb, hdr, nlq->vdr_in_max); |
795 |
|
✗ |
switch (mapping->nlq_method_idc) { |
796 |
|
✗ |
case AV_DOVI_NLQ_LINEAR_DZ: |
797 |
|
✗ |
put_ue_coef(pb, hdr, nlq->linear_deadzone_slope); |
798 |
|
✗ |
put_ue_coef(pb, hdr, nlq->linear_deadzone_threshold); |
799 |
|
✗ |
break; |
800 |
|
|
} |
801 |
|
|
} |
802 |
|
|
} |
803 |
|
|
|
804 |
|
✗ |
memcpy(s->vdr[vdr_rpu_id], mapping, sizeof(*mapping)); |
805 |
|
|
} |
806 |
|
|
|
807 |
|
✗ |
if (vdr_dm_metadata_present) { |
808 |
|
✗ |
DOVIExt *ext = s->ext_blocks; |
809 |
|
✗ |
const int denom = profile == 4 ? (1 << 30) : (1 << 28); |
810 |
|
✗ |
set_ue_golomb(pb, color->dm_metadata_id); /* affected_dm_id */ |
811 |
|
✗ |
set_ue_golomb(pb, color->dm_metadata_id); /* current_dm_id */ |
812 |
|
✗ |
set_ue_golomb(pb, color->scene_refresh_flag); |
813 |
|
✗ |
if (!dm_compression) { |
814 |
|
✗ |
for (int i = 0; i < 9; i++) |
815 |
|
✗ |
put_sbits(pb, 16, av_q2den(color->ycc_to_rgb_matrix[i], 1 << 13)); |
816 |
|
✗ |
for (int i = 0; i < 3; i++) |
817 |
|
✗ |
put_bits32(pb, av_q2den(color->ycc_to_rgb_offset[i], denom)); |
818 |
|
✗ |
for (int i = 0; i < 9; i++) |
819 |
|
✗ |
put_sbits(pb, 16, av_q2den(color->rgb_to_lms_matrix[i], 1 << 14)); |
820 |
|
✗ |
put_bits(pb, 16, color->signal_eotf); |
821 |
|
✗ |
put_bits(pb, 16, color->signal_eotf_param0); |
822 |
|
✗ |
put_bits(pb, 16, color->signal_eotf_param1); |
823 |
|
✗ |
put_bits32(pb, color->signal_eotf_param2); |
824 |
|
✗ |
put_bits(pb, 5, color->signal_bit_depth); |
825 |
|
✗ |
put_bits(pb, 2, color->signal_color_space); |
826 |
|
✗ |
put_bits(pb, 2, color->signal_chroma_format); |
827 |
|
✗ |
put_bits(pb, 2, color->signal_full_range_flag); |
828 |
|
✗ |
put_bits(pb, 12, color->source_min_pq); |
829 |
|
✗ |
put_bits(pb, 12, color->source_max_pq); |
830 |
|
✗ |
put_bits(pb, 10, color->source_diagonal); |
831 |
|
|
} |
832 |
|
|
|
833 |
|
✗ |
memcpy(s->dm, color, sizeof(*color)); |
834 |
|
✗ |
s->color = s->dm; |
835 |
|
|
|
836 |
|
|
/* Extension blocks */ |
837 |
|
✗ |
set_ue_golomb(pb, num_ext_blocks_v1); |
838 |
|
✗ |
align_put_bits(pb); |
839 |
|
✗ |
for (int i = 0; i < metadata->num_ext_blocks; i++) { |
840 |
|
✗ |
const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); |
841 |
|
✗ |
if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) |
842 |
|
✗ |
continue; |
843 |
|
✗ |
generate_ext_v1(pb, dm); |
844 |
|
|
} |
845 |
|
|
|
846 |
|
✗ |
if (num_ext_blocks_v2) { |
847 |
|
✗ |
set_ue_golomb(pb, num_ext_blocks_v2); |
848 |
|
✗ |
align_put_bits(pb); |
849 |
|
✗ |
for (int i = 0; i < metadata->num_ext_blocks; i++) { |
850 |
|
✗ |
const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); |
851 |
|
✗ |
if (dm_compression && ff_dovi_rpu_extension_is_static(dm->level)) |
852 |
|
✗ |
continue; |
853 |
|
✗ |
generate_ext_v2(pb, av_dovi_get_ext(metadata, i)); |
854 |
|
|
} |
855 |
|
|
} |
856 |
|
|
|
857 |
|
✗ |
if (ext) { |
858 |
|
✗ |
size_t ext_sz = FFMIN(sizeof(AVDOVIDmData), metadata->ext_block_size); |
859 |
|
✗ |
ext->num_dynamic = 0; |
860 |
|
✗ |
if (!dm_compression) |
861 |
|
✗ |
ext->num_static = 0; |
862 |
|
✗ |
for (int i = 0; i < metadata->num_ext_blocks; i++) { |
863 |
|
✗ |
const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); |
864 |
|
✗ |
if (!ff_dovi_rpu_extension_is_static(dm->level)) |
865 |
|
✗ |
memcpy(&ext->dm_dynamic[ext->num_dynamic++], dm, ext_sz); |
866 |
|
✗ |
else if (!dm_compression) |
867 |
|
✗ |
memcpy(&ext->dm_static[ext->num_static++], dm, ext_sz); |
868 |
|
|
} |
869 |
|
|
} |
870 |
|
|
} else { |
871 |
|
✗ |
s->color = &ff_dovi_color_default; |
872 |
|
✗ |
av_refstruct_unref(&s->ext_blocks); |
873 |
|
|
} |
874 |
|
|
|
875 |
|
✗ |
flush_put_bits(pb); |
876 |
|
✗ |
crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, |
877 |
|
✗ |
s->rpu_buf, put_bytes_output(pb))); |
878 |
|
✗ |
put_bits32(pb, crc); |
879 |
|
✗ |
put_bits(pb, 8, 0x80); /* terminator */ |
880 |
|
✗ |
flush_put_bits(pb); |
881 |
|
|
|
882 |
|
✗ |
rpu_size = put_bytes_output(pb); |
883 |
|
✗ |
if (flags & FF_DOVI_WRAP_T35) { |
884 |
|
✗ |
*out_rpu = av_malloc(rpu_size + 15); |
885 |
|
✗ |
if (!*out_rpu) |
886 |
|
✗ |
return AVERROR(ENOMEM); |
887 |
|
✗ |
init_put_bits(pb, *out_rpu, rpu_size + 15); |
888 |
|
✗ |
put_bits(pb, 8, ITU_T_T35_COUNTRY_CODE_US); |
889 |
|
✗ |
put_bits(pb, 16, ITU_T_T35_PROVIDER_CODE_DOLBY); |
890 |
|
✗ |
put_bits32(pb, 0x800); /* provider_oriented_code */ |
891 |
|
✗ |
put_bits(pb, 27, 0x01be6841u); /* fixed EMDF header, see above */ |
892 |
|
✗ |
if (rpu_size > 0xFF) { |
893 |
|
|
av_assert2(rpu_size <= 0x10000); |
894 |
|
✗ |
put_bits(pb, 8, (rpu_size >> 8) - 1); |
895 |
|
✗ |
put_bits(pb, 1, 1); /* read_more */ |
896 |
|
✗ |
put_bits(pb, 8, rpu_size & 0xFF); |
897 |
|
✗ |
put_bits(pb, 1, 0); |
898 |
|
|
} else { |
899 |
|
✗ |
put_bits(pb, 8, rpu_size); |
900 |
|
✗ |
put_bits(pb, 1, 0); |
901 |
|
|
} |
902 |
|
✗ |
ff_copy_bits(pb, s->rpu_buf, rpu_size * 8); |
903 |
|
✗ |
put_bits(pb, 17, 0x400); /* emdf payload id + emdf_protection */ |
904 |
|
|
|
905 |
|
✗ |
pad = pb->bit_left & 7; |
906 |
|
✗ |
put_bits(pb, pad, (1 << pad) - 1); /* pad to next byte with 1 bits */ |
907 |
|
✗ |
flush_put_bits(pb); |
908 |
|
✗ |
*out_size = put_bytes_output(pb); |
909 |
|
✗ |
return 0; |
910 |
|
✗ |
} else if (flags & FF_DOVI_WRAP_NAL) { |
911 |
|
✗ |
*out_rpu = dst = av_malloc(4 + rpu_size * 3 / 2); /* worst case */ |
912 |
|
✗ |
if (!*out_rpu) |
913 |
|
✗ |
return AVERROR(ENOMEM); |
914 |
|
✗ |
*dst++ = 25; /* NAL prefix */ |
915 |
|
✗ |
zero_run = 0; |
916 |
|
✗ |
for (int i = 0; i < rpu_size; i++) { |
917 |
|
✗ |
if (zero_run < 2) { |
918 |
|
✗ |
if (s->rpu_buf[i] == 0) { |
919 |
|
✗ |
zero_run++; |
920 |
|
|
} else { |
921 |
|
✗ |
zero_run = 0; |
922 |
|
|
} |
923 |
|
|
} else { |
924 |
|
✗ |
if ((s->rpu_buf[i] & ~3) == 0) { |
925 |
|
|
/* emulation prevention */ |
926 |
|
✗ |
*dst++ = 3; |
927 |
|
|
} |
928 |
|
✗ |
zero_run = s->rpu_buf[i] == 0; |
929 |
|
|
} |
930 |
|
✗ |
*dst++ = s->rpu_buf[i]; |
931 |
|
|
} |
932 |
|
✗ |
*out_size = dst - *out_rpu; |
933 |
|
✗ |
return 0; |
934 |
|
|
} else { |
935 |
|
|
/* Return intermediate buffer directly */ |
936 |
|
✗ |
*out_rpu = s->rpu_buf; |
937 |
|
✗ |
*out_size = rpu_size; |
938 |
|
✗ |
s->rpu_buf = NULL; |
939 |
|
✗ |
s->rpu_buf_sz = 0; |
940 |
|
✗ |
return 0; |
941 |
|
|
} |
942 |
|
|
} |
943 |
|
|
|