Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
MPEG Renderer

Common Parameters

The class SoMPEGRenderer encapsulates several common parameters, described below.

Specify rendering options:

  • Background color of your video file:

Use SoMPEGRenderer::setBackgroundColor().

  • Dimensions (width, height) of your video file:

Use SoMPEGRenderer::setSize().

The width and the height of your video must be a multiple of 16, otherwise they are changed to a lower value that is a multiple of 16.

Use SoMPEGRenderer::setNumFramesPerSecond(). This information is stored in your MPEG file and will be set the number of frames recorded for one second video. The possible values are 24, 25, 30 and 60 frames per second and will impact the size of the video.

  • Specific rendering attributes:

Use SoMPEGRenderer::setGLRenderAction(). If this action is not specified, an SoGLRenderAction is created automatically.

Specify MPEG output name:

You can specify a file name with the method SoMPEGRenderer::openFile() or a file pointer with the method SoMPEGRenderer::setFilePointer().

When using the method SoMPEGRenderer::openFile(), do not forget to close your MPEG file with the
method SoMPEGRenderer::closeFile().

Specify the scene graph:

Use the method SoMPEGRenderer::setSceneGraph() to specify the scene graph used for generating your video file.

Recording a Video:

In order to simplify the recording of a video, new methods have been introduced. These methods allow you to start, pause and stop a recording process. The frames added to the video with the SoMPEGRenderer::addFrame() method will be encoded in a separate thread in order to improve performance.

The renderer can be plugged into a render area or viewer, which will automatically send new drawn frames to it when the recording is started. The following code demonstrates this possibility.

Example : Plugging an MPEGRenderer into a render area

// Create the render area
SoXxRenderArea* myRA = new SoXxRenderArea( mainWidget );
// Create the renderer
SoMPEGRenderer* mpgRec = new SoMPEGRenderer();
// Set it in the render area
myRA->setMPEGRecorder( mpgRec );
// Start the recording
mpgRec->openFile( “test.mpg” );
mpgRec->record();
// Do some interactions with the render area
mpgRec->stop(); // The recorder will be destroyed by the render area.

Note that this functionality is accessible from the popup menu of the viewers. It provides a user interface to set up the recording. If no renderer was specified, the viewer will create it.

Using SoMPEGNavRenderer

This class records all camera changes, then generates an MPEG output file. After specifying your MPEG file name, your scene graph, and other rendering options (see Common Parameters), call SoMPEGNavRenderer::record() to record camera changes. Finally, call SoMPEGNavRenderer::stop() to stop recording and generate the MPEG output file.

Generating the MPEG output (after the call to**
SoMPEGNavRenderer::stop()**) may take several seconds or even minutes depending on
the length of your video. To give you an idea of the time it may take, at least 3 minutes are
necessary for obtaining 1 minute of video with 25 frames per second.

The example supplied in $OIVHOME/src/Inventor/examples/Features/MPEGRender/MPEGNavRenderer.cxx shows an example of use of SoMPEGNavRenderer. The following is a code fragment extract from this example.

Example : Extract of using SoMPEGNavRenderer

C++ :

