From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> To: ffmpeg-devel@ffmpeg.org Subject: Re: [FFmpeg-devel] [PATCH v10 4/6] lavc: Implement Dolby Vision RPU parsing Date: Tue, 4 Jan 2022 10:13:03 +0100 Message-ID: <AM7PR03MB66608D842C0846C94C95A29E8F4A9@AM7PR03MB6660.eurprd03.prod.outlook.com> (raw) In-Reply-To: <20220103002727.38840-4-ffmpeg@haasn.xyz> Niklas Haas: > From: Niklas Haas <git@haasn.dev> > > Based on a mixture of guesswork, partial documentation in patents, and > reverse engineering of real-world samples. Confirmed working for all the > samples I've thrown at it. > > Contains some annoying machinery to persist these values in between > frames, which is needed in theory even though I've never actually seen a > sample that relies on it in practice. May or may not work. > > Since the distinction matters greatly for parsing the color matrix > values, this includes a small helper function to guess the right profile > from the RPU itself in case the user has forgotten to forward the dovi > configuration record to the decoder. (Which in practice, only ffmpeg.c > and ffplay do..) > > Notable omissions / deviations: > - CRC32 verification. This is based on the MPEG2 CRC32 type, which is > similar to IEEE CRC32 but apparently different in subtle enough ways > that I could not get it to pass verification no matter what parameters > I fed to av_crc. It's possible the code needs some changes. > - Linear interpolation support. Nothing documents this (beyond its > existence) and no samples use it, so impossible to implement. > - All of the extension metadata blocks, but these contain values that > seem largely congruent with ST2094, HDR10, or other existing forms of > side data, so I will defer parsing/attaching them to a future commit. > - The patent describes a mechanism for predicting coefficients from > previous RPUs, but the bit for the flag whether to use the > prediction deltas or signal entirely new coefficients does not seem to > be present in actual RPUs, so we ignore this subsystem entirely. > - In the patent's spec, the NLQ subsystem also loops over > num_nlq_pivots, but even in the patent the number is hard-coded to one > iteration rather than signalled. So we only store one set of coefs. > > Heavily influenced by https://github.com/quietvoid/dovi_tool > Documentation drawn from US Patent 10,701,399 B2 and ETSI GS CCM 001 > > Signed-off-by: Niklas Haas <git@haasn.dev> > --- > configure | 2 + > libavcodec/Makefile | 1 + > libavcodec/dovi_rpu.c | 449 ++++++++++++++++++++++++++++++++++++++++++ > libavcodec/dovi_rpu.h | 87 ++++++++ > 4 files changed, 539 insertions(+) > create mode 100644 libavcodec/dovi_rpu.c > create mode 100644 libavcodec/dovi_rpu.h > > diff --git a/configure b/configure > index 6ad70b9f7b..8303e1329e 100755 > --- a/configure > +++ b/configure > @@ -2434,6 +2434,7 @@ CONFIG_EXTRA=" > cbs_vp9 > dirac_parse > dnn > + dovi_rpu > dvprofile > exif > faandct > @@ -2706,6 +2707,7 @@ cbs_mpeg2_select="cbs" > cbs_vp9_select="cbs" > dct_select="rdft" > dirac_parse_select="golomb" > +dovi_rpu_select="golomb" > dnn_suggest="libtensorflow libopenvino" > dnn_deps="avformat swscale" > error_resilience_select="me_cmp" > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 9577062eec..ceecdf05e1 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -77,6 +77,7 @@ OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o > OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o > OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o > OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o > +OBJS-$(CONFIG_DOVI_RPU) += dovi_rpu.o > OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o > OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o > OBJS-$(CONFIG_FAANDCT) += faandct.o > diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c > new file mode 100644 > index 0000000000..a87562c8a3 > --- /dev/null > +++ b/libavcodec/dovi_rpu.c > @@ -0,0 +1,449 @@ > +/* > + * Dolby Vision RPU decoder > + * > + * Copyright (C) 2021 Jan Ekström > + * Copyright (C) 2021 Niklas Haas > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include "libavutil/buffer.h" > + > +#include "dovi_rpu.h" > +#include "golomb.h" > +#include "get_bits.h" > + > +enum { > + RPU_COEFF_FIXED = 0, > + RPU_COEFF_FLOAT = 1, > +}; > + > +/** > + * Private contents of vdr_ref. > + */ > +typedef struct DOVIVdrRef { > + AVDOVIDataMapping mapping; > + AVDOVIColorMetadata color; > +} DOVIVdrRef; > + > +void ff_dovi_ctx_unref(DOVIContext *s) > +{ > + for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) > + av_buffer_unref(&s->vdr_ref[i]); > + > + *s = (DOVIContext) { > + .logctx = s->logctx, > + }; This could be simplified to ff_dovi_ctx_flush(); s->dv_profile = 0; > +} > + > +void ff_dovi_ctx_flush(DOVIContext *s) > +{ > + for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++) > + av_buffer_unref(&s->vdr_ref[i]); > + > + *s = (DOVIContext) { > + .logctx = s->logctx, > + .dv_profile = s->dv_profile, > + }; > +} > + > +int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) > +{ > + int ret; > + s->logctx = s0->logctx; > + s->mapping = s0->mapping; > + s->color = s0->color; > + s->dv_profile = s0->dv_profile; > + for (int i = 0; i < DOVI_MAX_DM_ID; i++) { > + if ((ret = av_buffer_replace(&s->vdr_ref[i], s0->vdr_ref[i])) < 0) > + goto fail; > + } > + > + return 0; > + > +fail: > + ff_dovi_ctx_unref(s); > + return ret; > +} > + > +void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg) > +{ > + if (!cfg) > + return; > + > + s->dv_profile = cfg->dv_profile; > +} > + > +int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) > +{ > + AVFrameSideData *sd; > + AVBufferRef *buf; > + AVDOVIMetadata *dovi; > + size_t dovi_size; > + > + if (!s->mapping || !s->color) > + return 0; /* incomplete dovi metadata */ > + > + dovi = av_dovi_metadata_alloc(&dovi_size); > + if (!dovi) > + return AVERROR(ENOMEM); > + > + buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0); > + if (!buf) { > + av_free(dovi); > + return AVERROR(ENOMEM); > + } > + > + sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); > + if (!sd) { > + av_buffer_unref(&buf); > + return AVERROR(ENOMEM); > + } > + > + /* Copy only the parts of these structs known to us at compiler-time. */ > +#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) > + COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag); > + COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq[2].linear_deadzone_threshold); You should be able to use nlg as last element (without [2].linear_deadzone_threshold). (Obviously the changes suggested by these comments could be applied at any time.) > + COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); > + return 0; > +} > + > +static int guess_profile(const AVDOVIRpuDataHeader *hdr) > +{ > + switch (hdr->vdr_rpu_profile) { > + case 0: > + if (hdr->bl_video_full_range_flag) > + return 5; > + break; > + case 1: > + if (hdr->el_spatial_resampling_filter_flag && !hdr->disable_residual_flag) { > + if (hdr->vdr_bit_depth == 12) { > + return 7; > + } else { > + return 4; > + } > + } else { > + return 8; > + } > + } > + > + return 0; /* unknown */ > +} > + > +static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) > +{ > + uint64_t ipart; > + union { uint32_t u32; float f32; } fpart; > + > + switch (hdr->coef_data_type) { > + case RPU_COEFF_FIXED: > + ipart = get_ue_golomb_long(gb); > + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); > + return (ipart << hdr->coef_log2_denom) + fpart.u32; > + > + case RPU_COEFF_FLOAT: > + fpart.u32 = get_bits_long(gb, 32); > + return fpart.f32 * (1 << hdr->coef_log2_denom); > + } > + > + return 0; /* unreachable */ > +} > + > +static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) > +{ > + int64_t ipart; > + union { uint32_t u32; float f32; } fpart; > + > + switch (hdr->coef_data_type) { > + case RPU_COEFF_FIXED: > + ipart = get_se_golomb_long(gb); > + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); > + return (ipart << hdr->coef_log2_denom) + fpart.u32; > + > + case RPU_COEFF_FLOAT: > + fpart.u32 = get_bits_long(gb, 32); > + return fpart.f32 * (1 << hdr->coef_log2_denom); > + } > + > + return 0; /* unreachable */ > +} > + > +#define VALIDATE(VAR, MIN, MAX) \ > + do { \ > + if (VAR < MIN || VAR > MAX) { \ > + av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ > + #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ > + goto fail; \ > + } \ > + } while (0) > + > +int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size) > +{ > + AVDOVIRpuDataHeader *hdr = &s->header; > + GetBitContext *gb = &(GetBitContext){0}; > + DOVIVdrRef *vdr; > + int ret; > + > + uint8_t nal_prefix; > + uint8_t rpu_type; > + uint8_t vdr_seq_info_present; > + uint8_t vdr_dm_metadata_present; > + uint8_t use_prev_vdr_rpu; > + uint8_t use_nlq; > + uint8_t profile; > + if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) > + return ret; > + > + /* RPU header, common values */ > + nal_prefix = get_bits(gb, 8); > + VALIDATE(nal_prefix, 25, 25); > + rpu_type = get_bits(gb, 6); > + if (rpu_type != 2) { > + av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " > + "%"PRIu8", ignoring\n", rpu_type); > + return 0; > + } > + > + hdr->rpu_type = rpu_type; > + hdr->rpu_format = get_bits(gb, 11); > + > + /* Values specific to RPU type 2 */ > + hdr->vdr_rpu_profile = get_bits(gb, 4); > + hdr->vdr_rpu_level = get_bits(gb, 4); > + > + vdr_seq_info_present = get_bits1(gb); > + if (vdr_seq_info_present) { > + hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); > + hdr->coef_data_type = get_bits(gb, 2); > + VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); > + switch (hdr->coef_data_type) { > + case RPU_COEFF_FIXED: > + hdr->coef_log2_denom = get_ue_golomb(gb); > + VALIDATE(hdr->coef_log2_denom, 13, 32); > + break; > + case RPU_COEFF_FLOAT: > + hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ > + break; > + } > + > + hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); > + hdr->bl_video_full_range_flag = get_bits1(gb); > + > + if ((hdr->rpu_format & 0x700) == 0) { > + int bl_bit_depth_minus8 = get_ue_golomb_31(gb); > + int el_bit_depth_minus8 = get_ue_golomb_31(gb); > + int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); > + VALIDATE(bl_bit_depth_minus8, 0, 8); > + VALIDATE(el_bit_depth_minus8, 0, 8); > + VALIDATE(vdr_bit_depth_minus8, 0, 8); > + hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; > + hdr->el_bit_depth = el_bit_depth_minus8 + 8; > + hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; > + hdr->spatial_resampling_filter_flag = get_bits1(gb); > + skip_bits(gb, 3); /* reserved_zero_3bits */ > + hdr->el_spatial_resampling_filter_flag = get_bits1(gb); > + hdr->disable_residual_flag = get_bits1(gb); > + } > + } > + > + if (!hdr->bl_bit_depth) { > + av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n"); > + goto fail; > + } > + > + vdr_dm_metadata_present = get_bits1(gb); > + use_prev_vdr_rpu = get_bits1(gb); > + use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; > + > + profile = s->dv_profile ? s->dv_profile : guess_profile(hdr); > + if (profile == 5 && use_nlq) { > + av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); > + goto fail; > + } > + > + if (use_prev_vdr_rpu) { > + int prev_vdr_rpu_id = get_ue_golomb_31(gb); > + VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); > + if (!s->vdr_ref[prev_vdr_rpu_id]) { > + av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", > + prev_vdr_rpu_id); > + goto fail; > + } > + vdr = (DOVIVdrRef *) s->vdr_ref[prev_vdr_rpu_id]->data; > + s->mapping = &vdr->mapping; > + } else { > + int vdr_rpu_id = get_ue_golomb_31(gb); > + VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); > + if (!s->vdr_ref[vdr_rpu_id]) { > + s->vdr_ref[vdr_rpu_id] = av_buffer_allocz(sizeof(DOVIVdrRef)); > + if (!s->vdr_ref[vdr_rpu_id]) > + return AVERROR(ENOMEM); > + } > + > + vdr = (DOVIVdrRef *) s->vdr_ref[vdr_rpu_id]->data; > + s->mapping = &vdr->mapping; > + > + vdr->mapping.vdr_rpu_id = vdr_rpu_id; > + vdr->mapping.mapping_color_space = get_ue_golomb_31(gb); > + vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb); > + > + for (int c = 0; c < 3; c++) { > + AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; > + int num_pivots_minus_2 = get_ue_golomb_31(gb); > + int pivot = 0; > + > + VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); > + curve->num_pivots = num_pivots_minus_2 + 2; > + for (int i = 0; i < curve->num_pivots; i++) { > + pivot += get_bits(gb, hdr->bl_bit_depth); > + curve->pivots[i] = av_clip_uint16(pivot); > + } > + } > + > + if (use_nlq) { > + vdr->mapping.nlq_method_idc = get_bits(gb, 3); > + /** > + * The patent mentions another legal value, NLQ_MU_LAW, but it's > + * not documented anywhere how to parse or apply that type of NLQ. > + */ > + VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); > + } else { > + vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE; > + } > + > + vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1; > + vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1; > + /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ > + > + for (int c = 0; c < 3; c++) { > + AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; > + for (int i = 0; i < curve->num_pivots - 1; i++) { > + int mapping_idc = get_ue_golomb_31(gb); > + VALIDATE(mapping_idc, 0, 1); > + curve->mapping_idc[i] = mapping_idc; > + switch (mapping_idc) { > + case AV_DOVI_MAPPING_POLYNOMIAL: { > + int poly_order_minus1 = get_ue_golomb_31(gb); > + VALIDATE(poly_order_minus1, 0, 1); > + curve->poly_order[i] = poly_order_minus1 + 1; > + if (poly_order_minus1 == 0) { > + int linear_interp_flag = get_bits1(gb); > + if (linear_interp_flag) { > + /* lack of documentation/samples */ > + avpriv_request_sample(s->logctx, "Dolby Vision " > + "linear interpolation"); > + ff_dovi_ctx_unref(s); > + return AVERROR_PATCHWELCOME; > + } > + } > + for (int k = 0; k <= curve->poly_order[i]; k++) > + curve->poly_coef[i][k] = get_se_coef(gb, hdr); > + break; > + } > + case AV_DOVI_MAPPING_MMR: { > + int mmr_order_minus1 = get_bits(gb, 2); > + VALIDATE(mmr_order_minus1, 0, 2); > + curve->mmr_order[i] = mmr_order_minus1 + 1; > + curve->mmr_constant[i] = get_se_coef(gb, hdr); > + for (int j = 0; j < curve->mmr_order[i]; j++) { > + for (int k = 0; k < 7; k++) > + curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); > + } > + break; > + } > + } > + } > + } > + > + if (use_nlq) { > + for (int c = 0; c < 3; c++) { > + AVDOVINLQParams *nlq = &vdr->mapping.nlq[c]; > + nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); > + nlq->vdr_in_max = get_ue_coef(gb, hdr); > + switch (vdr->mapping.nlq_method_idc) { > + case AV_DOVI_NLQ_LINEAR_DZ: > + nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); > + nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); > + break; > + } > + } > + } > + } > + > + if (vdr_dm_metadata_present) { > + AVDOVIColorMetadata *color; > + int affected_dm_id = get_ue_golomb_31(gb); > + int current_dm_id = get_ue_golomb_31(gb); > + VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); > + VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); > + if (!s->vdr_ref[affected_dm_id]) { > + s->vdr_ref[affected_dm_id] = av_buffer_allocz(sizeof(DOVIVdrRef)); > + if (!s->vdr_ref[affected_dm_id]) > + return AVERROR(ENOMEM); > + } > + > + if (!s->vdr_ref[current_dm_id]) { > + av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n", > + current_dm_id); > + goto fail; > + } > + > + /* Update current pointer based on current_dm_id */ > + vdr = (DOVIVdrRef *) s->vdr_ref[current_dm_id]->data; > + s->color = &vdr->color; > + > + /* Update values of affected_dm_id */ > + vdr = (DOVIVdrRef *) s->vdr_ref[affected_dm_id]->data; > + color = &vdr->color; > + color->dm_metadata_id = affected_dm_id; > + color->scene_refresh_flag = get_ue_golomb_31(gb); > + for (int i = 0; i < 9; i++) > + color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); > + for (int i = 0; i < 3; i++) { > + int denom = profile == 4 ? (1 << 30) : (1 << 28); > + unsigned offset = get_bits_long(gb, 32); > + if (offset > INT_MAX) { > + /* Ensure the result fits inside AVRational */ > + offset >>= 1; > + denom >>= 1; > + } > + color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); > + } > + for (int i = 0; i < 9; i++) > + color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); > + > + color->signal_eotf = get_bits(gb, 16); > + color->signal_eotf_param0 = get_bits(gb, 16); > + color->signal_eotf_param1 = get_bits(gb, 16); > + color->signal_eotf_param2 = get_bits_long(gb, 32); > + color->signal_bit_depth = get_bits(gb, 5); > + VALIDATE(color->signal_bit_depth, 8, 16); > + color->signal_color_space = get_bits(gb, 2); > + color->signal_chroma_format = get_bits(gb, 2); > + color->signal_full_range_flag = get_bits(gb, 2); > + color->source_min_pq = get_bits(gb, 12); > + color->source_max_pq = get_bits(gb, 12); > + color->source_diagonal = get_bits(gb, 10); > + } > + > + /* FIXME: verify CRC32, requires implementation of AV_CRC_32_MPEG_2 */ > + return 0; > + > +fail: > + ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */ > + return AVERROR(EINVAL); > +} > diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h > new file mode 100644 > index 0000000000..f6ca5bbbc5 > --- /dev/null > +++ b/libavcodec/dovi_rpu.h > @@ -0,0 +1,87 @@ > +/* > + * Dolby Vision RPU decoder > + * > + * Copyright (C) 2021 Jan Ekström > + * Copyright (C) 2021 Niklas Haas > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#ifndef AVCODEC_DOVI_RPU_H > +#define AVCODEC_DOVI_RPU_H > + > +#include "libavutil/dovi_meta.h" > +#include "libavutil/frame.h" > + > +#define DOVI_MAX_DM_ID 15 > +typedef struct DOVIContext { > + void *logctx; > + > + /** > + * Currently active RPU data header, updates on every dovi_rpu_parse(). > + */ > + AVDOVIRpuDataHeader header; > + > + /** > + * Currently active data mappings, or NULL. Points into memory owned by the > + * corresponding rpu/vdr_ref, which becomes invalid on the next call to > + * dovi_rpu_parse. > + */ > + const AVDOVIDataMapping *mapping; > + const AVDOVIColorMetadata *color; > + > + /** > + * Private fields internal to dovi_rpu.c > + */ > + AVBufferRef *vdr_ref[DOVI_MAX_DM_ID+1]; > + uint8_t dv_profile; > + > +} DOVIContext; > + > +int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0); > + > +/** > + * Completely reset a DOVIContext, preserving only logctx. > + */ > +void ff_dovi_ctx_unref(DOVIContext *s); > + > +/** > + * Partially reset the internal state. Resets per-frame state while preserving > + * fields parsed from the configuration record. > + */ > +void ff_dovi_ctx_flush(DOVIContext *s); > + > +/** > + * Read the contents of an AVDOVIDecoderConfigurationRecord (usually provided > + * by stream side data) and update internal state accordingly. > + */ > +void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg); > + > +/** > + * Parse the contents of a Dovi RPU NAL and update the parsed values in the > + * DOVIContext struct. > + * > + * Returns 0 or an error code. > + */ > +int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size); > + > +/** > + * Attach the decoded AVDOVIMetadata as side data to an AVFrame. > + */ > +int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); > + > +#endif /* AVCODEC_DOVI_RPU_H */ > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2022-01-04 9:13 UTC|newest] Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-01-03 0:27 [FFmpeg-devel] [PATCH v10 1/6] lavu/frame: Add Dolby Vision metadata side data type Niklas Haas 2022-01-03 0:27 ` [FFmpeg-devel] [PATCH v10 2/6] lavfi/showinfo: Support AV_FRAME_DATA_DOVI_METADATA Niklas Haas 2022-01-03 0:27 ` [FFmpeg-devel] [PATCH v10 3/6] ffprobe: " Niklas Haas 2022-01-03 0:27 ` [FFmpeg-devel] [PATCH v10 4/6] lavc: Implement Dolby Vision RPU parsing Niklas Haas 2022-01-04 9:13 ` Andreas Rheinhardt [this message] 2022-01-03 0:27 ` [FFmpeg-devel] [PATCH v10 5/6] fate: Limit Dolby Vision RPU test frame count Niklas Haas 2022-01-03 0:27 ` [FFmpeg-devel] [PATCH v10 6/6] lavc/hevcdec: Parse DOVI RPU NALs Niklas Haas 2022-01-04 9:17 ` Andreas Rheinhardt 2022-01-03 8:40 ` [FFmpeg-devel] [PATCH v10 1/6] lavu/frame: Add Dolby Vision metadata side data type Niklas Haas 2022-01-03 8:45 ` Andreas Rheinhardt 2022-01-03 8:55 ` [FFmpeg-devel] [PATCH v11] " Niklas Haas 2022-01-04 9:03 ` Andreas Rheinhardt
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=AM7PR03MB66608D842C0846C94C95A29E8F4A9@AM7PR03MB6660.eurprd03.prod.outlook.com \ --to=andreas.rheinhardt@outlook.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git