Qt编程:QtScrcpyCore 中 DeviceObserver 类

    在 QtScrcpy 项目中,DeviceObserver 是 QtScrcpy 项目中的核心接口类,作为连接底层设备操作和上层 UI 交互的关键桥梁。其作为核心观察者接口,在 QtScrcpyCore(核心层)和 QtScrcpy(UI层)之间扮演着 桥梁 角色,其设计体现了清晰的分层架构和观察者模式的应用。

DeviceObserver类角色定位

1.1 设计模式

  • 观察者模式:作为抽象观察者接口,允许具体观察者(如 VideoForm)订阅设备事件

  • 桥接模式:连接设备核心功能模块与UI表示层

1.2 架构层次

QtScrcpy (UI层)
│
├── VideoForm
├── Controller
│
QtScrcpyCore (核心层)
│
├── DeviceObserver (接口)
├── Device (被观察者)
└── InputManager
QtScrcpyCore(核心层)
  • 职责:处理底层设备连接、视频流解码、输入控制等核心逻辑。

  • 关键类

    • Device:代表物理设备,管理ADB连接和原始数据流。

    • InputManager:负责将输入事件转换为ADB命令。

    • DeviceObserver:作为抽象接口,定义核心层向UI层通知的事件(如视频帧、输入事件等)。

QtScrcpy(UI层)
  • 职责:实现用户界面、渲染视频、处理用户交互。

  • 关键类

    • VideoForm:继承自 DeviceObserver,接收视频帧并渲染到界面。

    • Controller:处理用户输入(鼠标/键盘),通过核心层转发到设备。

接口功能分类

    DeviceObserver 定义了 两类关键接口,分别用于 数据上行控制下行

数据上行(Core → UI)

    核心层通过这些接口向UI层推送实时数据:

// 视频帧回调(YUV格式)
virtual void onFrame(int width, int height, uint8_t* dataY, uint8_t* dataU, uint8_t* dataV, ...);

// 帧率更新
virtual void updateFPS(quint32 fps);

// 设备剪贴板内容回调
virtual void onDeviceClipboardUpdated(const QString& text);
控制下行(UI → Core)

    UI层通过实现这些接口向核心层发送控制命令:

// 输入事件(UI层捕获用户操作后调用)
virtual void mouseEvent(const QMouseEvent* event, const QSize& frameSize);
virtual void keyEvent(const QKeyEvent* event);

// 系统命令(如返回键、音量控制)
virtual void postGoBack();
virtual void postVolumeUp();

2.1 视频数据通道

virtual void onFrame(int width, int height, 
                    uint8_t* dataY, uint8_t* dataU, uint8_t* dataV,
                    int linesizeY, int linesizeU, int linesizeV);
  • 参数说明

    • YUV420格式视频帧数据

    • linesize包含内存对齐的步长信息

  • 调用频率:每帧调用,典型60fps设备约16ms调用一次

2.2 输入事件通道

virtual void mouseEvent(const QMouseEvent* from, 
                       const QSize& frameSize,
                       const QSize& showSize);
  • 坐标转换

    • frameSize:设备物理分辨率(如1080x1920)

    • showSize:实际显示区域(可能缩放后)

  • 事件映射:将Qt事件转换为Android输入协议

2.3 系统控制通道

virtual void postGoBack();  // KEYCODE_BACK
virtual void postPower();   // KEYCODE_POWER
virtual void setScreenPowerMode(bool open);  // 屏幕唤醒/休眠

典型工作流程

3.1 视频流处理流程

  1. 核心层:通过ADB获取设备视频流,解码为YUV格式。

  2. 通知UI:调用 VideoForm::onFrame(),传递YUV数据。

  3. UI层:在 QYUVOpenGLWidget 中渲染帧数据。

 

3.2 输入事件流程

  1. UI层VideoForm 捕获鼠标点击事件。

  2. 转发到核心层:调用 mouseEvent(),核心层通过 InputManager 将其转换为ADB触摸事件。

  3. 设备执行:ADB命令发送到设备,触发实际点击。

UI层中使用

     针对DeviceObserver继承具体实现类和注册观察者

UI层VideoForm 类

class ToolForm;
class FileHandler;
class QYUVOpenGLWidget;
class QLabel;
class VideoForm : public QWidget, public qsc::DeviceObserver
{
    Q_OBJECT
public:
    explicit VideoForm(bool framelessWindow = false, bool skin = true, QWidget *parent = 0);
    ~VideoForm();

    void staysOnTop(bool top = true);
    void updateShowSize(const QSize &newSize);
    void updateRender(int width, int height, uint8_t* dataY, uint8_t* dataU, uint8_t* dataV, int linesizeY, int linesizeU, int linesizeV);
    void setSerial(const QString& serial);
    QRect getGrabCursorRect();
    const QSize &frameSize();
    void resizeSquare();
    void removeBlackRect();
    void showFPS(bool show);
    void switchFullScreen();

