mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-08-04 06:38:39 +00:00
feat: add screenshot
This commit is contained in:
parent
5abff3f573
commit
9f5f432316
9 changed files with 107 additions and 20 deletions
|
@ -12,7 +12,7 @@ AVFrameConvert::~AVFrameConvert()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFrameConvert::setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixelFormat srcFormat)
|
void AVFrameConvert::setSrcFrameInfo(int srcWidth, int srcHeight, AVPixelFormat srcFormat)
|
||||||
{
|
{
|
||||||
m_srcWidth = srcWidth;
|
m_srcWidth = srcWidth;
|
||||||
m_srcHeight = srcHeight;
|
m_srcHeight = srcHeight;
|
||||||
|
@ -20,21 +20,21 @@ void AVFrameConvert::setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixe
|
||||||
qDebug() << "Convert::src frame info " << srcWidth << "x" << srcHeight;
|
qDebug() << "Convert::src frame info " << srcWidth << "x" << srcHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFrameConvert::getSrcFrameInfo(quint32& srcWidth, quint32& srcHeight, AVPixelFormat& srcFormat)
|
void AVFrameConvert::getSrcFrameInfo(int& srcWidth, int& srcHeight, AVPixelFormat& srcFormat)
|
||||||
{
|
{
|
||||||
srcWidth = m_srcWidth;
|
srcWidth = m_srcWidth;
|
||||||
srcHeight = m_srcHeight;
|
srcHeight = m_srcHeight;
|
||||||
srcFormat = m_srcFormat;
|
srcFormat = m_srcFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFrameConvert::setDstFrameInfo(quint32 dstWidth, quint32 dstHeight, AVPixelFormat dstFormat)
|
void AVFrameConvert::setDstFrameInfo(int dstWidth, int dstHeight, AVPixelFormat dstFormat)
|
||||||
{
|
{
|
||||||
m_dstWidth = dstWidth;
|
m_dstWidth = dstWidth;
|
||||||
m_dstHeight = dstHeight;
|
m_dstHeight = dstHeight;
|
||||||
m_dstFormat = dstFormat;
|
m_dstFormat = dstFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVFrameConvert::getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat)
|
void AVFrameConvert::getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat)
|
||||||
{
|
{
|
||||||
dstWidth = m_dstWidth;
|
dstWidth = m_dstWidth;
|
||||||
dstHeight = m_dstHeight;
|
dstHeight = m_dstHeight;
|
||||||
|
@ -67,12 +67,15 @@ void AVFrameConvert::deInit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AVFrameConvert::convert(AVFrame* srcFrame, AVFrame* dstFrame)
|
bool AVFrameConvert::convert(const AVFrame* srcFrame, AVFrame* dstFrame)
|
||||||
{
|
{
|
||||||
if(!m_convertCtx || !srcFrame || !dstFrame) {
|
if(!m_convertCtx || !srcFrame || !dstFrame) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qint32 ret = sws_scale(m_convertCtx, (const uint8_t* const*)srcFrame->data, srcFrame->linesize, 0, m_srcHeight, dstFrame->data, dstFrame->linesize);
|
qint32 ret = sws_scale(m_convertCtx,
|
||||||
|
static_cast<const uint8_t* const*>(srcFrame->data),
|
||||||
|
srcFrame->linesize, 0, m_srcHeight, dstFrame->data,
|
||||||
|
dstFrame->linesize);
|
||||||
if (0 == ret) {
|
if (0 == ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,22 +16,22 @@ public:
|
||||||
virtual ~AVFrameConvert();
|
virtual ~AVFrameConvert();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixelFormat srcFormat);
|
void setSrcFrameInfo(int srcWidth, int srcHeight, AVPixelFormat srcFormat);
|
||||||
void getSrcFrameInfo(quint32& srcWidth, quint32& srcHeight, AVPixelFormat& srcFormat);
|
void getSrcFrameInfo(int& srcWidth, int& srcHeight, AVPixelFormat& srcFormat);
|
||||||
void setDstFrameInfo(quint32 dstWidth, quint32 dstHeight, AVPixelFormat dstFormat);
|
void setDstFrameInfo(int dstWidth, int dstHeight, AVPixelFormat dstFormat);
|
||||||
void getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat);
|
void getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat);
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
bool isInit();
|
bool isInit();
|
||||||
void deInit();
|
void deInit();
|
||||||
bool convert(AVFrame* srcFrame, AVFrame* dstFrame);
|
bool convert(const AVFrame* srcFrame, AVFrame* dstFrame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint32 m_srcWidth = 0;
|
int m_srcWidth = 0;
|
||||||
quint32 m_srcHeight = 0;
|
int m_srcHeight = 0;
|
||||||
AVPixelFormat m_srcFormat = AV_PIX_FMT_NONE;
|
AVPixelFormat m_srcFormat = AV_PIX_FMT_NONE;
|
||||||
quint32 m_dstWidth = 0;
|
int m_dstWidth = 0;
|
||||||
quint32 m_dstHeight = 0;
|
int m_dstHeight = 0;
|
||||||
AVPixelFormat m_dstFormat = AV_PIX_FMT_NONE;
|
AVPixelFormat m_dstFormat = AV_PIX_FMT_NONE;
|
||||||
|
|
||||||
struct SwsContext *m_convertCtx = Q_NULLPTR;
|
struct SwsContext *m_convertCtx = Q_NULLPTR;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
|
@ -11,6 +12,11 @@
|
||||||
#include "videoform.h"
|
#include "videoform.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "avframeconvert.h"
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "libavutil/imgutils.h"
|
||||||
|
}
|
||||||
|
|
||||||
Device::Device(DeviceParams params, QObject *parent)
|
Device::Device(DeviceParams params, QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
|
@ -97,10 +103,16 @@ void Device::updateScript(QString script)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::onScreenshot()
|
||||||
|
{
|
||||||
|
m_screenshot = true;
|
||||||
|
}
|
||||||
|
|
||||||
void Device::initSignals()
|
void Device::initSignals()
|
||||||
{
|
{
|
||||||
if (m_controller && m_videoForm) {
|
if (m_controller && m_videoForm) {
|
||||||
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor);
|
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor);
|
||||||
|
connect(m_videoForm, &VideoForm::screenshot, this, &Device::onScreenshot);
|
||||||
}
|
}
|
||||||
if (m_videoForm) {
|
if (m_videoForm) {
|
||||||
connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){
|
connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){
|
||||||
|
@ -138,7 +150,7 @@ void Device::initSignals()
|
||||||
});
|
});
|
||||||
connect(m_server, &Server::connectToResult, this, [this](bool success, const QString &deviceName, const QSize &size){
|
connect(m_server, &Server::connectToResult, this, [this](bool success, const QString &deviceName, const QSize &size){
|
||||||
if (success) {
|
if (success) {
|
||||||
float diff = m_startTimeCount.elapsed() / 1000.0f;
|
double diff = m_startTimeCount.elapsed() / 1000.0;
|
||||||
qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str());
|
qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str());
|
||||||
|
|
||||||
// update ui
|
// update ui
|
||||||
|
@ -189,6 +201,12 @@ void Device::initSignals()
|
||||||
if (m_videoForm) {
|
if (m_videoForm) {
|
||||||
m_videoForm->updateRender(frame);
|
m_videoForm->updateRender(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// screenshot
|
||||||
|
if (m_screenshot) {
|
||||||
|
saveFrame(frame);
|
||||||
|
m_screenshot = false;
|
||||||
|
}
|
||||||
m_vb->unLock();
|
m_vb->unLock();
|
||||||
},Qt::QueuedConnection);
|
},Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
@ -216,3 +234,56 @@ void Device::startServer()
|
||||||
m_server->start(params);
|
m_server->start(params);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Device::saveFrame(const AVFrame* frame)
|
||||||
|
{
|
||||||
|
if (!frame) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create buffer
|
||||||
|
QImage rgbImage(frame->width, frame->height, QImage::Format_RGB32);
|
||||||
|
AVFrame* rgbFrame = av_frame_alloc();
|
||||||
|
if (!rgbFrame) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind buffer to AVFrame
|
||||||
|
av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, rgbImage.bits(), AV_PIX_FMT_RGB32, frame->width, frame->height, 4);
|
||||||
|
|
||||||
|
// convert
|
||||||
|
AVFrameConvert convert;
|
||||||
|
convert.setSrcFrameInfo(frame->width, frame->height, AV_PIX_FMT_YUV420P);
|
||||||
|
convert.setDstFrameInfo(frame->width, frame->height, AV_PIX_FMT_RGB32);
|
||||||
|
bool ret = false;
|
||||||
|
ret = convert.init();
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ret = convert.convert(frame, rgbFrame);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
convert.deInit();
|
||||||
|
av_free(rgbFrame);
|
||||||
|
|
||||||
|
// save
|
||||||
|
QString absFilePath;
|
||||||
|
QString fileDir(Config::getInstance().getRecordPath());
|
||||||
|
if (fileDir.isEmpty()) {
|
||||||
|
qWarning() << "please select record path!!!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QDateTime dateTime = QDateTime::currentDateTime();
|
||||||
|
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
|
||||||
|
fileName = Config::getInstance().getTitle() + fileName + ".jpg";
|
||||||
|
QDir dir(fileDir);
|
||||||
|
absFilePath = dir.absoluteFilePath(fileName);
|
||||||
|
ret = rgbImage.save(absFilePath);
|
||||||
|
if (!ret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << "screenshot save to " << absFilePath;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ class FileHandler;
|
||||||
class Stream;
|
class Stream;
|
||||||
class VideoForm;
|
class VideoForm;
|
||||||
class Controller;
|
class Controller;
|
||||||
|
struct AVFrame;
|
||||||
class Device : public QObject
|
class Device : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -40,9 +41,13 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void deviceDisconnect(QString serial);
|
void deviceDisconnect(QString serial);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onScreenshot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initSignals();
|
void initSignals();
|
||||||
void startServer();
|
void startServer();
|
||||||
|
bool saveFrame(const AVFrame* frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// server relevant
|
// server relevant
|
||||||
|
@ -59,6 +64,8 @@ private:
|
||||||
|
|
||||||
QTime m_startTimeCount;
|
QTime m_startTimeCount;
|
||||||
DeviceParams m_params;
|
DeviceParams m_params;
|
||||||
|
|
||||||
|
bool m_screenshot = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEVICE_H
|
#endif // DEVICE_H
|
||||||
|
|
|
@ -20,9 +20,6 @@ ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
|
||||||
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
|
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
|
||||||
|
|
||||||
initStyle();
|
initStyle();
|
||||||
|
|
||||||
// TODO
|
|
||||||
ui->screenShotBtn->hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolForm::~ToolForm()
|
ToolForm::~ToolForm()
|
||||||
|
@ -123,7 +120,7 @@ void ToolForm::on_powerBtn_clicked()
|
||||||
|
|
||||||
void ToolForm::on_screenShotBtn_clicked()
|
void ToolForm::on_screenShotBtn_clicked()
|
||||||
{
|
{
|
||||||
// TODO
|
emit screenshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolForm::on_volumeUpBtn_clicked()
|
void ToolForm::on_volumeUpBtn_clicked()
|
||||||
|
|
|
@ -27,6 +27,9 @@ protected:
|
||||||
void showEvent(QShowEvent *event);
|
void showEvent(QShowEvent *event);
|
||||||
void hideEvent(QHideEvent *event);
|
void hideEvent(QHideEvent *event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void screenshot();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_fullScreenBtn_clicked();
|
void on_fullScreenBtn_clicked();
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,8 @@ void VideoForm::showToolForm(bool show)
|
||||||
if (!m_toolForm) {
|
if (!m_toolForm) {
|
||||||
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT);
|
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT);
|
||||||
m_toolForm->move(pos().x() + geometry().width(), pos().y() + 30);
|
m_toolForm->move(pos().x() + geometry().width(), pos().y() + 30);
|
||||||
|
|
||||||
|
connect(m_toolForm, &ToolForm::screenshot, this, &VideoForm::screenshot);
|
||||||
}
|
}
|
||||||
m_toolForm->setVisible(show);
|
m_toolForm->setVisible(show);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ public:
|
||||||
void setFileHandler(FileHandler *fileHandler);
|
void setFileHandler(FileHandler *fileHandler);
|
||||||
void setSerial(const QString &serial);
|
void setSerial(const QString &serial);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void screenshot();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onGrabCursor(bool grab);
|
void onGrabCursor(bool grab);
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ private slots:
|
||||||
void on_stopAllServerBtn_clicked();
|
void on_stopAllServerBtn_clicked();
|
||||||
|
|
||||||
void on_refreshGameScriptBtn_clicked();
|
void on_refreshGameScriptBtn_clicked();
|
||||||
|
|
||||||
void on_applyScriptBtn_clicked();
|
void on_applyScriptBtn_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue