vdr-plugin-softhdcuvid/hdr.c

492 lines
14 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");
}