Skip to content

Commit

Permalink
H264Libav: Use AVFrame for pixel format conversion buffer
Browse files Browse the repository at this point in the history
This ensures that the buffer is allocated with the correct alignment and
padding for use with sws_scale.

This fixes out-of-bounds writes which would in some cases cause
segmentation faults and/or heap corruption.

(cherry picked from commit fff17ca)
  • Loading branch information
any1 authored and LMattsson committed Oct 22, 2024
1 parent 4c573f8 commit 9724ea0
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 12 deletions.
27 changes: 17 additions & 10 deletions common/rfb/H264LibavDecoderContext.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ bool H264LibavDecoderContext::initCodec() {
os::AutoMutex lock(&mutex);

sws = NULL;
swsBuffer = NULL;
h264WorkBuffer = NULL;
h264WorkBufferLength = 0;

Expand Down Expand Up @@ -87,9 +86,6 @@ bool H264LibavDecoderContext::initCodec() {
return false;
}

int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB32, rect.width(), rect.height(), 1);
swsBuffer = new uint8_t[numBytes];

initialized = true;
return true;
}
Expand All @@ -101,8 +97,8 @@ void H264LibavDecoderContext::freeCodec() {
return;
av_parser_close(parser);
avcodec_free_context(&avctx);
av_frame_free(&rgbFrame);
av_frame_free(&frame);
delete[] swsBuffer;
free(h264WorkBuffer);
initialized = false;
}
Expand Down Expand Up @@ -220,11 +216,22 @@ void H264LibavDecoderContext::decode(const uint8_t* h264_in_buffer,
frame->width, frame->height, AV_PIX_FMT_RGB32,
0, NULL, NULL, NULL);

int stride;
pb->getBuffer(rect, &stride);
int dst_linesize = stride * pb->getPF().bpp/8; // stride is in pixels, linesize is in bytes (stride x4). We need bytes
if (rgbFrame && (rgbFrame->width != frame->width || rgbFrame->height != frame->height)) {
av_frame_free(&rgbFrame);

}

if (!rgbFrame) {
rgbFrame = av_frame_alloc();
// TODO: Can we really assume that the pixel format will always be RGB32?
rgbFrame->format = AV_PIX_FMT_RGB32;
rgbFrame->width = frame->width;
rgbFrame->height = frame->height;
av_frame_get_buffer(rgbFrame, 0);
}

sws_scale(sws, frame->data, frame->linesize, 0, frame->height, &swsBuffer, &dst_linesize);
sws_scale(sws, frame->data, frame->linesize, 0, frame->height, rgbFrame->data,
rgbFrame->linesize);

pb->imageRect(rect, swsBuffer, stride);
pb->imageRect(rect, rgbFrame->data[0], rgbFrame->linesize[0] / 4);
}
5 changes: 3 additions & 2 deletions common/rfb/H264LibavDecoderContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ extern "C" {
namespace rfb {
class H264LibavDecoderContext : public H264DecoderContext {
public:
H264LibavDecoderContext(const Rect &r) : H264DecoderContext(r) {}
H264LibavDecoderContext(const Rect &r)
: H264DecoderContext(r), rgbFrame(NULL) {}
~H264LibavDecoderContext() { freeCodec(); }

virtual void decode(const uint8_t* h264_buffer, uint32_t len,
Expand All @@ -47,8 +48,8 @@ namespace rfb {
AVCodecContext *avctx;
AVCodecParserContext *parser;
AVFrame* frame;
AVFrame* rgbFrame;
SwsContext* sws;
uint8_t* swsBuffer;
uint8_t* h264WorkBuffer;
uint32_t h264WorkBufferLength;
};
Expand Down

0 comments on commit 9724ea0

Please sign in to comment.