1
0
mirror of https://github.com/jojo61/vdr-plugin-softhdcuvid.git synced 2023-10-10 13:37:41 +02:00

Inital Support for DRM with HDR10 and HDR-HLG

This commit is contained in:
jojo61 2019-12-10 10:45:22 +01:00
parent f17e58c7c5
commit 3bed988b14
6 changed files with 1216 additions and 175 deletions

View File

@ -11,13 +11,20 @@
### Configuration (edit this for your needs) ### Configuration (edit this for your needs)
# comment out if not needed # comment out if not needed
# what kind of driver do we make - # what kind of decoder do we make -
# if VAAPI is enabled the drivername is softhdvaapi # if VAAPI is enabled the pluginname is softhdvaapi
# if CUVID is enabled the drivername is softhdcuvid # if CUVID is enabled the pluginname is softhdcuvid
# if DRM is enabled the pluginname is softhddrm
#VAAPI=1 #VAAPI=1
CUVID=1 CUVID=1
# use libplacebo - available for both drivers # if you enable DRM then the plugin will only run without X server
# only valid for VAAPI
# does not work with libplacebo
#DRM=1
# use libplacebo - available for both decoders but not for DRM
#LIBPLACEBO=1 #LIBPLACEBO=1
# use YADIF deint - only available with cuvid # use YADIF deint - only available with cuvid
@ -25,6 +32,7 @@ CUVID=1
CONFIG := #-DDEBUG # remove # to enable debug output
@ -60,7 +68,6 @@ SWRESAMPLE = 1
#AVRESAMPLE = 1 #AVRESAMPLE = 1
#endif #endif
CONFIG := #-DDEBUG #-DOSD_DEBUG # enable debug output+functions
CONFIG += -DHAVE_GL # needed for mpv libs CONFIG += -DHAVE_GL # needed for mpv libs
#CONFIG += -DSTILL_DEBUG=2 # still picture debug verbose level #CONFIG += -DSTILL_DEBUG=2 # still picture debug verbose level
CONFIG += -DAV_INFO -DAV_INFO_TIME=3000 # info/debug a/v sync CONFIG += -DAV_INFO -DAV_INFO_TIME=3000 # info/debug a/v sync
@ -152,6 +159,14 @@ ifeq ($(LIBPLACEBO),1)
CONFIG += -DPLACEBO CONFIG += -DPLACEBO
endif endif
ifeq ($(DRM),1)
PLUGIN = softhddrm
CONFIG += -DUSE_DRM -DVAAPI
_CFLAGS += $(shell pkg-config --cflags libdrm)
LIBS += -lgbm -ldrm
endif
ifeq ($(CUVID),1) ifeq ($(CUVID),1)
CONFIG += -DUSE_PIP # PIP support CONFIG += -DUSE_PIP # PIP support
CONFIG += -DCUVID # enable CUVID decoder CONFIG += -DCUVID # enable CUVID decoder
@ -261,7 +276,7 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D_GNU_SOURCE $(CONFIG) \
### Make it standard ### Make it standard
override CXXFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \ override CXXFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
-g -Wextra -Winit-self -Werror=overloaded-virtual -std=c++0x -g -W -Wextra -Winit-self -Werror=overloaded-virtual -Wno-unused-parameter
override CFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \ override CFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
-g -W -Wextra -Winit-self -Wdeclaration-after-statement -g -W -Wextra -Winit-self -Wdeclaration-after-statement
@ -273,7 +288,7 @@ ifeq ($(OPENGLOSD),1)
OBJS += openglosd.o OBJS += openglosd.o
endif endif
SRCS = $(wildcard $(OBJS:.o=.c)) softhdcuvid.cpp SRCS = $(wildcard $(OBJS:.o=.c)) *.cpp
### The main target: ### The main target:
@ -348,6 +363,8 @@ HDRS= $(wildcard *.h)
indent: indent:
for i in $(SRCS) $(HDRS); do \ for i in $(SRCS) $(HDRS); do \
indent $$i; \ indent $$i; \
unexpand -a $$i | sed -e s/constconst/const/ > $$i.up; \
mv $$i.up $$i; \
done done
video_test: video.c Makefile video_test: video.c Makefile

471
drm.c Normal file
View File

