c++ – FFmpeg sws_scale causes heap corruption (Aborted / double free) when writing to QImage
I am developing a video player in C++ using FFmpeg and Qt. I am trying to convert video frames from YUV420P to RGBA using sws_scale and store the result in a QImage. However, my application crashes with Aborted (SIGABRT) or double free or corruption at the sws_freeContext line. The first frame often processes, but the second one crashes.
I am requesting AV_PIX_FMT_RGBA in sws_getContext, but the context is being initialized with dst_format = 26. Is it possible that sws_scale is internally overriding the format, and how can I force it to use RGBA to match my QImage format?
ffmpeg version n8.1.1
The terminal output shows a critical heap corruption error: corrupted size vs. prev_size.
this is swsCtx: enter image description here
Code:
while (av_read_frame(formatContext, packet) >= 0)
{
if (packet->stream_index == videoStreamIndex) {
if (avcodec_send_packet(codecContext, packet) == 0) {
while (avcodec_receive_frame(codecContext, frame) == 0) {
// FRAME LOAD
QImage image = renderFrame(frame, codecContext);
sentToSink(image, sink);
av_frame_unref(frame);
}
} else
qDebug() << "Couldn't send packet";
}
av_packet_unref(packet);
}
QImage MediaPlayer::renderFrame(AVFrame *frame, AVCodecContext *codecCntx)
{
SwsContext *swsCtx = sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format, frame->width, frame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
QImage image(frame->width, frame->height, QImage::Format_RGB32);
uint8_t *dest[4] {image.bits(), nullptr, nullptr, nullptr};
int destLinesize[4] {static_cast(image.bytesPerLine()), 0, 0, 0};
sws_scale(swsCtx, frame->data, frame->linesize, 0, frame->height, dest, destLinesize);
sws_freeContext(swsCtx); // Crush occurs here
return image;
}
void MediaPlayer::sentToSink(QImage &image, QVideoSink *sink)
{
QVideoFrameFormat format(image.size(), QVideoFrameFormat::Format_RGBA8888);
QVideoFrame frame(format);
if (frame.map(QVideoFrame::WriteOnly)) {
memcpy(frame.bits(0), image.constBits(), image.sizeInBytes());
frame.unmap();
sink->setVideoFrame(frame);
}
}
Read more here: Source link
