alok alok - 1 month ago 26
C Question

SDL2 C++ Capturing Video of Renderer Animation/Sprite

I have an animation/sprite created using SDL2. The animation works fine when it is being rendered to a screen. But now I also want it to be recorded into a video file (locally stored). For this, I am planning on using FFmpeg APIs, to which I'll be sending a raw RGB pixel data array.

My problem is with fetching the data from SDL2 APIs.

What I've tried is:

// From http://stackoverflow.com/questions/30157164/sdl-saving-window-as-bmp
SDL_Surface *sshot = SDL_CreateRGBSurface(0, 750, 750, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
SDL_RenderReadPixels(gRenderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch);

// From https://wiki.libsdl.org/SDL_RWFromMem
char fName[50];
sprintf(fName, "/tmp/a/ss%03d.bmp", fileCnt);


char bitmap[310000];
SDL_RWops *rw = SDL_RWFromMem(bitmap, sizeof(bitmap));
SDL_SaveBMP_RW(sshot, rw, 1);




Above does not work. But dumping a single frame into a file with following code works:

SDL_SaveBMP(sshot, "/tmp/alok1/ss.bmp")


This obviously is not an acceptable solution - Writing to thousands of BMPs and then using FFmpeg from command-line to create a video.

What am I doing wrong? How do you extract data from SDL_RWops? Is the use of SDL_RWFromMem the right approach to my problem statement?

Answer

Your buffer is too small to fit specified image, hence it cannot be saved here. Increase buffer size to at least actual image size + BMP header (width*height*bpp + 54, but padding needs to be counted too (what SDL_Surface refers as pitch)).

Note that taking 3Mb from stack may get you dangerously close to overflow (but could still be fine, depends on what happened in functions prior to the one in question). Chain-calling several functions that takes big chunk of stack may very quickly deplete it. It is likely you don't really need any extra space or BMP conversion at all - like creating AVImage and copying pixels directly to it from SDL_Surface.

Also in terms of performance this kind of readback would not be great (but probably compression itself is much heavier anyway).