void
myKeyPressCB( void*, SoEventCallback* eventCB )
{
const SoEvent* event = eventCB->getEvent();
// check for the keys being pressed
if ( SO_KEY_PRESS_EVENT( event, R ) )
{
MPEGRenderer->record();
}
else if ( SO_KEY_PRESS_EVENT( event, S ) )
{
MPEGRenderer->stop();
}
else if ( SO_KEY_PRESS_EVENT( event, C ) )
{
MPEGRenderer->closeFile();
delete MPEGRenderer;
exit( 0 );
}
}
int
main( int, char** argv )
{
// Initialize Inventor and Xt
Widget myWindow = SoXt::init( "MPEGFrameRenderer" );
// Build the viewer in the applications main window
SoXtExaminerViewer* myViewer = new SoXtExaminerViewer( myWindow );
// Read the geometry from a file and add to the scene
SoInput myInput;
if ( !myInput.openFile( "../../../data/jumpyMan.iv" ) )
exit( 1 );
SoSeparator* geomObject = SoDB::readAll( &myInput );
if ( geomObject == NULL )
exit( 1 );
// Build the scene graph
SoSeparator* root = new SoSeparator;
root->ref();
SoPerspectiveCamera* camera = new SoPerspectiveCamera;
root->addChild( camera );
root->addChild( geomObject );
// Track the keyboard events
SoEventCallback* myEventCB = new SoEventCallback;
myEventCB->addEventCallback( SoKeyboardEvent::getClassTypeId(), myKeyPressCB, myViewer );
root->addChild( myEventCB );
// Attach the viewer to the scene graph
myViewer->setSceneGraph( root );
camera->viewAll( geomObject, myViewer->getViewportRegion() );
// Create the MPEG renderer
MPEGRenderer = new SoMPEGNavRenderer( myViewer->getSceneManager()->getSceneGraph() );
MPEGRenderer->setSize( SbVec2s( 300, 300 ) );
MPEGRenderer->adjustNumFramesPerSecond( TRUE );
int i = 0;
char mpegFileName[20] = "MPEGOutput.mpg";
while ( !MPEGRenderer->openFile( mpegFileName ) )
{
sprintf( mpegFileName, "MPEGOutput%d.mpg", i );
i++;
}
// Show the main window
myViewer->show();
SoXt::show( myWindow );
// Loop forever
SoXt::mainLoop();
return 0;
}

C# :

private SoSeparator _root;
private SoWinExaminerViewer _viewer;
private SoSwitch InfoSwitch;
private string _currentPathData;
private SoMPEGNavRenderer MPEGRenderer;
*[STAThread] static void
Main() {
MPEGNavRenderer demo = new MPEGNavRenderer();
demo.Start();
Application.Run( demo );
}
public void LaunchDemo()
{
try
{
_viewer = new SoWinExaminerViewer( _parent, "Name", true, SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER );
}
catch ( Exception ex )
{
MessageBox.Show( ex.ToString() );
}
_root = new SoSeparator();
// SoGradientBackground bg = new SoGradientBackground();
// _root.AddChild(bg);
SoMaterial material = new SoMaterial();
material.diffuseColor.SetValue( 0.0f, 0.0f, 1.0f );
_root.AddChild( material );
SoSeparator geomObject = SoDB.ReadAll( _currentPathData + "/jumpyMan.iv" );
// Build the scene graph
InfoSwitch = DisplayInfo();
_root.AddChild( InfoSwitch );
SoPerspectiveCamera camera = new SoPerspectiveCamera();
_root.AddChild( camera );
_root.AddChild( geomObject );
// Track the keyboard events
SoEventCallback eventCB = new SoEventCallback();
eventCB.AddEventCallback( typeof( SoKeyboardEvent ), new SoEventCallback.EventCB( keyCB ) );
_root.AddChild( eventCB );
_viewer.SetSceneGraph( _root );
_viewer.ViewAll();
camera.ViewAll( geomObject, _viewer.GetViewportRegion() );
// Create the MPEG renderer
MPEGRenderer = new SoMPEGNavRenderer( _viewer.GetSceneGraph() );
MPEGRenderer.SetSize( new SbVec2s( 300, 300 ) );
MPEGRenderer.AdjustNumFramesPerSecond( true );
MPEGRenderer.SetBitPerSec( -1 );
MPEGRenderer.SetCompressionRate( 0.0f );
int i = 1;
while ( File.Exists( "MPEGOutput" + i + ".mpg" ) )
i++;
MPEGRenderer.OpenFile( "MPEGOutput" + i + ".mpg" );
}
public void Start()
{
LaunchDemo();
// Show();
}
public bool Init( Panel parent )
{
/** The demo Launcher always give a parent */
/** If we don't want to put the application on demoLauncher, we just need to */
/** Comment the setParent line and uncomment the show method */
SetParent( parent );
return true;
}
public void Stop()
{
HideViewer();
Close();
}
public void SetParent( Panel P )
{
_parent = P;
}
public void HideViewer()
{
_viewer.Hide();
}
private SoSwitch
DisplayInfo()
{
// Informations
SoSwitch infoSwitch = new SoSwitch();
infoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_ALL;
SoSeparator infoSep = new SoSeparator();
infoSwitch.AddChild( infoSep );
SoLightModel lModel = new SoLightModel();
lModel.model.Value = SoLightModel.Models.BASE_COLOR;
infoSep.AddChild( lModel );
SoFont fontInfo = new SoFont();
fontInfo.size.SetValue( 12.0f );
infoSep.AddChild( fontInfo );
SoBaseColor infoColor = new SoBaseColor();
infoColor.rgb.SetValue( new SbColor( 1, 1, 0 ) );
infoSep.AddChild( infoColor );
SoTranslation transInfo = new SoTranslation();
transInfo.translation.SetValue( -0.95f, 0.95f, 0.0f );
infoSep.AddChild( transInfo );
SoText2 infoText = new SoText2();
string[] display = new string[4]{ "H : Toggle this display ",
"R : Record camera movements to the MPEG file ",
"S : Stop recording ",
"C : Generate the file MPEGOutputx.mpg and Exit " };
infoText.stringField.SetValues( 0, display );
infoSep.AddChild( infoText );
return infoSwitch;
}
private void
keyCB( SoEventCallback sender )
{
SoKeyboardEvent evt = ( SoKeyboardEvent )sender.GetEvent();
if ( !SoKeyboardEvent.IsKeyReleaseEvent( evt, evt.GetKey() ) )
return;
if ( evt.GetKey() == SoKeyboardEvent.Keys.H )
{
if ( InfoSwitch.whichChild.Value == SoSwitch.WhichChild.SO_SWITCH_ALL )
InfoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_NONE;
else
InfoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_ALL;
}
else if ( evt.GetKey() == SoKeyboardEvent.Keys.R )
{
MPEGRenderer.Record();
}
else if ( evt.GetKey() == SoKeyboardEvent.Keys.S )
{
MPEGRenderer.Stop();
}
else if ( evt.GetKey() == SoKeyboardEvent.Keys.C )
{
MPEGRenderer.CloseFile();
this.Close();
}
}

Java :

Using SoMPEGFrameRenderer

This class generates an MPEG movie, frame by frame. After specifying the MPEG file name, the scene graph, and other rendering options (see Common Parameters), call SoMPEGFrameRenderer::recordFrame(float duration) to record a new frame in your MPEG video file. The duration field indicates how long to play the frame.

The example supplied in $OIVHOME/src/Inventor/examples/Features/MPEGRender/MPEGFrameRenderer.cxx shows an example of use of SoMPEGFrameRenderer. The following is a code fragment extract from this example.

Example : Generate an MPEG file frame by frame

C++ :

void
myKeyPressCB( void*, SoEventCallback* eventCB )
{
const SoEvent* event = eventCB->getEvent();
// check for the keys being pressed
if ( SO_KEY_PRESS_EVENT( event, A ) )
{
MPEGRenderer->recordFrame( 2 );
}
else if ( SO_KEY_PRESS_EVENT( event, C ) )
{
MPEGRenderer->closeFile();
delete MPEGRenderer;
exit( 0 );
}
}
int
main( int, char** argv )
{
// Initialize Inventor and Xt
Widget myWindow = SoXt::init( "MPEGFrameRenderer" );
// Build the viewer in the applications main window
SoXtExaminerViewer* myViewer = new SoXtExaminerViewer( myWindow );
// Read the geometry from a file and add to the scene
SoInput myInput;
if ( !myInput.openFile( "../../../data/jumpyMan.iv" ) )
exit( 1 );
SoSeparator* geomObject = SoDB::readAll( &myInput );
if ( geomObject == NULL )
exit( 1 );
// Create the MPEG renderer
MPEGRenderer = new SoMPEGFrameRenderer();
MPEGRenderer->setSize( SbVec2s( 300, 300 ) );
int i = 0;
char mpegFileName[20] = "MPEGOutput.mpg";
while ( !MPEGRenderer->openFile( mpegFileName ) )
{
sprintf( mpegFileName, "MPEGOutput%d.mpg", i );
i++;
}
// Build the scene graph
SoSeparator* root = new SoSeparator;
root->ref();
SoPerspectiveCamera* camera = new SoPerspectiveCamera;
root->addChild( camera );
root->addChild( geomObject );
// Track the keyboard events
SoEventCallback* myEventCB = new SoEventCallback;
myEventCB->addEventCallback( SoKeyboardEvent::getClassTypeId(), myKeyPressCB, myViewer );
root->addChild( myEventCB );
// Attach the viewer to the scene graph
myViewer->setSceneGraph( root );
MPEGRenderer->setSceneGraph( myViewer->getSceneManager()->getSceneGraph() );
camera->viewAll( geomObject, myViewer->getViewportRegion() );
myViewer->show();
SoXt::show( myWindow ); // Show the main window
SoXt::mainLoop(); // Loop forever
return 0;
}

C# :

private SoSwitch InfoSwitch;
private SoMPEGFrameRenderer MPEGRenderer;
private SoSeparator _root;
private string _currentPathData;
private SoWinExaminerViewer _viewer;
[STAThread] static void
Main() {
MPEGFrameRenderer demo = new MPEGFrameRenderer();
demo.Start();
Application.Run( demo );
}
public void LaunchDemo()
{
try
{
_viewer = new SoWinExaminerViewer( _parent, "Name", true, SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER );
}
catch ( Exception ex )
{
MessageBox.Show( ex.ToString() );
}
// Create the MPEG renderer
MPEGRenderer = new SoMPEGFrameRenderer();
MPEGRenderer.SetSize( new SbVec2s( 300, 300 ) );
MPEGRenderer.SetBitPerSec( -1 );
MPEGRenderer.SetCompressionRate( 0.0f );
int i = 1;
while ( File.Exists( "MPEGOutput" + i + ".mpg" ) )
i++;
MPEGRenderer.OpenFile( "MPEGOutput" + i + ".mpg" );
_root = new SoSeparator();
// SoGradientBackground bg = new SoGradientBackground();
// _root.AddChild(bg);
SoMaterial material = new SoMaterial();
material.diffuseColor.SetValue( 0.0f, 0.0f, 1.0f );
_root.AddChild( material );
SoSeparator geomObject = SoDB.ReadAll( _currentPathData + "/jumpyMan.iv" );
// Build the scene graph
InfoSwitch = DisplayInfo();
_root.AddChild( InfoSwitch );
SoPerspectiveCamera camera = new SoPerspectiveCamera();
_root.AddChild( camera );
_root.AddChild( geomObject );
// Track the keyboard events
SoEventCallback eventCB = new SoEventCallback();
eventCB.AddEventCallback( typeof( SoKeyboardEvent ), new SoEventCallback.EventCB( keyCB ) );
_root.AddChild( eventCB );
_viewer.SetSceneGraph( _root );
_viewer.ViewAll();
MPEGRenderer.SetSceneGraph( _viewer.GetSceneGraph() );
camera.ViewAll( geomObject, _viewer.GetViewportRegion() );
}
public void Start()
{
LaunchDemo();
// Show();
}
public bool Init( Panel parent )
{
/** The demo Launcher always give a parent */
/** If we don't want to put the application on demoLauncher, we just need to */
/** Comment the setParent line and uncomment the show method */
SetParent( parent );
return true;
}
public void Stop()
{
HideViewer();
Close();
}
public void SetParent( Panel P )
{
_parent = P;
}
public void HideViewer()
{
_viewer.Hide();
}
private SoSwitch DisplayInfo()
{
// Informations
SoSwitch infoSwitch = new SoSwitch();
infoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_ALL;
SoSeparator infoSep = new SoSeparator();
infoSwitch.AddChild( infoSep );
SoLightModel lModel = new SoLightModel();
lModel.model.Value = SoLightModel.Models.BASE_COLOR;
infoSep.AddChild( lModel );
SoFont fontInfo = new SoFont();
fontInfo.size.Value = 12.0f;
infoSep.AddChild( fontInfo );
SoBaseColor infoColor = new SoBaseColor();
infoColor.rgb.SetValue( new SbColor( 1, 1, 0 ) );
infoSep.AddChild( infoColor );
SoTranslation transInfo = new SoTranslation();
transInfo.translation.SetValue( -0.95f, 0.95f, 0.0f );
infoSep.AddChild( transInfo );
SoText2 infoText = new SoText2();
string[] display =
new string[3]{ "H : Toggle this display ", "A : Add a new frame to the MPEG file", "C : Generate the file MPEGOutputx.mpg and Exit " };
infoText.stringField.SetValues( 0, display );
infoSep.AddChild( infoText );
return infoSwitch;
}
private void keyCB( SoEventCallback sender )
{
SoKeyboardEvent evt = ( SoKeyboardEvent )sender.GetEvent();
if ( !SoKeyboardEvent.IsKeyReleaseEvent( evt, evt.GetKey() ) )
return;
if ( evt.GetKey() == SoKeyboardEvent.Keys.H )
{
if ( InfoSwitch.whichChild.Value == SoSwitch.WhichChild.SO_SWITCH_ALL )
InfoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_NONE;
else
InfoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_ALL;
}
else if ( evt.GetKey() == SoKeyboardEvent.Keys.A )
{
int savedSwitchValue = InfoSwitch.whichChild.Value;
InfoSwitch.whichChild.Value = SoSwitch.WhichChild.SO_SWITCH_NONE;
MPEGRenderer.RecordFrame( 2 );
InfoSwitch.whichChild.Value = savedSwitchValue;
}
else if ( evt.GetKey() == SoKeyboardEvent.Keys.C )
{
MPEGRenderer.CloseFile();
this.Close();
}
}

