mirror of
https://github.com/jojo61/vdr-plugin-softhdcuvid.git
synced 2023-10-10 13:37:41 +02:00
492 lines
15 KiB
C
492 lines
15 KiB
C
|
#include <libavutil/mastering_display_metadata.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;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
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;
|
||
|
static uint32_t blob_id = 0;
|
||
|
int ret,MaxCLL=1500,MaxFALL=400;
|
||
|
int max_lum=4000,min_lum=0050;
|
||
|
struct AVMasteringDisplayMetadata *md = NULL;
|
||
|
struct AVContentLightMetadata *ld = NULL;
|
||
|
|
||
|
if (render->hdr_metadata == -1) { // Metadata not supported
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// clean up FFMEPG stuff
|
||
|
if (trc == AVCOL_TRC_BT2020_10)
|
||
|
trc = AVCOL_TRC_ARIB_STD_B67;
|
||
|
if (trc == AVCOL_TRC_UNSPECIFIED)
|
||
|
trc = AVCOL_TRC_BT709;
|
||
|
if (color == AVCOL_PRI_UNSPECIFIED)
|
||
|
color = AVCOL_PRI_BT709;
|
||
|
|
||
|
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));
|
||
|
|
||
|
printf("Update HDR to TRC %d color %d\n",trc,color);
|
||
|
|
||
|
if (trc == AVCOL_TRC_BT2020_10)
|
||
|
trc = AVCOL_TRC_ARIB_STD_B67;
|
||
|
|
||
|
old_color = color;
|
||
|
old_trc = trc;
|
||
|
|
||
|
if (blob_id)
|
||
|
drmModeDestroyPropertyBlob(render->fd_drm, 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;
|
||
|
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), &blob_id);
|
||
|
if (ret) {
|
||
|
printf("DRM: HDR metadata: failed blob create \n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ret = drmModeConnectorSetProperty(render->fd_drm, render->connector_id,
|
||
|
render->hdr_metadata, blob_id);
|
||
|
if (ret) {
|
||
|
printf("DRM: HDR metadata: failed property set %d\n",ret);
|
||
|
|
||
|
if (blob_id)
|
||
|
drmModeDestroyPropertyBlob(render->fd_drm, blob_id);
|
||
|
return;
|
||
|
}
|
||
|
m_need_modeset = 1;
|
||
|
|
||
|
printf("DRM: HDR metadata: prop set\n");
|
||
|
|
||
|
}
|
||
|
|