mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-07-07 17:41:30 +00:00
update:视频传输和控制指令改为两个不同的socket videosocket负责视频接收 controlsocket负责指令发送
This commit is contained in:
parent
7220d91ed3
commit
b44f78f19b
18 changed files with 181 additions and 125 deletions
|
@ -6,16 +6,16 @@ class QScrcpyEvent : public QEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
DeviceSocket = QEvent::User + 1,
|
VideoSocket = QEvent::User + 1,
|
||||||
Control,
|
Control,
|
||||||
};
|
};
|
||||||
QScrcpyEvent(Type type) : QEvent(QEvent::Type(type)){}
|
QScrcpyEvent(Type type) : QEvent(QEvent::Type(type)){}
|
||||||
};
|
};
|
||||||
|
|
||||||
// DeviceSocketEvent
|
// VideoSocketEvent
|
||||||
class DeviceSocketEvent : public QScrcpyEvent
|
class VideoSocketEvent : public QScrcpyEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeviceSocketEvent() : QScrcpyEvent(DeviceSocket){}
|
VideoSocketEvent() : QScrcpyEvent(VideoSocket){}
|
||||||
};
|
};
|
||||||
#endif // QSCRCPYEVENT_H
|
#endif // QSCRCPYEVENT_H
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "devicesocket.h"
|
#include "videosocket.h"
|
||||||
#include "controlevent.h"
|
#include "controlevent.h"
|
||||||
|
|
||||||
Controller::Controller(QObject* parent) : QObject(parent)
|
Controller::Controller(QObject* parent) : QObject(parent)
|
||||||
|
@ -14,9 +14,9 @@ Controller::~Controller()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::setDeviceSocket(DeviceSocket *deviceSocket)
|
void Controller::setControlSocket(QTcpSocket* controlSocket)
|
||||||
{
|
{
|
||||||
m_deviceSocket = deviceSocket;
|
m_controlSocket = controlSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::postControlEvent(ControlEvent *controlEvent)
|
void Controller::postControlEvent(ControlEvent *controlEvent)
|
||||||
|
@ -51,8 +51,8 @@ bool Controller::sendControl(const QByteArray &buffer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qint32 len = 0;
|
qint32 len = 0;
|
||||||
if (m_deviceSocket) {
|
if (m_controlSocket) {
|
||||||
len = m_deviceSocket->write(buffer.data(), buffer.length());
|
len = m_controlSocket->write(buffer.data(), buffer.length());
|
||||||
}
|
}
|
||||||
return len == buffer.length() ? true : false;
|
return len == buffer.length() ? true : false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
class DeviceSocket;
|
class QTcpSocket;
|
||||||
class ControlEvent;
|
class ControlEvent;
|
||||||
class Controller : public QObject
|
class Controller : public QObject
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ public:
|
||||||
Controller(QObject* parent = Q_NULLPTR);
|
Controller(QObject* parent = Q_NULLPTR);
|
||||||
virtual ~Controller();
|
virtual ~Controller();
|
||||||
|
|
||||||
void setDeviceSocket(DeviceSocket* deviceSocket);
|
void setControlSocket(QTcpSocket* controlSocket);
|
||||||
void postControlEvent(ControlEvent* controlEvent);
|
void postControlEvent(ControlEvent* controlEvent);
|
||||||
void test(QRect rc);
|
void test(QRect rc);
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ private:
|
||||||
bool sendControl(const QByteArray& buffer);
|
bool sendControl(const QByteArray& buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<DeviceSocket> m_deviceSocket;
|
QPointer<QTcpSocket> m_controlSocket;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONTROLLER_H
|
#endif // CONTROLLER_H
|
||||||
|
|
|
@ -10,9 +10,9 @@ InputConvertBase::~InputConvertBase()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputConvertBase::setDeviceSocket(DeviceSocket *deviceSocket)
|
void InputConvertBase::setControlSocket(QTcpSocket *controlSocket)
|
||||||
{
|
{
|
||||||
m_controller.setDeviceSocket(deviceSocket);
|
m_controller.setControlSocket(controlSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputConvertBase::sendControlEvent(ControlEvent *event)
|
void InputConvertBase::sendControlEvent(ControlEvent *event)
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
virtual void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize) = 0;
|
virtual void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize) = 0;
|
||||||
virtual void keyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize) = 0;
|
virtual void keyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize) = 0;
|
||||||
|
|
||||||
void setDeviceSocket(DeviceSocket* deviceSocket);
|
void setControlSocket(QTcpSocket* controlSocket);
|
||||||
void sendControlEvent(ControlEvent* event);
|
void sendControlEvent(ControlEvent* event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QSize>
|
|
||||||
#include <QTimerEvent>
|
#include <QTimerEvent>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
@ -18,24 +17,29 @@ Server::Server(QObject *parent) : QObject(parent)
|
||||||
connect(&m_serverProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult);
|
connect(&m_serverProcess, &AdbProcess::adbProcessResult, this, &Server::onWorkProcessResult);
|
||||||
|
|
||||||
connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){
|
connect(&m_serverSocket, &QTcpServer::newConnection, this, [this](){
|
||||||
m_deviceSocket = dynamic_cast<DeviceSocket*>(m_serverSocket.nextPendingConnection());
|
QTcpSocket* tmp = m_serverSocket.nextPendingConnection();
|
||||||
|
if (dynamic_cast<VideoSocket*>(tmp)) {
|
||||||
QString deviceName;
|
m_videoSocket = dynamic_cast<VideoSocket*>(tmp);
|
||||||
QSize deviceSize;
|
if (!m_videoSocket->isValid() || !readInfo(m_deviceName, m_deviceSize)) {
|
||||||
|
stop();
|
||||||
if (m_deviceSocket->isValid() && readInfo(deviceName, deviceSize)) {
|
emit connectToResult(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_controlSocket = tmp;
|
||||||
|
if (m_controlSocket && m_controlSocket->isValid()) {
|
||||||
// we don't need the server socket anymore
|
// we don't need the server socket anymore
|
||||||
// just m_deviceSocket is ok
|
// just m_videoSocket is ok
|
||||||
m_serverSocket.close();
|
m_serverSocket.close();
|
||||||
// we don't need the adb tunnel anymore
|
// we don't need the adb tunnel anymore
|
||||||
disableTunnelReverse();
|
disableTunnelReverse();
|
||||||
m_tunnelEnabled = false;
|
m_tunnelEnabled = false;
|
||||||
emit connectToResult(true, deviceName, deviceSize);
|
emit connectToResult(true, m_deviceName, m_deviceSize);
|
||||||
} else {
|
} else {
|
||||||
stop();
|
stop();
|
||||||
emit connectToResult(false, deviceName, deviceSize);
|
emit connectToResult(false);
|
||||||
}
|
}
|
||||||
stopAcceptTimeoutTimer();
|
stopAcceptTimeoutTimer();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +163,7 @@ bool Server::connectTo()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_tunnelForward && !m_deviceSocket) {
|
if (!m_tunnelForward && !m_videoSocket) {
|
||||||
startAcceptTimeoutTimer();
|
startAcceptTimeoutTimer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -167,39 +171,49 @@ bool Server::connectTo()
|
||||||
// device server need time to start
|
// device server need time to start
|
||||||
// TODO:电脑配置太低的话,这里有可能时间不够导致连接太早,安卓监听socket还没有建立
|
// TODO:电脑配置太低的话,这里有可能时间不够导致连接太早,安卓监听socket还没有建立
|
||||||
// 后续研究其他办法
|
// 后续研究其他办法
|
||||||
|
// wait for devices server start
|
||||||
QTimer::singleShot(1000, this, [this](){
|
QTimer::singleShot(1000, this, [this](){
|
||||||
QString deviceName;
|
QString deviceName;
|
||||||
QSize deviceSize;
|
QSize deviceSize;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
m_deviceSocket = new DeviceSocket();
|
// video socket
|
||||||
|
m_videoSocket = new VideoSocket();
|
||||||
// wait for devices server start
|
m_videoSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
|
||||||
m_deviceSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
|
if (!m_videoSocket->waitForConnected(1000)) {
|
||||||
if (!m_deviceSocket->waitForConnected(1000)) {
|
|
||||||
stop();
|
stop();
|
||||||
qWarning("connect to server failed");
|
qWarning("video socket connect to server failed");
|
||||||
emit connectToResult(false, "", QSize());
|
emit connectToResult(false, "", QSize());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (QTcpSocket::ConnectedState == m_deviceSocket->state()) {
|
if (QTcpSocket::ConnectedState == m_videoSocket->state()) {
|
||||||
// connect will success even if devices offline, recv data is real connect success
|
// connect will success even if devices offline, recv data is real connect success
|
||||||
// because connect is to pc adb server
|
// because connect is to pc adb server
|
||||||
m_deviceSocket->waitForReadyRead(1000);
|
m_videoSocket->waitForReadyRead(1000);
|
||||||
// devices will send 1 byte first on tunnel forward mode
|
// devices will send 1 byte first on tunnel forward mode
|
||||||
QByteArray data = m_deviceSocket->read(1);
|
QByteArray data = m_videoSocket->read(1);
|
||||||
if (!data.isEmpty() && readInfo(deviceName, deviceSize)) {
|
if (!data.isEmpty() && readInfo(deviceName, deviceSize)) {
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
qWarning("connect to server read device info failed");
|
qWarning("video socket connect to server read device info failed");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning("connect to server failed");
|
qWarning("connect to server failed");
|
||||||
m_deviceSocket->deleteLater();
|
m_videoSocket->deleteLater();
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// control socket
|
||||||
|
m_controlSocket = new QTcpSocket();
|
||||||
|
m_controlSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
|
||||||
|
if (!m_controlSocket->waitForConnected(1000)) {
|
||||||
|
stop();
|
||||||
|
qWarning("control socket connect to server failed");
|
||||||
|
emit connectToResult(false, "", QSize());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// we don't need the adb tunnel anymore
|
// we don't need the adb tunnel anymore
|
||||||
disableTunnelForward();
|
disableTunnelForward();
|
||||||
|
@ -221,16 +235,25 @@ void Server::timerEvent(QTimerEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceSocket* Server::getDeviceSocket()
|
VideoSocket* Server::getVideoSocket()
|
||||||
{
|
{
|
||||||
return m_deviceSocket;
|
return m_videoSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTcpSocket *Server::getControlSocket()
|
||||||
|
{
|
||||||
|
return m_controlSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::stop()
|
void Server::stop()
|
||||||
{
|
{
|
||||||
if (m_deviceSocket) {
|
if (m_videoSocket) {
|
||||||
m_deviceSocket->close();
|
m_videoSocket->close();
|
||||||
m_deviceSocket->deleteLater();
|
m_videoSocket->deleteLater();
|
||||||
|
}
|
||||||
|
if (m_controlSocket) {
|
||||||
|
m_controlSocket->close();
|
||||||
|
m_controlSocket->deleteLater();
|
||||||
}
|
}
|
||||||
// ignore failure
|
// ignore failure
|
||||||
m_serverProcess.kill();
|
m_serverProcess.kill();
|
||||||
|
@ -270,7 +293,7 @@ bool Server::startServerByStep()
|
||||||
// client listens and the server connects to the client. That way, the
|
// client listens and the server connects to the client. That way, the
|
||||||
// client can listen before starting the server app, so there is no need to
|
// client can listen before starting the server app, so there is no need to
|
||||||
// try to connect until the server socket is listening on the device.
|
// try to connect until the server socket is listening on the device.
|
||||||
m_serverSocket.setMaxPendingConnections(1);
|
m_serverSocket.setMaxPendingConnections(2);
|
||||||
if (!m_serverSocket.listen(QHostAddress::LocalHost, m_localPort)) {
|
if (!m_serverSocket.listen(QHostAddress::LocalHost, m_localPort)) {
|
||||||
qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str());
|
qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str());
|
||||||
m_serverStartStep = SSS_NULL;
|
m_serverStartStep = SSS_NULL;
|
||||||
|
@ -300,11 +323,11 @@ bool Server::startServerByStep()
|
||||||
bool Server::readInfo(QString &deviceName, QSize &size)
|
bool Server::readInfo(QString &deviceName, QSize &size)
|
||||||
{
|
{
|
||||||
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
|
unsigned char buf[DEVICE_NAME_FIELD_LENGTH + 4];
|
||||||
if (m_deviceSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) {
|
if (m_videoSocket->bytesAvailable() <= (DEVICE_NAME_FIELD_LENGTH + 4)) {
|
||||||
m_deviceSocket->waitForReadyRead(300);
|
m_videoSocket->waitForReadyRead(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 len = m_deviceSocket->read((char*)buf, sizeof(buf));
|
qint64 len = m_videoSocket->read((char*)buf, sizeof(buf));
|
||||||
if (len < DEVICE_NAME_FIELD_LENGTH + 4) {
|
if (len < DEVICE_NAME_FIELD_LENGTH + 4) {
|
||||||
qInfo("Could not retrieve device information");
|
qInfo("Could not retrieve device information");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
#include "tcpserver.h"
|
#include "tcpserver.h"
|
||||||
#include "devicesocket.h"
|
#include "videosocket.h"
|
||||||
#include "adbprocess.h"
|
#include "adbprocess.h"
|
||||||
|
|
||||||
class Server : public QObject
|
class Server : public QObject
|
||||||
|
@ -27,13 +28,14 @@ public:
|
||||||
bool start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta = false);
|
bool start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta = false);
|
||||||
bool connectTo();
|
bool connectTo();
|
||||||
|
|
||||||
DeviceSocket* getDeviceSocket();
|
VideoSocket* getVideoSocket();
|
||||||
|
QTcpSocket* getControlSocket();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void serverStartResult(bool success);
|
void serverStartResult(bool success);
|
||||||
void connectToResult(bool success, const QString &deviceName, const QSize &size);
|
void connectToResult(bool success, const QString &deviceName = "", const QSize &size = QSize());
|
||||||
void onServerStop();
|
void onServerStop();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -62,7 +64,8 @@ private:
|
||||||
QString m_serial = "";
|
QString m_serial = "";
|
||||||
AdbProcess m_serverProcess;
|
AdbProcess m_serverProcess;
|
||||||
TcpServer m_serverSocket; // only used if !tunnel_forward
|
TcpServer m_serverSocket; // only used if !tunnel_forward
|
||||||
QPointer<DeviceSocket> m_deviceSocket = Q_NULLPTR;
|
QPointer<VideoSocket> m_videoSocket = Q_NULLPTR;
|
||||||
|
QPointer<QTcpSocket> m_controlSocket = Q_NULLPTR;
|
||||||
quint16 m_localPort = 0;
|
quint16 m_localPort = 0;
|
||||||
bool m_tunnelEnabled = false;
|
bool m_tunnelEnabled = false;
|
||||||
bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse"
|
bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse"
|
||||||
|
@ -71,6 +74,8 @@ private:
|
||||||
quint32 m_bitRate = 0;
|
quint32 m_bitRate = 0;
|
||||||
QString m_crop = "";
|
QString m_crop = "";
|
||||||
quint32 m_acceptTimeoutTimer = 0;
|
quint32 m_acceptTimeoutTimer = 0;
|
||||||
|
QString m_deviceName = "";
|
||||||
|
QSize m_deviceSize = QSize();
|
||||||
|
|
||||||
SERVER_START_STEP m_serverStartStep = SSS_NULL;
|
SERVER_START_STEP m_serverStartStep = SSS_NULL;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/devicesocket.h \
|
|
||||||
$$PWD/server.h \
|
$$PWD/server.h \
|
||||||
$$PWD/tcpserver.h
|
$$PWD/tcpserver.h \
|
||||||
|
$$PWD/videosocket.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/devicesocket.cpp \
|
|
||||||
$$PWD/server.cpp \
|
$$PWD/server.cpp \
|
||||||
$$PWD/tcpserver.cpp
|
$$PWD/tcpserver.cpp \
|
||||||
|
$$PWD/videosocket.cpp
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "tcpserver.h"
|
#include "tcpserver.h"
|
||||||
#include "devicesocket.h"
|
#include "videosocket.h"
|
||||||
|
|
||||||
TcpServer::TcpServer(QObject *parent) : QTcpServer(parent)
|
TcpServer::TcpServer(QObject *parent) : QTcpServer(parent)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,16 @@ TcpServer::~TcpServer()
|
||||||
|
|
||||||
void TcpServer::incomingConnection(qintptr handle)
|
void TcpServer::incomingConnection(qintptr handle)
|
||||||
{
|
{
|
||||||
DeviceSocket *socket = new DeviceSocket();
|
if (m_isVideoSocket) {
|
||||||
|
VideoSocket *socket = new VideoSocket();
|
||||||
socket->setSocketDescriptor(handle);
|
socket->setSocketDescriptor(handle);
|
||||||
addPendingConnection(socket);
|
addPendingConnection(socket);
|
||||||
|
|
||||||
|
// next is control socket
|
||||||
|
m_isVideoSocket = false;
|
||||||
|
} else {
|
||||||
|
QTcpSocket *socket = new QTcpSocket();
|
||||||
|
socket->setSocketDescriptor(handle);
|
||||||
|
addPendingConnection(socket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void incomingConnection(qintptr handle);
|
virtual void incomingConnection(qintptr handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isVideoSocket = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TCPSERVER_H
|
#endif // TCPSERVER_H
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "qscrcpyevent.h"
|
#include "qscrcpyevent.h"
|
||||||
#include "devicesocket.h"
|
#include "videosocket.h"
|
||||||
|
|
||||||
DeviceSocket::DeviceSocket(QObject *parent) : QTcpSocket(parent)
|
VideoSocket::VideoSocket(QObject *parent) : QTcpSocket(parent)
|
||||||
{
|
{
|
||||||
connect(this, &DeviceSocket::readyRead, this, &DeviceSocket::onReadyRead);
|
connect(this, &VideoSocket::readyRead, this, &VideoSocket::onReadyRead);
|
||||||
connect(this, &DeviceSocket::aboutToClose, this, &DeviceSocket::quitNotify);
|
connect(this, &VideoSocket::aboutToClose, this, &VideoSocket::quitNotify);
|
||||||
connect(this, &DeviceSocket::disconnected, this, &DeviceSocket::quitNotify);
|
connect(this, &VideoSocket::disconnected, this, &VideoSocket::quitNotify);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceSocket::~DeviceSocket()
|
VideoSocket::~VideoSocket()
|
||||||
{
|
{
|
||||||
quitNotify();
|
quitNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
|
qint32 VideoSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
|
||||||
{
|
{
|
||||||
// this function cant call in main thread
|
// this function cant call in main thread
|
||||||
Q_ASSERT(QCoreApplication::instance()->thread() != QThread::currentThread());
|
Q_ASSERT(QCoreApplication::instance()->thread() != QThread::currentThread());
|
||||||
|
@ -31,7 +31,7 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
|
||||||
m_dataSize = 0;
|
m_dataSize = 0;
|
||||||
|
|
||||||
// post event
|
// post event
|
||||||
DeviceSocketEvent* getDataEvent = new DeviceSocketEvent();
|
VideoSocketEvent* getDataEvent = new VideoSocketEvent();
|
||||||
QCoreApplication::postEvent(this, getDataEvent);
|
QCoreApplication::postEvent(this, getDataEvent);
|
||||||
|
|
||||||
// wait
|
// wait
|
||||||
|
@ -43,16 +43,16 @@ qint32 DeviceSocket::subThreadRecvData(quint8 *buf, qint32 bufSize)
|
||||||
return m_dataSize;
|
return m_dataSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceSocket::event(QEvent *event)
|
bool VideoSocket::event(QEvent *event)
|
||||||
{
|
{
|
||||||
if (event->type() == QScrcpyEvent::DeviceSocket) {
|
if (event->type() == QScrcpyEvent::VideoSocket) {
|
||||||
onReadyRead();
|
onReadyRead();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return QTcpSocket::event(event);
|
return QTcpSocket::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceSocket::onReadyRead()
|
void VideoSocket::onReadyRead()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
if (m_buffer && 0 < bytesAvailable()) {
|
if (m_buffer && 0 < bytesAvailable()) {
|
||||||
|
@ -67,7 +67,7 @@ void DeviceSocket::onReadyRead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceSocket::quitNotify()
|
void VideoSocket::quitNotify()
|
||||||
{
|
{
|
||||||
m_quit = true;
|
m_quit = true;
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
|
@ -1,17 +1,17 @@
|
||||||
#ifndef DEVICESOCKET_H
|
#ifndef VIDEOSOCKET_H
|
||||||
#define DEVICESOCKET_H
|
#define VIDEOSOCKET_H
|
||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QWaitCondition>
|
#include <QWaitCondition>
|
||||||
|
|
||||||
class DeviceSocket : public QTcpSocket
|
class VideoSocket : public QTcpSocket
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DeviceSocket(QObject *parent = nullptr);
|
explicit VideoSocket(QObject *parent = nullptr);
|
||||||
virtual ~DeviceSocket();
|
virtual ~VideoSocket();
|
||||||
|
|
||||||
qint32 subThreadRecvData(quint8* buf, qint32 bufSize);
|
qint32 subThreadRecvData(quint8* buf, qint32 bufSize);
|
||||||
|
|
||||||
|
@ -32,4 +32,4 @@ private:
|
||||||
bool m_quit = false;
|
bool m_quit = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEVICESOCKET_H
|
#endif // VIDEOSOCKET_H
|
|
@ -4,7 +4,7 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
#include "devicesocket.h"
|
#include "videosocket.h"
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
|
|
||||||
#define BUFSIZE 0x10000
|
#define BUFSIZE 0x10000
|
||||||
|
@ -199,9 +199,9 @@ static qint32 readRawPacket(void *opaque, quint8 *buf, qint32 bufSize) {
|
||||||
return AVERROR_EOF;
|
return AVERROR_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::setDeviceSocket(DeviceSocket* deviceSocket)
|
void Stream::setVideoSocket(VideoSocket* videoSocket)
|
||||||
{
|
{
|
||||||
m_deviceSocket = deviceSocket;
|
m_videoSocket = videoSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::setRecoder(Recorder *recorder)
|
void Stream::setRecoder(Recorder *recorder)
|
||||||
|
@ -214,8 +214,8 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize)
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (m_deviceSocket) {
|
if (m_videoSocket) {
|
||||||
qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize);
|
qint32 len = m_videoSocket->subThreadRecvData(buf, bufSize);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -223,7 +223,7 @@ qint32 Stream::recvData(quint8* buf, qint32 bufSize)
|
||||||
|
|
||||||
bool Stream::startDecode()
|
bool Stream::startDecode()
|
||||||
{
|
{
|
||||||
if (!m_deviceSocket) {
|
if (!m_videoSocket) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_quit.store(0);
|
m_quit.store(0);
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C"
|
||||||
#include "libavformat/avformat.h"
|
#include "libavformat/avformat.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeviceSocket;
|
class VideoSocket;
|
||||||
class Recorder;
|
class Recorder;
|
||||||
class Decoder;
|
class Decoder;
|
||||||
class Stream : public QThread
|
class Stream : public QThread
|
||||||
|
@ -38,7 +38,7 @@ public:
|
||||||
static void deInit();
|
static void deInit();
|
||||||
|
|
||||||
void setDecoder(Decoder* vb);
|
void setDecoder(Decoder* vb);
|
||||||
void setDeviceSocket(DeviceSocket* deviceSocket);
|
void setVideoSocket(VideoSocket* deviceSocket);
|
||||||
void setRecoder(Recorder* recorder);
|
void setRecoder(Recorder* recorder);
|
||||||
qint32 recvData(quint8* buf, qint32 bufSize);
|
qint32 recvData(quint8* buf, qint32 bufSize);
|
||||||
bool startDecode();
|
bool startDecode();
|
||||||
|
@ -52,7 +52,7 @@ protected:
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<DeviceSocket> m_deviceSocket;
|
QPointer<VideoSocket> m_videoSocket;
|
||||||
QAtomicInteger<qint8> m_quit;
|
QAtomicInteger<qint8> m_quit;
|
||||||
|
|
||||||
// for recorder
|
// for recorder
|
||||||
|
|
|
@ -171,11 +171,11 @@ void VideoForm::initSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
// init decoder
|
// init decoder
|
||||||
m_stream.setDeviceSocket(m_server->getDeviceSocket());
|
m_stream.setVideoSocket(m_server->getVideoSocket());
|
||||||
m_stream.startDecode();
|
m_stream.startDecode();
|
||||||
|
|
||||||
// init controller
|
// init controller
|
||||||
m_inputConvert.setDeviceSocket(m_server->getDeviceSocket());
|
m_inputConvert.setControlSocket(m_server->getControlSocket());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,20 @@ public final class DesktopConnection implements Closeable {
|
||||||
|
|
||||||
private static final String SOCKET_NAME = "qtscrcpy";
|
private static final String SOCKET_NAME = "qtscrcpy";
|
||||||
|
|
||||||
private final LocalSocket socket;
|
private final LocalSocket videoSocket;
|
||||||
private final InputStream inputStream;
|
private final FileDescriptor videoFd;
|
||||||
private final FileDescriptor fd;
|
|
||||||
|
private final LocalSocket controlSocket;
|
||||||
|
private final InputStream controlInputStream;
|
||||||
|
|
||||||
|
|
||||||
private final ControlEventReader reader = new ControlEventReader();
|
private final ControlEventReader reader = new ControlEventReader();
|
||||||
|
|
||||||
private DesktopConnection(LocalSocket socket) throws IOException {
|
private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException {
|
||||||
this.socket = socket;
|
this.videoSocket = videoSocket;
|
||||||
inputStream = socket.getInputStream();
|
this.controlSocket = controlSocket;
|
||||||
fd = socket.getFileDescriptor();
|
controlInputStream = controlSocket.getInputStream();
|
||||||
|
videoFd = videoSocket.getFileDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LocalSocket connect(String abstractName) throws IOException {
|
private static LocalSocket connect(String abstractName) throws IOException {
|
||||||
|
@ -34,35 +38,47 @@ public final class DesktopConnection implements Closeable {
|
||||||
return localSocket;
|
return localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LocalSocket listenAndAccept(String abstractName) throws IOException {
|
public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
|
||||||
LocalServerSocket localServerSocket = new LocalServerSocket(abstractName);
|
LocalSocket videoSocket;
|
||||||
|
LocalSocket controlSocket;
|
||||||
|
if (tunnelForward) {
|
||||||
|
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
|
||||||
try {
|
try {
|
||||||
return localServerSocket.accept();
|
videoSocket = localServerSocket.accept();
|
||||||
|
// send one byte so the client may read() to detect a connection error
|
||||||
|
videoSocket.getOutputStream().write(0);
|
||||||
|
try {
|
||||||
|
controlSocket = localServerSocket.accept();
|
||||||
|
} catch (IOException | RuntimeException e) {
|
||||||
|
videoSocket.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
localServerSocket.close();
|
localServerSocket.close();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
|
|
||||||
LocalSocket socket;
|
|
||||||
if (tunnelForward) {
|
|
||||||
socket = listenAndAccept(SOCKET_NAME);
|
|
||||||
// send one byte so the client may read() to detect a connection error
|
|
||||||
socket.getOutputStream().write(0);
|
|
||||||
} else {
|
} else {
|
||||||
socket = connect(SOCKET_NAME);
|
videoSocket = connect(SOCKET_NAME);
|
||||||
|
try {
|
||||||
|
controlSocket = connect(SOCKET_NAME);
|
||||||
|
} catch (IOException | RuntimeException e) {
|
||||||
|
videoSocket.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopConnection connection = new DesktopConnection(socket);
|
DesktopConnection connection = new DesktopConnection(videoSocket, controlSocket);
|
||||||
Size videoSize = device.getScreenInfo().getVideoSize();
|
Size videoSize = device.getScreenInfo().getVideoSize();
|
||||||
connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
|
connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
socket.shutdownInput();
|
videoSocket.shutdownInput();
|
||||||
socket.shutdownOutput();
|
videoSocket.shutdownOutput();
|
||||||
socket.close();
|
videoSocket.close();
|
||||||
|
controlSocket.shutdownInput();
|
||||||
|
controlSocket.shutdownOutput();
|
||||||
|
controlSocket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("checkstyle:MagicNumber")
|
@SuppressWarnings("checkstyle:MagicNumber")
|
||||||
|
@ -78,17 +94,17 @@ public final class DesktopConnection implements Closeable {
|
||||||
buffer[DEVICE_NAME_FIELD_LENGTH + 1] = (byte) width;
|
buffer[DEVICE_NAME_FIELD_LENGTH + 1] = (byte) width;
|
||||||
buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8);
|
buffer[DEVICE_NAME_FIELD_LENGTH + 2] = (byte) (height >> 8);
|
||||||
buffer[DEVICE_NAME_FIELD_LENGTH + 3] = (byte) height;
|
buffer[DEVICE_NAME_FIELD_LENGTH + 3] = (byte) height;
|
||||||
IO.writeFully(fd, buffer, 0, buffer.length);
|
IO.writeFully(videoFd, buffer, 0, buffer.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileDescriptor getFd() {
|
public FileDescriptor getVideoFd() {
|
||||||
return fd;
|
return videoFd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ControlEvent receiveControlEvent() throws IOException {
|
public ControlEvent receiveControlEvent() throws IOException {
|
||||||
ControlEvent event = reader.next();
|
ControlEvent event = reader.next();
|
||||||
while (event == null) {
|
while (event == null) {
|
||||||
reader.readFrom(inputStream);
|
reader.readFrom(controlInputStream);
|
||||||
event = reader.next();
|
event = reader.next();
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
|
|
|
@ -25,7 +25,7 @@ public final class Server {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// synchronous
|
// synchronous
|
||||||
screenEncoder.streamScreen(device, connection.getFd());
|
screenEncoder.streamScreen(device, connection.getVideoFd());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// this is expected on close
|
// this is expected on close
|
||||||
Ln.d("Screen streaming stopped");
|
Ln.d("Screen streaming stopped");
|
||||||
|
|
BIN
third_party/scrcpy-server.jar
vendored
BIN
third_party/scrcpy-server.jar
vendored
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue