Intel® INDE Media Pack for Android* Tutorials - Video Capturing for LibGDX Applications

This tutorial explains how to use Intel® INDE Media Pack for Android* to add video capturing capability to a LibGDX based game.

Before getting started, download and install Intel INDE by visiting http://intel.com/software/inde. After installing Intel INDE, choose to download and install the Media Pack for Android. For additional assistance visit the Intel INDE forum.

Go to the installation folder of Media Pack for Android -> libs and copy two jar files (android-<version>.jar and domain-<version>.jar) to your application’s libs folder:

                                                                                         

We are ready to go now, but first let me explain how GLCapture class works. GLCapture has its own rendering surface and an OpenGL* context. All frames rendered to this surface could be encoded as video frames. Before the first use we need to setup some required parameters like video resolution, bit rate, path to video file, etc.

Our example is based on the GDX Invaders sample application from libGDX package. Let see how to add video capturing functionality into this game.

    

As we can’t directly add Android functionality to a core project we need to create an abstract interface inside the core project and then implement this interface for Android port:

public interface GameScreenCapture
{
    // Initiates video capturing process
    public void start();
    // Interrupts video capturing process
    public void stop();
	
    // Check the state of capturing process
    public boolean isStarted();
	
    // Switch the current OpenGL context to the video capturing surface
    public void beginCapture();
    // Restore OpenGL context 
    public void endCapture();

    // width and height of video frame
    public int getFrameWidth();
    public int getFrameHeight();
} 

To keep our code more clear we will use VideoCapture class from the Intel® INDE Media Pack for Android Samples application. VideoCapture is a singleton wrapper for GLCapture which takes care about initialization and provides just a few methods:

public void start(String videoPath)

Launches capturing process, sets up the video format and destination file path.

public void stop()

Interrupts capturing process.

public void beginCaptureFrame()

This method checks if the video surface is configured. If it’s not the method tries to configure video surface first by calling setSurfaceSize() and then by calling beginCaptureFrame() of GLCapture.

public void endCaptureFrame()

calls endCaptureFrame  of GLCapture.

Now let’s add GameScreenCapture implementation for an Android project:

public class AndroidGameScreenCapture implements GameScreenCapture
{
    // Path to video file
    private String mVideoPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/inviders.mp4";

    public AndroidGameScreenCapture()
    {
    }

    @Override
    public void start()
    {
        try
        {
            // start could throw IOException in case if file couldn't be opened
            VideoCapture.getInstance().start(mVideoPath);
        }
        catch (IOException e)
        {
        }
    }

    @Override
    public void stop()
    {
        VideoCapture.getInstance().stop();
    }

    @Override
    public boolean isStarted()
    {
        return VideoCapture.getInstance().isStarted();
    }

    @Override
    public void beginCapture()
    {
        VideoCapture.getInstance().beginCaptureFrame();
    }

    @Override
    public void endCapture()
    {
        VideoCapture.getInstance().endCaptureFrame();
    }

    @Override
    public int getFrameWidth()
    {
        return VideoCapture.getInstance().getFrameWidth();
    }

    @Override
    public int getFrameHeight()
    {
        return VideoCapture.getInstance().getFrameHeight();
    }
}

We define this class as a member of AndroidApplication inside the Android application port:

public class GdxInvadersAndroid extends AndroidApplication
{	
    private AndroidGameScreenCapture mScreenCapture = new AndroidGameScreenCapture();
    … 
}

We pass this instance to a game object via constructor:

public void onCreate (Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    …
    initialize(new GdxInvaders(mScreenCapture), config);
}

And for that we need to change this constructor and add a member variable to store this object:

public class GdxInvaders extends Game 
{
    GameScreenCapture gameScreenCapture;
    …
    public GdxInvaders(GameScreenCapture gameScreenCapture) 
    {
        …
    }
}

Our plan is to add the capturing functionality only for the GameLoop screen, so another step is to pass this object to the GameLoop screen:

public class GameLoop extends InvadersScreen implements SimulationListener
{
    GameScreenCapture gameScreenCapture;
    …
    public GameLoop (GameScreenCapture gameScreenCapture)
    {
        …
    }
}

Now we need to add some logic for the game screen. In our sample app we added a recording button onto the game screen. By pressing this button the user can start and stop the capturing process (see screenshots below). 

         

         

Inside a click handler we simply switch the state of the video capturing based on its current state:

if(gameScreenCapture.isStarted())
{
    gameScreenCapture.stop();
}
else
{
    gameScreenCapture.start();
} 

Now everything is ready except the main part: video capturing functionality inside the rendering loop. There are at least two ways to capture frames: double rendering and using frame buffer. In this sample we will to implement both.

Render twice is simpler method to implement:

public void draw (float delta) 
{
    …
    // Render scene to display
    renderer.render(simulation, delta);

    // Video capture available and in a recording state
    if(gameScreenCapture != null && gameScreenCapture.isStarted())
    {
        // Switch OpenGL context
        gameScreenCapture.beginCapture();
	
        // Render scene, keep in mind delta should 0
        // as we are not going to update game logic twice
        renderer.render(simulation, 0);

        // switch back to original context
        gameScreenCapture.endCapture();
    }
}

Another approach to capture video is to use a Frame Buffer. Thanks to libGDX there is already a class which we can use to implement this solution. We need to just make some changes in the GameLoop class:

// Frame buffer to be used as a render target
FrameBuffer fbo;
// Texture region to copy frame buffer texture to display and video surface
TextureRegion fboRegion;

public GameLoop (GameScreenCapture gameScreenCapture)
{
    fbo = new FrameBuffer(Pixmap.Format.RGB888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
    fboRegion = new TextureRegion(mFBO.getColorBufferTexture());
    fboRegion.flip(false, true);
}

public void draw (float delta) 
{
    // Set Frame Buffer as a render target
    fbo.begin();
    // Render scene
    renderer.render(simulation, delta);
    // Restore original render target
    fbo.end();

    …

    // Draw Frame Buffer texture to display
    spriteBatch.begin();
    spriteBatch.draw(fboRegion, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    spriteBatch.end();

    // Video capture available and in a recording state
    if(gameScreenCapture != null && gameScreenCapture.isStarted())
    {
        // Switch OpenGL context
        gameScreenCapture.beginCapture();
	
        // Draw Frame Buffer texture to video surface
        spriteBatch.begin();
        spriteBatch.draw(mFBORegion, 0, 0, gameScreenCapture.getFrameWidth(), gameScreenCapture.getFrameHeight());
        spriteBatch.end();

        // switch back to original context
        gameScreenCapture.endCapture();
    }
}
Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.