I know there are similar questions to this one but I can't seem to find the solution in my own circumstances.
I've made a program using opengl and ffmpeg that uses a buffer to complete it's operations. Normally, the program runs just fine with no errors whatsoever. However when I run my application using valgrind I get this error:
==31277== Invalid read of size 16
==31277== at 0xD27852: memcpy (string_fortified.h:29)
==31277== by 0xD27852: scale_internal (swscale.c:947)
==31277== by 0xD29EE8: sws_scale (swscale.c:1213)
==31277== by 0x268BBC: Videooio::video_encoder::set_frame_yuv_from_rgb(AVFrame*, SwsContext*) (video_encoder.cpp:441)
==31277== by 0x268D18: Videooio::video_encoder::get_video_frame(Videooio::OutputStream*) (video_encoder.cpp:486)
==31277== by 0x269032: write_video_frame (video_encoder.cpp:499)
==31277== by 0x269032: Videooio::video_encoder::encode_one_frame() (video_encoder.cpp:553)
==31277== by 0x22BD89: Videooio::Application::main_loop() (Application.cpp:212)
==31277== by 0x21B007: Videooio::Application::Run() (Application.cpp:70)
==31277== by 0x219C94: main (main.cpp:22)
==31277== Address 0x50df9c8 is 744 bytes inside a block of size 752 alloc'd
==31277== at 0x4849013: operator new(unsigned long) (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==31277== by 0x21A970: Videooio::Application::Run() (Application.cpp:40)
==31277== by 0x219C94: main (main.cpp:22)
I've diagnosed the problem down to the following lines but I'm not quite sure how to fix it:
Application.cpp
void Run()
{
...
40 encoder = new video_encoder(width, height, fps, duration);
...
while (second < duration)
{
auto* fbo = opengl_engine.glBuffer;
encoder->set_encode_framebuffer(fbo);
212 encoder->encode_one_Frame();
}
}
video_encoder.h:
namespace Videooio{
class video_encoder{
public:
video_encoder(int w, int h, unsigned int fps, unsigned int duration);
void set_encode_framebuffer(uint8_t* data, bool audio_only = false);
void encode_one_frame();
~video_encoder();
private:
int write_frame(AVFormatContext *fmt_ctx, AVCodecContext *c,
AVStream *st, AVFrame *frame, AVPacket *pkt);
AVFrame *get_video_frame(OutputStream *ost);
int write_video_frame(AVFormatContext *oc, OutputStream *ost);
uint8_t *rgb_data;
int width;
int height;
void set_frame_yuv_from_rgb(AVFrame *frame, struct SwsContext *sws_context);
};
}
Here is opengl_engine, where fbo is allocated:
...
if (posix_memalign((void**)&glBuffer, 128, (gl_width * gl_height * 4) ) != 0)
{
ERROR("Couldn't allocate frame buffer ");
return false;
}
...
Here is where I set the rgb_data that is inside the encoder (Probably the culprit too) is set to the allocated fbo:
void video_encoder::set_audio_frame(AVFrame* audio, AVSampleFormat* format)
{
audio_data = *audio;
input_sample_fmt = *format;
}
rgb_data
is set uninitialized up until this point before it's usage (I've tried mallocing it inside the constructor, which was a horrible practice, but doing so changed nothing.).
And here is where it's used and where valgrind mentions:
void video_encoder::set_frame_yuv_from_rgb(AVFrame *frame, struct SwsContext
*sws_context) {
const int in_linesize[1] = { 4 * width };
//uint8_t* dest[4] = { rgb_data, NULL, NULL, NULL };
sws_context = sws_getContext(
width, height, AV_PIX_FMT_RGBA,
width, height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, 0, 0, 0);
440 std::cout << "Address: " << rgb_data << std::endl;
441 sws_scale(sws_context, (const uint8_t * const *)&rgb_data, in_linesize, 0,
442 height, frame->data, frame->linesize);
}
I'm not 0 sure whether rgb_data
is causing this error or not but digging into sws_scale
and finding where memcpy
is used shows that rgb_data
is used inside it.
I've tried changing the buffer size of glBuffer
to no avail since valgrind allways says 744 bytes inside a block of size 752
the size of which the error mentions is not changing when I change glBuffer
s size, this led me to believe that rgb_data
might not be the culprit. But it's still my best bet.
I've looked into these questions but I just can't seem to apply them to my own circumstance.
I'm using ubuntu.
CodePudding user response:
Looks like an ffmpeg bug. ffmpeg is reading 4 source strides and 4 source pointers but (if the pixel format is packed) only cares about the first one.
You could pass an array of 4, or add some extra padding to the end of class video_encoder
so that ffmpeg reads allocated memory, or move rgb_data earlier in the class so that the members after it act as padding. It doesn't matter if there are valid pointers there.