expose video capture as logging command in b3RobotSimulatorClientAPI (C++) and pybullet (use STATE_LOGGING_VIDEO_MP4)

This commit is contained in:
Erwin Coumans 2017-03-16 09:13:33 -07:00
parent b7b46b12d3
commit 59d16b2c42
16 changed files with 180 additions and 22 deletions

View File

@ -85,6 +85,9 @@ struct GUIHelperInterface
virtual void removeAllUserDebugItems( ){};
virtual void setVisualizerFlagCallback(VisualizerFlagCallback callback){}
//empty name stops dumping video
virtual void dumpFramesToVideo(const char* mp4FileName) {};
};

View File

@ -191,6 +191,8 @@ SET(BulletExampleBrowser_SRCS
../SharedMemory/PhysicsLoopBackC_API.h
../SharedMemory/PhysicsServerCommandProcessor.cpp
../SharedMemory/PhysicsServerCommandProcessor.h
../SharedMemory/SharedMemoryCommands.h
../SharedMemory/SharedMemoryPublic.h
../BasicDemo/BasicExample.cpp
../BasicDemo/BasicExample.h
../InverseDynamics/InverseDynamicsExample.cpp

View File

@ -371,6 +371,7 @@ void OpenGLExampleBrowserVisualizerFlagCallback(int flag, bool enable)
if (flag == COV_ENABLE_GUI)
{
renderGui = enable;
renderGrid = enable;
}
if (flag == COV_ENABLE_WIREFRAME)
@ -868,8 +869,8 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[])
}
int width = 1024;
int height=768;
int width = 1280;
int height=640;
#ifndef NO_OPENGL3
SimpleOpenGL3App* simpleApp=0;
sUseOpenGL2 =args.CheckCmdLineFlag("opengl2");

View File

@ -568,3 +568,10 @@ struct CommonGraphicsApp* OpenGLGuiHelper::getAppInterface()
return m_data->m_glApp;
}
void OpenGLGuiHelper::dumpFramesToVideo(const char* mp4FileName)
{
if (m_data->m_glApp)
{
m_data->m_glApp->dumpFramesToVideo(mp4FileName);
}
}

View File

@ -85,6 +85,8 @@ struct OpenGLGuiHelper : public GUIHelperInterface
virtual void setVisualizerFlagCallback(VisualizerFlagCallback callback);
virtual void dumpFramesToVideo(const char* mp4FileName);
};
#endif //OPENGL_GUI_HELPER_H

View File

@ -88,6 +88,8 @@ project "App_BulletExampleBrowser"
"../SharedMemory/PhysicsServerCommandProcessor.h",
"../SharedMemory/TinyRendererVisualShapeConverter.cpp",
"../SharedMemory/TinyRendererVisualShapeConverter.h",
"../SharedMemory/SharedMemoryCommands.h",
"../SharedMemory/SharedMemoryPublic.h",
"../MultiThreading/MultiThreadingExample.cpp",
"../MultiThreading/b3PosixThreadSupport.cpp",
"../MultiThreading/b3Win32ThreadSupport.cpp",

View File

@ -774,16 +774,18 @@ void SimpleOpenGL3App::swapBuffer()
m_data->m_frameDumpPngFileName = 0;
}
}
m_window->endRendering();
m_window->startRendering();
m_window->endRendering();
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 = (int)m_window->getRetinaScale()*m_instancingRenderer->getScreenWidth();
int height = (int)m_window->getRetinaScale()*m_instancingRenderer->getScreenHeight();
char cmd[8192];
if (mp4FileName)
{
int width = (int)m_window->getRetinaScale()*m_instancingRenderer->getScreenWidth();
int height = (int)m_window->getRetinaScale()*m_instancingRenderer->getScreenHeight();
char cmd[8192];
#ifdef _WIN32
sprintf(cmd, "ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - "
@ -803,15 +805,25 @@ void SimpleOpenGL3App::dumpFramesToVideo(const char* 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);
}
if (mp4FileName)
{
m_data->m_ffmpegFile = popen(cmd, "w");
if (m_data->m_ffmpegFile)
{
pclose(m_data->m_ffmpegFile);
}
if (mp4FileName)
{
m_data->m_ffmpegFile = popen(cmd, "w");
m_data->m_frameDumpPngFileName = mp4FileName;
m_data->m_frameDumpPngFileName = mp4FileName;
}
} else
{
if (m_data->m_ffmpegFile)
{
fflush(m_data->m_ffmpegFile);
pclose(m_data->m_ffmpegFile);
m_data->m_frameDumpPngFileName = 0;
}
m_data->m_ffmpegFile = 0;
}
}
void SimpleOpenGL3App::dumpNextFrameToPng(const char* filename)

View File

