enable png and mp4 output in SimpleOpenGL3App, see

Demos3/SimpleOpenGL3 use commandline parameter
--png_file="pngname" or
--mp4_file="video.mp4"

Thanks to http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/
This commit is contained in:
Erwin Coumans 2014-07-29 16:58:22 -07:00
parent fb01827aee
commit 0c39cda57b
4 changed files with 182 additions and 10 deletions

View File

@ -1,13 +1,18 @@
#include "../../btgui/OpenGLWindow/SimpleOpenGL3App.h"
#include "OpenGLWindow/SimpleOpenGL3App.h"
#include "Bullet3Common/b3Vector3.h"
#include "Bullet3Common/b3CommandLineArgs.h"
#include "assert.h"
#include <stdio.h>
char* gVideoFileName = 0;
char* gPngFileName = 0;
int main(int argc, char* argv[])
{
b3CommandLineArgs myArgs(argc,argv);
float dt = 1./120.f;
SimpleOpenGL3App* app = new SimpleOpenGL3App("SimpleOpenGL3App",1024,768);
app->m_instancingRenderer->setCameraDistance(13);
app->m_instancingRenderer->setCameraPitch(0);
@ -15,25 +20,40 @@ int main(int argc, char* argv[])
GLint err = glGetError();
assert(err==GL_NO_ERROR);
myArgs.GetCmdLineArgument("mp4_file",gVideoFileName);
if (gVideoFileName)
app->dumpFramesToVideo(gVideoFileName);
myArgs.GetCmdLineArgument("png_file",gPngFileName);
char fileName[1024];
do
{
static int frameCount = 0;
frameCount++;
if (gPngFileName)
{
printf("gPngFileName=%s\n",gPngFileName);
sprintf(fileName,"%s%d.png",gPngFileName,frameCount++);
app->dumpNextFrameToPng(fileName);
}
GLint err = glGetError();
assert(err==GL_NO_ERROR);
app->m_instancingRenderer->init();
app->m_instancingRenderer->updateCamera();
app->drawGrid();
char bla[1024];
static int frameCount = 0;
frameCount++;
sprintf(bla,"Simple test frame %d", frameCount);
app->drawText(bla,10,10);
app->swapBuffer();
} while (!app->m_window->requestedExit());
delete app;
return 0;
}

View File

