vdr-plugin-softhdcuvid/hdr.c

607 lines
15 KiB
C

#include <libavutil/mastering_display_metadata.h>
#ifndef _DRM_MODE_H
/**
* struct hdr_metadata_infoframe - HDR Metadata Infoframe Data.
*
* HDR Metadata Infoframe as per CTA 861.G spec. This is expected
* to match exactly with the spec.
*
* Userspace is expected to pass the metadata information as per
* the format described in this structure.
*/
struct hdr_metadata_infoframe {
/**
* @eotf: Electro-Optical Transfer Function (EOTF)
* used in the stream.
*/
__u8 eotf;
/**
* @metadata_type: Static_Metadata_Descriptor_ID.
*/
__u8 metadata_type;
/**
* @display_primaries: Color Primaries of the Data.
* These are coded as unsigned 16-bit values in units of
* 0.00002, where 0x0000 represents zero and 0xC350
* represents 1.0000.
* @display_primaries.x: X cordinate of color primary.
* @display_primaries.y: Y cordinate of color primary.
*/
struct {
__u16 x, y;
} display_primaries[3];
/**
* @white_point: White Point of Colorspace Data.
* These are coded as unsigned 16-bit values in units of
* 0.00002, where 0x0000 represents zero and 0xC350
* represents 1.0000.
* @white_point.x: X cordinate of whitepoint of color primary.
* @white_point.y: Y cordinate of whitepoint of color primary.
*/
struct {
__u16 x, y;
} white_point;
/**
* @max_display_mastering_luminance: Max Mastering Display Luminance.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_display_mastering_luminance;
/**
* @min_display_mastering_luminance: Min Mastering Display Luminance.
* This value is coded as an unsigned 16-bit value in units of
* 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
* represents 6.5535 cd/m2.
*/
__u16 min_display_mastering_luminance;
/**
* @max_cll: Max Content Light Level.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_cll;
/**
* @max_fall: Max Frame Average Light Level.
* This value is coded as an unsigned 16-bit value in units of 1 cd/m2,
* where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
*/
__u16 max_fall;
};
/**
* struct hdr_output_metadata - HDR output metadata
*
* Metadata Information to be passed from userspace
*/
struct hdr_output_metadata {
/**
* @metadata_type: Static_Metadata_Descriptor_ID.
*/
__u32 metadata_type;
/**
* @hdmi_metadata_type1: HDR Metadata Infoframe.
*/
union {
struct hdr_metadata_infoframe hdmi_metadata_type1;
};
};
#endif
enum hdr_metadata_eotf {
EOTF_TRADITIONAL_GAMMA_SDR,
EOTF_TRADITIONAL_GAMMA_HDR,
EOTF_ST2084,
EOTF_HLG,
};
enum metadata_id {
METADATA_TYPE1,
};
void weston_hdr_metadata(void *data, uint16_t display_primary_r_x, uint16_t display_primary_r_y,
uint16_t display_primary_g_x, uint16_t display_primary_g_y, uint16_t display_primary_b_x,
uint16_t display_primary_b_y, uint16_t white_point_x, uint16_t white_point_y,
uint16_t min_luminance, uint16_t max_luminance, uint16_t max_cll, uint16_t max_fall,
enum hdr_metadata_eotf eotf) {
uint8_t *data8;
uint16_t *data16;
data8 = data;
*data8++ = eotf;
*data8++ = METADATA_TYPE1;
data16 = (void *)data8;
*data16++ = display_primary_r_x;
*data16++ = display_primary_r_y;
*data16++ = display_primary_g_x;
*data16++ = display_primary_g_y;
*data16++ = display_primary_b_x;
*data16++ = display_primary_b_y;
*data16++ = white_point_x;
*data16++ = white_point_y;
*data16++ = max_luminance;
*data16++ = min_luminance;
*data16++ = max_cll;
*data16++ = max_fall;
}
struct weston_vector {
float f[4];
};
struct weston_colorspace {
struct weston_vector r, g, b;
struct weston_vector whitepoint;
const char *name;
const char *whitepoint_name;
};
struct weston_colorspace hdr10;
static const struct weston_colorspace bt470m = {
.r = {{
0.670f,
0.330f,
}},
.g = {{
0.210f,
0.710f,
}},
.b = {{
0.140f,
0.080f,
}},
.whitepoint = {{
0.3101f,
0.3162f,
}},
.name = "BT.470 M",
.whitepoint_name = "C",
};
static const struct weston_colorspace bt470bg = {
.r = {{
0.640f,
0.330f,
}},
.g = {{
0.290f,
0.600f,
}},
.b = {{
0.150f,
0.060f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "BT.470 B/G",
.whitepoint_name = "D65",
};
static const struct weston_colorspace smpte170m = {
.r = {{
0.630f,
0.340f,
}},
.g = {{
0.310f,
0.595f,
}},
.b = {{
0.155f,
0.070f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "SMPTE 170M",
.whitepoint_name = "D65",
};
static const struct weston_colorspace smpte240m = {
.r = {{
0.630f,
0.340f,
}},
.g = {{
0.310f,
0.595f,
}},
.b = {{
0.155f,
0.070f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "SMPTE 240M",
.whitepoint_name = "D65",
};
static const struct weston_colorspace bt709 = {
.r = {{
0.640f,
0.330f,
}},
.g = {{
0.300f,
0.600f,
}},
.b = {{
0.150f,
0.060f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "BT.709",
.whitepoint_name = "D65",
};
static const struct weston_colorspace bt2020 = {
.r = {{
0.708f,
0.292f,
}},
.g = {{
0.170f,
0.797f,
}},
.b = {{
0.131f,
0.046f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "BT.2020",
.whitepoint_name = "D65",
};
static const struct weston_colorspace srgb = {
.r = {{
0.640f,
0.330f,
}},
.g = {{
0.300f,
0.600f,
}},
.b = {{
0.150f,
0.060f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "sRGB",
.whitepoint_name = "D65",
};
static const struct weston_colorspace adobergb = {
.r = {{
0.640f,
0.330f,
}},
.g = {{
0.210f,
0.710f,
}},
.b = {{
0.150f,
0.060f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "AdobeRGB",
.whitepoint_name = "D65",
};
static const struct weston_colorspace dci_p3 = {
.r = {{
0.680f,
0.320f,
}},
.g = {{
0.265f,
0.690f,
}},
.b = {{
0.150f,
0.060f,
}},
.whitepoint = {{
0.3127f,
0.3290f,
}},
.name = "DCI-P3 D65",
.whitepoint_name = "D65",
};
static const struct weston_colorspace prophotorgb = {
.r = {{
0.7347f,
0.2653f,
}},
.g = {{
0.1596f,
0.8404f,
}},
.b = {{
0.0366f,
0.0001f,
}},
.whitepoint = {{.3457, .3585}},
.name = "ProPhoto RGB",
.whitepoint_name = "D50",
};
static const struct weston_colorspace ciergb = {
.r = {{
0.7347f,
0.2653f,
}},
.g = {{
0.2738f,
0.7174f,
}},
.b = {{
0.1666f,
0.0089f,
}},
.whitepoint = {{
1.0f / 3.0f,
1.0f / 3.0f,
}},
.name = "CIE RGB",
.whitepoint_name = "E",
};
static const struct weston_colorspace ciexyz = {
.r = {{
1.0f,
0.0f,
}},
.g = {{
0.0f,
1.0f,
}},
.b = {{
0.0f,
0.0f,
}},
.whitepoint = {{
1.0f / 3.0f,
1.0f / 3.0f,
}},
.name = "CIE XYZ",
.whitepoint_name = "E",
};
const struct weston_colorspace ap0 = {
.r = {{
0.7347f,
0.2653f,
}},
.g = {{
0.0000f,
1.0000f,
}},
.b = {{
0.0001f,
-0.0770f,
}},
.whitepoint = {{
.32168f,
.33767f,
}},
.name = "ACES primaries #0",
.whitepoint_name = "D60",
};
const struct weston_colorspace ap1 = {
.r = {{
0.713f,
0.393f,
}},
.g = {{
0.165f,
0.830f,
}},
.b = {{
0.128f,
0.044f,
}},
.whitepoint = {{
0.32168f,
0.33767f,
}},
.name = "ACES primaries #1",
.whitepoint_name = "D60",
};
static const struct weston_colorspace *const colorspaces[] = {
&bt470m, &bt470bg, &smpte170m, &smpte240m, &bt709, &bt2020, &srgb,
&adobergb, &dci_p3, &prophotorgb, &ciergb, &ciexyz, &ap0, &ap1,
};
#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a)[0])
const struct weston_colorspace *weston_colorspace_lookup(const char *name) {
unsigned i;
if (!name)
return NULL;
for (i = 0; i < ARRAY_LENGTH(colorspaces); i++) {
const struct weston_colorspace *c = colorspaces[i];
if (!strcmp(c->name, name))
return c;
}
return NULL;
}
static int cleanup = 0;
static uint16_t encode_xyy(float xyy) { return xyy * 50000; }
static AVMasteringDisplayMetadata md_save = {0};
static AVContentLightMetadata ld_save = {0};
static void set_hdr_metadata(int color, int trc, AVFrameSideData *sd1, AVFrameSideData *sd2) {
drmModeAtomicReqPtr ModeReq;
struct weston_colorspace *cs;
enum hdr_metadata_eotf eotf;
struct hdr_output_metadata data;
int ret, MaxCLL = 1500, MaxFALL = 400;
int max_lum = 4000, min_lum = 0050;
struct AVMasteringDisplayMetadata *md = NULL;
struct AVContentLightMetadata *ld = NULL;
// clean up FFMEPG stuff
if (trc == AVCOL_TRC_BT2020_10)
trc = AVCOL_TRC_ARIB_STD_B67;
if ((old_color == color && old_trc == trc && !sd1 && !sd2) || !render->hdr_metadata)
return; // nothing to do
if (sd1)
md = sd1->data;
if (sd2)
ld = sd2->data;
if (md && !memcmp(md, &md_save, sizeof(md_save)))
if (ld && !memcmp(ld, &ld_save, sizeof(ld_save))) {
return;
} else if (ld && !memcmp(ld, &ld_save, sizeof(ld_save))) {
return;
}
if (ld)
memcpy(&ld_save, ld, sizeof(ld_save));
if (md)
memcpy(&md_save, md, sizeof(md_save));
Debug(3, "Update HDR to TRC %d color %d\n", trc, color);
old_color = color;
old_trc = trc;
if (VulkanTargetColorSpace != 3) { // no HDR TV
m_need_modeset = 1; // change in colorsettings
return;
}
if (render->hdr_blob_id)
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
switch (trc) {
case AVCOL_TRC_BT709: // 1
case AVCOL_TRC_UNSPECIFIED: // 2
eotf = EOTF_TRADITIONAL_GAMMA_SDR;
break;
case AVCOL_TRC_BT2020_10: // 14
case AVCOL_TRC_BT2020_12:
case AVCOL_TRC_ARIB_STD_B67: // 18 HLG
eotf = EOTF_HLG;
break;
case AVCOL_TRC_SMPTE2084: // 16
eotf = EOTF_ST2084;
break;
default:
eotf = EOTF_TRADITIONAL_GAMMA_SDR;
break;
}
switch (color) {
case AVCOL_PRI_BT709: // 1
case AVCOL_PRI_UNSPECIFIED: // 2
cs = weston_colorspace_lookup("BT.709");
break;
case AVCOL_PRI_BT2020: // 9
cs = weston_colorspace_lookup("BT.2020");
break;
case AVCOL_PRI_BT470BG: // 5
cs = weston_colorspace_lookup("BT.470 B/G"); // BT.601
break;
default:
cs = weston_colorspace_lookup("BT.709");
break;
}
if (md) { // we got Metadata
if (md->has_primaries) {
Debug(3,
"Mastering Display Metadata,\n has_primaries:%d has_luminance:%d \n"
"r(%5.4f,%5.4f) g(%5.4f,%5.4f) b(%5.4f %5.4f) wp(%5.4f, %5.4f) \n"
"min_luminance=%f, max_luminance=%f\n",
md->has_primaries, md->has_luminance, av_q2d(md->display_primaries[0][0]),
av_q2d(md->display_primaries[0][1]), av_q2d(md->display_primaries[1][0]),
av_q2d(md->display_primaries[1][1]), av_q2d(md->display_primaries[2][0]),
av_q2d(md->display_primaries[2][1]), av_q2d(md->white_point[0]), av_q2d(md->white_point[1]),
av_q2d(md->min_luminance), av_q2d(md->max_luminance));
cs = &hdr10;
cs->r.f[0] = (float)md->display_primaries[0][0].num / (float)md->display_primaries[0][0].den;
cs->r.f[1] = (float)md->display_primaries[0][1].num / (float)md->display_primaries[0][1].den;
cs->g.f[0] = (float)md->display_primaries[1][0].num / (float)md->display_primaries[1][0].den;
cs->g.f[1] = (float)md->display_primaries[1][1].num / (float)md->display_primaries[1][1].den;
cs->b.f[0] = (float)md->display_primaries[2][0].num / (float)md->display_primaries[2][0].den;
cs->b.f[1] = (float)md->display_primaries[2][1].num / (float)md->display_primaries[2][1].den;
cs->whitepoint.f[0] = (float)md->white_point[0].num / (float)md->white_point[0].den;
cs->whitepoint.f[1] = (float)md->white_point[1].num / (float)md->white_point[1].den;
}
if (md->has_luminance) {
max_lum = av_q2d(md->max_luminance);
min_lum = av_q2d(md->min_luminance) * 10000;
printf("max_lum %d min_lum %d\n", max_lum, min_lum);
}
}
if (ld) {
Debug(3, "Has MaxCLL %d MaxFALL %d\n", ld->MaxCLL, ld->MaxFALL);
MaxCLL = ld->MaxCLL;
MaxFALL = ld->MaxFALL;
}
data.metadata_type = 7; // ????????????????????????
weston_hdr_metadata(&data.hdmi_metadata_type1, encode_xyy(cs->r.f[0]), encode_xyy(cs->r.f[1]),
encode_xyy(cs->g.f[0]), encode_xyy(cs->g.f[1]), encode_xyy(cs->b.f[0]), encode_xyy(cs->b.f[1]),
encode_xyy(cs->whitepoint.f[0]), encode_xyy(cs->whitepoint.f[1]),
max_lum, // max_display_mastering_luminance
min_lum, // min_display_mastering_luminance
MaxCLL, // Maximum Content Light Level (MaxCLL)
MaxFALL, // Maximum Frame-Average Light Level (MaxFALL)
eotf);
ret = drmModeCreatePropertyBlob(render->fd_drm, &data, sizeof(data), &render->hdr_blob_id);
if (ret) {
printf("DRM: HDR metadata: failed blob create \n");
render->hdr_blob_id = 0;
return;
}
ret = drmModeConnectorSetProperty(render->fd_drm, render->connector_id, render->hdr_metadata, render->hdr_blob_id);
if (ret) {
printf("DRM: HDR metadata: failed property set %d\n", ret);
if (render->hdr_blob_id)
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
render->hdr_blob_id = 0;
return;
}
m_need_modeset = 1;
Debug(3, "DRM: HDR metadata: prop set\n");
}