QtScrcpy源码解析(1)

844 阅读2分钟

前沿

之前开发了一个云真机软件,参考的是QtScrcpy这个工程来开发。
开发的时间比较旧了,当时参考的这个工程还是一年多前了,现在回头再看看,源码解析一下这个工程,顺便也重新学习一下。
QtScrcpy地址
解析的版本是v2.1.2

自己工程结构

因为是云真机,所以走的是服务器方式,并不是本地直接连接
服务器代码是java代码,因为之前主要开发安卓,对java比较熟悉,采用的是spring-boot,通过netty框架进行通讯

整体流程-导出.png

QtScrcpy视频流处理

qtscrcpy视频播放流程-导出.png

关键代码

该代码在QtScrcpyCore中,该仓库类似于一个SDK服务
QtScrcpyCore地址

// 启动scrcpy服务
AdbProcess::execute(const QString &serial, const QStringList &args)

// server.cpp中,被动监听视频流
connect(&m_serverSocket, &QTcpServer::newConnection, this, [this]() {
    // 省略
    // 校验成功后通知连接成功
    emit serverStarted(true);
    // 省略
});

// device.cpp
connect(m_server, &Server::serverStarted, this, [this](bool success, const QString &deviceName, const QSize &size) {
    // 省略
    // 初始化socket并且开始解码
    m_stream->installVideoSocket(m_server->removeVideoSocket());
    m_stream->startDecode();
    // 省略
});

// demuxer.cpp
// 该类是一个线程,视频流在线程中不停读取解码
bool Demuxer::startDecode()
{
    if (!m_videoSocket) {
        return false;
    }
    start();
    return true;
}
// 具体实现在run中
void Demuxer::run()
{
   // 省略
    for (;;) {
        // 获取视频流包
        bool ok = recvPacket(packet);
        if (!ok) {
            // end of stream
            break;
        }
        // 将解码好的视频流包推送到ui层
        ok = pushPacket(packet);
        av_packet_unref(packet);
        if (!ok) {
            // cannot process packet (error already logged)
            break;
        }
    }
   // 省略
}

bool Demuxer::recvPacket(AVPacket *packet)
{
    quint8 header[HEADER_SIZE];
    // 读取socket数据
    qint32 r = recvData(header, HEADER_SIZE);
    if (r < HEADER_SIZE) {
        return false;
    }
    quint64 ptsFlags = bufferRead64be(header);
    quint32 len = bufferRead32be(&header[8]);
    if (av_new_packet(packet, static_cast<int>(len))) {
        qCritical("Could not allocate packet");
        return false;
    }
    // 读取socket数据
    r = recvData(packet->data, static_cast<qint32>(len));
    if (r < 0 || static_cast<quint32>(r) < len) {
        av_packet_unref(packet);
        return false;
    }
    if (ptsFlags & SC_PACKET_FLAG_CONFIG) {
        packet->pts = AV_NOPTS_VALUE;
    } else {
        packet->pts = ptsFlags & SC_PACKET_PTS_MASK;
    }
    if (ptsFlags & SC_PACKET_FLAG_KEY_FRAME) {
        packet->flags |= AV_PKT_FLAG_KEY;
    }
    packet->dts = packet->pts;
    return true;
}

qint32 Demuxer::recvData(quint8 *buf, qint32 bufSize)
{
    if (!buf || !m_videoSocket) {
        return 0;
    }
    // 实际走了socket的read函数
    qint32 len = m_videoSocket->subThreadRecvData(buf, bufSize);
    return len;
}

bool Demuxer::pushPacket(AVPacket *packet)
{
   // 省略
   bool ok = parse(packet);
   // 省略
}

bool Demuxer::parse(AVPacket *packet)
{
   // 省略
   bool ok = processFrame(packet);
   // 省略
}

bool Demuxer::processFrame(AVPacket *packet)
{
    packet->dts = packet->pts;
    // 将处理好的帧数据抛出去
    // 最终会到decoder.cpp中的onNewFrame方法中
    // registerDeviceObserver将帧传递到ui层
    emit getFrame(packet);
    return true;
}