Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/video_output/libplacebo/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 24 kB image not shown  

Quelle  utils.c   Sprache: C

 

/*****************************************************************************
 * placebo.c: Definition of various libplacebo helpers
 *****************************************************************************
 * Copyright (C) 2018 Niklas Haas
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <assert.h>
#include <stdatomic.h>
#include <stdlib.h>

#include <vlc_common.h>
#include "utils.h"

static void Log(void *priv, enum pl_log_level level, const char *msg)
{
    struct vlc_object_t *obj = priv;

    switch (level) {
    case PL_LOG_FATAL: // fall through
    case PL_LOG_ERR:   msg_Err(obj,  "%s", msg); break;
    case PL_LOG_WARN:  msg_Warn(obj, "%s", msg); break;
    case PL_LOG_INFO: // fall through
    case PL_LOG_DEBUG: msg_Dbg(obj,  "%s", msg); break;
    default: break;
    }
}

pl_log vlc_placebo_CreateLog(vlc_object_t *obj)
{
    return pl_log_create(PL_API_VER, &(struct pl_log_params) {
        // Print placebo DEBUG logs with "-vvv"
        // Print placebo INFO logs with "-vv"
        .log_level = var_InheritInteger(obj, "verbose") >= 3 ? PL_LOG_DEBUG
                                                             : PL_LOG_INFO,
        .log_cb    = Log,
        .log_priv  = obj,
    });
}

struct plane_desc {
    int components;
    size_t pixel_size;
    int comp_bits[4];
    int comp_map[4];
    int w_denom;
    int h_denom;
};

struct fmt_desc {
    enum pl_fmt_type type;
    struct plane_desc planes[4];
    int num_planes;
    int color_bits; // relevant bits, or 0 if the same as the texture depth
};

#define SIZE(n, bits, pad) (((n) * (bits) + (pad) + 7) / 8)
#define COMPS(...) {__VA_ARGS__}

#define PLANE(n, bits, map, wd, hd, pad)            \
  { .components = n,                                \
    .pixel_size = SIZE(n, bits, pad),               \
    .comp_bits = {bits, bits, bits, bits},          \
    .comp_map = map,                                \
    .w_denom = wd,                                  \
    .h_denom = hd,                                  \
  }

#define _PLANAR(n, bits, wd, hd)          \
  .type = PL_FMT_UNORM,                   \
  .num_planes = n,                        \
  .planes = {                             \
      PLANE(1, bits, {0},  1,  1, 0),     \
      PLANE(1, bits, {1}, wd, hd, 0),     \
      PLANE(1, bits, {2}, wd, hd, 0),     \
      PLANE(1, bits, {3},  1,  1, 0),     \
  }

#define _SEMIPLANAR(n, bits, wd, hd)           \
  .type = PL_FMT_UNORM,                        \
  .num_planes = n,                             \
  .planes = {                                  \
      PLANE(1, bits, {0},          1,  1, 0),  \
      PLANE(2, bits, COMPS(1, 2), wd, hd, 0),  \
      PLANE(1, bits, {3},          1,  1, 0),  \
  }

#define PACKED(n, bits, pad)                          \
  .type = PL_FMT_UNORM,                               \
  .num_planes = 1,                                    \
  .planes = {                                         \
      PLANE(n, bits, COMPS(0, 1, 2, 3), 1, 1, pad),   \
  }

#define SINGLE(t, bits)                   \
  .type = PL_FMT_##t,                     \
  .num_planes = 1,                        \
  .planes = {                             \
      PLANE(1, bits, {0}, 1, 1, 0),       \
  }

#define PLANAR(...) _PLANAR(__VA_ARGS__)
#define SEMIPLANAR(...) _SEMIPLANAR(__VA_ARGS__)

#define _410 4, 2
#define _411 4, 1
#define _420 2, 2
#define _422 2, 1
#define _440 1, 2
#define _444 1, 1

// NOTE: This list contains some special formats that don't follow the normal
// rules, but which are included regardless. The corrections for these
// exceptions happen below, in the function vlc_placebo_PlaneData!
static const struct { vlc_fourcc_t fcc; struct fmt_desc desc; } formats[] = {
    { VLC_CODEC_I410,           {PLANAR(3,  8, _410)} },
    { VLC_CODEC_I411,           {PLANAR(3,  8, _411)} },
    { VLC_CODEC_I440,           {PLANAR(3,  8, _440)} },
    { VLC_CODEC_GREY,           {PLANAR(1,  8, _444)} },

    { VLC_CODEC_I420,           {PLANAR(3,  8, _420)} },
#ifdef WORDS_BIGENDIAN
    { VLC_CODEC_I420_9B,        {PLANAR(3, 16, _420), .color_bits = 9} },
    { VLC_CODEC_I420_10B,       {PLANAR(3, 16, _420), .color_bits = 10} },
    { VLC_CODEC_I420_12B,       {PLANAR(3, 16, _420), .color_bits = 12} },
    { VLC_CODEC_I420_16B,       {PLANAR(3, 16, _420), .color_bits = 16} },
#else
    { VLC_CODEC_I420_9L,        {PLANAR(3, 16, _420), .color_bits = 9} },
    { VLC_CODEC_I420_10L,       {PLANAR(3, 16, _420), .color_bits = 10} },
    { VLC_CODEC_I420_12L,       {PLANAR(3, 16, _420), .color_bits = 12} },
    { VLC_CODEC_I420_16L,       {PLANAR(3, 16, _420), .color_bits = 16} },
#endif

    { VLC_CODEC_I422,           {PLANAR(3,  8, _422)} },
#ifdef WORDS_BIGENDIAN
    { VLC_CODEC_I422_9B,        {PLANAR(3, 16, _422), .color_bits = 9} },
    { VLC_CODEC_I422_10B,       {PLANAR(3, 16, _422), .color_bits = 10} },
    { VLC_CODEC_I422_12B,       {PLANAR(3, 16, _422), .color_bits = 12} },
#else
    { VLC_CODEC_I422_9L,        {PLANAR(3, 16, _422), .color_bits = 9} },
    { VLC_CODEC_I422_10L,       {PLANAR(3, 16, _422), .color_bits = 10} },
    { VLC_CODEC_I422_12L,       {PLANAR(3, 16, _422), .color_bits = 12} },
#endif

    { VLC_CODEC_I444,           {PLANAR(3,  8, _444)} },
#ifdef WORDS_BIGENDIAN
    { VLC_CODEC_I444_9B,        {PLANAR(3, 16, _444), .color_bits = 9} },
    { VLC_CODEC_I444_10B,       {PLANAR(3, 16, _444), .color_bits = 10} },
    { VLC_CODEC_I444_12B,       {PLANAR(3, 16, _444), .color_bits = 12} },
    { VLC_CODEC_I444_16B,       {PLANAR(3, 16, _444), .color_bits = 16} },
#else
    { VLC_CODEC_I444_9L,        {PLANAR(3, 16, _444), .color_bits = 9} },
    { VLC_CODEC_I444_10L,       {PLANAR(3, 16, _444), .color_bits = 10} },
    { VLC_CODEC_I444_12L,       {PLANAR(3, 16, _444), .color_bits = 12} },
    { VLC_CODEC_I444_16L,       {PLANAR(3, 16, _444), .color_bits = 16} },
#endif

    { VLC_CODEC_YUVA,           {PLANAR(4,  8, _444)} },
    { VLC_CODEC_YUV422A,        {PLANAR(4,  8, _422)} },
#ifdef WORDS_BIGENDIAN
    { VLC_CODEC_YUVA_444_10B,   {PLANAR(4, 16, _444), .color_bits = 10} },
#else
    { VLC_CODEC_YUVA_444_10L,   {PLANAR(4, 16, _444), .color_bits = 10} },
#endif

    { VLC_CODEC_NV12,           {SEMIPLANAR(2,  8, _420)} },
    { VLC_CODEC_NV21,           {SEMIPLANAR(2,  8, _420)} },
    { VLC_CODEC_P010,           {SEMIPLANAR(2, 16, _420)} },
    { VLC_CODEC_P016,           {SEMIPLANAR(2, 16, _420)} },
    { VLC_CODEC_NV16,           {SEMIPLANAR(2,  8, _422)} },
    { VLC_CODEC_NV61,           {SEMIPLANAR(2,  8, _422)} },
    { VLC_CODEC_NV24,           {SEMIPLANAR(2,  8, _444)} },
    { VLC_CODEC_NV42,           {SEMIPLANAR(2,  8, _444)} },

    { VLC_CODEC_RGB233,         {PACKED(3, 2, 2)} },
    { VLC_CODEC_BGR233,         {PACKED(3, 2, 2)} },
    { VLC_CODEC_RGB332,         {PACKED(3, 2, 2)} },
    { VLC_CODEC_RGB565LE,       {PACKED(3, 5, 1)} },
    { VLC_CODEC_RGB555LE,       {PACKED(3, 5, 1)} },
    { VLC_CODEC_RGB24,          {PACKED(3, 8, 0)} },
    { VLC_CODEC_BGR24,          {PACKED(3, 8, 0)} },
    { VLC_CODEC_RGBA,           {PACKED(4, 8, 0)} },
    { VLC_CODEC_BGRX,           {PACKED(3, 8, 8)} },
    { VLC_CODEC_BGRA,           {PACKED(4, 8, 0)} },

    { VLC_CODEC_GBR_PLANAR,     {PLANAR(3,  8, _444)} },
#ifdef WORDS_BIGENDIAN
    { VLC_CODEC_GBR_PLANAR_9B,  {PLANAR(3, 16, _444), .color_bits = 9} },
    { VLC_CODEC_GBR_PLANAR_10B, {PLANAR(3, 16, _444), .color_bits = 10} },
    { VLC_CODEC_GBR_PLANAR_16B, {PLANAR(3, 16, _444), .color_bits = 16} },
#else
    { VLC_CODEC_GBR_PLANAR_9L,  {PLANAR(3, 16, _444), .color_bits = 9} },
    { VLC_CODEC_GBR_PLANAR_10L, {PLANAR(3, 16, _444), .color_bits = 10} },
    { VLC_CODEC_GBR_PLANAR_16L, {PLANAR(3, 16, _444), .color_bits = 16} },
#endif

    { VLC_CODEC_U8,             {SINGLE(UNORM,  8)} },
    { VLC_CODEC_S8,             {SINGLE(SNORM,  8)} },
    { VLC_CODEC_U16N,           {SINGLE(UNORM, 16)} },
    { VLC_CODEC_S16N,           {SINGLE(SNORM, 16)} },
    { VLC_CODEC_U24N,           {SINGLE(UNORM, 24)} },
    { VLC_CODEC_S24N,           {SINGLE(SNORM, 24)} },
    { VLC_CODEC_U32N,           {SINGLE(UNORM, 32)} },
    { VLC_CODEC_S32N,           {SINGLE(SNORM, 32)} },
    { VLC_CODEC_FL32,           {SINGLE(FLOAT, 32)} },
    { VLC_CODEC_FL64,           {SINGLE(FLOAT, 64)} },

    { 0 },
};

static const struct fmt_desc *FindDesc(vlc_fourcc_t fcc)
{
    for (int i = 0; formats[i].fcc; i++) {
        if (formats[i].fcc == fcc) {
            return &formats[i].desc;
        }
    }

    return NULL;
}

// This fills everything except width/height, which are left as 1
static void FillDesc(vlc_fourcc_t fcc, const struct fmt_desc *desc,
                     struct pl_plane_data data[4])
{
    assert(desc->num_planes <= 4);
    for (int i = 0; i < desc->num_planes; i++) {
        const struct plane_desc *p = &desc->planes[i];

        data[i] = (struct pl_plane_data) {
            .type   = desc->type,
            .width  = 1,
            .height = 1,
            .pixel_stride = p->pixel_size,
        };

        for (int c = 0; c < p->components; c++) {
            data[i].component_size[c] = p->comp_bits[c];
            data[i].component_map[c] = p->comp_map[c];
        }
    }

    // Exceptions to the rule
    switch (fcc) {
    case VLC_CODEC_YV12:
        // Planar Y:V:U
        data[1].component_map[0] = 2;
        data[2].component_map[0] = 1;
        break;

    case VLC_CODEC_BGRX:
    case VLC_CODEC_BGRA:
        // Packed BGR
        data[0].component_map[0] = 2;
        data[0].component_map[1] = 1;
        data[0].component_map[2] = 0;
        break;

    case VLC_CODEC_GBR_PLANAR:
    case VLC_CODEC_GBR_PLANAR_9L:
    case VLC_CODEC_GBR_PLANAR_10L:
    case VLC_CODEC_GBR_PLANAR_16L:
    case VLC_CODEC_GBR_PLANAR_9B:
    case VLC_CODEC_GBR_PLANAR_10B:
    case VLC_CODEC_GBR_PLANAR_16B:
        // Planar GBR
        data[0].component_map[0] = 1;
        data[1].component_map[0] = 2;
        data[2].component_map[0] = 0;
        break;

    case VLC_CODEC_RGB565LE:
        // 5:6:5 instead of 5:5:5
        data[0].component_size[1] += 1;
        break;

    case VLC_CODEC_RGB233:
        // 2:3:3 instead of 2:2:2
        data[0].component_size[1] += 1;
        data[0].component_size[2] += 1;
        break;

    case VLC_CODEC_BGR233:
        // 2:3:3 instead of 2:2:2
        data[0].component_size[1] += 1;
        data[0].component_size[2] += 1;
        // Packed BGR
        data[0].component_map[0] = 2;
        data[0].component_map[1] = 1;
        data[0].component_map[2] = 0;
        break;

    case VLC_CODEC_RGB332:
        // 3:3:2 instead of 2:2:2
        data[0].component_size[0] += 1;
        data[0].component_size[1] += 1;
        break;

    default: break;
    }
}

int vlc_placebo_PlaneData(const picture_t *pic, struct pl_plane_data data[4])
{
    const struct fmt_desc *desc = FindDesc(pic->format.i_chroma);
    if (!desc || desc->num_planes == 0)
        return 0;
    assert(desc->num_planes == pic->i_planes);

    FillDesc(pic->format.i_chroma, desc, data);
    for (int i = 0; i < desc->num_planes; i++) {
        const struct plane_desc *p = &desc->planes[i];
        data[i].width  = (pic->format.i_visible_width  + p->w_denom - 1) / p->w_denom;
        data[i].height = (pic->format.i_visible_height + p->h_denom - 1) / p->h_denom;

        // assert(data[i].height == pic->p[i].i_visible_lines);
        data[i].row_stride = pic->p[i].i_pitch;

        const size_t pixels_offset =
                ((pic->format.i_y_offset + p->w_denom - 1) / p->w_denom) * pic->p[i].i_pitch +
                ((pic->format.i_x_offset + p->h_denom - 1) / p->h_denom) * pic->p[i].i_pixel_pitch;

        data[i].pixels = pic->p[i].p_pixels + pixels_offset;
    }

    return desc->num_planes;
}

bool vlc_placebo_FormatSupported(pl_gpu gpu, vlc_fourcc_t fcc)
{
    const struct fmt_desc *desc = FindDesc(fcc);
    if (!desc)
        return false;

    struct pl_plane_data data[4];
    FillDesc(fcc, desc, data);
    for (int i = 0; i < desc->num_planes; i++) {
        if (!pl_plane_find_fmt(gpu, NULL, &data[i]))
            return false;
    }

    return true;
}

struct pl_color_space vlc_placebo_ColorSpace(const video_format_t *fmt)
{
    static const enum pl_color_primaries primaries[COLOR_PRIMARIES_MAX+1] = {
        [COLOR_PRIMARIES_UNDEF]     = PL_COLOR_PRIM_UNKNOWN,
        [COLOR_PRIMARIES_BT601_525] = PL_COLOR_PRIM_BT_601_525,
        [COLOR_PRIMARIES_BT601_625] = PL_COLOR_PRIM_BT_601_625,
        [COLOR_PRIMARIES_BT709]     = PL_COLOR_PRIM_BT_709,
        [COLOR_PRIMARIES_BT2020]    = PL_COLOR_PRIM_BT_2020,
        [COLOR_PRIMARIES_DCI_P3]    = PL_COLOR_PRIM_DCI_P3,
        [COLOR_PRIMARIES_BT470_M]   = PL_COLOR_PRIM_BT_470M,
    };

    static const enum pl_color_transfer transfers[TRANSFER_FUNC_MAX+1] = {
        [TRANSFER_FUNC_UNDEF]        = PL_COLOR_TRC_UNKNOWN,
        [TRANSFER_FUNC_LINEAR]       = PL_COLOR_TRC_LINEAR,
        [TRANSFER_FUNC_SRGB]         = PL_COLOR_TRC_SRGB,
        [TRANSFER_FUNC_SMPTE_ST2084] = PL_COLOR_TRC_PQ,
        [TRANSFER_FUNC_HLG]          = PL_COLOR_TRC_HLG,
        // these are all designed to be displayed on BT.1886 displays, so this
        // is the correct way to handle them in libplacebo
        [TRANSFER_FUNC_BT470_BG]    = PL_COLOR_TRC_BT_1886,
        [TRANSFER_FUNC_BT470_M]     = PL_COLOR_TRC_BT_1886,
        [TRANSFER_FUNC_BT709]       = PL_COLOR_TRC_BT_1886,
        [TRANSFER_FUNC_SMPTE_240]   = PL_COLOR_TRC_BT_1886,
    };

    return (struct pl_color_space) {
        .primaries = primaries[fmt->primaries],
        .transfer  = transfers[fmt->transfer],
        .hdr = {
            .prim = {
                .green.x = fmt->mastering.primaries[0] / 50000.0f,
                .green.y = fmt->mastering.primaries[1] / 50000.0f,
                .blue.x  = fmt->mastering.primaries[2] / 50000.0f,
                .blue.y  = fmt->mastering.primaries[3] / 50000.0f,
                .red.x   = fmt->mastering.primaries[4] / 50000.0f,
                .red.y   = fmt->mastering.primaries[5] / 50000.0f,
                .white.x = fmt->mastering.white_point[0] / 50000.0f,
                .white.y = fmt->mastering.white_point[1] / 50000.0f,
            },
            .min_luma = fmt->mastering.min_luminance / 10000.0f,
            .max_luma = fmt->mastering.max_luminance / 10000.0f,
            .max_cll = fmt->lighting.MaxCLL,
            .max_fall = fmt->lighting.MaxFALL,
        },
    };
}

struct pl_color_repr vlc_placebo_ColorRepr(const video_format_t *fmt)
{
    static const enum pl_color_system yuv_systems[COLOR_SPACE_MAX+1] = {
        [COLOR_SPACE_UNDEF]     = PL_COLOR_SYSTEM_BT_709, // _UNKNOWN is RGB
        [COLOR_SPACE_BT601]     = PL_COLOR_SYSTEM_BT_601,
        [COLOR_SPACE_BT709]     = PL_COLOR_SYSTEM_BT_709,
        [COLOR_SPACE_BT2020]    = PL_COLOR_SYSTEM_BT_2020_NC,
    };

    // fmt->space describes the YCbCr type only, it does not distinguish
    // between YUV, XYZ, RGB and the likes!
    enum pl_color_system sys;
    if (likely(vlc_fourcc_IsYUV(fmt->i_chroma))) {
        sys = yuv_systems[fmt->space];
    } else if (unlikely(fmt->i_chroma == VLC_CODEC_XYZ_12L||
                        fmt->i_chroma == VLC_CODEC_XYZ_12B)) {
        sys = PL_COLOR_SYSTEM_XYZ;
    } else {
        sys = PL_COLOR_SYSTEM_RGB;
    }

    const struct fmt_desc *desc = FindDesc(fmt->i_chroma);
    int sample_depth = desc->planes[0].comp_bits[0]; // just use first component

    return (struct pl_color_repr) {
        .sys        = sys,
        .alpha      = PL_ALPHA_PREMULTIPLIED,
        .levels     = unlikely(fmt->color_range == COLOR_RANGE_FULL)
                        ? PL_COLOR_LEVELS_PC
                        : PL_COLOR_LEVELS_TV,
        .bits = {
            .sample_depth   = sample_depth,
            .color_depth    = desc->color_bits ? desc->color_bits : sample_depth,
            .bit_shift      = 0,
        },
    };
}

void vlc_placebo_HdrMetadata(const vlc_video_hdr_dynamic_metadata_t *src,
                             struct pl_hdr_metadata *dst)
{
#if PL_API_VER >= 242
    for (size_t i = 0; i < ARRAY_SIZE(dst->scene_max); i++)
        dst->scene_max[i] = src->maxscl[i];
    dst->scene_avg = src->average_maxrgb;

    if (src->tone_mapping_flag) {
        static_assert(sizeof(dst->ootf.anchors) == sizeof(src->bezier_curve_anchors), "array mismatch");
        memcpy(dst->ootf.anchors, src->bezier_curve_anchors, sizeof(dst->ootf.anchors));
        dst->ootf.num_anchors = src->num_bezier_anchors;
        dst->ootf.target_luma = src->targeted_luminance;
        dst->ootf.knee_x = src->knee_point_x;
        dst->ootf.knee_y = src->knee_point_y;
    }
#else
    (void) src;
    (void) dst;
#endif
}

void vlc_placebo_DoviMetadata(const vlc_video_dovi_metadata_t *src,
                              struct pl_dovi_metadata *dst)
{
    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 (size_t 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 (size_t 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 (size_t 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;
            }
        }
    }
}

void vlc_placebo_frame_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);
    vlc_placebo_DoviMetadata(src, dst);

    // 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);
}

enum pl_chroma_location vlc_placebo_ChromaLoc(const video_format_t *fmt)
{
    static const enum pl_chroma_location locs[CHROMA_LOCATION_MAX+1] = {
        [CHROMA_LOCATION_UNDEF]         = PL_CHROMA_UNKNOWN,
        [CHROMA_LOCATION_LEFT]          = PL_CHROMA_LEFT,
        [CHROMA_LOCATION_CENTER]        = PL_CHROMA_CENTER,
        [CHROMA_LOCATION_TOP_LEFT]      = PL_CHROMA_TOP_LEFT,
        [CHROMA_LOCATION_TOP_CENTER]    = PL_CHROMA_TOP_CENTER,
        [CHROMA_LOCATION_BOTTOM_LEFT]   = PL_CHROMA_BOTTOM_LEFT,
        [CHROMA_LOCATION_BOTTOM_CENTER] = PL_CHROMA_BOTTOM_CENTER,
    };

    return locs[fmt->chroma_location];
}

int vlc_placebo_PlaneComponents(const video_format_t *fmt,
                                struct pl_plane planes[4]) {
    const struct fmt_desc *desc = FindDesc(fmt->i_chroma);
    if (!desc)
        return 0;

    for (int i = 0; i < desc->num_planes; i++) {
        const struct plane_desc *p = &desc->planes[i];

        planes[i].components = p->components;
        for (int c = 0; c < p->components; ++c)
            planes[i].component_mapping[c] = p->comp_map[c];
    }

    return desc->num_planes;
}

void vlc_placebo_ColorMapParams(vlc_object_t *obj, const char *prefix,
                                struct pl_color_map_params *params)
{
#define PREFIX(str) (snprintf(opt, sizeof(opt), "%s-%s", prefix, str), opt)
    char opt[64];

    *params = pl_color_map_default_params;

    switch (var_InheritInteger(obj, PREFIX("gamut-mapping"))) {
    case GAMUT_AUTO:        break;
#if PL_API_VER >= 269
    case GAMUT_CLIP:        params->gamut_mapping = &pl_gamut_map_clip; break;
    case GAMUT_PERCEPTUAL:  params->gamut_mapping = &pl_gamut_map_perceptual; break;
    case GAMUT_RELATIVE:    params->gamut_mapping = &pl_gamut_map_relative; break;
    case GAMUT_SATURATION:  params->gamut_mapping = &pl_gamut_map_saturation; break;
    case GAMUT_ABSOLUTE:    params->gamut_mapping = &pl_gamut_map_absolute; break;
    case GAMUT_DESATURATE:  params->gamut_mapping = &pl_gamut_map_desaturate; break;
    case GAMUT_DARKEN:      params->gamut_mapping = &pl_gamut_map_darken; break;
    case GAMUT_WARN:        params->gamut_mapping = &pl_gamut_map_highlight; break;
    case GAMUT_LINEAR:      params->gamut_mapping = &pl_gamut_map_linear; break;
#else
    case GAMUT_CLIP:        params->gamut_mode = PL_GAMUT_CLIP; break;
    case GAMUT_PERCEPTUAL:  break; // unsupported
    case GAMUT_RELATIVE:    params->intent = PL_INTENT_RELATIVE_COLORIMETRIC; break;
    case GAMUT_SATURATION:  params->intent = PL_INTENT_SATURATION; break;
    case GAMUT_ABSOLUTE:    params->intent = PL_INTENT_ABSOLUTE_COLORIMETRIC; break;
    case GAMUT_DESATURATE:  params->gamut_mode = PL_GAMUT_DESATURATE; break;
    case GAMUT_DARKEN:      params->gamut_mode = PL_GAMUT_DARKEN; break;
    case GAMUT_WARN:        params->gamut_mode = PL_GAMUT_WARN; break;
    case GAMUT_LINEAR:      break; // unsupported
#endif
    }

    switch (var_InheritInteger(obj, PREFIX("tone-mapping-function"))) {
    case TONEMAP_AUTO:      break;
    case TONEMAP_CLIP:      params->tone_mapping_function = &pl_tone_map_clip; break;
    case TONEMAP_BT2390:    params->tone_mapping_function = &pl_tone_map_bt2390; break;
    case TONEMAP_REINHARD:  params->tone_mapping_function = &pl_tone_map_reinhard; break;
    case TONEMAP_MOBIUS:    params->tone_mapping_function = &pl_tone_map_mobius; break;
    case TONEMAP_HABLE:     params->tone_mapping_function = &pl_tone_map_hable; break;
    case TONEMAP_GAMMA:     params->tone_mapping_function = &pl_tone_map_gamma; break;
    case TONEMAP_LINEAR:    params->tone_mapping_function = &pl_tone_map_linear; break;
    case TONEMAP_BT2446A:   params->tone_mapping_function = &pl_tone_map_bt2446a; break;
    case TONEMAP_SPLINE:    params->tone_mapping_function = &pl_tone_map_spline; break;
    }

    params->tone_mapping_param = var_InheritFloat(obj, PREFIX("tone-mapping-param"));
    params->inverse_tone_mapping = var_InheritBool(obj, PREFIX("inverse-tone-mapping"));
}

Messung
CHZG
849510093

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.