mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-20 11:35:56 +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_srcHeight = srcHeight;
|
||||
|
@ -20,21 +20,21 @@ void AVFrameConvert::setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixe
|
|||
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;
|
||||
srcHeight = m_srcHeight;
|
||||
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_dstHeight = dstHeight;
|
||||
m_dstFormat = dstFormat;
|
||||
}
|
||||
|
||||
void AVFrameConvert::getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat)
|
||||
void AVFrameConvert::getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat)
|
||||
{
|
||||
dstWidth = m_dstWidth;
|
||||
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) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -16,22 +16,22 @@ public:
|
|||
virtual ~AVFrameConvert();
|
||||
|
||||
public:
|
||||
void setSrcFrameInfo(quint32 srcWidth, quint32 srcHeight, AVPixelFormat srcFormat);
|
||||
void getSrcFrameInfo(quint32& srcWidth, quint32& srcHeight, AVPixelFormat& srcFormat);
|
||||
void setDstFrameInfo(quint32 dstWidth, quint32 dstHeight, AVPixelFormat dstFormat);
|
||||
void getDstFrameInfo(quint32& dstWidth, quint32& dstHeight, AVPixelFormat& dstFormat);
|
||||
void setSrcFrameInfo(int srcWidth, int srcHeight, AVPixelFormat srcFormat);
|
||||
void getSrcFrameInfo(int& srcWidth, int& srcHeight, AVPixelFormat& srcFormat);
|
||||
void setDstFrameInfo(int dstWidth, int dstHeight, AVPixelFormat dstFormat);
|
||||
void getDstFrameInfo(int& dstWidth, int& dstHeight, AVPixelFormat& dstFormat);
|
||||
|
||||
bool init();
|
||||
bool isInit();
|
||||
void deInit();
|
||||
bool convert(AVFrame* srcFrame, AVFrame* dstFrame);
|
||||
bool convert(const AVFrame* srcFrame, AVFrame* dstFrame);
|
||||
|
||||
private:
|
||||
quint32 m_srcWidth = 0;
|
||||
quint32 m_srcHeight = 0;
|
||||
int m_srcWidth = 0;
|
||||
int m_srcHeight = 0;
|
||||
AVPixelFormat m_srcFormat = AV_PIX_FMT_NONE;
|
||||
quint32 m_dstWidth = 0;
|
||||
quint32 m_dstHeight = 0;
|
||||
int m_dstWidth = 0;
|
||||
int m_dstHeight = 0;
|
||||
AVPixelFormat m_dstFormat = AV_PIX_FMT_NONE;
|
||||
|
||||
struct SwsContext *m_convertCtx = Q_NULLPTR;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
|
||||
#include "device.h"
|
||||
#include "recorder.h"
|
||||
|
@ -11,6 +12,11 @@
|
|||
#include "videoform.h"
|
||||
#include "controller.h"
|
||||
#include "config.h"
|
||||
#include "avframeconvert.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "libavutil/imgutils.h"
|
||||
}
|
||||
|
||||
Device::Device(DeviceParams params, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -97,10 +103,16 @@ void Device::updateScript(QString script)
|
|||
}
|
||||
}
|
||||
|
||||
void Device::onScreenshot()
|
||||
{
|
||||
m_screenshot = true;
|
||||
}
|
||||
|
||||
void Device::initSignals()
|
||||
{
|
||||
if (m_controller && m_videoForm) {
|
||||
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor);
|
||||
connect(m_videoForm, &VideoForm::screenshot, this, &Device::onScreenshot);
|
||||
}
|
||||
if (m_videoForm) {
|
||||
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){
|
||||
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());
|
||||
|
||||
// update ui
|
||||
|
@ -189,6 +201,12 @@ void Device::initSignals()
|
|||
if (m_videoForm) {
|
||||
m_videoForm->updateRender(frame);
|
||||
}
|
||||
|
||||
// screenshot
|
||||
if (m_screenshot) {
|
||||
saveFrame(frame);
|
||||
m_screenshot = false;
|
||||
}
|
||||
m_vb->unLock();
|
||||
},Qt::QueuedConnection);
|
||||
}
|
||||
|
@ -216,3 +234,56 @@ void Device::startServer()
|
|||
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 VideoForm;
|
||||
class Controller;
|
||||
struct AVFrame;
|
||||
class Device : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -40,9 +41,13 @@ public:
|
|||
signals:
|
||||
void deviceDisconnect(QString serial);
|
||||
|
||||
public slots:
|
||||
void onScreenshot();
|
||||
|
||||
private:
|
||||
void initSignals();
|
||||
void startServer();
|
||||
bool saveFrame(const AVFrame* frame);
|
||||
|
||||
private:
|
||||
// server relevant
|
||||
|
@ -59,6 +64,8 @@ private:
|
|||
|
||||
QTime m_startTimeCount;
|
||||
DeviceParams m_params;
|
||||
|
||||
bool m_screenshot = false;
|
||||
};
|
||||
|
||||
#endif // DEVICE_H
|
||||
|
|
|
@ -20,9 +20,6 @@ ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
|
|||
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
|
||||
|
||||
initStyle();
|
||||
|
||||
// TODO
|
||||
ui->screenShotBtn->hide();
|
||||
}
|
||||
|
||||
ToolForm::~ToolForm()
|
||||
|
@ -123,7 +120,7 @@ void ToolForm::on_powerBtn_clicked()
|
|||
|
||||
void ToolForm::on_screenShotBtn_clicked()
|
||||
{
|
||||
// TODO
|
||||
emit screenshot();
|
||||
}
|
||||
|
||||
void ToolForm::on_volumeUpBtn_clicked()
|
||||
|
|
|
@ -27,6 +27,9 @@ protected:
|
|||
void showEvent(QShowEvent *event);
|
||||
void hideEvent(QHideEvent *event);
|
||||
|
||||
signals:
|
||||
void screenshot();
|
||||
|
||||
private slots:
|
||||
void on_fullScreenBtn_clicked();
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ void VideoForm::showToolForm(bool show)
|
|||
if (!m_toolForm) {
|
||||
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT);
|
||||
m_toolForm->move(pos().x() + geometry().width(), pos().y() + 30);
|
||||
|
||||
connect(m_toolForm, &ToolForm::screenshot, this, &VideoForm::screenshot);
|
||||
}
|
||||
m_toolForm->setVisible(show);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ public:
|
|||
void setFileHandler(FileHandler *fileHandler);
|
||||
void setSerial(const QString &serial);
|
||||
|
||||
signals:
|
||||
void screenshot();
|
||||
|
||||
public slots:
|
||||
void onGrabCursor(bool grab);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ private slots:
|
|||
void on_stopAllServerBtn_clicked();
|
||||
|
||||
void on_refreshGameScriptBtn_clicked();
|
||||
|
||||
void on_applyScriptBtn_clicked();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Add table
Reference in a new issue