feat: sync scrcpy

This commit is contained in:
rankun 2020-01-15 19:52:31 +08:00
parent 5710b08301
commit d7e9b7809f
9 changed files with 86 additions and 39 deletions

View file

@ -140,7 +140,7 @@ macos {
-L$$PWD/../third_party/ffmpeg/lib -lswscale.5
# mac bundle file
APP_SCRCPY_SERVER.files = $$files($$PWD/../third_party/scrcpy-server.jar)
APP_SCRCPY_SERVER.files = $$files($$PWD/../third_party/scrcpy-server)
APP_SCRCPY_SERVER.path = Contents/MacOS
QMAKE_BUNDLE_DATA += APP_SCRCPY_SERVER

View file

@ -1,5 +1,6 @@
#include <QDebug>
#include <QFileInfo>
#include <QCoreApplication>
#include "compat.h"
#include "recorder.h"
@ -24,6 +25,10 @@ Recorder::RecordPacket* Recorder::packetNew(const AVPacket *packet) {
if (!rec) {
return Q_NULLPTR;
}
// av_packet_ref() does not initialize all fields in old FFmpeg versions
av_init_packet(&rec->packet);
if (av_packet_ref(&rec->packet, packet)) {
delete rec;
return Q_NULLPTR;
@ -121,6 +126,10 @@ bool Recorder::open(const AVCodec* inputCodec)
m_formatCtx->oformat = (AVOutputFormat*)format;
QString comment = "Recorded by QtScrcpy " + QCoreApplication::applicationVersion();
av_dict_set(&m_formatCtx->metadata, "comment",
comment.toUtf8(), 0);
AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec);
if (!outStream) {
avformat_free_context(m_formatCtx);
@ -152,7 +161,7 @@ bool Recorder::open(const AVCodec* inputCodec)
avformat_free_context(m_formatCtx);
m_formatCtx = Q_NULLPTR;
return false;
}
}
return true;
}
@ -160,11 +169,17 @@ bool Recorder::open(const AVCodec* inputCodec)
void Recorder::close()
{
if (Q_NULLPTR != m_formatCtx) {
int ret = av_write_trailer(m_formatCtx);
if (ret < 0) {
qCritical(QString("Failed to write trailer to %1").arg(m_fileName).toUtf8().toStdString().c_str());
if (m_headerWritten) {
int ret = av_write_trailer(m_formatCtx);
if (ret < 0) {
qCritical(QString("Failed to write trailer to %1").arg(m_fileName).toUtf8().toStdString().c_str());
m_failed = true;
} else {
qInfo(QString("success record %1").arg(m_fileName).toStdString().c_str());
}
} else {
qInfo(QString("success record %1").arg(m_fileName).toStdString().c_str());
// the recorded file is empty
m_failed = true;
}
avio_close(m_formatCtx->pb);
avformat_free_context(m_formatCtx);
@ -274,23 +289,53 @@ Recorder::RecorderFormat Recorder::guessRecordFormat(const QString &fileName)
void Recorder::run() {
for (;;) {
QMutexLocker locker(&m_mutex);
while (!m_stopped && queueIsEmpty(&m_queue)) {
m_recvDataCond.wait(&m_mutex);
RecordPacket *rec = Q_NULLPTR;
{
QMutexLocker locker(&m_mutex);
while (!m_stopped && queueIsEmpty(&m_queue)) {
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 (last) {
// assign an arbitrary duration to the last packet
last->packet.duration = 100000;
bool ok = write(&last->packet);
if (!ok) {
// failing to write the last frame is not very serious, no
// future frame may depend on it, so the resulting file
// will still be valid
qWarning("Could not record last packet");
}
packetDelete(last);
}
break;
}
rec = queueTake(&m_queue);
}
// if stopped is set, continue to process the remaining events (to
// finish the recording) before actually stopping
if (m_stopped && queueIsEmpty(&m_queue)) {
break;
// recorder->previous is only written from this thread, no need to lock
RecordPacket* previous = m_previous;
m_previous = rec;
if (!previous) {
// we just received the first packet
continue;
}
RecordPacket *rec = queueTake(&m_queue);
// config packets have no PTS, we must ignore them
if (rec->packet.pts != AV_NOPTS_VALUE
&& previous->packet.pts != AV_NOPTS_VALUE) {
// we now know the duration of the previous packet
previous->packet.duration = rec->packet.pts - previous->packet.pts;
}
//mutex_unlock(recorder->mutex);
bool ok = write(&rec->packet);
packetDelete(rec);
bool ok = write(&previous->packet);
packetDelete(previous);
if (!ok) {
qCritical("Could not record packet");
@ -300,7 +345,6 @@ void Recorder::run() {
queueClear(&m_queue);
break;
}
}
qDebug("Recorder thread ended");

View file

@ -73,6 +73,11 @@ private:
bool m_stopped = false; // set on recorder_stop() by the stream reader
bool m_failed = false; // set on packet write failure
RecorderQueue 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;
};
#endif // RECORDER_H

View file

@ -56,7 +56,7 @@ const QString& Server::getServerPath()
m_serverPath = QString::fromLocal8Bit(qgetenv("QTSCRCPY_SERVER_PATH"));
QFileInfo fileInfo(m_serverPath);
if (m_serverPath.isEmpty() || !fileInfo.isFile()) {
m_serverPath = QCoreApplication::applicationDirPath() + "/scrcpy-server.jar";
m_serverPath = QCoreApplication::applicationDirPath() + "/scrcpy-server";
}
}
return m_serverPath;
@ -129,10 +129,7 @@ bool Server::execute()
args << "app_process";
args << "/"; // unused;
args << "com.genymobile.scrcpy.Server";
// version
QStringList versionList = QCoreApplication::applicationVersion().split(".");
QString version = versionList[0] + "." + versionList[1] + "." + versionList[2];
args << version;
args << QCoreApplication::applicationVersion();
args << QString::number(m_params.maxSize);
args << QString::number(m_params.bitRate);
args << QString::number(m_params.maxFps);
@ -145,7 +142,7 @@ bool Server::execute()
args << "true"; // always send frame meta (packet boundaries + timestamp)
args << (m_params.control ? "true" : "false");
// adb -s P7C0218510000537 shell CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 0 8000000 false
// adb -s P7C0218510000537 shell CLASSPATH=/data/local/tmp/scrcpy-server app_process / com.genymobile.scrcpy.Server 0 8000000 false
// mark: crop input format: "width:height:x:y" or - for no crop, for example: "100:200:0:0"
// 这条adb命令是阻塞运行的m_serverProcess进程不会退出了
m_serverProcess.execute(m_params.serial, args);

View file

@ -30,6 +30,11 @@ int main(int argc, char *argv[])
qDebug() << a.applicationVersion();
qDebug() << a.applicationName();
//update version
QStringList versionList = QCoreApplication::applicationVersion().split(".");
QString version = versionList[0] + "." + versionList[1] + "." + versionList[2];
a.setApplicationVersion(version);
installTranslator();
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX)
MouseTap::getInstance()->initMouseEventTap();
@ -37,13 +42,13 @@ int main(int argc, char *argv[])
#ifdef Q_OS_WIN32
qputenv("QTSCRCPY_ADB_PATH", "../../../../third_party/adb/win/adb.exe");
qputenv("QTSCRCPY_SERVER_PATH", "../../../../third_party/scrcpy-server.jar");
qputenv("QTSCRCPY_SERVER_PATH", "../../../../third_party/scrcpy-server");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../keymap");
#endif
#ifdef Q_OS_LINUX
qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/linux/adb");
qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server.jar");
qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server");
#endif
//加载样式表
@ -59,6 +64,8 @@ int main(int argc, char *argv[])
g_mainDlg = new Dialog;
g_mainDlg->show();
qInfo(QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion()).toUtf8());
int ret = a.exec();
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX)

View file

@ -174,11 +174,11 @@ Try to provide all the dependencies and make it easy to compile.
3. Open the project root directory all.pro with QtCreator
4. Compile and run
### Android (If you do not need to modify the requirements, you can use the built-in scrcpy-server.jar directly)
### Android (If you do not need to modify the requirements, you can use the built-in scrcpy-server directly)
1. Set up an Android development environment on the target platform
2. Open the server project in the project root directory using Android Studio
3. Build it
4. After compiling apk, rename it to scrcpy-server.jar and replace third_party/scrcpy-server.jar.
4. After compiling apk, rename it to scrcpy-server and replace third_party/scrcpy-server
## Licence
Since it is based on scrcpy, respect its Licence

View file

@ -182,12 +182,12 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
3. 使用QtCreator打开项目根目录all.pro
4. 编译,运行即可
### Android端 没有修改需求的话直接使用自带的scrcpy-server.jar即可)
### Android端 没有修改需求的话直接使用自带的scrcpy-server即可
1. 目标平台上搭建Android开发环境
2. 使用Android Studio打开项目根目录中的server项目
3. 第一次打开如果你没有对应版本的gradle会提示找不到gradle是否升级gradle并创建选择取消取消后会弹出选择已有gradle的位置同样取消即可会自动下载
4. 按需编辑代码即可,当然也可以不编辑
4. 编译出apk以后改名为scrcpy-server.jar并替换third_party/scrcpy-server.jar即可
4. 编译出apk以后改名为scrcpy-server并替换third_party/scrcpy-server即可
## Licence
由于是复刻的scrcpy尊重它的Licence

View file

@ -1,20 +1,15 @@
最后同步scrcpy b91ecf52256da73f5c8dca04fb82c13ec826cbd7
最后同步scrcpy 31bd95022bc525be42ca273d59a3211d964d278b
# TODO
## 低优先级
- 中文输入server需要改为apk作为一个输入法暂不实现或者有其他方式案件注入方式例如搜狗手机输入法可以监听当前注入
- 鼠标事件相关系列 b35733edb6df2a00b6af9b1c98627d344c377963
- [跳过帧改为动态配置,而不是静态编译](https://github.com/Genymobile/scrcpy/commit/ebccb9f6cc111e8acfbe10d656cac5c1f1b744a0)
- [单独线程统计帧率](https://github.com/Genymobile/scrcpy/commit/e2a272bf99ecf48fcb050177113f903b3fb323c4)
- ui提供show touch设置
- 隐藏手机皮肤开关
## 中优先级
- [截屏保存为jpg](https://blog.csdn.net/m0_37684310/article/details/77950390)
- 版本号升级优化
- linux打包以及版本号
- 自动打包脚本
- 按键映射可配置
- 脚本
- 群控
- 配置文件
@ -24,10 +19,9 @@
- 分辨率码率可自定义
## 高优先级
- 同步延迟优化
- linux打包以及版本号
# BUG
1. 魅族手机提示cant open video stream解决方法 https://dim.red/2019/03/03/scrcpy_usage/
# mark
[ffmpeg编译参数详解](https://www.cnblogs.com/wainiwann/p/4204230.html)

BIN
third_party/scrcpy-server vendored Normal file

Binary file not shown.