mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-25 05:55:01 +00:00
feat: add config option to render expired frames
Replace the compilation flag SKIP_FRAMES by a config flag to force rendering of expired frames. By default, the expired frames are skipped.
This commit is contained in:
parent
eeeeae97fb
commit
e43b3bc0ad
10 changed files with 58 additions and 42 deletions
|
@ -9,6 +9,3 @@ SOURCES += \
|
||||||
$$PWD/fpscounter.cpp \
|
$$PWD/fpscounter.cpp \
|
||||||
$$PWD/avframeconvert.cpp \
|
$$PWD/avframeconvert.cpp \
|
||||||
$$PWD/videobuffer.cpp
|
$$PWD/videobuffer.cpp
|
||||||
|
|
||||||
#DEFINES += SKIP_FRAMES
|
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,9 @@ VideoBuffer::~VideoBuffer()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoBuffer::init()
|
bool VideoBuffer::init(bool renderExpiredFrames)
|
||||||
{
|
{
|
||||||
|
m_renderExpiredFrames = renderExpiredFrames;
|
||||||
m_decodingFrame = av_frame_alloc();
|
m_decodingFrame = av_frame_alloc();
|
||||||
if (!m_decodingFrame) {
|
if (!m_decodingFrame) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -71,17 +72,17 @@ void VideoBuffer::offerDecodedFrame(bool& previousFrameSkipped)
|
||||||
{
|
{
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
|
|
||||||
#ifndef SKIP_FRAMES
|
if (m_renderExpiredFrames) {
|
||||||
// if SKIP_FRAMES is disabled, then the decoder must wait for the current
|
// if m_renderExpiredFrames is enable, then the decoder must wait for the current
|
||||||
// frame to be consumed
|
// frame to be consumed
|
||||||
while (!m_renderingFrameConsumed && !m_interrupted) {
|
while (!m_renderingFrameConsumed && !m_interrupted) {
|
||||||
m_renderingFrameConsumedCond.wait(&m_mutex);
|
m_renderingFrameConsumedCond.wait(&m_mutex);
|
||||||
}
|
}
|
||||||
#else
|
} else {
|
||||||
if (m_fpsCounter.isStarted() && !m_renderingFrameConsumed) {
|
if (m_fpsCounter.isStarted() && !m_renderingFrameConsumed) {
|
||||||
m_fpsCounter.addSkippedFrame();
|
m_fpsCounter.addSkippedFrame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
swap();
|
swap();
|
||||||
previousFrameSkipped = !m_renderingFrameConsumed;
|
previousFrameSkipped = !m_renderingFrameConsumed;
|
||||||
|
@ -96,23 +97,23 @@ const AVFrame *VideoBuffer::consumeRenderedFrame()
|
||||||
if (m_fpsCounter.isStarted()) {
|
if (m_fpsCounter.isStarted()) {
|
||||||
m_fpsCounter.addRenderedFrame();
|
m_fpsCounter.addRenderedFrame();
|
||||||
}
|
}
|
||||||
#ifndef SKIP_FRAMES
|
if (m_renderExpiredFrames) {
|
||||||
// if SKIP_FRAMES is disabled, then notify the decoder the current frame is
|
// if m_renderExpiredFrames is enable, then notify the decoder the current frame is
|
||||||
// consumed, so that it may push a new one
|
// consumed, so that it may push a new one
|
||||||
m_renderingFrameConsumedCond.wakeOne();
|
m_renderingFrameConsumedCond.wakeOne();
|
||||||
#endif
|
}
|
||||||
return m_renderingframe;
|
return m_renderingframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBuffer::interrupt()
|
void VideoBuffer::interrupt()
|
||||||
{
|
{
|
||||||
#ifndef SKIP_FRAMES
|
if (m_renderExpiredFrames) {
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
m_interrupted = true;
|
m_interrupted = true;
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
// wake up blocking wait
|
// wake up blocking wait
|
||||||
m_renderingFrameConsumedCond.wakeOne();
|
m_renderingFrameConsumedCond.wakeOne();
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoBuffer::swap()
|
void VideoBuffer::swap()
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
VideoBuffer();
|
VideoBuffer();
|
||||||
virtual ~VideoBuffer();
|
virtual ~VideoBuffer();
|
||||||
|
|
||||||
bool init();
|
bool init(bool renderExpiredFrames = false);
|
||||||
void deInit();
|
void deInit();
|
||||||
void lock();
|
void lock();
|
||||||
void unLock();
|
void unLock();
|
||||||
|
@ -45,10 +45,12 @@ private:
|
||||||
bool m_renderingFrameConsumed = true;
|
bool m_renderingFrameConsumed = true;
|
||||||
FpsCounter m_fpsCounter;
|
FpsCounter m_fpsCounter;
|
||||||
|
|
||||||
#ifndef SKIP_FRAMES
|
bool m_renderExpiredFrames = false;
|
||||||
QWaitCondition m_renderingFrameConsumedCond;
|
QWaitCondition m_renderingFrameConsumedCond;
|
||||||
bool m_interrupted = true;
|
|
||||||
#endif
|
// interrupted is not used if expired frames are not rendered
|
||||||
|
// since offering a frame will never block
|
||||||
|
bool m_interrupted = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VIDEO_BUFFER_H
|
#endif // VIDEO_BUFFER_H
|
||||||
|
|
|
@ -30,7 +30,7 @@ Device::Device(DeviceParams params, QObject *parent)
|
||||||
|
|
||||||
if (params.display) {
|
if (params.display) {
|
||||||
m_vb = new VideoBuffer();
|
m_vb = new VideoBuffer();
|
||||||
m_vb->init();
|
m_vb->init(params.renderExpiredFrames);
|
||||||
m_decoder = new Decoder(m_vb, this);
|
m_decoder = new Decoder(m_vb, this);
|
||||||
m_fileHandler = new FileHandler(this);
|
m_fileHandler = new FileHandler(this);
|
||||||
m_controller = new Controller(params.gameScript, this);
|
m_controller = new Controller(params.gameScript, this);
|
||||||
|
|
|
@ -18,16 +18,17 @@ class Device : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
struct DeviceParams {
|
struct DeviceParams {
|
||||||
QString recordFileName = ""; // 视频录制文件名
|
QString recordFileName = ""; // 视频录制文件名
|
||||||
QString serial = ""; // 设备序列号
|
QString serial = ""; // 设备序列号
|
||||||
quint16 localPort = 27183; // reverse时本地监听端口
|
quint16 localPort = 27183; // reverse时本地监听端口
|
||||||
quint16 maxSize = 720; // 视频分辨率
|
quint16 maxSize = 720; // 视频分辨率
|
||||||
quint32 bitRate = 8000000; // 视频比特率
|
quint32 bitRate = 8000000; // 视频比特率
|
||||||
quint32 maxFps = 60; // 视频最大帧率
|
quint32 maxFps = 60; // 视频最大帧率
|
||||||
bool closeScreen = false; // 启动时自动息屏
|
bool closeScreen = false; // 启动时自动息屏
|
||||||
bool useReverse = true; // true:先使用adb reverse,失败后自动使用adb forward;false:直接使用adb forward
|
bool useReverse = true; // true:先使用adb reverse,失败后自动使用adb forward;false:直接使用adb forward
|
||||||
bool display = true; // 是否显示画面(或者仅仅后台录制)
|
bool display = true; // 是否显示画面(或者仅仅后台录制)
|
||||||
QString gameScript = ""; // 游戏映射脚本
|
QString gameScript = ""; // 游戏映射脚本
|
||||||
|
bool renderExpiredFrames = false; // 是否渲染延迟视频帧
|
||||||
};
|
};
|
||||||
explicit Device(DeviceParams params, QObject *parent = nullptr);
|
explicit Device(DeviceParams params, QObject *parent = nullptr);
|
||||||
virtual ~Device();
|
virtual ~Device();
|
||||||
|
|
|
@ -162,6 +162,7 @@ void Dialog::on_startServerBtn_clicked()
|
||||||
params.closeScreen = ui->closeScreenCheck->isChecked();
|
params.closeScreen = ui->closeScreenCheck->isChecked();
|
||||||
params.useReverse = ui->useReverseCheck->isChecked();
|
params.useReverse = ui->useReverseCheck->isChecked();
|
||||||
params.display = !ui->notDisplayCheck->isChecked();
|
params.display = !ui->notDisplayCheck->isChecked();
|
||||||
|
params.renderExpiredFrames = Config::getInstance().getRenderExpiredFrames();
|
||||||
|
|
||||||
m_deviceManage.connectDevice(params);
|
m_deviceManage.connectDevice(params);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#define COMMON_SKIN_KEY "UseSkin"
|
#define COMMON_SKIN_KEY "UseSkin"
|
||||||
#define COMMON_SKIN_DEF 1
|
#define COMMON_SKIN_DEF 1
|
||||||
|
|
||||||
|
#define COMMON_RENDER_EXPIRED_FRAMES_KEY "RenderExpiredFrames"
|
||||||
|
#define COMMON_RENDER_EXPIRED_FRAMES_DEF 0
|
||||||
|
|
||||||
QString Config::s_configPath = "";
|
QString Config::s_configPath = "";
|
||||||
|
|
||||||
Config::Config(QObject *parent) : QObject(parent)
|
Config::Config(QObject *parent) : QObject(parent)
|
||||||
|
@ -108,6 +111,15 @@ int Config::getSkin()
|
||||||
return skin;
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Config::getRenderExpiredFrames()
|
||||||
|
{
|
||||||
|
int renderExpiredFrames = 1;
|
||||||
|
m_settings->beginGroup(GROUP_COMMON);
|
||||||
|
renderExpiredFrames = m_settings->value(COMMON_RENDER_EXPIRED_FRAMES_KEY, COMMON_RENDER_EXPIRED_FRAMES_DEF).toInt();
|
||||||
|
m_settings->endGroup();
|
||||||
|
return renderExpiredFrames;
|
||||||
|
}
|
||||||
|
|
||||||
QString Config::getPushFilePath()
|
QString Config::getPushFilePath()
|
||||||
{
|
{
|
||||||
QString pushFile;
|
QString pushFile;
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
int getMaxFps();
|
int getMaxFps();
|
||||||
int getDesktopOpenGL();
|
int getDesktopOpenGL();
|
||||||
int getSkin();
|
int getSkin();
|
||||||
|
int getRenderExpiredFrames();
|
||||||
QString getPushFilePath();
|
QString getPushFilePath();
|
||||||
QString getServerPath();
|
QString getServerPath();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ PushFilePath=/sdcard/
|
||||||
MaxFps=60
|
MaxFps=60
|
||||||
# 是否显示手机皮肤,0不显示
|
# 是否显示手机皮肤,0不显示
|
||||||
UseSkin=1
|
UseSkin=1
|
||||||
|
# 是否渲染过期视频帧(跳过过期视频帧意味着更低的延迟)
|
||||||
|
RenderExpiredFrames=0
|
||||||
# 视频解码方式:-1 自动,0 软解,1 dx硬解,2 opengl硬解
|
# 视频解码方式:-1 自动,0 软解,1 dx硬解,2 opengl硬解
|
||||||
UseDesktopOpenGL=-1
|
UseDesktopOpenGL=-1
|
||||||
# scrcpy-server的版本号(不要修改)
|
# scrcpy-server的版本号(不要修改)
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
# TODO
|
# TODO
|
||||||
## 低优先级
|
## 低优先级
|
||||||
- 中文输入(server需要改为apk,作为一个输入法,暂不实现)(或者有其他方式案件注入方式,例如搜狗手机输入法可以监听当前注入?)
|
- 中文输入(server需要改为apk,作为一个输入法,暂不实现)(或者有其他方式案件注入方式,例如搜狗手机输入法可以监听当前注入?)
|
||||||
- [跳过帧改为动态配置,而不是静态编译](https://github.com/Genymobile/scrcpy/commit/ebccb9f6cc111e8acfbe10d656cac5c1f1b744a0)
|
|
||||||
- [单独线程统计帧率](https://github.com/Genymobile/scrcpy/commit/e2a272bf99ecf48fcb050177113f903b3fb323c4)
|
- [单独线程统计帧率](https://github.com/Genymobile/scrcpy/commit/e2a272bf99ecf48fcb050177113f903b3fb323c4)
|
||||||
- text转换 https://github.com/Genymobile/scrcpy/commit/c916af0984f72a60301d13fa8ef9a85112f54202?tdsourcetag=s_pctim_aiomsg
|
- text转换 https://github.com/Genymobile/scrcpy/commit/c916af0984f72a60301d13fa8ef9a85112f54202?tdsourcetag=s_pctim_aiomsg
|
||||||
- ui提供show touch设置
|
- ui提供show touch设置
|
||||||
|
|
Loading…
Add table
Reference in a new issue