Home | Programming | C++ | OpenGL screenshots
RSS Githublogo Youtubelogo higgs.at kovacs.cf

There are various reasons for taking a screenshot of an OpenGL-application from within (initiated by the program itself and not the user). One may just want to take a screenshot here and there for documentation or even print every frame and create a video with these pictures. Most programs for screen recording are inferior in quality and frame management. Taking a screenshot every frame gives the user the control over the quality. In certain cases real time screen capturing can not generate a fluid video. Mostly because calculations between frames are taking too long and are not constant so speeding up the captured video is not an option.

The C++ function below will take a screenshot from the current OpenGL window:
bool screenshot_png(const std::string& filename, int width, int height, std::vector<unsigned char>& pixel)
{

   glReadPixels(0, 0, wnd_width, height, GL_RGBA, GL_UNSIGNED_BYTE, &pixel[0]);

   FILE *fp = fopen(filename.c_str(), "wb");

   if(fp == 0)
      return false;

   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);

   if(png_ptr == 0)
   {
      fclose(fp);
      return false;
   }

   png_infop info_ptr = png_create_info_struct(png_ptr);

   if(info_ptr == 0)
   {
      fclose(fp);
      png_destroy_write_struct(&png_ptr, png_infopp_NULL);
      return false;
   }

   png_init_io(png_ptr, fp);
   png_set_IHDR(png_ptr, info_ptr, wnd_width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
   png_write_info(png_ptr, info_ptr);

   std::vector<png_bytep> row_pointers(height);

   for(int i=0; i < height; ++i)
   {
      int ii = height - i - 1;
      row_pointers[ii] = &pixel[i * wnd_width * 4];
   }

   png_write_image(png_ptr, &row_pointers[0]);

   png_write_end(png_ptr, info_ptr);
   png_destroy_write_struct(&png_ptr, &info_ptr);
   fclose(fp);

   return true;
}

   const size_t format_nchannels = 4;
   std::vector<unsigned char> pixel_store(format_nchannels * wnd_width * wnd_height);
   screenshot_png(filename, wnd_width, wnd_height, pixel_store);

The best option for recording the screen i found was recordmydesktop which was not providing a sufficient quality.

Taking a PNG-screenshot every frame and then converting these screenshots into a video with ffmpeg yields a satisfying output video.

The command used to create the video:
ffmpeg -framerate 50 -i png_screen%d.png -c:v libx264 -preset 0 -crf 0 -r 30 -pix_fmt yuv420p output.mp4

Rendering the screen directly into a file and not displaying anything on the screen (offscreen rendering) is not faster than onscreen rendering if nothing can be done parallel.

Comparison between recordmydesktop and the PNG-screen render-method:

recordmydesktop
screen render

Note: Both videos above have been made with the best knowledge on the day of creation. Others may achieve better results with recordmydesktop (depending on their knowledge and hardware). Nevertheless in my optinion creating the video from screenshots gives more control over the quality of the resulting video.