2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @file video.c @brief Video module
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// Copyright (c) 2009 - 2015 by Johns. All Rights Reserved.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Contributor(s):
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// License: AGPLv3
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
/// published by the Free Software Foundation, either version 3 of the
/// License.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/// GNU Affero General Public License for more details.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// $Id: bacf89f24503be74d113a83139a277ff2290014a $
2018-08-19 11:45:46 +02:00
//////////////////////////////////////////////////////////////////////////////
///
2019-10-26 18:42:19 +02:00
/// @defgroup Video The video module.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// This module contains all video rendering functions.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @todo disable screen saver support
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Uses Xlib where it is needed for VA-API or cuvid. XCB is used for
/// everything else.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// - X11
/// - OpenGL rendering
/// - OpenGL rendering with GLX texture-from-pixmap
/// - Xrender rendering
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @todo FIXME: use vaErrorStr for all VA-API errors.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
# define USE_XLIB_XCB ///< use xlib/xcb backend
# define noUSE_SCREENSAVER ///< support disable screensaver
2019-04-05 07:20:52 +02:00
2021-12-27 20:02:45 +01:00
# define USE_GRAB ///< experimental grab code
// #define USE_GLX ///< outdated GLX code
# define USE_DOUBLEBUFFER ///< use GLX double buffers
# define USE_CUVID ///< enable cuvid support
// #define AV_INFO ///< log a/v sync informations
2018-08-19 11:45:46 +02:00
# ifndef AV_INFO_TIME
2021-12-27 20:02:45 +01:00
# define AV_INFO_TIME (50 * 60) ///< a/v info every minute
2018-08-19 11:45:46 +02:00
# endif
2021-12-27 20:02:45 +01:00
# define USE_VIDEO_THREAD ///< run decoder in an own thread
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
# include <stdio.h>
2018-08-19 11:45:46 +02:00
# include <sys/ipc.h>
# include <sys/prctl.h>
2021-12-27 20:02:45 +01:00
# include <sys/shm.h>
# include <sys/time.h>
2019-04-05 07:20:52 +02:00
2021-12-27 20:02:45 +01:00
# include <errno.h> /* ERROR Number Definitions */
# include <fcntl.h> /* File Control Definitions */
# include <sys/ioctl.h> /* ioctl() */
# include <termios.h> /* POSIX Terminal Control Definitions */
# include <unistd.h> /* UNIX Standard Definitions */
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
# include <math.h>
2018-08-19 11:45:46 +02:00
# include <stdbool.h>
# include <stdint.h>
2021-12-27 20:02:45 +01:00
# include <stdio.h>
# include <stdlib.h>
2018-08-19 11:45:46 +02:00
# include <string.h>
# include <unistd.h>
# include <libintl.h>
2021-12-27 20:02:45 +01:00
# define _(str) gettext(str) ///< gettext shortcut
# define _N(str) str ///< gettext_noop shortcut
2018-08-19 11:45:46 +02:00
# ifdef USE_VIDEO_THREAD
# ifndef __USE_GNU
# define __USE_GNU
# endif
# include <pthread.h>
# include <signal.h>
2021-12-27 20:02:45 +01:00
# include <time.h>
2018-08-19 11:45:46 +02:00
# ifndef HAVE_PTHREAD_NAME
2019-10-28 21:43:37 +01:00
/// only available with newer glibc
2018-08-19 11:45:46 +02:00
# define pthread_setname_np(thread, name)
# endif
# endif
# ifdef USE_XLIB_XCB
# include <X11/Xlib-xcb.h>
# include <X11/Xlib.h>
# include <X11/Xutil.h>
# include <X11/keysym.h>
# include <xcb/xcb.h>
2019-10-04 10:37:57 +02:00
2018-08-19 11:45:46 +02:00
# ifdef USE_SCREENSAVER
# include <xcb/dpms.h>
2021-12-27 20:02:45 +01:00
# include <xcb/screensaver.h>
2018-08-19 11:45:46 +02:00
# endif
2019-10-04 10:37:57 +02:00
2019-10-28 21:43:37 +01:00
// #include <xcb/shm.h>
// #include <xcb/xv.h>
2018-08-19 11:45:46 +02:00
2019-10-28 21:43:37 +01:00
// #include <xcb/xcb_image.h>
// #include <xcb/xcb_event.h>
// #include <xcb/xcb_atom.h>
2018-08-19 11:45:46 +02:00
# include <xcb/xcb_icccm.h>
# ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
# include <xcb/xcb_ewmh.h>
# else // compatibility hack for old xcb-util
/**
* @ brief Action on the _NET_WM_STATE property
*/
2021-12-27 20:02:45 +01:00
typedef enum {
2018-08-19 11:45:46 +02:00
/* Remove/unset property */
XCB_EWMH_WM_STATE_REMOVE = 0 ,
/* Add/set property */
XCB_EWMH_WM_STATE_ADD = 1 ,
2021-12-27 20:02:45 +01:00
/* Toggle property */
2018-08-19 11:45:46 +02:00
XCB_EWMH_WM_STATE_TOGGLE = 2
} xcb_ewmh_wm_state_action_t ;
# endif
# endif
# ifdef USE_GLX
2021-01-10 13:55:09 +01:00
# ifndef PLACEBO_GL
2018-08-19 11:45:46 +02:00
# include <GL/glew.h>
2021-01-10 13:55:09 +01:00
# else
# include <epoxy/egl.h>
# endif
2021-12-27 20:02:45 +01:00
// clang-format off
2018-08-19 11:45:46 +02:00
# include <GL/glu.h>
# include <GL/glut.h>
# include <GL/freeglut_ext.h>
2021-12-27 20:02:45 +01:00
// clang-format on
2018-08-19 11:45:46 +02:00
# endif
2022-01-14 10:31:55 +01:00
# include <libavcodec/avcodec.h>
2019-08-22 12:34:29 +02:00
# include <libavutil/hwcontext.h>
2021-03-16 09:40:08 +01:00
# include <libavutil/mastering_display_metadata.h>
2019-10-04 10:37:57 +02:00
# include <libavutil/pixdesc.h>
2019-08-22 12:34:29 +02:00
2018-08-19 11:45:46 +02:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
// clang-format off
2020-03-06 12:42:14 +01:00
# include <ffnvcodec/dynlink_cuda.h>
# include <ffnvcodec/dynlink_loader.h>
2018-08-19 11:45:46 +02:00
# include <libavutil/hwcontext_cuda.h>
2018-10-12 12:51:52 +02:00
# include "drvapi_error_string.h"
2021-12-27 20:02:45 +01:00
// clang-format on
2018-08-19 11:45:46 +02:00
# define __DEVICE_TYPES_H__
# endif
2019-08-22 12:34:29 +02:00
# ifdef VAAPI
2022-05-24 00:09:55 +02:00
# if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 74, 100)
2019-08-22 12:34:29 +02:00
# include <libavcodec/vaapi.h>
2022-01-14 10:31:55 +01:00
# endif
2022-05-24 00:09:55 +02:00
# include <libavutil/hwcontext_vaapi.h>
2020-08-14 12:38:27 +02:00
# include <libdrm/drm_fourcc.h>
2021-12-27 20:02:45 +01:00
# include <va/va_drmcommon.h>
# define TO_AVHW_DEVICE_CTX(x) ((AVHWDeviceContext *)x->data)
# define TO_AVHW_FRAMES_CTX(x) ((AVHWFramesContext *)x->data)
# define TO_VAAPI_DEVICE_CTX(x) ((AVVAAPIDeviceContext *)TO_AVHW_DEVICE_CTX(x)->hwctx)
# define TO_VAAPI_FRAMES_CTX(x) ((AVVAAPIFramesContext *)TO_AVHW_FRAMES_CTX(x)->hwctx)
2019-08-22 12:34:29 +02:00
# endif
2019-10-04 10:37:57 +02:00
# include <assert.h>
2019-10-28 21:43:37 +01:00
// #define EGL_EGLEXT_PROTOTYPES
2021-01-10 13:55:09 +01:00
# if !defined PLACEBO_GL
2019-10-04 10:37:57 +02:00
# include <EGL/egl.h>
# include <EGL/eglext.h>
2021-01-10 13:55:09 +01:00
# endif
2019-10-04 10:37:57 +02:00
# ifndef GL_OES_EGL_image
2019-10-26 18:42:19 +02:00
typedef void * GLeglImageOES ;
2019-10-04 10:37:57 +02:00
# endif
# ifndef EGL_KHR_image
typedef void * EGLImageKHR ;
# endif
2019-08-22 12:34:29 +02:00
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
# include <libplacebo/opengl.h>
# else
2018-11-17 14:58:25 +01:00
# define VK_USE_PLATFORM_XCB_KHR
2018-11-04 13:44:18 +01:00
# include <libplacebo/vulkan.h>
2020-05-01 12:06:04 +02:00
# endif
2021-03-16 09:40:08 +01:00
# if PL_API_VER >= 113
# include <libplacebo/shaders/lut.h>
# endif
2018-11-04 13:44:18 +01:00
# include <libplacebo/renderer.h>
# endif
2018-08-19 11:45:46 +02:00
# include <libswscale/swscale.h>
2021-12-27 20:02:45 +01:00
# if defined(YADIF) || defined(VAAPI)
2019-04-05 07:20:52 +02:00
# include <libavfilter/buffersink.h>
# include <libavfilter/buffersrc.h>
# include <libavutil/opt.h>
# endif
2021-12-27 20:02:45 +01:00
// clang-format off
# include "iatomic.h" // portable atomic_t
2018-08-19 11:45:46 +02:00
# include "misc.h"
# include "video.h"
# include "audio.h"
# include "codec.h"
2021-12-27 20:02:45 +01:00
// clang-format on
2018-08-19 11:45:46 +02:00
2019-10-22 15:21:26 +02:00
# if defined(APIVERSNUM) && APIVERSNUM < 20400
# error "VDR 2.4.0 or greater is required!"
# endif
2021-12-27 20:02:45 +01:00
# define HAS_FFMPEG_3_4_API (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 107, 100))
# define HAS_FFMPEG_4_API (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 18, 100))
2019-10-22 15:21:26 +02:00
# if !HAS_FFMPEG_3_4_API
# error "FFmpeg 3.4 or greater is required!"
# endif
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Declarations
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Video resolutions selector.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef enum _video_resolutions_ {
VideoResolution576i , ///< ...x576 interlaced
VideoResolution720p , ///< ...x720 progressive
VideoResolutionFake1080i , ///< 1280x1080 1440x1080 interlaced
VideoResolution1080i , ///< 1920x1080 interlaced
VideoResolutionUHD , /// UHD progressive
VideoResolutionMax ///< number of resolution indexs
2018-08-19 11:45:46 +02:00
} VideoResolutions ;
///
2019-10-26 18:42:19 +02:00
/// Video deinterlace modes.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef enum _video_deinterlace_modes_ {
VideoDeinterlaceCuda , ///< Cuda build in deinterlace
VideoDeinterlaceYadif , ///< Yadif deinterlace
2018-08-19 11:45:46 +02:00
} VideoDeinterlaceModes ;
///
2019-10-26 18:42:19 +02:00
/// Video scaleing modes.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef enum _video_scaling_modes_ {
VideoScalingNormal , ///< normal scaling
VideoScalingFast , ///< fastest scaling
VideoScalingHQ , ///< high quality scaling
VideoScalingAnamorphic , ///< anamorphic scaling
2018-08-19 11:45:46 +02:00
} VideoScalingModes ;
///
2019-10-26 18:42:19 +02:00
/// Video zoom modes.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef enum _video_zoom_modes_ {
VideoNormal , ///< normal
VideoStretch , ///< stretch to all edges
VideoCenterCutOut , ///< center and cut out
VideoNone , ///< no scaling
2018-08-19 11:45:46 +02:00
} VideoZoomModes ;
///
2019-10-26 18:42:19 +02:00
/// Video color space conversions.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef enum _video_color_space_ {
VideoColorSpaceNone , ///< no conversion
VideoColorSpaceBt601 , ///< ITU.BT-601 Y'CbCr
VideoColorSpaceBt709 , ///< ITU.BT-709 HDTV Y'CbCr
VideoColorSpaceSmpte240 ///< SMPTE-240M Y'PbPr
2018-08-19 11:45:46 +02:00
} VideoColorSpace ;
///
2019-10-26 18:42:19 +02:00
/// Video output module structure and typedef.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef struct _video_module_ {
const char * Name ; ///< video output module name
char Enabled ; ///< flag output module enabled
2018-08-19 11:45:46 +02:00
/// allocate new video hw decoder
VideoHwDecoder * ( * const NewHwDecoder ) ( VideoStream * ) ;
2019-10-26 18:42:19 +02:00
void ( * const DelHwDecoder ) ( VideoHwDecoder * ) ;
unsigned ( * const GetSurface ) ( VideoHwDecoder * , const AVCodecContext * ) ;
void ( * const ReleaseSurface ) ( VideoHwDecoder * , unsigned ) ;
2021-12-27 20:02:45 +01:00
enum AVPixelFormat ( * const get_format ) ( VideoHwDecoder * , AVCodecContext * , const enum AVPixelFormat * ) ;
2019-10-26 18:42:19 +02:00
void ( * const RenderFrame ) ( VideoHwDecoder * , const AVCodecContext * , const AVFrame * ) ;
2018-08-19 11:45:46 +02:00
void * ( * const GetHwAccelContext ) ( VideoHwDecoder * ) ;
2019-10-26 18:42:19 +02:00
void ( * const SetClock ) ( VideoHwDecoder * , int64_t ) ;
2021-12-27 20:02:45 +01:00
int64_t ( * const GetClock ) ( const VideoHwDecoder * ) ;
2019-10-26 18:42:19 +02:00
void ( * const SetClosing ) ( const VideoHwDecoder * ) ;
void ( * const ResetStart ) ( const VideoHwDecoder * ) ;
void ( * const SetTrickSpeed ) ( const VideoHwDecoder * , int ) ;
2018-10-25 20:04:35 +02:00
uint8_t * ( * const GrabOutput ) ( int * , int * , int * , int ) ;
2020-02-02 13:26:51 +01:00
void ( * const GetStats ) ( VideoHwDecoder * , int * , int * , int * , int * , float * , int * , int * , int * , int * ) ;
2019-10-26 18:42:19 +02:00
void ( * const SetBackground ) ( uint32_t ) ;
void ( * const SetVideoMode ) ( void ) ;
2018-08-19 11:45:46 +02:00
/// module display handler thread
2019-10-26 18:42:19 +02:00
void ( * const DisplayHandlerThread ) ( void ) ;
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
void ( * const OsdClear ) ( void ) ; ///< clear OSD
2018-08-19 11:45:46 +02:00
/// draw OSD ARGB area
2019-10-26 18:42:19 +02:00
void ( * const OsdDrawARGB ) ( int , int , int , int , int , const uint8_t * , int , int ) ;
2021-12-27 20:02:45 +01:00
void ( * const OsdInit ) ( int , int ) ; ///< initialize OSD
void ( * const OsdExit ) ( void ) ; ///< cleanup OSD
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int ( * const Init ) ( const char * ) ; ///< initialize video output module
void ( * const Exit ) ( void ) ; ///< cleanup video output module
2018-08-19 11:45:46 +02:00
} VideoModule ;
2021-12-27 20:02:45 +01:00
typedef struct {
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
/** Left X co-ordinate. Inclusive. */
uint32_t x0 ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
/** Top Y co-ordinate. Inclusive. */
uint32_t y0 ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
/** Right X co-ordinate. Exclusive. */
uint32_t x1 ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
/** Bottom Y co-ordinate. Exclusive. */
uint32_t y1 ;
} VdpRect ;
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Defines
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2021-12-27 20:02:45 +01:00
# define CODEC_SURFACES_MAX 12 //
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
# define VIDEO_SURFACES_MAX 6 ///< video output surfaces for queue
2020-03-31 13:57:43 +02:00
2021-12-27 20:02:45 +01:00
# define NUM_SHADERS 5 // Number of supported user shaders with placebo
2020-06-07 12:31:18 +02:00
2022-05-24 00:09:55 +02:00
# if defined VAAPI
2019-10-20 14:48:28 +02:00
# define PIXEL_FORMAT AV_PIX_FMT_VAAPI
2021-12-27 20:02:45 +01:00
# define SWAP_BUFFER_SIZE 3
2019-10-04 10:37:57 +02:00
# endif
# ifdef CUVID
2019-10-20 14:48:28 +02:00
# define PIXEL_FORMAT AV_PIX_FMT_CUDA
2021-12-27 20:02:45 +01:00
# define SWAP_BUFFER_SIZE 3
2019-10-04 10:37:57 +02:00
# endif
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Variables
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2021-12-27 20:02:45 +01:00
AVBufferRef * HwDeviceContext ; ///< ffmpeg HW device context
char VideoIgnoreRepeatPict ; ///< disable repeat pict warning
2018-11-17 14:58:25 +01:00
2019-12-23 11:14:38 +01:00
int Planes = 2 ;
2018-11-17 14:58:25 +01:00
unsigned char * posd ;
2021-12-27 20:02:45 +01:00
static const char * VideoDriverName = " cuvid " ; ///< video output device
static Display * XlibDisplay ; ///< Xlib X11 display
static xcb_connection_t * Connection ; ///< xcb connection
static xcb_colormap_t VideoColormap ; ///< video colormap
static xcb_window_t VideoWindow ; ///< video window
static xcb_screen_t const * VideoScreen ; ///< video screen
static uint32_t VideoBlankTick ; ///< blank cursor timer
static xcb_pixmap_t VideoCursorPixmap ; ///< blank curosr pixmap
static xcb_cursor_t VideoBlankCursor ; ///< empty invisible cursor
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
static int VideoWindowX ; ///< video output window x coordinate
static int VideoWindowY ; ///< video outout window y coordinate
static unsigned VideoWindowWidth ; ///< video output window width
static unsigned VideoWindowHeight ; ///< video output window height
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
static const VideoModule NoopModule ; ///< forward definition of noop module
2018-08-19 11:45:46 +02:00
2019-10-28 21:43:37 +01:00
/// selected video module
2018-08-19 11:45:46 +02:00
static const VideoModule * VideoUsedModule = & NoopModule ;
2021-12-27 20:02:45 +01:00
signed char VideoHardwareDecoder = - 1 ; ///< flag use hardware decoder
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
static char VideoSurfaceModesChanged ; ///< flag surface modes changed
2018-08-19 11:45:46 +02:00
2019-10-28 21:43:37 +01:00
/// flag use transparent OSD.
2018-08-19 11:45:46 +02:00
static const char VideoTransparentOsd = 1 ;
2021-12-27 20:02:45 +01:00
static uint32_t VideoBackground ; ///< video background color
char VideoStudioLevels ; ///< flag use studio levels
2018-08-19 11:45:46 +02:00
2019-10-28 21:43:37 +01:00
/// Default deinterlace mode.
2018-08-19 11:45:46 +02:00
static VideoDeinterlaceModes VideoDeinterlace [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default number of deinterlace surfaces
2018-08-19 11:45:46 +02:00
static const int VideoDeinterlaceSurfaces = 4 ;
2019-10-28 21:43:37 +01:00
/// Default skip chroma deinterlace flag (CUVID only).
2018-08-19 11:45:46 +02:00
static char VideoSkipChromaDeinterlace [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default inverse telecine flag (CUVID only).
2018-08-19 11:45:46 +02:00
static char VideoInverseTelecine [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default amount of noise reduction algorithm to apply (0 .. 1000).
2018-08-19 11:45:46 +02:00
static int VideoDenoise [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default amount of sharpening, or blurring, to apply (-1000 .. 1000).
2018-08-19 11:45:46 +02:00
static int VideoSharpen [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default cut top and bottom in pixels
2018-08-19 11:45:46 +02:00
static int VideoCutTopBottom [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default cut left and right in pixels
2018-08-19 11:45:46 +02:00
static int VideoCutLeftRight [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default scaling mode
2018-08-19 11:45:46 +02:00
static VideoScalingModes VideoScaling [ VideoResolutionMax ] ;
2019-10-28 21:43:37 +01:00
/// Default audio/video delay
2018-08-19 11:45:46 +02:00
int VideoAudioDelay ;
2019-10-28 21:43:37 +01:00
/// Default zoom mode for 4:3
2018-08-19 11:45:46 +02:00
static VideoZoomModes Video4to3ZoomMode ;
2019-10-28 21:43:37 +01:00
/// Default zoom mode for 16:9 and others
2018-08-19 11:45:46 +02:00
static VideoZoomModes VideoOtherZoomMode ;
2019-12-12 11:31:40 +01:00
/// Default Value for DRM Connector
static char * DRMConnector = NULL ;
/// Default Value for DRM Refreshrate
static int DRMRefresh = 50 ;
2021-12-27 20:02:45 +01:00
static char Video60HzMode ; ///< handle 60hz displays
static char VideoSoftStartSync ; ///< soft start sync audio/video
static const int VideoSoftStartFrames = 100 ; ///< soft start frames
static char VideoShowBlackPicture ; ///< flag show black picture
2018-08-19 11:45:46 +02:00
2018-11-17 14:58:25 +01:00
static float VideoBrightness = 0.0f ;
static float VideoContrast = 1.0f ;
static float VideoSaturation = 1.0f ;
static float VideoHue = 0.0f ;
static float VideoGamma = 1.0f ;
2021-04-16 13:50:45 +02:00
static float VideoTemperature = 0.0f ;
2018-11-17 16:32:55 +01:00
static int VulkanTargetColorSpace = 0 ;
2018-12-07 13:07:50 +01:00
static int VideoScalerTest = 0 ;
static int VideoColorBlindness = 0 ;
static float VideoColorBlindnessFaktor = 1.0f ;
2018-11-17 14:58:25 +01:00
2021-12-27 20:02:45 +01:00
static char * shadersp [ NUM_SHADERS ] ;
2020-06-16 08:49:03 +02:00
char MyConfigDir [ 200 ] ;
2020-06-07 12:31:18 +02:00
static int num_shaders = 0 ;
2021-03-16 09:40:08 +01:00
static int LUTon = - 1 ;
2020-06-07 12:31:18 +02:00
2019-10-26 18:42:19 +02:00
static xcb_atom_t WmDeleteWindowAtom ; ///< WM delete message atom
static xcb_atom_t NetWmState ; ///< wm-state message atom
static xcb_atom_t NetWmStateFullscreen ; ///< fullscreen wm-state message atom
2018-12-10 13:10:58 +01:00
static xcb_atom_t NetWmStateAbove ;
2018-08-19 11:45:46 +02:00
# ifdef DEBUG
2021-12-27 20:02:45 +01:00
extern uint32_t VideoSwitch ; ///< ticks for channel switch
2018-08-19 11:45:46 +02:00
# endif
2021-12-27 20:02:45 +01:00
extern void AudioVideoReady ( int64_t ) ; ///< tell audio video is ready
2018-08-19 11:45:46 +02:00
# ifdef USE_VIDEO_THREAD
2021-12-27 20:02:45 +01:00
static pthread_t VideoThread ; ///< video decode thread
static pthread_cond_t VideoWakeupCond ; ///< wakeup condition variable
static pthread_mutex_t VideoMutex ; ///< video condition mutex
2023-07-14 09:13:09 +02:00
pthread_mutex_t VideoLockMutex ; ///< video lock mutex
2021-12-27 20:02:45 +01:00
pthread_mutex_t OSDMutex ; ///< OSD update mutex
2018-08-19 11:45:46 +02:00
# endif
2021-12-27 20:02:45 +01:00
static pthread_t VideoDisplayThread ; ///< video display thread
2019-10-11 11:47:11 +02:00
2019-10-28 21:43:37 +01:00
// static pthread_cond_t VideoDisplayWakeupCond; ///< wakeup condition variable
// static pthread_mutex_t VideoDisplayMutex; ///< video condition mutex
// static pthread_mutex_t VideoDisplayLockMutex; ///< video lock mutex
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
static int OsdConfigWidth ; ///< osd configured width
static int OsdConfigHeight ; ///< osd configured height
static char OsdShown ; ///< flag show osd
static char Osd3DMode ; ///< 3D OSD mode
static int OsdWidth ; ///< osd width
static int OsdHeight ; ///< osd height
static int OsdDirtyX ; ///< osd dirty area x
static int OsdDirtyY ; ///< osd dirty area y
static int OsdDirtyWidth ; ///< osd dirty area width
static int OsdDirtyHeight ; ///< osd dirty area height
2019-10-04 10:37:57 +02:00
2019-10-26 18:42:19 +02:00
static void ( * VideoEventCallback ) ( void ) = NULL ; /// callback function to notify VDR about Video Events
2019-10-04 10:37:57 +02:00
2021-12-27 20:02:45 +01:00
static int64_t VideoDeltaPTS ; ///< FIXME: fix pts
2018-08-19 11:45:46 +02:00
# ifdef USE_SCREENSAVER
2021-12-27 20:02:45 +01:00
static char DPMSDisabled ; ///< flag we have disabled dpms
static char EnableDPMSatBlackScreen ; ///< flag we should enable dpms at black screen
2018-08-19 11:45:46 +02:00
# endif
2020-05-01 12:06:04 +02:00
static unsigned int Count ;
2021-12-27 20:02:45 +01:00
static int EglEnabled ; ///< use EGL
static int GlxVSyncEnabled = 1 ; ///< enable/disable v-sync
2019-10-11 11:47:11 +02:00
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
static GLXContext glxSharedContext ; ///< shared gl context
static GLXContext glxContext ; ///< our gl context
2019-10-04 10:37:57 +02:00
2021-12-27 20:02:45 +01:00
static GLXContext glxThreadContext ; ///< our gl context for the thread
2019-12-17 10:22:22 +01:00
2021-12-27 20:02:45 +01:00
static XVisualInfo * GlxVisualInfo ; ///< our gl visual
2019-10-26 18:42:19 +02:00
static void GlxSetupWindow ( xcb_window_t window , int width , int height , GLXContext context ) ;
GLXContext OSDcontext ;
2019-10-04 10:37:57 +02:00
# else
2019-10-26 18:42:19 +02:00
static EGLContext eglSharedContext ; ///< shared gl context
2020-04-10 16:17:23 +02:00
static EGLContext eglOSDContext = NULL ; ///< our gl context for the thread
2019-10-26 18:42:19 +02:00
static EGLContext eglContext ; ///< our gl context
static EGLConfig eglConfig ;
static EGLDisplay eglDisplay ;
static EGLSurface eglSurface , eglOSDSurface ;
static EGLint eglAttrs [ 10 ] ;
static int eglVersion = 2 ;
2021-12-27 20:02:45 +01:00
static EGLImageKHR ( EGLAPIENTRY * CreateImageKHR ) ( EGLDisplay , EGLContext , EGLenum , EGLClientBuffer , const EGLint * ) ;
static EGLBoolean ( EGLAPIENTRY * DestroyImageKHR ) ( EGLDisplay , EGLImageKHR ) ;
static void ( EGLAPIENTRY * EGLImageTargetTexture2DOES ) ( GLenum , GLeglImageOES ) ;
2019-12-10 10:45:22 +01:00
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR ;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR ;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR ;
PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR ;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID ;
2019-10-04 10:37:57 +02:00
2021-12-27 20:02:45 +01:00
static EGLContext eglThreadContext ; ///< our gl context for the thread
2019-12-17 10:22:22 +01:00
2019-10-26 18:42:19 +02:00
static void GlxSetupWindow ( xcb_window_t window , int width , int height , EGLContext context ) ;
EGLContext OSDcontext ;
2018-08-24 16:05:20 +02:00
# endif
2021-12-27 20:02:45 +01:00
static GLuint OsdGlTextures [ 2 ] ; ///< gl texture for OSD
static int OsdIndex = 0 ; ///< index into OsdGlTextures
2018-08-24 16:05:20 +02:00
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Common Functions
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2021-12-27 20:02:45 +01:00
void VideoThreadLock ( void ) ; ///< lock video thread
void VideoThreadUnlock ( void ) ; ///< unlock video thread
static void VideoThreadExit ( void ) ; ///< exit/kill video thread
2018-08-19 11:45:46 +02:00
# ifdef USE_SCREENSAVER
static void X11SuspendScreenSaver ( xcb_connection_t * , int ) ;
static int X11HaveDPMS ( xcb_connection_t * ) ;
static void X11DPMSReenable ( xcb_connection_t * ) ;
static void X11DPMSDisable ( xcb_connection_t * ) ;
# endif
2019-10-11 12:05:26 +02:00
2021-12-27 20:02:45 +01:00
char * eglErrorString ( EGLint error ) {
2020-01-07 22:22:07 +01:00
switch ( error ) {
case EGL_SUCCESS :
return " No error " ;
case EGL_NOT_INITIALIZED :
return " EGL not initialized or failed to initialize " ;
case EGL_BAD_ACCESS :
return " Resource inaccessible " ;
case EGL_BAD_ALLOC :
return " Cannot allocate resources " ;
case EGL_BAD_ATTRIBUTE :
return " Unrecognized attribute or attribute value " ;
case EGL_BAD_CONTEXT :
return " Invalid EGL context " ;
case EGL_BAD_CONFIG :
return " Invalid EGL frame buffer configuration " ;
case EGL_BAD_CURRENT_SURFACE :
return " Current surface is no longer valid " ;
case EGL_BAD_DISPLAY :
return " Invalid EGL display " ;
case EGL_BAD_SURFACE :
return " Invalid surface " ;
case EGL_BAD_MATCH :
return " Inconsistent arguments " ;
case EGL_BAD_PARAMETER :
return " Invalid argument " ;
case EGL_BAD_NATIVE_PIXMAP :
return " Invalid native pixmap " ;
case EGL_BAD_NATIVE_WINDOW :
return " Invalid native window " ;
case EGL_CONTEXT_LOST :
return " Context lost " ;
}
return " Unknown error " ;
}
///
/// egl check error.
///
2021-12-27 20:02:45 +01:00
# define EglCheck(void) \
{ \
EGLint err ; \
\
if ( ( err = eglGetError ( ) ) ! = EGL_SUCCESS ) { \
Debug ( 3 , " video/egl: %s:%d error %d %s \n " , __FILE__ , __LINE__ , err , eglErrorString ( err ) ) ; \
} \
}
2020-01-07 22:22:07 +01:00
2019-12-10 10:45:22 +01:00
//----------------------------------------------------------------------------
// DRM Helper Functions
//----------------------------------------------------------------------------
# ifdef USE_DRM
# include "drm.c"
# include "hdr.c"
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Update video pts.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param pts_p pointer to pts
2021-12-27 20:02:45 +01:00
/// @param interlaced interlaced flag (frame isn't right)
2019-10-26 18:42:19 +02:00
/// @param frame frame to display
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note frame->interlaced_frame can't be used for interlace detection
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void VideoSetPts ( int64_t * pts_p , int interlaced , const AVCodecContext * video_ctx , const AVFrame * frame ) {
2018-08-19 11:45:46 +02:00
int64_t pts ;
int duration ;
2022-12-19 09:17:34 +01:00
static int64_t lastpts ;
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// Get duration for this frame.
// FIXME: using framerate as workaround for av_frame_get_pkt_duration
2018-08-19 11:45:46 +02:00
//
2019-10-26 18:42:19 +02:00
2019-10-28 21:43:37 +01:00
// if (video_ctx->framerate.num && video_ctx->framerate.den) {
// duration = 1000 * video_ctx->framerate.den / video_ctx->framerate.num;
// } else {
2021-12-27 20:02:45 +01:00
duration = interlaced ? 40 : 20 ; // 50Hz -> 20ms default
2019-10-28 21:43:37 +01:00
// }
2021-12-27 20:02:45 +01:00
// Debug(4, "video: %d/%d %" PRIx64 " -> %d\n", video_ctx->framerate.den,
// video_ctx->framerate.num, av_frame_get_pkt_duration(frame), duration);
2018-08-19 11:45:46 +02:00
// update video clock
2021-12-27 20:02:45 +01:00
if ( * pts_p ! = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
* pts_p + = duration * 90 ;
2021-12-27 20:02:45 +01:00
// Info("video: %s +pts\n", Timestamp2String(*pts_p));
2018-08-19 11:45:46 +02:00
}
2019-10-28 21:43:37 +01:00
// av_opt_ptr(avcodec_get_frame_class(), frame, "best_effort_timestamp");
// pts = frame->best_effort_timestamp;
// pts = frame->pkt_pts;
2019-10-26 18:42:19 +02:00
pts = frame - > pts ;
2021-12-27 20:02:45 +01:00
if ( pts = = ( int64_t ) AV_NOPTS_VALUE | | ! pts ) {
2019-10-26 18:42:19 +02:00
// libav: 0.8pre didn't set pts
pts = frame - > pkt_dts ;
2018-08-19 11:45:46 +02:00
}
// libav: sets only pkt_dts which can be 0
2021-12-27 20:02:45 +01:00
if ( pts & & pts ! = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
// build a monotonic pts
2021-12-27 20:02:45 +01:00
if ( * pts_p ! = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
int64_t delta ;
delta = pts - * pts_p ;
// ignore negative jumps
if ( delta > - 600 * 90 & & delta < = - 40 * 90 ) {
if ( - delta > VideoDeltaPTS ) {
VideoDeltaPTS = - delta ;
Debug ( 4 , " video: %#012 " PRIx64 " ->%#012 " PRIx64 " delta%+4 " PRId64 " pts \n " , * pts_p , pts ,
2021-12-27 20:02:45 +01:00
pts - * pts_p ) ;
2019-10-26 18:42:19 +02:00
}
return ;
}
2021-12-27 20:02:45 +01:00
} else { // first new clock value
2019-10-26 18:42:19 +02:00
Debug ( 3 , " ++++++++++++++++++++++++++++++++++++starte audio \n " ) ;
AudioVideoReady ( pts ) ;
}
2022-12-19 09:17:34 +01:00
if ( * pts_p ! = pts & & lastpts ! = pts ) {
2019-10-26 18:42:19 +02:00
Debug ( 4 , " video: %#012 " PRIx64 " ->%#012 " PRIx64 " delta=%4 " PRId64 " pts \n " , * pts_p , pts , pts - * pts_p ) ;
* pts_p = pts ;
}
2018-08-19 11:45:46 +02:00
}
2022-12-19 09:17:34 +01:00
lastpts = pts ;
2018-08-19 11:45:46 +02:00
}
2018-10-14 13:05:22 +02:00
int CuvidMessage ( int level , const char * format , . . . ) ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Update output for new size or aspect ratio.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param input_aspect_ratio video stream aspect
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
static void VideoUpdateOutput ( AVRational input_aspect_ratio , int input_width , int input_height ,
2021-12-27 20:02:45 +01:00
VideoResolutions resolution , int video_x , int video_y , int video_width , int video_height ,
int * output_x , int * output_y , int * output_width , int * output_height , int * crop_x ,
int * crop_y , int * crop_width , int * crop_height ) {
2018-08-19 11:45:46 +02:00
AVRational display_aspect_ratio ;
AVRational tmp_ratio ;
2020-04-13 18:04:57 +02:00
// input not initialized yet, return immediately
2018-08-19 11:45:46 +02:00
if ( ! input_aspect_ratio . num | | ! input_aspect_ratio . den ) {
2021-01-10 13:55:09 +01:00
* output_width = video_width ;
* output_height = video_height ;
2020-04-13 18:04:57 +02:00
return ;
2018-08-19 11:45:46 +02:00
}
2019-12-10 10:45:22 +01:00
# ifdef USE_DRM
2020-04-10 16:17:23 +02:00
get_drm_aspect ( & display_aspect_ratio . num , & display_aspect_ratio . den ) ;
2019-12-10 10:45:22 +01:00
# else
2020-04-13 18:04:57 +02:00
display_aspect_ratio . num = VideoScreen - > width_in_pixels ;
display_aspect_ratio . den = VideoScreen - > height_in_pixels ;
2019-12-10 10:45:22 +01:00
# endif
2020-04-13 18:04:57 +02:00
av_reduce ( & display_aspect_ratio . num , & display_aspect_ratio . den , display_aspect_ratio . num , display_aspect_ratio . den ,
2021-12-27 20:02:45 +01:00
1024 * 1024 ) ;
2020-04-13 18:04:57 +02:00
Debug ( 3 , " video: input %dx%d (%d:%d) \n " , input_width , input_height , input_aspect_ratio . num ,
2021-12-27 20:02:45 +01:00
input_aspect_ratio . den ) ;
2020-04-13 18:04:57 +02:00
Debug ( 3 , " video: display aspect %d:%d Resolution %d \n " , display_aspect_ratio . num , display_aspect_ratio . den ,
2021-12-27 20:02:45 +01:00
resolution ) ;
2020-04-13 18:04:57 +02:00
Debug ( 3 , " video: video %+d%+d %dx%d \n " , video_x , video_y , video_width , video_height ) ;
2018-08-19 11:45:46 +02:00
* crop_x = VideoCutLeftRight [ resolution ] ;
* crop_y = VideoCutTopBottom [ resolution ] ;
* crop_width = input_width - VideoCutLeftRight [ resolution ] * 2 ;
* crop_height = input_height - VideoCutTopBottom [ resolution ] * 2 ;
2020-04-13 18:04:57 +02:00
CuvidMessage ( 2 , " video: crop to %+d%+d %dx%d \n " , * crop_x , * crop_y , * crop_width , * crop_height ) ;
2018-08-19 11:45:46 +02:00
tmp_ratio . num = 4 ;
tmp_ratio . den = 3 ;
if ( ! av_cmp_q ( input_aspect_ratio , tmp_ratio ) ) {
2019-10-26 18:42:19 +02:00
switch ( Video4to3ZoomMode ) {
case VideoNormal :
goto normal ;
case VideoStretch :
goto stretch ;
case VideoCenterCutOut :
goto center_cut_out ;
2020-04-13 18:04:57 +02:00
case VideoNone :
goto video_none ;
2019-10-26 18:42:19 +02:00
}
2018-08-19 11:45:46 +02:00
}
switch ( VideoOtherZoomMode ) {
2019-10-26 18:42:19 +02:00
case VideoNormal :
goto normal ;
case VideoStretch :
goto stretch ;
case VideoCenterCutOut :
goto center_cut_out ;
2020-04-13 18:04:57 +02:00
case VideoNone :
goto video_none ;
2018-08-19 11:45:46 +02:00
}
2021-12-27 20:02:45 +01:00
normal :
2018-08-19 11:45:46 +02:00
* output_x = video_x ;
* output_y = video_y ;
2020-04-13 18:04:57 +02:00
* output_height = video_height ;
* output_width = ( * crop_width * * output_height * input_aspect_ratio . num ) / ( input_aspect_ratio . den * * crop_height ) ;
2018-08-19 11:45:46 +02:00
if ( * output_width > video_width ) {
2019-10-26 18:42:19 +02:00
* output_width = video_width ;
2020-04-13 18:04:57 +02:00
* output_height =
( * crop_height * * output_width * input_aspect_ratio . den ) / ( input_aspect_ratio . num * * crop_width ) ;
2019-10-26 18:42:19 +02:00
* output_y + = ( video_height - * output_height ) / 2 ;
2020-04-13 18:04:57 +02:00
} else if ( * output_width < video_width ) {
2019-10-26 18:42:19 +02:00
* output_x + = ( video_width - * output_width ) / 2 ;
2018-08-19 11:45:46 +02:00
}
2020-04-13 18:04:57 +02:00
CuvidMessage ( 2 , " video: normal aspect output %dx%d%+d%+d \n " , * output_width , * output_height , * output_x , * output_y ) ;
2018-08-19 11:45:46 +02:00
return ;
2021-12-27 20:02:45 +01:00
stretch :
2018-08-19 11:45:46 +02:00
* output_x = video_x ;
* output_y = video_y ;
* output_width = video_width ;
* output_height = video_height ;
2020-04-13 18:04:57 +02:00
CuvidMessage ( 2 , " video: stretch output %dx%d%+d%+d \n " , * output_width , * output_height , * output_x , * output_y ) ;
2018-08-19 11:45:46 +02:00
return ;
2021-12-27 20:02:45 +01:00
center_cut_out :
2018-08-19 11:45:46 +02:00
* output_x = video_x ;
* output_y = video_y ;
* output_height = video_height ;
2020-04-13 18:04:57 +02:00
* output_width = ( * crop_width * * output_height * input_aspect_ratio . num ) / ( input_aspect_ratio . den * * crop_height ) ;
if ( * output_width > video_width ) {
// fix height cropping
* crop_width = ( int ) ( ( * crop_width * video_width ) / ( * output_width * 2.0 ) + 0.5 ) * 2 ;
* crop_x = ( input_width - * crop_width ) / 2 ;
* output_width = video_width ;
} else if ( * output_width < video_width ) {
// fix width cropping
* crop_height = ( int ) ( ( * crop_height * * output_width ) / ( video_width * 2.0 ) + 0.5 ) * 2 ;
* crop_y = ( input_height - * crop_height ) / 2 ;
* output_width = video_width ;
2018-08-19 11:45:46 +02:00
}
2020-04-13 18:04:57 +02:00
CuvidMessage ( 2 , " video: aspect crop %dx%d%+d%+d \n " , * crop_width , * crop_height , * crop_x , * crop_y ) ;
return ;
2021-12-27 20:02:45 +01:00
video_none :
2020-04-13 18:04:57 +02:00
* output_height = * crop_height ;
2021-12-27 20:02:45 +01:00
* output_width = ( * crop_width * input_aspect_ratio . num ) / input_aspect_ratio . den ; // normalize pixel aspect ratio
2020-04-13 18:04:57 +02:00
* output_x = video_x + ( video_width - * output_width ) / 2 ;
* output_y = video_y + ( video_height - * output_height ) / 2 ;
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 , " video: original aspect output %dx%d%+d%+d \n " , * output_width , * output_height , * output_x ,
* output_y ) ;
2018-08-19 11:45:46 +02:00
return ;
}
2019-10-26 18:42:19 +02:00
static uint64_t test_time = 0 ;
2019-10-11 11:47:11 +02:00
///
2019-10-26 18:42:19 +02:00
/// Lock video thread.
2019-10-11 11:47:11 +02:00
///
2021-12-27 20:02:45 +01:00
# define VideoThreadLock(void) \
{ \
if ( VideoThread ) { \
if ( pthread_mutex_lock ( & VideoLockMutex ) ) { \
Error ( _ ( " video: can't lock thread \n " ) ) ; \
} \
} \
}
2019-10-28 21:43:37 +01:00
// test_time = GetusTicks();
// printf("Lock start....");
2019-10-11 11:47:11 +02:00
///
2019-10-26 18:42:19 +02:00
/// Unlock video thread.
2019-10-11 11:47:11 +02:00
///
2021-12-27 20:02:45 +01:00
# define VideoThreadUnlock(void) \
{ \
if ( VideoThread ) { \
if ( pthread_mutex_unlock ( & VideoLockMutex ) ) { \
Error ( _ ( " video: can't unlock thread \n " ) ) ; \
} \
} \
}
2019-10-28 21:43:37 +01:00
// printf("Video Locked for %d\n",(GetusTicks()-test_time)/1000);
2018-08-19 11:45:46 +02:00
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
# define Lock_and_SharedContext \
{ \
VideoThreadLock ( ) ; \
2023-07-14 09:13:09 +02:00
Debug ( 4 , " Lock OSDMutex %s %d \n " , __FILE__ , __LINE__ ) ; \
pthread_mutex_lock ( & OSDMutex ) ; \
2021-12-27 20:02:45 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglSharedContext ) ; \
EglCheck ( ) ; \
}
# define Unlock_and_NoContext \
{ \
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ; \
EglCheck ( ) ; \
2023-07-14 09:13:09 +02:00
Debug ( 4 , " UnLock OSDMutex %s %d \n " , __FILE__ , __LINE__ ) ; \
pthread_mutex_unlock ( & OSDMutex ) ; \
2021-12-27 20:02:45 +01:00
VideoThreadUnlock ( ) ; \
}
# define SharedContext \
{ \
2023-07-14 09:13:09 +02:00
Debug ( 4 , " Lock OSDMutex %s %d \n " , __FILE__ , __LINE__ ) ; \
pthread_mutex_lock ( & OSDMutex ) ; \
2021-12-27 20:02:45 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglSharedContext ) ; \
EglCheck ( ) ; \
}
# define NoContext \
{ \
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ; \
EglCheck ( ) ; \
2023-07-14 09:13:09 +02:00
Debug ( 4 , " UnLock OSDMutex %s %d \n " , __FILE__ , __LINE__ ) ; \
pthread_mutex_unlock ( & OSDMutex ) ; \
2021-12-27 20:02:45 +01:00
}
2021-01-10 13:55:09 +01:00
# else
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
# define Lock_and_SharedContext \
{ VideoThreadLock ( ) ; }
# define Unlock_and_NoContext \
{ VideoThreadUnlock ( ) ; }
# define SharedContext \
{ }
# define NoContext \
{ }
2021-01-10 13:55:09 +01:00
# endif
# endif
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// GLX
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
# ifdef USE_GLX
///
2019-10-26 18:42:19 +02:00
/// GLX extension functions
2018-08-19 11:45:46 +02:00
///@{
# ifdef GLX_MESA_swap_control
static PFNGLXSWAPINTERVALMESAPROC GlxSwapIntervalMESA ;
# endif
# ifdef GLX_SGI_video_sync
static PFNGLXGETVIDEOSYNCSGIPROC GlxGetVideoSyncSGI ;
# endif
# ifdef GLX_SGI_swap_control
static PFNGLXSWAPINTERVALSGIPROC GlxSwapIntervalSGI ;
# endif
///
2019-10-26 18:42:19 +02:00
/// GLX check error.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
# define GlxCheck(void) \
{ \
GLenum err ; \
\
if ( ( err = glGetError ( ) ) ! = GL_NO_ERROR ) { \
Debug ( 3 , " video/glx: error %s:%d %d '%s' \n " , __FILE__ , __LINE__ , err , gluErrorString ( err ) ) ; \
} \
}
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// GLX check if a GLX extension is supported.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param ext extension to query
2019-10-26 18:42:19 +02:00
/// @returns true if supported, false otherwise
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int GlxIsExtensionSupported ( const char * ext ) {
2019-10-04 10:37:57 +02:00
const char * extensions ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
if ( ( extensions = glXQueryExtensionsString ( XlibDisplay , DefaultScreen ( XlibDisplay ) ) ) ) {
const char * s ;
int l ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
s = strstr ( extensions , ext ) ;
l = strlen ( ext ) ;
return s & & ( s [ l ] = = ' ' | | s [ l ] = = ' \0 ' ) ;
2018-08-19 11:45:46 +02:00
}
2019-10-04 10:37:57 +02:00
return 0 ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Setup GLX window.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param window xcb window id
/// @param width window width
/// @param height window height
/// @param context GLX context
2018-08-19 11:45:46 +02:00
///
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2018-08-19 11:45:46 +02:00
static void GlxSetupWindow ( xcb_window_t window , int width , int height , GLXContext context )
2019-10-04 10:37:57 +02:00
# else
static void GlxSetupWindow ( xcb_window_t window , int width , int height , EGLContext context )
# endif
2018-08-19 11:45:46 +02:00
{
2019-10-04 14:21:55 +02:00
2018-08-19 11:45:46 +02:00
uint32_t start ;
uint32_t end ;
int i ;
unsigned count ;
2019-10-04 14:21:55 +02:00
2019-04-05 07:20:52 +02:00
# ifdef PLACEBO_
2019-10-26 18:42:19 +02:00
return ;
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
Debug ( 3 , " video/egl: %s %x %dx%d context: %p " , __FUNCTION__ , window , width , height , context ) ;
2018-08-19 11:45:46 +02:00
2019-10-04 10:37:57 +02:00
// set gl context
# ifdef CUVID
2019-10-26 18:42:19 +02:00
if ( ! glXMakeCurrent ( XlibDisplay , window , context ) ) {
Fatal ( _ ( " video/egl: GlxSetupWindow can't make egl/glx context current \n " ) ) ;
EglEnabled = 0 ;
return ;
}
2019-10-25 23:25:20 +02:00
# endif
2019-10-04 10:37:57 +02:00
Debug ( 3 , " video/egl: ok \n " ) ;
2018-08-19 11:45:46 +02:00
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2018-08-19 11:45:46 +02:00
// check if v-sync is working correct
end = GetMsTicks ( ) ;
for ( i = 0 ; i < 10 ; + + i ) {
2019-10-26 18:42:19 +02:00
start = end ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
glXSwapBuffers ( XlibDisplay , window ) ;
end = GetMsTicks ( ) ;
GlxGetVideoSyncSGI ( & count ) ;
Debug ( 4 , " video/glx: %5d frame rate %dms \n " , count , end - start ) ;
// nvidia can queue 5 swaps
if ( i > 5 & & ( end - start ) < 15 ) {
Warning ( _ ( " video/glx: no v-sync \n " ) ) ;
}
}
GLenum err = glewInit ( ) ;
if ( err ! = GLEW_OK ) {
Debug ( 3 , " Error: %s \n " , glewGetErrorString ( err ) ) ;
}
GlxCheck ( ) ;
2018-08-19 11:45:46 +02:00
# endif
// viewpoint
glViewport ( 0 , 0 , width , height ) ;
2019-10-26 18:42:19 +02:00
GlxCheck ( ) ;
2019-10-04 10:37:57 +02:00
# ifdef VAAPI
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2018-08-19 11:45:46 +02:00
# endif
}
///
2019-10-26 18:42:19 +02:00
/// Initialize GLX.
2018-08-19 11:45:46 +02:00
///
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
static void EglInit ( void ) {
2018-08-22 21:04:52 +02:00
2019-10-26 18:42:19 +02:00
XVisualInfo * vi = NULL ;
2020-05-01 12:06:04 +02:00
# if defined PLACEBO && !defined PLACEBO_GL
2019-10-26 18:42:19 +02:00
return ;
# endif
2020-04-10 16:17:23 +02:00
2019-10-28 21:43:37 +01:00
// The desired 30-bit color visual
2021-12-27 20:02:45 +01:00
int attributeList10 [ ] = { GLX_DRAWABLE_TYPE ,
GLX_WINDOW_BIT ,
GLX_RENDER_TYPE ,
GLX_RGBA_BIT ,
GLX_DOUBLEBUFFER ,
True ,
GLX_RED_SIZE ,
10 , /*10bits for R */
GLX_GREEN_SIZE ,
10 , /*10bits for G */
GLX_BLUE_SIZE ,
10 , /*10bits for B */
None } ;
int attributeList [ ] = { GLX_DRAWABLE_TYPE ,
GLX_WINDOW_BIT ,
GLX_RENDER_TYPE ,
GLX_RGBA_BIT ,
GLX_DOUBLEBUFFER ,
True ,
GLX_RED_SIZE ,
8 , /*8 bits for R */
GLX_GREEN_SIZE ,
8 , /*8 bits for G */
GLX_BLUE_SIZE ,
8 , /*8 bits for B */
None } ;
2019-10-26 18:42:19 +02:00
int fbcount ;
2018-08-19 11:45:46 +02:00
GLXContext context ;
int major ;
int minor ;
int glx_GLX_EXT_swap_control ;
int glx_GLX_MESA_swap_control ;
int glx_GLX_SGI_swap_control ;
int glx_GLX_SGI_video_sync ;
2019-10-26 18:42:19 +02:00
GLXFBConfig * fbc ;
int redSize , greenSize , blueSize ;
2018-08-19 11:45:46 +02:00
if ( ! glXQueryVersion ( XlibDisplay , & major , & minor ) ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video/glx: no GLX support \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2020-04-10 16:17:23 +02:00
Debug ( 3 , " video/glx: glx version %d.%d \n " , major , minor ) ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// check which extension are supported
2018-08-19 11:45:46 +02:00
//
glx_GLX_EXT_swap_control = GlxIsExtensionSupported ( " GLX_EXT_swap_control " ) ;
2019-10-26 18:42:19 +02:00
glx_GLX_MESA_swap_control = GlxIsExtensionSupported ( " GLX_MESA_swap_control " ) ;
2018-08-19 11:45:46 +02:00
glx_GLX_SGI_swap_control = GlxIsExtensionSupported ( " GLX_SGI_swap_control " ) ;
glx_GLX_SGI_video_sync = GlxIsExtensionSupported ( " GLX_SGI_video_sync " ) ;
# ifdef GLX_MESA_swap_control
if ( glx_GLX_MESA_swap_control ) {
2021-12-27 20:02:45 +01:00
GlxSwapIntervalMESA = ( PFNGLXSWAPINTERVALMESAPROC ) glXGetProcAddress ( ( const GLubyte * ) " glXSwapIntervalMESA " ) ;
2018-08-19 11:45:46 +02:00
}
Debug ( 3 , " video/glx: GlxSwapIntervalMESA=%p \n " , GlxSwapIntervalMESA ) ;
# endif
# ifdef GLX_SGI_swap_control
if ( glx_GLX_SGI_swap_control ) {
2021-12-27 20:02:45 +01:00
GlxSwapIntervalSGI = ( PFNGLXSWAPINTERVALSGIPROC ) glXGetProcAddress ( ( const GLubyte * ) " wglSwapIntervalEXT " ) ;
2018-08-19 11:45:46 +02:00
}
Debug ( 3 , " video/glx: GlxSwapIntervalSGI=%p \n " , GlxSwapIntervalSGI ) ;
# endif
# ifdef GLX_SGI_video_sync
if ( glx_GLX_SGI_video_sync ) {
2021-12-27 20:02:45 +01:00
GlxGetVideoSyncSGI = ( PFNGLXGETVIDEOSYNCSGIPROC ) glXGetProcAddress ( ( const GLubyte * ) " glXGetVideoSyncSGI " ) ;
2018-08-19 11:45:46 +02:00
}
Debug ( 3 , " video/glx: GlxGetVideoSyncSGI=%p \n " , GlxGetVideoSyncSGI ) ;
# endif
// create glx context
glXMakeCurrent ( XlibDisplay , None , NULL ) ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
fbc = glXChooseFBConfig ( XlibDisplay , DefaultScreen ( XlibDisplay ) , attributeList10 , & fbcount ) ; // try 10 Bit
2019-10-26 18:42:19 +02:00
if ( fbc = = NULL ) {
2021-12-27 20:02:45 +01:00
fbc =
glXChooseFBConfig ( XlibDisplay , DefaultScreen ( XlibDisplay ) , attributeList , & fbcount ) ; // fall back to 8 Bit
2019-10-26 18:42:19 +02:00
if ( fbc = = NULL )
Fatal ( _ ( " did not get FBconfig " ) ) ;
}
vi = glXGetVisualFromFBConfig ( XlibDisplay , fbc [ 0 ] ) ;
glXGetFBConfigAttrib ( XlibDisplay , fbc [ 0 ] , GLX_RED_SIZE , & redSize ) ;
glXGetFBConfigAttrib ( XlibDisplay , fbc [ 0 ] , GLX_GREEN_SIZE , & greenSize ) ;
glXGetFBConfigAttrib ( XlibDisplay , fbc [ 0 ] , GLX_BLUE_SIZE , & blueSize ) ;
Debug ( 3 , " RGB size %d:%d:%d \n " , redSize , greenSize , blueSize ) ;
Debug ( 3 , " Chosen visual ID = 0x%x \n " , vi - > visualid ) ;
2018-09-30 15:26:55 +02:00
2018-08-19 11:45:46 +02:00
context = glXCreateContext ( XlibDisplay , vi , NULL , GL_TRUE ) ;
if ( ! context ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video/glx: can't create glx context \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2019-10-20 14:48:28 +02:00
glxSharedContext = context ;
context = glXCreateContext ( XlibDisplay , vi , glxSharedContext , GL_TRUE ) ;
2018-08-19 11:45:46 +02:00
if ( ! context ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video/glx: can't create glx context \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2019-10-20 14:48:28 +02:00
glxContext = context ;
2019-10-26 18:42:19 +02:00
EglEnabled = 1 ;
2018-08-19 11:45:46 +02:00
GlxVisualInfo = vi ;
Debug ( 3 , " video/glx: visual %#02x depth %u \n " , ( unsigned ) vi - > visualid , vi - > depth ) ;
//
2021-12-27 20:02:45 +01:00
// query default v-sync state
2018-08-19 11:45:46 +02:00
//
if ( glx_GLX_EXT_swap_control ) {
2019-10-26 18:42:19 +02:00
unsigned tmp ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
tmp = - 1 ;
glXQueryDrawable ( XlibDisplay , DefaultRootWindow ( XlibDisplay ) , GLX_SWAP_INTERVAL_EXT , & tmp ) ;
GlxCheck ( ) ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/glx: default v-sync is %d \n " , tmp ) ;
2018-08-19 11:45:46 +02:00
} else {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/glx: default v-sync is unknown \n " ) ;
2018-08-19 11:45:46 +02:00
}
//
2021-12-27 20:02:45 +01:00
// disable wait on v-sync
2018-08-19 11:45:46 +02:00
//
// FIXME: sleep before swap / busy waiting hardware
// FIXME: 60hz lcd panel
// FIXME: config: default, on, off
# ifdef GLX_SGI_swap_control
if ( GlxVSyncEnabled < 0 & & GlxSwapIntervalSGI ) {
2019-10-26 18:42:19 +02:00
if ( GlxSwapIntervalSGI ( 0 ) ) {
GlxCheck ( ) ;
Warning ( _ ( " video/glx: can't disable v-sync \n " ) ) ;
} else {
Info ( _ ( " video/glx: v-sync disabled \n " ) ) ;
}
2018-08-19 11:45:46 +02:00
} else
# endif
# ifdef GLX_MESA_swap_control
2021-12-27 20:02:45 +01:00
if ( GlxVSyncEnabled < 0 & & GlxSwapIntervalMESA ) {
2019-10-26 18:42:19 +02:00
if ( GlxSwapIntervalMESA ( 0 ) ) {
GlxCheck ( ) ;
Warning ( _ ( " video/glx: can't disable v-sync \n " ) ) ;
} else {
Info ( _ ( " video/glx: v-sync disabled \n " ) ) ;
}
2018-08-19 11:45:46 +02:00
}
# endif
//
2021-12-27 20:02:45 +01:00
// enable wait on v-sync
2018-08-19 11:45:46 +02:00
//
# ifdef GLX_SGI_swap_control
if ( GlxVSyncEnabled > 0 & & GlxSwapIntervalMESA ) {
2019-10-26 18:42:19 +02:00
if ( GlxSwapIntervalMESA ( 1 ) ) {
GlxCheck ( ) ;
Warning ( _ ( " video/glx: can't enable v-sync \n " ) ) ;
} else {
Info ( _ ( " video/glx: v-sync enabled \n " ) ) ;
}
2018-08-19 11:45:46 +02:00
} else
# endif
# ifdef GLX_MESA_swap_control
2021-12-27 20:02:45 +01:00
if ( GlxVSyncEnabled > 0 & & GlxSwapIntervalSGI ) {
2019-10-26 18:42:19 +02:00
if ( GlxSwapIntervalSGI ( 1 ) ) {
GlxCheck ( ) ;
Warning ( _ ( " video/glx: SGI can't enable v-sync \n " ) ) ;
} else {
Info ( _ ( " video/glx: SGI v-sync enabled \n " ) ) ;
}
2018-08-19 11:45:46 +02:00
}
# endif
}
2019-10-26 18:42:19 +02:00
# else // VAAPI
2021-12-27 20:02:45 +01:00
static void EglInit ( void ) {
2019-10-26 18:42:19 +02:00
int redSize , greenSize , blueSize , alphaSize ;
2020-01-07 22:22:07 +01:00
static int glewdone = 0 ;
2020-04-10 16:17:23 +02:00
2021-01-10 13:55:09 +01:00
# if defined PLACEBO && !defined PLACEBO_GL
2019-10-26 18:42:19 +02:00
return ;
2019-10-04 10:37:57 +02:00
# endif
2019-10-26 18:42:19 +02:00
EGLContext context ;
2019-10-04 10:37:57 +02:00
// create egl context
2021-12-27 20:02:45 +01:00
// setenv("MESA_GL_VERSION_OVERRIDE", "3.3", 0);
// setenv("V3D_DOUBLE_BUFFER", "1", 0);
2019-10-04 10:37:57 +02:00
make_egl ( ) ;
2020-04-10 16:17:23 +02:00
if ( ! glewdone ) {
2020-01-07 22:22:07 +01:00
GLenum err = glewInit ( ) ;
2020-04-10 16:17:23 +02:00
glewdone = 1 ;
2021-12-27 20:02:45 +01:00
// if (err != GLEW_OK) {
// Debug(3, "Error: %s\n", glewGetErrorString(err));
// }
2020-04-10 16:17:23 +02:00
}
2019-10-26 18:42:19 +02:00
eglGetConfigAttrib ( eglDisplay , eglConfig , EGL_BLUE_SIZE , & blueSize ) ;
eglGetConfigAttrib ( eglDisplay , eglConfig , EGL_RED_SIZE , & redSize ) ;
eglGetConfigAttrib ( eglDisplay , eglConfig , EGL_GREEN_SIZE , & greenSize ) ;
eglGetConfigAttrib ( eglDisplay , eglConfig , EGL_ALPHA_SIZE , & alphaSize ) ;
Debug ( 3 , " RGB size %d:%d:%d Alpha %d \n " , redSize , greenSize , blueSize , alphaSize ) ;
2019-10-04 10:37:57 +02:00
eglSharedContext = eglContext ;
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
context = eglCreateContext ( eglDisplay , eglConfig , eglSharedContext , eglAttrs ) ;
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
EglCheck ( ) ;
2019-10-04 10:37:57 +02:00
if ( ! context ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video/egl: can't create egl context \n " ) ) ;
2019-10-04 10:37:57 +02:00
}
eglContext = context ;
2019-10-26 18:42:19 +02:00
}
2019-10-04 10:37:57 +02:00
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Cleanup GLX.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void EglExit ( void ) {
2019-10-04 10:37:57 +02:00
Debug ( 3 , " video/egl: %s \n " , __FUNCTION__ ) ;
2021-01-10 13:55:09 +01:00
# if defined PLACEBO && !defined PLACEBO_GL
2019-10-26 18:42:19 +02:00
return ;
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
glFinish ( ) ;
2019-10-04 10:37:57 +02:00
// must destroy contet
# ifdef CUVID
2019-10-26 18:42:19 +02:00
// must destroy glx
2019-10-28 21:43:37 +01:00
// if (glXGetCurrentContext() == glxContext) {
2019-10-26 18:42:19 +02:00
// if currently used, set to none
2022-07-09 12:52:28 +02:00
// glXMakeCurrent(XlibDisplay, None, NULL);
2019-10-28 21:43:37 +01:00
// }
2019-10-20 14:48:28 +02:00
if ( OSDcontext ) {
2019-10-26 18:42:19 +02:00
glXDestroyContext ( XlibDisplay , OSDcontext ) ;
GlxCheck ( ) ;
OSDcontext = NULL ;
2018-08-19 11:45:46 +02:00
}
2019-10-20 14:48:28 +02:00
if ( glxContext ) {
2019-10-26 18:42:19 +02:00
glXDestroyContext ( XlibDisplay , glxContext ) ;
GlxCheck ( ) ;
glxContext = NULL ;
2018-08-19 11:45:46 +02:00
}
2020-01-07 22:22:07 +01:00
2019-10-20 14:48:28 +02:00
if ( glxSharedContext ) {
2019-10-26 18:42:19 +02:00
glXDestroyContext ( XlibDisplay , glxSharedContext ) ;
GlxCheck ( ) ;
glxSharedContext = NULL ;
}
2019-10-04 10:37:57 +02:00
# else
if ( eglGetCurrentContext ( ) = = eglContext ) {
2019-10-26 18:42:19 +02:00
// if currently used, set to none
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2019-10-04 10:37:57 +02:00
}
2020-01-07 22:22:07 +01:00
# ifndef USE_DRM
2019-10-04 10:37:57 +02:00
if ( eglSharedContext ) {
2019-10-26 18:42:19 +02:00
eglDestroyContext ( eglDisplay , eglSharedContext ) ;
EglCheck ( ) ;
2019-10-04 10:37:57 +02:00
}
2020-01-07 22:22:07 +01:00
2019-10-04 10:37:57 +02:00
if ( eglContext ) {
2019-10-26 18:42:19 +02:00
eglDestroyContext ( eglDisplay , eglContext ) ;
EglCheck ( ) ;
2020-04-10 16:17:23 +02:00
eglContext = NULL ;
2019-10-04 10:37:57 +02:00
}
2020-01-07 22:22:07 +01:00
2019-10-26 18:42:19 +02:00
eglTerminate ( eglDisplay ) ;
2019-10-04 10:37:57 +02:00
# endif
2020-04-10 16:17:23 +02:00
2020-01-07 22:22:07 +01:00
# ifdef USE_DRM
2020-04-10 16:17:23 +02:00
drm_clean_up ( ) ;
# endif
2020-01-07 22:22:07 +01:00
# endif
2018-08-19 11:45:46 +02:00
}
# endif
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// common functions
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Calculate resolution group.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param width video picture raw width
/// @param height video picture raw height
2021-12-27 20:02:45 +01:00
/// @param interlace flag interlaced video picture
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note interlace isn't used yet and probably wrong set by caller.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static VideoResolutions VideoResolutionGroup ( int width , int height , __attribute__ ( ( unused ) ) int interlace ) {
2018-08-19 11:45:46 +02:00
if ( height = = 2160 ) {
2019-10-26 18:42:19 +02:00
return VideoResolutionUHD ;
2018-08-19 11:45:46 +02:00
}
if ( height < = 576 ) {
2019-10-26 18:42:19 +02:00
return VideoResolution576i ;
2018-08-19 11:45:46 +02:00
}
if ( height < = 720 ) {
2019-10-26 18:42:19 +02:00
return VideoResolution720p ;
2018-08-19 11:45:46 +02:00
}
2018-10-12 15:12:30 +02:00
if ( height < 1080 ) {
2019-10-26 18:42:19 +02:00
return VideoResolutionFake1080i ;
2018-08-19 11:45:46 +02:00
}
if ( width < 1920 ) {
2019-10-26 18:42:19 +02:00
return VideoResolutionFake1080i ;
2018-08-19 11:45:46 +02:00
}
return VideoResolution1080i ;
}
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// CUVID
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
# ifdef USE_CUVID
2018-11-05 10:42:33 +01:00
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
struct ext_buf {
2018-11-04 13:44:18 +01:00
int fd ;
2019-08-22 12:34:29 +02:00
# ifdef CUVID
2018-11-04 13:44:18 +01:00
CUexternalMemory mem ;
2019-10-26 18:42:19 +02:00
CUmipmappedArray mma ;
CUexternalSemaphore ss ;
CUexternalSemaphore ws ;
const struct pl_sysnc * sysnc ;
2019-08-22 12:34:29 +02:00
# endif
2018-11-04 13:44:18 +01:00
} ;
2018-11-05 10:42:33 +01:00
# endif
2018-11-04 13:44:18 +01:00
2019-08-22 12:34:29 +02:00
# ifdef VAAPI
2021-12-27 20:02:45 +01:00
static VADisplay * VaDisplay ; ///< VA-API display
2019-08-22 12:34:29 +02:00
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// CUVID decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
typedef struct _cuvid_decoder_ {
2019-10-26 18:42:19 +02:00
# ifdef VAAPI
2021-12-27 20:02:45 +01:00
VADisplay * VaDisplay ; ///< VA-API display
2019-08-22 12:34:29 +02:00
# endif
2021-12-27 20:02:45 +01:00
xcb_window_t Window ; ///< output window
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int VideoX ; ///< video base x coordinate
int VideoY ; ///< video base y coordinate
int VideoWidth ; ///< video base width
int VideoHeight ; ///< video base height
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int OutputX ; ///< real video output x coordinate
int OutputY ; ///< real video output y coordinate
int OutputWidth ; ///< real video output width
int OutputHeight ; ///< real video output height
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
enum AVPixelFormat PixFmt ; ///< ffmpeg frame pixfmt
enum AVColorSpace ColorSpace ; /// ffmpeg ColorSpace
2019-10-26 18:42:19 +02:00
enum AVColorTransferCharacteristic trc ; //
enum AVColorPrimaries color_primaries ;
2021-12-27 20:02:45 +01:00
int WrongInterlacedWarned ; ///< warning about interlace flag issued
int Interlaced ; ///< ffmpeg interlaced flag
int TopFieldFirst ; ///< ffmpeg top field displayed first
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int InputWidth ; ///< video input width
int InputHeight ; ///< video input height
AVRational InputAspect ; ///< video input aspect ratio
VideoResolutions Resolution ; ///< resolution group
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int CropX ; ///< video crop x
int CropY ; ///< video crop y
int CropWidth ; ///< video crop width
int CropHeight ; ///< video crop height
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int grabwidth , grabheight , grab ; // Grab Data
2019-10-26 18:42:19 +02:00
void * grabbase ;
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
int SurfacesNeeded ; ///< number of surface to request
int SurfaceUsedN ; ///< number of used video surfaces
2018-08-19 11:45:46 +02:00
/// used video surface ids
int SurfacesUsed [ CODEC_SURFACES_MAX ] ;
2021-12-27 20:02:45 +01:00
int SurfaceFreeN ; ///< number of free video surfaces
2018-08-19 11:45:46 +02:00
/// free video surface ids
int SurfacesFree [ CODEC_SURFACES_MAX ] ;
/// video surface ring buffer
int SurfacesRb [ VIDEO_SURFACES_MAX ] ;
2019-10-28 21:43:37 +01:00
// CUcontext cuda_ctx;
2019-10-26 18:42:19 +02:00
2019-10-28 21:43:37 +01:00
// cudaStream_t stream; // make my own cuda stream
// CUgraphicsResource cuResource;
2021-12-27 20:02:45 +01:00
int SurfaceWrite ; ///< write pointer
int SurfaceRead ; ///< read pointer
atomic_t SurfacesFilled ; ///< how many of the buffer is used
2019-10-26 18:42:19 +02:00
AVFrame * frames [ CODEC_SURFACES_MAX + 1 ] ;
# ifdef CUVID
CUarray cu_array [ CODEC_SURFACES_MAX + 1 ] [ 2 ] ;
CUgraphicsResource cu_res [ CODEC_SURFACES_MAX + 1 ] [ 2 ] ;
CUcontext cuda_ctx ;
# endif
2021-12-27 20:02:45 +01:00
GLuint gl_textures [ ( CODEC_SURFACES_MAX + 1 ) * 2 ] ; // where we will copy the CUDA result
2019-10-04 10:37:57 +02:00
# ifdef VAAPI
2019-10-26 18:42:19 +02:00
EGLImageKHR images [ ( CODEC_SURFACES_MAX + 1 ) * 2 ] ;
int fds [ ( CODEC_SURFACES_MAX + 1 ) * 2 ] ;
2019-10-04 10:37:57 +02:00
# endif
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
struct pl_frame pl_frames [ CODEC_SURFACES_MAX + 1 ] ; // images for Placebo chain
struct ext_buf ebuf [ CODEC_SURFACES_MAX + 1 ] ; // for managing vk buffer
2019-10-26 18:42:19 +02:00
# endif
2021-12-27 20:02:45 +01:00
int SurfaceField ; ///< current displayed field
int TrickSpeed ; ///< current trick speed
int TrickCounter ; ///< current trick speed counter
struct timespec FrameTime ; ///< time of last display
VideoStream * Stream ; ///< video stream
int Closing ; ///< flag about closing current stream
int SyncOnAudio ; ///< flag sync to audio
int64_t PTS ; ///< video PTS clock
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
# if defined(YADIF) || defined(VAAPI)
2019-10-26 18:42:19 +02:00
AVFilterContext * buffersink_ctx ;
AVFilterContext * buffersrc_ctx ;
AVFilterGraph * filter_graph ;
# endif
2020-04-10 16:17:23 +02:00
AVBufferRef * cached_hw_frames_ctx ;
2021-12-27 20:02:45 +01:00
int LastAVDiff ; ///< last audio - video difference
int SyncCounter ; ///< counter to sync frames
int StartCounter ; ///< counter for video start
int FramesDuped ; ///< number of frames duplicated
int FramesMissed ; ///< number of frames missed
int FramesDropped ; ///< number of frames dropped
int FrameCounter ; ///< number of frames decoded
int FramesDisplayed ; ///< number of frames displayed
float Frameproc ; /// Time to process frame
2019-10-26 18:42:19 +02:00
int newchannel ;
2018-08-19 11:45:46 +02:00
} CuvidDecoder ;
2021-12-27 20:02:45 +01:00
static CuvidDecoder * CuvidDecoders [ 2 ] ; ///< open decoder streams
static int CuvidDecoderN ; ///< number of decoder streams
2020-03-06 13:03:21 +01:00
# ifdef CUVID
2020-03-06 12:42:14 +01:00
static CudaFunctions * cu ;
2020-03-06 13:03:21 +01:00
# endif
2018-08-19 11:45:46 +02:00
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2021-03-16 09:40:08 +01:00
2021-12-27 20:02:45 +01:00
struct file {
2021-03-16 09:40:08 +01:00
void * data ;
size_t size ;
} ;
2021-12-27 20:02:45 +01:00
typedef struct priv {
2023-02-15 15:58:51 +01:00
# if PL_API_VER >= 229
const struct pl_gpu_t * gpu ;
const struct pl_vulkan_t * vk ;
const struct pl_vk_inst_t * vk_inst ;
# else
2019-10-26 18:42:19 +02:00
const struct pl_gpu * gpu ;
const struct pl_vulkan * vk ;
const struct pl_vk_inst * vk_inst ;
2023-02-15 15:58:51 +01:00
# endif
2019-10-26 18:42:19 +02:00
struct pl_context * ctx ;
2021-03-16 09:40:08 +01:00
struct pl_custom_lut * lut ;
2019-10-26 18:42:19 +02:00
struct pl_renderer * renderer ;
struct pl_renderer * renderertest ;
const struct pl_swapchain * swapchain ;
2023-02-15 15:58:51 +01:00
struct pl_log_params context ;
2020-05-01 12:06:04 +02:00
# ifndef PLACEBO_GL
2019-10-26 18:42:19 +02:00
VkSurfaceKHR pSurface ;
2020-05-01 12:06:04 +02:00
# endif
2019-10-26 18:42:19 +02:00
int has_dma_buf ;
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
2023-02-16 12:50:57 +01:00
# if PL_API_VER >= 229
struct pl_opengl_t * gl ;
# else
2020-05-01 12:06:04 +02:00
struct pl_opengl * gl ;
2023-02-16 12:50:57 +01:00
# endif
2020-05-01 12:06:04 +02:00
# endif
2020-06-07 12:31:18 +02:00
const struct pl_hook * hook [ NUM_SHADERS ] ;
int num_shaders ;
2021-03-16 09:40:08 +01:00
2019-10-26 18:42:19 +02:00
} priv ;
2020-06-07 12:31:18 +02:00
2018-11-17 14:58:25 +01:00
static priv * p ;
static struct pl_overlay osdoverlay ;
2023-02-15 15:58:51 +01:00
# if PL_API_VER >= 229
static struct pl_overlay_part part ;
# endif
2018-11-17 14:58:25 +01:00
2019-04-05 07:20:52 +02:00
static int semid ;
struct itimerval itimer ;
2018-11-04 13:44:18 +01:00
# endif
2018-11-05 10:38:27 +01:00
2019-10-28 21:43:37 +01:00
GLuint vao_buffer ;
2018-11-17 14:58:25 +01:00
2021-12-27 20:02:45 +01:00
// GLuint vao_vao[4];
GLuint gl_shader = 0 , gl_prog = 0 , gl_fbo = 0 ; // shader programm
2019-10-26 18:42:19 +02:00
GLint gl_colormatrix , gl_colormatrix_c ;
GLuint OSDfb = 0 ;
GLuint OSDtexture , gl_prog_osd = 0 ;
2018-09-28 17:02:56 +02:00
2019-10-26 18:42:19 +02:00
int OSDx , OSDy , OSDxsize , OSDysize ;
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
static struct timespec CuvidFrameTime ; ///< time of last display
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
int window_width , window_height ;
2018-08-19 11:45:46 +02:00
# include "shaders.h"
2018-10-12 12:51:52 +02:00
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Output video messages.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Reduce output.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param level message level (Error, Warning, Info, Debug, ...)
/// @param format printf format string (NULL to flush messages)
2021-12-27 20:02:45 +01:00
/// @param ... printf arguments
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns true, if message shown
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
int CuvidMessage ( int level , const char * format , . . . ) {
2018-08-19 11:45:46 +02:00
if ( SysLogLevel > level | | DebugLevel > level ) {
2019-10-26 18:42:19 +02:00
static const char * last_format ;
static char buf [ 256 ] ;
va_list ap ;
va_start ( ap , format ) ;
2021-12-27 20:02:45 +01:00
if ( format ! = last_format ) { // don't repeat same message
if ( buf [ 0 ] ) { // print last repeated message
2019-10-26 18:42:19 +02:00
syslog ( LOG_ERR , " %s " , buf ) ;
buf [ 0 ] = ' \0 ' ;
}
if ( format ) {
last_format = format ;
vsyslog ( LOG_ERR , format , ap ) ;
}
va_end ( ap ) ;
return 1 ;
}
vsnprintf ( buf , sizeof ( buf ) , format , ap ) ;
va_end ( ap ) ;
2018-08-19 11:45:46 +02:00
}
return 0 ;
}
2018-10-14 13:05:22 +02:00
////////////////////////////////////////////////////////////////////////////////
// These are CUDA Helper functions
2019-08-22 12:34:29 +02:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
// This will output the proper CUDA error strings in the event that a CUDA host
// call returns an error
# define checkCudaErrors(err) __checkCudaErrors(err, __FILE__, __LINE__)
2018-10-14 13:05:22 +02:00
// These are the inline versions for all of the SDK helper functions
2021-12-27 20:02:45 +01:00
static inline void __checkCudaErrors ( CUresult err , const char * file , const int line ) {
2019-10-26 18:42:19 +02:00
if ( CUDA_SUCCESS ! = err ) {
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 ,
" checkCudaErrors() Driver API error = %04d >%s< from file "
" <%s>, line %i. \n " ,
err , getCudaDrvErrorString ( err ) , file , line ) ;
2018-10-14 13:05:22 +02:00
exit ( EXIT_FAILURE ) ;
}
}
2019-08-22 12:34:29 +02:00
# endif
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
// Surfaces -------------------------------------------------------------
2021-12-27 20:02:45 +01:00
void createTextureDst ( CuvidDecoder * decoder , int anz , unsigned int size_x , unsigned int size_y ,
enum AVPixelFormat PixFmt ) ;
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Create surfaces for CUVID decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
/// @param width surface source/video width
/// @param height surface source/video height
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidCreateSurfaces ( CuvidDecoder * decoder , int width , int height , enum AVPixelFormat PixFmt ) {
2018-08-19 11:45:46 +02:00
int i ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
# ifdef DEBUG
if ( ! decoder - > SurfacesNeeded ) {
2019-10-26 18:42:19 +02:00
Error ( _ ( " video/cuvid: surface needed not set \n " ) ) ;
decoder - > SurfacesNeeded = VIDEO_SURFACES_MAX ;
2018-08-19 11:45:46 +02:00
}
# endif
2018-10-10 20:11:43 +02:00
Debug ( 3 , " video/cuvid: %s: %dx%d * %d \n " , __FUNCTION__ , width , height , decoder - > SurfacesNeeded ) ;
2018-08-19 11:45:46 +02:00
// allocate only the number of needed surfaces
decoder - > SurfaceFreeN = decoder - > SurfacesNeeded ;
2019-10-26 18:42:19 +02:00
createTextureDst ( decoder , decoder - > SurfacesNeeded , width , height , PixFmt ) ;
for ( i = 0 ; i < decoder - > SurfaceFreeN ; + + i ) {
decoder - > SurfacesFree [ i ] = i ;
}
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 4 , " video/cuvid: created video surface %dx%d with id %d \n " , width , height , decoder - > SurfacesFree [ i ] ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Destroy surfaces of CUVID decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidDestroySurfaces ( CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
int i , j ;
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video/cuvid: %s \n " , __FUNCTION__ ) ;
2019-10-26 18:42:19 +02:00
2018-11-17 14:58:25 +01:00
# ifndef PLACEBO
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
glXMakeCurrent ( XlibDisplay , VideoWindow , glxSharedContext ) ;
GlxCheck ( ) ;
2019-10-04 10:37:57 +02:00
# else
2019-10-26 18:42:19 +02:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglContext ) ;
EglCheck ( ) ;
# endif
# endif
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO
2020-06-22 16:35:37 +02:00
pl_gpu_finish ( p - > gpu ) ;
2021-12-27 20:02:45 +01:00
# if API_VER >= 58
2020-06-07 12:31:18 +02:00
p - > num_shaders = 0 ;
2020-06-22 16:35:37 +02:00
# endif
# endif
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
for ( i = 0 ; i < decoder - > SurfacesNeeded ; i + + ) {
if ( decoder - > frames [ i ] ) {
av_frame_free ( & decoder - > frames [ i ] ) ;
}
2019-12-23 11:14:38 +01:00
for ( j = 0 ; j < Planes ; j + + ) {
2019-10-26 18:42:19 +02:00
# ifdef PLACEBO
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ i ] . planes [ j ] . texture ) {
2019-10-26 18:42:19 +02:00
# ifdef VAAPI
2021-03-16 09:40:08 +01:00
if ( p - > has_dma_buf & & decoder - > pl_frames [ i ] . planes [ j ] . texture - > params . shared_mem . handle . fd ) {
close ( decoder - > pl_frames [ i ] . planes [ j ] . texture - > params . shared_mem . handle . fd ) ;
2019-10-26 18:42:19 +02:00
}
# endif
2021-01-28 12:59:58 +01:00
SharedContext ;
2021-03-16 09:40:08 +01:00
pl_tex_destroy ( p - > gpu , & decoder - > pl_frames [ i ] . planes [ j ] . texture ) ;
2021-01-28 12:59:58 +01:00
NoContext ;
2019-10-26 18:42:19 +02:00
}
2018-11-04 13:44:18 +01:00
# else
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuGraphicsUnregisterResource ( decoder - > cu_res [ i ] [ j ] ) ) ;
2019-10-04 10:37:57 +02:00
# endif
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO
2021-01-28 12:59:58 +01:00
if ( p - > hasdma_buf ) {
2021-01-10 13:55:09 +01:00
# endif
2021-01-11 16:13:04 +01:00
# ifdef VAAPI
2021-01-28 12:59:58 +01:00
if ( decoder - > images [ i * Planes + j ] ) {
DestroyImageKHR ( eglGetCurrentDisplay ( ) , decoder - > images [ i * Planes + j ] ) ;
if ( decoder - > fds [ i * Planes + j ] )
close ( decoder - > fds [ i * Planes + j ] ) ;
}
decoder - > fds [ i * Planes + j ] = 0 ;
decoder - > images [ i * Planes + j ] = 0 ;
2021-01-11 16:13:04 +01:00
# endif
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO
2021-01-28 12:59:58 +01:00
}
2019-10-04 10:37:57 +02:00
# endif
2018-11-04 13:44:18 +01:00
# endif
2019-10-26 18:42:19 +02:00
}
}
2020-06-07 12:31:18 +02:00
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2020-06-07 12:31:18 +02:00
2021-12-27 20:02:45 +01:00
// pl_renderer_destroy(&p->renderer);
// p->renderer = pl_renderer_create(p->ctx, p->gpu);
2020-06-07 12:31:18 +02:00
2018-11-04 13:44:18 +01:00
# else
2021-12-27 20:02:45 +01:00
glDeleteTextures ( CODEC_SURFACES_MAX * 2 , ( GLuint * ) & decoder - > gl_textures ) ;
2019-10-26 18:42:19 +02:00
GlxCheck ( ) ;
2021-12-27 20:02:45 +01:00
if ( CuvidDecoderN = = 1 ) { // only wenn last decoder closes
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Last decoder closes \n " ) ;
2021-12-27 20:02:45 +01:00
glDeleteBuffers ( 1 , ( GLuint * ) & vao_buffer ) ;
2019-10-26 18:42:19 +02:00
if ( gl_prog )
glDeleteProgram ( gl_prog ) ;
gl_prog = 0 ;
}
# endif
2021-12-27 20:02:45 +01:00
2018-08-19 11:45:46 +02:00
for ( i = 0 ; i < decoder - > SurfaceFreeN ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesFree [ i ] = - 1 ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
for ( i = 0 ; i < decoder - > SurfaceUsedN ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesUsed [ i ] = - 1 ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
decoder - > SurfaceFreeN = 0 ;
decoder - > SurfaceUsedN = 0 ;
}
///
2019-10-26 18:42:19 +02:00
/// Get a free surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns the oldest free surface
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int CuvidGetVideoSurface0 ( CuvidDecoder * decoder ) {
2018-08-19 11:45:46 +02:00
int surface ;
int i ;
if ( ! decoder - > SurfaceFreeN ) {
2019-10-28 21:43:37 +01:00
// Error(_("video/cuvid: out of surfaces\n"));
2019-10-26 18:42:19 +02:00
return - 1 ;
2018-08-19 11:45:46 +02:00
}
// use oldest surface
surface = decoder - > SurfacesFree [ 0 ] ;
decoder - > SurfaceFreeN - - ;
for ( i = 0 ; i < decoder - > SurfaceFreeN ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesFree [ i ] = decoder - > SurfacesFree [ i + 1 ] ;
2018-08-19 11:45:46 +02:00
}
decoder - > SurfacesFree [ i ] = - 1 ;
// save as used
decoder - > SurfacesUsed [ decoder - > SurfaceUsedN + + ] = surface ;
return surface ;
}
///
2019-10-26 18:42:19 +02:00
/// Release a surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
/// @param surface surface no longer used
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidReleaseSurface ( CuvidDecoder * decoder , int surface ) {
2018-08-19 11:45:46 +02:00
int i ;
2019-10-26 18:42:19 +02:00
if ( decoder - > frames [ surface ] ) {
av_frame_free ( & decoder - > frames [ surface ] ) ;
}
# ifdef PLACEBO
2021-01-28 12:59:58 +01:00
SharedContext ;
2019-10-26 18:42:19 +02:00
if ( p - > has_dma_buf ) {
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ surface ] . planes [ 0 ] . texture ) {
if ( decoder - > pl_frames [ surface ] . planes [ 0 ] . texture - > params . shared_mem . handle . fd ) {
close ( decoder - > pl_frames [ surface ] . planes [ 0 ] . texture - > params . shared_mem . handle . fd ) ;
2019-10-26 18:42:19 +02:00
}
2021-03-16 09:40:08 +01:00
pl_tex_destroy ( p - > gpu , & decoder - > pl_frames [ surface ] . planes [ 0 ] . texture ) ;
2019-10-26 18:42:19 +02:00
}
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ surface ] . planes [ 1 ] . texture ) {
if ( decoder - > pl_frames [ surface ] . planes [ 1 ] . texture - > params . shared_mem . handle . fd ) {
close ( decoder - > pl_frames [ surface ] . planes [ 1 ] . texture - > params . shared_mem . handle . fd ) ;
2019-10-26 18:42:19 +02:00
}
2021-03-16 09:40:08 +01:00
pl_tex_destroy ( p - > gpu , & decoder - > pl_frames [ surface ] . planes [ 1 ] . texture ) ;
2019-10-26 18:42:19 +02:00
}
}
2021-01-28 12:59:58 +01:00
NoContext ;
2019-10-04 10:37:57 +02:00
# else
2020-04-10 16:17:23 +02:00
# ifdef VAAPI
if ( decoder - > images [ surface * Planes ] ) {
DestroyImageKHR ( eglGetCurrentDisplay ( ) , decoder - > images [ surface * Planes ] ) ;
DestroyImageKHR ( eglGetCurrentDisplay ( ) , decoder - > images [ surface * Planes + 1 ] ) ;
2021-11-19 17:46:38 +01:00
2020-04-10 16:17:23 +02:00
if ( decoder - > fds [ surface * Planes ] ) {
close ( decoder - > fds [ surface * Planes ] ) ;
2021-11-19 17:46:38 +01:00
}
2021-12-27 20:02:45 +01:00
if ( decoder - > fds [ surface * Planes + 1 ] ) {
close ( decoder - > fds [ surface * Planes + 1 ] ) ;
2020-04-10 16:17:23 +02:00
}
}
decoder - > fds [ surface * Planes ] = 0 ;
decoder - > fds [ surface * Planes + 1 ] = 0 ;
decoder - > images [ surface * Planes ] = 0 ;
decoder - > images [ surface * Planes + 1 ] = 0 ;
2019-10-04 10:37:57 +02:00
# endif
2019-08-22 12:34:29 +02:00
# endif
2018-08-19 11:45:46 +02:00
for ( i = 0 ; i < decoder - > SurfaceUsedN ; + + i ) {
2019-10-26 18:42:19 +02:00
if ( decoder - > SurfacesUsed [ i ] = = surface ) {
// no problem, with last used
decoder - > SurfacesUsed [ i ] = decoder - > SurfacesUsed [ - - decoder - > SurfaceUsedN ] ;
decoder - > SurfacesFree [ decoder - > SurfaceFreeN + + ] = surface ;
return ;
}
2018-08-19 11:45:46 +02:00
}
Fatal ( _ ( " video/cuvid: release surface %#08x, which is not in use \n " ) , surface ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Debug CUVID decoder frames drop...
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidPrintFrames ( const CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/cuvid: %d missed, %d duped, %d dropped frames of %d,%d \n " , decoder - > FramesMissed ,
2021-12-27 20:02:45 +01:00
decoder - > FramesDuped , decoder - > FramesDropped , decoder - > FrameCounter , decoder - > FramesDisplayed ) ;
2018-08-19 11:45:46 +02:00
# ifndef DEBUG
( void ) decoder ;
# endif
2019-10-04 10:37:57 +02:00
}
2021-12-27 20:02:45 +01:00
int CuvidTestSurfaces ( ) {
2020-04-10 16:17:23 +02:00
int i = 0 ;
2019-10-26 18:42:19 +02:00
if ( CuvidDecoders [ 0 ] ! = NULL ) {
2020-04-10 16:17:23 +02:00
if ( i = atomic_read ( & CuvidDecoders [ 0 ] - > SurfacesFilled ) < VIDEO_SURFACES_MAX - 1 )
2019-12-10 10:45:22 +01:00
return i ;
2019-10-26 18:42:19 +02:00
return 0 ;
} else
return 0 ;
2019-10-04 10:37:57 +02:00
}
# ifdef VAAPI
2021-12-27 20:02:45 +01:00
struct mp_egl_config_attr {
2019-10-04 10:37:57 +02:00
int attrib ;
const char * name ;
} ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
# define MPGL_VER(major, minor) (((major)*100) + (minor)*10)
2019-10-04 10:37:57 +02:00
# define MPGL_VER_GET_MAJOR(ver) ((unsigned)(ver) / 100)
# define MPGL_VER_GET_MINOR(ver) ((unsigned)(ver) % 100 / 10)
2021-12-27 20:02:45 +01:00
# define MP_EGL_ATTRIB(id) \
{ id , # id }
2019-10-04 10:37:57 +02:00
static const struct mp_egl_config_attr mp_egl_attribs [ ] = {
2021-12-27 20:02:45 +01:00
MP_EGL_ATTRIB ( EGL_CONFIG_ID ) , MP_EGL_ATTRIB ( EGL_RED_SIZE ) , MP_EGL_ATTRIB ( EGL_GREEN_SIZE ) ,
MP_EGL_ATTRIB ( EGL_BLUE_SIZE ) , MP_EGL_ATTRIB ( EGL_ALPHA_SIZE ) , MP_EGL_ATTRIB ( EGL_COLOR_BUFFER_TYPE ) ,
MP_EGL_ATTRIB ( EGL_CONFIG_CAVEAT ) , MP_EGL_ATTRIB ( EGL_CONFORMANT ) ,
2019-10-04 10:37:57 +02:00
} ;
2021-12-27 20:02:45 +01:00
const int mpgl_preferred_gl_versions [ ] = { 460 , 440 , 430 , 400 , 330 , 320 , 310 , 300 , 210 , 0 } ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
static bool create_context_cb ( EGLDisplay display , int es_version , EGLContext * out_context , EGLConfig * out_config ,
int * bpp ) {
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
EGLenum api ;
EGLint rend , * attribs ;
const char * name ;
switch ( es_version ) {
2019-10-26 18:42:19 +02:00
case 0 :
api = EGL_OPENGL_API ;
rend = EGL_OPENGL_BIT ;
name = " Desktop OpenGL " ;
break ;
case 2 :
api = EGL_OPENGL_ES_API ;
rend = EGL_OPENGL_ES2_BIT ;
name = " GLES 2.x " ;
break ;
case 3 :
api = EGL_OPENGL_ES_API ;
rend = EGL_OPENGL_ES3_BIT ;
name = " GLES 3.x " ;
break ;
default :
2021-12-27 20:02:45 +01:00
Fatal ( _ ( " Wrong ES version \n " ) ) ;
;
2019-10-26 18:42:19 +02:00
}
2019-10-04 10:37:57 +02:00
if ( ! eglBindAPI ( api ) ) {
Fatal ( _ ( " Could not bind API! \n " ) ) ;
}
2021-12-27 20:02:45 +01:00
2021-01-28 12:59:58 +01:00
Debug ( 3 , " Trying to create %s context \n " , name ) ;
2021-12-27 20:02:45 +01:00
2019-10-04 10:37:57 +02:00
EGLint attributes8 [ ] = {
2021-12-27 20:02:45 +01:00
EGL_SURFACE_TYPE , EGL_WINDOW_BIT , EGL_RED_SIZE , 8 , EGL_GREEN_SIZE , 8 , EGL_BLUE_SIZE , 8 , EGL_ALPHA_SIZE , 8 ,
EGL_RENDERABLE_TYPE , rend , EGL_NONE } ;
EGLint attributes10 [ ] = { EGL_SURFACE_TYPE ,
EGL_WINDOW_BIT ,
EGL_RED_SIZE ,
10 ,
EGL_GREEN_SIZE ,
10 ,
EGL_BLUE_SIZE ,
10 ,
EGL_ALPHA_SIZE ,
2 ,
EGL_RENDERABLE_TYPE ,
rend ,
EGL_NONE } ;
2020-04-10 16:17:23 +02:00
EGLint num_configs = 0 ;
2019-10-26 18:42:19 +02:00
attribs = attributes10 ;
2019-12-10 10:45:22 +01:00
* bpp = 10 ;
2021-12-27 20:02:45 +01:00
if ( ! eglChooseConfig ( display , attributes10 , NULL , 0 ,
& num_configs ) ) { // try 10 Bit
2021-03-16 09:40:08 +01:00
EglCheck ( ) ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " 10 Bit egl Failed \n " ) ;
attribs = attributes8 ;
2019-12-10 10:45:22 +01:00
* bpp = 8 ;
2021-12-27 20:02:45 +01:00
if ( ! eglChooseConfig ( display , attributes8 , NULL , 0 ,
& num_configs ) ) { // try 8 Bit
2019-10-26 18:42:19 +02:00
num_configs = 0 ;
}
2022-05-24 00:09:55 +02:00
} else if ( num_configs = = 0 ) {
2019-10-26 18:42:19 +02:00
EglCheck ( ) ;
Debug ( 3 , " 10 Bit egl Failed \n " ) ;
attribs = attributes8 ;
2019-12-10 10:45:22 +01:00
* bpp = 8 ;
2021-12-27 20:02:45 +01:00
if ( ! eglChooseConfig ( display , attributes8 , NULL , 0 ,
& num_configs ) ) { // try 8 Bit
2019-10-26 18:42:19 +02:00
num_configs = 0 ;
}
}
2021-12-27 20:02:45 +01:00
2019-10-04 10:37:57 +02:00
EGLConfig * configs = malloc ( sizeof ( EGLConfig ) * num_configs ) ;
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
if ( ! eglChooseConfig ( display , attribs , configs , num_configs , & num_configs ) )
num_configs = 0 ;
if ( ! num_configs ) {
2019-10-26 18:42:19 +02:00
free ( configs ) ;
Debug ( 3 , " Could not choose EGLConfig for %s! \n " , name ) ;
2019-10-04 10:37:57 +02:00
return false ;
}
2019-10-20 14:48:28 +02:00
EGLConfig config = configs [ 0 ] ;
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
free ( configs ) ;
EGLContext * egl_ctx = NULL ;
if ( es_version ) {
eglAttrs [ 0 ] = EGL_CONTEXT_CLIENT_VERSION ;
2019-10-26 18:42:19 +02:00
eglAttrs [ 1 ] = es_version ;
eglAttrs [ 2 ] = EGL_NONE ;
2019-10-04 10:37:57 +02:00
egl_ctx = eglCreateContext ( display , config , EGL_NO_CONTEXT , eglAttrs ) ;
} else {
for ( int n = 0 ; mpgl_preferred_gl_versions [ n ] ; n + + ) {
int ver = mpgl_preferred_gl_versions [ n ] ;
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
eglAttrs [ 0 ] = EGL_CONTEXT_MAJOR_VERSION ;
2019-10-26 18:42:19 +02:00
eglAttrs [ 1 ] = MPGL_VER_GET_MAJOR ( ver ) ;
eglAttrs [ 2 ] = EGL_CONTEXT_MINOR_VERSION ;
eglAttrs [ 3 ] = MPGL_VER_GET_MINOR ( ver ) ;
eglAttrs [ 4 ] = EGL_CONTEXT_OPENGL_PROFILE_MASK ;
eglAttrs [ 5 ] = ver > = 320 ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT : 0 ;
eglAttrs [ 6 ] = EGL_NONE ;
2019-10-04 10:37:57 +02:00
egl_ctx = eglCreateContext ( display , config , EGL_NO_CONTEXT , eglAttrs ) ;
2019-10-26 18:42:19 +02:00
EglCheck ( ) ;
2019-10-04 10:37:57 +02:00
if ( egl_ctx ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Use %d GLVersion \n " , ver ) ;
2019-10-04 10:37:57 +02:00
break ;
2019-10-26 18:42:19 +02:00
}
2019-10-04 10:37:57 +02:00
}
}
if ( ! egl_ctx ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Could not create EGL context for %s! \n " , name ) ;
2019-10-04 10:37:57 +02:00
return false ;
}
* out_context = egl_ctx ;
* out_config = config ;
2019-10-26 18:42:19 +02:00
eglVersion = es_version ;
2019-10-04 10:37:57 +02:00
return true ;
}
2021-12-27 20:02:45 +01:00
make_egl ( ) {
2019-12-10 10:45:22 +01:00
int bpp ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
CreateImageKHR = ( void * ) eglGetProcAddress ( " eglCreateImageKHR " ) ;
DestroyImageKHR = ( void * ) eglGetProcAddress ( " eglDestroyImageKHR " ) ;
EGLImageTargetTexture2DOES = ( void * ) eglGetProcAddress ( " glEGLImageTargetTexture2DOES " ) ;
2019-12-10 10:45:22 +01:00
eglCreateSyncKHR = ( void * ) eglGetProcAddress ( " eglCreateSyncKHR " ) ;
eglDestroySyncKHR = ( void * ) eglGetProcAddress ( " eglDestroySyncKHR " ) ;
eglWaitSyncKHR = ( void * ) eglGetProcAddress ( " eglWaitSyncKHR " ) ;
eglClientWaitSyncKHR = ( void * ) eglGetProcAddress ( " eglClientWaitSyncKHR " ) ;
eglDupNativeFenceFDANDROID = ( void * ) eglGetProcAddress ( " eglDupNativeFenceFDANDROID " ) ;
2020-04-10 16:17:23 +02:00
2019-12-10 10:45:22 +01:00
if ( ! CreateImageKHR | | ! DestroyImageKHR | | ! EGLImageTargetTexture2DOES | | ! eglCreateSyncKHR )
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " Can't get EGL Extentions \n " ) ) ;
2019-12-10 10:45:22 +01:00
# ifndef USE_DRM
2019-10-26 18:42:19 +02:00
eglDisplay = eglGetDisplay ( XlibDisplay ) ;
2019-12-10 10:45:22 +01:00
# endif
2019-10-04 10:37:57 +02:00
if ( ! eglInitialize ( eglDisplay , NULL , NULL ) ) {
Fatal ( _ ( " Could not initialize EGL. \n " ) ) ;
2019-10-26 18:42:19 +02:00
}
2019-12-10 10:45:22 +01:00
if ( ! create_context_cb ( eglDisplay , 0 , & eglContext , & eglConfig , & bpp ) ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " Could not create EGL Context \n " ) ) ;
}
int vID , n ;
2019-10-20 14:48:28 +02:00
2019-10-04 10:37:57 +02:00
eglGetConfigAttrib ( eglDisplay , eglConfig , EGL_NATIVE_VISUAL_ID , & vID ) ;
2020-04-10 16:17:23 +02:00
Debug ( 3 , " chose visual 0x%x bpp %d \n " , vID , bpp ) ;
2019-12-10 10:45:22 +01:00
# ifdef USE_DRM
InitBo ( bpp ) ;
# else
2021-12-27 20:02:45 +01:00
eglSurface = eglCreateWindowSurface ( eglDisplay , eglConfig , ( EGLNativeWindowType ) VideoWindow , NULL ) ;
2019-10-04 10:37:57 +02:00
if ( eglSurface = = EGL_NO_SURFACE ) {
Fatal ( _ ( " Could not create EGL surface! \n " ) ) ;
}
2019-12-10 10:45:22 +01:00
# endif
2019-10-26 18:42:19 +02:00
if ( ! eglMakeCurrent ( eglDisplay , eglSurface , eglSurface , eglContext ) ) {
2019-10-04 10:37:57 +02:00
Fatal ( _ ( " Could not make context current! \n " ) ) ;
}
2019-10-26 18:42:19 +02:00
EglEnabled = 1 ;
}
2019-10-04 10:37:57 +02:00
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Allocate new CUVID decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param stream video stream
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns a new prepared cuvid hardware decoder.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static CuvidDecoder * CuvidNewHwDecoder ( VideoStream * stream ) {
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
CuvidDecoder * decoder ;
2019-08-22 12:34:29 +02:00
2019-10-26 18:42:19 +02:00
int i = 0 ;
2018-08-19 11:45:46 +02:00
2019-10-28 21:43:37 +01:00
// setenv ("DISPLAY", ":0", 0);
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Cuvid New HW Decoder \n " ) ;
if ( ( unsigned ) CuvidDecoderN > = sizeof ( CuvidDecoders ) / sizeof ( * CuvidDecoders ) ) {
Error ( _ ( " video/cuvid: out of decoders \n " ) ) ;
return NULL ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
# ifdef CUVID
2019-01-04 10:08:47 +01:00
if ( ( i = av_hwdevice_ctx_create ( & hw_device_ctx , AV_HWDEVICE_TYPE_CUDA , X11DisplayName , NULL , 0 ) ) ! = 0 ) {
2019-10-26 18:42:19 +02:00
Fatal ( " codec: can't allocate HW video codec context err %04x " , i ) ;
2018-09-28 17:02:56 +02:00
}
2019-08-22 12:34:29 +02:00
# endif
2022-05-24 00:09:55 +02:00
# if defined(VAAPI)
2021-12-27 20:02:45 +01:00
// if ((i = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,
// ":0.0" , NULL, 0)) != 0 ) {
2019-10-26 18:42:19 +02:00
if ( ( i = av_hwdevice_ctx_create ( & hw_device_ctx , AV_HWDEVICE_TYPE_VAAPI , " /dev/dri/renderD128 " , NULL , 0 ) ) ! = 0 ) {
Fatal ( " codec: can't allocate HW video codec context err %04x " , i ) ;
2019-08-22 12:34:29 +02:00
}
# endif
2018-09-28 17:02:56 +02:00
HwDeviceContext = av_buffer_ref ( hw_device_ctx ) ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
if ( ! ( decoder = calloc ( 1 , sizeof ( * decoder ) ) ) ) {
2019-10-26 18:42:19 +02:00
Error ( _ ( " video/cuvid: out of memory \n " ) ) ;
return NULL ;
2018-08-19 11:45:46 +02:00
}
2022-05-24 00:09:55 +02:00
# if defined(VAAPI)
2019-08-22 12:34:29 +02:00
VaDisplay = TO_VAAPI_DEVICE_CTX ( HwDeviceContext ) - > display ;
decoder - > VaDisplay = VaDisplay ;
# endif
2018-08-19 11:45:46 +02:00
decoder - > Window = VideoWindow ;
2019-10-28 21:43:37 +01:00
// decoder->VideoX = 0; // done by calloc
// decoder->VideoY = 0;
2018-08-19 11:45:46 +02:00
decoder - > VideoWidth = VideoWindowWidth ;
decoder - > VideoHeight = VideoWindowHeight ;
for ( i = 0 ; i < CODEC_SURFACES_MAX ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesUsed [ i ] = - 1 ;
decoder - > SurfacesFree [ i ] = - 1 ;
2018-08-19 11:45:46 +02:00
}
//
// setup video surface ring buffer
//
atomic_set ( & decoder - > SurfacesFilled , 0 ) ;
for ( i = 0 ; i < VIDEO_SURFACES_MAX ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesRb [ i ] = - 1 ;
2018-08-19 11:45:46 +02:00
}
decoder - > OutputWidth = VideoWindowWidth ;
decoder - > OutputHeight = VideoWindowHeight ;
decoder - > PixFmt = AV_PIX_FMT_NONE ;
decoder - > Stream = stream ;
2021-12-27 20:02:45 +01:00
if ( ! CuvidDecoderN ) { // FIXME: hack sync on audio
2019-10-26 18:42:19 +02:00
decoder - > SyncOnAudio = 1 ;
2018-08-19 11:45:46 +02:00
}
decoder - > Closing = - 300 - 1 ;
decoder - > PTS = AV_NOPTS_VALUE ;
CuvidDecoders [ CuvidDecoderN + + ] = decoder ;
return decoder ;
}
///
2019-10-26 18:42:19 +02:00
/// Cleanup CUVID.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidCleanup ( CuvidDecoder * decoder ) {
2019-01-04 10:08:47 +01:00
int i ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Cuvid Clean up \n " ) ;
2018-08-19 11:45:46 +02:00
if ( decoder - > SurfaceFreeN | | decoder - > SurfaceUsedN ) {
2019-10-26 18:42:19 +02:00
CuvidDestroySurfaces ( decoder ) ;
2018-08-19 11:45:46 +02:00
}
//
// reset video surface ring buffer
//
atomic_set ( & decoder - > SurfacesFilled , 0 ) ;
for ( i = 0 ; i < VIDEO_SURFACES_MAX ; + + i ) {
2019-10-26 18:42:19 +02:00
decoder - > SurfacesRb [ i ] = - 1 ;
2018-08-19 11:45:46 +02:00
}
decoder - > SurfaceRead = 0 ;
decoder - > SurfaceWrite = 0 ;
decoder - > SurfaceField = 0 ;
decoder - > SyncCounter = 0 ;
decoder - > FrameCounter = 0 ;
decoder - > FramesDisplayed = 0 ;
decoder - > StartCounter = 0 ;
decoder - > Closing = 0 ;
decoder - > PTS = AV_NOPTS_VALUE ;
VideoDeltaPTS = 0 ;
}
///
2019-10-26 18:42:19 +02:00
/// Destroy a CUVID decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidDelHwDecoder ( CuvidDecoder * decoder ) {
2019-01-04 10:08:47 +01:00
int i ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " cuvid del hw decoder \n " ) ;
if ( decoder = = CuvidDecoders [ 0 ] )
VideoThreadLock ( ) ;
2018-11-17 14:58:25 +01:00
# ifndef PLACEBO
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
glXMakeCurrent ( XlibDisplay , VideoWindow , glxSharedContext ) ;
GlxCheck ( ) ;
2019-10-04 10:37:57 +02:00
# else
2019-10-26 18:42:19 +02:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglContext ) ;
EglCheck ( ) ;
2019-10-04 10:37:57 +02:00
# endif
2020-04-10 16:17:23 +02:00
# endif
2019-12-17 11:12:00 +01:00
# if defined PLACEBO || defined VAAPI
2018-08-19 11:45:46 +02:00
if ( decoder - > SurfaceFreeN | | decoder - > SurfaceUsedN ) {
2019-10-26 18:42:19 +02:00
CuvidDestroySurfaces ( decoder ) ;
2018-08-19 11:45:46 +02:00
}
2020-04-10 16:17:23 +02:00
# endif
2019-10-26 18:42:19 +02:00
if ( decoder = = CuvidDecoders [ 0 ] )
VideoThreadUnlock ( ) ;
2018-10-05 14:21:50 +02:00
2019-10-28 21:43:37 +01:00
// glXMakeCurrent(XlibDisplay, None, NULL);
2018-08-19 11:45:46 +02:00
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
2019-10-26 18:42:19 +02:00
if ( CuvidDecoders [ i ] = = decoder ) {
CuvidDecoders [ i ] = NULL ;
// copy last slot into empty slot
if ( i < - - CuvidDecoderN ) {
CuvidDecoders [ i ] = CuvidDecoders [ CuvidDecoderN ] ;
}
2019-10-28 21:43:37 +01:00
// CuvidCleanup(decoder);
2019-10-26 18:42:19 +02:00
CuvidPrintFrames ( decoder ) ;
2019-10-20 14:48:28 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
if ( decoder - > cuda_ctx & & CuvidDecoderN = = 1 ) {
cuCtxDestroy ( decoder - > cuda_ctx ) ;
}
2019-10-20 14:48:28 +02:00
# endif
2019-10-26 18:42:19 +02:00
free ( decoder ) ;
return ;
}
2018-08-19 11:45:46 +02:00
}
Error ( _ ( " video/cuvid: decoder not in decoder list. \n " ) ) ;
}
2021-12-27 20:02:45 +01:00
static int CuvidGlxInit ( __attribute__ ( ( unused ) ) const char * display_name ) {
2020-01-07 22:22:07 +01:00
2020-05-01 12:06:04 +02:00
# if !defined PLACEBO || defined PLACEBO_GL
2019-10-26 18:42:19 +02:00
2019-10-04 10:37:57 +02:00
EglInit ( ) ;
if ( EglEnabled ) {
2019-10-20 14:48:28 +02:00
# ifdef CUVID
GlxSetupWindow ( VideoWindow , VideoWindowWidth , VideoWindowHeight , glxContext ) ;
# else
2019-10-26 18:42:19 +02:00
GlxSetupWindow ( VideoWindow , VideoWindowWidth , VideoWindowHeight , eglContext ) ;
2019-10-20 14:48:28 +02:00
# endif
2018-08-19 11:45:46 +02:00
}
2018-11-17 14:58:25 +01:00
2019-10-04 10:37:57 +02:00
if ( ! EglEnabled ) {
Fatal ( _ ( " video/egl: egl init error \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2018-11-17 14:58:25 +01:00
# else
2019-10-26 18:42:19 +02:00
EglEnabled = 0 ;
2018-11-17 14:58:25 +01:00
# endif
2018-08-19 11:45:46 +02:00
return 1 ;
}
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// CUVID cleanup.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidExit ( void ) {
2018-08-19 11:45:46 +02:00
int i ;
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
2019-10-26 18:42:19 +02:00
if ( CuvidDecoders [ i ] ) {
CuvidDelHwDecoder ( CuvidDecoders [ i ] ) ;
CuvidDecoders [ i ] = NULL ;
}
2018-08-19 11:45:46 +02:00
}
CuvidDecoderN = 0 ;
2019-12-10 10:45:22 +01:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " CuvidExit \n " ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Update output for new size or aspect ratio.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidUpdateOutput ( CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
VideoUpdateOutput ( decoder - > InputAspect , decoder - > InputWidth , decoder - > InputHeight , decoder - > Resolution ,
2021-12-27 20:02:45 +01:00
decoder - > VideoX , decoder - > VideoY , decoder - > VideoWidth , decoder - > VideoHeight , & decoder - > OutputX ,
& decoder - > OutputY , & decoder - > OutputWidth , & decoder - > OutputHeight , & decoder - > CropX ,
& decoder - > CropY , & decoder - > CropWidth , & decoder - > CropHeight ) ;
2018-08-19 11:45:46 +02:00
}
2021-12-27 20:02:45 +01:00
void SDK_CHECK_ERROR_GL ( ) {
2018-08-19 11:45:46 +02:00
GLenum gl_error = glGetError ( ) ;
if ( gl_error ! = GL_NO_ERROR ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video/cuvid: SDL error %d \n " ) , gl_error ) ;
2018-08-19 11:45:46 +02:00
}
}
2019-10-26 18:42:19 +02:00
2019-10-12 09:04:04 +02:00
# ifdef CUVID
// copy image and process using CUDA
2021-12-27 20:02:45 +01:00
void generateCUDAImage ( CuvidDecoder * decoder , int index , const AVFrame * frame , int image_width , int image_height ,
int bytes ) {
2019-10-12 09:04:04 +02:00
int n ;
2019-10-26 18:42:19 +02:00
2019-10-28 21:43:37 +01:00
for ( n = 0 ; n < 2 ; n + + ) {
2019-10-12 09:04:04 +02:00
// widthInBytes must account for the chroma plane
// elements being two samples wide.
CUDA_MEMCPY2D cpy = {
. srcMemoryType = CU_MEMORYTYPE_DEVICE ,
2019-10-26 18:42:19 +02:00
. dstMemoryType = CU_MEMORYTYPE_ARRAY ,
2021-12-27 20:02:45 +01:00
. srcDevice = ( CUdeviceptr ) frame - > data [ n ] ,
2019-10-26 18:42:19 +02:00
. srcPitch = frame - > linesize [ n ] ,
. srcY = 0 ,
. dstArray = decoder - > cu_array [ index ] [ n ] ,
. WidthInBytes = image_width * bytes ,
. Height = n = = 0 ? image_height : image_height / 2 ,
2019-10-12 09:04:04 +02:00
} ;
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuMemcpy2D ( & cpy ) ) ;
2019-10-12 09:04:04 +02:00
}
}
2018-08-19 11:45:46 +02:00
2019-10-12 09:04:04 +02:00
# endif
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
void createTextureDst ( CuvidDecoder * decoder , int anz , unsigned int size_x , unsigned int size_y ,
enum AVPixelFormat PixFmt ) {
2019-10-26 18:42:19 +02:00
int n , i , size = 1 , fd ;
const struct pl_fmt * fmt ;
struct pl_tex * tex ;
2021-03-16 09:40:08 +01:00
struct pl_frame * img ;
2019-10-26 18:42:19 +02:00
struct pl_plane * pl ;
2021-01-28 12:59:58 +01:00
SharedContext ;
2019-10-28 21:43:37 +01:00
// printf("Create textures and planes %d %d\n",size_x,size_y);
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/vulkan: create %d Textures Format %s w %d h %d \n " , anz ,
2021-12-27 20:02:45 +01:00
PixFmt = = AV_PIX_FMT_NV12 ? " NV12 " : " P010 " , size_x , size_y ) ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
for ( i = 0 ; i < anz ; i + + ) { // number of texture
2019-10-26 18:42:19 +02:00
if ( decoder - > frames [ i ] ) {
av_frame_free ( & decoder - > frames [ i ] ) ;
decoder - > frames [ i ] = NULL ;
}
2021-12-27 20:02:45 +01:00
for ( n = 0 ; n < 2 ; n + + ) { // number of planes
2019-10-26 18:42:19 +02:00
bool ok = true ;
if ( PixFmt = = AV_PIX_FMT_NV12 ) {
fmt = pl_find_named_fmt ( p - > gpu , n = = 0 ? " r8 " : " rg8 " ) ; // 8 Bit YUV
size = 1 ;
} else {
2021-12-27 20:02:45 +01:00
fmt = pl_find_named_fmt ( p - > gpu , n = = 0 ? " r16 " : " rg16 " ) ; // 10 Bit YUV
2019-10-26 18:42:19 +02:00
size = 2 ;
}
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ i ] . planes [ n ] . texture ) {
2021-12-27 20:02:45 +01:00
// #ifdef VAAPI
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ i ] . planes [ n ] . texture - > params . shared_mem . handle . fd ) {
close ( decoder - > pl_frames [ i ] . planes [ n ] . texture - > params . shared_mem . handle . fd ) ;
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
// #endif
pl_tex_destroy ( p - > gpu ,
& decoder - > pl_frames [ i ] . planes [ n ] . texture ) ; // delete old texture
2019-10-26 18:42:19 +02:00
}
if ( p - > has_dma_buf = = 0 ) {
2021-12-27 20:02:45 +01:00
decoder - > pl_frames [ i ] . planes [ n ] . texture = pl_tex_create (
p - > gpu , & ( struct pl_tex_params ) {
. w = n = = 0 ? size_x : size_x / 2 , . h = n = = 0 ? size_y : size_y / 2 , . d = 0 , . format = fmt ,
. sampleable = true , . host_writable = true , . blit_dst = true ,
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2021-12-27 20:02:45 +01:00
. sample_mode = PL_TEX_SAMPLE_LINEAR , . address_mode = PL_TEX_ADDRESS_CLAMP ,
2021-11-16 15:05:49 +01:00
# endif
2021-01-10 13:55:09 +01:00
# if !defined PLACEBO_GL
2019-10-26 18:42:19 +02:00
. export_handle = PL_HANDLE_FD ,
2021-01-10 13:55:09 +01:00
# endif
2019-10-26 18:42:19 +02:00
} ) ;
}
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
// make planes for image
2021-03-16 09:40:08 +01:00
pl = & decoder - > pl_frames [ i ] . planes [ n ] ;
2019-10-26 18:42:19 +02:00
pl - > components = n = = 0 ? 1 : 2 ;
2020-04-10 16:17:23 +02:00
pl - > shift_x = 0.0f ;
2019-10-26 18:42:19 +02:00
pl - > shift_y = 0.0f ;
if ( n = = 0 ) {
pl - > component_mapping [ 0 ] = PL_CHANNEL_Y ;
pl - > component_mapping [ 1 ] = - 1 ;
pl - > component_mapping [ 2 ] = - 1 ;
pl - > component_mapping [ 3 ] = - 1 ;
} else {
2021-12-27 20:02:45 +01:00
pl - > shift_x = - 0.5f ; // PL_CHROMA_LEFT
2019-10-26 18:42:19 +02:00
pl - > component_mapping [ 0 ] = PL_CHANNEL_U ;
pl - > component_mapping [ 1 ] = PL_CHANNEL_V ;
pl - > component_mapping [ 2 ] = - 1 ;
pl - > component_mapping [ 3 ] = - 1 ;
}
if ( ! ok ) {
Fatal ( _ ( " Unable to create placebo textures " ) ) ;
}
2019-10-11 11:47:11 +02:00
# ifdef CUVID
2021-03-16 09:40:08 +01:00
fd = dup ( decoder - > pl_frames [ i ] . planes [ n ] . texture - > shared_mem . handle . fd ) ;
2019-10-26 18:42:19 +02:00
CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
. type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD ,
. handle . fd = fd ,
2021-12-27 20:02:45 +01:00
. size =
decoder - > pl_frames [ i ] . planes [ n ] . texture - > shared_mem . size , // image_width * image_height * bytes,
2019-10-26 18:42:19 +02:00
. flags = 0 ,
} ;
2021-12-27 20:02:45 +01:00
checkCudaErrors (
cu - > cuImportExternalMemory ( & decoder - > ebuf [ i * 2 + n ] . mem , & ext_desc ) ) ; // Import Memory segment
2019-10-26 18:42:19 +02:00
CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
2021-03-16 09:40:08 +01:00
. offset = decoder - > pl_frames [ i ] . planes [ n ] . texture - > shared_mem . offset ,
2021-12-27 20:02:45 +01:00
. arrayDesc =
{
2019-10-26 18:42:19 +02:00
. Width = n = = 0 ? size_x : size_x / 2 ,
. Height = n = = 0 ? size_y : size_y / 2 ,
. Depth = 0 ,
. Format = PixFmt = = AV_PIX_FMT_NV12 ? CU_AD_FORMAT_UNSIGNED_INT8 : CU_AD_FORMAT_UNSIGNED_INT16 ,
. NumChannels = n = = 0 ? 1 : 2 ,
. Flags = 0 ,
} ,
. numLevels = 1 ,
} ;
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuExternalMemoryGetMappedMipmappedArray ( & decoder - > ebuf [ i * 2 + n ] . mma ,
2021-12-27 20:02:45 +01:00
decoder - > ebuf [ i * 2 + n ] . mem , & tex_desc ) ) ;
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuMipmappedArrayGetLevel ( & decoder - > cu_array [ i ] [ n ] , decoder - > ebuf [ i * 2 + n ] . mma , 0 ) ) ;
2019-10-26 18:42:19 +02:00
# endif
}
// make image
2021-03-16 09:40:08 +01:00
img = & decoder - > pl_frames [ i ] ;
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2019-10-26 18:42:19 +02:00
img - > signature = i ;
2021-11-16 15:05:49 +01:00
img - > width = size_x ;
img - > height = size_y ;
# endif
2019-10-26 18:42:19 +02:00
img - > num_planes = 2 ;
img - > repr . sys = PL_COLOR_SYSTEM_BT_709 ; // overwritten later
img - > repr . levels = PL_COLOR_LEVELS_TV ;
img - > repr . alpha = PL_ALPHA_UNKNOWN ;
2021-12-27 20:02:45 +01:00
img - > color . primaries = pl_color_primaries_guess ( size_x , size_y ) ; // Gammut overwritten later
img - > color . transfer = PL_COLOR_TRC_BT_1886 ; // overwritten later
img - > color . light = PL_COLOR_LIGHT_SCENE_709_1886 ; // needs config ???
img - > color . sig_peak = 0.0f ; // needs config ????
2019-10-26 18:42:19 +02:00
img - > color . sig_avg = 0.0f ;
img - > num_overlays = 0 ;
}
2021-01-28 12:59:58 +01:00
NoContext ;
2018-11-04 13:44:18 +01:00
}
2019-10-26 18:42:19 +02:00
2019-08-22 12:34:29 +02:00
# ifdef VAAPI
2019-10-04 10:37:57 +02:00
2019-08-22 12:34:29 +02:00
// copy image and process using CUDA
2021-12-27 20:02:45 +01:00
void generateVAAPIImage ( CuvidDecoder * decoder , int index , const AVFrame * frame , int image_width , int image_height ) {
2019-08-22 12:34:29 +02:00
int n ;
2019-10-26 18:42:19 +02:00
VAStatus status ;
int toggle = 0 ;
uint64_t first_time ;
VADRMPRIMESurfaceDescriptor desc ;
2021-12-27 20:02:45 +01:00
2021-12-05 17:44:45 +01:00
vaSyncSurface ( decoder - > VaDisplay , ( unsigned int ) frame - > data [ 3 ] ) ;
2019-10-26 18:42:19 +02:00
status =
vaExportSurfaceHandle ( decoder - > VaDisplay , ( unsigned int ) frame - > data [ 3 ] , VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 ,
2021-12-27 20:02:45 +01:00
VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS , & desc ) ;
2019-10-26 18:42:19 +02:00
if ( status ! = VA_STATUS_SUCCESS ) {
printf ( " Fehler beim export VAAPI Handle \n " ) ;
return ;
}
2021-12-27 20:02:45 +01:00
// vaSyncSurface(decoder->VaDisplay, (unsigned int)frame->data[3]);
2023-04-23 11:07:09 +02:00
2021-01-28 12:59:58 +01:00
Lock_and_SharedContext ;
2023-04-23 11:07:09 +02:00
2021-12-27 20:02:45 +01:00
for ( n = 0 ; n < 2 ; n + + ) { // Set DMA_BUF from VAAPI decoder to Textures
2019-10-26 18:42:19 +02:00
int id = desc . layers [ n ] . object_index [ 0 ] ;
int fd = desc . objects [ id ] . fd ;
uint32_t size = desc . objects [ id ] . size ;
uint32_t offset = desc . layers [ n ] . offset [ 0 ] ;
2023-02-16 12:50:57 +01:00
# if PL_API_VER < 229
2021-01-10 13:55:09 +01:00
struct pl_fmt * fmt ;
2023-02-16 12:50:57 +01:00
# else
struct pl_fmt_t * fmt ;
# endif
2019-10-26 18:42:19 +02:00
if ( fd = = - 1 ) {
printf ( " Fehler beim Import von Surface %d \n " , index ) ;
return ;
}
2021-12-05 17:44:45 +01:00
2021-12-27 20:02:45 +01:00
if ( ! size ) {
size = n = = 0 ? desc . width * desc . height : desc . width * desc . height / 2 ;
}
// fmt = pl_find_fourcc(p->gpu,desc.layers[n].drm_format);
# if 1
2019-10-26 18:42:19 +02:00
if ( decoder - > PixFmt = = AV_PIX_FMT_NV12 ) {
fmt = pl_find_named_fmt ( p - > gpu , n = = 0 ? " r8 " : " rg8 " ) ; // 8 Bit YUV
} else {
2021-12-27 20:02:45 +01:00
fmt = pl_find_fourcc ( p - > gpu ,
n = = 0 ? 0x20363152 : 0x32335247 ) ; // 10 Bit YUV
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
# endif
2021-03-16 09:40:08 +01:00
assert ( fmt ! = NULL ) ;
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO_GL
fmt - > fourcc = desc . layers [ n ] . drm_format ;
# endif
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
struct pl_tex_params tex_params = {
2021-12-27 20:02:45 +01:00
. w = n = = 0 ? image_width : image_width / 2 ,
2019-10-26 18:42:19 +02:00
. h = n = = 0 ? image_height : image_height / 2 ,
. d = 0 ,
. format = fmt ,
. sampleable = true ,
. host_writable = false ,
2021-01-10 13:55:09 +01:00
. blit_dst = true ,
2021-01-28 12:59:58 +01:00
. renderable = true ,
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2021-12-27 20:02:45 +01:00
. address_mode = PL_TEX_ADDRESS_CLAMP ,
2019-10-26 18:42:19 +02:00
. sample_mode = PL_TEX_SAMPLE_LINEAR ,
2021-11-16 15:05:49 +01:00
# endif
2019-10-26 18:42:19 +02:00
. import_handle = PL_HANDLE_DMA_BUF ,
2021-12-27 20:02:45 +01:00
. shared_mem =
( struct pl_shared_mem ) {
. handle =
{
2019-10-26 18:42:19 +02:00
. fd = fd ,
} ,
2019-08-22 12:34:29 +02:00
. size = size ,
. offset = offset ,
2021-03-16 09:40:08 +01:00
. stride_h = n = = 0 ? image_height : image_height / 2 ,
2021-01-28 12:59:58 +01:00
. stride_w = desc . layers [ n ] . pitch [ 0 ] ,
2021-03-16 09:40:08 +01:00
. drm_format_mod = desc . objects [ id ] . drm_format_modifier ,
2021-12-27 20:02:45 +01:00
} ,
2019-10-26 18:42:19 +02:00
} ;
2019-08-22 12:34:29 +02:00
2021-12-27 20:02:45 +01:00
// printf("vor create Object %d with fd %d import size %u offset %d
// %dx%d\n",id,fd,size,offset, tex_params.w,tex_params.h);
2019-08-22 12:34:29 +02:00
2021-03-16 09:40:08 +01:00
if ( decoder - > pl_frames [ index ] . planes [ n ] . texture ) {
pl_tex_destroy ( p - > gpu , & decoder - > pl_frames [ index ] . planes [ n ] . texture ) ;
2019-10-26 18:42:19 +02:00
}
2021-01-10 13:55:09 +01:00
2021-03-16 09:40:08 +01:00
decoder - > pl_frames [ index ] . planes [ n ] . texture = pl_tex_create ( p - > gpu , & tex_params ) ;
2021-01-10 13:55:09 +01:00
}
2023-04-23 11:07:09 +02:00
2021-01-10 13:55:09 +01:00
Unlock_and_NoContext ;
2023-04-23 11:07:09 +02:00
2019-08-22 12:34:29 +02:00
}
# endif
2019-12-10 10:45:22 +01:00
# else // no PLACEBO
2019-10-04 10:37:57 +02:00
2021-12-27 20:02:45 +01:00
void createTextureDst ( CuvidDecoder * decoder , int anz , unsigned int size_x , unsigned int size_y ,
enum AVPixelFormat PixFmt ) {
2019-10-26 18:42:19 +02:00
int n , i ;
Debug ( 3 , " video: create %d Textures Format %s w %d h %d \n " , anz , PixFmt = = AV_PIX_FMT_NV12 ? " NV12 " : " P010 " ,
2021-12-27 20:02:45 +01:00
size_x , size_y ) ;
2020-04-10 16:17:23 +02:00
2020-01-31 12:28:18 +01:00
# ifdef USE_DRM
2021-12-27 20:02:45 +01:00
// set_video_mode(size_x,size_y); // switch Mode here (highly
// experimental)
2020-01-31 12:28:18 +01:00
# endif
2020-04-10 16:17:23 +02:00
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
glXMakeCurrent ( XlibDisplay , VideoWindow , glxSharedContext ) ;
GlxCheck ( ) ;
2019-10-04 10:37:57 +02:00
# else
2020-02-18 22:02:53 +01:00
# ifdef USE_DRM
pthread_mutex_lock ( & OSDMutex ) ;
2020-04-10 16:17:23 +02:00
# endif
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglSharedContext ) ;
2019-10-26 18:42:19 +02:00
# endif
glGenBuffers ( 1 , & vao_buffer ) ;
GlxCheck ( ) ;
// create texture planes
2019-12-23 11:14:38 +01:00
glGenTextures ( CODEC_SURFACES_MAX * Planes , decoder - > gl_textures ) ;
2019-10-26 18:42:19 +02:00
GlxCheck ( ) ;
for ( i = 0 ; i < anz ; i + + ) {
2021-12-27 20:02:45 +01:00
for ( n = 0 ; n < Planes ; n + + ) { // number of planes
2019-10-26 18:42:19 +02:00
2019-12-23 11:14:38 +01:00
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ i * Planes + n ] ) ;
2019-10-26 18:42:19 +02:00
GlxCheck ( ) ;
// set basic parameters
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2020-04-10 16:17:23 +02:00
if ( PixFmt = = AV_PIX_FMT_NV12 )
glTexImage2D ( GL_TEXTURE_2D , 0 , n = = 0 ? GL_R8 : GL_RG8 , n = = 0 ? size_x : size_x / 2 ,
2021-12-27 20:02:45 +01:00
n = = 0 ? size_y : size_y / 2 , 0 , n = = 0 ? GL_RED : GL_RG , GL_UNSIGNED_BYTE , NULL ) ;
2020-04-10 16:17:23 +02:00
else
glTexImage2D ( GL_TEXTURE_2D , 0 , n = = 0 ? GL_R16 : GL_RG16 , n = = 0 ? size_x : size_x / 2 ,
2021-12-27 20:02:45 +01:00
n = = 0 ? size_y : size_y / 2 , 0 , n = = 0 ? GL_RED : GL_RG , GL_UNSIGNED_SHORT , NULL ) ;
2019-10-26 18:42:19 +02:00
SDK_CHECK_ERROR_GL ( ) ;
// register this texture with CUDA
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuGraphicsGLRegisterImage ( & decoder - > cu_res [ i ] [ n ] , decoder - > gl_textures [ i * Planes + n ] ,
2021-12-27 20:02:45 +01:00
GL_TEXTURE_2D , CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD ) ) ;
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuGraphicsMapResources ( 1 , & decoder - > cu_res [ i ] [ n ] , 0 ) ) ;
2021-12-27 20:02:45 +01:00
checkCudaErrors (
cu - > cuGraphicsSubResourceGetMappedArray ( & decoder - > cu_array [ i ] [ n ] , decoder - > cu_res [ i ] [ n ] , 0 , 0 ) ) ;
2020-03-06 12:42:14 +01:00
checkCudaErrors ( cu - > cuGraphicsUnmapResources ( 1 , & decoder - > cu_res [ i ] [ n ] , 0 ) ) ;
2019-10-26 18:42:19 +02:00
# endif
}
}
2023-02-15 13:06:44 +01:00
2019-10-26 18:42:19 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
GlxCheck ( ) ;
2019-10-04 10:37:57 +02:00
# ifdef VAAPI
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2020-02-18 22:02:53 +01:00
# ifdef USE_DRM
pthread_mutex_unlock ( & OSDMutex ) ;
# endif
2019-10-04 10:37:57 +02:00
# endif
2018-08-19 11:45:46 +02:00
}
2019-10-12 09:04:04 +02:00
2019-10-04 10:37:57 +02:00
# ifdef VAAPI
# define MP_ARRAY_SIZE(s) (sizeof(s) / sizeof((s)[0]))
2021-12-27 20:02:45 +01:00
# define ADD_ATTRIB(name, value) \
do { \
assert ( num_attribs + 3 < MP_ARRAY_SIZE ( attribs ) ) ; \
attribs [ num_attribs + + ] = ( name ) ; \
attribs [ num_attribs + + ] = ( value ) ; \
attribs [ num_attribs ] = EGL_NONE ; \
2019-10-04 10:37:57 +02:00
} while ( 0 )
2023-02-15 13:06:44 +01:00
# define ADD_DMABUF_PLANE_ATTRIBS(plane, fd, offset, stride) \
do { \
ADD_ATTRIB ( EGL_DMA_BUF_PLANE # # plane # # _FD_EXT , \
fd ) ; \
ADD_ATTRIB ( EGL_DMA_BUF_PLANE # # plane # # _OFFSET_EXT , \
offset ) ; \
ADD_ATTRIB ( EGL_DMA_BUF_PLANE # # plane # # _PITCH_EXT , \
stride ) ; \
} while ( 0 )
# define ADD_DMABUF_PLANE_MODIFIERS(plane, mod) \
do { \
ADD_ATTRIB ( EGL_DMA_BUF_PLANE # # plane # # _MODIFIER_LO_EXT , \
( uint32_t ) ( ( mod ) & 0xFFFFFFFFlu ) ) ; \
ADD_ATTRIB ( EGL_DMA_BUF_PLANE # # plane # # _MODIFIER_HI_EXT , \
( uint32_t ) ( ( ( mod ) > > 32u ) & 0xFFFFFFFFlu ) ) ; \
2021-12-27 20:02:45 +01:00
} while ( 0 )
void generateVAAPIImage ( CuvidDecoder * decoder , VASurfaceID index , const AVFrame * frame , int image_width ,
int image_height ) {
2019-10-26 18:42:19 +02:00
VAStatus status ;
uint64_t first_time ;
2020-04-10 16:17:23 +02:00
2022-05-24 00:09:55 +02:00
# if defined(VAAPI)
2019-10-26 18:42:19 +02:00
VADRMPRIMESurfaceDescriptor desc ;
2021-12-27 20:02:45 +01:00
vaSyncSurface ( decoder - > VaDisplay , ( VASurfaceID ) ( uintptr_t ) frame - > data [ 3 ] ) ;
status = vaExportSurfaceHandle ( decoder - > VaDisplay , ( VASurfaceID ) ( uintptr_t ) frame - > data [ 3 ] ,
VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 ,
VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS , & desc ) ;
2019-10-26 18:42:19 +02:00
if ( status ! = VA_STATUS_SUCCESS ) {
printf ( " Fehler beim export VAAPI Handle \n " ) ;
return ;
}
2021-12-27 20:02:45 +01:00
// vaSyncSurface(decoder->VaDisplay, (VASurfaceID) (uintptr_t)
// frame->data[3]);
2019-12-23 11:14:38 +01:00
# endif
2023-07-14 09:13:09 +02:00
pthread_mutex_lock ( & OSDMutex ) ;
2019-10-26 18:42:19 +02:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglSharedContext ) ;
EglCheck ( ) ;
2019-12-23 11:14:38 +01:00
for ( int n = 0 ; n < Planes ; n + + ) {
2021-12-27 20:02:45 +01:00
int attribs [ 20 ] = { EGL_NONE } ;
2020-03-16 16:31:47 +01:00
uint num_attribs = 0 ;
2023-02-15 13:06:44 +01:00
int id = desc . layers [ n ] . object_index [ 0 ] ;
int fd = desc . objects [ id ] . fd ;
2020-04-10 16:17:23 +02:00
2022-05-24 00:09:55 +02:00
# if defined(VAAPI)
2023-02-15 13:06:44 +01:00
//Debug(3,"Plane %d w %d h %d layers %d planes %d pitch %d format %04x\n",n,image_width,image_height,desc.num_layers,desc.layers[n].num_planes,desc.layers[n].pitch[0],desc.layers[n].drm_format);
2020-04-10 16:17:23 +02:00
ADD_ATTRIB ( EGL_WIDTH , n = = 0 ? image_width : image_width / 2 ) ;
ADD_ATTRIB ( EGL_HEIGHT , n = = 0 ? image_height : image_height / 2 ) ;
2023-02-15 13:06:44 +01:00
ADD_DMABUF_PLANE_MODIFIERS ( 0 , desc . objects [ id ] . drm_format_modifier ) ;
ADD_ATTRIB ( EGL_LINUX_DRM_FOURCC_EXT , desc . layers [ n ] . drm_format ) ;
ADD_DMABUF_PLANE_ATTRIBS ( 0 , fd , desc . layers [ n ] . offset [ 0 ] , desc . layers [ n ] . pitch [ 0 ] ) ;
2019-12-23 11:14:38 +01:00
# endif
decoder - > images [ index * Planes + n ] =
2019-12-10 10:45:22 +01:00
CreateImageKHR ( eglDisplay , EGL_NO_CONTEXT , EGL_LINUX_DMA_BUF_EXT , NULL , attribs ) ;
2020-04-10 16:17:23 +02:00
2019-12-23 11:14:38 +01:00
if ( ! decoder - > images [ index * Planes + n ] )
2019-10-26 18:42:19 +02:00
goto esh_failed ;
2019-12-23 11:14:38 +01:00
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ index * Planes + n ] ) ;
EGLImageTargetTexture2DOES ( GL_TEXTURE_2D , decoder - > images [ index * Planes + n ] ) ;
2021-11-19 17:46:38 +01:00
decoder - > fds [ index * Planes + n ] = desc . objects [ n ] . fd ;
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
EglCheck ( ) ;
2023-07-14 09:13:09 +02:00
pthread_mutex_unlock ( & OSDMutex ) ;
2020-03-02 16:20:34 +01:00
return ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
esh_failed :
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Failure in generateVAAPIImage \n " ) ;
2019-12-23 11:14:38 +01:00
for ( int n = 0 ; n < Planes ; n + + )
2019-10-26 18:42:19 +02:00
close ( desc . objects [ n ] . fd ) ;
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
EglCheck ( ) ;
2023-07-14 09:13:09 +02:00
pthread_mutex_unlock ( & OSDMutex ) ;
2019-10-04 10:37:57 +02:00
}
# endif
2019-08-22 12:34:29 +02:00
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Configure CUVID for new video format.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetupOutput ( CuvidDecoder * decoder ) {
2018-08-19 11:45:46 +02:00
// FIXME: need only to create and destroy surfaces for size changes
2021-12-27 20:02:45 +01:00
// or when number of needed surfaces changed!
2018-08-19 11:45:46 +02:00
decoder - > Resolution = VideoResolutionGroup ( decoder - > InputWidth , decoder - > InputHeight , decoder - > Interlaced ) ;
2019-10-26 18:42:19 +02:00
CuvidCreateSurfaces ( decoder , decoder - > InputWidth , decoder - > InputHeight , decoder - > PixFmt ) ;
2021-12-27 20:02:45 +01:00
CuvidUpdateOutput ( decoder ) ; // update aspect/scaling
2018-08-19 11:45:46 +02:00
window_width = decoder - > OutputWidth ;
window_height = decoder - > OutputHeight ;
}
///
2021-12-27 20:02:45 +01:00
/// Get a free surface. Called from ffmpeg.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2021-12-27 20:02:45 +01:00
/// @param video_ctx ffmpeg video codec context
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns the oldest free surface
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static unsigned CuvidGetVideoSurface ( CuvidDecoder * decoder , const AVCodecContext * video_ctx ) {
2018-08-19 11:45:46 +02:00
( void ) video_ctx ;
return CuvidGetVideoSurface0 ( decoder ) ;
}
2021-12-27 20:02:45 +01:00
# if defined(VAAPI) || defined(YADIF)
static void CuvidSyncRenderFrame ( CuvidDecoder * decoder , const AVCodecContext * video_ctx , AVFrame * frame ) ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
int push_filters ( AVCodecContext * dec_ctx , CuvidDecoder * decoder , AVFrame * frame ) {
2020-04-10 16:17:23 +02:00
2020-03-02 16:20:34 +01:00
int ret ;
2019-10-26 18:42:19 +02:00
AVFrame * filt_frame = av_frame_alloc ( ) ;
/* push the decoded frame into the filtergraph */
if ( av_buffersrc_add_frame_flags ( decoder - > buffersrc_ctx , frame , AV_BUFFERSRC_FLAG_KEEP_REF ) < 0 ) {
av_log ( NULL , AV_LOG_ERROR , " Error while feeding the filtergraph \n " ) ;
}
2021-12-27 20:02:45 +01:00
// printf("Interlaced %d tff
// %d\n",frame->interlaced_frame,frame->top_field_first);
2019-10-26 18:42:19 +02:00
/* pull filtered frames from the filtergraph */
2020-04-10 16:17:23 +02:00
while ( ( ret = av_buffersink_get_frame ( decoder - > buffersink_ctx , filt_frame ) ) > = 0 ) {
2019-10-26 18:42:19 +02:00
filt_frame - > pts / = 2 ;
decoder - > Interlaced = 0 ;
2021-12-27 20:02:45 +01:00
// printf("vaapideint video:new %#012" PRIx64 " old %#012" PRIx64
// "\n",filt_frame->pts,frame->pts);
2019-10-26 18:42:19 +02:00
CuvidSyncRenderFrame ( decoder , dec_ctx , filt_frame ) ;
2021-12-27 20:02:45 +01:00
filt_frame = av_frame_alloc ( ) ; // get new frame
2019-10-26 18:42:19 +02:00
}
av_frame_free ( & filt_frame ) ;
av_frame_free ( & frame ) ;
return ret ;
}
2021-12-27 20:02:45 +01:00
int init_filters ( AVCodecContext * dec_ctx , CuvidDecoder * decoder , AVFrame * frame ) {
2019-10-26 18:42:19 +02:00
enum AVPixelFormat format = PIXEL_FORMAT ;
2019-08-22 12:34:29 +02:00
# ifdef VAAPI
2020-04-13 18:04:57 +02:00
const char * filters_descr = " deinterlace_vaapi=rate=field:auto=1 " ;
2019-08-22 12:34:29 +02:00
# endif
# ifdef YADIF
2019-10-26 18:42:19 +02:00
const char * filters_descr = " yadif_cuda=1:0:1 " ; // mode=send_field,parity=tff,deint=interlaced";
2021-12-27 20:02:45 +01:00
enum AVPixelFormat pix_fmts [ ] = { format , AV_PIX_FMT_NONE } ;
2019-08-22 12:34:29 +02:00
# endif
2019-10-26 18:42:19 +02:00
2019-08-22 12:34:29 +02:00
char args [ 512 ] ;
int ret = 0 ;
2019-10-26 18:42:19 +02:00
const AVFilter * buffersrc = avfilter_get_by_name ( " buffer " ) ;
2019-08-22 12:34:29 +02:00
const AVFilter * buffersink = avfilter_get_by_name ( " buffersink " ) ;
AVFilterInOut * outputs = avfilter_inout_alloc ( ) ;
2019-10-26 18:42:19 +02:00
AVFilterInOut * inputs = avfilter_inout_alloc ( ) ;
AVBufferSrcParameters * src_params ;
if ( decoder - > filter_graph )
avfilter_graph_free ( & decoder - > filter_graph ) ;
2019-08-22 12:34:29 +02:00
decoder - > filter_graph = avfilter_graph_alloc ( ) ;
if ( ! outputs | | ! inputs | | ! decoder - > filter_graph ) {
ret = AVERROR ( ENOMEM ) ;
goto end ;
}
2021-12-27 20:02:45 +01:00
/* buffer video source: the decoded frames from the decoder will be inserted
* here . */
2019-10-26 18:42:19 +02:00
snprintf ( args , sizeof ( args ) , " video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d " , dec_ctx - > width ,
2021-12-27 20:02:45 +01:00
dec_ctx - > height , format , 1 , 90000 , dec_ctx - > sample_aspect_ratio . num , dec_ctx - > sample_aspect_ratio . den ) ;
2019-10-26 18:42:19 +02:00
ret = avfilter_graph_create_filter ( & decoder - > buffersrc_ctx , buffersrc , " in " , args , NULL , decoder - > filter_graph ) ;
2019-08-22 12:34:29 +02:00
if ( ret < 0 ) {
Debug ( 3 , " Cannot create buffer source \n " ) ;
goto end ;
}
2019-10-26 18:42:19 +02:00
src_params = av_buffersrc_parameters_alloc ( ) ;
src_params - > hw_frames_ctx = frame - > hw_frames_ctx ;
src_params - > format = format ;
src_params - > time_base . num = 1 ;
src_params - > time_base . den = 90000 ;
src_params - > width = dec_ctx - > width ;
src_params - > height = dec_ctx - > height ;
src_params - > frame_rate . num = 50 ;
src_params - > frame_rate . den = 1 ;
src_params - > sample_aspect_ratio = dec_ctx - > sample_aspect_ratio ;
2021-12-27 20:02:45 +01:00
// printf("width %d height %d hw_frames_ctx
// %p\n",dec_ctx->width,dec_ctx->height ,frame->hw_frames_ctx);
2019-10-26 18:42:19 +02:00
ret = av_buffersrc_parameters_set ( decoder - > buffersrc_ctx , src_params ) ;
if ( ret < 0 ) {
2019-08-22 12:34:29 +02:00
Debug ( 3 , " Cannot set hw_frames_ctx to src \n " ) ;
goto end ;
}
/* buffer video sink: to terminate the filter chain. */
2019-10-26 18:42:19 +02:00
ret = avfilter_graph_create_filter ( & decoder - > buffersink_ctx , buffersink , " out " , NULL , NULL , decoder - > filter_graph ) ;
2019-08-22 12:34:29 +02:00
if ( ret < 0 ) {
Debug ( 3 , " Cannot create buffer sink \n " ) ;
goto end ;
}
2019-10-20 14:48:28 +02:00
# ifdef YADIF
2019-10-26 18:42:19 +02:00
ret = av_opt_set_int_list ( decoder - > buffersink_ctx , " pix_fmts " , pix_fmts , AV_PIX_FMT_NONE , AV_OPT_SEARCH_CHILDREN ) ;
2019-08-22 12:34:29 +02:00
if ( ret < 0 ) {
Debug ( 3 , " Cannot set output pixel format \n " ) ;
goto end ;
}
# endif
/*
* Set the endpoints for the filter graph . The filter_graph will
* be linked to the graph described by filters_descr .
*/
/*
* The buffer source output must be connected to the input pad of
* the first filter described by filters_descr ; since the first
* filter input label is not specified , it is set to " in " by
* default .
*/
2019-10-26 18:42:19 +02:00
outputs - > name = av_strdup ( " in " ) ;
2019-08-22 12:34:29 +02:00
outputs - > filter_ctx = decoder - > buffersrc_ctx ;
2019-10-26 18:42:19 +02:00
outputs - > pad_idx = 0 ;
outputs - > next = NULL ;
2019-08-22 12:34:29 +02:00
/*
* The buffer sink input must be connected to the output pad of
* the last filter described by filters_descr ; since the last
* filter output label is not specified , it is set to " out " by
* default .
*/
2019-10-26 18:42:19 +02:00
inputs - > name = av_strdup ( " out " ) ;
2019-08-22 12:34:29 +02:00
inputs - > filter_ctx = decoder - > buffersink_ctx ;
2019-10-26 18:42:19 +02:00
inputs - > pad_idx = 0 ;
inputs - > next = NULL ;
2019-08-22 12:34:29 +02:00
if ( ( ret = avfilter_graph_parse_ptr ( decoder - > filter_graph , filters_descr , & inputs , & outputs , NULL ) ) < 0 ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Cannot set graph parse %d \n " , ret ) ;
2019-08-22 12:34:29 +02:00
goto end ;
2019-10-26 18:42:19 +02:00
}
2019-08-22 12:34:29 +02:00
if ( ( ret = avfilter_graph_config ( decoder - > filter_graph , NULL ) ) < 0 ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Cannot set graph config %d \n " , ret ) ;
2019-08-22 12:34:29 +02:00
goto end ;
2019-10-26 18:42:19 +02:00
}
2019-08-22 12:34:29 +02:00
2021-12-27 20:02:45 +01:00
end :
2019-08-22 12:34:29 +02:00
avfilter_inout_free ( & inputs ) ;
avfilter_inout_free ( & outputs ) ;
return ret ;
}
# endif
2020-01-31 14:15:56 +01:00
# ifdef VAAPI
2021-12-27 20:02:45 +01:00
static int init_generic_hwaccel ( CuvidDecoder * decoder , enum AVPixelFormat hw_fmt , AVCodecContext * video_ctx ) {
2020-04-10 16:17:23 +02:00
2020-01-27 18:00:45 +01:00
AVBufferRef * new_frames_ctx = NULL ;
if ( ! hw_device_ctx ) {
Debug ( 3 , " Missing device context. \n " ) ;
goto error ;
}
2020-04-10 16:17:23 +02:00
if ( avcodec_get_hw_frames_parameters ( video_ctx , hw_device_ctx , hw_fmt , & new_frames_ctx ) < 0 ) {
2020-01-27 18:00:45 +01:00
Debug ( 3 , " Hardware decoding of this stream is unsupported? \n " ) ;
goto error ;
}
AVHWFramesContext * new_fctx = ( void * ) new_frames_ctx - > data ;
// We might be able to reuse a previously allocated frame pool.
if ( decoder - > cached_hw_frames_ctx ) {
AVHWFramesContext * old_fctx = ( void * ) decoder - > cached_hw_frames_ctx - > data ;
2020-04-10 16:17:23 +02:00
Debug ( 3 , " CMP %d:%d %d:%d %d:%d %d:%d %d:%d \ , " , new_fctx - > format , old_fctx - > format , new_fctx - > sw_format ,
2021-12-27 20:02:45 +01:00
old_fctx - > sw_format , new_fctx - > width , old_fctx - > width , new_fctx - > height , old_fctx - > height ,
new_fctx - > initial_pool_size , old_fctx - > initial_pool_size ) ;
if ( new_fctx - > format ! = old_fctx - > format | | new_fctx - > sw_format ! = old_fctx - > sw_format | |
new_fctx - > width ! = old_fctx - > width | | new_fctx - > height ! = old_fctx - > height | |
new_fctx - > initial_pool_size ! = old_fctx - > initial_pool_size ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " delete old cache " ) ;
if ( decoder - > filter_graph )
avfilter_graph_free ( & decoder - > filter_graph ) ;
av_buffer_unref ( & decoder - > cached_hw_frames_ctx ) ;
2020-01-31 12:28:18 +01:00
}
2020-01-27 18:00:45 +01:00
}
if ( ! decoder - > cached_hw_frames_ctx ) {
2020-02-02 11:15:17 +01:00
new_fctx - > initial_pool_size = 17 ;
2020-01-27 18:00:45 +01:00
if ( av_hwframe_ctx_init ( new_frames_ctx ) < 0 ) {
Debug ( 3 , " Failed to allocate hw frames. \n " ) ;
goto error ;
}
decoder - > cached_hw_frames_ctx = new_frames_ctx ;
new_frames_ctx = NULL ;
}
video_ctx - > hw_frames_ctx = av_buffer_ref ( decoder - > cached_hw_frames_ctx ) ;
if ( ! video_ctx - > hw_frames_ctx )
goto error ;
av_buffer_unref ( & new_frames_ctx ) ;
return 0 ;
2021-12-27 20:02:45 +01:00
error :
2020-04-10 16:17:23 +02:00
Debug ( 3 , " Error with hwframes \n " ) ;
2020-01-27 18:00:45 +01:00
av_buffer_unref ( & new_frames_ctx ) ;
av_buffer_unref ( & decoder - > cached_hw_frames_ctx ) ;
return - 1 ;
}
2020-01-31 14:15:56 +01:00
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Callback to negotiate the PixelFormat.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param fmt is the list of formats which are supported by the codec,
/// it is terminated by -1 as 0 is a valid format, the
/// formats are ordered by quality.
2018-08-19 11:45:46 +02:00
///
2018-09-08 16:53:55 +02:00
2021-12-27 20:02:45 +01:00
static enum AVPixelFormat Cuvid_get_format ( CuvidDecoder * decoder , AVCodecContext * video_ctx ,
const enum AVPixelFormat * fmt ) {
2018-08-19 11:45:46 +02:00
const enum AVPixelFormat * fmt_idx ;
2019-10-26 18:42:19 +02:00
int bitformat16 = 0 , deint = 0 ;
2018-08-19 11:45:46 +02:00
VideoDecoder * ist = video_ctx - > opaque ;
//
2021-12-27 20:02:45 +01:00
// look through formats
2018-08-19 11:45:46 +02:00
//
Debug ( 3 , " %s: codec %d fmts: \n " , __FUNCTION__ , video_ctx - > codec_id ) ;
for ( fmt_idx = fmt ; * fmt_idx ! = AV_PIX_FMT_NONE ; fmt_idx + + ) {
Debug ( 3 , " \t %#010x %s \n " , * fmt_idx , av_get_pix_fmt_name ( * fmt_idx ) ) ;
if ( * fmt_idx = = AV_PIX_FMT_P010LE )
bitformat16 = 1 ;
}
2019-08-22 12:34:29 +02:00
# ifdef VAAPI
2019-10-26 18:42:19 +02:00
if ( video_ctx - > profile = = FF_PROFILE_HEVC_MAIN_10 )
bitformat16 = 1 ;
2019-08-22 12:34:29 +02:00
# endif
2018-08-19 11:45:46 +02:00
Debug ( 3 , " %s: codec %d fmts: \n " , __FUNCTION__ , video_ctx - > codec_id ) ;
for ( fmt_idx = fmt ; * fmt_idx ! = AV_PIX_FMT_NONE ; fmt_idx + + ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " \t %#010x %s \n " , * fmt_idx , av_get_pix_fmt_name ( * fmt_idx ) ) ;
// check supported pixel format with entry point
switch ( * fmt_idx ) {
case PIXEL_FORMAT :
break ;
default :
continue ;
}
break ;
}
Debug ( 3 , " video profile %d codec id %d \n " , video_ctx - > profile , video_ctx - > codec_id ) ;
2018-08-19 11:45:46 +02:00
if ( * fmt_idx = = AV_PIX_FMT_NONE ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video: no valid pixfmt found \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2019-10-20 14:48:28 +02:00
if ( * fmt_idx ! = PIXEL_FORMAT ) {
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " video: no valid profile found \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
// decoder->newchannel = 1;
2020-01-27 18:00:45 +01:00
# ifdef VAAPI
2020-04-10 16:17:23 +02:00
init_generic_hwaccel ( decoder , PIXEL_FORMAT , video_ctx ) ;
2020-01-27 18:00:45 +01:00
# endif
if ( ist - > GetFormatDone ) {
2019-10-26 18:42:19 +02:00
return PIXEL_FORMAT ;
2020-04-10 16:17:23 +02:00
}
2019-10-20 14:48:28 +02:00
2019-10-26 18:42:19 +02:00
ist - > GetFormatDone = 1 ;
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
Debug ( 3 , " video: create decoder 16bit?=%d %dx%d old %d %d \n " , bitformat16 , video_ctx - > width , video_ctx - > height ,
decoder - > InputWidth , decoder - > InputHeight ) ;
2019-10-20 14:48:28 +02:00
2021-12-27 20:02:45 +01:00
if ( * fmt_idx = = PIXEL_FORMAT ) { // HWACCEL used
2019-10-26 18:42:19 +02:00
// Check image, format, size
//
if ( bitformat16 ) {
2021-12-27 20:02:45 +01:00
decoder - > PixFmt = AV_PIX_FMT_YUV420P ; // 10 Bit Planar
2019-10-26 18:42:19 +02:00
ist - > hwaccel_output_format = AV_PIX_FMT_YUV420P ;
2018-08-19 11:45:46 +02:00
} else {
2021-12-27 20:02:45 +01:00
decoder - > PixFmt = AV_PIX_FMT_NV12 ; // 8 Bit Planar
2019-10-26 18:42:19 +02:00
ist - > hwaccel_output_format = AV_PIX_FMT_NV12 ;
2018-08-19 11:45:46 +02:00
}
2019-08-22 12:34:29 +02:00
2021-12-27 20:02:45 +01:00
if ( ( video_ctx - > width ! = decoder - > InputWidth | | video_ctx - > height ! = decoder - > InputHeight ) & &
decoder - > TrickSpeed = = 0 ) {
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
// if (decoder->TrickSpeed == 0) {
2019-10-04 10:37:57 +02:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
VideoThreadLock ( ) ;
# endif
2020-03-31 13:57:43 +02:00
decoder - > newchannel = 1 ;
2019-10-26 18:42:19 +02:00
CuvidCleanup ( decoder ) ;
decoder - > InputAspect = video_ctx - > sample_aspect_ratio ;
decoder - > InputWidth = video_ctx - > width ;
decoder - > InputHeight = video_ctx - > height ;
decoder - > Interlaced = 0 ;
decoder - > SurfacesNeeded = VIDEO_SURFACES_MAX + 1 ;
CuvidSetupOutput ( decoder ) ;
2019-10-04 10:37:57 +02:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
VideoThreadUnlock ( ) ;
2019-12-10 10:45:22 +01:00
// dont show first frame
2018-11-05 14:49:54 +01:00
# endif
2019-04-05 07:20:52 +02:00
# ifdef YADIF
2019-10-26 18:42:19 +02:00
if ( VideoDeinterlace [ decoder - > Resolution ] = = VideoDeinterlaceYadif ) {
deint = 0 ;
2021-12-27 20:02:45 +01:00
ist - > filter = 1 ; // init yadif_cuda
2019-10-26 18:42:19 +02:00
} else {
deint = 2 ;
ist - > filter = 0 ;
}
CuvidMessage ( 2 , " deint = %s \n " , deint = = 0 ? " Yadif " : " Cuda " ) ;
2021-12-27 20:02:45 +01:00
if ( av_opt_set_int ( video_ctx - > priv_data , " deint " , deint , 0 ) < 0 ) { // adaptive
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " codec: can't set option deint to video codec! \n " ) ) ;
}
# endif
2020-04-10 16:17:23 +02:00
} else {
2020-03-31 13:57:43 +02:00
decoder - > SyncCounter = 0 ;
decoder - > FrameCounter = 0 ;
decoder - > FramesDisplayed = 0 ;
decoder - > StartCounter = 0 ;
decoder - > Closing = 0 ;
decoder - > PTS = AV_NOPTS_VALUE ;
VideoDeltaPTS = 0 ;
2020-06-01 17:15:07 +02:00
decoder - > InputAspect = video_ctx - > sample_aspect_ratio ;
2021-12-27 20:02:45 +01:00
CuvidUpdateOutput ( decoder ) ; // update aspect/scaling
2019-10-26 18:42:19 +02:00
}
CuvidMessage ( 2 , " GetFormat Init ok %dx%d \n " , video_ctx - > width , video_ctx - > height ) ;
decoder - > InputAspect = video_ctx - > sample_aspect_ratio ;
2019-08-22 12:34:29 +02:00
# ifdef CUVID
2018-11-05 14:49:54 +01:00
ist - > active_hwaccel_id = HWACCEL_CUVID ;
2019-10-20 14:48:28 +02:00
# else
2021-12-27 20:02:45 +01:00
if ( VideoDeinterlace [ decoder - > Resolution ] ) // need deinterlace
ist - > filter = 1 ; // init deint vaapi
2020-04-10 16:17:23 +02:00
else
ist - > filter = 0 ;
2020-01-13 18:17:07 +01:00
2019-08-22 12:34:29 +02:00
ist - > active_hwaccel_id = HWACCEL_VAAPI ;
# endif
2019-10-26 18:42:19 +02:00
ist - > hwaccel_pix_fmt = PIXEL_FORMAT ;
return PIXEL_FORMAT ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " NO Format valid " ) ) ;
2018-08-19 11:45:46 +02:00
return * fmt_idx ;
}
# ifdef USE_GRAB
2021-12-27 20:02:45 +01:00
void swapc ( unsigned char * x , unsigned char * y ) {
2021-04-13 13:36:21 +02:00
unsigned char temp = * x ;
2021-12-27 20:02:45 +01:00
2021-04-13 13:36:21 +02:00
* x = * y ;
* y = temp ;
}
2021-12-27 20:02:45 +01:00
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
int get_RGB ( CuvidDecoder * decoder , struct pl_overlay * ovl ) {
2018-11-17 14:58:25 +01:00
# else
2021-12-27 20:02:45 +01:00
int get_RGB ( CuvidDecoder * decoder ) {
2018-11-17 14:58:25 +01:00
# endif
2018-11-04 13:44:18 +01:00
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
struct pl_render_params render_params = pl_render_default_params ;
2021-12-27 20:02:45 +01:00
struct pl_frame target = { 0 } ;
2019-10-26 18:42:19 +02:00
const struct pl_fmt * fmt ;
2020-05-01 12:06:04 +02:00
2019-10-26 18:42:19 +02:00
int offset , x1 , y1 , x0 , y0 ;
float faktorx , faktory ;
# endif
uint8_t * base ;
int width ;
int height ;
GLuint fb , texture ;
int current ;
GLint texLoc ;
base = decoder - > grabbase ;
width = decoder - > grabwidth ;
height = decoder - > grabheight ;
current = decoder - > SurfacesRb [ decoder - > SurfaceRead ] ;
# ifndef PLACEBO
glGenTextures ( 1 , & texture ) ;
GlxCheck ( ) ;
glBindTexture ( GL_TEXTURE_2D , texture ) ;
GlxCheck ( ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
GlxCheck ( ) ;
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_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
GlxCheck ( ) ;
glGenFramebuffers ( 1 , & fb ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fb ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texture , 0 ) ;
if ( glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ! = GL_FRAMEBUFFER_COMPLETE ) {
Debug ( 3 , " video/cuvid: grab Framebuffer is not complete! " ) ;
return 0 ;
}
glViewport ( 0 , 0 , width , height ) ;
GlxCheck ( ) ;
if ( gl_prog = = 0 )
2021-12-27 20:02:45 +01:00
gl_prog = sc_generate ( gl_prog , decoder - > ColorSpace ) ; // generate shader programm
2019-10-26 18:42:19 +02:00
glUseProgram ( gl_prog ) ;
texLoc = glGetUniformLocation ( gl_prog , " texture0 " ) ;
glUniform1i ( texLoc , 0 ) ;
texLoc = glGetUniformLocation ( gl_prog , " texture1 " ) ;
glUniform1i ( texLoc , 1 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2019-12-23 11:14:38 +01:00
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ current * Planes + 0 ] ) ;
2019-10-26 18:42:19 +02:00
glActiveTexture ( GL_TEXTURE1 ) ;
2019-12-23 11:14:38 +01:00
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ current * Planes + 1 ] ) ;
2019-10-26 18:42:19 +02:00
glBindFramebuffer ( GL_FRAMEBUFFER , fb ) ;
render_pass_quad ( 1 , 0.0 , 0.0 ) ;
glUseProgram ( 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
if ( OsdShown & & decoder - > grab = = 2 ) {
2019-11-18 13:01:19 +01:00
int x , y , h , w ;
2019-10-26 18:42:19 +02:00
GLint texLoc ;
2019-11-18 13:01:19 +01:00
2019-11-11 17:45:59 +01:00
if ( OsdShown = = 1 ) {
if ( OSDtexture )
2019-11-18 13:01:19 +01:00
glDeleteTextures ( 1 , & OSDtexture ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_lock(&OSDMutex);
2019-11-11 17:45:59 +01:00
glGenTextures ( 1 , & OSDtexture ) ;
glBindTexture ( GL_TEXTURE_2D , OSDtexture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , OSDxsize , OSDysize , 0 , GL_RGBA , GL_UNSIGNED_BYTE , posd ) ;
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_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_unlock(&OSDMutex);
2019-11-11 17:45:59 +01:00
OsdShown = 2 ;
}
2019-11-05 22:06:54 +01:00
2019-11-18 13:01:19 +01:00
y = OSDy * height / VideoWindowHeight ;
x = OSDx * width / VideoWindowWidth ;
h = OSDysize * height / VideoWindowHeight ;
w = OSDxsize * width / VideoWindowWidth ;
glViewport ( x , ( height - h - y ) , w , h ) ;
2019-10-26 18:42:19 +02:00
glEnable ( GL_BLEND ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
if ( gl_prog_osd = = 0 )
gl_prog_osd = sc_generate_osd ( gl_prog_osd ) ; // generate shader programm
glUseProgram ( gl_prog_osd ) ;
texLoc = glGetUniformLocation ( gl_prog_osd , " texture0 " ) ;
glUniform1i ( texLoc , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_lock(&OSDMutex);
2019-10-26 18:42:19 +02:00
glBindTexture ( GL_TEXTURE_2D , OSDtexture ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , fb ) ;
2019-11-05 22:06:54 +01:00
render_pass_quad ( 0 , 0.0 , 0.0 ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_unlock(&OSDMutex);
2019-10-26 18:42:19 +02:00
glUseProgram ( 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
}
glFlush ( ) ;
2022-05-24 00:09:55 +02:00
// Debug(3, "Read pixels %d %d\n", width, height);
2019-10-26 18:42:19 +02:00
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2018-11-17 14:58:25 +01:00
2019-10-26 18:42:19 +02:00
glReadPixels ( 0 , 0 , width , height , GL_BGRA , GL_UNSIGNED_BYTE , base ) ;
2018-11-17 14:58:25 +01:00
GlxCheck ( ) ;
2019-10-26 18:42:19 +02:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glDeleteFramebuffers ( 1 , & fb ) ;
glDeleteTextures ( 1 , & texture ) ;
2020-04-10 16:17:23 +02:00
# else // Placebo
2019-10-26 18:42:19 +02:00
faktorx = ( float ) width / ( float ) VideoWindowWidth ;
faktory = ( float ) height / ( float ) VideoWindowHeight ;
2021-04-13 13:36:21 +02:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
fmt = pl_find_named_fmt ( p - > gpu , " rgba8 " ) ; // bgra8 not supported
2021-04-13 13:36:21 +02:00
# else
2021-12-27 20:02:45 +01:00
fmt = pl_find_named_fmt ( p - > gpu , " bgra8 " ) ;
2021-04-13 13:36:21 +02:00
# endif
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2021-12-27 20:02:45 +01:00
target . fbo = pl_tex_create (
p - > gpu , & ( struct pl_tex_params ) {
2021-11-16 15:05:49 +01:00
# else
target . num_planes = 1 ;
target . planes [ 0 ] . components = 4 ;
target . planes [ 0 ] . component_mapping [ 0 ] = PL_CHANNEL_R ;
target . planes [ 0 ] . component_mapping [ 1 ] = PL_CHANNEL_G ;
target . planes [ 0 ] . component_mapping [ 2 ] = PL_CHANNEL_B ;
target . planes [ 0 ] . component_mapping [ 3 ] = PL_CHANNEL_A ;
2021-12-27 20:02:45 +01:00
target . planes [ 0 ] . texture = pl_tex_create (
p - > gpu , & ( struct pl_tex_params ) {
2021-11-16 15:05:49 +01:00
# endif
2021-12-27 20:02:45 +01:00
. w = width , . h = height , . d = 0 , . format = fmt , . sampleable = true , . renderable = true , . blit_dst = true ,
2019-10-26 18:42:19 +02:00
. host_readable = true ,
2021-12-27 20:02:45 +01:00
# if PL_API_VER < 159
. sample_mode = PL_TEX_SAMPLE_LINEAR , . address_mode = PL_TEX_ADDRESS_CLAMP ,
2021-11-16 15:05:49 +01:00
# endif
2019-10-26 18:42:19 +02:00
} ) ;
2021-12-27 20:02:45 +01:00
# if PL_API_VER >= 100
2021-01-10 13:55:09 +01:00
target . crop . x0 = ( float ) decoder - > OutputX * faktorx ;
target . crop . y0 = ( float ) decoder - > OutputY * faktory ;
target . crop . x1 = ( float ) ( decoder - > OutputX + decoder - > OutputWidth ) * faktorx ;
target . crop . y1 = ( float ) ( decoder - > OutputY + decoder - > OutputHeight ) * faktory ;
# else
2019-10-26 18:42:19 +02:00
target . dst_rect . x0 = ( float ) decoder - > OutputX * faktorx ;
target . dst_rect . y0 = ( float ) decoder - > OutputY * faktory ;
target . dst_rect . x1 = ( float ) ( decoder - > OutputX + decoder - > OutputWidth ) * faktorx ;
target . dst_rect . y1 = ( float ) ( decoder - > OutputY + decoder - > OutputHeight ) * faktory ;
2021-01-10 13:55:09 +01:00
# endif
2019-10-26 18:42:19 +02:00
target . repr . sys = PL_COLOR_SYSTEM_RGB ;
target . repr . levels = PL_COLOR_LEVELS_PC ;
target . repr . alpha = PL_ALPHA_UNKNOWN ;
target . repr . bits . sample_depth = 8 ;
target . repr . bits . color_depth = 8 ;
target . repr . bits . bit_shift = 0 ;
target . color . primaries = PL_COLOR_PRIM_BT_709 ;
target . color . transfer = PL_COLOR_TRC_BT_1886 ;
2023-07-14 10:46:25 +02:00
//target.color.light = PL_COLOR_LIGHT_DISPLAY;
//target.color.sig_peak = 0;
//target.color.sig_avg = 0;
2019-10-26 18:42:19 +02:00
if ( ovl ) {
target . overlays = ovl ;
target . num_overlays = 1 ;
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2021-04-13 13:36:21 +02:00
# ifdef PLACEBO_GL
2019-10-26 18:42:19 +02:00
x0 = ovl - > rect . x0 ;
2021-04-13 13:36:21 +02:00
y1 = ovl - > rect . y0 ;
x1 = ovl - > rect . x1 ;
y0 = ovl - > rect . y1 ;
2021-12-27 20:02:45 +01:00
ovl - > rect . x0 = ( float ) x0 * faktorx ;
ovl - > rect . y0 = ( float ) y0 * faktory ;
ovl - > rect . x1 = ( float ) x1 * faktorx ;
ovl - > rect . y1 = ( float ) y1 * faktory ;
2021-04-13 13:36:21 +02:00
# else
2021-12-27 20:02:45 +01:00
x0 = ovl - > rect . x0 ;
2019-10-26 18:42:19 +02:00
y0 = ovl - > rect . y0 ;
x1 = ovl - > rect . x1 ;
y1 = ovl - > rect . y1 ;
2021-12-27 20:02:45 +01:00
ovl - > rect . x0 = ( float ) x0 * faktorx ;
ovl - > rect . y0 = ( float ) y0 * faktory ;
ovl - > rect . x1 = ( float ) x1 * faktorx ;
ovl - > rect . y1 = ( float ) y1 * faktory ;
2021-04-13 13:36:21 +02:00
# endif
2023-02-15 15:58:51 +01:00
# else
# ifdef PLACEBO_GL
x0 = part . dst . x0 ;
y1 = part . dst . y0 ;
x1 = part . dst . x1 ;
y0 = part . dst . y1 ;
part . dst . x0 = ( float ) x0 * faktorx ;
part . dst . y0 = ( float ) y0 * faktory ;
part . dst . x1 = ( float ) x1 * faktorx ;
part . dst . y1 = ( float ) y1 * faktory ;
# else
x0 = part . dst . x0 ;
y0 = part . dst . y0 ;
x1 = part . dst . x1 ;
y1 = part . dst . y1 ;
part . dst . x0 = ( float ) x0 * faktorx ;
part . dst . y0 = ( float ) y0 * faktory ;
part . dst . x1 = ( float ) x1 * faktorx ;
part . dst . y1 = ( float ) y1 * faktory ;
# endif
# endif
2019-10-26 18:42:19 +02:00
} else {
target . overlays = 0 ;
target . num_overlays = 0 ;
}
2021-03-16 09:40:08 +01:00
if ( ! pl_render_image ( p - > renderer , & decoder - > pl_frames [ current ] , & target , & render_params ) ) {
2018-11-04 13:44:18 +01:00
Fatal ( _ ( " Failed rendering frame! \n " ) ) ;
}
2021-04-13 13:36:21 +02:00
2019-10-26 18:42:19 +02:00
pl_gpu_finish ( p - > gpu ) ;
if ( ovl ) {
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2021-04-13 13:36:21 +02:00
# ifdef PLACEBO_GL
2019-10-26 18:42:19 +02:00
ovl - > rect . x0 = x0 ;
2021-04-13 13:36:21 +02:00
ovl - > rect . y0 = y1 ;
ovl - > rect . x1 = x1 ;
ovl - > rect . y1 = y0 ;
# else
2021-12-27 20:02:45 +01:00
ovl - > rect . x0 = x0 ;
2019-10-26 18:42:19 +02:00
ovl - > rect . y0 = y0 ;
ovl - > rect . x1 = x1 ;
ovl - > rect . y1 = y1 ;
2023-02-15 15:58:51 +01:00
# endif
# else
# ifdef PLACEBO_GL
part . dst . x0 = x0 ;
part . dst . y0 = y1 ;
part . dst . x1 = x1 ;
part . dst . y1 = y0 ;
# else
part . dst . x0 = x0 ;
part . dst . y0 = y0 ;
part . dst . x1 = x1 ;
part . dst . y1 = y1 ;
# endif
2021-04-13 13:36:21 +02:00
# endif
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
pl_tex_download (
p - > gpu , & ( struct pl_tex_transfer_params ) { // download Data
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2019-10-26 18:42:19 +02:00
. tex = target . fbo ,
2021-11-16 15:05:49 +01:00
# else
2021-12-27 20:02:45 +01:00
. tex = target . planes [ 0 ] . texture ,
2021-11-16 15:05:49 +01:00
# endif
2019-10-26 18:42:19 +02:00
. ptr = base ,
} ) ;
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2019-10-26 18:42:19 +02:00
pl_tex_destroy ( p - > gpu , & target . fbo ) ;
2021-11-16 15:05:49 +01:00
# else
pl_tex_destroy ( p - > gpu , & target . planes [ 0 ] . texture ) ;
# endif
2021-04-13 13:36:21 +02:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
unsigned char * b = base ;
for ( int i = 0 ; i < width * height * 4 ; i + = 4 )
swapc ( & b [ i + 0 ] , & b [ i + 2 ] ) ;
2021-04-13 13:36:21 +02:00
# endif
2019-10-26 18:42:19 +02:00
# endif
return 0 ;
2018-10-04 16:49:06 +02:00
}
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Grab output surface already locked.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param ret_size[out] size of allocated surface copy
2021-12-27 20:02:45 +01:00
/// @param ret_width[in,out] width of output
/// @param ret_height[in,out] height of output
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static uint8_t * CuvidGrabOutputSurfaceLocked ( int * ret_size , int * ret_width , int * ret_height , int mitosd ) {
2018-08-19 11:45:46 +02:00
uint32_t size ;
uint32_t width ;
uint32_t height ;
2018-10-04 16:49:06 +02:00
uint8_t * base ;
2018-08-19 11:45:46 +02:00
VdpRect source_rect ;
2019-10-26 18:42:19 +02:00
CuvidDecoder * decoder ;
decoder = CuvidDecoders [ 0 ] ;
2021-12-27 20:02:45 +01:00
if ( decoder = = NULL ) // no video aktiv
2019-10-26 18:42:19 +02:00
return NULL ;
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
// surface = CuvidSurfacesRb[CuvidOutputSurfaceIndex];
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
// get real surface size
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2018-12-11 17:29:01 +01:00
width = decoder - > VideoWidth ;
2019-10-26 18:42:19 +02:00
height = decoder - > VideoHeight ;
2018-11-17 14:58:25 +01:00
# else
2019-10-26 18:42:19 +02:00
width = decoder - > InputWidth ;
height = decoder - > InputHeight ;
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
2019-10-28 21:43:37 +01:00
// Debug(3, "video/cuvid: grab %dx%d\n", width, height);
2018-08-19 11:45:46 +02:00
source_rect . x0 = 0 ;
source_rect . y0 = 0 ;
source_rect . x1 = width ;
source_rect . y1 = height ;
if ( ret_width & & ret_height ) {
2021-12-27 20:02:45 +01:00
if ( * ret_width < = - 64 ) { // this is an Atmo grab service request
2019-10-26 18:42:19 +02:00
int overscan ;
// calculate aspect correct size of analyze image
width = * ret_width * - 1 ;
height = ( width * source_rect . y1 ) / source_rect . x1 ;
// calculate size of grab (sub) window
overscan = * ret_height ;
if ( overscan > 0 & & overscan < = 200 ) {
source_rect . x0 = source_rect . x1 * overscan / 1000 ;
source_rect . x1 - = source_rect . x0 ;
source_rect . y0 = source_rect . y1 * overscan / 1000 ;
source_rect . y1 - = source_rect . y0 ;
}
} else {
if ( * ret_width > 0 & & ( unsigned ) * ret_width < width ) {
width = * ret_width ;
}
if ( * ret_height > 0 & & ( unsigned ) * ret_height < height ) {
height = * ret_height ;
}
}
2019-10-28 21:43:37 +01:00
// printf("video/cuvid: grab source dim %dx%d\n", width, height);
2019-10-26 18:42:19 +02:00
size = width * height * sizeof ( uint32_t ) ;
base = malloc ( size ) ;
if ( ! base ) {
Error ( _ ( " video/cuvid: out of memory \n " ) ) ;
return NULL ;
}
decoder - > grabbase = base ;
decoder - > grabwidth = width ;
decoder - > grabheight = height ;
if ( mitosd )
decoder - > grab = 2 ;
else
decoder - > grab = 1 ;
while ( decoder - > grab ) {
2021-12-27 20:02:45 +01:00
usleep ( 1000 ) ; // wait for data
2019-10-26 18:42:19 +02:00
}
2019-10-28 21:43:37 +01:00
// Debug(3,"got grab data\n");
2019-10-26 18:42:19 +02:00
if ( ret_size ) {
* ret_size = size ;
}
if ( ret_width ) {
* ret_width = width ;
}
if ( ret_height ) {
* ret_height = height ;
}
return base ;
}
2018-08-19 11:45:46 +02:00
2018-10-04 16:49:06 +02:00
return NULL ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Grab output surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param ret_size[out] size of allocated surface copy
2021-12-27 20:02:45 +01:00
/// @param ret_width[in,out] width of output
/// @param ret_height[in,out] height of output
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static uint8_t * CuvidGrabOutputSurface ( int * ret_size , int * ret_width , int * ret_height , int mitosd ) {
2018-08-19 11:45:46 +02:00
uint8_t * img ;
2018-10-25 20:04:35 +02:00
img = CuvidGrabOutputSurfaceLocked ( ret_size , ret_width , ret_height , mitosd ) ;
2018-08-19 11:45:46 +02:00
return img ;
}
# endif
///
2019-10-26 18:42:19 +02:00
/// Queue output surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
/// @param surface output surface
/// @param softdec software decoder
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note we can't mix software and hardware decoder surfaces
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidQueueVideoSurface ( CuvidDecoder * decoder , int surface , int softdec ) {
2018-08-19 11:45:46 +02:00
int old ;
+ + decoder - > FrameCounter ;
// can't wait for output queue empty
2019-10-26 18:42:19 +02:00
if ( atomic_read ( & decoder - > SurfacesFilled ) > = VIDEO_SURFACES_MAX ) {
2020-01-08 17:04:18 +01:00
Warning ( _ ( " video/cuvid: output buffer full, dropping frame (%d/%d) \n " ) , + + decoder - > FramesDropped ,
2021-12-27 20:02:45 +01:00
decoder - > FrameCounter ) ;
2019-10-26 18:42:19 +02:00
if ( ! ( decoder - > FramesDisplayed % 300 ) ) {
CuvidPrintFrames ( decoder ) ;
}
// software surfaces only
if ( softdec ) {
CuvidReleaseSurface ( decoder , surface ) ;
}
return ;
}
2018-08-19 11:45:46 +02:00
//
2019-10-28 21:43:37 +01:00
// Check and release, old surface
2018-08-19 11:45:46 +02:00
//
2019-10-26 18:42:19 +02:00
if ( ( old = decoder - > SurfacesRb [ decoder - > SurfaceWrite ] ) ! = - 1 ) {
// now we can release the surface, software surfaces only
if ( softdec ) {
CuvidReleaseSurface ( decoder , old ) ;
}
2018-08-19 11:45:46 +02:00
}
2020-01-08 17:04:18 +01:00
Debug ( 4 , " video/cuvid: yy video surface %#08x@%d ready \n " , surface , decoder - > SurfaceWrite ) ;
2018-08-19 11:45:46 +02:00
decoder - > SurfacesRb [ decoder - > SurfaceWrite ] = surface ;
2019-10-26 18:42:19 +02:00
decoder - > SurfaceWrite = ( decoder - > SurfaceWrite + 1 ) % VIDEO_SURFACES_MAX ;
2018-08-19 11:45:46 +02:00
atomic_inc ( & decoder - > SurfacesFilled ) ;
}
2019-08-22 12:34:29 +02:00
#if 0
2019-10-26 18:42:19 +02:00
extern void Nv12ToBgra32 ( uint8_t * dpNv12 , int nNv12Pitch , uint8_t * dpBgra , int nBgraPitch , int nWidth , int nHeight ,
int iMatrix , cudaStream_t stream ) ;
extern void P016ToBgra32 ( uint8_t * dpNv12 , int nNv12Pitch , uint8_t * dpBgra , int nBgraPitch , int nWidth , int nHeight ,
int iMatrix , cudaStream_t stream ) ;
extern void ResizeNv12 ( unsigned char * dpDstNv12 , int nDstPitch , int nDstWidth , int nDstHeight ,
unsigned char * dpSrcNv12 , int nSrcPitch , int nSrcWidth , int nSrcHeight , unsigned char * dpDstNv12UV ) ;
extern void ResizeP016 ( unsigned char * dpDstP016 , int nDstPitch , int nDstWidth , int nDstHeight ,
unsigned char * dpSrcP016 , int nSrcPitch , int nSrcWidth , int nSrcHeight , unsigned char * dpDstP016UV ) ;
extern void cudaLaunchNV12toARGBDrv ( uint32_t * d_srcNV12 , size_t nSourcePitch , uint32_t * d_dstARGB , size_t nDestPitch ,
uint32_t width , uint32_t height , CUstream streamID ) ;
# endif
2019-10-20 14:48:28 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Render a ffmpeg frame.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2021-12-27 20:02:45 +01:00
/// @param video_ctx ffmpeg video codec context
2019-10-26 18:42:19 +02:00
/// @param frame frame to display
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidRenderFrame ( CuvidDecoder * decoder , const AVCodecContext * video_ctx , AVFrame * frame ) {
2019-10-26 18:42:19 +02:00
uint64_t first_time ;
2018-08-19 11:45:46 +02:00
int surface ;
2019-10-26 18:42:19 +02:00
enum AVColorSpace color ;
if ( decoder - > Closing = = 1 ) {
av_frame_free ( & frame ) ;
return ;
}
2020-04-10 16:17:23 +02:00
2020-03-31 13:57:43 +02:00
if ( ! decoder - > Closing ) {
VideoSetPts ( & decoder - > PTS , decoder - > Interlaced , video_ctx , frame ) ;
}
2020-04-10 16:17:23 +02:00
2018-08-19 11:45:46 +02:00
// update aspect ratio changes
2019-10-26 18:42:19 +02:00
if ( decoder - > InputWidth & & decoder - > InputHeight & & av_cmp_q ( decoder - > InputAspect , frame - > sample_aspect_ratio ) ) {
2020-01-08 17:04:18 +01:00
Debug ( 3 , " video/cuvid: aspect ratio changed \n " ) ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
decoder - > InputAspect = frame - > sample_aspect_ratio ;
2021-12-27 20:02:45 +01:00
// printf("new aspect
// %d:%d\n",frame->sample_aspect_ratio.num,frame->sample_aspect_ratio.den);
2019-10-26 18:42:19 +02:00
CuvidUpdateOutput ( decoder ) ;
}
2021-12-27 20:02:45 +01:00
// printf("Orig colorspace %d Primaries %d TRC %d -------
//",frame->colorspace,frame->color_primaries,frame->color_trc);
// Fix libav colorspace failure
color = frame - > colorspace ;
if ( color = = AVCOL_SPC_UNSPECIFIED ) // failure with RTL HD and all SD channels
// with vaapi
if ( frame - > width > 720 )
color = AVCOL_SPC_BT709 ;
else
color = AVCOL_SPC_BT470BG ;
if ( color = = AVCOL_SPC_RGB ) // Cuvid decoder failure with SD channels
color = AVCOL_SPC_BT470BG ;
2021-03-16 09:40:08 +01:00
frame - > colorspace = color ;
2021-12-27 20:02:45 +01:00
// Fix libav Color primaries failures
if ( frame - > color_primaries = = AVCOL_PRI_UNSPECIFIED ) // failure with RTL HD and all SD channels with
// vaapi
if ( frame - > width > 720 )
frame - > color_primaries = AVCOL_PRI_BT709 ;
else
frame - > color_primaries = AVCOL_PRI_BT470BG ;
if ( frame - > color_primaries = = AVCOL_PRI_RESERVED0 ) // cuvid decoder failure with SD channels
frame - > color_primaries = AVCOL_PRI_BT470BG ;
// Fix libav Color TRC failures
if ( frame - > color_trc = = AVCOL_TRC_UNSPECIFIED ) // failure with RTL HD and all
// SD channels with vaapi
if ( frame - > width > 720 )
frame - > color_trc = AVCOL_TRC_BT709 ;
else
frame - > color_trc = AVCOL_TRC_SMPTE170M ;
if ( frame - > color_trc = = AVCOL_TRC_RESERVED0 ) // cuvid decoder failure with SD channels
frame - > color_trc = AVCOL_TRC_SMPTE170M ;
2022-05-24 00:09:55 +02:00
// printf("Patched colorspace %d Primaries %d TRC
// %d\n",frame->colorspace,frame->color_primaries,frame->color_trc);
2019-10-26 18:42:19 +02:00
//
2021-12-27 20:02:45 +01:00
// Copy data from frame to image
2019-10-26 18:42:19 +02:00
//
if ( video_ctx - > pix_fmt = = PIXEL_FORMAT ) {
int w = decoder - > InputWidth ;
int h = decoder - > InputHeight ;
2021-12-27 20:02:45 +01:00
decoder - > ColorSpace = color ; // save colorspace
2019-10-26 18:42:19 +02:00
decoder - > trc = frame - > color_trc ;
decoder - > color_primaries = frame - > color_primaries ;
surface = CuvidGetVideoSurface0 ( decoder ) ;
2021-12-27 20:02:45 +01:00
if ( surface = = - 1 ) { // no free surfaces
2019-10-26 18:42:19 +02:00
Debug ( 3 , " no more surfaces \n " ) ;
av_frame_free ( & frame ) ;
return ;
}
2021-12-27 20:02:45 +01:00
# if defined(VAAPI) && defined(PLACEBO)
if ( p - > has_dma_buf ) { // Vulkan supports DMA_BUF no copy required
2019-10-26 18:42:19 +02:00
generateVAAPIImage ( decoder , surface , frame , w , h ) ;
2021-12-27 20:02:45 +01:00
} else { // we need to Copy the frame via RAM
2019-10-26 18:42:19 +02:00
AVFrame * output ;
VideoThreadLock ( ) ;
vaSyncSurface ( decoder - > VaDisplay , ( unsigned int ) frame - > data [ 3 ] ) ;
output = av_frame_alloc ( ) ;
av_hwframe_transfer_data ( output , frame , 0 ) ;
av_frame_copy_props ( output , frame ) ;
2021-12-27 20:02:45 +01:00
// printf("Save Surface ID %d %p
// %p\n",surface,decoder->pl_frames[surface].planes[0].texture,decoder->pl_frames[surface].planes[1].texture);
bool ok = pl_tex_upload ( p - > gpu , & ( struct pl_tex_transfer_params ) {
. tex = decoder - > pl_frames [ surface ] . planes [ 0 ] . texture ,
. stride_w = output - > linesize [ 0 ] ,
. stride_h = h ,
. ptr = output - > data [ 0 ] ,
. rc . x1 = w ,
. rc . y1 = h ,
. rc . z1 = 0 ,
} ) ;
ok & = pl_tex_upload ( p - > gpu , & ( struct pl_tex_transfer_params ) {
. tex = decoder - > pl_frames [ surface ] . planes [ 1 ] . texture ,
. stride_w = output - > linesize [ 0 ] / 2 ,
. stride_h = h / 2 ,
. ptr = output - > data [ 1 ] ,
. rc . x1 = w / 2 ,
. rc . y1 = h / 2 ,
. rc . z1 = 0 ,
} ) ;
2019-10-26 18:42:19 +02:00
av_frame_free ( & output ) ;
VideoThreadUnlock ( ) ;
}
2019-10-04 10:37:57 +02:00
# else
2019-08-22 12:34:29 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
// copy to texture
generateCUDAImage ( decoder , surface , frame , w , h , decoder - > PixFmt = = AV_PIX_FMT_NV12 ? 1 : 2 ) ;
# else
// copy to texture
generateVAAPIImage ( decoder , surface , frame , w , h ) ;
2019-08-22 12:34:29 +02:00
# endif
2019-10-04 10:37:57 +02:00
# endif
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
CuvidQueueVideoSurface ( decoder , surface , 1 ) ;
decoder - > frames [ surface ] = frame ;
return ;
}
2021-12-27 20:02:45 +01:00
// Debug(3,"video/cuvid: pixel format %d not supported\n",
// video_ctx->pix_fmt);
2020-04-10 16:17:23 +02:00
av_frame_free ( & frame ) ;
return ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Get hwaccel context for ffmpeg.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void * CuvidGetHwAccelContext ( CuvidDecoder * decoder ) {
2020-04-10 16:17:23 +02:00
unsigned int version , ret ;
2018-11-05 14:49:54 +01:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Initializing cuvid hwaccel thread ID:%ld \n " , ( long int ) syscall ( 186 ) ) ;
2019-10-28 21:43:37 +01:00
// turn NULL;
2019-08-22 12:34:29 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
if ( decoder - > cuda_ctx ) {
Debug ( 3 , " schon passiert \n " ) ;
return NULL ;
}
2020-04-10 16:17:23 +02:00
2020-03-06 12:42:14 +01:00
if ( ! cu ) {
ret = cuda_load_functions ( & cu , NULL ) ;
if ( ret < 0 ) {
Error ( _ ( " Could not dynamically load CUDA \n " ) ) ;
return 0 ;
}
}
checkCudaErrors ( cu - > cuInit ( 0 ) ) ;
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
checkCudaErrors ( cu - > cuCtxCreate ( & decoder - > cuda_ctx , ( unsigned int ) CU_CTX_SCHED_BLOCKING_SYNC , ( CUdevice ) 0 ) ) ;
2019-10-26 18:42:19 +02:00
2018-11-05 14:49:54 +01:00
if ( decoder - > cuda_ctx = = NULL )
2019-10-26 18:42:19 +02:00
Fatal ( _ ( " Kein Cuda device gefunden " ) ) ;
2018-11-05 14:49:54 +01:00
2020-03-06 12:42:14 +01:00
// cu->cuCtxGetApiVersion(decoder->cuda_ctx, &version);
// Debug(3, "***********CUDA API Version %d\n", version);
2019-08-22 12:34:29 +02:00
# endif
2019-10-26 18:42:19 +02:00
return NULL ;
2018-11-04 13:44:18 +01:00
}
2018-08-19 11:45:46 +02:00
2018-11-17 14:58:25 +01:00
///
2019-10-26 18:42:19 +02:00
/// Create and display a black empty surface.
2018-11-17 14:58:25 +01:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-11-17 14:58:25 +01:00
///
2019-10-26 18:42:19 +02:00
/// @FIXME: render only video area, not fullscreen!
/// decoder->Output.. isn't correct setup for radio stations
2018-11-17 14:58:25 +01:00
///
2021-12-27 20:02:45 +01:00
static void CuvidBlackSurface ( __attribute__ ( ( unused ) ) CuvidDecoder * decoder ) {
2018-11-24 09:34:55 +01:00
# ifndef PLACEBO
2019-10-26 18:42:19 +02:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2018-11-24 09:34:55 +01:00
# endif
2019-10-26 18:42:19 +02:00
return ;
2018-11-17 14:58:25 +01:00
}
///
2019-10-26 18:42:19 +02:00
/// Advance displayed frame of decoder.
2018-11-17 14:58:25 +01:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-11-17 14:58:25 +01:00
///
2021-12-27 20:02:45 +01:00
static void CuvidAdvanceDecoderFrame ( CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
// next surface, if complete frame is displayed (1 -> 0)
if ( decoder - > SurfaceField ) {
int filled ;
// FIXME: this should check the caller
// check decoder, if new surface is available
// need 2 frames for progressive
// need 4 frames for interlaced
filled = atomic_read ( & decoder - > SurfacesFilled ) ;
if ( filled < = 1 + 2 * decoder - > Interlaced ) {
// keep use of last surface
+ + decoder - > FramesDuped ;
// FIXME: don't warn after stream start, don't warn during pause
2019-10-28 21:43:37 +01:00
// printf("video: display buffer empty, duping frame (%d/%d) %d\n",
// decoder->FramesDuped, decoder->FrameCounter,
// VideoGetBuffers(decoder->Stream));
2019-10-26 18:42:19 +02:00
return ;
}
2019-08-22 12:34:29 +02:00
2019-10-26 18:42:19 +02:00
decoder - > SurfaceRead = ( decoder - > SurfaceRead + 1 ) % VIDEO_SURFACES_MAX ;
atomic_dec ( & decoder - > SurfacesFilled ) ;
decoder - > SurfaceField = ! decoder - > Interlaced ;
return ;
}
// next field
decoder - > SurfaceField = 1 ;
2018-11-17 14:58:25 +01:00
}
2021-12-27 20:02:45 +01:00
2020-06-07 12:31:18 +02:00
# if defined PLACEBO && PL_API_VER >= 58
2021-12-27 20:02:45 +01:00
static const struct pl_hook * parse_user_shader ( char * shader ) {
2020-06-07 12:31:18 +02:00
char tmp [ 200 ] ;
2021-12-27 20:02:45 +01:00
if ( ! shader )
2020-06-07 12:31:18 +02:00
return NULL ;
const struct pl_hook * hook = NULL ;
char * str = NULL ;
2020-06-16 08:49:03 +02:00
2021-12-27 20:02:45 +01:00
// Debug(3,"Parse user shader %s/%s\n",MyConfigDir,shader);
sprintf ( tmp , " %s/%s " , MyConfigDir , shader ) ;
2020-06-07 12:31:18 +02:00
FILE * f = fopen ( tmp , " rb " ) ;
if ( ! f ) {
2020-06-16 08:49:03 +02:00
Debug ( 3 , " Failed to open shader file %s: %s \n " , tmp , strerror ( errno ) ) ;
2020-06-07 12:31:18 +02:00
goto error ;
}
int ret = fseek ( f , 0 , SEEK_END ) ;
2021-12-27 20:02:45 +01:00
2020-06-07 12:31:18 +02:00
if ( ret = = - 1 )
goto error ;
long length = ftell ( f ) ;
2021-12-27 20:02:45 +01:00
2020-06-07 12:31:18 +02:00
if ( length = = - 1 )
goto error ;
rewind ( f ) ;
str = malloc ( length ) ;
if ( ! str )
goto error ;
ret = fread ( str , length , 1 , f ) ;
if ( ret ! = 1 )
goto error ;
hook = pl_mpv_user_shader_parse ( p - > gpu , str , length ) ;
// fall through
2021-12-27 20:02:45 +01:00
Debug ( 3 , " User shader %p \n " , hook ) ;
2020-06-07 12:31:18 +02:00
error :
if ( f )
fclose ( f ) ;
free ( str ) ;
return hook ;
}
# endif
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Render video surface to output surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
/// @param level video surface level 0 = bottom
2018-08-19 11:45:46 +02:00
///
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
static void CuvidMixVideo ( CuvidDecoder * decoder , int level , struct pl_frame * target , struct pl_overlay * ovl )
2019-10-26 18:42:19 +02:00
# else
2021-12-27 20:02:45 +01:00
static void CuvidMixVideo ( CuvidDecoder * decoder , __attribute__ ( ( unused ) ) int level )
2019-10-26 18:42:19 +02:00
# endif
{
# ifdef PLACEBO
struct pl_render_params render_params ;
struct pl_deband_params deband ;
struct pl_color_adjustment colors ;
struct pl_cone_params cone ;
struct pl_tex_vk * vkp ;
2019-12-10 10:45:22 +01:00
struct pl_plane * pl ;
2021-12-27 20:02:45 +01:00
struct pl_tex * tex0 , * tex1 ;
2020-05-01 12:06:04 +02:00
2021-03-16 09:40:08 +01:00
struct pl_frame * img ;
2019-10-26 18:42:19 +02:00
bool ok ;
VdpRect video_src_rect ;
VdpRect dst_rect ;
VdpRect dst_video_rect ;
# endif
int current ;
int y ;
float xcropf , ycropf ;
GLint texLoc ;
2019-12-10 10:45:22 +01:00
AVFrame * frame ;
2021-12-27 20:02:45 +01:00
AVFrameSideData * sd , * sd1 = NULL , * sd2 = NULL ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
# ifdef PLACEBO
if ( level ) {
2021-12-27 20:02:45 +01:00
dst_rect . x0 = decoder - > VideoX ; // video window output (clip)
2019-10-26 18:42:19 +02:00
dst_rect . y0 = decoder - > VideoY ;
dst_rect . x1 = decoder - > VideoX + decoder - > VideoWidth ;
dst_rect . y1 = decoder - > VideoY + decoder - > VideoHeight ;
} else {
2021-12-27 20:02:45 +01:00
dst_rect . x0 = 0 ; // complete window (clip)
2019-10-26 18:42:19 +02:00
dst_rect . y0 = 0 ;
dst_rect . x1 = VideoWindowWidth ;
dst_rect . y1 = VideoWindowHeight ;
}
video_src_rect . x0 = decoder - > CropX ; // video source (crop)
video_src_rect . y0 = decoder - > CropY ;
video_src_rect . x1 = decoder - > CropX + decoder - > CropWidth ;
video_src_rect . y1 = decoder - > CropY + decoder - > CropHeight ;
2021-12-27 20:02:45 +01:00
dst_video_rect . x0 = decoder - > OutputX ; // video output (scale)
2019-10-26 18:42:19 +02:00
dst_video_rect . y0 = decoder - > OutputY ;
dst_video_rect . x1 = decoder - > OutputX + decoder - > OutputWidth ;
dst_video_rect . y1 = decoder - > OutputY + decoder - > OutputHeight ;
# endif
xcropf = ( float ) decoder - > CropX / ( float ) decoder - > InputWidth ;
ycropf = ( float ) decoder - > CropY / ( float ) decoder - > InputHeight ;
current = decoder - > SurfacesRb [ decoder - > SurfaceRead ] ;
2020-04-10 16:17:23 +02:00
# ifdef USE_DRM
2019-10-26 18:42:19 +02:00
if ( ! decoder - > Closing ) {
2020-04-10 16:17:23 +02:00
frame = decoder - > frames [ current ] ;
2021-03-16 09:40:08 +01:00
sd1 = av_frame_get_side_data ( frame , AV_FRAME_DATA_MASTERING_DISPLAY_METADATA ) ;
sd2 = av_frame_get_side_data ( frame , AV_FRAME_DATA_CONTENT_LIGHT_LEVEL ) ;
2020-04-10 16:17:23 +02:00
set_hdr_metadata ( frame - > color_primaries , frame - > color_trc , sd1 , sd2 ) ;
2019-10-26 18:42:19 +02:00
}
2020-03-31 13:57:43 +02:00
# endif
2020-04-10 16:17:23 +02:00
// Render Progressive frame
2019-10-26 18:42:19 +02:00
# ifndef PLACEBO
y = VideoWindowHeight - decoder - > OutputY - decoder - > OutputHeight ;
if ( y < 0 )
y = 0 ;
glViewport ( decoder - > OutputX , y , decoder - > OutputWidth , decoder - > OutputHeight ) ;
if ( gl_prog = = 0 )
2021-12-27 20:02:45 +01:00
gl_prog = sc_generate ( gl_prog , decoder - > ColorSpace ) ; // generate shader programm
2019-10-26 18:42:19 +02:00
glUseProgram ( gl_prog ) ;
texLoc = glGetUniformLocation ( gl_prog , " texture0 " ) ;
glUniform1i ( texLoc , 0 ) ;
texLoc = glGetUniformLocation ( gl_prog , " texture1 " ) ;
glUniform1i ( texLoc , 1 ) ;
2020-04-10 16:17:23 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ current * Planes + 0 ] ) ;
glActiveTexture ( GL_TEXTURE1 ) ;
glBindTexture ( GL_TEXTURE_2D , decoder - > gl_textures [ current * Planes + 1 ] ) ;
2019-10-26 18:42:19 +02:00
render_pass_quad ( 0 , xcropf , ycropf ) ;
glUseProgram ( 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2018-11-17 14:58:25 +01:00
# else
2021-03-16 09:40:08 +01:00
img = & decoder - > pl_frames [ current ] ;
pl = & decoder - > pl_frames [ current ] . planes [ 1 ] ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
memcpy ( & deband , & pl_deband_default_params , sizeof ( deband ) ) ;
memcpy ( & render_params , & pl_render_default_params , sizeof ( render_params ) ) ;
2021-01-28 12:59:58 +01:00
render_params . deband_params = & deband ;
2021-03-16 09:40:08 +01:00
2023-02-16 12:50:57 +01:00
// provide LUT Table
if ( LUTon )
render_params . lut = p - > lut ;
else
render_params . lut = NULL ;
2021-03-16 09:40:08 +01:00
frame = decoder - > frames [ current ] ;
2021-12-27 20:02:45 +01:00
// Fix Color Parameters
2021-03-16 09:40:08 +01:00
2019-10-26 18:42:19 +02:00
switch ( decoder - > ColorSpace ) {
2021-12-27 20:02:45 +01:00
case AVCOL_SPC_RGB : // BT 601 is reportet as RGB
2021-03-16 09:40:08 +01:00
case AVCOL_SPC_BT470BG :
2021-01-28 12:59:58 +01:00
memcpy ( & img - > repr , & pl_color_repr_sdtv , sizeof ( struct pl_color_repr ) ) ;
2019-10-26 18:42:19 +02:00
img - > color . primaries = PL_COLOR_PRIM_BT_601_625 ;
img - > color . transfer = PL_COLOR_TRC_BT_1886 ;
img - > color . light = PL_COLOR_LIGHT_DISPLAY ;
2019-12-10 10:45:22 +01:00
pl - > shift_x = 0.0f ;
2019-10-26 18:42:19 +02:00
break ;
case AVCOL_SPC_BT709 :
2021-12-27 20:02:45 +01:00
case AVCOL_SPC_UNSPECIFIED : // comes with UHD
2021-01-28 12:59:58 +01:00
memcpy ( & img - > repr , & pl_color_repr_hdtv , sizeof ( struct pl_color_repr ) ) ;
2019-10-26 18:42:19 +02:00
memcpy ( & img - > color , & pl_color_space_bt709 , sizeof ( struct pl_color_space ) ) ;
2019-12-10 10:45:22 +01:00
pl - > shift_x = - 0.5f ;
2019-10-26 18:42:19 +02:00
break ;
case AVCOL_SPC_BT2020_NCL :
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 ) ) ;
2021-12-27 20:02:45 +01:00
deband . grain = 0.0f ; // no grain in HDR
2019-12-10 10:45:22 +01:00
pl - > shift_x = - 0.5f ;
2023-02-16 12:50:57 +01:00
// Kein LUT bei HDR
render_params . lut = NULL ;
#if 0
2021-03-16 09:40:08 +01:00
if ( ( sd = av_frame_get_side_data ( frame , AV_FRAME_DATA_ICC_PROFILE ) ) ) {
2021-12-27 20:02:45 +01:00
img - > profile = ( struct pl_icc_profile ) {
2021-03-16 09:40:08 +01:00
. data = sd - > data ,
. len = sd - > size ,
} ;
// Needed to ensure profile uniqueness
pl_icc_profile_compute_signature ( & img - > profile ) ;
}
if ( ( sd1 = av_frame_get_side_data ( frame , AV_FRAME_DATA_CONTENT_LIGHT_LEVEL ) ) ) {
2021-12-27 20:02:45 +01:00
const AVContentLightMetadata * clm = ( AVContentLightMetadata * ) sd - > data ;
2021-03-16 09:40:08 +01:00
img - > color . sig_peak = clm - > MaxCLL / PL_COLOR_SDR_WHITE ;
img - > color . sig_avg = clm - > MaxFALL / PL_COLOR_SDR_WHITE ;
}
// This overrides the CLL values above, if both are present
if ( ( sd2 = av_frame_get_side_data ( frame , AV_FRAME_DATA_MASTERING_DISPLAY_METADATA ) ) ) {
2021-12-27 20:02:45 +01:00
const AVMasteringDisplayMetadata * mdm = ( AVMasteringDisplayMetadata * ) sd - > data ;
2021-03-16 09:40:08 +01:00
if ( mdm - > has_luminance )
img - > color . sig_peak = av_q2d ( mdm - > max_luminance ) / PL_COLOR_SDR_WHITE ;
}
// Make sure this value is more or less legal
if ( img - > color . sig_peak < 1.0 | | img - > color . sig_peak > 50.0 )
img - > color . sig_peak = 0.0 ;
2023-02-16 12:50:57 +01:00
# endif
2021-12-27 20:02:45 +01:00
# if defined VAAPI || defined USE_DRM
2019-10-26 18:42:19 +02:00
render_params . peak_detect_params = NULL ;
2021-01-28 12:59:58 +01:00
render_params . deband_params = NULL ;
render_params . dither_params = NULL ;
render_params . skip_anti_aliasing = true ;
2019-10-26 18:42:19 +02:00
# endif
2023-02-16 12:50:57 +01:00
2019-10-26 18:42:19 +02:00
break ;
2021-12-27 20:02:45 +01:00
default : // fallback
2021-01-28 12:59:58 +01:00
memcpy ( & img - > repr , & pl_color_repr_hdtv , sizeof ( struct pl_color_repr ) ) ;
2019-10-26 18:42:19 +02:00
memcpy ( & img - > color , & pl_color_space_bt709 , sizeof ( struct pl_color_space ) ) ;
2019-12-10 10:45:22 +01:00
pl - > shift_x = - 0.5f ;
2019-10-26 18:42:19 +02:00
break ;
}
2021-12-27 20:02:45 +01:00
target - > repr . sys = PL_COLOR_SYSTEM_RGB ;
2021-03-17 14:24:52 +01:00
if ( VideoStudioLevels )
target - > repr . levels = PL_COLOR_LEVELS_PC ;
else
target - > repr . levels = PL_COLOR_LEVELS_TV ;
target - > repr . alpha = PL_ALPHA_UNKNOWN ;
2021-03-16 09:40:08 +01:00
2021-03-17 14:24:52 +01:00
// target.repr.bits.sample_depth = 16;
// target.repr.bits.color_depth = 16;
// target.repr.bits.bit_shift =0;
2021-12-27 20:02:45 +01:00
2021-03-17 14:24:52 +01:00
# if USE_DRM
2021-12-27 20:02:45 +01:00
switch ( VulkanTargetColorSpace ) {
case 0 : // Monitor
memcpy ( & target - > color , & pl_color_space_monitor , sizeof ( struct pl_color_space ) ) ;
2021-03-17 14:24:52 +01:00
break ;
2021-12-27 20:02:45 +01:00
case 1 : // sRGB
memcpy ( & target - > color , & pl_color_space_srgb , sizeof ( struct pl_color_space ) ) ;
break ;
case 2 : // HD TV
set_hdr_metadata ( frame - > color_primaries , frame - > color_trc , sd1 , sd2 ) ;
if ( decoder - > ColorSpace = = AVCOL_SPC_BT470BG ) {
target - > color . primaries = PL_COLOR_PRIM_BT_601_625 ;
target - > color . transfer = PL_COLOR_TRC_BT_1886 ;
target - > color . light = PL_COLOR_LIGHT_DISPLAY ;
} else {
memcpy ( & target - > color , & pl_color_space_bt709 , sizeof ( struct pl_color_space ) ) ;
}
break ;
case 3 : // HDR TV
set_hdr_metadata ( frame - > color_primaries , frame - > color_trc , sd1 , sd2 ) ;
if ( decoder - > ColorSpace = = AVCOL_SPC_BT2020_NCL ) {
memcpy ( & target - > color , & pl_color_space_bt2020_hlg , sizeof ( struct pl_color_space ) ) ;
} else if ( decoder - > ColorSpace = = AVCOL_SPC_BT470BG ) {
target - > color . primaries = PL_COLOR_PRIM_BT_601_625 ;
target - > color . transfer = PL_COLOR_TRC_BT_1886 ;
target - > color . light = PL_COLOR_LIGHT_DISPLAY ;
;
} else {
memcpy ( & target - > color , & pl_color_space_bt709 , sizeof ( struct pl_color_space ) ) ;
}
break ;
default :
memcpy ( & target - > color , & pl_color_space_monitor , sizeof ( struct pl_color_space ) ) ;
break ;
}
# else
2021-03-17 14:24:52 +01:00
switch ( VulkanTargetColorSpace ) {
2021-12-27 20:02:45 +01:00
case 0 : // Monitor
2021-03-17 14:24:52 +01:00
memcpy ( & target - > color , & pl_color_space_monitor , sizeof ( struct pl_color_space ) ) ;
break ;
2021-12-27 20:02:45 +01:00
case 1 : // sRGB
2021-03-17 14:24:52 +01:00
memcpy ( & target - > color , & pl_color_space_srgb , sizeof ( struct pl_color_space ) ) ;
break ;
2021-12-27 20:02:45 +01:00
case 2 : // HD TV
case 3 : // UHD HDR TV
memcpy ( & target - > color , & pl_color_space_bt709 , sizeof ( struct pl_color_space ) ) ;
2021-03-17 14:24:52 +01:00
break ;
default :
memcpy ( & target - > color , & pl_color_space_monitor , sizeof ( struct pl_color_space ) ) ;
break ;
}
# endif
2021-03-16 09:40:08 +01:00
2021-12-27 20:02:45 +01:00
// printf("sys %d prim %d trc %d light
// %d\n",img->repr.sys,img->color.primaries,img->color.transfer,img->color.light);
// Source crop
if ( VideoScalerTest ) { // right side defined scaler
// Input crop
2021-01-10 13:55:09 +01:00
img - > crop . x0 = video_src_rect . x1 / 2 + 1 ;
img - > crop . y0 = video_src_rect . y0 ;
img - > crop . x1 = video_src_rect . x1 ;
img - > crop . y1 = video_src_rect . y1 ;
// Output scale
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO_GL
2021-01-28 12:59:58 +01:00
target - > crop . x0 = dst_video_rect . x1 / 2 + dst_video_rect . x0 / 2 + 1 ;
2022-01-14 15:24:56 +01:00
target - > crop . y0 = VideoWindowHeight - dst_video_rect . y0 ;
2021-01-10 13:55:09 +01:00
target - > crop . x1 = dst_video_rect . x1 ;
2022-01-14 15:24:56 +01:00
target - > crop . y1 = VideoWindowHeight - dst_video_rect . y1 ;
2021-01-10 13:55:09 +01:00
# else
target - > crop . x0 = dst_video_rect . x1 / 2 + dst_video_rect . x0 / 2 + 1 ;
target - > crop . y0 = dst_video_rect . y0 ;
target - > crop . x1 = dst_video_rect . x1 ;
2021-12-27 20:02:45 +01:00
target - > crop . y1 = dst_video_rect . y1 ;
2021-01-10 13:55:09 +01:00
# endif
2021-03-16 09:40:08 +01:00
2019-10-26 18:42:19 +02:00
} else {
2021-03-16 09:40:08 +01:00
2021-01-10 13:55:09 +01:00
img - > crop . x0 = video_src_rect . x0 ;
img - > crop . y0 = video_src_rect . y0 ;
img - > crop . x1 = video_src_rect . x1 ;
img - > crop . y1 = video_src_rect . y1 ;
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO_GL
2021-01-28 12:59:58 +01:00
target - > crop . x0 = dst_video_rect . x0 ;
2022-01-14 15:24:56 +01:00
target - > crop . y0 = VideoWindowHeight - dst_video_rect . y0 ;
2021-01-10 13:55:09 +01:00
target - > crop . x1 = dst_video_rect . x1 ;
2022-01-14 15:24:56 +01:00
target - > crop . y1 = VideoWindowHeight - dst_video_rect . y1 ;
2021-01-10 13:55:09 +01:00
# else
target - > crop . x0 = dst_video_rect . x0 ;
target - > crop . y0 = dst_video_rect . y0 ;
target - > crop . x1 = dst_video_rect . x1 ;
2021-12-27 20:02:45 +01:00
target - > crop . y1 = dst_video_rect . y1 ;
2021-01-10 13:55:09 +01:00
# endif
2019-10-26 18:42:19 +02:00
}
2021-01-10 13:55:09 +01:00
# if PL_API_VER < 100
if ( level = = 0 )
2021-12-27 20:02:45 +01:00
pl_tex_clear ( p - > gpu , target - > fbo , ( float [ 4 ] ) { 0 } ) ;
2021-01-10 13:55:09 +01:00
# else
if ( ! level & & pl_frame_is_cropped ( target ) )
2021-12-27 20:02:45 +01:00
pl_frame_clear ( p - > gpu , target , ( float [ 3 ] ) { 0 } ) ;
2021-01-10 13:55:09 +01:00
# endif
2019-10-26 18:42:19 +02:00
if ( VideoColorBlindness ) {
switch ( VideoColorBlindness ) {
case 1 :
memcpy ( & cone , & pl_vision_protanomaly , sizeof ( cone ) ) ;
break ;
case 2 :
memcpy ( & cone , & pl_vision_deuteranomaly , sizeof ( cone ) ) ;
break ;
case 3 :
memcpy ( & cone , & pl_vision_tritanomaly , sizeof ( cone ) ) ;
break ;
case 4 :
memcpy ( & cone , & pl_vision_monochromacy , sizeof ( cone ) ) ;
break ;
default :
memcpy ( & cone , & pl_vision_normal , sizeof ( cone ) ) ;
break ;
}
cone . strength = VideoColorBlindnessFaktor ;
render_params . cone_params = & cone ;
} else {
render_params . cone_params = NULL ;
}
2019-10-28 21:43:37 +01:00
// render_params.upscaler = &pl_filter_ewa_lanczos;
2019-10-26 18:42:19 +02:00
render_params . upscaler = pl_named_filters [ VideoScaling [ decoder - > Resolution ] ] . filter ;
render_params . downscaler = pl_named_filters [ VideoScaling [ decoder - > Resolution ] ] . filter ;
2021-03-16 09:40:08 +01:00
2019-10-26 18:42:19 +02:00
render_params . color_adjustment = & colors ;
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
colors . brightness = VideoBrightness ;
colors . contrast = VideoContrast ;
colors . saturation = VideoSaturation ;
colors . hue = VideoHue ;
colors . gamma = VideoGamma ;
2021-04-20 08:27:19 +02:00
# if PL_API_VER >= 119
2021-12-27 20:02:45 +01:00
colors . temperature = VideoTemperature ;
2021-04-20 08:27:19 +02:00
# endif
2019-10-26 18:42:19 +02:00
if ( ovl ) {
target - > overlays = ovl ;
target - > num_overlays = 1 ;
} else {
target - > overlays = 0 ;
target - > num_overlays = 0 ;
}
2021-12-27 20:02:45 +01:00
2020-06-07 12:31:18 +02:00
# if PL_API_VER >= 58
2021-12-27 20:02:45 +01:00
if ( decoder - > newchannel = = 1 & & ! level ) { // got new textures
2020-06-07 12:31:18 +02:00
p - > num_shaders = 0 ;
2021-12-27 20:02:45 +01:00
for ( int i = NUM_SHADERS - 1 ; i > = 0 ; i - - ) { // Remove shaders in invers order
2020-06-07 12:31:18 +02:00
if ( p - > hook [ i ] ) {
pl_mpv_user_shader_destroy ( & p - > hook [ i ] ) ;
p - > hook [ i ] = NULL ;
2021-12-27 20:02:45 +01:00
Debug ( 3 , " remove shader %d \n " , i ) ;
2020-06-07 12:31:18 +02:00
}
}
2021-12-27 20:02:45 +01:00
for ( int i = 0 ; i < num_shaders ; i + + ) {
2020-06-07 12:31:18 +02:00
if ( p - > hook [ i ] = = NULL & & shadersp [ i ] ) {
p - > hook [ i ] = parse_user_shader ( shadersp [ i ] ) ;
if ( ! p - > hook [ i ] )
2021-12-27 20:02:45 +01:00
shadersp [ i ] = 0 ;
2020-06-07 12:31:18 +02:00
else
p - > num_shaders + + ;
}
}
2021-01-10 13:55:09 +01:00
}
2021-12-27 20:02:45 +01:00
render_params . hooks = & p - > hook ;
if ( level | | ovl | | ( video_src_rect . x1 > dst_video_rect . x1 ) | | ( video_src_rect . y1 > dst_video_rect . y1 ) ) {
render_params . num_hooks = 0 ; // no user shaders when OSD activ or downward scaling or PIP
} else {
render_params . num_hooks = p - > num_shaders ;
2021-01-10 13:55:09 +01:00
}
2020-06-07 12:31:18 +02:00
# endif
2023-02-16 12:50:57 +01:00
2021-12-27 20:02:45 +01:00
2021-03-16 09:40:08 +01:00
if ( decoder - > newchannel & & current = = 0 ) {
2019-10-26 18:42:19 +02:00
colors . brightness = - 1.0f ;
colors . contrast = 0.0f ;
2021-03-16 09:40:08 +01:00
if ( ! pl_render_image ( p - > renderer , & decoder - > pl_frames [ current ] , target , & render_params ) ) {
2020-06-07 12:31:18 +02:00
Debug ( 3 , " Failed rendering first frame! \n " ) ;
2020-04-10 16:17:23 +02:00
}
2020-06-07 12:31:18 +02:00
decoder - > newchannel = 2 ;
2019-10-26 18:42:19 +02:00
return ;
}
decoder - > newchannel = 0 ;
2021-12-27 20:02:45 +01:00
// uint64_t tt = GetusTicks();
2021-03-16 09:40:08 +01:00
if ( ! pl_render_image ( p - > renderer , & decoder - > pl_frames [ current ] , target , & render_params ) ) {
2021-01-10 13:55:09 +01:00
Debug ( 4 , " Failed rendering frame! \n " ) ;
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
// pl_gpu_finish(p->gpu);
// printf("Rendertime %ld -- \n,",GetusTicks() - tt);
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
if ( VideoScalerTest ) { // left side test scaler
2021-03-16 09:40:08 +01:00
2021-01-10 13:55:09 +01:00
// Source crop
img - > crop . x0 = video_src_rect . x0 ;
img - > crop . y0 = video_src_rect . y0 ;
img - > crop . x1 = video_src_rect . x1 / 2 ;
img - > crop . y1 = video_src_rect . y1 ;
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO_GL
2021-01-28 12:59:58 +01:00
target - > crop . x0 = dst_video_rect . x0 ;
2021-01-10 13:55:09 +01:00
target - > crop . y1 = dst_video_rect . y0 ;
target - > crop . x1 = dst_video_rect . x1 / 2 + dst_video_rect . x0 / 2 ;
2021-12-27 20:02:45 +01:00
target - > crop . y0 = dst_video_rect . y1 ;
2021-01-10 13:55:09 +01:00
# else
// Video aspect ratio
target - > crop . x0 = dst_video_rect . x0 ;
target - > crop . y0 = dst_video_rect . y0 ;
target - > crop . x1 = dst_video_rect . x1 / 2 + dst_video_rect . x0 / 2 ;
target - > crop . y1 = dst_video_rect . y1 ;
# endif
2019-10-26 18:42:19 +02:00
render_params . upscaler = pl_named_filters [ VideoScalerTest - 1 ] . filter ;
render_params . downscaler = pl_named_filters [ VideoScalerTest - 1 ] . filter ;
2021-12-27 20:02:45 +01:00
// render_params.lut = NULL;
2021-03-16 09:40:08 +01:00
render_params . num_hooks = 0 ;
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
if ( ! p - > renderertest )
p - > renderertest = pl_renderer_create ( p - > ctx , p - > gpu ) ;
2021-03-16 09:40:08 +01:00
if ( ! pl_render_image ( p - > renderertest , & decoder - > pl_frames [ current ] , target , & render_params ) ) {
2021-01-10 13:55:09 +01:00
Debug ( 4 , " Failed rendering frame! \n " ) ;
2019-10-26 18:42:19 +02:00
}
} else if ( p - > renderertest ) {
pl_renderer_destroy ( & p - > renderertest ) ;
p - > renderertest = NULL ;
}
# endif
2020-01-08 17:04:18 +01:00
Debug ( 4 , " video/cuvid: yy video surface %p displayed \n " , current , decoder - > SurfaceRead ) ;
2019-10-26 18:42:19 +02:00
}
# ifdef PLACEBO
2021-12-27 20:02:45 +01:00
void make_osd_overlay ( int x , int y , int width , int height ) {
2019-10-26 18:42:19 +02:00
const struct pl_fmt * fmt ;
struct pl_overlay * pl ;
int offset = VideoWindowHeight - ( VideoWindowHeight - height - y ) - ( VideoWindowHeight - y ) ;
2021-12-27 20:02:45 +01:00
fmt = pl_find_named_fmt ( p - > gpu , " rgba8 " ) ; // 8 Bit RGB
2019-10-26 18:42:19 +02:00
pl = & osdoverlay ;
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2019-11-01 08:22:26 +01:00
if ( pl - > plane . texture & & ( pl - > plane . texture - > params . w ! = width | | pl - > plane . texture - > params . h ! = height ) ) {
2019-10-26 18:42:19 +02:00
pl_tex_destroy ( p - > gpu , & pl - > plane . texture ) ;
2023-02-15 15:58:51 +01:00
# else
if ( pl - > tex & & ( pl - > tex - > params . w ! = width | | pl - > tex - > params . h ! = height ) ) {
pl_tex_destroy ( p - > gpu , & pl - > tex ) ;
# endif
2019-10-26 18:42:19 +02:00
}
2019-11-18 13:01:19 +01:00
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2019-10-26 18:42:19 +02:00
// make texture for OSD
2019-11-18 13:01:19 +01:00
if ( pl - > plane . texture = = NULL ) {
2021-12-27 20:02:45 +01:00
pl - > plane . texture = pl_tex_create (
p - > gpu , & ( struct pl_tex_params ) {
. w = width , . h = height , . d = 0 , . format = fmt , . sampleable = true , . host_writable = true ,
2019-11-18 13:01:19 +01:00
. blit_dst = true ,
2021-11-16 15:05:49 +01:00
# if PL_API_VER < 159
2021-12-27 20:02:45 +01:00
. sample_mode = PL_TEX_SAMPLE_LINEAR , . address_mode = PL_TEX_ADDRESS_CLAMP ,
2021-11-16 15:05:49 +01:00
# endif
2019-11-18 13:01:19 +01:00
} ) ;
}
2019-10-26 18:42:19 +02:00
// make overlay
2021-12-27 20:02:45 +01:00
pl_tex_clear ( p - > gpu , pl - > plane . texture , ( float [ 4 ] ) { 0 } ) ;
2019-10-26 18:42:19 +02:00
pl - > plane . components = 4 ;
pl - > plane . shift_x = 0.0f ;
pl - > plane . shift_y = 0.0f ;
2019-11-05 22:06:54 +01:00
pl - > plane . component_mapping [ 0 ] = PL_CHANNEL_R ;
2019-10-26 18:42:19 +02:00
pl - > plane . component_mapping [ 1 ] = PL_CHANNEL_G ;
2019-11-05 22:06:54 +01:00
pl - > plane . component_mapping [ 2 ] = PL_CHANNEL_B ;
2019-10-26 18:42:19 +02:00
pl - > plane . component_mapping [ 3 ] = PL_CHANNEL_A ;
2023-02-15 15:58:51 +01:00
# else
// make texture for OSD
if ( pl - > tex = = NULL ) {
pl - > tex = pl_tex_create (
p - > gpu , & ( struct pl_tex_params ) {
. w = width , . h = height , . d = 0 , . format = fmt , . sampleable = true , . host_writable = true ,
. blit_dst = true ,
} ) ;
}
// make overlay
pl_tex_clear ( p - > gpu , pl - > tex , ( float [ 4 ] ) { 0 } ) ;
part . src . x0 = 0.0f ;
part . src . y0 = 0.0f ;
part . src . x1 = width ;
part . src . y1 = height ;
# endif
2019-10-26 18:42:19 +02:00
pl - > mode = PL_OVERLAY_NORMAL ;
pl - > repr . sys = PL_COLOR_SYSTEM_RGB ;
pl - > repr . levels = PL_COLOR_LEVELS_PC ;
pl - > repr . alpha = PL_ALPHA_INDEPENDENT ;
memcpy ( & osdoverlay . color , & pl_color_space_srgb , sizeof ( struct pl_color_space ) ) ;
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO_GL
2021-01-10 13:55:09 +01:00
pl - > rect . x0 = x ;
2021-12-27 20:02:45 +01:00
pl - > rect . y1 = VideoWindowHeight - y ; // Boden von oben
2021-01-10 13:55:09 +01:00
pl - > rect . x1 = x + width ;
2021-12-27 20:02:45 +01:00
pl - > rect . y0 = VideoWindowHeight - height - y ;
2021-01-10 13:55:09 +01:00
# else
2019-10-26 18:42:19 +02:00
pl - > rect . x0 = x ;
2021-12-27 20:02:45 +01:00
pl - > rect . y0 = VideoWindowHeight - y + offset ; // Boden von oben
2019-10-26 18:42:19 +02:00
pl - > rect . x1 = x + width ;
pl - > rect . y1 = VideoWindowHeight - height - y + offset ;
2021-01-10 13:55:09 +01:00
# endif
2023-02-15 15:58:51 +01:00
# else
osdoverlay . parts = & part ;
osdoverlay . num_parts = 1 ;
# ifdef PLACEBO_GL
part . dst . x0 = x ;
part . dst . y1 = VideoWindowHeight - y ; // Boden von oben
part . dst . x1 = x + width ;
part . dst . y0 = VideoWindowHeight - height - y ;
# else
part . dst . x0 = x ;
part . dst . y0 = VideoWindowHeight - y + offset ; // Boden von oben
part . dst . x1 = x + width ;
part . dst . y1 = VideoWindowHeight - height - y + offset ;
# endif
# endif
2019-10-26 18:42:19 +02:00
}
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
///
/// Display a video frame.
///
2020-05-01 12:06:04 +02:00
2021-12-27 20:02:45 +01:00
static void CuvidDisplayFrame ( void ) {
2019-10-26 18:42:19 +02:00
static uint64_t first_time = 0 , round_time = 0 ;
static uint64_t last_time = 0 ;
int i ;
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
int filled ;
CuvidDecoder * decoder ;
int RTS_flag ;
int valid_frame = 0 ;
float ldiff ;
2019-12-10 10:45:22 +01:00
float turnaround ;
2020-04-10 16:17:23 +02:00
2018-11-04 13:44:18 +01:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
uint64_t diff ;
static float fdiff = 23000.0 ;
struct pl_swapchain_frame frame ;
2021-03-16 09:40:08 +01:00
struct pl_frame target ;
2019-10-26 18:42:19 +02:00
bool ok ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
const struct pl_fmt * fmt ;
2021-12-27 20:02:45 +01:00
const float black [ 4 ] = { 0.0f , 0.0f , 0.0f , 1.0f } ;
2019-10-26 18:42:19 +02:00
# endif
# ifndef PLACEBO
2019-12-10 10:45:22 +01:00
2019-10-26 18:42:19 +02:00
if ( CuvidDecoderN )
CuvidDecoders [ 0 ] - > Frameproc = ( float ) ( GetusTicks ( ) - last_time ) / 1000000.0 ;
# ifdef CUVID
glXMakeCurrent ( XlibDisplay , VideoWindow , glxThreadContext ) ;
2021-12-27 20:02:45 +01:00
glXWaitVideoSyncSGI ( 2 , ( Count + 1 ) % 2 ,
& Count ) ; // wait for previous frame to swap
2019-10-26 18:42:19 +02:00
last_time = GetusTicks ( ) ;
# else
eglMakeCurrent ( eglDisplay , eglSurface , eglSurface , eglThreadContext ) ;
EglCheck ( ) ;
2022-05-24 00:09:55 +02:00
# ifndef USE_DRM
2022-01-15 15:13:42 +01:00
usleep ( 5000 ) ;
2022-01-18 17:48:17 +01:00
# endif
2022-01-15 15:36:01 +01:00
# endif
2022-05-24 00:09:55 +02:00
2019-10-26 18:42:19 +02:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2020-04-10 16:17:23 +02:00
# else // PLACEBO
2019-10-26 18:42:19 +02:00
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
# ifdef CUVID
glXMakeCurrent ( XlibDisplay , VideoWindow , glxThreadContext ) ;
2021-12-27 20:02:45 +01:00
glXWaitVideoSyncSGI ( 2 , ( Count + 1 ) % 2 ,
& Count ) ; // wait for previous frame to swap
2020-05-01 12:06:04 +02:00
last_time = GetusTicks ( ) ;
# else
eglMakeCurrent ( eglDisplay , eglSurface , eglSurface , eglThreadContext ) ;
EglCheck ( ) ;
# endif
glClear ( GL_COLOR_BUFFER_BIT ) ;
# endif
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
if ( CuvidDecoderN ) {
ldiff = ( float ) ( GetusTicks ( ) - round_time ) / 1000000.0 ;
if ( ldiff < 100.0 & & ldiff > 0.0 )
CuvidDecoders [ 0 ] - > Frameproc = ( CuvidDecoders [ 0 ] - > Frameproc + ldiff + ldiff ) / 3.0 ;
}
2019-11-02 13:28:42 +01:00
2019-10-26 18:42:19 +02:00
round_time = GetusTicks ( ) ;
if ( ! p - > swapchain )
return ;
# ifdef CUVID
VideoThreadLock ( ) ;
# endif
2019-11-18 13:01:19 +01:00
2019-10-26 18:42:19 +02:00
last_time = GetusTicks ( ) ;
2021-12-27 20:02:45 +01:00
while ( ! pl_swapchain_start_frame ( p - > swapchain , & frame ) ) { // get new frame wait for previous to swap
2019-10-26 18:42:19 +02:00
usleep ( 5 ) ;
}
if ( ! frame . fbo ) {
# ifdef CUVID
VideoThreadUnlock ( ) ;
# endif
return ;
}
# ifdef VAAPI
VideoThreadLock ( ) ;
# endif
2021-12-27 20:02:45 +01:00
pl_frame_from_swapchain ( & target , & frame ) ; // make target frame
2019-10-26 18:42:19 +02:00
if ( VideoSurfaceModesChanged ) {
pl_renderer_destroy ( & p - > renderer ) ;
p - > renderer = pl_renderer_create ( p - > ctx , p - > gpu ) ;
if ( p - > renderertest ) {
pl_renderer_destroy ( & p - > renderertest ) ;
p - > renderertest = NULL ;
}
VideoSurfaceModesChanged = 0 ;
}
2020-02-18 22:02:53 +01:00
# ifdef GAMMA
2020-03-13 08:19:58 +01:00
// target.color.transfer = PL_COLOR_TRC_LINEAR;
2020-02-18 22:02:53 +01:00
# endif
2019-10-26 18:42:19 +02:00
# endif
//
2021-12-27 20:02:45 +01:00
// Render videos into output
2019-10-26 18:42:19 +02:00
//
///
2019-01-04 10:08:47 +01:00
2019-10-26 18:42:19 +02:00
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
2018-11-05 10:38:27 +01:00
2019-10-26 18:42:19 +02:00
decoder = CuvidDecoders [ i ] ;
decoder - > FramesDisplayed + + ;
decoder - > StartCounter + + ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
filled = atomic_read ( & decoder - > SurfacesFilled ) ;
2021-12-27 20:02:45 +01:00
// printf("Filled %d\n",filled);
// need 1 frame for progressive, 3 frames for interlaced
2019-10-26 18:42:19 +02:00
if ( filled < 1 + 2 * decoder - > Interlaced ) {
// FIXME: rewrite MixVideo to support less surfaces
2021-12-27 20:02:45 +01:00
if ( ( VideoShowBlackPicture & & ! decoder - > TrickSpeed ) | |
( VideoShowBlackPicture & & decoder - > Closing < - 300 ) ) {
2019-10-26 18:42:19 +02:00
CuvidBlackSurface ( decoder ) ;
CuvidMessage ( 4 , " video/cuvid: black surface displayed \n " ) ;
}
continue ;
}
valid_frame = 1 ;
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2023-07-14 09:13:09 +02:00
//pthread_mutex_lock(&OSDMutex);
2021-12-27 20:02:45 +01:00
if ( OsdShown = = 1 ) { // New OSD opened
2023-07-14 09:13:09 +02:00
2019-10-26 18:42:19 +02:00
make_osd_overlay ( OSDx , OSDy , OSDxsize , OSDysize ) ;
if ( posd ) {
2021-12-27 20:02:45 +01:00
pl_tex_upload ( p - > gpu , & ( struct pl_tex_transfer_params ) {
// upload OSD
2023-02-18 08:45:32 +01:00
# if PL_API_VER >= 229
2023-02-15 15:58:51 +01:00
. tex = osdoverlay . tex ,
# else
2021-12-27 20:02:45 +01:00
. tex = osdoverlay . plane . texture ,
2023-02-15 15:58:51 +01:00
# endif
2021-12-27 20:02:45 +01:00
. ptr = posd ,
} ) ;
2019-10-26 18:42:19 +02:00
}
OsdShown = 2 ;
2023-07-14 09:13:09 +02:00
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
if ( OsdShown = = 2 ) {
CuvidMixVideo ( decoder , i , & target , & osdoverlay ) ;
} else {
CuvidMixVideo ( decoder , i , & target , NULL ) ;
}
2023-07-14 09:13:09 +02:00
//pthread_mutex_unlock(&OSDMutex);
2019-10-04 10:37:57 +02:00
# else
2019-10-26 18:42:19 +02:00
CuvidMixVideo ( decoder , i ) ;
2019-10-04 10:37:57 +02:00
# endif
2021-12-27 20:02:45 +01:00
if ( i = = 0 & & decoder - > grab ) { // Grab frame
2019-10-26 18:42:19 +02:00
# ifdef PLACEBO
if ( decoder - > grab = = 2 & & OsdShown = = 2 ) {
get_RGB ( decoder , & osdoverlay ) ;
} else {
get_RGB ( decoder , NULL ) ;
}
2019-04-05 07:20:52 +02:00
# else
2019-10-26 18:42:19 +02:00
get_RGB ( decoder ) ;
# endif
decoder - > grab = 0 ;
}
}
2019-10-20 14:48:28 +02:00
2019-10-26 18:42:19 +02:00
# ifndef PLACEBO
2021-12-27 20:02:45 +01:00
// add osd to surface
2019-11-05 22:06:54 +01:00
2019-10-26 18:42:19 +02:00
if ( OsdShown & & valid_frame ) {
GLint texLoc ;
2019-11-18 13:01:19 +01:00
int x , y , w , h ;
2019-11-05 22:06:54 +01:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2019-12-10 10:45:22 +01:00
GlxCheck ( ) ;
2019-11-11 17:45:59 +01:00
if ( OsdShown = = 1 ) {
if ( OSDtexture )
2019-11-18 13:01:19 +01:00
glDeleteTextures ( 1 , & OSDtexture ) ;
pthread_mutex_lock ( & OSDMutex ) ;
2019-11-11 17:45:59 +01:00
glGenTextures ( 1 , & OSDtexture ) ;
glBindTexture ( GL_TEXTURE_2D , OSDtexture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , OSDxsize , OSDysize , 0 , GL_RGBA , GL_UNSIGNED_BYTE , posd ) ;
2019-12-10 10:45:22 +01:00
GlxCheck ( ) ;
2019-11-11 17:45:59 +01:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2019-12-10 10:45:22 +01:00
GlxCheck ( ) ;
2019-11-11 17:45:59 +01:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
glFlush ( ) ;
pthread_mutex_unlock ( & OSDMutex ) ;
2019-11-18 13:01:19 +01:00
OsdShown = 2 ;
2019-11-11 17:45:59 +01:00
}
2019-12-10 10:45:22 +01:00
GlxCheck ( ) ;
2019-11-05 22:06:54 +01:00
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2019-12-10 10:45:22 +01:00
GlxCheck ( ) ;
2019-10-26 18:42:19 +02:00
glEnable ( GL_BLEND ) ;
GlxCheck ( ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
GlxCheck ( ) ;
2019-11-05 22:06:54 +01:00
2019-11-18 13:01:19 +01:00
y = OSDy * VideoWindowHeight / OsdHeight ;
x = OSDx * VideoWindowWidth / OsdWidth ;
h = OSDysize * VideoWindowHeight / OsdHeight ;
w = OSDxsize * VideoWindowWidth / OsdWidth ;
glViewport ( x , ( VideoWindowHeight - h - y ) , w , h ) ;
2019-10-26 18:42:19 +02:00
if ( gl_prog_osd = = 0 )
gl_prog_osd = sc_generate_osd ( gl_prog_osd ) ; // generate shader programm
glUseProgram ( gl_prog_osd ) ;
texLoc = glGetUniformLocation ( gl_prog_osd , " texture0 " ) ;
glUniform1i ( texLoc , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_lock(&OSDMutex);
2019-10-26 18:42:19 +02:00
glBindTexture ( GL_TEXTURE_2D , OSDtexture ) ;
2019-11-05 22:06:54 +01:00
render_pass_quad ( 1 , 0 , 0 ) ;
2021-12-27 20:02:45 +01:00
// pthread_mutex_unlock(&OSDMutex);
2019-10-26 18:42:19 +02:00
glUseProgram ( 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2021-12-27 20:02:45 +01:00
// eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglThreadContext);
2019-10-26 18:42:19 +02:00
}
2019-10-20 14:48:28 +02:00
# endif
2019-10-26 18:42:19 +02:00
2021-01-10 13:55:09 +01:00
# if defined PLACEBO // && !defined PLACEBO_GL
2019-10-28 21:43:37 +01:00
// first_time = GetusTicks();
2019-10-26 18:42:19 +02:00
if ( ! pl_swapchain_submit_frame ( p - > swapchain ) )
2023-04-23 11:07:09 +02:00
Fatal ( _ ( " Failed to submit swapchain buffer \n " ) ) ;
VideoThreadUnlock ( ) ;
2021-12-27 20:02:45 +01:00
pl_swapchain_swap_buffers ( p - > swapchain ) ; // swap buffers
2023-07-14 09:13:09 +02:00
# ifdef PLACEBO_GL
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
EglCheck ( ) ;
# endif
2023-04-23 11:07:09 +02:00
2020-04-10 16:17:23 +02:00
# else // not PLACEBO
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
glXGetVideoSyncSGI ( & Count ) ; // get current frame
2019-10-26 18:42:19 +02:00
glXSwapBuffers ( XlibDisplay , VideoWindow ) ;
glXMakeCurrent ( XlibDisplay , None , NULL ) ;
2019-10-04 10:37:57 +02:00
# else
2020-04-10 16:17:23 +02:00
# ifndef USE_DRM
eglSwapBuffers ( eglDisplay , eglSurface ) ;
2019-10-26 18:42:19 +02:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2019-12-10 10:45:22 +01:00
# else
drm_swap_buffers ( ) ;
# endif
2019-10-04 10:37:57 +02:00
# endif
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
// FIXME: CLOCK_MONOTONIC_RAW
clock_gettime ( CLOCK_MONOTONIC , & CuvidFrameTime ) ;
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
// remember time of last shown surface
CuvidDecoders [ i ] - > FrameTime = CuvidFrameTime ;
}
2018-08-19 11:45:46 +02:00
}
2021-12-27 20:02:45 +01:00
# ifdef PLACEBO_GL
CuvidSwapBuffer ( ) {
2020-05-01 12:06:04 +02:00
# ifndef USE_DRM
eglSwapBuffers ( eglDisplay , eglSurface ) ;
2021-12-27 20:02:45 +01:00
// eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
// EGL_NO_CONTEXT);
2020-05-01 12:06:04 +02:00
# else
drm_swap_buffers ( ) ;
2021-12-27 20:02:45 +01:00
# endif
2020-05-01 12:06:04 +02:00
}
# endif
2021-12-27 20:02:45 +01:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set CUVID decoder video clock.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hardware decoder
2021-12-27 20:02:45 +01:00
/// @param pts audio presentation timestamp
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void CuvidSetClock ( CuvidDecoder * decoder , int64_t pts ) { decoder - > PTS = pts ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Get CUVID decoder video clock.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// FIXME: 20 wrong for 60hz dvb streams
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int64_t CuvidGetClock ( const CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
// pts is the timestamp of the latest decoded frame
2021-12-27 20:02:45 +01:00
if ( decoder - > PTS = = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
return AV_NOPTS_VALUE ;
}
// subtract buffered decoded frames
if ( decoder - > Interlaced ) {
/*
Info ( " video: %s =pts field%d #%d \n " ,
Timestamp2String ( decoder - > PTS ) ,
decoder - > SurfaceField ,
atomic_read ( & decoder - > SurfacesFilled ) ) ;
*/
// 1 field is future, 2 fields are past, + 2 in driver queue
return decoder - > PTS - 20 * 90 * ( 2 * atomic_read ( & decoder - > SurfacesFilled ) - decoder - > SurfaceField - 2 + 2 ) ;
}
// + 2 in driver queue
2020-03-31 13:57:43 +02:00
return decoder - > PTS - 20 * 90 * ( atomic_read ( & decoder - > SurfacesFilled ) + SWAP_BUFFER_SIZE + 1 ) ; // +2
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Set CUVID decoder closing stream flag.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetClosing ( CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
decoder - > Closing = 1 ;
OsdShown = 0 ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Reset start of frame counter.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidResetStart ( CuvidDecoder * decoder ) { decoder - > StartCounter = 0 ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set trick play speed.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID decoder
/// @param speed trick speed (0 = normal)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetTrickSpeed ( CuvidDecoder * decoder , int speed ) {
2019-10-26 18:42:19 +02:00
decoder - > TrickSpeed = speed ;
decoder - > TrickCounter = speed ;
if ( speed ) {
decoder - > Closing = 0 ;
}
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Get CUVID decoder statistics.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID decoder
2021-12-27 20:02:45 +01:00
/// @param[out] missed missed frames
/// @param[out] duped duped frames
2019-10-26 18:42:19 +02:00
/// @param[out] dropped dropped frames
2021-12-27 20:02:45 +01:00
/// @param[out] count number of decoded frames
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void CuvidGetStats ( CuvidDecoder * decoder , int * missed , int * duped , int * dropped , int * counter , float * frametime ,
int * width , int * height , int * color , int * eotf ) {
2019-10-26 18:42:19 +02:00
* missed = decoder - > FramesMissed ;
* duped = decoder - > FramesDuped ;
* dropped = decoder - > FramesDropped ;
* counter = decoder - > FrameCounter ;
* frametime = decoder - > Frameproc ;
2020-02-02 13:26:51 +01:00
* width = decoder - > InputWidth ;
* height = decoder - > InputHeight ;
* color = decoder - > ColorSpace ;
* eotf = 0 ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Sync decoder output to audio.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// trick-speed show frame <n> times
/// still-picture show frame until new frame arrives
2021-12-27 20:02:45 +01:00
/// 60hz-mode repeat every 5th picture
2019-10-26 18:42:19 +02:00
/// video>audio slow down video by duplicating frames
/// video<audio speed up video by skipping frames
2021-12-27 20:02:45 +01:00
/// soft-start show every second frame
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2018-08-19 11:45:46 +02:00
///
2019-10-11 11:47:11 +02:00
void AudioDelayms ( int ) ;
2021-12-27 20:02:45 +01:00
static void CuvidSyncDecoder ( CuvidDecoder * decoder ) {
2019-10-26 18:42:19 +02:00
int filled ;
int64_t audio_clock ;
int64_t video_clock ;
int err = 0 ;
2020-04-10 16:17:23 +02:00
static int speedup = 3 ;
2019-10-26 18:42:19 +02:00
2020-02-18 22:02:53 +01:00
# ifdef GAMMA
Get_Gamma ( ) ;
# endif
2020-04-10 16:17:23 +02:00
2020-03-31 13:57:43 +02:00
video_clock = CuvidGetClock ( decoder ) ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
filled = atomic_read ( & decoder - > SurfacesFilled ) ;
if ( ! decoder - > SyncOnAudio ) {
audio_clock = AV_NOPTS_VALUE ;
// FIXME: 60Hz Mode
goto skip_sync ;
}
audio_clock = AudioGetClock ( ) ;
2021-12-27 20:02:45 +01:00
// printf("Diff %d %#012" PRIx64 " %#012" PRIx64" filled %d
// \n",(video_clock - audio_clock -
// VideoAudioDelay)/90,video_clock,audio_clock,filled);
2019-10-26 18:42:19 +02:00
// 60Hz: repeat every 5th field
if ( Video60HzMode & & ! ( decoder - > FramesDisplayed % 6 ) ) {
2021-12-27 20:02:45 +01:00
if ( audio_clock = = ( int64_t ) AV_NOPTS_VALUE | | video_clock = = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
goto out ;
}
// both clocks are known
if ( audio_clock + VideoAudioDelay < = video_clock + 25 * 90 ) {
goto out ;
}
// out of sync: audio before video
if ( ! decoder - > TrickSpeed ) {
goto skip_sync ;
}
}
// TrickSpeed
if ( decoder - > TrickSpeed ) {
if ( decoder - > TrickCounter - - ) {
goto out ;
}
decoder - > TrickCounter = decoder - > TrickSpeed ;
goto skip_sync ;
}
2020-04-01 12:45:33 +02:00
#if 0
2019-10-26 18:42:19 +02:00
// at start of new video stream, soft or hard sync video to audio
if ( ! VideoSoftStartSync & & decoder - > StartCounter < VideoSoftStartFrames & & video_clock ! = ( int64_t ) AV_NOPTS_VALUE
2021-12-27 20:02:45 +01:00
& & ( audio_clock = = ( int64_t ) AV_NOPTS_VALUE | | video_clock > audio_clock + VideoAudioDelay + 120 * 90 ) ) {
Debug ( 4 , " video: initial slow down video, frame %d \n " , decoder - > StartCounter ) ;
goto skip_sync ;
2019-10-26 18:42:19 +02:00
}
2020-04-01 12:45:33 +02:00
# endif
2019-10-26 18:42:19 +02:00
if ( decoder - > SyncCounter & & decoder - > SyncCounter - - ) {
goto skip_sync ;
}
2021-12-27 20:02:45 +01:00
if ( audio_clock ! = ( int64_t ) AV_NOPTS_VALUE & & video_clock ! = ( int64_t ) AV_NOPTS_VALUE ) {
2019-10-26 18:42:19 +02:00
// both clocks are known
int diff ;
diff = video_clock - audio_clock - VideoAudioDelay ;
2021-12-27 20:02:45 +01:00
// diff = (decoder->LastAVDiff + diff) / 2;
2019-10-26 18:42:19 +02:00
decoder - > LastAVDiff = diff ;
2019-10-04 10:37:57 +02:00
#if 0
2021-12-27 20:02:45 +01:00
if ( abs ( diff / 90 ) > 0 ) {
printf ( " Diff %d filled %d \n " , diff / 90 , filled ) ;
}
2019-10-26 18:42:19 +02:00
# endif
2021-12-27 20:02:45 +01:00
if ( abs ( diff ) > 5000 * 90 ) { // more than 5s
2020-04-10 16:17:23 +02:00
err = CuvidMessage ( 2 , " video: audio/video difference too big %d \n " , diff / 90 ) ;
2019-10-28 21:43:37 +01:00
// decoder->SyncCounter = 1;
// usleep(10);
2020-03-31 13:57:43 +02:00
goto skip_sync ;
2019-10-26 18:42:19 +02:00
} else if ( diff > 100 * 90 ) {
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
err = CuvidMessage ( 4 , " video: slow down video, duping frame %d \n " , diff / 90 ) ;
+ + decoder - > FramesDuped ;
2020-04-01 12:45:33 +02:00
if ( ( speedup & & - - speedup ) | | VideoSoftStartSync )
2020-03-31 13:57:43 +02:00
decoder - > SyncCounter = 1 ;
2020-04-10 16:17:23 +02:00
else
decoder - > SyncCounter = 0 ;
2019-10-26 18:42:19 +02:00
goto out ;
2020-03-31 13:57:43 +02:00
} else if ( diff > 25 * 90 ) {
2019-10-26 18:42:19 +02:00
err = CuvidMessage ( 3 , " video: slow down video, duping frame %d \n " , diff / 90 ) ;
+ + decoder - > FramesDuped ;
decoder - > SyncCounter = 1 ;
goto out ;
2020-03-31 13:57:43 +02:00
} else if ( ( diff < - 100 * 90 ) ) {
2019-10-26 18:42:19 +02:00
if ( filled > 2 ) {
err = CuvidMessage ( 3 , " video: speed up video, droping frame %d \n " , diff / 90 ) ;
+ + decoder - > FramesDropped ;
CuvidAdvanceDecoderFrame ( decoder ) ;
2021-12-27 20:02:45 +01:00
} else if ( ( diff < - 100 * 90 ) ) { // give it some time to get frames to drop
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Delay Audio %d ms \n " , abs ( diff / 90 ) ) ;
AudioDelayms ( abs ( diff / 90 ) ) ;
}
decoder - > SyncCounter = 1 ;
2020-04-10 16:17:23 +02:00
} else {
2020-04-01 12:45:33 +02:00
speedup = 2 ;
2020-03-31 13:57:43 +02:00
}
2018-08-19 11:45:46 +02:00
# if defined(DEBUG) || defined(AV_INFO)
2019-10-26 18:42:19 +02:00
if ( ! decoder - > SyncCounter & & decoder - > StartCounter < 1000 ) {
2018-08-19 11:45:46 +02:00
# ifdef DEBUG
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/cuvid: synced after %d frames %dms \n " , decoder - > StartCounter , GetMsTicks ( ) - VideoSwitch ) ;
2018-08-19 11:45:46 +02:00
# else
2019-10-26 18:42:19 +02:00
Info ( " video/cuvid: synced after %d frames \n " , decoder - > StartCounter ) ;
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
decoder - > StartCounter + = 1000 ;
}
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
}
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
skip_sync :
2019-10-26 18:42:19 +02:00
// check if next field is available
if ( decoder - > SurfaceField & & filled < = 1 + 2 * decoder - > Interlaced ) {
if ( filled < 1 + 2 * decoder - > Interlaced ) {
+ + decoder - > FramesDuped ;
2018-08-19 11:45:46 +02:00
#if 0
2021-12-27 20:02:45 +01:00
// FIXME: don't warn after stream start, don't warn during pause
err =
CuvidMessage ( 1 , _ ( " video: decoder buffer empty, duping frame (%d/%d) %d v-buf \n " ) ,
decoder - > FramesDuped , decoder - > FrameCounter , VideoGetBuffers ( decoder - > Stream ) ) ;
// some time no new picture or black video configured
if ( decoder - > Closing < - 300 | | ( VideoShowBlackPicture & & decoder - > Closing ) ) {
// clear ring buffer to trigger black picture
atomic_set ( & decoder - > SurfacesFilled , 0 ) ;
}
2019-10-26 18:42:19 +02:00
# endif
}
2021-12-27 20:02:45 +01:00
// Debug(3,"filled zu klein %d Field %d Interlaced
// %d\n",filled,decoder->SurfaceField,decoder->Interlaced); goto out;
2019-10-26 18:42:19 +02:00
}
CuvidAdvanceDecoderFrame ( decoder ) ;
2021-12-27 20:02:45 +01:00
out :
2018-08-19 11:45:46 +02:00
#if 0
2019-10-26 18:42:19 +02:00
// defined(DEBUG) || defined(AV_INFO)
// debug audio/video sync
if ( err | | ! ( decoder - > FramesDisplayed % AV_INFO_TIME ) ) {
2021-12-27 20:02:45 +01:00
if ( ! err ) {
CuvidMessage ( 0 , NULL ) ;
}
Info ( " video: %s%+5 " PRId64 " %4 " PRId64 " %3d/ \\ ms %3d%+d%+d v-buf \n " , Timestamp2String ( video_clock ) ,
abs ( ( video_clock - audio_clock ) / 90 ) < 8888 ? ( ( video_clock - audio_clock ) / 90 ) : 8888 ,
AudioGetDelay ( ) / 90 , ( int ) VideoDeltaPTS / 90 , VideoGetBuffers ( decoder - > Stream ) ,
decoder - > Interlaced ? 2 * atomic_read ( & decoder - > SurfacesFilled )
- decoder - > SurfaceField : atomic_read ( & decoder - > SurfacesFilled ) , CuvidOutputSurfaceQueued ) ;
if ( ! ( decoder - > FramesDisplayed % ( 5 * 60 * 60 ) ) ) {
CuvidPrintFrames ( decoder ) ;
}
2019-10-26 18:42:19 +02:00
}
# endif
2021-12-27 20:02:45 +01:00
return ; // fix gcc bug!
2019-10-26 18:42:19 +02:00
}
///
/// Sync a video frame.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSyncFrame ( void ) {
2019-10-26 18:42:19 +02:00
int i ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
//
2021-12-27 20:02:45 +01:00
// Sync video decoder to audio
2019-10-26 18:42:19 +02:00
//
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
CuvidSyncDecoder ( CuvidDecoders [ i ] ) ;
}
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Sync and display surface.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSyncDisplayFrame ( void ) {
2018-11-04 13:44:18 +01:00
2019-10-26 18:42:19 +02:00
CuvidDisplayFrame ( ) ;
CuvidSyncFrame ( ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Sync and render a ffmpeg frame
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2021-12-27 20:02:45 +01:00
/// @param video_ctx ffmpeg video codec context
2019-10-26 18:42:19 +02:00
/// @param frame frame to display
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSyncRenderFrame ( CuvidDecoder * decoder , const AVCodecContext * video_ctx , AVFrame * frame ) {
2018-10-14 13:05:22 +02:00
#if 0
2019-10-26 18:42:19 +02:00
// FIXME: temp debug
if ( 0 & & frame - > pkt_pts ! = ( int64_t ) AV_NOPTS_VALUE ) {
2021-12-27 20:02:45 +01:00
Debug ( 3 , " video: render frame pts %s \n " , Timestamp2String ( frame - > pkt_pts ) ) ;
2019-10-26 18:42:19 +02:00
}
2018-10-14 13:05:22 +02:00
# endif
2018-08-19 11:45:46 +02:00
# ifdef DEBUG
2019-10-26 18:42:19 +02:00
if ( ! atomic_read ( & decoder - > SurfacesFilled ) ) {
Debug ( 4 , " video: new stream frame %dms \n " , GetMsTicks ( ) - VideoSwitch ) ;
}
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
// if video output buffer is full, wait and display surface.
// loop for interlace
if ( atomic_read ( & decoder - > SurfacesFilled ) > = VIDEO_SURFACES_MAX ) {
Fatal ( " video/cuvid: this code part shouldn't be used \n " ) ;
return ;
}
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
// if (!decoder->Closing) {
2019-10-28 21:43:37 +01:00
// VideoSetPts(&decoder->PTS, decoder->Interlaced, video_ctx, frame);
// }
2019-10-26 18:42:19 +02:00
CuvidRenderFrame ( decoder , video_ctx , frame ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Set CUVID background color.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param rgba 32 bit RGBA color.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetBackground ( __attribute__ ( ( unused ) ) uint32_t rgba ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set CUVID video mode.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetVideoMode ( void ) {
2019-10-26 18:42:19 +02:00
int i ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Set video mode %dx%d \n " , VideoWindowWidth , VideoWindowHeight ) ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
if ( EglEnabled ) {
2019-10-20 14:48:28 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
GlxSetupWindow ( VideoWindow , VideoWindowWidth , VideoWindowHeight , glxThreadContext ) ;
2019-10-20 14:48:28 +02:00
# else
2019-10-26 18:42:19 +02:00
GlxSetupWindow ( VideoWindow , VideoWindowWidth , VideoWindowHeight , eglContext ) ;
2018-11-17 14:58:25 +01:00
# endif
2019-10-26 18:42:19 +02:00
}
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
// reset video window, upper level needs to fix the positions
CuvidDecoders [ i ] - > VideoX = 0 ;
CuvidDecoders [ i ] - > VideoY = 0 ;
CuvidDecoders [ i ] - > VideoWidth = VideoWindowWidth ;
CuvidDecoders [ i ] - > VideoHeight = VideoWindowHeight ;
CuvidUpdateOutput ( CuvidDecoders [ i ] ) ;
}
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Handle a CUVID display.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidDisplayHandlerThread ( void ) {
2019-10-26 18:42:19 +02:00
int i ;
int err = 0 ;
int allfull ;
int decoded ;
int filled ;
struct timespec nowtime ;
CuvidDecoder * decoder ;
allfull = 1 ;
decoded = 0 ;
for ( i = 0 ; i < CuvidDecoderN ; + + i ) {
decoder = CuvidDecoders [ i ] ;
//
// fill frame output ring buffer
//
filled = atomic_read ( & decoder - > SurfacesFilled ) ;
2021-12-27 20:02:45 +01:00
// if (filled <= 1 + 2 * decoder->Interlaced) {
2020-03-31 13:57:43 +02:00
if ( filled < 5 ) {
2019-10-26 18:42:19 +02:00
// FIXME: hot polling
// fetch+decode or reopen
allfull = 0 ;
2021-12-27 20:02:45 +01:00
err = VideoDecodeInput ( decoder - > Stream , decoder - > TrickSpeed ) ;
2019-10-26 18:42:19 +02:00
} else {
err = VideoPollInput ( decoder - > Stream ) ;
}
// decoder can be invalid here
if ( err ) {
// nothing buffered?
if ( err = = - 1 & & decoder - > Closing ) {
decoder - > Closing - - ;
if ( ! decoder - > Closing ) {
Debug ( 3 , " video/cuvid: closing eof \n " ) ;
decoder - > Closing = - 1 ;
}
}
2020-03-31 13:57:43 +02:00
usleep ( 10 * 1000 ) ;
2019-10-26 18:42:19 +02:00
continue ;
}
decoded = 1 ;
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
if ( ! decoded ) { // nothing decoded, sleep
2019-10-26 18:42:19 +02:00
// FIXME: sleep on wakeup
usleep ( 1 * 1000 ) ;
}
usleep ( 1000 ) ;
// all decoder buffers are full
// and display is not preempted
// speed up filling display queue, wait on display queue empty
if ( ! allfull & & ! decoder - > TrickSpeed ) {
clock_gettime ( CLOCK_MONOTONIC , & nowtime ) ;
// time for one frame over?
2021-12-27 20:02:45 +01:00
if ( ( nowtime . tv_sec - CuvidFrameTime . tv_sec ) * 1000 * 1000 * 1000 +
( nowtime . tv_nsec - CuvidFrameTime . tv_nsec ) <
15 * 1000 * 1000 ) {
2019-10-26 18:42:19 +02:00
return ;
}
}
return ;
2019-04-05 07:20:52 +02:00
}
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set video output position.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder CUVID hw decoder
2021-12-27 20:02:45 +01:00
/// @param x video output x coordinate inside the window
/// @param y video output y coordinate inside the window
2019-10-26 18:42:19 +02:00
/// @param width video output width
/// @param height video output height
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note FIXME: need to know which stream.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void CuvidSetOutputPosition ( CuvidDecoder * decoder , int x , int y , int width , int height ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/cuvid: output %dx%d%+d%+d \n " , width , height , x , y ) ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
decoder - > VideoX = x ;
decoder - > VideoY = y ;
decoder - > VideoWidth = width ;
decoder - > VideoHeight = height ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
// next video pictures are automatic rendered to correct position
2018-08-19 11:45:46 +02:00
}
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// CUVID OSD
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// CUVID module.
2018-08-19 11:45:46 +02:00
///
static const VideoModule CuvidModule = {
2019-10-26 18:42:19 +02:00
. Name = " cuvid " ,
. Enabled = 1 ,
. NewHwDecoder = ( VideoHwDecoder * ( * const ) ( VideoStream * ) ) CuvidNewHwDecoder ,
2021-12-27 20:02:45 +01:00
. DelHwDecoder = ( void ( * const ) ( VideoHwDecoder * ) ) CuvidDelHwDecoder ,
. GetSurface = ( unsigned ( * const ) ( VideoHwDecoder * , const AVCodecContext * ) ) CuvidGetVideoSurface ,
. ReleaseSurface = ( void ( * const ) ( VideoHwDecoder * , unsigned ) ) CuvidReleaseSurface ,
. get_format =
( enum AVPixelFormat ( * const ) ( VideoHwDecoder * , AVCodecContext * , const enum AVPixelFormat * ) ) Cuvid_get_format ,
. RenderFrame = ( void ( * const ) ( VideoHwDecoder * , const AVCodecContext * , const AVFrame * ) ) CuvidSyncRenderFrame ,
2019-10-26 18:42:19 +02:00
. GetHwAccelContext = ( void * ( * const ) ( VideoHwDecoder * ) ) CuvidGetHwAccelContext ,
2021-12-27 20:02:45 +01:00
. SetClock = ( void ( * const ) ( VideoHwDecoder * , int64_t ) ) CuvidSetClock ,
2020-04-13 18:04:57 +02:00
. GetClock = ( int64_t ( * const ) ( const VideoHwDecoder * ) ) CuvidGetClock ,
2021-12-27 20:02:45 +01:00
. SetClosing = ( void ( * const ) ( const VideoHwDecoder * ) ) CuvidSetClosing ,
. ResetStart = ( void ( * const ) ( const VideoHwDecoder * ) ) CuvidResetStart ,
. SetTrickSpeed = ( void ( * const ) ( const VideoHwDecoder * , int ) ) CuvidSetTrickSpeed ,
2018-10-04 16:49:06 +02:00
. GrabOutput = CuvidGrabOutputSurface ,
2021-12-27 20:02:45 +01:00
. GetStats = ( void ( * const ) ( VideoHwDecoder * , int * , int * , int * , int * , float * , int * , int * , int * ,
int * ) ) CuvidGetStats ,
2018-08-19 11:45:46 +02:00
. SetBackground = CuvidSetBackground ,
. SetVideoMode = CuvidSetVideoMode ,
2019-10-12 09:04:04 +02:00
2018-08-19 11:45:46 +02:00
. DisplayHandlerThread = CuvidDisplayHandlerThread ,
2019-10-28 21:43:37 +01:00
// .OsdClear = GlxOsdClear,
// .OsdDrawARGB = GlxOsdDrawARGB,
// .OsdInit = GlxOsdInit,
// .OsdExit = GlxOsdExit,
// .OsdClear = CuvidOsdClear,
// .OsdDrawARGB = CuvidOsdDrawARGB,
// .OsdInit = CuvidOsdInit,
// .OsdExit = CuvidOsdExit,
2018-08-19 11:45:46 +02:00
. Exit = CuvidExit ,
. Init = CuvidGlxInit ,
} ;
# endif
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// NOOP
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Allocate new noop decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param stream video stream
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns always NULL.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static VideoHwDecoder * NoopNewHwDecoder ( __attribute__ ( ( unused ) ) VideoStream * stream ) { return NULL ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Release a surface.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Can be called while exit.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param decoder noop hw decoder
/// @param surface surface no longer used
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopReleaseSurface ( __attribute__ ( ( unused ) ) VideoHwDecoder * decoder ,
__attribute__ ( ( unused ) ) unsigned surface ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set noop background color.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param rgba 32 bit RGBA color.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopSetBackground ( __attribute__ ( ( unused ) ) uint32_t rgba ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Noop initialize OSD.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param width osd width
/// @param height osd height
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopOsdInit ( __attribute__ ( ( unused ) ) int width , __attribute__ ( ( unused ) ) int height ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Draw OSD ARGB image.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param xi x-coordinate in argb image
/// @param yi y-coordinate in argb image
2019-10-26 18:42:19 +02:00
/// @paran height height in pixel in argb image
/// @paran width width in pixel in argb image
/// @param pitch pitch of argb image
/// @param argb 32bit ARGB image data
2021-12-27 20:02:45 +01:00
/// @param x x-coordinate on screen of argb image
/// @param y y-coordinate on screen of argb image
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note looked by caller
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopOsdDrawARGB ( __attribute__ ( ( unused ) ) int xi , __attribute__ ( ( unused ) ) int yi ,
__attribute__ ( ( unused ) ) int width , __attribute__ ( ( unused ) ) int height ,
__attribute__ ( ( unused ) ) int pitch , __attribute__ ( ( unused ) ) const uint8_t * argb ,
__attribute__ ( ( unused ) ) int x , __attribute__ ( ( unused ) ) int y ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Noop setup.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param display_name x11/xcb display name
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns always true.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int NoopInit ( const char * display_name ) {
2018-08-19 11:45:46 +02:00
Info ( " video/noop: noop driver running on display '%s' \n " , display_name ) ;
return 1 ;
}
# ifdef USE_VIDEO_THREAD
///
2019-10-26 18:42:19 +02:00
/// Handle a noop display.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopDisplayHandlerThread ( void ) {
2018-08-19 11:45:46 +02:00
// avoid 100% cpu use
usleep ( 20 * 1000 ) ;
#if 0
// this can't be canceled
if ( XlibDisplay ) {
2021-12-27 20:02:45 +01:00
XEvent event ;
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
XPeekEvent ( XlibDisplay , & event ) ;
2018-08-19 11:45:46 +02:00
}
# endif
}
# else
2021-12-27 20:02:45 +01:00
# define NoopDisplayHandlerThread NULL
2018-08-19 11:45:46 +02:00
# endif
///
2019-10-26 18:42:19 +02:00
/// Noop void function.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void NoopVoid ( void ) { }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Noop video module.
2018-08-19 11:45:46 +02:00
///
static const VideoModule NoopModule = {
. Name = " noop " ,
. Enabled = 1 ,
. NewHwDecoder = NoopNewHwDecoder ,
#if 0
// can't be called:
. DelHwDecoder = NoopDelHwDecoder ,
. GetSurface = ( unsigned ( * const ) ( VideoHwDecoder * ,
2021-12-27 20:02:45 +01:00
const AVCodecContext * ) ) NoopGetSurface ,
2018-08-19 11:45:46 +02:00
# endif
. ReleaseSurface = NoopReleaseSurface ,
#if 0
. get_format = ( enum AVPixelFormat ( * const ) ( VideoHwDecoder * ,
2021-12-27 20:02:45 +01:00
AVCodecContext * , const enum AVPixelFormat * ) ) Noop_get_format ,
2018-08-19 11:45:46 +02:00
. RenderFrame = ( void ( * const ) ( VideoHwDecoder * ,
2021-12-27 20:02:45 +01:00
const AVCodecContext * , const AVFrame * ) ) NoopSyncRenderFrame ,
2018-08-19 11:45:46 +02:00
. GetHwAccelContext = ( void * ( * const ) ( VideoHwDecoder * ) )
2021-12-27 20:02:45 +01:00
DummyGetHwAccelContext ,
. SetClock = ( void ( * const ) ( VideoHwDecoder * , int64_t ) ) NoopSetClock ,
. GetClock = ( int64_t ( * const ) ( const VideoHwDecoder * ) ) NoopGetClock ,
. SetClosing = ( void ( * const ) ( const VideoHwDecoder * ) ) NoopSetClosing ,
. SetTrickSpeed = ( void ( * const ) ( const VideoHwDecoder * , int ) ) NoopSetTrickSpeed ,
2018-08-19 11:45:46 +02:00
. GrabOutput = NoopGrabOutputSurface ,
2021-12-27 20:02:45 +01:00
. GetStats = ( void ( * const ) ( VideoHwDecoder * , int * , int * , int * ,
int * , float * , int * , int * , int * , int * ) ) NoopGetStats ,
2018-08-19 11:45:46 +02:00
# endif
2021-12-27 20:02:45 +01:00
. ResetStart = ( void ( * const ) ( const VideoHwDecoder * ) ) NoopVoid ,
2018-08-19 11:45:46 +02:00
. SetBackground = NoopSetBackground ,
. SetVideoMode = NoopVoid ,
2019-10-12 09:04:04 +02:00
2018-08-19 11:45:46 +02:00
. DisplayHandlerThread = NoopDisplayHandlerThread ,
. OsdClear = NoopVoid ,
. OsdDrawARGB = NoopOsdDrawARGB ,
. OsdInit = NoopOsdInit ,
. OsdExit = NoopVoid ,
. Init = NoopInit ,
. Exit = NoopVoid ,
} ;
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// OSD
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Clear the OSD.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @todo I use glTexImage2D to clear the texture, are there faster and
/// better ways to clear a texture?
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoOsdClear ( void ) {
2018-09-05 20:39:12 +02:00
2018-11-17 14:58:25 +01:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
OsdShown = 0 ;
2018-11-17 14:58:25 +01:00
# else
VideoThreadLock ( ) ;
2019-10-28 21:43:37 +01:00
// VideoUsedModule->OsdClear();
2021-12-27 20:02:45 +01:00
OsdDirtyX = OsdWidth ; // reset dirty area
2018-08-19 11:45:46 +02:00
OsdDirtyY = OsdHeight ;
OsdDirtyWidth = 0 ;
OsdDirtyHeight = 0 ;
OsdShown = 0 ;
VideoThreadUnlock ( ) ;
2018-11-17 14:58:25 +01:00
# endif
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Draw an OSD ARGB image.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param xi x-coordinate in argb image
/// @param yi y-coordinate in argb image
2019-10-26 18:42:19 +02:00
/// @paran height height in pixel in argb image
/// @paran width width in pixel in argb image
/// @param pitch pitch of argb image
/// @param argb 32bit ARGB image data
2021-12-27 20:02:45 +01:00
/// @param x x-coordinate on screen of argb image
/// @param y y-coordinate on screen of argb image
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoOsdDrawARGB ( int xi , int yi , int width , int height , int pitch , const uint8_t * argb , int x , int y ) {
2018-08-19 11:45:46 +02:00
VideoThreadLock ( ) ;
// update dirty area
if ( x < OsdDirtyX ) {
2019-10-26 18:42:19 +02:00
if ( OsdDirtyWidth ) {
OsdDirtyWidth + = OsdDirtyX - x ;
}
OsdDirtyX = x ;
2018-08-19 11:45:46 +02:00
}
if ( y < OsdDirtyY ) {
2019-10-26 18:42:19 +02:00
if ( OsdDirtyHeight ) {
OsdDirtyHeight + = OsdDirtyY - y ;
}
OsdDirtyY = y ;
2018-08-19 11:45:46 +02:00
}
if ( x + width > OsdDirtyX + OsdDirtyWidth ) {
2019-10-26 18:42:19 +02:00
OsdDirtyWidth = x + width - OsdDirtyX ;
2018-08-19 11:45:46 +02:00
}
if ( y + height > OsdDirtyY + OsdDirtyHeight ) {
2019-10-26 18:42:19 +02:00
OsdDirtyHeight = y + height - OsdDirtyY ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video: osd dirty %dx%d%+d%+d -> %dx%d%+d%+d \n " , width , height , x , y , OsdDirtyWidth , OsdDirtyHeight ,
2021-12-27 20:02:45 +01:00
OsdDirtyX , OsdDirtyY ) ;
2018-08-19 11:45:46 +02:00
VideoThreadUnlock ( ) ;
}
2021-12-27 20:02:45 +01:00
void ActivateOsd ( GLuint texture , int x , int y , int xsize , int ysize ) {
// printf("OSD open %d %d %d %d\n",x,y,xsize,ysize);
2019-11-05 22:06:54 +01:00
2019-10-26 18:42:19 +02:00
OSDfb = texture ;
2021-12-27 20:02:45 +01:00
// OSDtexture = texture;
2019-10-26 18:42:19 +02:00
OSDx = x ;
OSDy = y ;
OSDxsize = xsize ;
OSDysize = ysize ;
2019-11-18 13:01:19 +01:00
OsdShown = 1 ;
2018-09-05 20:39:12 +02:00
}
2019-10-04 10:37:57 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Get OSD size.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param[out] width OSD width
/// @param[out] height OSD height
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoGetOsdSize ( int * width , int * height ) {
2018-08-19 11:45:46 +02:00
* width = 1920 ;
2021-12-27 20:02:45 +01:00
* height = 1080 ; // unknown default
2018-11-24 09:34:55 +01:00
2018-08-19 11:45:46 +02:00
if ( OsdWidth & & OsdHeight ) {
2019-10-26 18:42:19 +02:00
* width = OsdWidth ;
* height = OsdHeight ;
2018-08-19 11:45:46 +02:00
}
}
2019-10-26 18:42:19 +02:00
/// Set OSD Size.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param width OSD width
/// @param height OSD height
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetOsdSize ( int width , int height ) {
2018-10-11 17:37:59 +02:00
2018-08-19 11:45:46 +02:00
if ( OsdConfigWidth ! = width | | OsdConfigHeight ! = height ) {
2019-10-26 18:42:19 +02:00
VideoOsdExit ( ) ;
OsdConfigWidth = width ;
OsdConfigHeight = height ;
VideoOsdInit ( ) ;
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Set the 3d OSD mode.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param mode OSD mode (0=off, 1=SBS, 2=Top Bottom)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetOsd3DMode ( int mode ) { Osd3DMode = mode ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Setup osd.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// FIXME: looking for BGRA, but this fourcc isn't supported by the
/// drawing functions yet.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoOsdInit ( void ) {
2018-08-19 11:45:46 +02:00
if ( OsdConfigWidth & & OsdConfigHeight ) {
2019-10-26 18:42:19 +02:00
OsdWidth = OsdConfigWidth ;
OsdHeight = OsdConfigHeight ;
2018-08-19 11:45:46 +02:00
} else {
2019-10-26 18:42:19 +02:00
OsdWidth = VideoWindowWidth ;
OsdHeight = VideoWindowHeight ;
2018-08-19 11:45:46 +02:00
}
2021-12-27 20:02:45 +01:00
// printf("\nset osd %d x %d\n",OsdWidth,OsdHeight);
2020-03-04 16:34:40 +01:00
if ( posd )
free ( posd ) ;
2020-04-10 16:17:23 +02:00
posd = ( unsigned char * ) calloc ( ( OsdWidth + 1 ) * ( OsdHeight + 1 ) * 4 , 1 ) ;
2021-12-27 20:02:45 +01:00
// posd = (unsigned char *)calloc((4096 + 1) * (2160 + 1) * 4, 1);
2018-08-19 11:45:46 +02:00
VideoOsdClear ( ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Cleanup OSD.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoOsdExit ( void ) {
2018-08-19 11:45:46 +02:00
OsdDirtyWidth = 0 ;
OsdDirtyHeight = 0 ;
2020-04-10 16:17:23 +02:00
VideoOsdClear ( ) ;
2018-08-19 11:45:46 +02:00
}
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Events
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
/// C callback feed key press
extern void FeedKeyPress ( const char * , const char * , int , int , const char * ) ;
///
2019-10-26 18:42:19 +02:00
/// Handle XLib I/O Errors.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param display display with i/o error
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int VideoIOErrorHandler ( __attribute__ ( ( unused ) ) Display * display ) {
2018-08-19 11:45:46 +02:00
Error ( _ ( " video: fatal i/o error \n " ) ) ;
// should be called from VideoThread
if ( VideoThread & & VideoThread = = pthread_self ( ) ) {
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video: called from video thread \n " ) ;
VideoUsedModule = & NoopModule ;
XlibDisplay = NULL ;
VideoWindow = XCB_NONE ;
2018-08-19 11:45:46 +02:00
# ifdef USE_VIDEO_THREAD
2019-10-26 18:42:19 +02:00
pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE , NULL ) ;
pthread_cond_destroy ( & VideoWakeupCond ) ;
pthread_mutex_destroy ( & VideoLockMutex ) ;
pthread_mutex_destroy ( & VideoMutex ) ;
VideoThread = 0 ;
pthread_exit ( " video thread exit " ) ;
2018-08-19 11:45:46 +02:00
# endif
}
do {
2019-10-26 18:42:19 +02:00
sleep ( 1000 ) ;
2021-12-27 20:02:45 +01:00
} while ( 1 ) ; // let other threads running
2018-08-19 11:45:46 +02:00
return - 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Handle X11 events.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @todo Signal WmDeleteMessage to application.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void VideoEvent ( void ) {
2018-08-19 11:45:46 +02:00
XEvent event ;
KeySym keysym ;
const char * keynam ;
char buf [ 64 ] ;
char letter [ 64 ] ;
int letter_len ;
uint32_t values [ 1 ] ;
VideoThreadLock ( ) ;
XNextEvent ( XlibDisplay , & event ) ;
VideoThreadUnlock ( ) ;
switch ( event . type ) {
2019-10-26 18:42:19 +02:00
case ClientMessage :
Debug ( 3 , " video/event: ClientMessage \n " ) ;
if ( event . xclient . data . l [ 0 ] = = ( long ) WmDeleteWindowAtom ) {
Debug ( 3 , " video/event: wm-delete-message \n " ) ;
FeedKeyPress ( " XKeySym " , " Close " , 0 , 0 , NULL ) ;
}
break ;
case MapNotify :
Debug ( 3 , " video/event: MapNotify \n " ) ;
2019-10-28 21:43:37 +01:00
// wm workaround
2019-10-26 18:42:19 +02:00
VideoThreadLock ( ) ;
xcb_change_window_attributes ( Connection , VideoWindow , XCB_CW_CURSOR , & VideoBlankCursor ) ;
VideoThreadUnlock ( ) ;
VideoBlankTick = 0 ;
break ;
case Expose :
2019-10-28 21:43:37 +01:00
// Debug(3, "video/event: Expose\n");
2019-10-26 18:42:19 +02:00
break ;
case ReparentNotify :
Debug ( 3 , " video/event: ReparentNotify \n " ) ;
break ;
case ConfigureNotify :
2019-10-28 21:43:37 +01:00
// Debug(3, "video/event: ConfigureNotify\n");
2019-10-26 18:42:19 +02:00
VideoSetVideoMode ( event . xconfigure . x , event . xconfigure . y , event . xconfigure . width , event . xconfigure . height ) ;
break ;
case ButtonPress :
VideoSetFullscreen ( - 1 ) ;
break ;
case KeyPress :
VideoThreadLock ( ) ;
letter_len = XLookupString ( & event . xkey , letter , sizeof ( letter ) - 1 , & keysym , NULL ) ;
VideoThreadUnlock ( ) ;
if ( letter_len < 0 ) {
letter_len = 0 ;
}
letter [ letter_len ] = ' \0 ' ;
if ( keysym = = NoSymbol ) {
Warning ( _ ( " video/event: No symbol for %d \n " ) , event . xkey . keycode ) ;
break ;
}
VideoThreadLock ( ) ;
keynam = XKeysymToString ( keysym ) ;
VideoThreadUnlock ( ) ;
// check for key modifiers (Alt/Ctrl)
if ( event . xkey . state & ( Mod1Mask | ControlMask ) ) {
if ( event . xkey . state & Mod1Mask ) {
strcpy ( buf , " Alt+ " ) ;
} else {
buf [ 0 ] = ' \0 ' ;
}
if ( event . xkey . state & ControlMask ) {
strcat ( buf , " Ctrl+ " ) ;
}
strncat ( buf , keynam , sizeof ( buf ) - 10 ) ;
keynam = buf ;
}
FeedKeyPress ( " XKeySym " , keynam , 0 , 0 , letter ) ;
break ;
case KeyRelease :
2020-08-14 12:38:27 +02:00
case ButtonRelease :
2019-10-26 18:42:19 +02:00
break ;
case MotionNotify :
values [ 0 ] = XCB_NONE ;
VideoThreadLock ( ) ;
xcb_change_window_attributes ( Connection , VideoWindow , XCB_CW_CURSOR , values ) ;
VideoThreadUnlock ( ) ;
VideoBlankTick = GetMsTicks ( ) ;
break ;
default :
2018-08-19 11:45:46 +02:00
#if 0
2021-12-27 20:02:45 +01:00
if ( XShmGetEventBase ( XlibDisplay ) + ShmCompletion = = event . type ) {
// printf("ShmCompletion\n");
}
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Unsupported event type %d \n " , event . type ) ;
break ;
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Poll all x11 events.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoPollEvent ( void ) {
2018-08-19 11:45:46 +02:00
// hide cursor, after xx ms
if ( VideoBlankTick & & VideoWindow ! = XCB_NONE & & VideoBlankTick + 200 < GetMsTicks ( ) ) {
2019-10-26 18:42:19 +02:00
VideoThreadLock ( ) ;
xcb_change_window_attributes ( Connection , VideoWindow , XCB_CW_CURSOR , & VideoBlankCursor ) ;
VideoThreadUnlock ( ) ;
VideoBlankTick = 0 ;
2018-08-19 11:45:46 +02:00
}
while ( XlibDisplay ) {
2019-10-26 18:42:19 +02:00
VideoThreadLock ( ) ;
if ( ! XPending ( XlibDisplay ) ) {
VideoThreadUnlock ( ) ;
break ;
}
VideoThreadUnlock ( ) ;
VideoEvent ( ) ;
2018-08-19 11:45:46 +02:00
}
}
2019-10-04 10:37:57 +02:00
2021-12-27 20:02:45 +01:00
void VideoSetVideoEventCallback ( void ( * videoEventCallback ) ( void ) ) { VideoEventCallback = videoEventCallback ; }
2019-10-04 10:37:57 +02:00
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Thread
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
# ifdef USE_VIDEO_THREAD
2018-11-05 10:38:27 +01:00
# ifdef PLACEBO
2018-11-05 14:49:54 +01:00
2021-12-27 20:02:45 +01:00
static bool open_file ( const char * path , struct file * out ) {
2021-03-16 09:40:08 +01:00
if ( ! path | | ! path [ 0 ] ) {
2021-12-27 20:02:45 +01:00
* out = ( struct file ) { 0 } ;
2021-03-16 09:40:08 +01:00
return true ;
}
FILE * fp = NULL ;
bool success = false ;
fp = fopen ( path , " rb " ) ;
if ( ! fp )
goto done ;
if ( fseeko ( fp , 0 , SEEK_END ) )
goto done ;
off_t size = ftello ( fp ) ;
2021-12-27 20:02:45 +01:00
2021-03-16 09:40:08 +01:00
if ( size < 0 )
goto done ;
if ( fseeko ( fp , 0 , SEEK_SET ) )
goto done ;
void * data = malloc ( size ) ;
2021-12-27 20:02:45 +01:00
2021-03-16 09:40:08 +01:00
if ( ! fread ( data , size , 1 , fp ) )
goto done ;
2021-12-27 20:02:45 +01:00
* out = ( struct file ) {
2021-03-16 09:40:08 +01:00
. data = data ,
. size = size ,
} ;
success = true ;
done :
if ( fp )
fclose ( fp ) ;
return success ;
}
2021-12-27 20:02:45 +01:00
static void close_file ( struct file * file ) {
2021-03-16 09:40:08 +01:00
if ( ! file - > data )
return ;
free ( file - > data ) ;
2021-12-27 20:02:45 +01:00
* file = ( struct file ) { 0 } ;
2021-03-16 09:40:08 +01:00
}
2021-12-27 20:02:45 +01:00
void pl_log_intern ( void * stream , enum pl_log_level level , const char * msg ) {
2018-11-24 09:34:55 +01:00
static const char * prefix [ ] = {
2021-12-27 20:02:45 +01:00
[ PL_LOG_FATAL ] = " fatal " , [ PL_LOG_ERR ] = " error " , [ PL_LOG_WARN ] = " warn " ,
[ PL_LOG_INFO ] = " info " , [ PL_LOG_DEBUG ] = " debug " , [ PL_LOG_TRACE ] = " trace " ,
2018-11-24 09:34:55 +01:00
} ;
printf ( " %5s: %s \n " , prefix [ level ] , msg ) ;
}
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
void InitPlacebo ( ) {
2021-03-16 09:40:08 +01:00
static const char * lut_file = " lut/lut.cube " ;
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 , " Init Placebo mit API %d \n " , PL_API_VER ) ;
2021-03-16 09:40:08 +01:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 , " Placebo mit opengl \n " ) ;
2021-03-16 09:40:08 +01:00
# else
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 , " Placebo mit vulkan \n " ) ;
2021-03-16 09:40:08 +01:00
# endif
2019-10-26 18:42:19 +02:00
p = calloc ( 1 , sizeof ( struct priv ) ) ;
if ( ! p )
Fatal ( _ ( " Cant get memory for PLACEBO struct " ) ) ;
// Create context
p - > context . log_cb = & pl_log_intern ;
2021-12-27 20:02:45 +01:00
p - > context . log_level = PL_LOG_WARN ; // WARN
2018-11-04 13:44:18 +01:00
2023-02-15 15:58:51 +01:00
p - > ctx = pl_log_create ( PL_API_VER , & p - > context ) ;
2018-11-04 13:44:18 +01:00
if ( ! p - > ctx ) {
Fatal ( _ ( " Failed initializing libplacebo \n " ) ) ;
}
2021-12-27 20:02:45 +01:00
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
// eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
// eglSharedContext);
2020-05-01 12:06:04 +02:00
struct pl_opengl_params params = pl_opengl_default_params ;
2021-12-27 20:02:45 +01:00
2021-01-28 12:59:58 +01:00
params . egl_display = eglDisplay ;
params . egl_context = eglContext ;
2021-12-27 20:02:45 +01:00
2020-05-01 12:06:04 +02:00
p - > gl = pl_opengl_create ( p - > ctx , & params ) ;
2021-12-27 20:02:45 +01:00
2021-01-28 12:59:58 +01:00
if ( ! p - > gl )
Fatal ( _ ( " Failed to create placebo opengl \n " ) ) ;
2021-12-27 20:02:45 +01:00
p - > swapchain = pl_opengl_create_swapchain ( p - > gl , & ( struct pl_opengl_swapchain_params ) {
. swap_buffers = ( void ( * ) ( void * ) ) CuvidSwapBuffer ,
. framebuffer . flipped = true ,
. framebuffer . id = 0 ,
. max_swapchain_depth = 3 ,
. priv = VideoWindow ,
} ) ;
2020-05-01 12:06:04 +02:00
p - > gpu = p - > gl - > gpu ;
2021-12-27 20:02:45 +01:00
2020-05-01 12:06:04 +02:00
# else
2021-12-27 20:02:45 +01:00
struct pl_vulkan_params params = { 0 } ;
2020-05-01 12:06:04 +02:00
struct pl_vk_inst_params iparams = pl_vk_inst_default_params ;
2021-12-27 20:02:45 +01:00
VkXcbSurfaceCreateInfoKHR xcbinfo ;
char xcbext [ ] = { " VK_KHR_xcb_surface " } ;
char surfext [ ] = { " VK_KHR_surface " } ;
char * ext [ 2 ] = { & xcbext , & surfext } ;
2019-10-26 18:42:19 +02:00
// create Vulkan instance
2021-12-27 20:02:45 +01:00
// memcpy(&iparams, &pl_vk_inst_default_params, sizeof(iparams));
2019-10-28 21:43:37 +01:00
// iparams.debug = true;
2021-12-27 20:02:45 +01:00
iparams . num_extensions = 2 ; // extensions_count;
2020-05-15 16:37:06 +02:00
iparams . extensions = & ext ;
2019-10-26 18:42:19 +02:00
iparams . debug = false ;
p - > vk_inst = pl_vk_inst_create ( p - > ctx , & iparams ) ;
// create XCB surface for swapchain
xcbinfo . sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR ;
xcbinfo . pNext = NULL ;
xcbinfo . flags = 0 ;
xcbinfo . connection = Connection ;
xcbinfo . window = VideoWindow ;
if ( vkCreateXcbSurfaceKHR ( p - > vk_inst - > instance , & xcbinfo , NULL , & p - > pSurface ) ! = VK_SUCCESS ) {
Fatal ( _ ( " Failed to create XCB Surface \n " ) ) ;
}
// create Vulkan device
memcpy ( & params , & pl_vulkan_default_params , sizeof ( params ) ) ;
params . instance = p - > vk_inst - > instance ;
params . async_transfer = true ;
2018-11-17 14:58:25 +01:00
params . async_compute = true ;
2021-04-20 08:27:19 +02:00
params . queue_count = 16 ;
2019-10-26 18:42:19 +02:00
params . surface = p - > pSurface ;
2019-04-05 07:20:52 +02:00
params . allow_software = false ;
2019-10-26 18:42:19 +02:00
p - > vk = pl_vulkan_create ( p - > ctx , & params ) ;
if ( ! p - > vk )
Fatal ( _ ( " Failed to create Vulkan Device " ) ) ;
2018-11-04 13:44:18 +01:00
p - > gpu = p - > vk - > gpu ;
2021-12-27 20:02:45 +01:00
// Create initial swapchain
p - > swapchain = pl_vulkan_create_swapchain ( p - > vk , & ( struct pl_vulkan_swapchain_params ) {
. surface = p - > pSurface ,
. present_mode = VK_PRESENT_MODE_FIFO_KHR ,
. swapchain_depth = SWAP_BUFFER_SIZE ,
2023-02-15 15:58:51 +01:00
# if PL_API_VER < 229
2021-12-27 20:02:45 +01:00
. prefer_hdr = true ,
2023-02-15 15:58:51 +01:00
# endif
2021-12-27 20:02:45 +01:00
} ) ;
2018-11-17 14:58:25 +01:00
2020-05-01 12:06:04 +02:00
# endif
2021-12-27 20:02:45 +01:00
2018-11-17 14:58:25 +01:00
if ( ! p - > swapchain ) {
Fatal ( _ ( " Failed creating vulkan swapchain! " ) ) ;
}
2021-12-27 20:02:45 +01:00
2020-05-01 12:06:04 +02:00
if ( ! ( p - > gpu - > import_caps . tex & PL_HANDLE_DMA_BUF ) ) {
p - > has_dma_buf = 0 ;
Debug ( 3 , " No support for dma_buf import \n " ) ;
} else {
p - > has_dma_buf = 1 ;
Debug ( 3 , " dma_buf support available \n " ) ;
}
2019-04-05 07:20:52 +02:00
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
2021-12-27 20:02:45 +01:00
if ( ! pl_swapchain_resize ( p - > swapchain , & VideoWindowWidth , & VideoWindowHeight ) ) {
Fatal ( _ ( " libplacebo: failed initializing swapchain \n " ) ) ;
}
# endif
2021-03-16 09:40:08 +01:00
# if PL_API_VER >= 113
// load LUT File
struct file lutf ;
char tmp [ 200 ] ;
2021-12-27 20:02:45 +01:00
sprintf ( tmp , " %s/%s " , MyConfigDir , lut_file ) ;
2021-03-16 09:40:08 +01:00
if ( open_file ( tmp , & lutf ) & & lutf . size ) {
if ( ! ( p - > lut = pl_lut_parse_cube ( p - > ctx , lutf . data , lutf . size ) ) )
fprintf ( stderr , " Failed parsing LUT.. continuing anyway \n " ) ;
close_file ( & lutf ) ;
2021-12-27 20:02:45 +01:00
} else {
2021-03-16 09:40:08 +01:00
Debug ( 3 , " Placebo: No LUT File used \n " ) ;
}
# endif
2019-10-26 18:42:19 +02:00
// create renderer
p - > renderer = pl_renderer_create ( p - > ctx , p - > gpu ) ;
2018-11-04 13:44:18 +01:00
if ( ! p - > renderer ) {
Fatal ( _ ( " Failed initializing libplacebo renderer \n " ) ) ;
}
2020-05-01 12:06:04 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Placebo: init ok " ) ;
2018-11-17 14:58:25 +01:00
}
# endif
///
2019-10-26 18:42:19 +02:00
/// Video render thread.
2018-11-17 14:58:25 +01:00
///
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
void delete_decode ( ) { Debug ( 3 , " decoder thread exit \n " ) ; }
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
static void * VideoDisplayHandlerThread ( void * dummy ) {
2019-10-26 18:42:19 +02:00
2020-02-18 22:02:53 +01:00
prctl ( PR_SET_NAME , " video decoder " , 0 , 0 , 0 ) ;
2019-10-26 18:42:19 +02:00
sleep ( 2 ) ;
2020-04-10 16:17:23 +02:00
pthread_cleanup_push ( delete_decode , NULL ) ;
2018-08-19 11:45:46 +02:00
for ( ; ; ) {
2019-10-26 18:42:19 +02:00
// fix dead-lock with CuvidExit
pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE , NULL ) ;
pthread_testcancel ( ) ;
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE , NULL ) ;
2019-12-10 10:45:22 +01:00
2019-10-26 18:42:19 +02:00
VideoUsedModule - > DisplayHandlerThread ( ) ;
2018-08-19 11:45:46 +02:00
}
2020-04-10 16:17:23 +02:00
pthread_cleanup_pop ( NULL ) ;
2018-08-19 11:45:46 +02:00
return dummy ;
}
2021-12-27 20:02:45 +01:00
void exit_display ( ) {
2020-04-10 16:17:23 +02:00
2020-02-18 22:02:53 +01:00
# ifdef GAMMA
Exit_Gamma ( ) ;
# endif
2020-04-10 16:17:23 +02:00
2020-01-07 22:22:07 +01:00
# ifdef PLACEBO
Debug ( 3 , " delete placebo \n " ) ;
2020-06-07 12:31:18 +02:00
if ( p = = NULL ) {
2021-12-27 20:02:45 +01:00
Debug ( 3 , " Placebo not initialised \n " ) ;
2020-01-07 22:22:07 +01:00
return ;
2020-06-07 12:31:18 +02:00
}
pl_gpu_finish ( p - > gpu ) ;
2023-02-18 08:45:32 +01:00
# if PL_API_VER >= 229
2023-02-15 15:58:51 +01:00
if ( osdoverlay . tex )
pl_tex_destroy ( p - > gpu , & osdoverlay . tex ) ;
# else
2020-01-07 22:22:07 +01:00
if ( osdoverlay . plane . texture )
pl_tex_destroy ( p - > gpu , & osdoverlay . plane . texture ) ;
2023-02-15 15:58:51 +01:00
# endif
2020-01-07 22:22:07 +01:00
2021-12-27 20:02:45 +01:00
// pl_renderer_destroy(&p->renderer);
2020-01-07 22:22:07 +01:00
if ( p - > renderertest ) {
pl_renderer_destroy ( & p - > renderertest ) ;
p - > renderertest = NULL ;
}
2021-12-27 20:02:45 +01:00
2020-01-07 22:22:07 +01:00
pl_swapchain_destroy ( & p - > swapchain ) ;
2021-12-27 20:02:45 +01:00
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
pl_opengl_destroy ( & p - > gl ) ;
# else
2021-12-27 20:02:45 +01:00
// pl_vulkan_destroy(&p->vk);
2020-01-07 22:22:07 +01:00
vkDestroySurfaceKHR ( p - > vk_inst - > instance , p - > pSurface , NULL ) ;
pl_vk_inst_destroy ( & p - > vk_inst ) ;
2020-05-01 12:06:04 +02:00
# endif
2021-12-27 20:02:45 +01:00
2023-02-15 15:58:51 +01:00
pl_log_destroy ( & p - > ctx ) ;
2021-03-16 09:40:08 +01:00
# if PL_API_VER >= 113
pl_lut_free ( & p - > lut ) ;
# endif
2020-01-07 22:22:07 +01:00
free ( p ) ;
p = NULL ;
# endif
2021-12-27 20:02:45 +01:00
2020-01-07 22:22:07 +01:00
# ifdef CUVID
2020-04-10 16:17:23 +02:00
if ( glxThreadContext ) {
2020-01-07 22:22:07 +01:00
glXDestroyContext ( XlibDisplay , glxThreadContext ) ;
GlxCheck ( ) ;
glxThreadContext = NULL ;
}
# else
2020-04-10 16:17:23 +02:00
if ( eglThreadContext ) {
2020-01-07 22:22:07 +01:00
eglDestroyContext ( eglDisplay , eglThreadContext ) ;
EglCheck ( ) ;
2020-04-10 16:17:23 +02:00
eglThreadContext = NULL ;
2020-01-07 22:22:07 +01:00
}
# endif
2021-12-27 20:02:45 +01:00
Debug ( 3 , " display thread exit \n " ) ;
2020-01-07 22:22:07 +01:00
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
static void * VideoHandlerThread ( void * dummy ) {
2021-01-10 13:55:09 +01:00
# ifdef VAAPI
2021-12-27 20:02:45 +01:00
EGLint contextAttrs [ ] = { EGL_CONTEXT_CLIENT_VERSION , 3 , EGL_NONE } ;
2021-01-10 13:55:09 +01:00
# endif
2021-12-27 20:02:45 +01:00
int redSize , greenSize , blueSize , alphaSize ;
2020-01-07 22:22:07 +01:00
prctl ( PR_SET_NAME , " video display " , 0 , 0 , 0 ) ;
2020-02-18 22:02:53 +01:00
# ifdef GAMMA
Init_Gamma ( ) ;
2020-04-10 16:17:23 +02:00
Set_Gamma ( 0.0 , 6500 ) ;
2020-02-18 22:02:53 +01:00
# endif
2020-04-10 16:17:23 +02:00
2020-05-01 12:06:04 +02:00
# if (defined CUVID && !defined PLACEBO) || (defined CUVID && defined PLACEBO_GL)
2019-12-17 10:22:22 +01:00
if ( EglEnabled ) {
glxThreadContext = glXCreateContext ( XlibDisplay , GlxVisualInfo , glxSharedContext , GL_TRUE ) ;
GlxSetupWindow ( VideoWindow , VideoWindowWidth , VideoWindowHeight , glxThreadContext ) ;
}
2020-04-10 16:17:23 +02:00
# endif
2020-05-01 12:06:04 +02:00
# if (defined VAAPI && !defined PLACEBO) || (defined VAAPI && defined PLACEBO_GL)
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO_GL
2021-01-28 12:59:58 +01:00
if ( ! eglBindAPI ( EGL_OPENGL_API ) ) {
2021-01-10 13:55:09 +01:00
Fatal ( _ ( " Could not bind API! \n " ) ) ;
}
2021-01-28 12:59:58 +01:00
eglThreadContext = eglCreateContext ( eglDisplay , eglConfig , eglSharedContext , eglAttrs ) ;
2021-01-10 13:55:09 +01:00
# else
2019-12-17 10:22:22 +01:00
eglThreadContext = eglCreateContext ( eglDisplay , eglConfig , eglSharedContext , contextAttrs ) ;
2021-01-10 13:55:09 +01:00
# endif
2019-12-17 10:22:22 +01:00
if ( ! eglThreadContext ) {
EglCheck ( ) ;
Fatal ( _ ( " video/egl: can't create thread egl context \n " ) ) ;
return NULL ;
}
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , eglSurface , eglSurface , eglThreadContext ) ;
2019-12-17 10:22:22 +01:00
# endif
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO
InitPlacebo ( ) ;
2019-12-10 10:45:22 +01:00
# endif
2021-12-27 20:02:45 +01:00
2020-04-10 16:17:23 +02:00
pthread_cleanup_push ( exit_display , NULL ) ;
2020-06-07 12:31:18 +02:00
while ( 1 ) {
2019-10-26 18:42:19 +02:00
pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE , NULL ) ;
pthread_testcancel ( ) ;
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE , NULL ) ;
2020-01-07 22:22:07 +01:00
# ifndef USE_DRM
2019-10-26 18:42:19 +02:00
VideoPollEvent ( ) ;
2020-01-07 22:22:07 +01:00
# endif
2019-10-28 21:43:37 +01:00
// first_time = GetusTicks();
2019-10-26 18:42:19 +02:00
CuvidSyncDisplayFrame ( ) ;
2019-10-28 21:43:37 +01:00
// printf("syncdisplayframe exec %d\n",(GetusTicks()-first_time)/1000);
2019-10-26 18:42:19 +02:00
}
2020-01-07 22:22:07 +01:00
pthread_cleanup_pop ( NULL ) ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
return dummy ;
2019-04-05 07:20:52 +02:00
}
2019-12-10 10:45:22 +01:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Initialize video threads.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void VideoThreadInit ( void ) {
2018-11-17 14:58:25 +01:00
# ifndef PLACEBO
2019-10-04 10:37:57 +02:00
# ifdef CUVID
2019-10-26 18:42:19 +02:00
glXMakeCurrent ( XlibDisplay , None , NULL ) ;
2019-10-04 10:37:57 +02:00
# else
2020-01-07 22:22:07 +01:00
// eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext);
2019-10-04 10:37:57 +02:00
# endif
2021-12-27 20:02:45 +01:00
# endif
2018-08-19 11:45:46 +02:00
pthread_mutex_init ( & VideoMutex , NULL ) ;
pthread_mutex_init ( & VideoLockMutex , NULL ) ;
2019-10-26 18:42:19 +02:00
pthread_mutex_init ( & OSDMutex , NULL ) ;
pthread_cond_init ( & VideoWakeupCond , NULL ) ;
pthread_create ( & VideoThread , NULL , VideoDisplayHandlerThread , NULL ) ;
2020-04-10 16:17:23 +02:00
2019-10-26 18:42:19 +02:00
pthread_create ( & VideoDisplayThread , NULL , VideoHandlerThread , NULL ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Exit and cleanup video threads.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void VideoThreadExit ( void ) {
2018-08-19 11:45:46 +02:00
if ( VideoThread ) {
2019-10-26 18:42:19 +02:00
void * retval ;
Debug ( 3 , " video: video thread canceled \n " ) ;
// FIXME: can't cancel locked
if ( pthread_cancel ( VideoThread ) ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " video: can't queue cancel video display thread \n " ) ;
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
usleep ( 200000 ) ; // 200ms
2019-10-26 18:42:19 +02:00
if ( pthread_join ( VideoThread , & retval ) | | retval ! = PTHREAD_CANCELED ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " video: can't cancel video decoder thread \n " ) ;
2019-10-26 18:42:19 +02:00
}
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
if ( VideoDisplayThread ) {
if ( pthread_cancel ( VideoDisplayThread ) ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " video: can't queue cancel video display thread \n " ) ;
}
2021-12-27 20:02:45 +01:00
usleep ( 200000 ) ; // 200ms
2019-10-26 18:42:19 +02:00
if ( pthread_join ( VideoDisplayThread , & retval ) | | retval ! = PTHREAD_CANCELED ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " video: can't cancel video display thread \n " ) ;
2019-10-26 18:42:19 +02:00
}
VideoDisplayThread = 0 ;
}
2021-12-27 20:02:45 +01:00
2019-10-26 18:42:19 +02:00
VideoThread = 0 ;
pthread_cond_destroy ( & VideoWakeupCond ) ;
pthread_mutex_destroy ( & VideoLockMutex ) ;
pthread_mutex_destroy ( & VideoMutex ) ;
pthread_mutex_destroy ( & OSDMutex ) ;
2019-11-05 22:06:54 +01:00
2019-10-20 14:48:28 +02:00
# ifndef PLACEBO
2020-01-07 22:22:07 +01:00
2019-11-18 13:01:19 +01:00
if ( OSDtexture )
glDeleteTextures ( 1 , & OSDtexture ) ;
2020-01-07 22:22:07 +01:00
2019-10-26 18:42:19 +02:00
if ( gl_prog_osd ) {
glDeleteProgram ( gl_prog_osd ) ;
gl_prog_osd = 0 ;
}
if ( gl_prog ) {
glDeleteProgram ( gl_prog ) ;
gl_prog = 0 ;
}
2020-01-07 22:22:07 +01:00
2019-10-20 14:48:28 +02:00
# endif
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Video display wakeup.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// New video arrived, wakeup video thread.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoDisplayWakeup ( void ) {
2019-12-10 10:45:22 +01:00
# ifndef USE_DRM
2021-12-27 20:02:45 +01:00
if ( ! XlibDisplay ) { // not yet started
2019-10-26 18:42:19 +02:00
return ;
2018-08-19 11:45:46 +02:00
}
2019-12-10 10:45:22 +01:00
# endif
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
if ( ! VideoThread ) { // start video thread, if needed
2019-10-26 18:42:19 +02:00
VideoThreadInit ( ) ;
2018-08-19 11:45:46 +02:00
}
}
# endif
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Video API
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Table of all video modules.
2018-08-19 11:45:46 +02:00
///
static const VideoModule * VideoModules [ ] = {
2021-12-27 20:02:45 +01:00
& CuvidModule , & NoopModule } ;
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Video hardware decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
struct _video_hw_decoder_ {
union {
CuvidDecoder Cuvid ; ///< cuvid decoder structure
2018-08-19 11:45:46 +02:00
} ;
} ;
///
2019-10-26 18:42:19 +02:00
/// Allocate new video hw decoder.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param stream video stream
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns a new initialized video hardware decoder.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
VideoHwDecoder * VideoNewHwDecoder ( VideoStream * stream ) {
2018-08-19 11:45:46 +02:00
VideoHwDecoder * hw ;
VideoThreadLock ( ) ;
hw = VideoUsedModule - > NewHwDecoder ( stream ) ;
VideoThreadUnlock ( ) ;
return hw ;
}
///
2019-10-26 18:42:19 +02:00
/// Destroy a video hw decoder.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoDelHwDecoder ( VideoHwDecoder * hw_decoder ) {
2018-08-19 11:45:46 +02:00
if ( hw_decoder ) {
# ifdef DEBUG
2019-10-26 18:42:19 +02:00
if ( ! pthread_equal ( pthread_self ( ) , VideoThread ) ) {
Debug ( 3 , " video: should only be called from inside the thread \n " ) ;
}
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
// only called from inside the thread
2019-10-28 21:43:37 +01:00
// VideoThreadLock();
2019-10-26 18:42:19 +02:00
VideoUsedModule - > DelHwDecoder ( hw_decoder ) ;
2019-10-28 21:43:37 +01:00
// VideoThreadUnlock();
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Get a free hardware decoder surface.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param video_ctx ffmpeg video codec context
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns the oldest free surface or invalid surface
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
unsigned VideoGetSurface ( VideoHwDecoder * hw_decoder , const AVCodecContext * video_ctx ) {
2018-08-19 11:45:46 +02:00
return VideoUsedModule - > GetSurface ( hw_decoder , video_ctx ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Release a hardware decoder surface.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2019-10-26 18:42:19 +02:00
/// @param surface surface no longer used
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoReleaseSurface ( VideoHwDecoder * hw_decoder , unsigned surface ) {
2018-08-19 11:45:46 +02:00
// FIXME: must be guarded against calls, after VideoExit
VideoUsedModule - > ReleaseSurface ( hw_decoder , surface ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Callback to negotiate the PixelFormat.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param video_ctx ffmpeg video codec context
/// @param fmt is the list of formats which are supported by
/// the codec, it is terminated by -1 as 0 is a
/// valid format, the formats are ordered by
/// quality.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
enum AVPixelFormat Video_get_format ( VideoHwDecoder * hw_decoder , AVCodecContext * video_ctx ,
const enum AVPixelFormat * fmt ) {
2018-08-19 11:45:46 +02:00
# ifdef DEBUG
int ms_delay ;
// FIXME: use frame time
2021-12-27 20:02:45 +01:00
ms_delay = ( 1000 * video_ctx - > time_base . num * video_ctx - > ticks_per_frame ) / video_ctx - > time_base . den ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video: ready %s %2dms/frame %dms \n " , Timestamp2String ( VideoGetClock ( hw_decoder ) ) , ms_delay ,
2021-12-27 20:02:45 +01:00
GetMsTicks ( ) - VideoSwitch ) ;
2018-08-19 11:45:46 +02:00
# endif
return VideoUsedModule - > get_format ( hw_decoder , video_ctx , fmt ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Display a ffmpeg frame
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param video_ctx ffmpeg video codec context
2019-10-26 18:42:19 +02:00
/// @param frame frame to display
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoRenderFrame ( VideoHwDecoder * hw_decoder , const AVCodecContext * video_ctx , const AVFrame * frame ) {
2018-08-19 11:45:46 +02:00
#if 0
2019-10-26 18:42:19 +02:00
fprintf ( stderr , " video: render frame pts %s closing %d \n " , Timestamp2String ( frame - > pkt_pts ) ,
2021-12-27 20:02:45 +01:00
hw_decoder - > Cuvid . Closing ) ;
2018-08-19 11:45:46 +02:00
# endif
if ( frame - > repeat_pict & & ! VideoIgnoreRepeatPict ) {
2019-10-26 18:42:19 +02:00
Warning ( _ ( " video: repeated pict %d found, but not handled \n " ) , frame - > repeat_pict ) ;
2018-08-19 11:45:46 +02:00
}
VideoUsedModule - > RenderFrame ( hw_decoder , video_ctx , frame ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Get hwaccel context for ffmpeg.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// FIXME: new ffmpeg supports cuvid hw context
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder (must be VA-API)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void * VideoGetHwAccelContext ( VideoHwDecoder * hw_decoder ) { return VideoUsedModule - > GetHwAccelContext ( hw_decoder ) ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set video clock.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param pts audio presentation timestamp
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetClock ( VideoHwDecoder * hw_decoder , int64_t pts ) {
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: set clock %s \n " , Timestamp2String ( pts ) ) ;
if ( hw_decoder ) {
2019-10-26 18:42:19 +02:00
VideoUsedModule - > SetClock ( hw_decoder , pts ) ;
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Get video clock.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note this isn't monoton, decoding reorders frames, setter keeps it
/// monotonic
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
int64_t VideoGetClock ( const VideoHwDecoder * hw_decoder ) {
2018-08-19 11:45:46 +02:00
if ( hw_decoder ) {
2019-10-26 18:42:19 +02:00
return VideoUsedModule - > GetClock ( hw_decoder ) ;
2018-08-19 11:45:46 +02:00
}
return AV_NOPTS_VALUE ;
}
///
2019-10-26 18:42:19 +02:00
/// Set closing stream flag.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetClosing ( VideoHwDecoder * hw_decoder ) {
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: set closing \n " ) ;
VideoUsedModule - > SetClosing ( hw_decoder ) ;
// clear clock to avoid further sync
VideoSetClock ( hw_decoder , AV_NOPTS_VALUE ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Reset start of frame counter.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoResetStart ( VideoHwDecoder * hw_decoder ) {
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: reset start \n " ) ;
2020-06-07 12:31:18 +02:00
2018-08-19 11:45:46 +02:00
VideoUsedModule - > ResetStart ( hw_decoder ) ;
// clear clock to trigger new video stream
VideoSetClock ( hw_decoder , AV_NOPTS_VALUE ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Set trick play speed.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
2019-10-26 18:42:19 +02:00
/// @param speed trick speed (0 = normal)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetTrickSpeed ( VideoHwDecoder * hw_decoder , int speed ) {
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: set trick-speed %d \n " , speed ) ;
VideoUsedModule - > SetTrickSpeed ( hw_decoder , speed ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Grab full screen image.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param size[out] size of allocated image
2019-10-26 18:42:19 +02:00
/// @param width[in,out] width of image
/// @param height[in,out] height of image
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
uint8_t * VideoGrab ( int * size , int * width , int * height , int write_header ) {
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: grab \n " ) ;
# ifdef USE_GRAB
if ( VideoUsedModule - > GrabOutput ) {
2019-10-26 18:42:19 +02:00
uint8_t * data ;
uint8_t * rgb ;
char buf [ 64 ] ;
int i ;
int n ;
int scale_width ;
int scale_height ;
int x ;
int y ;
double src_x ;
double src_y ;
double scale_x ;
double scale_y ;
scale_width = * width ;
scale_height = * height ;
n = 0 ;
data = VideoUsedModule - > GrabOutput ( size , width , height , 1 ) ;
if ( data = = NULL )
return NULL ;
if ( scale_width < = 0 ) {
scale_width = * width ;
}
if ( scale_height < = 0 ) {
scale_height = * height ;
}
// hardware didn't scale for us, use simple software scaler
if ( scale_width ! = * width & & scale_height ! = * height ) {
if ( write_header ) {
n = snprintf ( buf , sizeof ( buf ) , " P6 \n %d \n %d \n 255 \n " , scale_width , scale_height ) ;
}
rgb = malloc ( scale_width * scale_height * 3 + n ) ;
if ( ! rgb ) {
Error ( _ ( " video: out of memory \n " ) ) ;
free ( data ) ;
return NULL ;
}
* size = scale_width * scale_height * 3 + n ;
2021-12-27 20:02:45 +01:00
memcpy ( rgb , buf , n ) ; // header
2019-10-26 18:42:19 +02:00
scale_x = ( double ) * width / scale_width ;
scale_y = ( double ) * height / scale_height ;
src_y = 0.0 ;
for ( y = 0 ; y < scale_height ; y + + ) {
int o ;
src_x = 0.0 ;
2021-12-27 20:02:45 +01:00
o = ( int ) src_y * * width ;
2019-10-26 18:42:19 +02:00
for ( x = 0 ; x < scale_width ; x + + ) {
i = 4 * ( o + ( int ) src_x ) ;
rgb [ n + ( x + y * scale_width ) * 3 + 0 ] = data [ i + 2 ] ;
rgb [ n + ( x + y * scale_width ) * 3 + 1 ] = data [ i + 1 ] ;
rgb [ n + ( x + y * scale_width ) * 3 + 2 ] = data [ i + 0 ] ;
src_x + = scale_x ;
}
src_y + = scale_y ;
}
* width = scale_width ;
* height = scale_height ;
// grabed image of correct size convert BGRA -> RGB
} else {
if ( write_header ) {
n = snprintf ( buf , sizeof ( buf ) , " P6 \n %d \n %d \n 255 \n " , * width , * height ) ;
}
rgb = malloc ( * width * * height * 3 + n ) ;
if ( ! rgb ) {
Error ( _ ( " video: out of memory \n " ) ) ;
free ( data ) ;
return NULL ;
}
2021-12-27 20:02:45 +01:00
memcpy ( rgb , buf , n ) ; // header
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
for ( i = 0 ; i < * size / 4 ; + + i ) { // convert bgra -> rgb
2019-10-26 18:42:19 +02:00
rgb [ n + i * 3 + 0 ] = data [ i * 4 + 2 ] ;
rgb [ n + i * 3 + 1 ] = data [ i * 4 + 1 ] ;
rgb [ n + i * 3 + 2 ] = data [ i * 4 + 0 ] ;
}
* size = * width * * height * 3 + n ;
}
free ( data ) ;
return rgb ;
2018-08-19 11:45:46 +02:00
} else
# endif
{
2019-10-26 18:42:19 +02:00
Warning ( _ ( " softhddev: grab unsupported \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
( void ) size ;
( void ) width ;
( void ) height ;
( void ) write_header ;
return NULL ;
}
///
2019-10-26 18:42:19 +02:00
/// Grab image service.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param size[out] size of allocated image
2019-10-26 18:42:19 +02:00
/// @param width[in,out] width of image
/// @param height[in,out] height of image
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
uint8_t * VideoGrabService ( int * size , int * width , int * height ) {
2019-10-28 21:43:37 +01:00
// Debug(3, "video: grab service\n");
2018-08-19 11:45:46 +02:00
# ifdef USE_GRAB
if ( VideoUsedModule - > GrabOutput ) {
2019-10-26 18:42:19 +02:00
return VideoUsedModule - > GrabOutput ( size , width , height , 0 ) ;
2018-08-19 11:45:46 +02:00
} else
# endif
{
2019-10-26 18:42:19 +02:00
Warning ( _ ( " softhddev: grab unsupported \n " ) ) ;
2018-08-19 11:45:46 +02:00
}
( void ) size ;
( void ) width ;
( void ) height ;
return NULL ;
}
///
2019-10-26 18:42:19 +02:00
/// Get decoder statistics.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param[out] missed missed frames
/// @param[out] duped duped frames
2019-10-26 18:42:19 +02:00
/// @param[out] dropped dropped frames
2021-12-27 20:02:45 +01:00
/// @param[out] count number of decoded frames
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoGetStats ( VideoHwDecoder * hw_decoder , int * missed , int * duped , int * dropped , int * counter , float * frametime ,
int * width , int * height , int * color , int * eotf ) {
2020-04-10 16:17:23 +02:00
VideoUsedModule - > GetStats ( hw_decoder , missed , duped , dropped , counter , frametime , width , height , color , eotf ) ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Get decoder video stream size.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param[out] width video stream width
/// @param[out] height video stream height
2019-10-26 18:42:19 +02:00
/// @param[out] aspect_num video stream aspect numerator
/// @param[out] aspect_den video stream aspect denominator
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoGetVideoSize ( VideoHwDecoder * hw_decoder , int * width , int * height , int * aspect_num , int * aspect_den ) {
2018-08-19 11:45:46 +02:00
* width = 1920 ;
* height = 1080 ;
* aspect_num = 16 ;
* aspect_den = 9 ;
// FIXME: test to check if working, than make module function
if ( VideoUsedModule = = & CuvidModule ) {
2019-10-26 18:42:19 +02:00
* width = hw_decoder - > Cuvid . InputWidth ;
* height = hw_decoder - > Cuvid . InputHeight ;
av_reduce ( aspect_num , aspect_den , hw_decoder - > Cuvid . InputWidth * hw_decoder - > Cuvid . InputAspect . num ,
2021-12-27 20:02:45 +01:00
hw_decoder - > Cuvid . InputHeight * hw_decoder - > Cuvid . InputAspect . den , 1024 * 1024 ) ;
2018-08-19 11:45:46 +02:00
}
}
# ifdef USE_SCREENSAVER
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// DPMS / Screensaver
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Suspend X11 screen saver.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param connection X11 connection to enable/disable screensaver
2019-10-26 18:42:19 +02:00
/// @param suspend True suspend screensaver,
2021-12-27 20:02:45 +01:00
/// false enable screensaver
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void X11SuspendScreenSaver ( xcb_connection_t * connection , int suspend ) {
2018-08-19 11:45:46 +02:00
const xcb_query_extension_reply_t * query_extension_reply ;
2019-10-26 18:42:19 +02:00
query_extension_reply = xcb_get_extension_data ( connection , & xcb_screensaver_id ) ;
2018-08-19 11:45:46 +02:00
if ( query_extension_reply & & query_extension_reply - > present ) {
2019-10-26 18:42:19 +02:00
xcb_screensaver_query_version_cookie_t cookie ;
xcb_screensaver_query_version_reply_t * reply ;
Debug ( 3 , " video: screen saver extension present \n " ) ;
2021-12-27 20:02:45 +01:00
cookie = xcb_screensaver_query_version_unchecked ( connection , XCB_SCREENSAVER_MAJOR_VERSION ,
XCB_SCREENSAVER_MINOR_VERSION ) ;
2019-10-26 18:42:19 +02:00
reply = xcb_screensaver_query_version_reply ( connection , cookie , NULL ) ;
2021-12-27 20:02:45 +01:00
if ( reply & & ( reply - > server_major_version > = XCB_SCREENSAVER_MAJOR_VERSION ) & &
( reply - > server_minor_version > = XCB_SCREENSAVER_MINOR_VERSION ) ) {
2019-10-26 18:42:19 +02:00
xcb_screensaver_suspend ( connection , suspend ) ;
}
free ( reply ) ;
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// DPMS (Display Power Management Signaling) extension available.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param connection X11 connection to check for DPMS
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static int X11HaveDPMS ( xcb_connection_t * connection ) {
2018-08-19 11:45:46 +02:00
static int have_dpms = - 1 ;
const xcb_query_extension_reply_t * query_extension_reply ;
2021-12-27 20:02:45 +01:00
if ( have_dpms ! = - 1 ) { // already checked
2019-10-26 18:42:19 +02:00
return have_dpms ;
2018-08-19 11:45:46 +02:00
}
have_dpms = 0 ;
query_extension_reply = xcb_get_extension_data ( connection , & xcb_dpms_id ) ;
if ( query_extension_reply & & query_extension_reply - > present ) {
2019-10-26 18:42:19 +02:00
xcb_dpms_get_version_cookie_t cookie ;
xcb_dpms_get_version_reply_t * reply ;
int major ;
int minor ;
Debug ( 3 , " video: dpms extension present \n " ) ;
cookie = xcb_dpms_get_version_unchecked ( connection , XCB_DPMS_MAJOR_VERSION , XCB_DPMS_MINOR_VERSION ) ;
reply = xcb_dpms_get_version_reply ( connection , cookie , NULL ) ;
// use locals to avoid gcc warning
major = XCB_DPMS_MAJOR_VERSION ;
minor = XCB_DPMS_MINOR_VERSION ;
2021-12-27 20:02:45 +01:00
if ( reply & & ( reply - > server_major_version > = major ) & & ( reply - > server_minor_version > = minor ) ) {
2019-10-26 18:42:19 +02:00
have_dpms = 1 ;
}
free ( reply ) ;
2018-08-19 11:45:46 +02:00
}
return have_dpms ;
}
///
2019-10-26 18:42:19 +02:00
/// Disable DPMS (Display Power Management Signaling)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param connection X11 connection to disable DPMS
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void X11DPMSDisable ( xcb_connection_t * connection ) {
2018-08-19 11:45:46 +02:00
if ( X11HaveDPMS ( connection ) ) {
2019-10-26 18:42:19 +02:00
xcb_dpms_info_cookie_t cookie ;
xcb_dpms_info_reply_t * reply ;
cookie = xcb_dpms_info_unchecked ( connection ) ;
reply = xcb_dpms_info_reply ( connection , cookie , NULL ) ;
if ( reply ) {
if ( reply - > state ) {
Debug ( 3 , " video: dpms was enabled \n " ) ;
2021-12-27 20:02:45 +01:00
xcb_dpms_disable ( connection ) ; // monitor powersave off
2019-10-26 18:42:19 +02:00
}
free ( reply ) ;
}
DPMSDisabled = 1 ;
2018-08-19 11:45:46 +02:00
}
}
///
2019-10-26 18:42:19 +02:00
/// Reenable DPMS (Display Power Management Signaling)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param connection X11 connection to enable DPMS
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void X11DPMSReenable ( xcb_connection_t * connection ) {
2018-08-19 11:45:46 +02:00
if ( DPMSDisabled & & X11HaveDPMS ( connection ) ) {
2021-12-27 20:02:45 +01:00
xcb_dpms_enable ( connection ) ; // monitor powersave on
2019-10-26 18:42:19 +02:00
xcb_dpms_force_level ( connection , XCB_DPMS_DPMS_MODE_ON ) ;
DPMSDisabled = 0 ;
2018-08-19 11:45:46 +02:00
}
}
# else
2019-10-28 21:43:37 +01:00
/// dummy function: Suspend X11 screen saver.
2018-08-19 11:45:46 +02:00
# define X11SuspendScreenSaver(connection, suspend)
2019-10-28 21:43:37 +01:00
/// dummy function: Disable X11 DPMS.
2018-08-19 11:45:46 +02:00
# define X11DPMSDisable(connection)
2019-10-28 21:43:37 +01:00
/// dummy function: Reenable X11 DPMS.
2018-08-19 11:45:46 +02:00
# define X11DPMSReenable(connection)
# endif
//----------------------------------------------------------------------------
2019-10-26 18:42:19 +02:00
// Setup
2018-08-19 11:45:46 +02:00
//----------------------------------------------------------------------------
///
2019-10-26 18:42:19 +02:00
/// Create main window.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param parent parent of new window
/// @param visual visual of parent
/// @param depth depth of parent
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
static void VideoCreateWindow ( xcb_window_t parent , xcb_visualid_t visual , uint8_t depth ) {
2018-08-19 11:45:46 +02:00
uint32_t values [ 4 ] ;
xcb_intern_atom_reply_t * reply ;
xcb_pixmap_t pixmap ;
xcb_cursor_t cursor ;
Debug ( 3 , " video: visual %#0x depth %d \n " , visual , depth ) ;
// Color map
VideoColormap = xcb_generate_id ( Connection ) ;
2019-10-26 18:42:19 +02:00
xcb_create_colormap ( Connection , XCB_COLORMAP_ALLOC_NONE , VideoColormap , parent , visual ) ;
2018-08-19 11:45:46 +02:00
values [ 0 ] = 0 ;
values [ 1 ] = 0 ;
2021-12-27 20:02:45 +01:00
values [ 2 ] = XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY ;
2018-08-19 11:45:46 +02:00
values [ 3 ] = VideoColormap ;
VideoWindow = xcb_generate_id ( Connection ) ;
2019-10-26 18:42:19 +02:00
xcb_create_window ( Connection , depth , VideoWindow , parent , VideoWindowX , VideoWindowY , VideoWindowWidth ,
2021-12-27 20:02:45 +01:00
VideoWindowHeight , 0 , XCB_WINDOW_CLASS_INPUT_OUTPUT , visual ,
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP , values ) ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " Create Window at %d,%d \n " , VideoWindowX , VideoWindowY ) ;
2018-08-19 11:45:46 +02:00
// define only available with xcb-utils-0.3.8
# ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
// FIXME: utf _NET_WM_NAME
2019-10-26 18:42:19 +02:00
xcb_icccm_set_wm_name ( Connection , VideoWindow , XCB_ATOM_STRING , 8 , sizeof ( " softhdcuvid " ) - 1 , " softhdcuvid " ) ;
xcb_icccm_set_wm_icon_name ( Connection , VideoWindow , XCB_ATOM_STRING , 8 , sizeof ( " softhdcuvid " ) - 1 , " softhdcuvid " ) ;
2018-08-19 11:45:46 +02:00
# endif
// define only available with xcb-utils-0.3.6
# ifdef XCB_NUM_WM_HINTS_ELEMENTS
// FIXME: utf _NET_WM_NAME
2018-09-08 16:53:55 +02:00
xcb_set_wm_name ( Connection , VideoWindow , XCB_ATOM_STRING , sizeof ( " softhdcuvid " ) - 1 , " softhdcuvid " ) ;
xcb_set_wm_icon_name ( Connection , VideoWindow , XCB_ATOM_STRING , sizeof ( " softhdcuvid " ) - 1 , " softhdcuvid " ) ;
2018-08-19 11:45:46 +02:00
# endif
// FIXME: size hints
2018-09-25 16:29:03 +02:00
2018-08-19 11:45:46 +02:00
// register interest in the delete window message
2021-12-27 20:02:45 +01:00
if ( ( reply = xcb_intern_atom_reply (
Connection , xcb_intern_atom ( Connection , 0 , sizeof ( " WM_DELETE_WINDOW " ) - 1 , " WM_DELETE_WINDOW " ) , NULL ) ) ) {
2019-10-26 18:42:19 +02:00
WmDeleteWindowAtom = reply - > atom ;
free ( reply ) ;
2021-12-27 20:02:45 +01:00
if ( ( reply = xcb_intern_atom_reply (
Connection , xcb_intern_atom ( Connection , 0 , sizeof ( " WM_PROTOCOLS " ) - 1 , " WM_PROTOCOLS " ) , NULL ) ) ) {
2018-08-19 11:45:46 +02:00
# ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
2019-10-26 18:42:19 +02:00
xcb_icccm_set_wm_protocols ( Connection , VideoWindow , reply - > atom , 1 , & WmDeleteWindowAtom ) ;
2018-08-19 11:45:46 +02:00
# endif
# ifdef XCB_NUM_WM_HINTS_ELEMENTS
2019-10-26 18:42:19 +02:00
xcb_set_wm_protocols ( Connection , reply - > atom , VideoWindow , 1 , & WmDeleteWindowAtom ) ;
2018-08-19 11:45:46 +02:00
# endif
2019-10-26 18:42:19 +02:00
free ( reply ) ;
}
2018-08-19 11:45:46 +02:00
}
2018-09-25 16:29:03 +02:00
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// prepare fullscreen.
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
if ( ( reply = xcb_intern_atom_reply (
Connection , xcb_intern_atom ( Connection , 0 , sizeof ( " _NET_WM_STATE " ) - 1 , " _NET_WM_STATE " ) , NULL ) ) ) {
2019-10-26 18:42:19 +02:00
NetWmState = reply - > atom ;
free ( reply ) ;
2018-08-19 11:45:46 +02:00
}
2021-12-27 20:02:45 +01:00
if ( ( reply = xcb_intern_atom_reply (
Connection ,
xcb_intern_atom ( Connection , 0 , sizeof ( " _NET_WM_STATE_FULLSCREEN " ) - 1 , " _NET_WM_STATE_FULLSCREEN " ) ,
NULL ) ) ) {
2019-10-26 18:42:19 +02:00
NetWmStateFullscreen = reply - > atom ;
free ( reply ) ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
if ( ( reply = xcb_intern_atom_reply (
Connection , xcb_intern_atom ( Connection , 0 , sizeof ( " _NET_WM_STATE_ABOVE " ) - 1 , " _NET_WM_STATE_ABOVE " ) ,
NULL ) ) ) {
2019-10-26 18:42:19 +02:00
NetWmStateAbove = reply - > atom ;
free ( reply ) ;
2018-12-10 13:10:58 +01:00
}
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
xcb_map_window ( Connection , VideoWindow ) ;
2019-10-26 18:42:19 +02:00
xcb_flush ( Connection ) ;
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// hide cursor
2018-08-19 11:45:46 +02:00
//
pixmap = xcb_generate_id ( Connection ) ;
xcb_create_pixmap ( Connection , 1 , pixmap , parent , 1 , 1 ) ;
cursor = xcb_generate_id ( Connection ) ;
2019-10-26 18:42:19 +02:00
xcb_create_cursor ( Connection , cursor , pixmap , pixmap , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 ) ;
2018-08-19 11:45:46 +02:00
values [ 0 ] = cursor ;
2018-09-08 16:53:55 +02:00
xcb_change_window_attributes ( Connection , VideoWindow , XCB_CW_CURSOR , values ) ;
2018-08-19 11:45:46 +02:00
VideoCursorPixmap = pixmap ;
VideoBlankCursor = cursor ;
VideoBlankTick = 0 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set video device.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Currently this only choose the driver.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetDevice ( const char * device ) { VideoDriverName = device ; }
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
void VideoSetConnector ( char * c ) { DRMConnector = c ; }
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
void VideoSetRefresh ( char * r ) { DRMRefresh = atoi ( r ) ; }
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
int VideoSetShader ( char * s ) {
2020-06-16 07:46:27 +02:00
# if defined PLACEBO && PL_API_VER >= 58
2021-12-27 20:02:45 +01:00
if ( num_shaders = = NUM_SHADERS )
2020-06-07 12:31:18 +02:00
return - 1 ;
2021-12-27 20:02:45 +01:00
p = malloc ( strlen ( s ) + 1 ) ;
memcpy ( p , s , strlen ( s ) + 1 ) ;
2020-06-07 12:31:18 +02:00
shadersp [ num_shaders + + ] = p ;
2021-12-27 20:02:45 +01:00
CuvidMessage ( 2 , " Use Shader %s \n " , s ) ;
2020-06-07 12:31:18 +02:00
return 0 ;
# else
printf ( " Shaders are only support with placebo \n " ) ;
return - 1 ;
# endif
}
2021-12-27 20:02:45 +01:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Get video driver name.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @returns name of current video driver.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
const char * VideoGetDriverName ( void ) {
2018-08-19 11:45:46 +02:00
if ( VideoUsedModule ) {
2019-10-26 18:42:19 +02:00
return VideoUsedModule - > Name ;
2018-08-19 11:45:46 +02:00
}
return " " ;
}
///
2019-10-26 18:42:19 +02:00
/// Set video geometry.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param geometry [=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
int VideoSetGeometry ( const char * geometry ) {
2018-10-16 16:09:37 +02:00
XParseGeometry ( geometry , & VideoWindowX , & VideoWindowY , & VideoWindowWidth , & VideoWindowHeight ) ;
2018-08-19 11:45:46 +02:00
return 0 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set 60hz display mode.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Pull up 50 Hz video for 60 Hz display.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff enable / disable the 60 Hz mode.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSet60HzMode ( int onoff ) { Video60HzMode = onoff ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set soft start audio/video sync.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff enable / disable the soft start sync.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetSoftStartSync ( int onoff ) { VideoSoftStartSync = onoff ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set show black picture during channel switch.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff enable / disable black picture.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetBlackPicture ( int onoff ) { VideoShowBlackPicture = onoff ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set brightness adjustment.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param brightness between -1000and 100.
/// 0 represents no modification
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetBrightness ( int brightness ) { VideoBrightness = ( float ) brightness / 100.0f ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set contrast adjustment.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param contrast between 0 and 100.
2021-12-27 20:02:45 +01:00
/// 1000 represents no modification
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetContrast ( int contrast ) { VideoContrast = ( float ) contrast / 100.0f ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set saturation adjustment.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param saturation between 0 and 100.
/// 100 represents no modification
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetSaturation ( int saturation ) { VideoSaturation = ( float ) saturation / 100.0f ; }
2018-08-19 11:45:46 +02:00
2018-11-17 14:58:25 +01:00
///
2019-10-26 18:42:19 +02:00
/// Set Gamma adjustment.
2018-11-17 14:58:25 +01:00
///
2021-12-27 20:02:45 +01:00
/// @param saturation between 0 and 100.
/// 100 represents no modification
2018-11-17 14:58:25 +01:00
///
2021-12-27 20:02:45 +01:00
void VideoSetGamma ( int gamma ) { VideoGamma = ( float ) gamma / 100.0f ; }
2021-04-16 13:50:45 +02:00
///
/// Set Color Temperature adjustment.
///
/// @param offset between -3500k and 3500k.
2021-12-27 20:02:45 +01:00
/// 100 represents no modification
///
void VideoSetTemperature ( int temp ) { VideoTemperature = ( float ) temp / 35.0f ; }
2021-04-16 13:50:45 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set TargetColorSpace.
2018-11-17 16:32:55 +01:00
///
2019-10-26 18:42:19 +02:00
/// @param TargetColorSpace
2018-11-17 16:32:55 +01:00
///
2021-12-27 20:02:45 +01:00
void VideoSetTargetColor ( int color ) { VulkanTargetColorSpace = color ; }
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set hue adjustment.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hue between -PI*100 and PI*100.
/// 0 represents no modification
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetHue ( int hue ) { VideoHue = ( float ) hue / 100.0f ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set video output position.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param hw_decoder video hardware decoder
/// @param x video output x coordinate OSD relative
/// @param y video output y coordinate OSD relative
2019-10-26 18:42:19 +02:00
/// @param width video output width
/// @param height video output height
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetOutputPosition ( VideoHwDecoder * hw_decoder , int x , int y , int width , int height ) {
2018-08-19 11:45:46 +02:00
if ( ! OsdWidth | | ! OsdHeight ) {
2019-10-26 18:42:19 +02:00
return ;
2018-08-19 11:45:46 +02:00
}
if ( ! width | | ! height ) {
2019-10-26 18:42:19 +02:00
// restore full size
width = VideoWindowWidth ;
height = VideoWindowHeight ;
} else {
// convert OSD coordinates to window coordinates
x = ( x * VideoWindowWidth ) / OsdWidth ;
width = ( width * VideoWindowWidth ) / OsdWidth ;
y = ( y * VideoWindowHeight ) / OsdHeight ;
height = ( height * VideoWindowHeight ) / OsdHeight ;
2018-08-19 11:45:46 +02:00
}
// FIXME: add function to module class
if ( VideoUsedModule = = & CuvidModule ) {
2019-10-26 18:42:19 +02:00
// check values to be able to avoid
// interfering with the video thread if possible
2018-08-19 11:45:46 +02:00
2021-12-27 20:02:45 +01:00
if ( x = = hw_decoder - > Cuvid . VideoX & & y = = hw_decoder - > Cuvid . VideoY & & width = = hw_decoder - > Cuvid . VideoWidth & &
height = = hw_decoder - > Cuvid . VideoHeight ) {
2019-10-26 18:42:19 +02:00
// not necessary...
return ;
}
VideoThreadLock ( ) ;
CuvidSetOutputPosition ( & hw_decoder - > Cuvid , x , y , width , height ) ;
CuvidUpdateOutput ( & hw_decoder - > Cuvid ) ;
VideoThreadUnlock ( ) ;
2018-08-19 11:45:46 +02:00
}
( void ) hw_decoder ;
}
///
2019-10-26 18:42:19 +02:00
/// Set video window position.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param x window x coordinate
/// @param y window y coordinate
2019-10-26 18:42:19 +02:00
/// @param width window width
/// @param height window height
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @note no need to lock, only called from inside the video thread
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetVideoMode ( __attribute__ ( ( unused ) ) int x , __attribute__ ( ( unused ) ) int y , int width , int height ) {
2018-08-19 11:45:46 +02:00
Debug ( 4 , " video: %s %dx%d%+d%+d \n " , __FUNCTION__ , width , height , x , y ) ;
2019-10-26 18:42:19 +02:00
if ( ( unsigned ) width = = VideoWindowWidth & & ( unsigned ) height = = VideoWindowHeight ) {
2021-12-27 20:02:45 +01:00
return ; // same size nothing todo
2018-08-19 11:45:46 +02:00
}
2018-10-25 20:04:35 +02:00
2018-10-12 12:51:52 +02:00
if ( VideoEventCallback ) {
2019-10-26 18:42:19 +02:00
sleep ( 1 ) ;
2018-09-05 20:39:12 +02:00
VideoEventCallback ( ) ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " call back set video mode %d %d \n " , width , height ) ;
}
2018-08-19 11:45:46 +02:00
VideoThreadLock ( ) ;
VideoWindowWidth = width ;
VideoWindowHeight = height ;
2019-10-12 11:14:51 +02:00
# ifdef PLACEBO
2019-10-26 18:42:19 +02:00
VideoSetOsdSize ( width , height ) ;
2020-05-01 12:06:04 +02:00
# ifdef PLACEBO_GL
if ( ! pl_swapchain_resize ( p - > swapchain , & width , & height ) ) {
2021-12-27 20:02:45 +01:00
Fatal ( _ ( " libplacebo: failed initializing swapchain \n " ) ) ;
2020-05-01 12:06:04 +02:00
}
# endif
2019-10-12 11:14:51 +02:00
# endif
2018-08-19 11:45:46 +02:00
VideoUsedModule - > SetVideoMode ( ) ;
VideoThreadUnlock ( ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Set 4:3 video display format.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param format video format (stretch, normal, center cut-out)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSet4to3DisplayFormat ( int format ) {
2018-08-19 11:45:46 +02:00
// convert api to internal format
switch ( format ) {
2021-12-27 20:02:45 +01:00
case - 1 : // rotate settings
2019-10-26 18:42:19 +02:00
format = ( Video4to3ZoomMode + 1 ) % ( VideoCenterCutOut + 1 ) ;
break ;
2021-12-27 20:02:45 +01:00
case 0 : // pan&scan (we have no pan&scan)
2019-10-26 18:42:19 +02:00
format = VideoStretch ;
break ;
2021-12-27 20:02:45 +01:00
case 1 : // letter box
2019-10-26 18:42:19 +02:00
format = VideoNormal ;
break ;
2021-12-27 20:02:45 +01:00
case 2 : // center cut-out
2019-10-26 18:42:19 +02:00
format = VideoCenterCutOut ;
break ;
2018-08-19 11:45:46 +02:00
}
if ( ( unsigned ) format = = Video4to3ZoomMode ) {
2021-12-27 20:02:45 +01:00
return ; // no change, no need to lock
2018-08-19 11:45:46 +02:00
}
VideoOsdExit ( ) ;
// FIXME: must tell VDR that the OsdSize has been changed!
VideoThreadLock ( ) ;
Video4to3ZoomMode = format ;
// FIXME: need only VideoUsedModule->UpdateOutput();
VideoUsedModule - > SetVideoMode ( ) ;
VideoThreadUnlock ( ) ;
VideoOsdInit ( ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Set other video display format.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param format video format (stretch, normal, center cut-out)
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetOtherDisplayFormat ( int format ) {
2018-08-19 11:45:46 +02:00
// convert api to internal format
switch ( format ) {
2021-12-27 20:02:45 +01:00
case - 1 : // rotate settings
2019-10-26 18:42:19 +02:00
format = ( VideoOtherZoomMode + 1 ) % ( VideoCenterCutOut + 1 ) ;
break ;
2021-12-27 20:02:45 +01:00
case 0 : // pan&scan (we have no pan&scan)
2019-10-26 18:42:19 +02:00
format = VideoStretch ;
break ;
2021-12-27 20:02:45 +01:00
case 1 : // letter box
2019-10-26 18:42:19 +02:00
format = VideoNormal ;
break ;
2021-12-27 20:02:45 +01:00
case 2 : // center cut-out
2019-10-26 18:42:19 +02:00
format = VideoCenterCutOut ;
break ;
2018-08-19 11:45:46 +02:00
}
if ( ( unsigned ) format = = VideoOtherZoomMode ) {
2021-12-27 20:02:45 +01:00
return ; // no change, no need to lock
2018-08-19 11:45:46 +02:00
}
VideoOsdExit ( ) ;
// FIXME: must tell VDR that the OsdSize has been changed!
VideoThreadLock ( ) ;
VideoOtherZoomMode = format ;
// FIXME: need only VideoUsedModule->UpdateOutput();
VideoUsedModule - > SetVideoMode ( ) ;
VideoThreadUnlock ( ) ;
VideoOsdInit ( ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Send fullscreen message to window.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff -1 toggle, true turn on, false turn off
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetFullscreen ( int onoff ) {
if ( XlibDisplay ) { // needs running connection
2019-10-26 18:42:19 +02:00
xcb_client_message_event_t event ;
memset ( & event , 0 , sizeof ( event ) ) ;
event . response_type = XCB_CLIENT_MESSAGE ;
event . format = 32 ;
event . window = VideoWindow ;
event . type = NetWmState ;
if ( onoff < 0 ) {
event . data . data32 [ 0 ] = XCB_EWMH_WM_STATE_TOGGLE ;
} else if ( onoff ) {
event . data . data32 [ 0 ] = XCB_EWMH_WM_STATE_ADD ;
} else {
event . data . data32 [ 0 ] = XCB_EWMH_WM_STATE_REMOVE ;
}
event . data . data32 [ 1 ] = NetWmStateFullscreen ;
event . data . data32 [ 2 ] = NetWmStateAbove ;
xcb_send_event ( Connection , XCB_SEND_EVENT_DEST_POINTER_WINDOW , DefaultRootWindow ( XlibDisplay ) ,
2021-12-27 20:02:45 +01:00
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT , ( void * ) & event ) ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/x11: send fullscreen message %x %x \n " , event . data . data32 [ 0 ] , event . data . data32 [ 1 ] ) ;
2018-08-19 11:45:46 +02:00
}
}
2021-12-27 20:02:45 +01:00
void VideoSetAbove ( ) {
if ( XlibDisplay ) { // needs running connection
2019-10-26 18:42:19 +02:00
xcb_client_message_event_t event ;
2018-12-10 13:10:58 +01:00
2019-10-26 18:42:19 +02:00
memset ( & event , 0 , sizeof ( event ) ) ;
event . response_type = XCB_CLIENT_MESSAGE ;
event . format = 32 ;
event . window = VideoWindow ;
event . type = NetWmState ;
event . data . data32 [ 0 ] = XCB_EWMH_WM_STATE_ADD ;
event . data . data32 [ 1 ] = NetWmStateAbove ;
2018-12-10 13:10:58 +01:00
2019-10-26 18:42:19 +02:00
xcb_send_event ( Connection , XCB_SEND_EVENT_DEST_POINTER_WINDOW , DefaultRootWindow ( XlibDisplay ) ,
2021-12-27 20:02:45 +01:00
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT , ( void * ) & event ) ;
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video/x11: send fullscreen message %x %x \n " , event . data . data32 [ 0 ] , event . data . data32 [ 1 ] ) ;
2018-12-10 13:10:58 +01:00
}
}
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set deinterlace mode.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetDeinterlace ( int mode [ VideoResolutionMax ] ) {
2020-01-13 18:17:07 +01:00
# ifdef CUVID
2021-12-27 20:02:45 +01:00
VideoDeinterlace [ 0 ] = mode [ 0 ] ; // 576i
VideoDeinterlace [ 1 ] = 1 ; // mode[1]; // 720p
VideoDeinterlace [ 2 ] = mode [ 2 ] ; // fake 1080
VideoDeinterlace [ 3 ] = mode [ 3 ] ; // 1080
VideoDeinterlace [ 4 ] = 1 ; // mode[4]; 2160p
2020-01-13 18:17:07 +01:00
# else
2021-12-27 20:02:45 +01:00
VideoDeinterlace [ 0 ] = 1 ; // 576i
VideoDeinterlace [ 1 ] = 0 ; // mode[1]; // 720p
VideoDeinterlace [ 2 ] = 1 ; // fake 1080
VideoDeinterlace [ 3 ] = 1 ; // 1080
VideoDeinterlace [ 4 ] = 0 ; // mode[4]; 2160p
2020-01-13 18:17:07 +01:00
# endif
2020-04-13 18:04:57 +02:00
VideoSurfaceModesChanged = 1 ;
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Set skip chroma deinterlace on/off.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetSkipChromaDeinterlace ( int onoff [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoSkipChromaDeinterlace [ 0 ] = onoff [ 0 ] ;
VideoSkipChromaDeinterlace [ 1 ] = onoff [ 1 ] ;
VideoSkipChromaDeinterlace [ 2 ] = onoff [ 2 ] ;
VideoSkipChromaDeinterlace [ 3 ] = onoff [ 3 ] ;
VideoSkipChromaDeinterlace [ 4 ] = onoff [ 4 ] ;
VideoSurfaceModesChanged = 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set inverse telecine on/off.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetInverseTelecine ( int onoff [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoInverseTelecine [ 0 ] = onoff [ 0 ] ;
VideoInverseTelecine [ 1 ] = onoff [ 1 ] ;
VideoInverseTelecine [ 2 ] = onoff [ 2 ] ;
VideoInverseTelecine [ 3 ] = onoff [ 3 ] ;
VideoInverseTelecine [ 4 ] = onoff [ 4 ] ;
VideoSurfaceModesChanged = 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set denoise level (0 .. 1000).
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetDenoise ( int level [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoDenoise [ 0 ] = level [ 0 ] ;
VideoDenoise [ 1 ] = level [ 1 ] ;
VideoDenoise [ 2 ] = level [ 2 ] ;
VideoDenoise [ 3 ] = level [ 3 ] ;
VideoDenoise [ 4 ] = level [ 4 ] ;
VideoSurfaceModesChanged = 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set sharpness level (-1000 .. 1000).
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetSharpen ( int level [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoSharpen [ 0 ] = level [ 0 ] ;
VideoSharpen [ 1 ] = level [ 1 ] ;
VideoSharpen [ 2 ] = level [ 2 ] ;
VideoSharpen [ 3 ] = level [ 3 ] ;
VideoSharpen [ 4 ] = level [ 4 ] ;
VideoSurfaceModesChanged = 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set scaling mode.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param mode table with VideoResolutionMax values
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetScaling ( int mode [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoScaling [ 0 ] = mode [ 0 ] ;
VideoScaling [ 1 ] = mode [ 1 ] ;
VideoScaling [ 2 ] = mode [ 2 ] ;
VideoScaling [ 3 ] = mode [ 3 ] ;
VideoScaling [ 4 ] = mode [ 4 ] ;
VideoSurfaceModesChanged = 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Set cut top and bottom.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param pixels table with VideoResolutionMax values
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetCutTopBottom ( int pixels [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoCutTopBottom [ 0 ] = pixels [ 0 ] ;
VideoCutTopBottom [ 1 ] = pixels [ 1 ] ;
VideoCutTopBottom [ 2 ] = pixels [ 2 ] ;
VideoCutTopBottom [ 3 ] = pixels [ 3 ] ;
VideoCutTopBottom [ 4 ] = pixels [ 4 ] ;
// FIXME: update output
}
///
2019-10-26 18:42:19 +02:00
/// Set cut left and right.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param pixels table with VideoResolutionMax values
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetCutLeftRight ( int pixels [ VideoResolutionMax ] ) {
2018-08-19 11:45:46 +02:00
VideoCutLeftRight [ 0 ] = pixels [ 0 ] ;
VideoCutLeftRight [ 1 ] = pixels [ 1 ] ;
VideoCutLeftRight [ 2 ] = pixels [ 2 ] ;
VideoCutLeftRight [ 3 ] = pixels [ 3 ] ;
VideoCutLeftRight [ 4 ] = pixels [ 4 ] ;
// FIXME: update output
}
///
2019-10-26 18:42:19 +02:00
/// Set studio levels.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff flag on/off
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetStudioLevels ( int onoff ) {
2018-08-19 11:45:46 +02:00
VideoStudioLevels = onoff ;
2020-03-04 16:34:40 +01:00
# ifdef GAMMA
2020-04-10 16:17:23 +02:00
Set_Gamma ( 2.4 , 6500 ) ;
2020-03-04 16:34:40 +01:00
# endif
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
2018-12-07 13:07:50 +01:00
///
2019-10-26 18:42:19 +02:00
/// Set scaler test.
2018-12-07 13:07:50 +01:00
///
2019-10-26 18:42:19 +02:00
/// @param onoff flag on/off
2018-12-07 13:07:50 +01:00
///
2021-12-27 20:02:45 +01:00
void VideoSetScalerTest ( int onoff ) {
2018-12-07 13:07:50 +01:00
VideoScalerTest = onoff ;
2019-10-26 18:42:19 +02:00
VideoSurfaceModesChanged = 1 ;
2018-12-07 13:07:50 +01:00
}
2019-10-26 18:42:19 +02:00
2021-12-27 20:02:45 +01:00
void ToggleLUT ( ) { LUTon ^ = - 1 ; }
///
2019-10-26 18:42:19 +02:00
/// Set Color Blindness.
2018-12-07 13:07:50 +01:00
///
2021-12-27 20:02:45 +01:00
void VideoSetColorBlindness ( int value ) {
VideoColorBlindness = value ;
;
2018-12-07 13:07:50 +01:00
}
2019-10-26 18:42:19 +02:00
2018-12-07 13:07:50 +01:00
///
2019-10-26 18:42:19 +02:00
/// Set Color Blindness Faktor.
2018-12-07 13:07:50 +01:00
///
2021-12-27 20:02:45 +01:00
void VideoSetColorBlindnessFaktor ( int value ) { VideoColorBlindnessFaktor = ( float ) value / 100.0f + 1.0f ; }
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set background color.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param rgba 32 bit RGBA color.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetBackground ( uint32_t rgba ) {
VideoBackground = rgba ; // saved for later start
2018-08-19 11:45:46 +02:00
VideoUsedModule - > SetBackground ( rgba ) ;
}
///
2019-10-26 18:42:19 +02:00
/// Set audio delay.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
/// @param ms delay in ms
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoSetAudioDelay ( int ms ) { VideoAudioDelay = ms * 90 ; }
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Set EnableDPMSatBlackScreen
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// Currently this only choose the driver.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void SetDPMSatBlackScreen ( int enable ) {
2018-08-19 11:45:46 +02:00
# ifdef USE_SCREENSAVER
EnableDPMSatBlackScreen = enable ;
# endif
}
///
2019-10-26 18:42:19 +02:00
/// Raise video window.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
int VideoRaiseWindow ( void ) {
static const uint32_t values [ ] = { XCB_STACK_MODE_ABOVE } ;
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
xcb_configure_window ( Connection , VideoWindow , XCB_CONFIG_WINDOW_STACK_MODE , values ) ;
2018-08-19 11:45:46 +02:00
return 1 ;
}
///
2019-10-26 18:42:19 +02:00
/// Initialize video output module.
2018-08-19 11:45:46 +02:00
///
2019-10-26 18:42:19 +02:00
/// @param display_name X11 display name
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoInit ( const char * display_name ) {
2018-08-19 11:45:46 +02:00
int screen_nr ;
int i ;
xcb_screen_iterator_t screen_iter ;
xcb_screen_t const * screen ;
2019-12-10 10:45:22 +01:00
# ifdef USE_DRM
VideoInitDrm ( ) ;
# else
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
if ( XlibDisplay ) { // allow multiple calls
2019-10-26 18:42:19 +02:00
Debug ( 3 , " video: x11 already setup \n " ) ;
return ;
2018-08-19 11:45:46 +02:00
}
2018-09-09 17:43:34 +02:00
# ifdef USE_GLX
if ( ! XInitThreads ( ) ) {
2019-10-26 18:42:19 +02:00
Error ( _ ( " video: Can't initialize X11 thread support on '%s' \n " ) , display_name ) ;
}
2018-09-09 17:43:34 +02:00
# endif
2018-08-19 11:45:46 +02:00
// Open the connection to the X server.
// use the DISPLAY environment variable as the default display name
if ( ! display_name & & ! ( display_name = getenv ( " DISPLAY " ) ) ) {
2019-10-26 18:42:19 +02:00
// if no environment variable, use :0.0 as default display name
display_name = " :0.0 " ;
2022-05-16 15:13:00 +02:00
}
if ( ! getenv ( " DISPLAY " ) ) {
2022-05-24 00:09:55 +02:00
// force set DISPLAY environment variable, otherwise nvidia driver
// has problems at libplace-swapchain-init
Debug ( 3 , " video: setting ENV DISPLAY=%s \n " , display_name ) ;
setenv ( " DISPLAY " , display_name , 0 ) ;
// Debug(3, "video: ENV:(%s)\n",getenv("DISPLAY"));
2018-08-19 11:45:46 +02:00
}
2018-11-24 09:34:55 +01:00
2018-08-19 11:45:46 +02:00
if ( ! ( XlibDisplay = XOpenDisplay ( display_name ) ) ) {
2019-10-26 18:42:19 +02:00
Error ( _ ( " video: Can't connect to X11 server on '%s' \n " ) , display_name ) ;
// FIXME: we need to retry connection
return ;
2018-08-19 11:45:46 +02:00
}
2018-09-09 17:43:34 +02:00
2018-08-19 11:45:46 +02:00
// Register error handler
XSetIOErrorHandler ( VideoIOErrorHandler ) ;
// Convert XLIB display to XCB connection
if ( ! ( Connection = XGetXCBConnection ( XlibDisplay ) ) ) {
2019-10-26 18:42:19 +02:00
Error ( _ ( " video: Can't convert XLIB display to XCB connection \n " ) ) ;
VideoExit ( ) ;
return ;
2018-08-19 11:45:46 +02:00
}
// prefetch extensions
2019-10-28 21:43:37 +01:00
// xcb_prefetch_extension_data(Connection, &xcb_big_requests_id);
2018-08-19 11:45:46 +02:00
# ifdef xcb_USE_GLX
xcb_prefetch_extension_data ( Connection , & xcb_glx_id ) ;
# endif
2021-12-27 20:02:45 +01:00
// xcb_prefetch_extension_data(Connection, &xcb_randr_id);
2018-08-19 11:45:46 +02:00
# ifdef USE_SCREENSAVER
xcb_prefetch_extension_data ( Connection , & xcb_screensaver_id ) ;
xcb_prefetch_extension_data ( Connection , & xcb_dpms_id ) ;
# endif
2021-12-27 20:02:45 +01:00
// xcb_prefetch_extension_data(Connection, &xcb_shm_id);
// xcb_prefetch_extension_data(Connection, &xcb_xv_id);
2018-08-19 11:45:46 +02:00
// Get the requested screen number
screen_nr = DefaultScreen ( XlibDisplay ) ;
screen_iter = xcb_setup_roots_iterator ( xcb_get_setup ( Connection ) ) ;
for ( i = 0 ; i < screen_nr ; + + i ) {
2019-10-26 18:42:19 +02:00
xcb_screen_next ( & screen_iter ) ;
2018-08-19 11:45:46 +02:00
}
screen = screen_iter . data ;
VideoScreen = screen ;
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// Default window size
2018-08-19 11:45:46 +02:00
//
if ( ! VideoWindowHeight ) {
2019-10-26 18:42:19 +02:00
if ( VideoWindowWidth ) {
VideoWindowHeight = ( VideoWindowWidth * 9 ) / 16 ;
2021-12-27 20:02:45 +01:00
} else { // default to fullscreen
2019-10-26 18:42:19 +02:00
VideoWindowHeight = screen - > height_in_pixels ;
VideoWindowWidth = screen - > width_in_pixels ;
//***********************************************************************************************
2018-09-28 17:02:56 +02:00
# if DEBUG_no
2019-10-26 18:42:19 +02:00
if ( strcmp ( " :0.0 " , display_name ) = = 0 ) {
VideoWindowHeight = 1080 ;
VideoWindowWidth = 1920 ;
}
2018-09-08 16:53:55 +02:00
# endif
2019-10-26 18:42:19 +02:00
}
2018-08-19 11:45:46 +02:00
}
if ( ! VideoWindowWidth ) {
2019-10-26 18:42:19 +02:00
VideoWindowWidth = ( VideoWindowHeight * 16 ) / 9 ;
2018-08-19 11:45:46 +02:00
}
2019-10-26 18:42:19 +02:00
//
// Create output window
//
2018-08-19 11:45:46 +02:00
2019-10-26 18:42:19 +02:00
VideoCreateWindow ( screen - > root , screen - > root_visual , screen - > root_depth ) ;
2018-08-19 11:45:46 +02:00
Debug ( 3 , " video: window prepared \n " ) ;
2019-12-10 10:45:22 +01:00
# endif
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// prepare hardware decoder
2018-08-19 11:45:46 +02:00
//
for ( i = 0 ; i < ( int ) ( sizeof ( VideoModules ) / sizeof ( * VideoModules ) ) ; + + i ) {
2019-10-26 18:42:19 +02:00
// FIXME: support list of drivers and include display name
// use user device or first working enabled device driver
2021-12-27 20:02:45 +01:00
if ( ( VideoDriverName & & ! strcasecmp ( VideoDriverName , VideoModules [ i ] - > Name ) ) | |
( ! VideoDriverName & & VideoModules [ i ] - > Enabled ) ) {
2019-10-26 18:42:19 +02:00
if ( VideoModules [ i ] - > Init ( display_name ) ) {
VideoUsedModule = VideoModules [ i ] ;
goto found ;
}
}
2018-08-19 11:45:46 +02:00
}
Error ( _ ( " video: '%s' output module isn't supported \n " ) , VideoDriverName ) ;
VideoUsedModule = & NoopModule ;
2021-12-27 20:02:45 +01:00
found : ;
2019-12-10 10:45:22 +01:00
# ifndef USE_DRM
2018-08-19 11:45:46 +02:00
// FIXME: make it configurable from gui
if ( getenv ( " NO_MPEG_HW " ) ) {
2019-10-26 18:42:19 +02:00
VideoHardwareDecoder = 1 ;
2018-08-19 11:45:46 +02:00
}
if ( getenv ( " NO_HW " ) ) {
2019-10-26 18:42:19 +02:00
VideoHardwareDecoder = 0 ;
2018-08-19 11:45:46 +02:00
}
// disable x11 screensaver
X11SuspendScreenSaver ( Connection , 1 ) ;
X11DPMSDisable ( Connection ) ;
2021-12-27 20:02:45 +01:00
// xcb_prefetch_maximum_request_length(Connection);
2018-08-19 11:45:46 +02:00
xcb_flush ( Connection ) ;
2019-12-10 10:45:22 +01:00
# endif
2021-01-10 13:55:09 +01:00
# ifdef PLACEBO_NOT
2019-10-26 18:42:19 +02:00
InitPlacebo ( ) ;
2018-11-24 09:34:55 +01:00
# endif
2018-08-19 11:45:46 +02:00
}
///
2019-10-26 18:42:19 +02:00
/// Cleanup video output module.
2018-08-19 11:45:46 +02:00
///
2021-12-27 20:02:45 +01:00
void VideoExit ( void ) {
2020-04-10 16:17:23 +02:00
Debug ( 3 , " Video Exit \n " ) ;
2019-12-10 10:45:22 +01:00
# ifndef USE_DRM
2021-12-27 20:02:45 +01:00
if ( ! XlibDisplay ) { // no init or failed
2019-10-26 18:42:19 +02:00
return ;
2018-08-19 11:45:46 +02:00
}
2020-01-07 22:22:07 +01:00
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// Reenable screensaver / DPMS.
2018-08-19 11:45:46 +02:00
//
X11DPMSReenable ( Connection ) ;
X11SuspendScreenSaver ( Connection , 0 ) ;
2019-12-10 10:45:22 +01:00
# endif
2018-08-19 11:45:46 +02:00
VideoUsedModule - > Exit ( ) ;
VideoUsedModule = & NoopModule ;
2018-08-22 21:04:52 +02:00
2018-08-19 11:45:46 +02:00
# ifdef USE_VIDEO_THREAD
2021-12-27 20:02:45 +01:00
VideoThreadExit ( ) ; // destroy all mutexes
2018-08-22 21:04:52 +02:00
# endif
2019-10-04 10:37:57 +02:00
2018-08-22 21:04:52 +02:00
# ifdef USE_GLX
2019-10-04 10:37:57 +02:00
if ( EglEnabled ) {
2021-12-27 20:02:45 +01:00
EglExit ( ) ; // delete all contexts
2018-08-22 21:04:52 +02:00
}
2018-08-19 11:45:46 +02:00
# endif
2019-12-10 10:45:22 +01:00
# ifndef USE_DRM
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// FIXME: cleanup.
2018-08-19 11:45:46 +02:00
//
2019-10-28 21:43:37 +01:00
// RandrExit();
2019-10-26 18:42:19 +02:00
2018-08-19 11:45:46 +02:00
//
2021-12-27 20:02:45 +01:00
// X11/xcb cleanup
2018-08-19 11:45:46 +02:00
//
2019-10-26 18:42:19 +02:00
if ( VideoWindow ! = XCB_NONE ) {
xcb_destroy_window ( Connection , VideoWindow ) ;
VideoWindow = XCB_NONE ;
2018-08-19 11:45:46 +02:00
}
if ( VideoColormap ! = XCB_NONE ) {
2019-10-26 18:42:19 +02:00
xcb_free_colormap ( Connection , VideoColormap ) ;
VideoColormap = XCB_NONE ;
2018-08-19 11:45:46 +02:00
}
if ( VideoBlankCursor ! = XCB_NONE ) {
2019-10-26 18:42:19 +02:00
xcb_free_cursor ( Connection , VideoBlankCursor ) ;
VideoBlankCursor = XCB_NONE ;
2018-08-19 11:45:46 +02:00
}
if ( VideoCursorPixmap ! = XCB_NONE ) {
2019-10-26 18:42:19 +02:00
xcb_free_pixmap ( Connection , VideoCursorPixmap ) ;
VideoCursorPixmap = XCB_NONE ;
2018-08-19 11:45:46 +02:00
}
xcb_flush ( Connection ) ;
if ( XlibDisplay ) {
2019-10-26 18:42:19 +02:00
if ( XCloseDisplay ( XlibDisplay ) ) {
Error ( _ ( " video: error closing display \n " ) ) ;
}
XlibDisplay = NULL ;
Connection = 0 ;
2018-08-19 11:45:46 +02:00
}
2019-12-10 10:45:22 +01:00
# endif
2018-08-19 11:45:46 +02:00
}
2020-04-10 16:17:23 +02:00
# ifdef USE_DRM
2021-12-27 20:02:45 +01:00
int GlxInitopengl ( ) {
EGLint contextAttrs [ ] = { EGL_CONTEXT_CLIENT_VERSION , 3 , EGL_NONE } ;
2020-04-10 16:17:23 +02:00
while ( ! eglSharedContext )
sleep ( 1 ) ;
2019-10-26 18:42:19 +02:00
2019-12-10 10:45:22 +01:00
if ( ! eglOSDContext ) {
eglOSDContext = eglCreateContext ( eglDisplay , eglConfig , eglSharedContext , contextAttrs ) ;
if ( ! eglOSDContext ) {
2020-04-10 16:17:23 +02:00
EglCheck ( ) ;
Fatal ( _ ( " video/egl: can't create thread egl context \n " ) ) ;
2023-07-14 09:13:09 +02:00
return 1 ;
2020-04-10 16:17:23 +02:00
}
2019-10-26 18:42:19 +02:00
}
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglOSDContext ) ;
2023-07-14 09:13:09 +02:00
return 0 ;
2019-12-10 10:45:22 +01:00
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
int GlxDrawopengl ( ) {
2019-12-10 10:45:22 +01:00
eglMakeCurrent ( eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , eglSharedContext ) ;
2023-07-14 09:13:09 +02:00
return 0 ;
2019-12-10 10:45:22 +01:00
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
void GlxDestroy ( ) {
2020-04-10 16:17:23 +02:00
eglDestroyContext ( eglDisplay , eglOSDContext ) ;
eglOSDContext = NULL ;
2020-01-13 18:17:07 +01:00
}
2018-09-29 15:57:27 +02:00
# endif
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
#if 0 // for debug only
2020-04-10 16:17:23 +02:00
# include <sys/stat.h>
2020-03-26 12:36:00 +01:00
extern uint8_t * CreateJpeg ( uint8_t * , int * , int , int , int ) ;
2020-04-10 16:17:23 +02:00
void makejpg ( uint8_t * data , int width , int height )
{
static int count = 0 ;
int i , n = 0 , gpu = 0 ; ;
char buf [ 32 ] , FileName [ 32 ] ;
uint8_t * rgb ;
2020-03-26 12:36:00 +01:00
uint8_t * jpg_image ;
2020-04-10 16:17:23 +02:00
int size , size1 ;
2020-03-26 12:36:00 +01:00
if ( data = = NULL ) {
2021-12-27 20:02:45 +01:00
data = malloc ( width * height * 4 ) ;
gpu = 1 ;
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
glReadPixels ( 0 , 0 , width , height , GL_BGRA , GL_UNSIGNED_BYTE , data ) ;
2020-03-26 12:36:00 +01:00
}
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
// n = snprintf(buf, sizeof(buf), "P6\n%d\n%d\n255\n", width, height);
2020-04-10 16:17:23 +02:00
sprintf ( FileName , " /tmp/test%d.jpg " , count + + ) ;
rgb = malloc ( width * height * 3 + n ) ;
if ( ! rgb ) {
2021-12-27 20:02:45 +01:00
printf ( " Unable to get RGB Memory \n " ) ;
return ;
2020-04-10 16:17:23 +02:00
}
2021-12-27 20:02:45 +01:00
// memcpy(rgb, buf, n); // header
2020-03-26 12:36:00 +01:00
size = width * height * 4 ;
2020-04-10 16:17:23 +02:00
2021-12-27 20:02:45 +01:00
for ( i = 0 ; i < size / 4 ; + + i ) { // convert bgra -> rgb
rgb [ n + i * 3 + 0 ] = data [ i * 4 + 2 ] ;
rgb [ n + i * 3 + 1 ] = data [ i * 4 + 1 ] ;
rgb [ n + i * 3 + 2 ] = data [ i * 4 + 0 ] ;
2020-04-10 16:17:23 +02:00
}
2018-08-19 11:45:46 +02:00
2020-03-26 12:36:00 +01:00
if ( gpu )
2021-12-27 20:02:45 +01:00
free ( data ) ;
2020-04-10 16:17:23 +02:00
2020-03-26 12:36:00 +01:00
jpg_image = CreateJpeg ( rgb , & size1 , 90 , width , height ) ;
2020-04-10 16:17:23 +02:00
int fd = open ( FileName , O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC , DEFFILEMODE ) ;
write ( fd , jpg_image , size1 ) ;
close ( fd ) ;
free ( rgb ) ;
2020-03-26 12:36:00 +01:00
}
2020-04-10 16:17:23 +02:00
# endif