Skip to content

Instantly share code, notes, and snippets.

@iamgreaser
Created November 11, 2015 21:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamgreaser/bcf5d11f45a07daffdcc to your computer and use it in GitHub Desktop.
Save iamgreaser/bcf5d11f45a07daffdcc to your computer and use it in GitHub Desktop.
kkrotchbulge - SDL2+GL capture on Linux & BSD
// kkrotchbulge: a cheap nasty hack to capture 60fps vids on Linux & BSD systems / GreaseMonkey, 2015 - Public Domain
// note, only does video right now, and only handles SDL2 + GL.
// compile+render: cc -fPIC -shared -o libkkrotchbulge.so kkrotchbulge.c -I/usr/local/include `sdl2-config --cflags` -L/usr/local/lib -lGL && env LD_PRELOAD=./libkkrotchbulge.so ./tfiy
// transcode (in another terminal): ffmpeg -s 1280x720 -r 60 -pix_fmt rgba -f rawvideo -i kkrotchbulge-out-vid tfiy-vid.mkv
// combine audio: ffmpeg -i tfiy-vid.mkv -i dat/ds15rel-gm.ogg -acodec copy -vcodec copy tfiy-60fps.mkv
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <epoxy/gl.h>
#include <SDL.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
// bypass epoxy shim
#undef glReadPixels
GLAPI void GLAPIENTRY glReadPixels( GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
GLvoid *pixels );
#undef glFinish
GLAPI void GLAPIENTRY glFinish( void );
#undef glFlush
GLAPI void GLAPIENTRY glFlush( void );
//
static uint64_t frame_counter = 0;
static int outfp_vid = -1;
static int outfp_aud = -1;
DECLSPEC void SDLCALL SDL_GL_SwapWindow(SDL_Window *window)
{
static void (*f_next)(SDL_Window *) = NULL;
static uint8_t *pbuf = NULL;
static int old_wnd_w = -1;
static int old_wnd_h = -1;
if(f_next == NULL)
f_next = dlsym(RTLD_NEXT, "SDL_GL_SwapWindow");
if(outfp_vid == -1)
{
mkfifo("kkrotchbulge-out-vid", 0660);
outfp_vid = open("kkrotchbulge-out-vid", O_WRONLY);
assert(outfp_vid >= 3);
}
frame_counter++;
glFlush();
int wnd_w, wnd_h;
SDL_GetWindowSize(window, &wnd_w, &wnd_h);
assert(wnd_w > 0);
assert(wnd_h > 0);
assert(wnd_w < 32000);
assert(wnd_h < 32000);
if(wnd_w != old_wnd_w || wnd_h != old_wnd_h)
{
if(pbuf != NULL)
free(pbuf);
pbuf = malloc(((uint64_t)wnd_w)*((uint64_t)wnd_h)*(uint64_t)4);
old_wnd_w = wnd_w;
old_wnd_h = wnd_h;
}
glFinish();
glReadPixels(0, 0, wnd_w, wnd_h, GL_RGBA, GL_UNSIGNED_BYTE, pbuf);
glFinish();
// Y-flip
int y;
for(y = 0; y < wnd_h; y++)
write(outfp_vid, pbuf + wnd_w*4*(wnd_h-1-y), wnd_w*4);
fsync(outfp_vid);
f_next(window);
}
extern DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
{
return (Uint32)((frame_counter * (uint64_t)1000) / (uint64_t)60);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment