JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
CrossFadePlayer.java
Go to the documentation of this file.
1/**
2 * Copyright 2014 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.demos.av;
30
31import com.jogamp.common.av.AudioSink;
32import com.jogamp.common.net.Uri;
33import com.jogamp.common.util.InterruptSource;
34import com.jogamp.opengl.util.av.GLMediaPlayer;
35import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener;
36import com.jogamp.opengl.util.av.GLMediaPlayer.StreamException;
37import com.jogamp.opengl.util.av.GLMediaPlayerFactory;
38import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame;
39
40import java.io.File;
41
42/**
43 * Parallel media player that demonstrate CrossFade of audio volume during playback.
44 * This also demonstrate audio only playback of the GLMediaPlayer.
45 */
46public class CrossFadePlayer
47{
48 static GLMediaPlayer[] player;
49 static volatile boolean stop = false;
50
51 public static void main(final String[] args)
52 {
53
54 if(args.length==0) {
55 System.out.println("No files! \n" +
56 "pass as many media files you want\n" +
57 "to the CrossFadePlayer arguments \n" +
58 "and i will try CrossFade-play them all in parallel!");
59 }
60
61 final GLMediaEventListener mediaEventListener = new GLMediaEventListener()
62 {
63 @Override
64 public void attributesChanged(final GLMediaPlayer mp, final GLMediaPlayer.EventMask eventMask, final long when)
65 {
66 System.out.println("\n***\nAttributesChanges: "+eventMask+", when "+when);
67 System.out.println("State of player: " + mp.getState().toString() +"\n");
68
69 if ( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Init) ) {
70 System.out.println("Duration: " + mp.getDuration() + "ms");
71 System.out.println("Volume: " + mp.getAudioVolume());
72 System.out.println("player.initGL()...");
73 new InterruptSource.Thread() {
74 @Override
75 public void run() {
76 try {
77 mp.initGL(null);
78 if ( GLMediaPlayer.State.Paused == mp.getState() ) { // init OK
79 mp.resume();
80 }
81 } catch (final Exception e) {
82 e.printStackTrace();
83 }
84 }
85 }.start();
86 } else if ( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Pause) ) {
87 } else if ( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Play) ) {
88 System.out.println(mp.toString());
89 System.out.println(mp.getAudioSink().toString());
90 } else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.EOS) ) {
91 final StreamException se = mp.getStreamException();
92 if( null != se ) {
93 System.err.println("Player State: Exception");
94 stop = true;
95 } else {
96 new InterruptSource.Thread() {
97 @Override
98 public void run() {
99 System.out.println("mp.setPlaySpeed(1f) returned: " + mp.setPlaySpeed(1f));
100 mp.seek(0);
101 mp.resume();
102 }
103 }.start();
104 }
105 }
106 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Error) || eventMask.isSet(GLMediaPlayer.EventMask.Bit.EOS) ) {
107 final StreamException se = mp.getStreamException();
108 if( null != se ) {
109 se.printStackTrace();
110 }
111 new InterruptSource.Thread() {
112 @Override
113 public void run() {
114 System.out.println("terminating...");
115 stop = true;
116 }
117 }.start();
118 }
119
120 }
121 };
122
123 // Initialize media players
124 player = new GLMediaPlayer[args.length];
125 int i=0;
126 for( final String arg: args ) {
128 if(player[i]!=null){
129 System.out.println("Created CrossFade player: "+ i + " " + player[i].getClass().getName());
130 player[i].addEventListener(mediaEventListener);
131 try {
132 final String filename = arg;
133 if(filename.equals("")){
134 System.out.println("No file selected: arg " + i +" = "+ filename);
135 player[i]=null;
136 } else {
137 final File file = new File(filename);
138 if(!file.exists()){
139 System.out.println("File do not exist");
140 } else {
141 final Uri uri = Uri.valueOf(file);
142 System.out.println("State of player "+ i +": " + player[i].getState().toString());
143 System.out.println("...initializing stream "+ i +"...");
145
146 }
147 }
148 } catch (final Exception e1) {
149 e1.printStackTrace();
150 }
151 } else {
152 System.out.println("Failed to create player "+ i +"!");
153 }
154 i++;
155 }
156
157
158 // Main thread CrossFade until playback is done
159 final long startTime = com.jogamp.common.os.Platform.currentTimeMillis();
160 final double piPlayers = Math.PI*2.0f/args.length;
161 StreamException se = null;
162 while( null == se && stop == false ) {
163 try {
164 Thread.sleep(100);
165 } catch (final InterruptedException e) { }
166
167 // Find out the longest duration...
168 float maxDuration = 1000.0f ;
169 for(final GLMediaPlayer p: player) {
170 if(p!=null){
171 if( p.getDuration() > maxDuration) {
172 maxDuration = p.getDuration();
173 }
174 }
175 }
176
177 // tune the volume on players to crossfade!
178 final float progress = (com.jogamp.common.os.Platform.currentTimeMillis()-startTime)/maxDuration;
179
180 i = 0;
181 for(final GLMediaPlayer p: player){
182 if(p!=null){
183 final AudioSink sink = p.getAudioSink();
184 if(sink != null){
185 final float volume = (float) (0.5f+(0.5f*(Math.cos(40.0f*progress+(piPlayers*i)))));
186 final float playbacktime = com.jogamp.common.os.Platform.currentTimeMillis()-startTime;
187 // System.out.println("player: "+ i +" volume = " + volume +" progress = "+ progress +" time = "+ playbacktime + " / duration = " + maxDuration);
188 sink.setVolume(volume);
189 }
190
191 se = p.getStreamException();
192 if( null != se) {
193 se.printStackTrace();
194 throw new RuntimeException(se);
195 }
196 }
197
198 i++;
199 }
200 }
201
202 for(final GLMediaPlayer p: player) {
203 if(p!=null)
204 p.destroy(null);
205 }
206 System.out.println("...main exit...");
207 }
208}
Parallel media player that demonstrate CrossFade of audio volume during playback.
static void main(final String[] args)
A StreamException encapsulates a caught exception in the decoder thread, a.k.a StreamWorker,...
As the contract of GLMediaFrameListener and TexSeqEventListener requests, implementations of GLMediaE...
GLMediaPlayer interface specifies a TextureSequence state machine using a multiplexed audio/video str...
float getAudioVolume()
Returns the audio volume.
int getDuration()
Return total duration of stream in msec.
static final int STREAM_ID_NONE
Constant {@value} for mute or not available.
void initGL(GL gl)
Initializes OpenGL related resources.
static final int TEXTURE_COUNT_DEFAULT
Default texture count, value {@value}.
boolean setPlaySpeed(float rate)
Sets the playback speed.
String toString()
Returns a string representation of this player, incl.
void playStream(Uri streamLoc, int vid, int aid, int sid, int textureCount)
Issues asynchronous stream initialization.
void addEventListener(GLMediaEventListener l)
Adds a GLMediaEventListener to this player.
StreamException getStreamException()
Returns the StreamException caught in the decoder thread, or null if none occured.
int seek(int msec)
Seeks to the new absolute position.
AudioSink getAudioSink()
If implementation uses a AudioSink, it's instance will be returned.
State resume()
Starts or resumes the StreamWorker decoding thread.
static final int STREAM_ID_AUTO
Constant {@value} for auto or unspecified.