[vlc-commits] [Git][videolan/vlc][master] 5 commits: vlc_es: add dolby vision metadata
François Cartegnie (@fcartegnie)
gitlab at videolan.org
Sun Jan 9 13:10:58 UTC 2022
François Cartegnie pushed to branch master at VideoLAN / VLC
Commits:
78ca0ad7 by Niklas Haas at 2022-01-09T12:37:00+00:00
vlc_es: add dolby vision metadata
Struct is made to be as close-as-possible to a carbon copy of the
libavutil struct as is reasonable, in order to make everybody's life
easier while still avoiding a direct dependency from the vout onto
libavutil.
- - - - -
1d58848f by Niklas Haas at 2022-01-09T12:37:00+00:00
picture: make vlc_GetAncillary const
This shouldn't need to mutate picture_t. Marking it const avoids warning
when passing it a const picture_t from elsewhere.
- - - - -
be4cb6f6 by Niklas Haas at 2022-01-09T12:37:00+00:00
picture: add ancillary allocation helper
This three-way allocation dance is rather annoying/verbose to write. So
give it a name and make sure nobody ever has to write it ever again.
- - - - -
b031e157 by Niklas Haas at 2022-01-09T12:37:00+00:00
avcodec: query and expose dolby vision metadata
- - - - -
147a1bd8 by Niklas Haas at 2022-01-09T12:37:00+00:00
libplacebo: forward dolby vision metadata
The mapping code is copy/pasted from the libavutil<->libplacebo helpers
found in <libplacebo/utils/libav_internal.h>. This is better than
pulling in an ffmpeg dependency, and is reasonably forward-compatible
(the updated libplacebo helper will just have to be copy/pasted in the
unlikely event that this metadata ever gets extended).
- - - - -
8 changed files:
- include/vlc_es.h
- include/vlc_picture.h
- modules/codec/avcodec/video.c
- modules/video_output/libplacebo/display.c
- modules/video_output/libplacebo/utils.c
- modules/video_output/libplacebo/utils.h
- src/libvlccore.sym
- src/misc/picture.c
Changes:
=====================================
include/vlc_es.h
=====================================
@@ -544,6 +544,63 @@ static inline video_transform_t transform_Inverse( video_transform_t transform )
return transform;
}
}
+
+/**
+ * Dolby Vision metadata description
+ */
+enum vlc_dovi_reshape_method_t
+{
+ VLC_DOVI_RESHAPE_POLYNOMIAL = 0,
+ VLC_DOVI_RESHAPE_MMR = 1,
+};
+
+enum vlc_dovi_nlq_method_t
+{
+ VLC_DOVI_NLQ_NONE = -1,
+ VLC_DOVI_NLQ_LINEAR_DZ = 0,
+};
+
+#define VLC_ANCILLARY_ID_DOVI VLC_FOURCC('D','o','V','i')
+
+typedef struct vlc_video_dovi_metadata_t
+{
+ /* Common header fields */
+ uint8_t coef_log2_denom;
+ uint8_t bl_bit_depth;
+ uint8_t el_bit_depth;
+ enum vlc_dovi_nlq_method_t nlq_method_idc;
+
+ /* Colorspace metadata */
+ float nonlinear_offset[3];
+ float nonlinear_matrix[9];
+ float linear_matrix[9];
+ uint16_t source_min_pq; /* 12-bit PQ values */
+ uint16_t source_max_pq;
+
+ /**
+ * Do not reorder or modify the following structs, they are intentionally
+ * specified to be identical to AVDOVIReshapingCurve / AVDOVINLQParams.
+ */
+ struct vlc_dovi_reshape_t {
+ uint8_t num_pivots;
+ uint16_t pivots[9];
+ enum vlc_dovi_reshape_method_t mapping_idc[8];
+ uint8_t poly_order[8];
+ int64_t poly_coef[8][3];
+ uint8_t mmr_order[8];
+ int64_t mmr_constant[8];
+ int64_t mmr_coef[8][3][7];
+ } curves[3];
+
+ struct vlc_dovi_nlq_t {
+ uint8_t offset_depth; /* bit depth of offset value */
+ uint16_t offset;
+ uint64_t hdr_in_max;
+ uint64_t dz_slope;
+ uint64_t dz_threshold;
+ } nlq[3];
+} vlc_video_dovi_metadata_t;
+
/**
* subtitles format description
*/
=====================================
include/vlc_picture.h
=====================================
@@ -431,6 +431,19 @@ VLC_API picture_t *picture_Clone(picture_t *pic);
VLC_API int
picture_AttachAncillary(picture_t *pic, struct vlc_ancillary *ancillary);
+/**
+ * Allocate a new ancillary and attach it to a picture. Helper equivalent to
+ * malloc + vlc_ancillary_Create + picture_AttachAncillary. The returned memory
+ * is not initialized.
+ *
+ * @param pic picture to attach created ancillary to
+ * @param id id of the ancillary to create
+ * @param size allocation size in bytes
+ * @return The allocated pointer on success, NULL on out-of-memory
+ */
+VLC_API void *
+picture_AttachNewAncillary(picture_t *pic, vlc_ancillary_id id, size_t size);
+
/**
* Return the ancillary identified by an ID
*
@@ -439,7 +452,7 @@ picture_AttachAncillary(picture_t *pic, struct vlc_ancillary *ancillary);
* not present
*/
VLC_API struct vlc_ancillary *
-picture_GetAncillary(picture_t *pic, vlc_ancillary_id id);
+picture_GetAncillary(const picture_t *pic, vlc_ancillary_id id);
/**
* This function will export a picture to an encoded bitstream.
=====================================
modules/codec/avcodec/video.c
=====================================
@@ -46,6 +46,10 @@
#include <libavutil/stereo3d.h>
+#if LIBAVUTIL_VERSION_CHECK( 57, 16, 100 )
+# include <libavutil/dovi_meta.h>
+#endif
+
#include "../cc.h"
#define FRAME_INFO_DEPTH 64
@@ -723,6 +727,34 @@ static void update_late_frame_count( decoder_t *p_dec, block_t *p_block,
}
}
+#if LIBAVUTIL_VERSION_CHECK( 57, 16, 100 )
+static void map_dovi_metadata( vlc_video_dovi_metadata_t *out,
+ const AVDOVIMetadata *data )
+{
+ const AVDOVIRpuDataHeader *hdr = av_dovi_get_header( data );
+ const AVDOVIDataMapping *vdm = av_dovi_get_mapping( data );
+ const AVDOVIColorMetadata *color = av_dovi_get_color( data );
+ out->bl_bit_depth = hdr->bl_bit_depth;
+ out->el_bit_depth = hdr->el_bit_depth;
+ out->coef_log2_denom = hdr->coef_log2_denom;
+ out->nlq_method_idc = (enum vlc_dovi_nlq_method_t) vdm->nlq_method_idc;
+ for( size_t i = 0; i < ARRAY_SIZE( out->nonlinear_offset ); i++ )
+ out->nonlinear_offset[i] = av_q2d( color->ycc_to_rgb_offset[i] );
+ for( size_t i = 0; i < ARRAY_SIZE( out->nonlinear_matrix ); i++ )
+ out->nonlinear_matrix[i] = av_q2d( color->ycc_to_rgb_matrix[i] );
+ for( size_t i = 0; i < ARRAY_SIZE( out->linear_matrix); i++ )
+ out->linear_matrix[i] = av_q2d( color->rgb_to_lms_matrix[i] );
+ out->source_min_pq = color->source_min_pq;
+ out->source_max_pq = color->source_max_pq;
+
+ static_assert(sizeof(out->curves) == sizeof(vdm->curves), "struct mismatch");
+ static_assert(sizeof(out->nlq) == sizeof(vdm->nlq), "struct mismatch");
+ memcpy(out->curves, vdm->curves, sizeof(out->curves));
+ memcpy(out->nlq, vdm->nlq, sizeof(out->nlq));
+ for( int i = 0; i < ARRAY_SIZE( out->curves ); i++)
+ assert( out->curves[i].num_pivots <= ARRAY_SIZE( out->curves[i].pivots ));
+}
+#endif
static int DecodeSidedata( decoder_t *p_dec, const AVFrame *frame, picture_t *p_pic )
{
@@ -876,6 +908,19 @@ static int DecodeSidedata( decoder_t *p_dec, const AVFrame *frame, picture_t *p_
cc_Flush( &p_sys->cc );
}
}
+
+#if LIBAVUTIL_VERSION_CHECK( 57, 16, 100 )
+ const AVFrameSideData *p_dovi = av_frame_get_side_data( frame, AV_FRAME_DATA_DOVI_METADATA );
+ if( p_dovi )
+ {
+ vlc_video_dovi_metadata_t *dst;
+ dst = picture_AttachNewAncillary( p_pic, VLC_ANCILLARY_ID_DOVI, sizeof(*dst) );
+ if( !dst )
+ return VLC_ENOMEM;
+ map_dovi_metadata( dst, (AVDOVIMetadata *) p_dovi->data );
+ }
+#endif
+
return 0;
}
=====================================
modules/video_output/libplacebo/display.c
=====================================
@@ -84,6 +84,10 @@ typedef struct vout_display_sys_t
const struct pl_hook *hook;
char *hook_path;
+
+#if PL_API_VER >= 185
+ struct pl_dovi_metadata dovi_metadata;
+#endif
} vout_display_sys_t;
// Display callbacks
@@ -239,6 +243,10 @@ static void PictureRender(vout_display_t *vd, picture_t *pic,
},
};
+#if PL_API_VER >= 185
+ vlc_placebo_DoviMetadata(&img, pic, &sys->dovi_metadata);
+#endif
+
// Upload the image data for each plane
struct pl_plane_data data[4];
if (!vlc_placebo_PlaneData(pic, data, NULL)) {
=====================================
modules/video_output/libplacebo/utils.c
=====================================
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <vlc_common.h>
+#include <vlc_ancillary.h>
#include "utils.h"
static void Log(void *priv, enum pl_log_level level, const char *msg)
@@ -451,6 +452,71 @@ struct pl_color_repr vlc_placebo_ColorRepr(const video_format_t *fmt)
};
}
+#if PL_API_VER >= 187
+void vlc_placebo_DoviMetadata(struct pl_frame *frame, const picture_t *pic,
+ struct pl_dovi_metadata *dst)
+{
+ struct vlc_ancillary *ancillary = picture_GetAncillary(pic, VLC_ANCILLARY_ID_DOVI);
+ if (!ancillary)
+ return;
+
+ const vlc_video_dovi_metadata_t *src = vlc_ancillary_GetData(ancillary);
+ static_assert(sizeof(dst->nonlinear_offset) == sizeof(src->nonlinear_offset), "array mismatch");
+ static_assert(sizeof(dst->nonlinear) == sizeof(src->nonlinear_matrix), "matrix mismatch");
+ static_assert(sizeof(dst->linear) == sizeof(src->linear_matrix), "matrix mismatch");
+ memcpy(dst->nonlinear_offset, src->nonlinear_offset,
+ sizeof(dst->nonlinear_offset));
+ memcpy(dst->nonlinear.m[0], src->nonlinear_matrix, sizeof(dst->nonlinear.m));
+ memcpy(dst->linear.m[0], src->linear_matrix, sizeof(dst->linear.m));
+
+ for (int c = 0; c < ARRAY_SIZE(dst->comp); c++) {
+ const struct vlc_dovi_reshape_t *csrc = &src->curves[c];
+ struct pl_reshape_data *cdst = &dst->comp[c];
+ cdst->num_pivots = csrc->num_pivots;
+ assert(csrc->num_pivots <= ARRAY_SIZE(csrc->pivots));
+ for (int i = 0; i < csrc->num_pivots; i++) {
+ const float scale = 1.0f / ((1 << src->bl_bit_depth) - 1);
+ cdst->pivots[i] = scale * csrc->pivots[i];
+ }
+ for (int i = 0; i < csrc->num_pivots - 1; i++) {
+ const float scale = 1.0f / (1 << src->coef_log2_denom);
+ cdst->method[i] = csrc->mapping_idc[i];
+ switch (csrc->mapping_idc[i]) {
+ case VLC_DOVI_RESHAPE_POLYNOMIAL:
+ for (int k = 0; k < ARRAY_SIZE(cdst->poly_coeffs[i]); k++) {
+ cdst->poly_coeffs[i][k] = (k <= csrc->poly_order[i])
+ ? scale * csrc->poly_coef[i][k]
+ : 0.0f;
+ }
+ break;
+ case VLC_DOVI_RESHAPE_MMR:
+ cdst->mmr_order[i] = csrc->mmr_order[i];
+ cdst->mmr_constant[i] = scale * csrc->mmr_constant[i];
+ for (int j = 0; j < csrc->mmr_order[i]; j++) {
+ for (int k = 0; k < ARRAY_SIZE(cdst->mmr_coeffs[i][j]); k++)
+ cdst->mmr_coeffs[i][j][k] = scale * csrc->mmr_coef[i][j][k];
+ }
+ break;
+ }
+ }
+ }
+
+ // The output of the Dolby Vision reshaping process is always BT.2020/PQ,
+ // no matter the color space of the base layer, so override these fields
+ frame->color.primaries = PL_COLOR_PRIM_BT_2020;
+ frame->color.transfer = PL_COLOR_TRC_PQ;
+ frame->repr.sys = PL_COLOR_SYSTEM_DOLBYVISION;
+ frame->repr.dovi = dst;
+
+ // These fields are specified to always have 12-bit precision
+ const float scale = 1.0f / ((1 << 12) - 1);
+ frame->color.hdr.min_luma = pl_hdr_rescale(PL_HDR_PQ, PL_HDR_NITS,
+ scale * src->source_min_pq);
+ frame->color.hdr.max_luma = pl_hdr_rescale(PL_HDR_PQ, PL_HDR_NITS,
+ scale * src->source_max_pq);
+}
+#endif
+
enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *fmt)
{
static const enum pl_chroma_location locs[CHROMA_LOCATION_MAX+1] = {
=====================================
modules/video_output/libplacebo/utils.h
=====================================
@@ -38,6 +38,12 @@ struct pl_color_space vlc_placebo_ColorSpace(const video_format_t *);
struct pl_color_repr vlc_placebo_ColorRepr(const video_format_t *);
enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *);
+#if PL_API_VER >= 185
+// Map dolby vision metadata, using `data` as storage.
+void vlc_placebo_DoviMetadata(struct pl_frame *out, const picture_t *pic,
+ struct pl_dovi_metadata *data);
+#endif
+
int vlc_placebo_PlaneComponents(const video_format_t *, struct pl_plane[4]);
// Fill a pl_plane_data array with various data. Returns the number of planes,
=====================================
src/libvlccore.sym
=====================================
@@ -309,6 +309,7 @@ net_SetCSCov
net_Write
NTPtime64
picture_AttachAncillary
+picture_AttachNewAncillary
picture_BlendSubpicture
picture_Clone
picture_CopyPixels
=====================================
src/misc/picture.c
=====================================
@@ -479,8 +479,29 @@ picture_AttachAncillary(picture_t *pic, struct vlc_ancillary *ancillary)
return vlc_ancillary_array_Insert(&priv->ancillaries, ancillary);
}
+void *
+picture_AttachNewAncillary(picture_t *pic, vlc_ancillary_id id, size_t size)
+{
+ void *data = malloc(size);
+ if (!data)
+ return NULL;
+
+ struct vlc_ancillary *ancillary = vlc_ancillary_Create(data, id);
+ if (!ancillary) {
+ free(data);
+ return NULL;
+ }
+
+ if (picture_AttachAncillary(pic, ancillary) != 0) {
+ vlc_ancillary_Release(ancillary);
+ return NULL;
+ }
+
+ return data;
+}
+
struct vlc_ancillary *
-picture_GetAncillary(picture_t *pic, vlc_ancillary_id id)
+picture_GetAncillary(const picture_t *pic, vlc_ancillary_id id)
{
picture_priv_t *priv = container_of(pic, picture_priv_t, picture);
return vlc_ancillary_array_Get(&priv->ancillaries, id);
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/76379ba010a5c081bbaa93aed5274b772423a81d...147a1bd812ab3d95aaeda127775a068bfdbc88b0
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/76379ba010a5c081bbaa93aed5274b772423a81d...147a1bd812ab3d95aaeda127775a068bfdbc88b0
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list