|
@@ -1,184 +0,0 @@
|
|
-= Video
|
|
|
|
-:author:
|
|
|
|
-:revnumber:
|
|
|
|
-:revdate: 2016/03/17 20:48
|
|
|
|
-:relfileprefix: ../../
|
|
|
|
-:imagesdir: ../..
|
|
|
|
-ifdef::env-github,env-browser[:outfilesuffix: .adoc]
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-[WARNING]
|
|
|
|
-====
|
|
|
|
-This +++<abbr title="Application Programming Interface">API</abbr>+++ is deprecated.
|
|
|
|
-====
|
|
|
|
-
|
|
|
|
-Relevant forum topics:
|
|
|
|
-
|
|
|
|
-link:http://hub.jmonkeyengine.org/t/ive-made-a-movieappstate-so-you-dont-have-to/31673[http://hub.jmonkeyengine.org/t/ive-made-a-movieappstate-so-you-dont-have-to/31673]
|
|
|
|
-
|
|
|
|
-link:http://hub.jmonkeyengine.org/t/news-about-playing-videos-on-jme/30084/5[http://hub.jmonkeyengine.org/t/news-about-playing-videos-on-jme/30084/5]
|
|
|
|
-
|
|
|
|
-link:https://jvm-gaming.org/t/yunpm-a-java-media-player/39517[YUNPM - a Java Media Player] (java-gaming.org)
|
|
|
|
-
|
|
|
|
-link:http://www.java-gaming.org/topics/gstlwjgl-yet-another-media-player/27146/view.html[GstLWJGL] (java-gaming.org)
|
|
|
|
-
|
|
|
|
-link:http://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/com/jogamp/opengl/util/av/package-summary.html[GL Media Player] (jogamp.org)
|
|
|
|
-
|
|
|
|
-link:http://www.xuggle.com/xuggler[Xuggler]
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-jMonkeyEngine supports Jheora Ogg video (`com.jme3.video`).
|
|
|
|
-
|
|
|
|
-You create either a file inputstream to load the video from your hard drive:
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-FileInputStream fis = new FileInputStream("E:\\my_bunny.ogg");
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Or you stream the video live from a web location:
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-InputStream fis = new URL("http://server/my_video.ogg").openStream();
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Setting the queued frames to a value value higher than 5 (`videoQueue = new VQueue(5);`) will make web streamed playback smoother at the cost of memory.
|
|
|
|
-Here is an example of video streaming in context:
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
- private void createVideo(){
|
|
|
|
- try {
|
|
|
|
- InputStream fis = new URL("http://mirrorblender.top-ix.org/peach/"+
|
|
|
|
- "bigbuckbunny_movies/big_buck_bunny_480p_stereo.ogg").openStream();
|
|
|
|
- videoQueue = new VQueue(5); // streaming quality vs memory
|
|
|
|
- decoder = new AVThread(fis, videoQueue);
|
|
|
|
- videoThread = new Thread(decoder, "Jheora Video Decoder");
|
|
|
|
- videoThread.setDaemon(true);
|
|
|
|
- videoThread.start();
|
|
|
|
- masterClock = decoder.getMasterClock();
|
|
|
|
- } catch (IOException ex) {
|
|
|
|
- ex.printStackTrace();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Use the simpleUpdate() method to play the audio:
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public void simpleUpdate(float tpf){
|
|
|
|
- if (source == null){
|
|
|
|
- if (decoder.getAudioStream() != null){
|
|
|
|
- source = new AudioNode(decoder.getAudioStream(), null);
|
|
|
|
- source.setPositional(false);
|
|
|
|
- source.setReverbEnabled(false);
|
|
|
|
- audioRenderer.playSource(source);
|
|
|
|
- }else{
|
|
|
|
- // uncomment this statement to be able to play videos
|
|
|
|
- // without audio.
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (waitTime > 0){
|
|
|
|
- waitTime -= tpf;
|
|
|
|
- if (waitTime > 0)
|
|
|
|
- return;
|
|
|
|
- else{
|
|
|
|
- waitTime = 0;
|
|
|
|
- drawFrame(frameToDraw);
|
|
|
|
- frameToDraw = null;
|
|
|
|
- }
|
|
|
|
- }else{
|
|
|
|
- VFrame frame;
|
|
|
|
- try {
|
|
|
|
- frame = videoQueue.take();
|
|
|
|
- } catch (InterruptedException ex){
|
|
|
|
- stop();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- if (frame.getTime() < lastFrameTime){
|
|
|
|
- videoQueue.returnFrame(frame);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (frame.getTime() == -2){
|
|
|
|
- // end of stream
|
|
|
|
- System.out.println("End of stream");
|
|
|
|
- stop();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- long AV_SYNC_THRESHOLD = 1 * Clock.MILLIS_TO_NANOS;
|
|
|
|
-
|
|
|
|
- long delay = frame.getTime() - lastFrameTime;
|
|
|
|
- long diff = frame.getTime() - masterClock.getTime();
|
|
|
|
- long syncThresh = delay > AV_SYNC_THRESHOLD ? delay : AV_SYNC_THRESHOLD;
|
|
|
|
-
|
|
|
|
- // if difference is more than 1 second, synchronize.
|
|
|
|
- if (Math.abs(diff) < Clock.SECONDS_TO_NANOS){
|
|
|
|
- if(diff <= -syncThresh) {
|
|
|
|
- delay = 0;
|
|
|
|
- } else if(diff >= syncThresh) {
|
|
|
|
- delay = 2 * delay;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- System.out.println("M: "+decoder.getSystemClock().getTimeSeconds()+
|
|
|
|
- ", V: "+decoder.getVideoClock().getTimeSeconds()+
|
|
|
|
- ", A: "+decoder.getAudioClock().getTimeSeconds());
|
|
|
|
-
|
|
|
|
- if (delay > 0){
|
|
|
|
- waitNanos(delay);
|
|
|
|
- drawFrame(frame);
|
|
|
|
- }else{
|
|
|
|
- videoQueue.returnFrame(frame);
|
|
|
|
- lastFrameTime = frame.getTime();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-Helper Methods:
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
- private void drawFrame(VFrame frame){
|
|
|
|
- Image image = frame.getImage();
|
|
|
|
- frame.setImage(image);
|
|
|
|
- picture.setTexture(assetManager, frame, false);
|
|
|
|
-
|
|
|
|
- // note: this forces renderer to upload frame immediately,
|
|
|
|
- // since it is going to be returned to the video queue pool
|
|
|
|
- // it could be used again.
|
|
|
|
- renderer.setTexture(0, frame);
|
|
|
|
- videoQueue.returnFrame(frame);
|
|
|
|
- lastFrameTime = frame.getTime();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
-[source,java]
|
|
|
|
-----
|
|
|
|
-
|
|
|
|
- private void waitNanos(long time){
|
|
|
|
- long millis = (long) (time / Clock.MILLIS_TO_NANOS);
|
|
|
|
- int nanos = (int) (time - (millis * Clock.MILLIS_TO_NANOS));
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- Thread.sleep(millis, nanos);
|
|
|
|
- }catch (InterruptedException ex){
|
|
|
|
- stop();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-----
|
|
|