feat: add config

This commit is contained in:
rankun 2020-01-16 17:08:56 +08:00
parent d7e9b7809f
commit c96e3ed9dd
11 changed files with 170 additions and 100 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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());
}

View file

@ -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
View 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
View 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

View file

@ -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
View file

@ -0,0 +1,4 @@
[common]
WindowTitle=abc
RecordPath=C:/Users/bytedance/Desktop
ServerVersion=1.12.1

View file

@ -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