    bool isHost();

private:
    void onFrame(int width, int height, uint8_t* dataY, uint8_t* dataU, uint8_t* dataV,
                 int linesizeY, int linesizeU, int linesizeV) override;
    void updateFPS(quint32 fps) override;
    void grabCursor(bool grab) override;

    void updateStyleSheet(bool vertical);
    QMargins getMargins(bool vertical);
    void initUI();

    void showToolForm(bool show = true);
    void moveCenter();
    void installShortcut();
    QRect getScreenRect();

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;
    void keyReleaseEvent(QKeyEvent *event) override;

    void paintEvent(QPaintEvent *) override;
    void showEvent(QShowEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
    void closeEvent(QCloseEvent *event) override;

    void dragEnterEvent(QDragEnterEvent *event) override;
    void dragMoveEvent(QDragMoveEvent *event) override;
    void dragLeaveEvent(QDragLeaveEvent *event) override;
    void dropEvent(QDropEvent *event) override;

private:
    // ui
    Ui::videoForm *ui;
    QPointer<ToolForm> m_toolForm;
    QPointer<QWidget> m_loadingWidget;
    QPointer<QYUVOpenGLWidget> m_videoWidget;
    QPointer<QLabel> m_fpsLabel;

    //inside member
    QSize m_frameSize;
    QSize m_normalSize;
    QPoint m_dragPosition;
    float m_widthHeightRatio = 0.5f;
    bool m_skin = true;
    QPoint m_fullScreenBeforePos;
    QString m_serial;
};

VideoForm 是 QtScrcpy 中负责视频显示和设备交互的核心窗口类,继承自 QWidget 和 qsc::DeviceObserver。

继承关系
  • 继承 QWidget:作为可视化窗口组件

  • 继承 qsc::DeviceObserver:实现设备观察者接口

主要职责
  1. 视频帧的渲染显示

  2. 用户输入事件处理

  3. 设备控制界面管理

  4. 窗口样式和行为控制

UI层GroupController类

#include "QtScrcpyCore.h"

class GroupController : public QObject, public qsc::DeviceObserver
{
    Q_OBJECT
public:
    static GroupController& instance();

    void updateDeviceState(const QString& serial);
    void addDevice(const QString& serial);
    void removeDevice(const QString& serial);

private:
    // DeviceObserver
    void mouseEvent(const QMouseEvent *from, const QSize &frameSize, const QSize &showSize) override;
    void wheelEvent(const QWheelEvent *from, const QSize &frameSize, const QSize &showSize) override;
    void keyEvent(const QKeyEvent *from, const QSize &frameSize, const QSize &showSize) override;

    void postGoBack() override;
    void postGoHome() override;
    void postGoMenu() override;
    void postAppSwitch() override;
    void postPower() override;
    void postVolumeUp() override;
    void postVolumeDown() override;
    void postCopy() override;
    void postCut() override;
    void setScreenPowerMode(bool open) override;
    void expandNotificationPanel() override;
    void collapsePanel() override;
    void postBackOrScreenOn(bool down) override;
    void postTextInput(QString &text) override;
    void requestDeviceClipboard() override;
    void setDeviceClipboard(bool pause = true) override;
    void clipboardPaste() override;
    void pushFileRequest(const QString &file, const QString &devicePath = "") override;
    void installApkRequest(const QString &apkFile) override;
    void screenshot() override;
    void showTouch(bool show) override;

private:
    explicit GroupController(QObject *parent = nullptr);
    bool isHost(const QString& serial);
    QSize getFrameSize(const QString& serial);

private:
    QVector<QString> m_devices;
};

GroupController 是一个实现设备群控功能的类,继承自 QObject 和 qsc::DeviceObserver,用于管理多个 Android 设备并同步控制它们。

继承关系
  • 继承 QObject:获得 Qt 对象系统的支持(信号槽、父子对象管理等)

  • 继承 qsc::DeviceObserver:实现设备观察者接口,处理设备输入输出

设计模式

  • 单例模式:通过 instance() 静态方法获取唯一实例

  • 观察者模式:继承 DeviceObserver 实现对设备事件的观察

线程模型分析

4.1 关键线程

  • 视频解码线程:调用onFrame()

  • UI主线程:处理渲染和用户输入

  • ADB I/O线程:处理设备通信

4.2 线程安全实践

// 视频线程到UI线程的帧数据传递
void VideoForm::onFrame(...) {
    QMetaObject::invokeMethod(this, [=](){
        // 实际渲染操作
    }, Qt::QueuedConnection);
}

总结

  1. 解耦核心与UI

    • 核心层不依赖具体UI实现,只需调用 DeviceObserver 接口。

    • UI层自由选择如何渲染视频或处理输入(如支持OpenGL或软件渲染)。

  2. 多平台扩展性
    通过实现 DeviceObserver,可轻松适配不同UI框架(如Qt/WxWidgets)或平台(Windows/Linux)。

  3. 事件驱动的异步模型
    核心层通过回调通知UI层,避免轮询,提高效率。

  4. 单一职责原则

    • QtScrcpyCore 专注设备通信和数据流。

    • QtScrcpy 专注用户交互和渲染。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值