diff --git a/tools/chatgui/src/call_video_decoder.cpp b/tools/chatgui/src/call_video_decoder.cpp index 49c619f7..07be4ec9 100644 --- a/tools/chatgui/src/call_video_decoder.cpp +++ b/tools/chatgui/src/call_video_decoder.cpp @@ -1,4 +1,5 @@ #include "call_video_decoder.h" +#include "video_frame_image.h" #include "debug_config.h" #include "../../../src/call/call_video_bitstream.h" #include @@ -88,7 +89,7 @@ bool CallVideoDecoder::decode(const call_video_frame& f, QImage& image) { valid = valid && (m->codec->profile == profile || (f.format.codec == CALL_VIDEO_H264 && f.format.profile == CALL_VIDEO_BASELINE && m->codec->profile == AV_PROFILE_H264_BASELINE)); if (valid) { - QImage output(decoded->width, decoded->height, QImage::Format_RGB888); + QImage output = video_frame_image(decoded->width, decoded->height); m->scale = sws_getCachedContext(m->scale, decoded->width, decoded->height, AV_PIX_FMT_YUV420P, decoded->width, decoded->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); if (!m->scale || output.isNull()) valid = false; diff --git a/tools/chatgui/src/streamplayer_window.cpp b/tools/chatgui/src/streamplayer_window.cpp index 18f406f3..ebc546b1 100644 --- a/tools/chatgui/src/streamplayer_window.cpp +++ b/tools/chatgui/src/streamplayer_window.cpp @@ -1,5 +1,6 @@ #include "streamplayer_window.h" #include "videoplayer_window.h" +#include "video_frame_image.h" #include "sound_manager.h" #include "../transport/stream_bridge.h" #include @@ -178,8 +179,8 @@ void StreamPlayerWindow::tick() { } if (!image.isNull()) { m_render->setFrame(image); m_status->setText(text("Live")); - if (first) DEBUG_INFO(DEBUG_CATEGORY_STREAM, "desktop first frame id=%llu %dx%d", (unsigned long long)p.id, - image.width(), image.height()); + if (first) DEBUG_INFO(DEBUG_CATEGORY_STREAM, "desktop first frame id=%llu %dx%d RGB_stride=%lld", + (unsigned long long)p.id, image.width(), image.height(), (long long)image.bytesPerLine()); emit framePresented(); } if (finished) { m_status->setText(text("Stream ended")); m_audio.close(); m_timer.stop(); } @@ -284,7 +285,7 @@ void StreamPlayerWindow::decode() { if (pts < p.clock(nowUs()) - 100000) { discarded++; continue; } } converter = sws_getCachedContext(converter, frame->width, frame->height, (AVPixelFormat)frame->format, frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr); - QImage image(frame->width, frame->height, QImage::Format_RGB888); + QImage image = video_frame_image(frame->width, frame->height); if (!converter || image.isNull()) { fail(text("Stream video conversion failed")); p.running = false; return; } uint8_t* destination[] = {image.bits(), nullptr, nullptr, nullptr}; int strides[] = {(int)image.bytesPerLine(), 0, 0, 0}; diff --git a/tools/chatgui/src/video_frame_image.h b/tools/chatgui/src/video_frame_image.h new file mode 100644 index 00000000..007b1cff --- /dev/null +++ b/tools/chatgui/src/video_frame_image.h @@ -0,0 +1,33 @@ +/* RGB888 для sws_scale: FFmpeg выделяет выровненные строки и запас для SIMD. + * QImage разделяет буфер без копирования; последний владелец освобождает AVFrame. */ +#pragma once + +#ifdef HAVE_FFMPEG +#include +#include "debug_config.h" +extern "C" { +#include +} + +inline QImage video_frame_image(int width, int height) { + AVFrame* frame = av_frame_alloc(); + if (!frame) { + DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "video RGB frame allocation failed size=%dx%d", width, height); return {}; + } + frame->format = AV_PIX_FMT_RGB24; frame->width = width; frame->height = height; + int result = av_frame_get_buffer(frame, 32); + if (result < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "video RGB buffer allocation failed size=%dx%d result=%d", width, height, result); + av_frame_free(&frame); return {}; + } + QImage image(frame->data[0], width, height, frame->linesize[0], QImage::Format_RGB888, [](void* owner) { + auto* frame = static_cast(owner); av_frame_free(&frame); + }, frame); + if (image.isNull()) { + DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "video RGB image initialization failed size=%dx%d stride=%d", width, height, frame->linesize[0]); + av_frame_free(&frame); return {}; + } + DEBUG_TRACE(DEBUG_CATEGORY_VIDEO, "video RGB buffer allocated size=%dx%d stride=%d alignment=32", width, height, frame->linesize[0]); + return image; +} +#endif