[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