mirror of
https://github.com/mpv-player/mpv
synced 2024-12-17 20:34:58 +00:00
drm: parse edid using libdisplay-info
libdrm unfortunately doesn't give us what is actually supported by the connector in question. To do that, we would have to parse the edid blob. Use libdisplay-info to do this and make it required for drm support. Using what we get back from the library, we can do a bit of sanity checking for hdr metadata to make sure that the display in question can handle it before we try setting the metadata. Strictly speaking, libdisplay-info has stuff for dynamic metadata that we could potentially use, but as a first pass and for simplicity, only static is considered for now.
This commit is contained in:
parent
8039128693
commit
a4d9bdd262
@ -935,9 +935,11 @@ if features['direct3d']
|
||||
endif
|
||||
|
||||
drm = dependency('libdrm', version: '>= 2.4.105', required: get_option('drm'))
|
||||
features += {'drm': drm.found() and (features['vt.h'] or features['consio.h'] or features['wsdisplay-usl-io.h'])}
|
||||
libdisplay_info = dependency('libdisplay-info', version: '>= 0.1.1', required: get_option('drm'))
|
||||
features += {'drm': drm.found() and libdisplay_info.found() and
|
||||
(features['vt.h'] or features['consio.h'] or features['wsdisplay-usl-io.h'])}
|
||||
if features['drm']
|
||||
dependencies += drm
|
||||
dependencies += [drm, libdisplay_info]
|
||||
sources += files('video/drmprime.c',
|
||||
'video/out/drm_atomic.c',
|
||||
'video/out/drm_common.c',
|
||||
|
@ -617,6 +617,83 @@ success:
|
||||
return true;
|
||||
}
|
||||
|
||||
static void setup_edid(struct vo_drm_state *drm)
|
||||
{
|
||||
drmModePropertyBlobRes *blob = NULL;
|
||||
for (int i = 0; i < drm->connector->count_props; ++i) {
|
||||
drmModePropertyRes *prop = drmModeGetProperty(drm->fd, drm->connector->props[i]);
|
||||
if (prop && strcmp(prop->name, "EDID") == 0)
|
||||
blob = drmModeGetPropertyBlob(drm->fd, drm->connector->prop_values[i]);
|
||||
drmModeFreeProperty(prop);
|
||||
if (blob)
|
||||
break;
|
||||
}
|
||||
if (!blob) {
|
||||
MP_VERBOSE(drm, "Unable to get EDID blob from connector.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
drm->info = di_info_parse_edid(blob->data, blob->length);
|
||||
if (!drm->info) {
|
||||
MP_VERBOSE(drm, "Failed to parse EDID info: %s\n", mp_strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
const struct di_edid *edid = di_info_get_edid(drm->info);
|
||||
if (!edid) {
|
||||
MP_VERBOSE(drm, "Failed to get EDID info: %s\n", mp_strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
drm->chromaticity = di_edid_get_chromaticity_coords(edid);
|
||||
|
||||
const struct di_edid_cta *cta;
|
||||
const struct di_edid_ext *const *exts = di_edid_get_extensions(edid);
|
||||
while (*exts && !(cta = di_edid_ext_get_cta(*exts++)));
|
||||
|
||||
if (!cta) {
|
||||
MP_VERBOSE(drm, "Unable to find CTA-861 extension block.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
const struct di_cta_data_block *const *blocks = di_edid_cta_get_data_blocks(cta);
|
||||
for (int i = 0; *blocks && blocks[i]; ++i) {
|
||||
if (!drm->colorimetry)
|
||||
drm->colorimetry = di_cta_data_block_get_colorimetry(blocks[i]);
|
||||
if (!drm->hdr_static_metadata)
|
||||
drm->hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(blocks[i]);
|
||||
if (drm->colorimetry && drm->hdr_static_metadata)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (blob)
|
||||
drmModeFreePropertyBlob(blob);
|
||||
}
|
||||
|
||||
static bool target_params_supported_by_display(struct vo_drm_state *drm)
|
||||
{
|
||||
if (!drm->chromaticity || !drm->colorimetry || !drm->hdr_static_metadata)
|
||||
return false;
|
||||
|
||||
const struct di_cta_hdr_static_metadata_block *hdr_static_metadata = drm->hdr_static_metadata;
|
||||
enum pl_color_transfer trc = drm->target_params.color.transfer;
|
||||
|
||||
if (!pl_color_transfer_is_hdr(trc) && !hdr_static_metadata->eotfs->traditional_sdr)
|
||||
return false;
|
||||
|
||||
if (pl_color_transfer_is_hdr(trc) && !drm->colorimetry->bt2020_rgb)
|
||||
return false;
|
||||
|
||||
if (trc == PL_COLOR_TRC_PQ && !hdr_static_metadata->eotfs->pq)
|
||||
return false;
|
||||
|
||||
if (trc == PL_COLOR_TRC_HLG && !hdr_static_metadata->eotfs->hlg)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool all_digits(const char *str)
|
||||
{
|
||||
if (str == NULL || str[0] == '\0') {
|
||||
@ -1034,6 +1111,8 @@ bool vo_drm_init(struct vo *vo)
|
||||
if (!setup_mode(drm))
|
||||
goto err;
|
||||
|
||||
setup_edid(drm);
|
||||
|
||||
// Universal planes allows accessing all the planes (including primary)
|
||||
if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
|
||||
MP_ERR(drm, "Failed to set Universal planes capability\n");
|
||||
@ -1079,6 +1158,9 @@ void vo_drm_uninit(struct vo *vo)
|
||||
restore_sdr(drm);
|
||||
destroy_hdr_blob(drm);
|
||||
|
||||
if (drm->info)
|
||||
di_info_destroy(drm->info);
|
||||
|
||||
vo_drm_release_crtc(drm);
|
||||
if (drm->vt_switcher_active)
|
||||
vt_switcher_destroy(&drm->vt_switcher);
|
||||
@ -1283,10 +1365,11 @@ bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr)
|
||||
|
||||
destroy_hdr_blob(drm);
|
||||
drm->target_params = target_params;
|
||||
bool use_sdr = !target_params_supported_by_display(drm) || force_sdr;
|
||||
|
||||
// For any HDR, the BT2020 drm colorspace is the only one that works in practice.
|
||||
struct drm_atomic_context *atomic_ctx = drm->atomic_context;
|
||||
int colorspace = !force_sdr && pl_color_space_is_hdr(&drm->target_params.color) ?
|
||||
int colorspace = !use_sdr && pl_color_space_is_hdr(&drm->target_params.color) ?
|
||||
DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT;
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->connector, "Colorspace", colorspace);
|
||||
|
||||
@ -1295,7 +1378,7 @@ bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr)
|
||||
.metadata_type = HDMI_STATIC_METADATA_TYPE1,
|
||||
.hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1,
|
||||
|
||||
.hdmi_metadata_type1.eotf = force_sdr ? HDMI_EOTF_TRADITIONAL_GAMMA_SDR : eotf_map[target_params.color.transfer],
|
||||
.hdmi_metadata_type1.eotf = use_sdr ? HDMI_EOTF_TRADITIONAL_GAMMA_SDR : eotf_map[target_params.color.transfer],
|
||||
|
||||
.hdmi_metadata_type1.display_primaries[0].x = lrintf(hdr->prim.red.x * DRM_PRIM_FACTOR),
|
||||
.hdmi_metadata_type1.display_primaries[0].y = lrintf(hdr->prim.red.y * DRM_PRIM_FACTOR),
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include <libdisplay-info/cta.h>
|
||||
#include <libdisplay-info/edid.h>
|
||||
#include <libdisplay-info/info.h>
|
||||
|
||||
#include "video/mp_image.h"
|
||||
#include "vo.h"
|
||||
|
||||
@ -129,6 +133,12 @@ struct vo_drm_state {
|
||||
struct vo *vo;
|
||||
struct vt_switcher vt_switcher;
|
||||
|
||||
// libdisplay-info edid stuff
|
||||
struct di_info *info;
|
||||
const struct di_edid_chromaticity_coords *chromaticity;
|
||||
const struct di_cta_hdr_static_metadata_block *hdr_static_metadata;
|
||||
const struct di_cta_colorimetry_block *colorimetry;
|
||||
|
||||
bool active;
|
||||
bool paused;
|
||||
bool still;
|
||||
|
Loading…
Reference in New Issue
Block a user