Merge remote-tracking branch 'origin/grabberDiscovery' into mediafoundation

This commit is contained in:
Paulchen Panther
2021-04-04 12:43:29 +02:00
committed by LordGrey
187 changed files with 3716 additions and 15430 deletions

View File

@@ -4,9 +4,15 @@
#include <xcb/randr.h>
#include <xcb/xcb_event.h>
// Constants
namespace {
const bool verbose = false;
} //End of constants
X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation)
: Grabber("X11GRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
, _x11Display(nullptr)
, _xImage(nullptr)
, _pixmap(None)
, _srcFormat(nullptr)
, _dstFormat(nullptr)
@@ -17,8 +23,15 @@ X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom,
, _calculatedHeight(0)
, _src_x(cropLeft)
, _src_y(cropTop)
, _XShmAvailable(false)
, _XRenderAvailable(false)
, _XRandRAvailable(false)
, _isWayland (false)
, _logger{}
, _image(0,0)
{
_logger = Logger::getInstance("X11");
_useImageResampler = false;
_imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XRender, XShmGetImage or XGetImage
memset(&_pictAttr, 0, sizeof(_pictAttr));
@@ -37,7 +50,10 @@ X11Grabber::~X11Grabber()
void X11Grabber::freeResources()
{
// Cleanup allocated resources of the X11 grab
XDestroyImage(_xImage);
if (_xImage != nullptr)
{
XDestroyImage(_xImage);
}
if (_XRandRAvailable)
{
qApp->removeNativeEventFilter(this);
@@ -100,39 +116,72 @@ void X11Grabber::setupResources()
_imageResampler.setHorizontalPixelDecimation(_pixelDecimation);
_imageResampler.setVerticalPixelDecimation(_pixelDecimation);
}
}
bool X11Grabber::Setup()
bool X11Grabber::open()
{
_x11Display = XOpenDisplay(NULL);
if (_x11Display == nullptr)
bool rc = false;
if (getenv("WAYLAND_DISPLAY") != nullptr)
{
Error(_log, "Unable to open display");
if (getenv("DISPLAY"))
_isWayland = true;
}
else
{
_x11Display = XOpenDisplay(nullptr);
if (_x11Display != nullptr)
{
Error(_log, "%s",getenv("DISPLAY"));
rc = true;
}
}
return rc;
}
bool X11Grabber::setupDisplay()
{
bool result = false;
if ( ! open() )
{
if ( _isWayland )
{
Error(_log, "Grabber does not work under Wayland!");
}
else
{
Error(_log, "DISPLAY environment variable not set");
if (getenv("DISPLAY") != nullptr)
{
Error(_log, "Unable to open display [%s]",getenv("DISPLAY"));
}
else
{
Error(_log, "DISPLAY environment variable not set");
}
}
return false;
}
else
{
_window = DefaultRootWindow(_x11Display);
_window = DefaultRootWindow(_x11Display);
int dummy, pixmaps_supported;
int dummy, pixmaps_supported;
_XRandRAvailable = XRRQueryExtension(_x11Display, &_XRandREventBase, &dummy);
_XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy);
_XShmAvailable = XShmQueryExtension(_x11Display);
XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported);
_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap;
_XRandRAvailable = XRRQueryExtension(_x11Display, &_XRandREventBase, &dummy);
_XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy);
_XShmAvailable = XShmQueryExtension(_x11Display);
XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported);
_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap;
Info(_log, QString("XRandR=[%1] XRender=[%2] XShm=[%3] XPixmap=[%4]")
.arg(_XRandRAvailable ? "available" : "unavailable")
.arg(_XRenderAvailable ? "available" : "unavailable")
.arg(_XShmAvailable ? "available" : "unavailable")
.arg(_XShmPixmapAvailable ? "available" : "unavailable")
.toStdString().c_str());
bool result = (updateScreenDimensions(true) >=0);
ErrorIf(!result, _log, "X11 Grabber start failed");
setEnabled(result);
result = (updateScreenDimensions(true) >=0);
ErrorIf(!result, _log, "X11 Grabber start failed");
setEnabled(result);
}
return result;
}
@@ -235,7 +284,8 @@ int X11Grabber::updateScreenDimensions(bool force)
_width = _windowAttr.width;
_height = _windowAttr.height;
int width=0, height=0;
int width=0;
int height=0;
// Image scaling is performed by XRender when available, otherwise by ImageResampler
if (_XRenderAvailable)
@@ -301,19 +351,24 @@ void X11Grabber::setVideoMode(VideoMode mode)
updateScreenDimensions(true);
}
void X11Grabber::setPixelDecimation(int pixelDecimation)
bool X11Grabber::setPixelDecimation(int pixelDecimation)
{
if(_pixelDecimation != pixelDecimation)
if(Grabber::setPixelDecimation(pixelDecimation))
{
_pixelDecimation = pixelDecimation;
updateScreenDimensions(true);
return true;
}
return false;
}
void X11Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
{
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
if(_x11Display != nullptr) updateScreenDimensions(true); // segfault on init
if(_x11Display != nullptr)
{
updateScreenDimensions(true); // segfault on init
}
}
bool X11Grabber::nativeEventFilter(const QByteArray & eventType, void * message, long int * /*result*/)
@@ -332,3 +387,78 @@ bool X11Grabber::nativeEventFilter(const QByteArray & eventType, void * message,
return false;
}
QJsonObject X11Grabber::discover(const QJsonObject& params)
{
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
QJsonObject inputsDiscovered;
if ( open() )
{
inputsDiscovered["device"] = "x11";
inputsDiscovered["device_name"] = "X11";
inputsDiscovered["type"] = "screen";
QJsonArray video_inputs;
if (_x11Display != nullptr)
{
QJsonArray fps = { 1, 5, 10, 15, 20, 25, 30, 40, 50, 60 };
// Iterate through all X screens
for (int i = 0; i < XScreenCount(_x11Display); ++i)
{
_window = DefaultRootWindow(_x11Display);
const Status status = XGetWindowAttributes(_x11Display, _window, &_windowAttr);
if (status == 0)
{
Debug(_log, "Failed to obtain window attributes");
}
else
{
QJsonObject in;
QString displayName;
char* name;
if ( XFetchName(_x11Display, _window, &name) > 0 )
{
displayName = name;
}
else {
displayName = QString("Display:%1").arg(i);
}
in["name"] = displayName;
in["inputIdx"] = i;
QJsonArray formats;
QJsonArray resolutionArray;
QJsonObject format;
QJsonObject resolution;
resolution["width"] = _windowAttr.width;
resolution["height"] = _windowAttr.height;
resolution["fps"] = fps;
resolutionArray.append(resolution);
format["resolutions"] = resolutionArray;
formats.append(format);
in["formats"] = formats;
video_inputs.append(in);
}
}
if ( !video_inputs.isEmpty() )
{
inputsDiscovered["video_inputs"] = video_inputs;
}
}
}
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
return inputsDiscovered;
}