plaidshirt
plaidshirt

Reputation: 5671

Video playing in libGDX

I have tried to use GDX-video extension in a libGDX project. I have converted an MP4 file into OGG (Theora+Vorbis) with use of VLC and placed under res/data/ folder in android project. When I run project, see black screen.

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.video.VideoPlayer;
import com.badlogic.gdx.video.VideoPlayerCreator;

import java.io.FileNotFoundException;

public class MyGdxGame extends ApplicationAdapter implements InputProcessor {
    public PerspectiveCamera cam;
    public CameraInputController inputController;
    public ModelInstance instance;
    public Environment environment;

    public VideoPlayer videoPlayer;
    public Mesh mesh;

    private final Vector3 tmpV1 = new Vector3();
    private final Vector3 target = new Vector3();

    @Override
    public void create() {
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, .4f, .4f, .4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(10f, 10f, 10f);
        cam.lookAt(0, 0, 0);
        cam.near = 0.1f;
        cam.far = 300f;
        cam.update();

        MeshBuilder meshBuilder = new MeshBuilder();
        meshBuilder.begin(Usage.Position | Usage.TextureCoordinates, GL20.GL_TRIANGLES);
        // @formatter:off
        meshBuilder.box(5, 5, 5);
        // @formatter:on
        mesh = meshBuilder.end();
        videoPlayer = VideoPlayerCreator.createVideoPlayer(cam, mesh, GL20.GL_TRIANGLES);
        try {
            videoPlayer.play(Gdx.files.internal("data/converted.ogg"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Gdx.input.setInputProcessor(new InputMultiplexer(this, inputController = new CameraInputController(cam)));
        Gdx.gl.glEnable(GL20.GL_CULL_FACE);
        Gdx.gl.glCullFace(GL20.GL_BACK);
    }

    @Override
    public void render() {
        inputController.update();

        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        final float delta = Gdx.graphics.getDeltaTime();
        tmpV1.set(cam.direction).crs(cam.up).y = 0f;
        cam.rotateAround(target, tmpV1.nor(), delta * 20);
        cam.rotateAround(target, Vector3.Y, delta * -30);
        cam.update();

        if (!videoPlayer.render()) { // As soon as the video is finished, we start the file again using the same player.
            try {
                videoPlayer.play(Gdx.files.internal("data/converted.ogg"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void dispose () {
    }

    public boolean needsGL20 () {
        return true;
    }

    public void resume () {
    }

    public void resize (int width, int height) {
    }

    public void pause () {
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

It is a freshly created project, only necessary Gradle dependencies have added to it.

Upvotes: 2

Views: 3223

Answers (1)

WLGfx
WLGfx

Reputation: 1179

Okay, so this was asked 5 years ago(ish), but I decided for my current project I needed it working with LibGDX.

First off the repository page:

https://github.com/libgdx/gdx-video

A page that kind of helped me a little and probably won't be mentioned again:

https://github.com/libgdx/gdx-video/issues/2

And then this that I was curious about:

https://oss.sonatype.org/content/repositories/snapshots/com/badlogicgames/gdx-video/

NB: This is Nov 2021 so the current versions of IntelliJ Idea and LibGDX I am using for this.

Before I start with integrating this library I'll add that LibGDX still sets up the older version of LWJGL for Desktop as the earlier version, but I fixed this by changing the 'DesktopLauncher.java' to this:

//import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
//import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import com.mygdx.game.MyGdxGame;

public class DesktopLauncher {
    public static void main (String[] arg) {
        //LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
        //new LwjglApplication(new MyGdxGame(), config);
        Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
        config.setWindowedMode(1280, 768);
        new Lwjgl3Application(new MyGdxGame(), config);
    }
}

On the first page it gives an explanation thus:

Core:
implementation "com.badlogicgames.gdx-video:gdx-video:0.0.1"
Desktop:
implementation "com.badlogicgames.gdx-video:gdx-video-lwjgl:0.0.1"
or
implementation "com.badlogicgames.gdx-video:gdx-video-lwjgl3:0.0.1"
Android:
implementation "com.badlogicgames.gdx-video:gdx-video-android:0.0.1"

It says on the github page to use the current version of 'gdx-video' instead of '0.0.1'. The 3rd link above is the repository for 'gdx-video' and on entering the directories, the current version as of this date is '1.3.2-SNAPSHOT'. It took me a few days to figure out I had to add the '-SNAPSHOT' at the end.

So, to get this working, the 'build.gradle' file was changed to this:

project(":core") {
    apply plugin: "java-library"

    // https://oss.sonatype.org/content/repositories/snapshots/com/badlogicgames/gdx-video/

    dependencies {
        implementation "com.badlogicgames.gdx-video:gdx-video:1.3.2-SNAPSHOT"
        api "com.badlogicgames.gdx:gdx:$gdxVersion"
        api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
        api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
        
    }
}

project(":android") {
    apply plugin: "com.android.application"

    configurations { natives }

    dependencies {
        implementation project(":core")
        implementation "com.badlogicgames.gdx-video:gdx-video-android:1.3.2-SNAPSHOT"
        api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
        api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86_64"
        api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86"
        natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64"
        
    }
}

project(":desktop") {
    apply plugin: "java-library"


    dependencies {
        implementation project(":core")
        implementation "com.badlogicgames.gdx-video:gdx-video-desktop:1.3.2-SNAPSHOT"
        api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
        api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
        api "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
        api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
        
    }
}

The desktop project then built and ran fine, but on Android it still compained. This was a simple fix as the error message said that the minSdkVersion needed to be 16 and not 14.

In the 'build.gradle:android':

defaultConfig {
    applicationId "com.mygdx.game"
    minSdkVersion 16 // just change this
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
}

Also note that you will need to resync your gradle project.

So, this has got it building for desktop and android, I'm not using other platforms but it should be the same for what is available in the repository.

Also, I'm just about to start testing this out so I don't actually know if it is working. I'll come back and make edits as needed.

UPDATE: 28 Nov 2021

I've ditched 'gdx-video' mainly because of the overhead of converting the video frames to a texture compatile with LibGDX. I've used ffmpeg in the past and by using a custom shader to render the YUV video frame instead of converting to RGB first. This is most notable when playing 1080p videos on low end Android hardware, the video playback is very glitchy. Using my old code I was able to play 1080p 60FPS on a single core 800Mhz Arm chip. This version was struggling playing 25FPS on a quad core ARM chip.

Also the desktop version of 'gdx-video', although would build, the VideoPlayerDesktop class was missing and could not play a single thing.

So for me, it's back to the drawing board and set up two separate projects.

Upvotes: 2

Related Questions