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:
@@ -1,13 +1,18 @@
|
|||||||
#include "../../btgui/OpenGLWindow/SimpleOpenGL3App.h"
|
#include "OpenGLWindow/SimpleOpenGL3App.h"
|
||||||
#include "Bullet3Common/b3Vector3.h"
|
#include "Bullet3Common/b3Vector3.h"
|
||||||
|
#include "Bullet3Common/b3CommandLineArgs.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
char* gVideoFileName = 0;
|
||||||
|
char* gPngFileName = 0;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
b3CommandLineArgs myArgs(argc,argv);
|
||||||
|
|
||||||
float dt = 1./120.f;
|
float dt = 1./120.f;
|
||||||
|
|
||||||
SimpleOpenGL3App* app = new SimpleOpenGL3App("SimpleOpenGL3App",1024,768);
|
SimpleOpenGL3App* app = new SimpleOpenGL3App("SimpleOpenGL3App",1024,768);
|
||||||
app->m_instancingRenderer->setCameraDistance(13);
|
app->m_instancingRenderer->setCameraDistance(13);
|
||||||
app->m_instancingRenderer->setCameraPitch(0);
|
app->m_instancingRenderer->setCameraPitch(0);
|
||||||
@@ -15,25 +20,40 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
GLint err = glGetError();
|
GLint err = glGetError();
|
||||||
assert(err==GL_NO_ERROR);
|
assert(err==GL_NO_ERROR);
|
||||||
|
|
||||||
|
myArgs.GetCmdLineArgument("mp4_file",gVideoFileName);
|
||||||
|
if (gVideoFileName)
|
||||||
|
app->dumpFramesToVideo(gVideoFileName);
|
||||||
|
|
||||||
|
myArgs.GetCmdLineArgument("png_file",gPngFileName);
|
||||||
|
char fileName[1024];
|
||||||
|
|
||||||
do
|
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();
|
GLint err = glGetError();
|
||||||
assert(err==GL_NO_ERROR);
|
assert(err==GL_NO_ERROR);
|
||||||
app->m_instancingRenderer->init();
|
app->m_instancingRenderer->init();
|
||||||
app->m_instancingRenderer->updateCamera();
|
app->m_instancingRenderer->updateCamera();
|
||||||
|
|
||||||
app->drawGrid();
|
app->drawGrid();
|
||||||
char bla[1024];
|
char bla[1024];
|
||||||
static int frameCount = 0;
|
|
||||||
frameCount++;
|
|
||||||
sprintf(bla,"Simple test frame %d", frameCount);
|
sprintf(bla,"Simple test frame %d", frameCount);
|
||||||
|
|
||||||
app->drawText(bla,10,10);
|
app->drawText(bla,10,10);
|
||||||
app->swapBuffer();
|
app->swapBuffer();
|
||||||
} while (!app->m_window->requestedExit());
|
} while (!app->m_window->requestedExit());
|
||||||
|
|
||||||
|
|
||||||
delete app;
|
delete app;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "OpenGLWindow/X11OpenGLWindow.h"
|
#include "OpenGLWindow/X11OpenGLWindow.h"
|
||||||
#endif //_WIN32
|
#endif //_WIN32
|
||||||
#endif//__APPLE__
|
#endif//__APPLE__
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "OpenGLWindow/GLPrimitiveRenderer.h"
|
#include "OpenGLWindow/GLPrimitiveRenderer.h"
|
||||||
#include "OpenGLWindow/GLInstancingRenderer.h"
|
#include "OpenGLWindow/GLInstancingRenderer.h"
|
||||||
@@ -24,6 +25,12 @@
|
|||||||
#include "OpenGLWindow/TwFonts.h"
|
#include "OpenGLWindow/TwFonts.h"
|
||||||
#include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h"
|
#include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "GLRenderToTexture.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define popen _popen
|
||||||
|
#define pclose _pclose
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
struct SimpleInternalData
|
struct SimpleInternalData
|
||||||
{
|
{
|
||||||
@@ -31,6 +38,9 @@ struct SimpleInternalData
|
|||||||
struct sth_stash* m_fontStash;
|
struct sth_stash* m_fontStash;
|
||||||
OpenGL2RenderCallbacks* m_renderCallbacks;
|
OpenGL2RenderCallbacks* m_renderCallbacks;
|
||||||
int m_droidRegular;
|
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;
|
gApp = this;
|
||||||
m_data = new SimpleInternalData;
|
m_data = new SimpleInternalData;
|
||||||
|
m_data->m_frameDumpPngFileName = 0;
|
||||||
|
m_data->m_renderTexture = 0;
|
||||||
|
m_data->m_ffmpegFile = 0;
|
||||||
|
|
||||||
m_window = new b3gDefaultOpenGLWindow();
|
m_window = new b3gDefaultOpenGLWindow();
|
||||||
b3gWindowConstructionInfo ci;
|
b3gWindowConstructionInfo ci;
|
||||||
ci.m_title = title;
|
ci.m_title = title;
|
||||||
@@ -404,8 +418,143 @@ SimpleOpenGL3App::~SimpleOpenGL3App()
|
|||||||
delete m_data ;
|
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()
|
void SimpleOpenGL3App::swapBuffer()
|
||||||
{
|
{
|
||||||
m_window->endRendering();
|
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();
|
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();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ struct SimpleOpenGL3App
|
|||||||
int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f);
|
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);
|
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 drawGrid(DrawGridData data=DrawGridData());
|
||||||
void swapBuffer();
|
void swapBuffer();
|
||||||
void drawText( const char* txt, int posX, int posY);
|
void drawText( const char* txt, int posX, int posY);
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ if findOpenGL() then
|
|||||||
include "../btgui/OpenGLWindow"
|
include "../btgui/OpenGLWindow"
|
||||||
|
|
||||||
-- include "../Demos3/ImplicitCloth"
|
-- include "../Demos3/ImplicitCloth"
|
||||||
-- include "../Demos3/SimpleOpenGL3"
|
include "../Demos3/SimpleOpenGL3"
|
||||||
|
|
||||||
include "../btgui/lua-5.2.3"
|
include "../btgui/lua-5.2.3"
|
||||||
include "../test/lua"
|
include "../test/lua"
|
||||||
|
|||||||
Reference in New Issue
Block a user