我正在尝试制作一个跨平台应用程序来测量 FPS。在 Windows 中它可以工作,但在仅使用 QT 的 Macos 中,我无法捕获该区域的其他应用程序。所以我使用 CoreGraphics for Mac 但我仍然遇到同样的问题。
这是我捕获屏幕的代码。
#include "framecounter.h"
#include <QtGui/QGuiApplication>
#include <QDir>
FrameCounter::FrameCounter(QWidget* parent) : QWidget(parent)
{
// Connect the captureTimer's timeout signal to the captureScreen slot.
connect(&m_captureTimer, &QTimer::timeout, this, &FrameCounter::captureScreen);
m_elapsedTimer.start(); // Start the elapsed timer.
}
void FrameCounter::captureScreen()
{
#ifdef Q_OS_MAC
// Capture the screen using Core Graphics
CGImageRef cgImage = CGWindowListCreateImage(CGRectMake(m_x, m_y, m_size, m_size), kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault);
QImage screenCapture = CGImageToQImage(cgImage);
CGImageRelease(cgImage);
// Save the captured image
static int i = 0;
QString fileName = QString("capture_%1.png").arg(i++);
saveImage(screenCapture, fileName);
#else
// Capture the screen using Qt
QScreen* screen = QGuiApplication::primaryScreen();
if (!screen)
return;
QImage screenCapture = screen->grabWindow(0, m_x, m_y, m_size, m_size).toImage();
#endif
if (!m_previousFrame.isNull() && screenCapture != m_previousFrame)
{
++m_frameCount;
}
m_previousFrame = screenCapture;
calculateFps();
}
void FrameCounter::calculateFps()
{
qint64 elapsed = m_elapsedTimer.elapsed();
// Calculate the current FPS and update the list of FPS values every 300 milliseconds.
if (elapsed >= 300)
{
m_currentFps = static_cast<double>(m_frameCount) / (static_cast<double>(elapsed) / 1000.0);
m_listOfFps.append(m_currentFps);
// Reset the frame count and restart the timer.
m_frameCount = 0;
m_elapsedTimer.restart();
emit newfpsvalue();
}
}
void FrameCounter::startMeasurement(int x, int y, int size)
{
// Define the measurement area and start timers
m_x = x;
m_y = y;
m_size = size;
// Start the capture timer to capture frames every 16 milliseconds.
m_captureTimer.start(16);
m_elapsedTimer.restart();
}
void FrameCounter::stopMeasurement()
{
m_captureTimer.stop();
// Reset FPS and clear the list of FPS values.
m_currentFps = 0;
m_listOfFps.clear();
}
#ifdef Q_OS_MAC
CGBitmapInfo FrameCounter::CGBitmapInfoForQImage(const QImage &image)
{
CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
switch (image.format()) {
case QImage::Format_ARGB32:
bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGB32:
bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGBA8888_Premultiplied:
bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBA8888:
bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBX8888:
bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
break;
case QImage::Format_ARGB32_Premultiplied:
bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
break;
default:
break;
}
return bitmapInfo;
}
QImage FrameCounter::CGImageToQImage(CGImageRef cgImage)
{
const size_t width = CGImageGetWidth(cgImage);
const size_t height = CGImageGetHeight(cgImage);
QImage image(static_cast<int>(width), static_cast<int>(height), QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
CGContextRef context = CGBitmapContextCreate(static_cast<void*>(image.bits()), static_cast<size_t>(image.width()), static_cast<size_t>(image.height()), 8,
static_cast<size_t>(image.bytesPerLine()), colorSpace, CGBitmapInfoForQImage(image));
// Scale the context so that painting happens in device-independent pixels
const qreal devicePixelRatio = image.devicePixelRatio();
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(context, rect, cgImage);
CFRelease(colorSpace);
CGContextRelease(context);
return image;
}
#endif
void FrameCounter::saveImage(const QImage& image, const QString& fileName)
{
QDir dir;
if (!dir.exists("captures"))
{
dir.mkpath("captures");
}
image.save("captures/" + fileName);
}
如何更改我的代码以使其捕获屏幕上的所有应用程序然后将其转换为 QImage?
也许,作为解决方法或临时解决方案,您可以使用 ffmpeg 管道, 例如
ffmpeg -video_size 1024x768 -framerate 25 -f x11grab -i :0.0+100,200 output.mp4
输出也可以是流媒体http://trac.ffmpeg.org/wiki/StreamingGuide 所以,你将能够在你的 qt 应用程序中获取它