@ -16,7 +16,7 @@ int main(int argc, char* argv[])
//sim->connect(eCONNECT_UDP, "localhost", 1234);
sim->configureDebugVisualizer( COV_ENABLE_GUI, 0);
// sim->configureDebugVisualizer( COV_ENABLE_SHADOWS, 0);//COV_ENABLE_WIREFRAME
sim->setTimeOut(10);
//syncBodies is only needed when connecting to an existing physics server that has already some bodies
sim->syncBodies();
b3Scalar fixedTimeStep = 1./240.;
@ -59,7 +59,9 @@ int main(int argc, char* argv[])
}
#endif
sim->setRealTimeSimulation(false);
int vidLogId = -1;
int minitaurLogId = -1;
while (sim->canSubmitCommand())
{
b3KeyboardEventsData keyEvents;
@ -67,14 +69,48 @@ int main(int argc, char* argv[])
if (keyEvents.m_numKeyboardEvents)
{
printf("num key events = %d]\n", keyEvents.m_numKeyboardEvents);
//printf("num key events = %d]\n", keyEvents.m_numKeyboardEvents);
//m_keyState is a flag combination of eButtonIsDown,eButtonTriggered, eButtonReleased
for (int i=0;i<keyEvents.m_numKeyboardEvents;i++)
{
printf("keyEvent[%d].m_keyCode = %d, state = %d\n", i,keyEvents.m_keyboardEvents[i].m_keyCode,keyEvents.m_keyboardEvents[i].m_keyState);
if (keyEvents.m_keyboardEvents[i].m_keyCode=='0')
{
if ( keyEvents.m_keyboardEvents[i].m_keyState&eButtonTriggered)
{
if (vidLogId < 0)
{
vidLogId = sim->startStateLogging(STATE_LOGGING_VIDEO_MP4,"video.mp4");
}
else
{
sim->stopStateLogging(vidLogId);
vidLogId=-1;
}
}
}
if (keyEvents.m_keyboardEvents[i].m_keyCode=='m')
{
if ( minitaurLogId<0 && keyEvents.m_keyboardEvents[i].m_keyState&eButtonTriggered)
{
minitaurLogId = sim->startStateLogging(STATE_LOGGING_MINITAUR,"simlog.bin");
}
if (minitaurLogId>=0 && keyEvents.m_keyboardEvents[i].m_keyState&eButtonReleased)
{
sim->stopStateLogging(minitaurLogId);
minitaurLogId=-1;
}
}
//printf("keyEvent[%d].m_keyCode = %d, state = %d\n", i,keyEvents.m_keyboardEvents[i].m_keyCode,keyEvents.m_keyboardEvents[i].m_keyState);
}
}
sim->stepSimulation();
static double yaw=0;
double distance = 10.5+9 * b3Sin(yaw);
yaw+=0.008;
sim->resetDebugVisualizerCamera(distance,yaw,20,b3MakeVector3(0,0,0.1));
b3Clock::usleep(1000.*1000.*fixedTimeStep);
}

View File

@ -134,6 +134,18 @@ bool b3RobotSimulatorClientAPI::isConnected() const
return (m_data->m_physicsClientHandle != 0);
}
void b3RobotSimulatorClientAPI::setTimeOut(double timeOutInSec)
{
if (!isConnected())
{
b3Warning("Not connected");
return;
}
b3SetTimeOut(m_data->m_physicsClientHandle,timeOutInSec);
}
void b3RobotSimulatorClientAPI::disconnect()
{
if (!isConnected())
@ -853,3 +865,18 @@ void b3RobotSimulatorClientAPI::stopStateLogging(int stateLoggerUniqueId)
b3StateLoggingStop(commandHandle, stateLoggerUniqueId);
statusHandle = b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClientHandle, commandHandle);
}
void b3RobotSimulatorClientAPI::resetDebugVisualizerCamera(double cameraDistance, double cameraPitch, double cameraYaw, const b3Vector3& targetPos)
{
b3SharedMemoryCommandHandle commandHandle = b3InitConfigureOpenGLVisualizer(m_data->m_physicsClientHandle);
if (commandHandle)
{
if ((cameraDistance >= 0))
{
b3Vector3FloatData camTargetPos;
targetPos.serializeFloat(camTargetPos);
b3ConfigureOpenGLVisualizerSetViewMatrix(commandHandle, cameraDistance, cameraPitch, cameraYaw, camTargetPos.m_floats);
}
b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClientHandle, commandHandle);
}
}

View File

@ -130,6 +130,8 @@ public:
bool isConnected() const;
void setTimeOut(double timeOutInSec);
void syncBodies();
void resetSimulation();
@ -181,8 +183,9 @@ public:
bool getLinkState(int bodyUniqueId, int linkIndex, b3LinkState* linkState);
void configureDebugVisualizer(enum b3ConfigureDebugVisualizerEnum flag, int enable);
void resetDebugVisualizerCamera(double cameraDistance, double cameraPitch, double cameraYaw, const b3Vector3& targetPos);
int startStateLogging(b3StateLoggingType loggingType, const std::string& fileName, const b3AlignedObjectArray<int>& objectUniqueIds, int maxLogDof = -1);
int startStateLogging(b3StateLoggingType loggingType, const std::string& fileName, const b3AlignedObjectArray<int>& objectUniqueIds=b3AlignedObjectArray<int>(), int maxLogDof = -1);
void stopStateLogging(int stateLoggerUniqueId);
void getVREvents(b3VREventsData* vrEventsData);

View File

