1
0
forked from BRT/arc
arc/VideoReceiver.cpp
2025-05-24 15:19:27 +07:00

92 lines
3.2 KiB
C++

#include "VideoReceiver.h"
#include <QDebug>
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<const uint8_t *>(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);
}