#include "VideoReceiver.h" #include VideoReceiver::VideoReceiver(QObject *parent) : QThread(parent) { } VideoReceiver::~VideoReceiver() { } void VideoReceiver::run() { QTcpSocket socket; socket.connectToHost("127.0.0.1", 27183); if (!socket.waitForConnected(3000)) { qWarning() << "Unable to connect to scrcpy stream"; return; } else { qDebug() << "Connected to scrcpy stream"; } // No need for explicit avcodec_register_all() with modern FFmpeg const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) { qCritical() << "H264 codec not found"; return; } m_codecCtx = avcodec_alloc_context3(codec); if (avcodec_open2(m_codecCtx, codec, nullptr) < 0) { qCritical() << "Failed to open codec"; return; } m_parser = av_parser_init(AV_CODEC_ID_H264); AVPacket *pkt = av_packet_alloc(); AVFrame *frame = av_frame_alloc(); // Delay determining width/height until after first frame if unknown SwsContext *swsCtx = nullptr; uint8_t *rgbData[4] = {nullptr}; int rgbLinesize[4] = {0}; QByteArray buffer; while (socket.waitForReadyRead()) { buffer.append(socket.readAll()); const uint8_t *data = reinterpret_cast(buffer.constData()); int dataSize = buffer.size(); while (dataSize > 0) { int len = av_parser_parse2(m_parser, m_codecCtx, &pkt->data, &pkt->size, data, dataSize, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); if (len < 0) break; data += len; dataSize -= len; if (pkt->size > 0) { avcodec_send_packet(m_codecCtx, pkt); while (avcodec_receive_frame(m_codecCtx, frame) == 0) { // Initialize scaler and buffers when frame size known if (!swsCtx) { m_dstWidth = frame->width; m_dstHeight = frame->height; swsCtx = sws_getContext( m_dstWidth, m_dstHeight, m_codecCtx->pix_fmt, m_dstWidth, m_dstHeight, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr ); av_image_alloc(rgbData, rgbLinesize, m_dstWidth, m_dstHeight, AV_PIX_FMT_RGB24, 1); } // Convert to RGB sws_scale(swsCtx, frame->data, frame->linesize, 0, m_dstHeight, rgbData, rgbLinesize); QImage img(rgbData[0], m_dstWidth, m_dstHeight, rgbLinesize[0], QImage::Format_RGB888); emit frameReady(img.copy()); } } } buffer.clear(); } if (rgbData[0]) av_freep(&rgbData[0]); if (swsCtx) sws_freeContext(swsCtx); av_frame_free(&frame); av_packet_free(&pkt); av_parser_close(m_parser); avcodec_free_context(&m_codecCtx); }