@ -38,6 +38,8 @@ SET(SharedMemory_SRCS
PhysicsServerCommandProcessor.h
TinyRendererVisualShapeConverter.cpp
TinyRendererVisualShapeConverter.h
SharedMemoryCommands.h
SharedMemoryPublic.h
../TinyRenderer/geometry.cpp
../TinyRenderer/model.cpp
../TinyRenderer/tgaimage.cpp

View File

@ -438,6 +438,31 @@ struct InternalStateLogger
};
struct VideoMP4Loggger : public InternalStateLogger
{
struct GUIHelperInterface* m_guiHelper;
std::string m_fileName;
VideoMP4Loggger(int loggerUid,const char* fileName,GUIHelperInterface* guiHelper)
:m_guiHelper(guiHelper)
{
m_fileName = fileName;
m_loggingUniqueId = loggerUid;
m_loggingType = STATE_LOGGING_VIDEO_MP4;
m_guiHelper->dumpFramesToVideo(fileName);
}
virtual void stop()
{
m_guiHelper->dumpFramesToVideo(0);
}
virtual void logState(btScalar timeStamp)
{
//dumping video frames happens in another thread
//we could add some overlay of timestamp here, if needed/wanted
}
};
struct MinitaurStateLogger : public InternalStateLogger
{
int m_loggingTimeStamp;
@ -1797,6 +1822,17 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
if (clientCmd.m_updateFlags & STATE_LOGGING_START_LOG)
{
if (clientCmd.m_stateLoggingArguments.m_logType == STATE_LOGGING_VIDEO_MP4)
{
if (clientCmd.m_stateLoggingArguments.m_fileName)
{
int loggerUid = m_data->m_stateLoggersUniqueId++;
VideoMP4Loggger* logger = new VideoMP4Loggger(loggerUid,clientCmd.m_stateLoggingArguments.m_fileName,this->m_data->m_guiHelper);
m_data->m_stateLoggers.push_back(logger);
serverStatusOut.m_type = CMD_STATE_LOGGING_START_COMPLETED;
serverStatusOut.m_stateLoggingResultArgs.m_loggingUniqueId = loggerUid;
}
}
if (clientCmd.m_stateLoggingArguments.m_logType == STATE_LOGGING_MINITAUR)
{

View File

@ -179,8 +179,10 @@ enum MultiThreadedGUIHelperCommunicationEnums
eGUIUserDebugAddParameter,
eGUIUserDebugRemoveItem,
eGUIUserDebugRemoveAllItems,
eGUIDumpFramesToVideo,
};
#include <stdio.h>
//#include "BulletMultiThreaded/PlatformDefinitions.h"
@ -489,7 +491,7 @@ void MotionThreadFunc(void* userPtr,void* lsMemory)
args->m_cs->unlock();
}
args->m_physicsServerPtr->disconnectSharedMemory(true);
//do nothing
}
@ -959,6 +961,16 @@ public:
}
const char* m_mp4FileName;
virtual void dumpFramesToVideo(const char* mp4FileName)
{
m_cs->lock();
m_mp4FileName = mp4FileName;
m_cs->setSharedParam(1, eGUIDumpFramesToVideo);
workerThreadWait();
m_mp4FileName = 0;
}
};
@ -1614,6 +1626,14 @@ void PhysicsServerExample::updateGraphics()
m_multiThreadedHelper->mainThreadRelease();
break;
}
case eGUIDumpFramesToVideo:
{
m_multiThreadedHelper->m_childGuiHelper->dumpFramesToVideo(m_multiThreadedHelper->m_mp4FileName);
m_multiThreadedHelper->mainThreadRelease();
break;
}
case eGUIHelperIdle:
{
break;

View File

@ -188,6 +188,8 @@ bool PhysicsServerSharedMemory::connectSharedMemory( struct GUIHelperInterface*
void PhysicsServerSharedMemory::disconnectSharedMemory(bool deInitializeSharedMemory)
{
m_data->m_commandProcessor->deleteDynamicsWorld();
m_data->m_commandProcessor->setGuiHelper(0);
if (m_data->m_verboseOutput)

View File

@ -330,7 +330,8 @@ enum b3StateLoggingType
STATE_LOGGING_MINITAUR = 0,
STATE_LOGGING_GENERIC_ROBOT = 1,
STATE_LOGGING_VR_CONTROLLERS = 2,
STATE_LOGGING_COMMANDS = 3,
STATE_LOGGING_VIDEO_MP4 = 3,
STATE_LOGGING_COMMANDS = 4,
};

View File

@ -125,6 +125,8 @@ if not _OPTIONS["no-enet"] then
"../../examples/SharedMemory/Win32SharedMemory.h",
"../../examples/SharedMemory/PosixSharedMemory.cpp",
"../../examples/SharedMemory/PosixSharedMemory.h",
"../../examples/SharedMemory/SharedMemoryCommands.h",
"../../examples/SharedMemory/SharedMemoryPublic.h",
"../../examples/Utils/b3ResourcePath.cpp",
"../../examples/Utils/b3ResourcePath.h",
"../../examples/Utils/RobotLoggingUtil.cpp",