1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Dolby Vision RPU decoder 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (C) 2021 Jan Ekström 5cabdff1aSopenharmony_ci * Copyright (C) 2021 Niklas Haas 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * This file is part of FFmpeg. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17cabdff1aSopenharmony_ci * Lesser General Public License for more details. 18cabdff1aSopenharmony_ci * 19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22cabdff1aSopenharmony_ci */ 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "libavutil/buffer.h" 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include "dovi_rpu.h" 27cabdff1aSopenharmony_ci#include "golomb.h" 28cabdff1aSopenharmony_ci#include "get_bits.h" 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_cienum { 31cabdff1aSopenharmony_ci RPU_COEFF_FIXED = 0, 32cabdff1aSopenharmony_ci RPU_COEFF_FLOAT = 1, 33cabdff1aSopenharmony_ci}; 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci/** 36cabdff1aSopenharmony_ci * Private contents of vdr_ref. 37cabdff1aSopenharmony_ci */ 38cabdff1aSopenharmony_citypedef struct DOVIVdrRef { 39cabdff1aSopenharmony_ci AVDOVIDataMapping mapping; 40cabdff1aSopenharmony_ci AVDOVIColorMetadata color; 41cabdff1aSopenharmony_ci} DOVIVdrRef; 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_civoid ff_dovi_ctx_unref(DOVIContext *s) 44cabdff1aSopenharmony_ci{ 45cabdff1aSopenharmony_ci for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) 46cabdff1aSopenharmony_ci av_buffer_unref(&s->vdr_ref[i]); 47cabdff1aSopenharmony_ci 48cabdff1aSopenharmony_ci *s = (DOVIContext) { 49cabdff1aSopenharmony_ci .logctx = s->logctx, 50cabdff1aSopenharmony_ci }; 51cabdff1aSopenharmony_ci} 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_civoid ff_dovi_ctx_flush(DOVIContext *s) 54cabdff1aSopenharmony_ci{ 55cabdff1aSopenharmony_ci for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) 56cabdff1aSopenharmony_ci av_buffer_unref(&s->vdr_ref[i]); 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_ci *s = (DOVIContext) { 59cabdff1aSopenharmony_ci .logctx = s->logctx, 60cabdff1aSopenharmony_ci .dv_profile = s->dv_profile, 61cabdff1aSopenharmony_ci }; 62cabdff1aSopenharmony_ci} 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ciint ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) 65cabdff1aSopenharmony_ci{ 66cabdff1aSopenharmony_ci int ret; 67cabdff1aSopenharmony_ci s->logctx = s0->logctx; 68cabdff1aSopenharmony_ci s->mapping = s0->mapping; 69cabdff1aSopenharmony_ci s->color = s0->color; 70cabdff1aSopenharmony_ci s->dv_profile = s0->dv_profile; 71cabdff1aSopenharmony_ci for (int i = 0; i < DOVI_MAX_DM_ID; i++) { 72cabdff1aSopenharmony_ci if ((ret = av_buffer_replace(&s->vdr_ref[i], s0->vdr_ref[i])) < 0) 73cabdff1aSopenharmony_ci goto fail; 74cabdff1aSopenharmony_ci } 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci return 0; 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_cifail: 79cabdff1aSopenharmony_ci ff_dovi_ctx_unref(s); 80cabdff1aSopenharmony_ci return ret; 81cabdff1aSopenharmony_ci} 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_civoid ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg) 84cabdff1aSopenharmony_ci{ 85cabdff1aSopenharmony_ci if (!cfg) 86cabdff1aSopenharmony_ci return; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci s->dv_profile = cfg->dv_profile; 89cabdff1aSopenharmony_ci} 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ciint ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) 92cabdff1aSopenharmony_ci{ 93cabdff1aSopenharmony_ci AVFrameSideData *sd; 94cabdff1aSopenharmony_ci AVBufferRef *buf; 95cabdff1aSopenharmony_ci AVDOVIMetadata *dovi; 96cabdff1aSopenharmony_ci size_t dovi_size; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci if (!s->mapping || !s->color) 99cabdff1aSopenharmony_ci return 0; /* incomplete dovi metadata */ 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci dovi = av_dovi_metadata_alloc(&dovi_size); 102cabdff1aSopenharmony_ci if (!dovi) 103cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0); 106cabdff1aSopenharmony_ci if (!buf) { 107cabdff1aSopenharmony_ci av_free(dovi); 108cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 109cabdff1aSopenharmony_ci } 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); 112cabdff1aSopenharmony_ci if (!sd) { 113cabdff1aSopenharmony_ci av_buffer_unref(&buf); 114cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci /* Copy only the parts of these structs known to us at compiler-time. */ 118cabdff1aSopenharmony_ci#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) 119cabdff1aSopenharmony_ci COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag); 120cabdff1aSopenharmony_ci COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq[2].linear_deadzone_threshold); 121cabdff1aSopenharmony_ci COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); 122cabdff1aSopenharmony_ci return 0; 123cabdff1aSopenharmony_ci} 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_cistatic int guess_profile(const AVDOVIRpuDataHeader *hdr) 126cabdff1aSopenharmony_ci{ 127cabdff1aSopenharmony_ci switch (hdr->vdr_rpu_profile) { 128cabdff1aSopenharmony_ci case 0: 129cabdff1aSopenharmony_ci if (hdr->bl_video_full_range_flag) 130cabdff1aSopenharmony_ci return 5; 131cabdff1aSopenharmony_ci break; 132cabdff1aSopenharmony_ci case 1: 133cabdff1aSopenharmony_ci if (hdr->el_spatial_resampling_filter_flag && !hdr->disable_residual_flag) { 134cabdff1aSopenharmony_ci if (hdr->vdr_bit_depth == 12) { 135cabdff1aSopenharmony_ci return 7; 136cabdff1aSopenharmony_ci } else { 137cabdff1aSopenharmony_ci return 4; 138cabdff1aSopenharmony_ci } 139cabdff1aSopenharmony_ci } else { 140cabdff1aSopenharmony_ci return 8; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci return 0; /* unknown */ 145cabdff1aSopenharmony_ci} 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_cistatic inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) 148cabdff1aSopenharmony_ci{ 149cabdff1aSopenharmony_ci uint64_t ipart; 150cabdff1aSopenharmony_ci union { uint32_t u32; float f32; } fpart; 151cabdff1aSopenharmony_ci 152cabdff1aSopenharmony_ci switch (hdr->coef_data_type) { 153cabdff1aSopenharmony_ci case RPU_COEFF_FIXED: 154cabdff1aSopenharmony_ci ipart = get_ue_golomb_long(gb); 155cabdff1aSopenharmony_ci fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); 156cabdff1aSopenharmony_ci return (ipart << hdr->coef_log2_denom) + fpart.u32; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci case RPU_COEFF_FLOAT: 159cabdff1aSopenharmony_ci fpart.u32 = get_bits_long(gb, 32); 160cabdff1aSopenharmony_ci return fpart.f32 * (1LL << hdr->coef_log2_denom); 161cabdff1aSopenharmony_ci } 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci return 0; /* unreachable */ 164cabdff1aSopenharmony_ci} 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_cistatic inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) 167cabdff1aSopenharmony_ci{ 168cabdff1aSopenharmony_ci int64_t ipart; 169cabdff1aSopenharmony_ci union { uint32_t u32; float f32; } fpart; 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci switch (hdr->coef_data_type) { 172cabdff1aSopenharmony_ci case RPU_COEFF_FIXED: 173cabdff1aSopenharmony_ci ipart = get_se_golomb_long(gb); 174cabdff1aSopenharmony_ci fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); 175cabdff1aSopenharmony_ci return ipart * (1LL << hdr->coef_log2_denom) + fpart.u32; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci case RPU_COEFF_FLOAT: 178cabdff1aSopenharmony_ci fpart.u32 = get_bits_long(gb, 32); 179cabdff1aSopenharmony_ci return fpart.f32 * (1LL << hdr->coef_log2_denom); 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci return 0; /* unreachable */ 183cabdff1aSopenharmony_ci} 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci#define VALIDATE(VAR, MIN, MAX) \ 186cabdff1aSopenharmony_ci do { \ 187cabdff1aSopenharmony_ci if (VAR < MIN || VAR > MAX) { \ 188cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ 189cabdff1aSopenharmony_ci #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ 190cabdff1aSopenharmony_ci goto fail; \ 191cabdff1aSopenharmony_ci } \ 192cabdff1aSopenharmony_ci } while (0) 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ciint ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size) 195cabdff1aSopenharmony_ci{ 196cabdff1aSopenharmony_ci AVDOVIRpuDataHeader *hdr = &s->header; 197cabdff1aSopenharmony_ci GetBitContext *gb = &(GetBitContext){0}; 198cabdff1aSopenharmony_ci DOVIVdrRef *vdr; 199cabdff1aSopenharmony_ci int ret; 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci uint8_t nal_prefix; 202cabdff1aSopenharmony_ci uint8_t rpu_type; 203cabdff1aSopenharmony_ci uint8_t vdr_seq_info_present; 204cabdff1aSopenharmony_ci uint8_t vdr_dm_metadata_present; 205cabdff1aSopenharmony_ci uint8_t use_prev_vdr_rpu; 206cabdff1aSopenharmony_ci uint8_t use_nlq; 207cabdff1aSopenharmony_ci uint8_t profile; 208cabdff1aSopenharmony_ci if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) 209cabdff1aSopenharmony_ci return ret; 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci /* RPU header, common values */ 212cabdff1aSopenharmony_ci nal_prefix = get_bits(gb, 8); 213cabdff1aSopenharmony_ci VALIDATE(nal_prefix, 25, 25); 214cabdff1aSopenharmony_ci rpu_type = get_bits(gb, 6); 215cabdff1aSopenharmony_ci if (rpu_type != 2) { 216cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " 217cabdff1aSopenharmony_ci "%"PRIu8", ignoring\n", rpu_type); 218cabdff1aSopenharmony_ci return 0; 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci hdr->rpu_type = rpu_type; 222cabdff1aSopenharmony_ci hdr->rpu_format = get_bits(gb, 11); 223cabdff1aSopenharmony_ci 224cabdff1aSopenharmony_ci /* Values specific to RPU type 2 */ 225cabdff1aSopenharmony_ci hdr->vdr_rpu_profile = get_bits(gb, 4); 226cabdff1aSopenharmony_ci hdr->vdr_rpu_level = get_bits(gb, 4); 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci vdr_seq_info_present = get_bits1(gb); 229cabdff1aSopenharmony_ci if (vdr_seq_info_present) { 230cabdff1aSopenharmony_ci hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); 231cabdff1aSopenharmony_ci hdr->coef_data_type = get_bits(gb, 2); 232cabdff1aSopenharmony_ci VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); 233cabdff1aSopenharmony_ci switch (hdr->coef_data_type) { 234cabdff1aSopenharmony_ci case RPU_COEFF_FIXED: 235cabdff1aSopenharmony_ci hdr->coef_log2_denom = get_ue_golomb(gb); 236cabdff1aSopenharmony_ci VALIDATE(hdr->coef_log2_denom, 13, 32); 237cabdff1aSopenharmony_ci break; 238cabdff1aSopenharmony_ci case RPU_COEFF_FLOAT: 239cabdff1aSopenharmony_ci hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ 240cabdff1aSopenharmony_ci break; 241cabdff1aSopenharmony_ci } 242cabdff1aSopenharmony_ci 243cabdff1aSopenharmony_ci hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); 244cabdff1aSopenharmony_ci hdr->bl_video_full_range_flag = get_bits1(gb); 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_ci if ((hdr->rpu_format & 0x700) == 0) { 247cabdff1aSopenharmony_ci int bl_bit_depth_minus8 = get_ue_golomb_31(gb); 248cabdff1aSopenharmony_ci int el_bit_depth_minus8 = get_ue_golomb_31(gb); 249cabdff1aSopenharmony_ci int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); 250cabdff1aSopenharmony_ci VALIDATE(bl_bit_depth_minus8, 0, 8); 251cabdff1aSopenharmony_ci VALIDATE(el_bit_depth_minus8, 0, 8); 252cabdff1aSopenharmony_ci VALIDATE(vdr_bit_depth_minus8, 0, 8); 253cabdff1aSopenharmony_ci hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; 254cabdff1aSopenharmony_ci hdr->el_bit_depth = el_bit_depth_minus8 + 8; 255cabdff1aSopenharmony_ci hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; 256cabdff1aSopenharmony_ci hdr->spatial_resampling_filter_flag = get_bits1(gb); 257cabdff1aSopenharmony_ci skip_bits(gb, 3); /* reserved_zero_3bits */ 258cabdff1aSopenharmony_ci hdr->el_spatial_resampling_filter_flag = get_bits1(gb); 259cabdff1aSopenharmony_ci hdr->disable_residual_flag = get_bits1(gb); 260cabdff1aSopenharmony_ci } 261cabdff1aSopenharmony_ci } 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci if (!hdr->bl_bit_depth) { 264cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n"); 265cabdff1aSopenharmony_ci goto fail; 266cabdff1aSopenharmony_ci } 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci vdr_dm_metadata_present = get_bits1(gb); 269cabdff1aSopenharmony_ci use_prev_vdr_rpu = get_bits1(gb); 270cabdff1aSopenharmony_ci use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci profile = s->dv_profile ? s->dv_profile : guess_profile(hdr); 273cabdff1aSopenharmony_ci if (profile == 5 && use_nlq) { 274cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); 275cabdff1aSopenharmony_ci goto fail; 276cabdff1aSopenharmony_ci } 277cabdff1aSopenharmony_ci 278cabdff1aSopenharmony_ci if (use_prev_vdr_rpu) { 279cabdff1aSopenharmony_ci int prev_vdr_rpu_id = get_ue_golomb_31(gb); 280cabdff1aSopenharmony_ci VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); 281cabdff1aSopenharmony_ci if (!s->vdr_ref[prev_vdr_rpu_id]) { 282cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", 283cabdff1aSopenharmony_ci prev_vdr_rpu_id); 284cabdff1aSopenharmony_ci goto fail; 285cabdff1aSopenharmony_ci } 286cabdff1aSopenharmony_ci vdr = (DOVIVdrRef *) s->vdr_ref[prev_vdr_rpu_id]->data; 287cabdff1aSopenharmony_ci s->mapping = &vdr->mapping; 288cabdff1aSopenharmony_ci } else { 289cabdff1aSopenharmony_ci int vdr_rpu_id = get_ue_golomb_31(gb); 290cabdff1aSopenharmony_ci VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); 291cabdff1aSopenharmony_ci if (!s->vdr_ref[vdr_rpu_id]) { 292cabdff1aSopenharmony_ci s->vdr_ref[vdr_rpu_id] = av_buffer_allocz(sizeof(DOVIVdrRef)); 293cabdff1aSopenharmony_ci if (!s->vdr_ref[vdr_rpu_id]) 294cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 295cabdff1aSopenharmony_ci } 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci vdr = (DOVIVdrRef *) s->vdr_ref[vdr_rpu_id]->data; 298cabdff1aSopenharmony_ci s->mapping = &vdr->mapping; 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci vdr->mapping.vdr_rpu_id = vdr_rpu_id; 301cabdff1aSopenharmony_ci vdr->mapping.mapping_color_space = get_ue_golomb_31(gb); 302cabdff1aSopenharmony_ci vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb); 303cabdff1aSopenharmony_ci 304cabdff1aSopenharmony_ci for (int c = 0; c < 3; c++) { 305cabdff1aSopenharmony_ci AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; 306cabdff1aSopenharmony_ci int num_pivots_minus_2 = get_ue_golomb_31(gb); 307cabdff1aSopenharmony_ci int pivot = 0; 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); 310cabdff1aSopenharmony_ci curve->num_pivots = num_pivots_minus_2 + 2; 311cabdff1aSopenharmony_ci for (int i = 0; i < curve->num_pivots; i++) { 312cabdff1aSopenharmony_ci pivot += get_bits(gb, hdr->bl_bit_depth); 313cabdff1aSopenharmony_ci curve->pivots[i] = av_clip_uint16(pivot); 314cabdff1aSopenharmony_ci } 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci if (use_nlq) { 318cabdff1aSopenharmony_ci vdr->mapping.nlq_method_idc = get_bits(gb, 3); 319cabdff1aSopenharmony_ci /** 320cabdff1aSopenharmony_ci * The patent mentions another legal value, NLQ_MU_LAW, but it's 321cabdff1aSopenharmony_ci * not documented anywhere how to parse or apply that type of NLQ. 322cabdff1aSopenharmony_ci */ 323cabdff1aSopenharmony_ci VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); 324cabdff1aSopenharmony_ci } else { 325cabdff1aSopenharmony_ci vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE; 326cabdff1aSopenharmony_ci } 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_ci vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1; 329cabdff1aSopenharmony_ci vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1; 330cabdff1aSopenharmony_ci /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_ci for (int c = 0; c < 3; c++) { 333cabdff1aSopenharmony_ci AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; 334cabdff1aSopenharmony_ci for (int i = 0; i < curve->num_pivots - 1; i++) { 335cabdff1aSopenharmony_ci int mapping_idc = get_ue_golomb_31(gb); 336cabdff1aSopenharmony_ci VALIDATE(mapping_idc, 0, 1); 337cabdff1aSopenharmony_ci curve->mapping_idc[i] = mapping_idc; 338cabdff1aSopenharmony_ci switch (mapping_idc) { 339cabdff1aSopenharmony_ci case AV_DOVI_MAPPING_POLYNOMIAL: { 340cabdff1aSopenharmony_ci int poly_order_minus1 = get_ue_golomb_31(gb); 341cabdff1aSopenharmony_ci VALIDATE(poly_order_minus1, 0, 1); 342cabdff1aSopenharmony_ci curve->poly_order[i] = poly_order_minus1 + 1; 343cabdff1aSopenharmony_ci if (poly_order_minus1 == 0) { 344cabdff1aSopenharmony_ci int linear_interp_flag = get_bits1(gb); 345cabdff1aSopenharmony_ci if (linear_interp_flag) { 346cabdff1aSopenharmony_ci /* lack of documentation/samples */ 347cabdff1aSopenharmony_ci avpriv_request_sample(s->logctx, "Dolby Vision " 348cabdff1aSopenharmony_ci "linear interpolation"); 349cabdff1aSopenharmony_ci ff_dovi_ctx_unref(s); 350cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 351cabdff1aSopenharmony_ci } 352cabdff1aSopenharmony_ci } 353cabdff1aSopenharmony_ci for (int k = 0; k <= curve->poly_order[i]; k++) 354cabdff1aSopenharmony_ci curve->poly_coef[i][k] = get_se_coef(gb, hdr); 355cabdff1aSopenharmony_ci break; 356cabdff1aSopenharmony_ci } 357cabdff1aSopenharmony_ci case AV_DOVI_MAPPING_MMR: { 358cabdff1aSopenharmony_ci int mmr_order_minus1 = get_bits(gb, 2); 359cabdff1aSopenharmony_ci VALIDATE(mmr_order_minus1, 0, 2); 360cabdff1aSopenharmony_ci curve->mmr_order[i] = mmr_order_minus1 + 1; 361cabdff1aSopenharmony_ci curve->mmr_constant[i] = get_se_coef(gb, hdr); 362cabdff1aSopenharmony_ci for (int j = 0; j < curve->mmr_order[i]; j++) { 363cabdff1aSopenharmony_ci for (int k = 0; k < 7; k++) 364cabdff1aSopenharmony_ci curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); 365cabdff1aSopenharmony_ci } 366cabdff1aSopenharmony_ci break; 367cabdff1aSopenharmony_ci } 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci } 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci if (use_nlq) { 373cabdff1aSopenharmony_ci for (int c = 0; c < 3; c++) { 374cabdff1aSopenharmony_ci AVDOVINLQParams *nlq = &vdr->mapping.nlq[c]; 375cabdff1aSopenharmony_ci nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); 376cabdff1aSopenharmony_ci nlq->vdr_in_max = get_ue_coef(gb, hdr); 377cabdff1aSopenharmony_ci switch (vdr->mapping.nlq_method_idc) { 378cabdff1aSopenharmony_ci case AV_DOVI_NLQ_LINEAR_DZ: 379cabdff1aSopenharmony_ci nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); 380cabdff1aSopenharmony_ci nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); 381cabdff1aSopenharmony_ci break; 382cabdff1aSopenharmony_ci } 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci } 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci if (vdr_dm_metadata_present) { 388cabdff1aSopenharmony_ci AVDOVIColorMetadata *color; 389cabdff1aSopenharmony_ci int affected_dm_id = get_ue_golomb_31(gb); 390cabdff1aSopenharmony_ci int current_dm_id = get_ue_golomb_31(gb); 391cabdff1aSopenharmony_ci VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); 392cabdff1aSopenharmony_ci VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); 393cabdff1aSopenharmony_ci if (!s->vdr_ref[affected_dm_id]) { 394cabdff1aSopenharmony_ci s->vdr_ref[affected_dm_id] = av_buffer_allocz(sizeof(DOVIVdrRef)); 395cabdff1aSopenharmony_ci if (!s->vdr_ref[affected_dm_id]) 396cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 397cabdff1aSopenharmony_ci } 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci if (!s->vdr_ref[current_dm_id]) { 400cabdff1aSopenharmony_ci av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n", 401cabdff1aSopenharmony_ci current_dm_id); 402cabdff1aSopenharmony_ci goto fail; 403cabdff1aSopenharmony_ci } 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci /* Update current pointer based on current_dm_id */ 406cabdff1aSopenharmony_ci vdr = (DOVIVdrRef *) s->vdr_ref[current_dm_id]->data; 407cabdff1aSopenharmony_ci s->color = &vdr->color; 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci /* Update values of affected_dm_id */ 410cabdff1aSopenharmony_ci vdr = (DOVIVdrRef *) s->vdr_ref[affected_dm_id]->data; 411cabdff1aSopenharmony_ci color = &vdr->color; 412cabdff1aSopenharmony_ci color->dm_metadata_id = affected_dm_id; 413cabdff1aSopenharmony_ci color->scene_refresh_flag = get_ue_golomb_31(gb); 414cabdff1aSopenharmony_ci for (int i = 0; i < 9; i++) 415cabdff1aSopenharmony_ci color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); 416cabdff1aSopenharmony_ci for (int i = 0; i < 3; i++) { 417cabdff1aSopenharmony_ci int denom = profile == 4 ? (1 << 30) : (1 << 28); 418cabdff1aSopenharmony_ci unsigned offset = get_bits_long(gb, 32); 419cabdff1aSopenharmony_ci if (offset > INT_MAX) { 420cabdff1aSopenharmony_ci /* Ensure the result fits inside AVRational */ 421cabdff1aSopenharmony_ci offset >>= 1; 422cabdff1aSopenharmony_ci denom >>= 1; 423cabdff1aSopenharmony_ci } 424cabdff1aSopenharmony_ci color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); 425cabdff1aSopenharmony_ci } 426cabdff1aSopenharmony_ci for (int i = 0; i < 9; i++) 427cabdff1aSopenharmony_ci color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); 428cabdff1aSopenharmony_ci 429cabdff1aSopenharmony_ci color->signal_eotf = get_bits(gb, 16); 430cabdff1aSopenharmony_ci color->signal_eotf_param0 = get_bits(gb, 16); 431cabdff1aSopenharmony_ci color->signal_eotf_param1 = get_bits(gb, 16); 432cabdff1aSopenharmony_ci color->signal_eotf_param2 = get_bits_long(gb, 32); 433cabdff1aSopenharmony_ci color->signal_bit_depth = get_bits(gb, 5); 434cabdff1aSopenharmony_ci VALIDATE(color->signal_bit_depth, 8, 16); 435cabdff1aSopenharmony_ci color->signal_color_space = get_bits(gb, 2); 436cabdff1aSopenharmony_ci color->signal_chroma_format = get_bits(gb, 2); 437cabdff1aSopenharmony_ci color->signal_full_range_flag = get_bits(gb, 2); 438cabdff1aSopenharmony_ci color->source_min_pq = get_bits(gb, 12); 439cabdff1aSopenharmony_ci color->source_max_pq = get_bits(gb, 12); 440cabdff1aSopenharmony_ci color->source_diagonal = get_bits(gb, 10); 441cabdff1aSopenharmony_ci } 442cabdff1aSopenharmony_ci 443cabdff1aSopenharmony_ci /* FIXME: verify CRC32, requires implementation of AV_CRC_32_MPEG_2 */ 444cabdff1aSopenharmony_ci return 0; 445cabdff1aSopenharmony_ci 446cabdff1aSopenharmony_cifail: 447cabdff1aSopenharmony_ci ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */ 448cabdff1aSopenharmony_ci return AVERROR(EINVAL); 449cabdff1aSopenharmony_ci} 450