Java :

class ProcessKeyEvents extends SoEventCallbackCB
{
public void invoke( SoEventCallback event )
{
// check for the keys being pressed
if ( SoKeyboardEvent.isKeyPressEvent( event.getEvent(), SoKeyboardEvent.Keys.P ) )
{
MPEGRenderer.recordFrame( 2 );
event.setHandled();
}
else if ( SoKeyboardEvent.isKeyPressEvent( event.getEvent(), SoKeyboardEvent.Keys.C ) )
{
MPEGRenderer.closeFile();
event.setHandled();
}
}
}
@Override public void
start()
{
super.start();
setLayout( new BorderLayout() );
Panel panel = new Panel( new BorderLayout() );
myViewer = new SwSimpleViewer( SwSimpleViewer.EXAMINER );
// Build the viewer in the applications main window
myViewer = new SwSimpleViewer( SwSceneViewer.EXAMINER );
// Read the geometry from a file and add to the scene
SoInput myInput = new SoInput();
if ( !myInput.openFile( "../../../../data/jumpyMan.iv" ) )
return;
SoSeparator geomObject = SoDB.readAll( myInput );
if ( geomObject == null )
return;
// Create the MPEG renderer
MPEGRenderer = new SoMPEGFrameRenderer();
MPEGRenderer.setSize( new SbVec2s( ( short )300, ( short )300 ) );
int i = 0;
String mpegFileName = "MPEGOutput.mpg";
while ( !MPEGRenderer.openFile( mpegFileName ) )
{
mpegFileName = "MPEGOutput" + i + ".mpg";
i++;
}
// Build the scene graph
SoSeparator root = new SoSeparator();
SoPerspectiveCamera camera = new SoPerspectiveCamera();
root.addChild( camera );
root.addChild( geomObject );
// Track the keyboard events
SoEventCallback myEventCB = new SoEventCallback();
myEventCB.addEventCallback( SoKeyboardEvent.class, new ProcessKeyEvents(), myViewer );
root.addChild( myEventCB );
// Create a viewer
myViewer = new SwSimpleViewer( SwSimpleViewer.EXAMINER );
// attach and show viewer
myViewer.setSceneGraph( root );
MPEGRenderer.setSceneGraph( myViewer.getScene().getSceneGraph() );
panel.add( myViewer );
add( panel );
}