@ -0,0 +1,471 @@
#include <unistd.h>
#include <gbm.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#define DRM_DEBUG
//----------------------------------------------------------------------------
// DRM
//----------------------------------------------------------------------------
struct _Drm_Render_
{
int fd_drm;
drmModeModeInfo mode;
drmModeCrtc *saved_crtc;
// drmEventContext ev;
int bpp;
uint32_t connector_id, crtc_id, video_plane;
uint32_t hdr_metadata;
};
typedef struct _Drm_Render_ VideoRender;
struct {
struct gbm_device *dev;
struct gbm_surface *surface;
} gbm;
VideoRender *render;
//----------------------------------------------------------------------------
// Helper functions
//----------------------------------------------------------------------------
static uint64_t GetPropertyValue(int fd_drm, uint32_t objectID,
uint32_t objectType, const char *propName)
{
uint32_t i;
int found = 0;
uint64_t value = 0;
drmModePropertyPtr Prop;
drmModeObjectPropertiesPtr objectProps =
drmModeObjectGetProperties(fd_drm, objectID, objectType);
for (i = 0; i < objectProps->count_props; i++) {
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
fprintf(stderr, "GetPropertyValue: Unable to query property.\n");
if (strcmp(propName, Prop->name) == 0) {
value = objectProps->prop_values[i];
found = 1;
}
drmModeFreeProperty(Prop);
if (found)
break;
}
drmModeFreeObjectProperties(objectProps);
#ifdef DRM_DEBUG
if (!found)
fprintf(stderr, "GetPropertyValue: Unable to find value for property \'%s\'.\n",
propName);
#endif
return value;
}
static uint32_t GetPropertyID(int fd_drm, uint32_t objectID,
uint32_t objectType, const char *propName)
{
uint32_t i;
int found = 0;
uint32_t value = -1;
drmModePropertyPtr Prop;
drmModeObjectPropertiesPtr objectProps =
drmModeObjectGetProperties(fd_drm, objectID, objectType);
for (i = 0; i < objectProps->count_props; i++) {
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
fprintf(stderr, "GetPropertyValue: Unable to query property.\n");
if (strcmp(propName, Prop->name) == 0) {
value = objectProps->props[i];
found = 1;
}
drmModeFreeProperty(Prop);
if (found)
break;
}
drmModeFreeObjectProperties(objectProps);
#ifdef DRM_DEBUG
if (!found)
Debug(3,"GetPropertyValue: Unable to find ID for property \'%s\'.\n",propName);
#endif
return value;
}
static int SetPropertyRequest(drmModeAtomicReqPtr ModeReq, int fd_drm,
uint32_t objectID, uint32_t objectType,
const char *propName, uint64_t value)
{
uint32_t i;
uint64_t id = 0;
drmModePropertyPtr Prop;
drmModeObjectPropertiesPtr objectProps =
drmModeObjectGetProperties(fd_drm, objectID, objectType);
for (i = 0; i < objectProps->count_props; i++) {
if ((Prop = drmModeGetProperty(fd_drm, objectProps->props[i])) == NULL)
printf( "SetPropertyRequest: Unable to query property.\n");
if (strcmp(propName, Prop->name) == 0) {
id = Prop->prop_id;
drmModeFreeProperty(Prop);
break;
}
drmModeFreeProperty(Prop);
}
drmModeFreeObjectProperties(objectProps);
if (id == 0)
printf( "SetPropertyRequest: Unable to find value for property \'%s\'.\n",
propName);
return drmModeAtomicAddProperty(ModeReq, objectID, id, value);
}
static int FindDevice(VideoRender * render)
{
drmVersion *version;
drmModeRes *resources;
drmModeConnector *connector;
drmModeEncoder *encoder = 0;
drmModeModeInfo *mode;
drmModePlane *plane;
drmModePlaneRes *plane_res;
drmModeObjectPropertiesPtr props;
uint32_t j, k;
uint64_t has_dumb;
uint64_t has_prime;
int i,ii=0;
render->fd_drm = open("/dev/dri/card0", O_RDWR);
if (render->fd_drm < 0) {
fprintf(stderr, "FindDevice: cannot open /dev/dri/card0: %m\n");
return -errno;
}
version = drmGetVersion(render->fd_drm);
fprintf(stderr, "FindDevice: open /dev/dri/card0: %i %s\n", version->name_len, version->name);
// check capability
if (drmGetCap(render->fd_drm, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || has_dumb == 0)
fprintf(stderr, "FindDevice: drmGetCap DRM_CAP_DUMB_BUFFER failed or doesn't have dumb buffer\n");
if (drmSetClientCap(render->fd_drm, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) != 0)
fprintf(stderr, "FindDevice: DRM_CLIENT_CAP_UNIVERSAL_PLANES not available.\n");
if (drmSetClientCap(render->fd_drm, DRM_CLIENT_CAP_ATOMIC, 1) != 0)
fprintf(stderr, "FindDevice: DRM_CLIENT_CAP_ATOMIC not available.\n");
if (drmGetCap(render->fd_drm, DRM_CAP_PRIME, &has_prime) < 0)
fprintf(stderr, "FindDevice: DRM_CAP_PRIME not available.\n");
if (drmGetCap(render->fd_drm, DRM_PRIME_CAP_EXPORT, &has_prime) < 0)
fprintf(stderr, "FindDevice: DRM_PRIME_CAP_EXPORT not available.\n");
if (drmGetCap(render->fd_drm, DRM_PRIME_CAP_IMPORT, &has_prime) < 0)
fprintf(stderr, "FindDevice: DRM_PRIME_CAP_IMPORT not available.\n");
if ((resources = drmModeGetResources(render->fd_drm)) == NULL){
fprintf(stderr, "FindDevice: cannot retrieve DRM resources (%d): %m\n", errno);
return -errno;
}
#ifdef DEBUG
Debug(3,"[FindDevice] DRM have %i connectors, %i crtcs, %i encoders\n",
resources->count_connectors, resources->count_crtcs,
resources->count_encoders);
#endif
// find all available connectors
for (i = 0; i < resources->count_connectors; i++) {
connector = drmModeGetConnector(render->fd_drm, resources->connectors[i]);
if (!connector) {
fprintf(stderr, "FindDevice: cannot retrieve DRM connector (%d): %m\n", errno);
return -errno;
}
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
render->connector_id = connector->connector_id;
// FIXME: use default encoder/crtc pair
if ((encoder = drmModeGetEncoder(render->fd_drm, connector->encoder_id)) == NULL){
fprintf(stderr, "FindDevice: cannot retrieve encoder (%d): %m\n", errno);
return -errno;
}
render->crtc_id = encoder->crtc_id;
render->hdr_metadata = GetPropertyID(render->fd_drm, connector->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "HDR_OUTPUT_METADATA");
printf("ID %d of METADATA in Connector %d connected %d\n",render->hdr_metadata,connector->connector_id,connector->connection);
memcpy(&render->mode, &connector->modes[0], sizeof(drmModeModeInfo)); // set fallback
// search Modes for Connector
for (ii = 0; ii < connector->count_modes; ii++) {
mode = &connector->modes[ii];
printf("Mode %d %dx%d Rate %d\n",ii,mode->hdisplay,mode->vdisplay,mode->vrefresh);
if (VideoWindowWidth && VideoWindowHeight) { // preset by command line
if (VideoWindowWidth == mode->hdisplay &&
VideoWindowHeight == mode->vdisplay &&
mode->vrefresh == 50 &&
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
break;
}
}
else {
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
VideoWindowWidth = mode->hdisplay;
VideoWindowHeight = mode->vdisplay;
break;
}
}
}
i = resources->count_connectors; // uuuuhh
}
VideoWindowWidth = render->mode.hdisplay;
VideoWindowHeight = render->mode.vdisplay;
printf("Use Mode %d %dx%d Rate %d\n",ii,render->mode.hdisplay,render->mode.vdisplay,render->mode.vrefresh);
drmModeFreeConnector(connector);
}
// find first plane
if ((plane_res = drmModeGetPlaneResources(render->fd_drm)) == NULL)
fprintf(stderr, "FindDevice: cannot retrieve PlaneResources (%d): %m\n", errno);
for (j = 0; j < plane_res->count_planes; j++) {
plane = drmModeGetPlane(render->fd_drm, plane_res->planes[j]);
if (plane == NULL)
fprintf(stderr, "FindDevice: cannot query DRM-KMS plane %d\n", j);
for (i = 0; i < resources->count_crtcs; i++) {
if (plane->possible_crtcs & (1 << i))
break;
}
uint64_t type = GetPropertyValue(render->fd_drm, plane_res->planes[j],
DRM_MODE_OBJECT_PLANE, "type");
uint64_t zpos = 0;
#ifdef DRM_DEBUG // If more then 2 crtcs this must rewriten!!!
printf("[FindDevice] Plane id %i crtc_id %i possible_crtcs %i possible CRTC %i type %s\n",
plane->plane_id, plane->crtc_id, plane->possible_crtcs, resources->crtcs[i],
(type == DRM_PLANE_TYPE_PRIMARY) ? "primary plane" :
(type == DRM_PLANE_TYPE_OVERLAY) ? "overlay plane" :
(type == DRM_PLANE_TYPE_CURSOR) ? "cursor plane" : "No plane type");
#endif
// test pixel format and plane caps
for (k = 0; k < plane->count_formats; k++) {
if (encoder->possible_crtcs & plane->possible_crtcs) {
switch (plane->formats[k]) {
case DRM_FORMAT_XRGB2101010:
if (!render->video_plane) {
render->video_plane = plane->plane_id;
}
break;
default:
break;
}
}
}
drmModeFreePlane(plane);
}
drmModeFreePlaneResources(plane_res);
drmModeFreeEncoder(encoder);
drmModeFreeResources(resources);
#ifdef DRM_DEBUG
printf("[FindDevice] DRM setup CRTC: %i video_plane: %i \n",
render->crtc_id, render->video_plane);
#endif
// save actual modesetting
render->saved_crtc = drmModeGetCrtc(render->fd_drm, render->crtc_id);
return 0;
}
///
/// Initialize video output module.
///
void VideoInitDrm()
{
int i;
if (!(render = calloc(1, sizeof(*render)))) {
Error(_("video/DRM: out of memory\n"));
return;
}
if (FindDevice(render)){
fprintf(stderr, "VideoInit: FindDevice() failed\n");
}
gbm.dev = gbm_create_device (render->fd_drm);
assert (gbm.dev != NULL);
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
get_platform_display =
(void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
assert(get_platform_display != NULL);
eglDisplay = get_platform_display(EGL_PLATFORM_GBM_KHR, gbm.dev, NULL);
assert (eglDisplay != NULL);
// return;
drmModeAtomicReqPtr ModeReq;
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
uint32_t modeID = 0;
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
fprintf(stderr, "Failed to create mode property.\n");
return;
}
if (!(ModeReq = drmModeAtomicAlloc())) {
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
return;
}
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", render->crtc_id);
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
drmModeAtomicFree(ModeReq);
}
struct gbm_bo *bo = NULL, *next_bo=NULL;
struct drm_fb *fb;
static int m_need_modeset = 0;
static int old_color=-1,old_trc=-1;
void InitBo(int bpp) {
// create the GBM and EGL surface
render->bpp = bpp;
gbm.surface = gbm_surface_create (gbm.dev, VideoWindowWidth,VideoWindowHeight,
bpp==10?GBM_FORMAT_XRGB2101010:GBM_FORMAT_ARGB8888,
GBM_BO_USE_SCANOUT|GBM_BO_USE_RENDERING);
assert(gbm.surface != NULL);
eglSurface = eglCreateWindowSurface (eglDisplay, eglConfig, gbm.surface, NULL);
assert(eglSurface != NULL);
}
static struct gbm_bo *previous_bo = NULL;
static uint32_t previous_fb;
static void drm_swap_buffers () {
uint32_t fb;
eglSwapBuffers (eglDisplay, eglSurface);
struct gbm_bo *bo = gbm_surface_lock_front_buffer (gbm.surface);
#if 1
if (bo == NULL)
bo = gbm_surface_lock_front_buffer (gbm.surface);
#endif
assert (bo != NULL);
uint32_t handle = gbm_bo_get_handle (bo).u32;
uint32_t pitch = gbm_bo_get_stride (bo);
drmModeAddFB (render->fd_drm, VideoWindowWidth,VideoWindowHeight,render->bpp==10? 30:24, 32, pitch, handle, &fb);
// drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
if (m_need_modeset) {
drmModeAtomicReqPtr ModeReq;
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
uint32_t modeID = 0;
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
fprintf(stderr, "Failed to create mode property.\n");
return;
}
if (!(ModeReq = drmModeAtomicAlloc())) {
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
return;
}
// Need to disable the CRTC in order to submit the HDR data....
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
sleep(2);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "Colorspace",old_color==AVCOL_PRI_BT2020?9:2 );
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", render->crtc_id);
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
drmModeAtomicFree(ModeReq);
m_need_modeset = 0;
}
drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
if (previous_bo) {
drmModeRmFB (render->fd_drm, previous_fb);
gbm_surface_release_buffer (gbm.surface, previous_bo);
}
previous_bo = bo;
previous_fb = fb;
}
static void drm_clean_up () {
// set the previous crtc
drmModeSetCrtc (render->fd_drm, render->saved_crtc->crtc_id, render->saved_crtc->buffer_id,
render->saved_crtc->x, render->saved_crtc->y, &render->connector_id, 1, &render->saved_crtc->mode);
drmModeFreeCrtc (render->saved_crtc);
if (previous_bo) {
drmModeRmFB (render->fd_drm, previous_fb);
gbm_surface_release_buffer (gbm.surface, previous_bo);
}
// eglDestroySurface (display, eglSurface);
gbm_surface_destroy (gbm.surface);
// eglDestroyContext (display, context);
// eglTerminate (display);
gbm_device_destroy (gbm.dev);
close (render->fd_drm);
}

