Guard RGB conversion bounds and use padded frames in file playback

This commit is contained in:
evgeny committed 2026-10-17 01:28:42 +02:00
1 parent f81b93ad0d
commit 64bbbdc631
3 files changed
+76 -7

No files matched your search

+14 -7
View File
@@ -1,5 +1,6 @@
#include <QCoreApplication>
#include "videoplayer_engine.h"
#include "video_frame_image.h"
#include "sound_manager.h"
#include "../../lib/debug_config.h"
@@ -200,14 +201,20 @@ void Worker::run() {
int gen = epoch->loadRelaxed();
auto emitFrame = [&](AVFrame* fr) {
if (fr->pts == AV_NOPTS_VALUE) return; /* кадр без pts ломает очередь */
QImage img(vw, vh, QImage::Format_RGB888);
uint8_t* dst[1] = { img.bits() };
int dstStride[1] = { (int)img.bytesPerLine() };
sws_scale(sws, fr->data, fr->linesize, 0, vh, dst, dstStride);
if (fr->pts == AV_NOPTS_VALUE) return true; /* кадр без pts ломает очередь */
QImage img = video_frame_image(vw, vh);
if (img.isNull()) { worker_fail(this, QCoreApplication::translate("ChatGui", "alloc failed")); return false; }
uint8_t* dst[4] = { img.bits(), nullptr, nullptr, nullptr };
int dstStride[4] = { (int)img.bytesPerLine(), 0, 0, 0 };
int rows = sws_scale(sws, fr->data, fr->linesize, 0, vh, dst, dstStride);
if (rows != vh) {
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "VideoEngine: RGB conversion failed size=%dx%d stride=%d rows=%d", vw, vh, dstStride[0], rows);
worker_fail(this, QCoreApplication::translate("ChatGui", "Video frame conversion failed")); return false;
}
qint64 ptsMs = av_rescale_q(fr->pts, vst->time_base, AVRational{1, 1000});
buffered->fetchAndAddRelaxed(1);
emit frameDecoded(img, ptsMs, gen);
return true;
};
bool eof = false;
@@ -232,7 +239,7 @@ void Worker::run() {
int ret = av_read_frame(fmt, pkt);
if (ret < 0) {
avcodec_send_packet(vdec, nullptr);
while (avcodec_receive_frame(vdec, frame) == 0) emitFrame(frame);
while (avcodec_receive_frame(vdec, frame) == 0) if (!emitFrame(frame)) { cleanup(); return; }
eof = true;
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "VideoEngine: decode finished");
emit finished();
@@ -240,7 +247,7 @@ void Worker::run() {
}
if (pkt->stream_index == vidx) {
avcodec_send_packet(vdec, pkt);
while (avcodec_receive_frame(vdec, frame) == 0) emitFrame(frame);
while (avcodec_receive_frame(vdec, frame) == 0) if (!emitFrame(frame)) { cleanup(); return; }
}
av_packet_unref(pkt);
}