diff --git a/settings.gradle b/settings.gradle index 4172a1ec..7abe4b74 100644 --- a/settings.gradle +++ b/settings.gradle @@ -28,6 +28,7 @@ include 'tools:d2s-reader' include 'tools:camera' include 'tools:direction' include 'tools:ds1-viewer' // deprecated +include 'tools:video-player' include 'tools:excel-serializer-generator' include 'tester' // deprecated diff --git a/tools/video-player/build.gradle b/tools/video-player/build.gradle new file mode 100644 index 00000000..1a6974b2 --- /dev/null +++ b/tools/video-player/build.gradle @@ -0,0 +1,8 @@ +description = 'Play videos from MPQ archives.' +application.mainClass = 'com.riiablo.video.VideoPlayerTool' + +dependencies { + implementation "com.badlogicgames.gdx:gdx-jnigen:$gdxVersion" + implementation "com.badlogicgames.gdx-video:gdx-video:1.3.2-SNAPSHOT" + implementation "com.badlogicgames.gdx-video:gdx-video-lwjgl:1.3.2-SNAPSHOT" +} diff --git a/tools/video-player/src/main/java/com/riiablo/video/VideoPlayerTool.java b/tools/video-player/src/main/java/com/riiablo/video/VideoPlayerTool.java new file mode 100644 index 00000000..6d4d50c7 --- /dev/null +++ b/tools/video-player/src/main/java/com/riiablo/video/VideoPlayerTool.java @@ -0,0 +1,148 @@ +package com.riiablo.video; + +import java.io.FileNotFoundException; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import com.badlogic.gdx.Application; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.video.VideoPlayer; +import com.badlogic.gdx.video.VideoPlayerCreator; + +import com.riiablo.Riiablo; +import com.riiablo.logger.Level; +import com.riiablo.logger.LogManager; +import com.riiablo.logger.Logger; +import com.riiablo.mpq.MPQFileHandleResolver; +import com.riiablo.tool.LwjglTool; +import com.riiablo.tool.Tool; +import com.riiablo.util.InstallationFinder; + +public class VideoPlayerTool extends Tool { + private static final Logger log = LogManager.getLogger(VideoPlayerTool.class); + + public static void main(String[] args) { + LogManager.setLevel(VideoPlayerTool.class.getCanonicalName(), Level.TRACE); + LwjglTool.create(VideoPlayerTool.class, "video-player", args) + .title("Video Player Tool") + .size(640, 480, false) // default video size + .start(); + } + + FileHandle home; + String file; + + float canvasX, canvasY; + float canvasWidth, canvasHeight; + + SpriteBatch batch; + VideoPlayer player; + + @Override + protected String getHelpHeader() { + return "Plays a specified D2 video file.\n" + + "E.g., {cmd} --file data/local/video/BlizNorth640x480.bik"; + } + + @Override + protected void createCliOptions(Options options) { + super.createCliOptions(options); + options.addOption(Option + .builder("f") + .longOpt("file") + .desc("path to the video file to play") + .required() + .hasArg() + .argName("path") + .build()); + } + + @Override + protected void handleCliOptions(String cmd, Options options, CommandLine cli) { + super.handleCliOptions(cmd, options, cli); + + InstallationFinder finder = InstallationFinder.getInstance(); + Array homeDirs = finder.getHomeDirs(); + home = homeDirs.first(); + + String fileOptionValue = cli.getOptionValue("file"); + file = fileOptionValue; + log.trace("file={}", file); + } + + @Override + public void create() { + Gdx.app.setLogLevel(Application.LOG_DEBUG); + Riiablo.home = home = Gdx.files.absolute(home.path()); + Riiablo.mpqs = new MPQFileHandleResolver(); + + batch = new SpriteBatch(); + player = VideoPlayerCreator.createVideoPlayer(); + player.setOnCompletionListener(new VideoPlayer.CompletionListener() { + @Override + public void onCompletionListener(FileHandle file) { + log.info("finished playing " + file.name()); + } + }); + player.setOnVideoSizeListener(new VideoPlayer.VideoSizeListener() { + @Override + public void onVideoSize(float width, float height) { + log.info("size " + width + "x" + height); + canvasWidth = width; + canvasHeight = height <= 240 ? height * 2 : height; + canvasY = Gdx.graphics.getHeight() / 2 - canvasHeight / 2; + } + }); + Gdx.app.postRunnable(new Runnable() { + @Override + public void run() { + try { + // FileHandle handle = Riiablo.mpqs.resolve(file); + // if (handle == null) throw new FileNotFoundException(file); + FileHandle handle = Gdx.files.absolute(file); + player.play(handle); + player.setVolume(0.1f); + log.info("playing " + handle); + } catch (FileNotFoundException t) { + log.error(ExceptionUtils.getRootCauseMessage(t), t); + } + } + }); + } + + @Override + public void render() { + Gdx.gl.glClearColor(0f, 0f, 0f, 0f); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + player.update(); + batch.begin(); + Texture frame = player.getTexture(); + if (frame != null) { + batch.draw(frame, canvasX, canvasY, canvasWidth, canvasHeight); + } + batch.end(); + } + + @Override + public void pause() { + player.pause(); + } + + @Override + public void resume() { + player.resume(); + } + + @Override + public void dispose() { + batch.dispose(); + player.dispose(); + } +}