491
hdr.c Normal file
View File

@ -0,0 +1,491 @@
#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");
}

View File

@ -220,6 +220,18 @@ void main() \
} \ } \
"; ";
#endif #endif
///
/// GLX check error.
///
#define GlxCheck(void)\
{\
GLenum err;\
\
if ((err = glGetError()) != GL_NO_ERROR) {\
esyslog( "video/glx: error %s:%d %d '%s'\n",__FILE__,__LINE__, err, gluErrorString(err));\
}\
}
static cShader *Shaders[stCount]; static cShader *Shaders[stCount];
void cShader::Use(void) { void cShader::Use(void) {
@ -322,14 +334,14 @@ bool cShader::CheckCompileErrors(GLuint object, bool program) {
glGetShaderiv(object, GL_COMPILE_STATUS, &success); glGetShaderiv(object, GL_COMPILE_STATUS, &success);
if (!success) { if (!success) {
glGetShaderInfoLog(object, 1024, NULL, infoLog); glGetShaderInfoLog(object, 1024, NULL, infoLog);
esyslog("[softhddev]:SHADER: Compile-time error: Type: %d - \n%s\n", type, infoLog); esyslog("\n[softhddev]:SHADER: Compile-time error: Type: %d - \n>%s<\n", type, infoLog);
return false; return false;
} }
} else { } else {
glGetProgramiv(object, GL_LINK_STATUS, &success); glGetProgramiv(object, GL_LINK_STATUS, &success);
if (!success) { if (!success) {
glGetProgramInfoLog(object, 1024, NULL, infoLog); glGetProgramInfoLog(object, 1024, NULL, infoLog);
esyslog("[softhddev]:SHADER: Link-time error: Type: %d - \n%s\n", type, infoLog); esyslog("[softhddev]:SHADER: Link-time error: Type: %d - \n>%s<\n", type, infoLog);
return false; return false;
} }
} }
@ -398,7 +410,8 @@ void cOglGlyph::LoadTexture(FT_BitmapGlyph ftGlyph) {
} }
extern "C" void GlxInitopengl();
extern "C" void GlxDrawopengl();
/**************************************************************************************** /****************************************************************************************
* cOglFont * cOglFont
****************************************************************************************/ ****************************************************************************************/
@ -1273,8 +1286,9 @@ bool cOglCmdDrawText::Execute(void) {
esyslog("[softhddev]ERROR: could not load glyph %x", sym); esyslog("[softhddev]ERROR: could not load glyph %x", sym);
} }
if ( limitX && xGlyph + g->AdvanceX() > limitX ) if ( limitX && xGlyph + g->AdvanceX() > limitX ) {
break; break;
}
kerning = f->Kerning(g, prevSym); kerning = f->Kerning(g, prevSym);
prevSym = sym; prevSym = sym;
@ -1320,6 +1334,7 @@ cOglCmdDrawImage::cOglCmdDrawImage(cOglFb *fb, tColor *argb, GLint width, GLint
this->overlay = overlay; this->overlay = overlay;
this->scaleX = scaleX; this->scaleX = scaleX;
this->scaleY = scaleY; this->scaleY = scaleY;
} }
cOglCmdDrawImage::~cOglCmdDrawImage(void) { cOglCmdDrawImage::~cOglCmdDrawImage(void) {
@ -1328,7 +1343,10 @@ cOglCmdDrawImage::~cOglCmdDrawImage(void) {
bool cOglCmdDrawImage::Execute(void) { bool cOglCmdDrawImage::Execute(void) {
GLuint texture; GLuint texture;
#ifdef USE_DRM
GlxDrawopengl(); // here we need the Shared Context for upload
GlxCheck();
#endif
glGenTextures(1, &texture); glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D( glTexImage2D(
@ -1347,7 +1365,10 @@ bool cOglCmdDrawImage::Execute(void) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
#ifdef USE_DRM
GlxInitopengl(); // Reset Context
GlxCheck();
#endif
GLfloat x1 = x; //left GLfloat x1 = x; //left
GLfloat y1 = y; //top GLfloat y1 = y; //top
@ -1479,6 +1500,7 @@ bool cOglCmdDropImage::Execute(void) {
cOglThread::cOglThread(cCondWait *startWait, int maxCacheSize) : cThread("oglThread") { cOglThread::cOglThread(cCondWait *startWait, int maxCacheSize) : cThread("oglThread") {
stalled = false; stalled = false;
memCached = 0; memCached = 0;
this->maxCacheSize = maxCacheSize * 1024 * 1024; this->maxCacheSize = maxCacheSize * 1024 * 1024;
this->startWait = startWait; this->startWait = startWait;
wait = new cCondWait(); wait = new cCondWait();
@ -1491,6 +1513,7 @@ cOglThread::cOglThread(cCondWait *startWait, int maxCacheSize) : cThread("oglThr
} }
Start(); Start();
} }
cOglThread::~cOglThread() { cOglThread::~cOglThread() {
@ -1689,13 +1712,12 @@ void cOglThread::Action(void) {
dsyslog("[softhddev]OpenGL Worker Thread Ended"); dsyslog("[softhddev]OpenGL Worker Thread Ended");
} }
extern "C" int GlxInitopengl();
bool cOglThread::InitOpenGL(void) { bool cOglThread::InitOpenGL(void) {
#ifdef USE_DRM
GlxInitopengl();
#else
const char *displayName = X11DisplayName; const char *displayName = X11DisplayName;
if (!displayName) { if (!displayName) {
displayName = getenv("DISPLAY"); displayName = getenv("DISPLAY");
@ -1728,6 +1750,7 @@ bool cOglThread::InitOpenGL(void) {
esyslog("[softhddev]glewInit failed, aborting\n"); esyslog("[softhddev]glewInit failed, aborting\n");
return false; return false;
} }
#endif
VertexBuffers[vbText]->EnableBlending(); VertexBuffers[vbText]->EnableBlending();
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -1790,8 +1813,9 @@ void cOglThread::Cleanup(void) {
DeleteShaders(); DeleteShaders();
// glVDPAUFiniNV(); // glVDPAUFiniNV();
cOglFont::Cleanup(); cOglFont::Cleanup();
#ifndef USE_DRM
glutExit(); glutExit();
#endif
pthread_mutex_unlock(&OSDMutex); pthread_mutex_unlock(&OSDMutex);
} }

View File

@ -61,7 +61,7 @@ extern "C"
/// vdr-plugin version number. /// vdr-plugin version number.
/// Makefile extracts the version number for generating the file name /// Makefile extracts the version number for generating the file name
/// for the distribution archive. /// for the distribution archive.
static const char *const VERSION = "2.1.0" static const char *const VERSION = "3.0.0"
#ifdef GIT_REV #ifdef GIT_REV
"-GIT" GIT_REV "-GIT" GIT_REV
#endif #endif
@ -2472,11 +2472,17 @@ class cSoftHdDevice:public cDevice
return "softhdcuvid"; return "softhdcuvid";
} }
#endif #endif
#ifdef VAAPI #if defined (VAAPI) && !defined (USE_DRM)
virtual cString DeviceName(void) const virtual cString DeviceName(void) const
{ {
return "softhdvaapi"; return "softhdvaapi";
} }
#endif
#if defined (VAAPI) && defined (USE_DRM)
virtual cString DeviceName(void) const
{
return "softhddrm";
}
#endif #endif
virtual bool HasDecoder(void) const; virtual bool HasDecoder(void) const;
virtual bool CanReplay(void) const; virtual bool CanReplay(void) const;

270
video.c
View File

@ -491,7 +491,7 @@ static void GlxSetupWindow(xcb_window_t window, int width, int height, GLXContex
GLXContext OSDcontext; GLXContext OSDcontext;
#else #else
static EGLContext eglSharedContext; ///< shared gl context static EGLContext eglSharedContext; ///< shared gl context
static EGLContext eglOSDContext = NULL; ///< our gl context for the thread
static EGLContext eglContext; ///< our gl context static EGLContext eglContext; ///< our gl context
static EGLConfig eglConfig; static EGLConfig eglConfig;
static EGLDisplay eglDisplay; static EGLDisplay eglDisplay;
@ -501,6 +501,11 @@ static int eglVersion = 2;
static EGLImageKHR(EGLAPIENTRY * CreateImageKHR) (EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *); static EGLImageKHR(EGLAPIENTRY * CreateImageKHR) (EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *);
static EGLBoolean(EGLAPIENTRY * DestroyImageKHR) (EGLDisplay, EGLImageKHR); static EGLBoolean(EGLAPIENTRY * DestroyImageKHR) (EGLDisplay, EGLImageKHR);
static void (EGLAPIENTRY * EGLImageTargetTexture2DOES) (GLenum, GLeglImageOES); static void (EGLAPIENTRY * EGLImageTargetTexture2DOES) (GLenum, GLeglImageOES);
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR;
PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
#ifdef USE_VIDEO_THREAD #ifdef USE_VIDEO_THREAD
static EGLContext eglThreadContext; ///< our gl context for the thread static EGLContext eglThreadContext; ///< our gl context for the thread
@ -527,6 +532,14 @@ static void X11DPMSReenable(xcb_connection_t *);
static void X11DPMSDisable(xcb_connection_t *); static void X11DPMSDisable(xcb_connection_t *);
#endif #endif
//----------------------------------------------------------------------------
// DRM Helper Functions
//----------------------------------------------------------------------------
#ifdef USE_DRM
#include "drm.c"
#include "hdr.c"
#endif
/// ///
/// Update video pts. /// Update video pts.
/// ///
@ -611,6 +624,7 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width, in
input_aspect_ratio.num = 1; input_aspect_ratio.num = 1;
input_aspect_ratio.den = 1; input_aspect_ratio.den = 1;
Debug(3, "video: aspect defaults to %d:%d\n", input_aspect_ratio.num, input_aspect_ratio.den); Debug(3, "video: aspect defaults to %d:%d\n", input_aspect_ratio.num, input_aspect_ratio.den);
} }
av_reduce(&input_aspect_ratio.num, &input_aspect_ratio.den, input_width * input_aspect_ratio.num, av_reduce(&input_aspect_ratio.num, &input_aspect_ratio.den, input_width * input_aspect_ratio.num,
@ -621,10 +635,13 @@ static void VideoUpdateOutput(AVRational input_aspect_ratio, int input_width, in
input_aspect_ratio.num = 1; input_aspect_ratio.num = 1;
input_aspect_ratio.den = 1; input_aspect_ratio.den = 1;
} }
#ifdef USE_DRM
display_aspect_ratio.num = 16;VideoWindowWidth;
display_aspect_ratio.den = 9; VideoWindowHeight;
#else
display_aspect_ratio.num = VideoScreen->width_in_pixels * VideoScreen->height_in_millimeters; display_aspect_ratio.num = VideoScreen->width_in_pixels * VideoScreen->height_in_millimeters;
display_aspect_ratio.den = VideoScreen->height_in_pixels * VideoScreen->width_in_millimeters; display_aspect_ratio.den = VideoScreen->height_in_pixels * VideoScreen->width_in_millimeters;
#endif
display_aspect_ratio = av_mul_q(input_aspect_ratio, display_aspect_ratio); display_aspect_ratio = av_mul_q(input_aspect_ratio, display_aspect_ratio);
Debug(3, "video: aspect %d:%d Resolution %d\n", display_aspect_ratio.num, display_aspect_ratio.den, resolution); Debug(3, "video: aspect %d:%d Resolution %d\n", display_aspect_ratio.num, display_aspect_ratio.den, resolution);
@ -843,27 +860,7 @@ char *eglErrorString(EGLint error)
}\ }\
} }
#ifdef VAAPI
void OSD_get_shared_context()
{
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext);
EglCheck();
}
void OSD_get_context()
{
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, OSDcontext);
EglCheck();
}
void OSD_release_context()
{
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// EglCheck();
}
#endif
/// ///
/// GLX check if a GLX extension is supported. /// GLX check if a GLX extension is supported.
@ -950,7 +947,7 @@ static void GlxSetupWindow(xcb_window_t window, int width, int height, EGLContex
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
GlxCheck(); GlxCheck();
#ifdef VAAPI #ifdef VAAPI
OSD_release_context(); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
#endif #endif
} }
@ -1706,9 +1703,10 @@ static void CuvidPrintFrames(const CuvidDecoder * decoder)
int CuvidTestSurfaces() int CuvidTestSurfaces()
{ {
int i=0;
if (CuvidDecoders[0] != NULL) { if (CuvidDecoders[0] != NULL) {
if (atomic_read(&CuvidDecoders[0]->SurfacesFilled) < VIDEO_SURFACES_MAX) if (i = atomic_read(&CuvidDecoders[0]->SurfacesFilled) < VIDEO_SURFACES_MAX-1)
return 1; return i;
return 0; return 0;
} else } else
return 0; return 0;
@ -1749,13 +1747,14 @@ const int mpgl_preferred_gl_versions[] = {
0 0
}; };
static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * out_context, EGLConfig * out_config) static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * out_context, EGLConfig * out_config, int *bpp)
{ {
EGLenum api; EGLenum api;
EGLint rend, *attribs; EGLint rend, *attribs;
const char *name; const char *name;
switch (es_version) { switch (es_version) {
case 0: case 0:
api = EGL_OPENGL_API; api = EGL_OPENGL_API;
@ -1803,10 +1802,11 @@ static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * o
EGLint num_configs; EGLint num_configs;
attribs = attributes10; attribs = attributes10;
*bpp = 10;
if (!eglChooseConfig(display, attributes10, NULL, 0, &num_configs)) { // try 10 Bit if (!eglChooseConfig(display, attributes10, NULL, 0, &num_configs)) { // try 10 Bit
Debug(3, " 10 Bit egl Failed\n"); Debug(3, " 10 Bit egl Failed\n");
attribs = attributes8; attribs = attributes8;
*bpp = 8;
if (!eglChooseConfig(display, attributes8, NULL, 0, &num_configs)) { // try 8 Bit if (!eglChooseConfig(display, attributes8, NULL, 0, &num_configs)) { // try 8 Bit
num_configs = 0; num_configs = 0;
} }
@ -1814,6 +1814,7 @@ static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * o
EglCheck(); EglCheck();
Debug(3, " 10 Bit egl Failed\n"); Debug(3, " 10 Bit egl Failed\n");
attribs = attributes8; attribs = attributes8;
*bpp = 8;
if (!eglChooseConfig(display, attributes8, NULL, 0, &num_configs)) { // try 8 Bit if (!eglChooseConfig(display, attributes8, NULL, 0, &num_configs)) { // try 8 Bit
num_configs = 0; num_configs = 0;
} }
@ -1873,34 +1874,41 @@ static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * o
make_egl() make_egl()
{ {
int bpp;
CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR");
DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR");
EGLImageTargetTexture2DOES = (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); EGLImageTargetTexture2DOES = (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES");
eglCreateSyncKHR = (void *)eglGetProcAddress("eglCreateSyncKHR");
eglDestroySyncKHR = (void *)eglGetProcAddress("eglDestroySyncKHR");
eglWaitSyncKHR = (void *)eglGetProcAddress("eglWaitSyncKHR");
eglClientWaitSyncKHR = (void *)eglGetProcAddress("eglClientWaitSyncKHR");
eglDupNativeFenceFDANDROID = (void *)eglGetProcAddress("eglDupNativeFenceFDANDROID");
if (!CreateImageKHR || !DestroyImageKHR || !EGLImageTargetTexture2DOES) if (!CreateImageKHR || !DestroyImageKHR || !EGLImageTargetTexture2DOES || !eglCreateSyncKHR)
Fatal(_("Can't get EGL Extentions\n")); Fatal(_("Can't get EGL Extentions\n"));
#ifndef USE_DRM
eglDisplay = eglGetDisplay(XlibDisplay); eglDisplay = eglGetDisplay(XlibDisplay);
#endif
if (!eglInitialize(eglDisplay, NULL, NULL)) { if (!eglInitialize(eglDisplay, NULL, NULL)) {
Fatal(_("Could not initialize EGL.\n")); Fatal(_("Could not initialize EGL.\n"));
} }
if (!create_context_cb(eglDisplay, 0, &eglContext, &eglConfig)) { if (!create_context_cb(eglDisplay, 0, &eglContext, &eglConfig, &bpp)) {
Fatal(_("Could not create EGL Context\n")); Fatal(_("Could not create EGL Context\n"));
} }
int vID, n; int vID, n;
eglGetConfigAttrib(eglDisplay, eglConfig, EGL_NATIVE_VISUAL_ID, &vID); eglGetConfigAttrib(eglDisplay, eglConfig, EGL_NATIVE_VISUAL_ID, &vID);
Debug(3, "chose visual 0x%x\n", vID); Debug(3, "chose visual 0x%x\n", vID);
#ifdef USE_DRM
InitBo(bpp);
#else
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType) VideoWindow, NULL); eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, (EGLNativeWindowType) VideoWindow, NULL);
if (eglSurface == EGL_NO_SURFACE) { if (eglSurface == EGL_NO_SURFACE) {
Fatal(_("Could not create EGL surface!\n")); Fatal(_("Could not create EGL surface!\n"));
} }
#endif
if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
Fatal(_("Could not make context current!\n")); Fatal(_("Could not make context current!\n"));
} }
@ -2108,6 +2116,7 @@ static void CuvidExit(void)
} }
} }
CuvidDecoderN = 0; CuvidDecoderN = 0;
Debug(3, "CuvidExit\n"); Debug(3, "CuvidExit\n");
} }
@ -2223,6 +2232,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
pl->component_mapping[2] = -1; pl->component_mapping[2] = -1;
pl->component_mapping[3] = -1; pl->component_mapping[3] = -1;
} else { } else {
pl->shift_x = -0.5f; // PL_CHROMA_LEFT
pl->component_mapping[0] = PL_CHANNEL_U; pl->component_mapping[0] = PL_CHANNEL_U;
pl->component_mapping[1] = PL_CHANNEL_V; pl->component_mapping[1] = PL_CHANNEL_V;
pl->component_mapping[2] = -1; pl->component_mapping[2] = -1;
@ -2347,7 +2357,7 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
} }
#endif #endif
#else #else // no PLACEBO
void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsigned int size_y, void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsigned int size_y,
enum AVPixelFormat PixFmt) enum AVPixelFormat PixFmt)
@ -2362,7 +2372,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
glXMakeCurrent(XlibDisplay, VideoWindow, glxSharedContext); glXMakeCurrent(XlibDisplay, VideoWindow, glxSharedContext);
GlxCheck(); GlxCheck();
#else #else
OSD_get_shared_context(); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext);
#endif #endif
glGenBuffers(1, &vao_buffer); glGenBuffers(1, &vao_buffer);
@ -2402,7 +2412,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
GlxCheck(); GlxCheck();
#ifdef VAAPI #ifdef VAAPI
OSD_release_context(); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
#endif #endif
} }
@ -2442,10 +2452,10 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
return; return;
} }
vaSyncSurface(decoder->VaDisplay, (unsigned int)frame->data[3]); vaSyncSurface(decoder->VaDisplay, (unsigned int)frame->data[3]);
//#ifndef USE_DRM
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext);
EglCheck(); EglCheck();
//#endif
for (int n = 0; n < 2; n++) { for (int n = 0; n < 2; n++) {
int attribs[20] = { EGL_NONE }; int attribs[20] = { EGL_NONE };
int num_attribs = 0; int num_attribs = 0;
@ -2456,7 +2466,7 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
ADD_PLANE_ATTRIBS(0); ADD_PLANE_ATTRIBS(0);
decoder->images[index * 2 + n] = decoder->images[index * 2 + n] =
CreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); CreateImageKHR(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
if (!decoder->images[index * 2 + n]) if (!decoder->images[index * 2 + n])
goto esh_failed; goto esh_failed;
@ -2519,6 +2529,7 @@ static void CuvidSyncRenderFrame(CuvidDecoder * decoder, const AVCodecContext *
int push_filters(AVCodecContext * dec_ctx, CuvidDecoder * decoder, AVFrame * frame) int push_filters(AVCodecContext * dec_ctx, CuvidDecoder * decoder, AVFrame * frame)
{ {
int ret, i = 0; int ret, i = 0;
AVFrame *filt_frame = av_frame_alloc(); AVFrame *filt_frame = av_frame_alloc();
@ -2744,8 +2755,7 @@ static enum AVPixelFormat Cuvid_get_format(CuvidDecoder * decoder, AVCodecContex
CuvidSetupOutput(decoder); CuvidSetupOutput(decoder);
#ifdef PLACEBO #ifdef PLACEBO
VideoThreadUnlock(); VideoThreadUnlock();
#endif // dont show first frame
#ifdef PLACEBO // dont show first frame
decoder->newchannel = 1; decoder->newchannel = 1;
#endif #endif
#ifdef YADIF #ifdef YADIF
@ -3390,6 +3400,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
struct pl_color_adjustment colors; struct pl_color_adjustment colors;
struct pl_cone_params cone; struct pl_cone_params cone;
struct pl_tex_vk *vkp; struct pl_tex_vk *vkp;
struct pl_plane *pl;
const struct pl_fmt *fmt; const struct pl_fmt *fmt;
VkImage Image; VkImage Image;
struct pl_image *img; struct pl_image *img;
@ -3404,6 +3415,8 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
int y; int y;
float xcropf, ycropf; float xcropf, ycropf;
GLint texLoc; GLint texLoc;
AVFrame *frame;
AVFrameSideData *FrameSideData = NULL;
#ifdef PLACEBO #ifdef PLACEBO
if (level) { if (level) {
@ -3433,9 +3446,14 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
ycropf = (float)decoder->CropY / (float)decoder->InputHeight; ycropf = (float)decoder->CropY / (float)decoder->InputHeight;
current = decoder->SurfacesRb[decoder->SurfaceRead]; current = decoder->SurfacesRb[decoder->SurfaceRead];
if (!decoder->Closing) { if (!decoder->Closing) {
VideoSetPts(&decoder->PTS, decoder->Interlaced, 0, decoder->frames[current]); frame = decoder->frames[current];
VideoSetPts(&decoder->PTS, decoder->Interlaced, 0, frame);
#ifdef USE_DRM
AVFrameSideData *sd1 = av_frame_get_side_data (frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
AVFrameSideData *sd2 = av_frame_get_side_data (frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
set_hdr_metadata(frame->color_primaries,frame->color_trc,sd1,sd2);
#endif
} }
// Render Progressive frame // Render Progressive frame
@ -3466,6 +3484,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
#else #else
img = &decoder->pl_images[current]; img = &decoder->pl_images[current];
pl = &decoder->pl_images[current].planes[1];
memcpy(&deband, &pl_deband_default_params, sizeof(deband)); memcpy(&deband, &pl_deband_default_params, sizeof(deband));
memcpy(&render_params, &pl_render_default_params, sizeof(render_params)); memcpy(&render_params, &pl_render_default_params, sizeof(render_params));
@ -3476,6 +3495,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
img->color.primaries = PL_COLOR_PRIM_BT_601_625; img->color.primaries = PL_COLOR_PRIM_BT_601_625;
img->color.transfer = PL_COLOR_TRC_BT_1886; img->color.transfer = PL_COLOR_TRC_BT_1886;
img->color.light = PL_COLOR_LIGHT_DISPLAY; img->color.light = PL_COLOR_LIGHT_DISPLAY;
pl->shift_x = 0.0f;
break; break;
case AVCOL_SPC_BT709: case AVCOL_SPC_BT709:
case AVCOL_SPC_UNSPECIFIED: // comes with UHD case AVCOL_SPC_UNSPECIFIED: // comes with UHD
@ -3485,6 +3505,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
// img->color.transfer = PL_COLOR_TRC_BT_1886; // img->color.transfer = PL_COLOR_TRC_BT_1886;
// img->color.light = PL_COLOR_LIGHT_SCENE_709_1886; // img->color.light = PL_COLOR_LIGHT_SCENE_709_1886;
// img->color.light = PL_COLOR_LIGHT_DISPLAY; // img->color.light = PL_COLOR_LIGHT_DISPLAY;
pl->shift_x = -0.5f;
break; break;
case AVCOL_SPC_BT2020_NCL: case AVCOL_SPC_BT2020_NCL:
@ -3492,7 +3513,8 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
memcpy(&img->repr, &pl_color_repr_uhdtv, sizeof(struct pl_color_repr)); memcpy(&img->repr, &pl_color_repr_uhdtv, sizeof(struct pl_color_repr));
memcpy(&img->color, &pl_color_space_bt2020_hlg, sizeof(struct pl_color_space)); memcpy(&img->color, &pl_color_space_bt2020_hlg, sizeof(struct pl_color_space));
deband.grain = 0.0f; // no grain in HDR deband.grain = 0.0f; // no grain in HDR
img->color.sig_scale = 2.0f; img->color.sig_scale = 1.0f;
pl->shift_x = -0.5f;
#ifdef VAAPI #ifdef VAAPI
render_params.peak_detect_params = NULL; render_params.peak_detect_params = NULL;
#endif #endif
@ -3507,6 +3529,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
// img->color.primaries = PL_COLOR_PRIM_BT_709; // img->color.primaries = PL_COLOR_PRIM_BT_709;
// img->color.transfer = PL_COLOR_TRC_BT_1886; // img->color.transfer = PL_COLOR_TRC_BT_1886;
// img->color.light = PL_COLOR_LIGHT_DISPLAY; // img->color.light = PL_COLOR_LIGHT_DISPLAY;
pl->shift_x = -0.5f;
break; break;
} }
// Source crop // Source crop
@ -3696,6 +3719,8 @@ static void CuvidDisplayFrame(void)
int RTS_flag; int RTS_flag;
int valid_frame = 0; int valid_frame = 0;
float ldiff; float ldiff;
static int first = 1;
float turnaround;
#ifdef PLACEBO #ifdef PLACEBO
uint64_t diff; uint64_t diff;
@ -3703,13 +3728,14 @@ static void CuvidDisplayFrame(void)
struct pl_swapchain_frame frame; struct pl_swapchain_frame frame;
struct pl_render_target target; struct pl_render_target target;
bool ok; bool ok;
static int first = 1;
VkImage Image; VkImage Image;
const struct pl_fmt *fmt; const struct pl_fmt *fmt;
const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; const float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
#endif #endif
#ifndef PLACEBO #ifndef PLACEBO
if (CuvidDecoderN) if (CuvidDecoderN)
CuvidDecoders[0]->Frameproc = (float)(GetusTicks() - last_time) / 1000000.0; CuvidDecoders[0]->Frameproc = (float)(GetusTicks() - last_time) / 1000000.0;
@ -3723,7 +3749,7 @@ static void CuvidDisplayFrame(void)
#endif #endif
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
#else #else // PLACEBO
if (CuvidDecoderN) { if (CuvidDecoderN) {
ldiff = (float)(GetusTicks() - round_time) / 1000000.0; ldiff = (float)(GetusTicks() - round_time) / 1000000.0;
@ -3826,7 +3852,7 @@ static void CuvidDisplayFrame(void)
decoder->StartCounter++; decoder->StartCounter++;
filled = atomic_read(&decoder->SurfacesFilled); filled = atomic_read(&decoder->SurfacesFilled);
//printf("Filled %d\n",filled);
// need 1 frame for progressive, 3 frames for interlaced // need 1 frame for progressive, 3 frames for interlaced
if (filled < 1 + 2 * decoder->Interlaced) { if (filled < 1 + 2 * decoder->Interlaced) {
// FIXME: rewrite MixVideo to support less surfaces // FIXME: rewrite MixVideo to support less surfaces
@ -3882,6 +3908,8 @@ static void CuvidDisplayFrame(void)
int x, y, w, h; int x, y, w, h;
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
GlxCheck();
if (OsdShown == 1) { if (OsdShown == 1) {
if (OSDtexture) if (OSDtexture)
glDeleteTextures(1, &OSDtexture); glDeleteTextures(1, &OSDtexture);
@ -3889,15 +3917,19 @@ static void CuvidDisplayFrame(void)
glGenTextures(1, &OSDtexture); glGenTextures(1, &OSDtexture);
glBindTexture(GL_TEXTURE_2D, OSDtexture); glBindTexture(GL_TEXTURE_2D, OSDtexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, OSDxsize, OSDysize, 0, GL_RGBA, GL_UNSIGNED_BYTE, posd); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, OSDxsize, OSDysize, 0, GL_RGBA, GL_UNSIGNED_BYTE, posd);
GlxCheck();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GlxCheck();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glFlush(); glFlush();
pthread_mutex_unlock(&OSDMutex); pthread_mutex_unlock(&OSDMutex);
OsdShown = 2; OsdShown = 2;
} }
GlxCheck();
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
GlxCheck();
glEnable(GL_BLEND); glEnable(GL_BLEND);
GlxCheck(); GlxCheck();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -3925,6 +3957,7 @@ static void CuvidDisplayFrame(void)
glUseProgram(0); glUseProgram(0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglThreadContext);
} }
#endif #endif
@ -3938,14 +3971,18 @@ static void CuvidDisplayFrame(void)
#endif #endif
VideoThreadUnlock(); VideoThreadUnlock();
#else #else // not PLACEBO
#ifdef CUVID #ifdef CUVID
glXGetVideoSyncSGI(&Count); // get current frame glXGetVideoSyncSGI(&Count); // get current frame
glXSwapBuffers(XlibDisplay, VideoWindow); glXSwapBuffers(XlibDisplay, VideoWindow);
glXMakeCurrent(XlibDisplay, None, NULL); glXMakeCurrent(XlibDisplay, None, NULL);
#else #else
#ifndef USE_DRM
eglSwapBuffers(eglDisplay, eglSurface); eglSwapBuffers(eglDisplay, eglSurface);
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
#else
drm_swap_buffers();
#endif
#endif #endif
#endif #endif
@ -4326,9 +4363,7 @@ static void CuvidDisplayHandlerThread(void)
allfull = 1; allfull = 1;
decoded = 0; decoded = 0;
#ifndef PLACEBO
VideoThreadLock();
#endif
for (i = 0; i < CuvidDecoderN; ++i) { for (i = 0; i < CuvidDecoderN; ++i) {
decoder = CuvidDecoders[i]; decoder = CuvidDecoders[i];
@ -4343,9 +4378,9 @@ static void CuvidDisplayHandlerThread(void)
allfull = 0; allfull = 0;
err = VideoDecodeInput(decoder->Stream); err = VideoDecodeInput(decoder->Stream);
} else { } else {
#ifdef PLACEBO
usleep(1000); usleep(1000);
#endif
err = VideoPollInput(decoder->Stream); err = VideoPollInput(decoder->Stream);
} }
// decoder can be invalid here // decoder can be invalid here
@ -4358,26 +4393,24 @@ static void CuvidDisplayHandlerThread(void)
decoder->Closing = -1; decoder->Closing = -1;
} }
} }
#ifdef PLACEBO
usleep(1000); usleep(1000);
#endif
continue; continue;
} }
decoded = 1; decoded = 1;
} }
#ifndef PLACEBO
VideoThreadUnlock();
#endif
if (!decoded) { // nothing decoded, sleep if (!decoded) { // nothing decoded, sleep
// FIXME: sleep on wakeup // FIXME: sleep on wakeup
usleep(1 * 1000); usleep(1 * 1000);
} }
#ifdef PLACEBO
usleep(1000); usleep(1000);
#endif
// all decoder buffers are full // all decoder buffers are full
// and display is not preempted // and display is not preempted
@ -4390,11 +4423,6 @@ static void CuvidDisplayHandlerThread(void)
return; return;
} }
} }
#ifndef PLACEBO
VideoThreadLock();
CuvidSyncDisplayFrame();
VideoThreadUnlock();
#endif
return; return;
} }
@ -5103,15 +5131,15 @@ static void *VideoDisplayHandlerThread(void *dummy)
glxThreadContext = glXCreateContext(XlibDisplay, GlxVisualInfo, glxSharedContext, GL_TRUE); glxThreadContext = glXCreateContext(XlibDisplay, GlxVisualInfo, glxSharedContext, GL_TRUE);
GlxSetupWindow(VideoWindow, VideoWindowWidth, VideoWindowHeight, glxThreadContext); GlxSetupWindow(VideoWindow, VideoWindowWidth, VideoWindowHeight, glxThreadContext);
#else #else
#if 0
eglThreadContext = eglCreateContext(eglDisplay, eglConfig, eglSharedContext, contextAttrs); eglThreadContext = eglCreateContext(eglDisplay, eglConfig, eglSharedContext, contextAttrs);
if (!eglThreadContext) { if (!eglThreadContext) {
EglCheck(); EglCheck();
Fatal(_("video/egl: can't create thread egl context\n")); Fatal(_("video/egl: can't create thread egl context\n"));
return NULL; return NULL;
} }
#endif #endif
#endif
} }
sleep(2); sleep(2);
for (;;) { for (;;) {
@ -5119,26 +5147,34 @@ static void *VideoDisplayHandlerThread(void *dummy)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel(); pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
#ifndef PLACEBO
VideoPollEvent();
#endif
VideoUsedModule->DisplayHandlerThread(); VideoUsedModule->DisplayHandlerThread();
} }
return dummy; return dummy;
} }
#ifdef PLACEBO
static void *VideoHandlerThread(void *dummy) static void *VideoHandlerThread(void *dummy)
{ {
EGLint contextAttrs[] = {
uint64_t first_time; EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
prctl(PR_SET_NAME, "cuvid video display", 0, 0, 0); prctl(PR_SET_NAME, "cuvid video display", 0, 0, 0);
#ifdef PLACEBO
InitPlacebo(); InitPlacebo();
pthread_cleanup_push(delete_placebo, NULL); pthread_cleanup_push(delete_placebo, NULL);
#else
eglThreadContext = eglCreateContext(eglDisplay, eglConfig, eglSharedContext, contextAttrs);
if (!eglThreadContext) {
EglCheck();
Fatal(_("video/egl: can't create thread egl context\n"));
return NULL;
}
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglThreadContext);
#endif
for (;;) { for (;;) {
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
@ -5149,15 +5185,14 @@ static void *VideoHandlerThread(void *dummy)
// first_time = GetusTicks(); // first_time = GetusTicks();
CuvidSyncDisplayFrame(); CuvidSyncDisplayFrame();
// printf("syncdisplayframe exec %d\n",(GetusTicks()-first_time)/1000); // printf("syncdisplayframe exec %d\n",(GetusTicks()-first_time)/1000);
} }
#ifdef PLACEBO
pthread_cleanup_pop(NULL); pthread_cleanup_pop(NULL);
#endif
return dummy; return dummy;
} }
#endif
/// ///
/// Initialize video threads. /// Initialize video threads.
/// ///
@ -5176,12 +5211,9 @@ static void VideoThreadInit(void)
pthread_mutex_init(&OSDMutex, NULL); pthread_mutex_init(&OSDMutex, NULL);
pthread_cond_init(&VideoWakeupCond, NULL); pthread_cond_init(&VideoWakeupCond, NULL);
pthread_create(&VideoThread, NULL, VideoDisplayHandlerThread, NULL); pthread_create(&VideoThread, NULL, VideoDisplayHandlerThread, NULL);
#ifdef PLACEBO
pthread_create(&VideoDisplayThread, NULL, VideoHandlerThread, NULL);
#else
VideoDisplayThread = 0; pthread_create(&VideoDisplayThread, NULL, VideoHandlerThread, NULL);
#endif
} }
/// ///
@ -5241,9 +5273,11 @@ static void VideoThreadExit(void)
/// ///
void VideoDisplayWakeup(void) void VideoDisplayWakeup(void)
{ {
#ifndef USE_DRM
if (!XlibDisplay) { // not yet started if (!XlibDisplay) { // not yet started
return; return;
} }
#endif
if (!VideoThread) { // start video thread, if needed if (!VideoThread) { // start video thread, if needed
VideoThreadInit(); VideoThreadInit();
@ -6444,6 +6478,10 @@ void VideoInit(const char *display_name)
xcb_screen_iterator_t screen_iter; xcb_screen_iterator_t screen_iter;
xcb_screen_t const *screen; xcb_screen_t const *screen;
#ifdef USE_DRM
VideoInitDrm();
#else
if (XlibDisplay) { // allow multiple calls if (XlibDisplay) { // allow multiple calls
Debug(3, "video: x11 already setup\n"); Debug(3, "video: x11 already setup\n");
return; return;
@ -6526,7 +6564,7 @@ void VideoInit(const char *display_name)
VideoCreateWindow(screen->root, screen->root_visual, screen->root_depth); VideoCreateWindow(screen->root, screen->root_visual, screen->root_depth);
Debug(3, "video: window prepared\n"); Debug(3, "video: window prepared\n");
#endif
// //
// prepare hardware decoder // prepare hardware decoder
// //
@ -6545,6 +6583,8 @@ void VideoInit(const char *display_name)
VideoUsedModule = &NoopModule; VideoUsedModule = &NoopModule;
found: found:
;
#ifndef USE_DRM
// FIXME: make it configurable from gui // FIXME: make it configurable from gui
if (getenv("NO_MPEG_HW")) { if (getenv("NO_MPEG_HW")) {
VideoHardwareDecoder = 1; VideoHardwareDecoder = 1;
@ -6558,7 +6598,7 @@ void VideoInit(const char *display_name)
//xcb_prefetch_maximum_request_length(Connection); //xcb_prefetch_maximum_request_length(Connection);
xcb_flush(Connection); xcb_flush(Connection);
#endif
#ifdef PLACEBO_ #ifdef PLACEBO_
InitPlacebo(); InitPlacebo();
#endif #endif
@ -6570,6 +6610,7 @@ void VideoInit(const char *display_name)
/// ///
void VideoExit(void) void VideoExit(void)
{ {
#ifndef USE_DRM
if (!XlibDisplay) { // no init or failed if (!XlibDisplay) { // no init or failed
return; return;
} }
@ -6578,7 +6619,7 @@ void VideoExit(void)
// //
X11DPMSReenable(Connection); X11DPMSReenable(Connection);
X11SuspendScreenSaver(Connection, 0); X11SuspendScreenSaver(Connection, 0);
#endif
VideoUsedModule->Exit(); VideoUsedModule->Exit();
VideoUsedModule = &NoopModule; VideoUsedModule = &NoopModule;
@ -6591,7 +6632,7 @@ void VideoExit(void)
EglExit(); // delete all contexts EglExit(); // delete all contexts
} }
#endif #endif
#ifndef USE_DRM
// //
// FIXME: cleanup. // FIXME: cleanup.
// //
@ -6624,43 +6665,34 @@ void VideoExit(void)
XlibDisplay = NULL; XlibDisplay = NULL;
Connection = 0; Connection = 0;
} }
#endif
#ifdef USE_DRM
drm_clean_up();
#endif
} }
int GlxInitopengl() #ifdef USE_DRM
{ int GlxInitopengl () {
#ifndef PLACEBO
#ifdef VAAPI
EGLint contextAttrs[] = { EGLint contextAttrs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE EGL_NONE
}; };
while (eglSharedContext == NULL || eglContext == NULL) { if (!eglOSDContext) {
sleep(1); // wait until Init from video thread is ready eglOSDContext = eglCreateContext(eglDisplay, eglConfig, eglSharedContext, contextAttrs);
if (!eglOSDContext) {
EglCheck();
Fatal(_("video/egl: can't create thread egl context\n"));
return NULL;
} }
#endif
#ifdef CUVID
while (glxSharedContext == NULL || glxContext == NULL) {
sleep(1); // wait until Init from video thread is ready
} }
OSDcontext = glXCreateContext(XlibDisplay, GlxVisualInfo, glxSharedContext, GL_TRUE); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglOSDContext);
#else return;
OSDcontext = eglCreateContext(eglDisplay, eglConfig, eglSharedContext, contextAttrs); }
#endif
if (!OSDcontext) { int GlxDrawopengl () {
Debug(3, "video/osd: can't create OSD egl context\n"); eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglSharedContext);
return 0; return;
} }
Debug(3, "Create OSD egl context\n");
#ifdef VAAPI
// eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, OSDcontext);
// EglCheck();
#else
glXMakeCurrent(XlibDisplay, VideoWindow, OSDcontext);
GlxCheck();
#endif #endif
#endif
return 1;
}