@ -13,6 +13,7 @@
#include "OpenGLWindow/X11OpenGLWindow.h"
#endif //_WIN32
#endif//__APPLE__
#include <stdio.h>
#include "OpenGLWindow/GLPrimitiveRenderer.h"
#include "OpenGLWindow/GLInstancingRenderer.h"
@ -24,6 +25,12 @@
#include "OpenGLWindow/TwFonts.h"
#include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h"
#include <assert.h>
#include "GLRenderToTexture.h"
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#endif // _WIN32
struct SimpleInternalData
{
@ -31,6 +38,9 @@ struct SimpleInternalData
struct sth_stash* m_fontStash;
OpenGL2RenderCallbacks* m_renderCallbacks;
int m_droidRegular;
const char* m_frameDumpPngFileName;
FILE* m_ffmpegFile;
GLRenderToTexture* m_renderTexture;
};
@ -70,6 +80,10 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height)
{
gApp = this;
m_data = new SimpleInternalData;
m_data->m_frameDumpPngFileName = 0;
m_data->m_renderTexture = 0;
m_data->m_ffmpegFile = 0;
m_window = new b3gDefaultOpenGLWindow();
b3gWindowConstructionInfo ci;
ci.m_title = title;
@ -404,8 +418,143 @@ SimpleOpenGL3App::~SimpleOpenGL3App()
delete m_data ;
}
//#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "OpenGLTrueTypeFont/stb_image_write.h"
static void writeTextureToFile(int textureWidth, int textureHeight, const char* fileName, FILE* ffmpegVideo)
{
int numComponents = 4;
//glPixelStorei(GL_PACK_ALIGNMENT,1);
GLuint err=glGetError();
assert(err==GL_NO_ERROR);
//glReadBuffer(GL_BACK);//COLOR_ATTACHMENT0);
err=glGetError();
assert(err==GL_NO_ERROR);
float* orgPixels = (float*)malloc(textureWidth*textureHeight*numComponents*4);
glReadPixels(0,0,textureWidth, textureHeight, GL_RGBA, GL_FLOAT, orgPixels);
//it is useful to have the actual float values for debugging purposes
//convert float->char
char* pixels = (char*)malloc(textureWidth*textureHeight*numComponents);
err=glGetError();
assert(err==GL_NO_ERROR);
for (int j=0;j<textureHeight;j++)
{
for (int i=0;i<textureWidth;i++)
{
pixels[(j*textureWidth+i)*numComponents] = orgPixels[(j*textureWidth+i)*numComponents]*255.f;
pixels[(j*textureWidth+i)*numComponents+1]=orgPixels[(j*textureWidth+i)*numComponents+1]*255.f;
pixels[(j*textureWidth+i)*numComponents+2]=orgPixels[(j*textureWidth+i)*numComponents+2]*255.f;
pixels[(j*textureWidth+i)*numComponents+3]=orgPixels[(j*textureWidth+i)*numComponents+3]*255.f;
}
}
if (ffmpegVideo)
{
fwrite(pixels, textureWidth*textureHeight*numComponents, 1, ffmpegVideo);
//fwrite(pixels, 100,1,ffmpegVideo);//textureWidth*textureHeight*numComponents, 1, ffmpegVideo);
} else
{
if (1)
{
//swap the pixels
unsigned char tmp;
for (int j=0;j<textureHeight/2;j++)
{
for (int i=0;i<textureWidth;i++)
{
for (int c=0;c<numComponents;c++)
{
tmp = pixels[(j*textureWidth+i)*numComponents+c];
pixels[(j*textureWidth+i)*numComponents+c]=
pixels[((textureHeight-j-1)*textureWidth+i)*numComponents+c];
pixels[((textureHeight-j-1)*textureWidth+i)*numComponents+c] = tmp;
}
}
}
}
stbi_write_png(fileName, textureWidth,textureHeight, numComponents, pixels, textureWidth*numComponents);
}
free(pixels);
free(orgPixels);
}
void SimpleOpenGL3App::swapBuffer()
{
m_window->endRendering();
if (m_data->m_frameDumpPngFileName)
{
writeTextureToFile(m_instancingRenderer->getScreenWidth(),
this->m_instancingRenderer->getScreenHeight(),m_data->m_frameDumpPngFileName,
m_data->m_ffmpegFile);
//m_data->m_renderTexture->disable();
//if (m_data->m_ffmpegFile==0)
//{
// m_data->m_frameDumpPngFileName = 0;
//}
}
m_window->startRendering();
}
// see also http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/
void SimpleOpenGL3App::dumpFramesToVideo(const char* mp4FileName)
{
int width = m_instancingRenderer->getScreenWidth();
int height = m_instancingRenderer->getScreenHeight();
char cmd[8192];
sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
"-threads 0 -y -crf 0 -b 50000k -vf vflip %s",width,height,mp4FileName);
// sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
// "-threads 0 -preset fast -y -crf 21 -vf vflip %s",width,height,mp4FileName);
if (m_data->m_ffmpegFile)
{
pclose(m_data->m_ffmpegFile);
}
m_data->m_ffmpegFile = popen(cmd, "w");
m_data->m_frameDumpPngFileName = mp4FileName;
}
void SimpleOpenGL3App::dumpNextFrameToPng(const char* filename)
{
// open pipe to ffmpeg's stdin in binary write mode
m_data->m_frameDumpPngFileName = filename;
//you could use m_renderTexture to allow to render at higher resolutions, such as 4k or so
/*if (!m_data->m_renderTexture)
{
m_data->m_renderTexture = new GLRenderToTexture();
GLuint renderTextureId;
glGenTextures(1, &renderTextureId);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, renderTextureId);
// Give an empty image to OpenGL ( the last "0" )
//glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
//glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F,
m_instancingRenderer->getScreenWidth(),m_instancingRenderer->getScreenHeight()
, 0,GL_RGBA, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_data->m_renderTexture->init(m_instancingRenderer->getScreenWidth(),this->m_instancingRenderer->getScreenHeight(),renderTextureId, RENDERTEXTURE_COLOR);
}
bool result = m_data->m_renderTexture->enable();
*/
}

View File

@ -38,6 +38,9 @@ struct SimpleOpenGL3App
int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f);
int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10);
void dumpNextFrameToPng(const char* pngFilename);
void dumpFramesToVideo(const char* mp4Filename);
void drawGrid(DrawGridData data=DrawGridData());
void swapBuffer();
void drawText( const char* txt, int posX, int posY);

View File

@ -116,7 +116,7 @@ if findOpenGL() then
include "../btgui/OpenGLWindow"
-- include "../Demos3/ImplicitCloth"
-- include "../Demos3/SimpleOpenGL3"
include "../Demos3/SimpleOpenGL3"
include "../btgui/lua-5.2.3"
include "../test/lua"