mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-20 03:25:02 +00:00
feat: add config
This commit is contained in:
parent
d7e9b7809f
commit
c96e3ed9dd
11 changed files with 170 additions and 100 deletions
|
@ -58,8 +58,8 @@ INCLUDEPATH += \
|
|||
|
||||
# 统一版本号入口,只修改这一个地方即可
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 12
|
||||
VERSION_PATCH = 1
|
||||
VERSION_MINOR = 1
|
||||
VERSION_PATCH = 0
|
||||
|
||||
# qmake变量的方式定义版本号
|
||||
VERSION = $${VERSION_MAJOR}.$${VERSION_MINOR}.$${VERSION_PATCH}
|
||||
|
@ -152,6 +152,10 @@ macos {
|
|||
APP_FFMPEG.path = Contents/MacOS
|
||||
QMAKE_BUNDLE_DATA += APP_FFMPEG
|
||||
|
||||
APP_CONFIG.files = $$files($$PWD/../config/config.ini)
|
||||
APP_CONFIG.path = Contents/MacOS
|
||||
QMAKE_BUNDLE_DATA += APP_CONFIG
|
||||
|
||||
# mac application icon
|
||||
ICON = $$PWD/res/QtScrcpy.icns
|
||||
QMAKE_INFO_PLIST = $$PWD/res/Info_mac.plist
|
||||
|
|
|
@ -12,85 +12,38 @@ Recorder::Recorder(const QString& fileName, QObject* parent)
|
|||
, m_fileName(fileName)
|
||||
, m_format(guessRecordFormat(fileName))
|
||||
{
|
||||
queueInit(&m_queue);
|
||||
}
|
||||
|
||||
Recorder::~Recorder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Recorder::RecordPacket* Recorder::packetNew(const AVPacket *packet) {
|
||||
RecordPacket* rec = new RecordPacket;
|
||||
AVPacket* Recorder::packetNew(const AVPacket *packet) {
|
||||
AVPacket* rec = new AVPacket;
|
||||
if (!rec) {
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
// av_packet_ref() does not initialize all fields in old FFmpeg versions
|
||||
av_init_packet(&rec->packet);
|
||||
av_init_packet(rec);
|
||||
|
||||
if (av_packet_ref(&rec->packet, packet)) {
|
||||
if (av_packet_ref(rec, packet)) {
|
||||
delete rec;
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
rec->next = Q_NULLPTR;
|
||||
return rec;
|
||||
}
|
||||
|
||||
void Recorder::packetDelete(Recorder::RecordPacket *rec) {
|
||||
av_packet_unref(&rec->packet);
|
||||
delete rec;
|
||||
void Recorder::packetDelete(AVPacket* packet) {
|
||||
av_packet_unref(packet);
|
||||
delete packet;
|
||||
}
|
||||
|
||||
void Recorder::queueInit(Recorder::RecorderQueue *queue) {
|
||||
queue->first = Q_NULLPTR;
|
||||
// queue->last is undefined if queue->first == NULL
|
||||
}
|
||||
|
||||
bool Recorder::queueIsEmpty(Recorder::RecorderQueue *queue) {
|
||||
return !queue->first;
|
||||
}
|
||||
|
||||
bool Recorder::queuePush(Recorder::RecorderQueue *queue, const AVPacket *packet) {
|
||||
RecordPacket *rec = packetNew(packet);
|
||||
if (!rec) {
|
||||
qCritical("Could not allocate record packet");
|
||||
return false;
|
||||
void Recorder::queueClear()
|
||||
{
|
||||
while (!m_queue.isEmpty()) {
|
||||
packetDelete(m_queue.dequeue());
|
||||
}
|
||||
rec->next = Q_NULLPTR;
|
||||
|
||||
if (queueIsEmpty(queue)) {
|
||||
queue->first = queue->last = rec;
|
||||
} else {
|
||||
// chain rec after the (current) last packet
|
||||
queue->last->next = rec;
|
||||
// the last packet is now rec
|
||||
queue->last = rec;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Recorder::RecordPacket* Recorder::queueTake(Recorder::RecorderQueue *queue) {
|
||||
assert(!queueIsEmpty(queue));
|
||||
|
||||
RecordPacket *rec = queue->first;
|
||||
assert(rec);
|
||||
|
||||
queue->first = rec->next;
|
||||
// no need to update queue->last if the queue is left empty:
|
||||
// queue->last is undefined if queue->first == NULL
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
void Recorder::queueClear(Recorder::RecorderQueue *queue) {
|
||||
RecordPacket *rec = queue->first;
|
||||
while (rec) {
|
||||
RecordPacket *current = rec;
|
||||
rec = rec->next;
|
||||
packetDelete(current);
|
||||
}
|
||||
queue->first = Q_NULLPTR;
|
||||
}
|
||||
|
||||
void Recorder::setFrameSize(const QSize &declaredFrameSize)
|
||||
|
@ -289,21 +242,21 @@ Recorder::RecorderFormat Recorder::guessRecordFormat(const QString &fileName)
|
|||
|
||||
void Recorder::run() {
|
||||
for (;;) {
|
||||
RecordPacket *rec = Q_NULLPTR;
|
||||
AVPacket *rec = Q_NULLPTR;
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
while (!m_stopped && queueIsEmpty(&m_queue)) {
|
||||
while (!m_stopped && m_queue.isEmpty()) {
|
||||
m_recvDataCond.wait(&m_mutex);
|
||||
}
|
||||
|
||||
// if stopped is set, continue to process the remaining events (to
|
||||
// finish the recording) before actually stopping
|
||||
if (m_stopped && queueIsEmpty(&m_queue)) {
|
||||
RecordPacket* last = m_previous;
|
||||
if (m_stopped && m_queue.isEmpty()) {
|
||||
AVPacket* last = m_previous;
|
||||
if (last) {
|
||||
// assign an arbitrary duration to the last packet
|
||||
last->packet.duration = 100000;
|
||||
bool ok = write(&last->packet);
|
||||
last->duration = 100000;
|
||||
bool ok = write(last);
|
||||
if (!ok) {
|
||||
// failing to write the last frame is not very serious, no
|
||||
// future frame may depend on it, so the resulting file
|
||||
|
@ -315,11 +268,11 @@ void Recorder::run() {
|
|||
break;
|
||||
}
|
||||
|
||||
rec = queueTake(&m_queue);
|
||||
rec = m_queue.dequeue();
|
||||
}
|
||||
|
||||
// recorder->previous is only written from this thread, no need to lock
|
||||
RecordPacket* previous = m_previous;
|
||||
AVPacket* previous = m_previous;
|
||||
m_previous = rec;
|
||||
|
||||
if (!previous) {
|
||||
|
@ -328,21 +281,20 @@ void Recorder::run() {
|
|||
}
|
||||
|
||||
// config packets have no PTS, we must ignore them
|
||||
if (rec->packet.pts != AV_NOPTS_VALUE
|
||||
&& previous->packet.pts != AV_NOPTS_VALUE) {
|
||||
if (rec->pts != AV_NOPTS_VALUE
|
||||
&& previous->pts != AV_NOPTS_VALUE) {
|
||||
// we now know the duration of the previous packet
|
||||
previous->packet.duration = rec->packet.pts - previous->packet.pts;
|
||||
previous->duration = rec->pts - previous->pts;
|
||||
}
|
||||
|
||||
bool ok = write(&previous->packet);
|
||||
bool ok = write(previous);
|
||||
packetDelete(previous);
|
||||
if (!ok) {
|
||||
qCritical("Could not record packet");
|
||||
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_failed = true;
|
||||
// discard pending packets
|
||||
queueClear(&m_queue);
|
||||
queueClear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -370,7 +322,10 @@ bool Recorder::push(const AVPacket *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ok = queuePush(&m_queue, packet);
|
||||
m_recvDataCond.wakeOne();
|
||||
return ok;
|
||||
AVPacket* rec = packetNew(packet);
|
||||
if (rec) {
|
||||
m_queue.enqueue(rec);
|
||||
m_recvDataCond.wakeOne();
|
||||
}
|
||||
return rec != Q_NULLPTR;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QQueue>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -41,23 +42,9 @@ private:
|
|||
RecorderFormat guessRecordFormat(const QString& fileName);
|
||||
|
||||
private:
|
||||
struct RecordPacket {
|
||||
AVPacket packet;
|
||||
RecordPacket *next;
|
||||
};
|
||||
|
||||
struct RecorderQueue {
|
||||
RecordPacket *first = Q_NULLPTR;
|
||||
RecordPacket *last = Q_NULLPTR; // undefined if first is NULL
|
||||
};
|
||||
|
||||
Recorder::RecordPacket* packetNew(const AVPacket *packet);
|
||||
void packetDelete(Recorder::RecordPacket *rec);
|
||||
void queueInit(Recorder::RecorderQueue *queue);
|
||||
bool queueIsEmpty(Recorder::RecorderQueue *queue);
|
||||
bool queuePush(Recorder::RecorderQueue *queue, const AVPacket *packet);
|
||||
Recorder::RecordPacket* queueTake(Recorder::RecorderQueue *queue);
|
||||
void queueClear(Recorder::RecorderQueue *queue);
|
||||
AVPacket* packetNew(const AVPacket *packet);
|
||||
void packetDelete(AVPacket* packet);
|
||||
void queueClear();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
@ -72,12 +59,12 @@ private:
|
|||
QWaitCondition m_recvDataCond;
|
||||
bool m_stopped = false; // set on recorder_stop() by the stream reader
|
||||
bool m_failed = false; // set on packet write failure
|
||||
RecorderQueue m_queue;
|
||||
QQueue<AVPacket*> m_queue;
|
||||
// we can write a packet only once we received the next one so that we can
|
||||
// set its duration (next_pts - current_pts)
|
||||
// "previous" is only accessed from the recorder thread, so it does not
|
||||
// need to be protected by the mutex
|
||||
RecordPacket* m_previous = Q_NULLPTR;
|
||||
AVPacket* m_previous = Q_NULLPTR;
|
||||
};
|
||||
|
||||
#endif // RECORDER_H
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <QFileInfo>
|
||||
|
||||
#include "server.h"
|
||||
#include "config.h"
|
||||
|
||||
#define DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||
#define DEVICE_NAME_FIELD_LENGTH 64
|
||||
|
@ -129,7 +130,7 @@ bool Server::execute()
|
|||
args << "app_process";
|
||||
args << "/"; // unused;
|
||||
args << "com.genymobile.scrcpy.Server";
|
||||
args << QCoreApplication::applicationVersion();
|
||||
args << Config::getInstance().getServerVersion();
|
||||
args << QString::number(m_params.maxSize);
|
||||
args << QString::number(m_params.bitRate);
|
||||
args << QString::number(m_params.maxFps);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "device.h"
|
||||
#include "videoform.h"
|
||||
#include "keymap.h"
|
||||
#include "config.h"
|
||||
|
||||
Dialog::Dialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
|
@ -63,7 +64,7 @@ Dialog::Dialog(QWidget *parent) :
|
|||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
{
|
||||
m_deviceManage.disconnectAllDevice();
|
||||
delete ui;
|
||||
}
|
||||
|
@ -92,6 +93,8 @@ void Dialog::initUI()
|
|||
// game only windows
|
||||
ui->gameCheck->setEnabled(false);
|
||||
#endif
|
||||
|
||||
ui->recordPathEdt->setText(Config::getInstance().getRecordPath());
|
||||
}
|
||||
|
||||
void Dialog::execAdbCmd()
|
||||
|
@ -287,6 +290,7 @@ void Dialog::on_selectRecordPathBtn_clicked()
|
|||
|
||||
void Dialog::on_recordPathEdt_textChanged(const QString &arg1)
|
||||
{
|
||||
Config::getInstance().setRecordPath(arg1);
|
||||
ui->recordPathEdt->setToolTip(arg1.trimmed());
|
||||
ui->notDisplayCheck->setCheckable(!arg1.trimmed().isEmpty());
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "dialog.h"
|
||||
#include "stream.h"
|
||||
#include "mousetap/mousetap.h"
|
||||
#include "config.h"
|
||||
|
||||
Dialog* g_mainDlg = Q_NULLPTR;
|
||||
|
||||
|
@ -44,11 +45,13 @@ int main(int argc, char *argv[])
|
|||
qputenv("QTSCRCPY_ADB_PATH", "../../../../third_party/adb/win/adb.exe");
|
||||
qputenv("QTSCRCPY_SERVER_PATH", "../../../../third_party/scrcpy-server");
|
||||
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../keymap");
|
||||
qputenv("QTSCRCPY_CONFIG_PATH", "../../../../config/config.ini");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/linux/adb");
|
||||
qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server");
|
||||
qputenv("QTSCRCPY_CONFIG_PATH", "../../../config/config.ini");
|
||||
#endif
|
||||
|
||||
//加载样式表
|
||||
|
@ -62,6 +65,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
g_mainDlg = new Dialog;
|
||||
g_mainDlg->setWindowTitle(Config::getInstance().getTitle());
|
||||
g_mainDlg->show();
|
||||
|
||||
qInfo(QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion()).toUtf8());
|
||||
|
|
80
QtScrcpy/util/config.cpp
Normal file
80
QtScrcpy/util/config.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include <QSettings>
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define GROUP_COMMON "common"
|
||||
|
||||
#define COMMON_TITLE_KEY "WindowTitle"
|
||||
#define COMMON_TITLE_DEF QCoreApplication::applicationName()
|
||||
|
||||
#define COMMON_RECORD_KEY "RecordPath"
|
||||
#define COMMON_RECORD_DEF ""
|
||||
|
||||
#define COMMON_SERVER_VERSION_KEY "ServerVersion"
|
||||
#define COMMON_SERVER_VERSION_DEF "1.12.1"
|
||||
|
||||
|
||||
QString Config::s_configPath = "";
|
||||
|
||||
Config::Config(QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_settings = new QSettings(getConfigPath(), QSettings::IniFormat);
|
||||
m_settings->setIniCodec("UTF-8");
|
||||
}
|
||||
|
||||
Config &Config::getInstance()
|
||||
{
|
||||
static Config config;
|
||||
return config;
|
||||
}
|
||||
|
||||
const QString& Config::getConfigPath()
|
||||
{
|
||||
if (s_configPath.isEmpty()) {
|
||||
s_configPath = QString::fromLocal8Bit(qgetenv("QTSCRCPY_CONFIG_PATH"));
|
||||
QFileInfo fileInfo(s_configPath);
|
||||
if (s_configPath.isEmpty() || !fileInfo.isFile()) {
|
||||
s_configPath = QCoreApplication::applicationDirPath() + "/config/config.ini";
|
||||
}
|
||||
}
|
||||
return s_configPath;
|
||||
}
|
||||
|
||||
QString Config::getRecordPath()
|
||||
{
|
||||
QString record;
|
||||
m_settings->beginGroup(GROUP_COMMON);
|
||||
record = m_settings->value(COMMON_RECORD_KEY, COMMON_RECORD_DEF).toString();
|
||||
m_settings->endGroup();
|
||||
return record;
|
||||
}
|
||||
|
||||
void Config::setRecordPath(const QString &path)
|
||||
{
|
||||
m_settings->beginGroup(GROUP_COMMON);
|
||||
m_settings->setValue(COMMON_RECORD_KEY, path);
|
||||
m_settings->endGroup();
|
||||
}
|
||||
|
||||
QString Config::getServerVersion()
|
||||
{
|
||||
QString server;
|
||||
m_settings->beginGroup(GROUP_COMMON);
|
||||
server = m_settings->value(COMMON_SERVER_VERSION_KEY, COMMON_SERVER_VERSION_DEF).toString();
|
||||
m_settings->endGroup();
|
||||
return server;
|
||||
}
|
||||
|
||||
QString Config::getTitle()
|
||||
{
|
||||
QString title;
|
||||
m_settings->beginGroup(GROUP_COMMON);
|
||||
title = m_settings->value(COMMON_TITLE_KEY, COMMON_TITLE_DEF).toString();
|
||||
m_settings->endGroup();
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
|
27
QtScrcpy/util/config.h
Normal file
27
QtScrcpy/util/config.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
class QSettings;
|
||||
class Config : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static Config& getInstance();
|
||||
QString getTitle();
|
||||
QString getRecordPath();
|
||||
void setRecordPath(const QString& path);
|
||||
QString getServerVersion();
|
||||
|
||||
private:
|
||||
explicit Config(QObject *parent = nullptr);
|
||||
const QString& getConfigPath();
|
||||
|
||||
private:
|
||||
static QString s_configPath;
|
||||
QPointer<QSettings> m_settings;
|
||||
};
|
||||
|
||||
#endif // CONFIG_H
|
|
@ -2,7 +2,9 @@ include ($$PWD/mousetap/mousetap.pri)
|
|||
|
||||
HEADERS += \
|
||||
$$PWD/compat.h \
|
||||
$$PWD/bufferutil.h
|
||||
$$PWD/bufferutil.h \
|
||||
$$PWD/config.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/bufferutil.cpp
|
||||
$$PWD/bufferutil.cpp \
|
||||
$$PWD/config.cpp
|
||||
|
|
4
config/config.ini
Normal file
4
config/config.ini
Normal file
|
@ -0,0 +1,4 @@
|
|||
[common]
|
||||
WindowTitle=abc
|
||||
RecordPath=C:/Users/bytedance/Desktop
|
||||
ServerVersion=1.12.1
|
|
@ -21,6 +21,7 @@ if /i "%1"=="x64" (
|
|||
set adb_path=%script_path%third_party\adb\win\*.*
|
||||
set jar_path=%script_path%third_party\scrcpy-server.jar
|
||||
set keymap_path=%script_path%keymap
|
||||
set config_path=%script_path%config
|
||||
|
||||
if /i %cpu_mode% == x86 (
|
||||
set publish_path=%script_path%QtScrcpy-win32\
|
||||
|
@ -42,6 +43,7 @@ xcopy %release_path% %publish_path% /E /Y
|
|||
xcopy %adb_path% %publish_path% /Y
|
||||
xcopy %jar_path% %publish_path% /Y
|
||||
xcopy %keymap_path% %publish_path%keymap\ /E /Y
|
||||
xcopy %config_path% %publish_path%config\ /E /Y
|
||||
|
||||
:: Ìí¼ÓqtÒÀÀµ°ü
|
||||
windeployqt %publish_path%\QtScrcpy.exe
|
||||
|
|
Loading…
Add table
Reference in a new issue