JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
MovieSimple.java
Go to the documentation of this file.
1/**
2 * Copyright 2012-2023 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 java.io.File;
32import java.io.IOException;
33import java.net.URI;
34import java.net.URISyntaxException;
35
36import com.jogamp.common.av.PTS;
37import com.jogamp.common.net.Uri;
38import com.jogamp.common.os.Clock;
39import com.jogamp.common.util.InterruptSource;
40import com.jogamp.graph.curve.Region;
41import com.jogamp.graph.curve.opengl.GLRegion;
42import com.jogamp.graph.curve.opengl.RegionRenderer;
43import com.jogamp.graph.font.Font;
44import com.jogamp.graph.font.FontScale;
45import com.jogamp.newt.Window;
46import com.jogamp.newt.event.KeyAdapter;
47import com.jogamp.newt.event.KeyEvent;
48import com.jogamp.newt.event.KeyListener;
49import com.jogamp.newt.event.MouseAdapter;
50import com.jogamp.newt.event.MouseEvent;
51import com.jogamp.newt.event.MouseListener;
52import com.jogamp.newt.event.WindowAdapter;
53import com.jogamp.newt.event.WindowEvent;
54import com.jogamp.newt.opengl.GLWindow;
55import com.jogamp.opengl.GL2ES2;
56import com.jogamp.opengl.GLAnimatorControl;
57import com.jogamp.opengl.GLAutoDrawable;
58import com.jogamp.opengl.GLCapabilities;
59import com.jogamp.opengl.GLEventListener;
60import com.jogamp.opengl.GLException;
61import com.jogamp.opengl.GLProfile;
62import com.jogamp.opengl.GLRunnable;
63import com.jogamp.opengl.JoglVersion;
64import com.jogamp.opengl.demos.es2.TextureSequenceES2;
65import com.jogamp.opengl.demos.graph.TextRendererGLELBase;
66import com.jogamp.opengl.demos.util.MiscUtils;
67import com.jogamp.opengl.util.Animator;
68import com.jogamp.opengl.util.GLReadBufferUtil;
69import com.jogamp.opengl.util.av.GLMediaPlayer;
70import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener;
71import com.jogamp.opengl.util.av.GLMediaPlayerFactory;
72import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame;
73
74/**
75 * Simple planar movie player w/ orthogonal 1:1 projection.
76 */
77public class MovieSimple implements GLEventListener {
78 public static final int EFFECT_NORMAL = 0;
79 public static final int EFFECT_GRADIENT_BOTTOM2TOP = 1<<1;
80 public static final int EFFECT_TRANSPARENT = 1<<3;
81
82 public static final String WINDOW_KEY = "window";
83 public static final String PLAYER = "player";
84
85 private static boolean waitForKey = false;
86 private int surfWidth, surfHeight;
87 private int prevMouseX; // , prevMouseY;
88 private boolean orthoProjection = true;
89 private float zoom0;
90 private float zoom1;
91 private float zoom;
92 private int effects = EFFECT_NORMAL;
93 private float alpha = 1.0f;
94 private int swapInterval = 1;
95 private boolean swapIntervalSet = true;
96
97 private TextureSequenceES2 screen=null;
98 private GLMediaPlayer mPlayer;
99 private final boolean mPlayerShared;
100 private boolean useOriginalScale;
101 private volatile boolean resetGLState = false;
102
103 private volatile GLAutoDrawable autoDrawable = null;
104
105 /** Blender's Big Buck Bunny: 24f 416p H.264, AAC 48000 Hz, 2 ch, mpeg stream. */
106 public static final Uri defURI;
107 static {
108 Uri _defURI = null;
109 try {
110 // Blender's Big Buck Bunny Trailer: 24f 640p VP8, Vorbis 44100Hz mono, WebM/Matroska Stream.
111 // _defURI = new URI("http://video.webmfiles.org/big-buck-bunny_trailer.webm");
112 _defURI = Uri.cast("http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4");
113 } catch (final URISyntaxException e) {
114 e.printStackTrace();
115 }
116 defURI = _defURI;
117 }
118
119 private final class InfoTextRendererGLELBase extends TextRendererGLELBase {
120 private final Font font = getFont(0, 0, 0);
121 private final float fontSize = 10f;
122 private final GLRegion regionFPS;
123
124 InfoTextRendererGLELBase(final GLProfile glp, final int rmode) {
125 // FIXME: Graph TextRenderer does not AA well w/o MSAA and FBO
126 super(rmode, Region.DEFAULT_AA_SAMPLE_COUNT);
128 regionFPS = GLRegion.create(glp, renderModes, null, 0, 0);
129 System.err.println("RegionFPS "+Region.getRenderModeString(renderModes)+", sampleCount "+Region.DEFAULT_AA_SAMPLE_COUNT+", class "+regionFPS.getClass().getName());
130 staticRGBAColor[0] = 0.9f;
131 staticRGBAColor[1] = 0.9f;
132 staticRGBAColor[2] = 0.9f;
133 staticRGBAColor[3] = 1.0f;
134 }
135
136 @Override
137 public void init(final GLAutoDrawable drawable) {
138 super.init(drawable);
139 }
140
141 @Override
142 public void dispose(final GLAutoDrawable drawable) {
143 if( null != regionFPS ) {
144 regionFPS.destroy(drawable.getGL().getGL2ES2());
145 }
146 super.dispose(drawable);
147 }
148
149 String text1_old = null;
150
151 @Override
152 public void display(final GLAutoDrawable drawable) {
153 final GLAnimatorControl anim = drawable.getAnimator();
154 final float lfps = null != anim ? anim.getLastFPS() : 0f;
155 final float tfps = null != anim ? anim.getTotalFPS() : 0f;
156 final long currentMillis = Clock.currentMillis();
157 final PTS scr = mPlayer.getPTS();
158 final float pts_s = scr.get(currentMillis) / 1000f;
159 final float now = currentMillis / 1000f;
160
161 // Note: MODELVIEW is from [ 0 .. height ]
162
163 final int height = drawable.getSurfaceHeight();
164
165 final float aspect = (float)mPlayer.getWidth() / (float)mPlayer.getHeight();
166
167 final String ptsPrec = null != regionFPS ? "3.1" : "3.0";
168 final String text1 = String.format("%0"+ptsPrec+"f/%0"+ptsPrec+"f/%0"+ptsPrec+"f s, %s (%01.2fx, vol %01.2f), a %01.2f, fps %02.1f -> %02.1f / %02.1f, swap %d",
169 now, pts_s, mPlayer.getDuration() / 1000f,
170 mPlayer.getState().toString().toLowerCase(), mPlayer.getPlaySpeed(), mPlayer.getAudioVolume(),
171 aspect, mPlayer.getFramerate(), lfps, tfps, drawable.getGL().getSwapInterval());
172 final String text2 = String.format("audio: id %d, kbps %d, codec %s",
173 mPlayer.getAID(), mPlayer.getAudioBitrate()/1000, mPlayer.getAudioCodec());
174 final String text3 = String.format("video: id %d, kbps %d, codec %s",
175 mPlayer.getVID(), mPlayer.getVideoBitrate()/1000, mPlayer.getVideoCodec());
176 final String text4 = mPlayer.getUri().path.decode();
177 if( displayOSD && null != renderer ) {
178 // We share ClearColor w/ MovieSimple's init !
179 final float pixelSize = FontScale.toPixels(fontSize, dpiH);
180 final GL2ES2 gl = drawable.getGL().getGL2ES2();
181 if( !text1.equals(text1_old) ) {
182 renderString(drawable, font, pixelSize, text1, 1 /* col */, 1 /* row */, 0, 0, -1, regionFPS.clear(gl)); // clear-cache
183 text1_old = text1;
184 } else {
185 renderRegion(drawable, font, pixelSize, 1 /* col */, 1 /* row */, 0, 0, -1, regionFPS);
186 }
187 renderString(drawable, font, pixelSize, text2, 1 /* col */, -4 /* row */, 0, height, -1, true);
188 renderString(drawable, font, pixelSize, text3, 1 /* col */, -3 /* row */, 0, height, -1, true);
189 renderString(drawable, font, pixelSize, text4, 1 /* col */, -2 /* row */, 0, height, -1, true);
190 }
191 } };
192 private InfoTextRendererGLELBase textRendererGLEL = null;
193 private boolean displayOSD = true;
194
195 public void printScreen(final GLAutoDrawable drawable) throws GLException, IOException {
196 final String filename = String.format("MovieSimple-snap%02d-%03dx%03d.png", screenshot_num++, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
197 if(screenshot.readPixels(drawable.getGL(), false)) {
198 screenshot.write(new File(filename.toString()));
199 }
200 }
201 private final GLReadBufferUtil screenshot;
202 private int screenshot_num = 0;
203
204 public void printScreenOnGLThread(final GLAutoDrawable drawable) {
205 drawable.invoke(false, new GLRunnable() {
206 @Override
207 public boolean run(final GLAutoDrawable drawable) {
208 try {
209 printScreen(drawable);
210 } catch (final GLException e) {
211 e.printStackTrace();
212 } catch (final IOException e) {
213 e.printStackTrace();
214 }
215 return true;
216 }
217 });
218 }
219
220 private final MouseListener mouseAction = new MouseAdapter() {
221
222 @Override
223 public void mouseClicked(final MouseEvent e) {
224 if(null != autoDrawable && e.getClickCount() == 3 ) {
225 MiscUtils.destroyWindow(autoDrawable);
226 }
227 }
228
229 @Override
230 public void mousePressed(final MouseEvent e) {
231 if(e.getY()<=surfHeight/2 && null!=mPlayer && 1 == e.getClickCount()) {
232 if(GLMediaPlayer.State.Playing == mPlayer.getState()) {
233 mPlayer.pause(false);
234 } else {
235 mPlayer.resume();
236 }
237 }
238 }
239 @Override
240 public void mouseReleased(final MouseEvent e) {
241 if(e.getY()<=surfHeight/2) {
242 zoom = zoom0;
243 if( null != screen ) {
244 screen.setZoom(zoom);
245 screen.setZRotation(-1f);
246 }
247 System.err.println("zoom: "+zoom);
248 }
249 }
250 @Override
251 public void mouseMoved(final MouseEvent e) {
252 prevMouseX = e.getX();
253 // prevMouseY = e.getY();
254 }
255 @Override
256 public void mouseDragged(final MouseEvent e) {
257 final int x = e.getX();
258 final int y = e.getY();
259
260 if(y>surfHeight/2) {
261 final float dp = (float)(x-prevMouseX)/(float)surfWidth;
262 final int pts0 = mPlayer.getPTS().getCurrent();
263 mPlayer.seek(pts0 + (int) (mPlayer.getDuration() * dp));
264 } else {
265 mPlayer.resume();
266 zoom = zoom1;
267 if( null != screen ) {
268 screen.setZoom(zoom);
269 screen.setZRotation(1f);
270 }
271 }
272
273 prevMouseX = x;
274 // prevMouseY = y;
275 }
276 @Override
277 public void mouseWheelMoved(final MouseEvent e) {
278 if( !e.isShiftDown() ) {
279 zoom += e.getRotation()[1]/10f; // vertical: wheel
280 if( null != screen ) {
281 screen.setZoom(zoom);
282 }
283 System.err.println("zoom: "+zoom);
284 }
285 } };
286
287 private final KeyListener keyAction = new KeyAdapter() {
288 @Override
289 public void keyReleased(final KeyEvent e) {
290 if( e.isAutoRepeat() ) {
291 return;
292 }
293 System.err.println("MC "+e);
294 final int pts0 = mPlayer.getPTS().getCurrent();
295 int pts1 = 0;
296 switch(e.getKeySymbol()) {
297 case KeyEvent.VK_V: {
298 switch(swapInterval) {
299 case 0: swapInterval = -1; break;
300 case -1: swapInterval = 1; break;
301 case 1: swapInterval = 0; break;
302 default: swapInterval = 1; break;
303 }
304 swapIntervalSet = true;
305 break;
306 }
307 case KeyEvent.VK_O: displayOSD = !displayOSD; break;
308 case KeyEvent.VK_RIGHT: pts1 = pts0 + 1000; break;
309 case KeyEvent.VK_UP: pts1 = pts0 + 10000; break;
310 case KeyEvent.VK_PAGE_UP: pts1 = pts0 + 30000; break;
311 case KeyEvent.VK_LEFT: pts1 = pts0 - 1000; break;
312 case KeyEvent.VK_DOWN: pts1 = pts0 - 10000; break;
313 case KeyEvent.VK_PAGE_DOWN: pts1 = pts0 - 30000; break;
314 case KeyEvent.VK_HOME:
315 case KeyEvent.VK_BACK_SPACE: {
316 System.err.println("Seek: "+pts0+" -> 0");
317 mPlayer.seek(0);
318 break;
319 }
320 case KeyEvent.VK_SPACE: {
321 if( GLMediaPlayer.State.Paused == mPlayer.getState() ) {
322 mPlayer.resume();
323 } else if(GLMediaPlayer.State.Uninitialized == mPlayer.getState()) {
324 playStream(mPlayer.getUri(), GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 3 /* textureCount */);
325 } else if( e.isShiftDown() ) {
326 mPlayer.stop();
327 } else {
328 mPlayer.pause(false);
329 }
330 break;
331 }
332 case KeyEvent.VK_MULTIPLY:
333 mPlayer.setPlaySpeed(1.0f);
334 break;
335 case KeyEvent.VK_SUBTRACT: {
336 float playSpeed = mPlayer.getPlaySpeed();
337 if( e.isShiftDown() ) {
338 playSpeed /= 2.0f;
339 } else {
340 playSpeed -= 0.1f;
341 }
342 mPlayer.setPlaySpeed(playSpeed);
343 } break;
344 case KeyEvent.VK_ADD: {
345 float playSpeed = mPlayer.getPlaySpeed();
346 if( e.isShiftDown() ) {
347 playSpeed *= 2.0f;
348 } else {
349 playSpeed += 0.1f;
350 }
351 mPlayer.setPlaySpeed(playSpeed);
352 } break;
353 case KeyEvent.VK_M: {
354 float audioVolume = mPlayer.getAudioVolume();
355 if( audioVolume > 0.5f ) {
356 audioVolume = 0f;
357 } else {
358 audioVolume = 1f;
359 }
360 mPlayer.setAudioVolume(audioVolume);
361 } break;
362 case KeyEvent.VK_S:
363 if(null != autoDrawable) {
364 printScreenOnGLThread(autoDrawable);
365 }
366 break;
367 case KeyEvent.VK_F4:
368 case KeyEvent.VK_ESCAPE:
369 case KeyEvent.VK_Q:
370 if(null != autoDrawable) {
371 MiscUtils.destroyWindow(autoDrawable);
372 }
373 break;
374 }
375
376 if( 0 != pts1 ) {
377 System.err.println("Seek: "+pts0+" -> "+pts1);
378 mPlayer.seek(pts1);
379 }
380 } };
381
382 /**
383 * Default constructor which also issues {@link #playStream(URI, int, int, int)} w/ default values
384 * and polls until the {@link GLMediaPlayer} is {@link GLMediaPlayer.State#Initialized}.
385 * If {@link GLMediaEventListener#EVENT_CHANGE_EOS} is reached, the stream is started over again.
386 * <p>
387 * This default constructor is merely useful for some <i>drop-in</i> test, e.g. using an applet.
388 * </p>
389 */
390 public MovieSimple() {
391 this(null);
392
394 @Override
395 public void attributesChanged(final GLMediaPlayer mp, final GLMediaPlayer.EventMask eventMask, final long when) {
396 System.err.println("MovieSimple.0 AttributesChanges: "+eventMask+", when "+when);
397 System.err.println("MovieSimple.0 State: "+mp);
398 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.EOS) ) {
399 new InterruptSource.Thread() {
400 @Override
401 public void run() {
402 // loop for-ever ..
403 mPlayer.seek(0);
404 mPlayer.resume();
405 } }.start();
406 }
407 }
408 });
410 }
411
412 /** Custom constructor, user needs to issue {@link #playStream(URI, int, int, int)} afterwards. */
413 public MovieSimple(final GLMediaPlayer sharedMediaPlayer) throws IllegalStateException {
414 screenshot = new GLReadBufferUtil(false, false);
415 mPlayer = sharedMediaPlayer;
416 mPlayerShared = null != mPlayer;
417 useOriginalScale = false;
418 if( !mPlayerShared ) {
420 mPlayer.attachObject(PLAYER, this);
421 }
422 System.out.println("pC.1a shared "+mPlayerShared+", "+mPlayer);
423 }
424
425 public void playStream(final Uri streamLoc, final int vid, final int aid, final int textureCount) {
426 mPlayer.playStream(streamLoc, vid, aid, GLMediaPlayer.STREAM_ID_NONE, textureCount);
427 System.out.println("pC.1b "+mPlayer);
428 }
429
430 public void setSwapInterval(final int v) { this.swapInterval = v; }
431
432 public void setUseOriginalScale(final boolean v) {
433 useOriginalScale = v;
434 }
435
436 public GLMediaPlayer getGLMediaPlayer() { return mPlayer; }
437
438 /** defaults to true */
439 public void setOrthoProjection(final boolean v) { orthoProjection=v; }
440 public boolean getOrthoProjection() { return orthoProjection; }
441
442 public void setEffects(final int e) { effects = e; };
443 public void setTransparency(final float alpha) { this.alpha = alpha; }
444
445 public void resetGLState() {
446 resetGLState = true;
447 }
448
449 @Override
450 public void init(final GLAutoDrawable drawable) {
451 if(null == mPlayer) {
452 throw new InternalError("mPlayer null");
453 }
454 // final boolean hasVideo = GLMediaPlayer.STREAM_ID_NONE != mPlayer.getVID();
455 resetGLState = false;
456
457 zoom0 = orthoProjection ? 0f : -2.5f;
458 zoom1 = orthoProjection ? 0f : -5f;
459 zoom = zoom0;
460
461 autoDrawable = drawable;
462
463 final GL2ES2 gl = drawable.getGL().getGL2ES2();
464 System.err.println(JoglVersion.getGLInfo(gl, null));
465 System.err.println("Alpha: "+alpha+", opaque "+drawable.getChosenGLCapabilities().isBackgroundOpaque()+
466 ", "+drawable.getClass().getName()+", "+drawable);
467
468 screen = new TextureSequenceES2(mPlayer, mPlayerShared, orthoProjection, zoom);
469 screen.setEffects(effects);
470 screen.setTransparency(alpha);
471 screen.setUseOriginalScale(useOriginalScale);
472
473 if(waitForKey) {
474 MiscUtils.waitForKey("Init>");
475 }
476
477 try {
478 mPlayer.initGL(gl);
479 } catch (final Exception e) {
480 e.printStackTrace();
481 if(null != mPlayer) {
482 mPlayer.destroy(gl);
483 mPlayer = null;
484 }
485 throw new GLException(e);
486 }
487 screen.init(drawable);
488
489 final Object upstreamWidget = drawable.getUpstreamWidget();
490 if (upstreamWidget instanceof Window) {
491 final Window window = (Window) upstreamWidget;
492 window.addMouseListener(mouseAction);
493 window.addKeyListener(keyAction);
494 surfWidth = window.getSurfaceWidth();
495 surfHeight = window.getSurfaceHeight();
496 }
497 final int rmode = drawable.getChosenGLCapabilities().getSampleBuffers() ? 0 : Region.VBAA_RENDERING_BIT;
498 textRendererGLEL = new InfoTextRendererGLELBase(gl.getGLProfile(), rmode);
499 drawable.addGLEventListener(textRendererGLEL);
500 }
501
502 @Override
503 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
504 if(null == mPlayer) { return; }
505 screen.reshape(drawable, x, y, width, height);
506 surfWidth = width;
507 surfHeight = height;
508 System.out.println("pR "+mPlayer);
509 }
510
511 @Override
512 public void dispose(final GLAutoDrawable drawable) {
513 autoDrawable = null;
514 screenshot.dispose(drawable.getGL());
515 disposeImpl(drawable, true);
516 }
517
518 private void disposeImpl(final GLAutoDrawable drawable, final boolean disposePlayer) {
519 if(null == mPlayer) { return; }
520
521 final Object upstreamWidget = drawable.getUpstreamWidget();
522 if (upstreamWidget instanceof Window) {
523 final Window window = (Window) upstreamWidget;
524 window.removeMouseListener(mouseAction);
525 window.removeKeyListener(keyAction);
526 }
527
528 System.out.println("pD.1 "+mPlayer+", disposePlayer "+disposePlayer);
529 final GL2ES2 gl = drawable.getGL().getGL2ES2();
530 if( null != textRendererGLEL ) {
531 drawable.disposeGLEventListener(textRendererGLEL, true);
532 textRendererGLEL = null;
533 }
534 if( disposePlayer ) {
535 if(!mPlayerShared) {
536 mPlayer.destroy(gl);
537 } else {
538 // mPlayer.stop(gl);
539 }
540 System.out.println("pD.X "+mPlayer);
541 mPlayer=null;
542 }
543 screen.dispose(drawable);
544 screen = null;
545 }
546
547 long lastPerfPos = 0;
548
549 @Override
550 public void display(final GLAutoDrawable drawable) {
551 final GL2ES2 gl = drawable.getGL().getGL2ES2();
552 if( swapIntervalSet ) {
553 final int _swapInterval = swapInterval;
554 gl.setSwapInterval(_swapInterval); // in case switching the drawable (impl. may bound attribute there)
555 if( null != drawable.getAnimator() ) {
556 drawable.getAnimator().resetFPSCounter();
557 }
558 swapInterval = gl.getSwapInterval();
559 System.err.println("Swap Interval: "+_swapInterval+" -> "+swapInterval);
560 swapIntervalSet = false;
561 }
562 if(null == mPlayer) { return; }
563
564 if( resetGLState ) {
565 resetGLState = false;
566 System.err.println("XXX resetGLState");
567 disposeImpl(drawable, false);
568 init(drawable);
569 reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
570 }
571
572 final long currentPos = System.currentTimeMillis();
573 if( currentPos - lastPerfPos > 2000 ) {
574 // System.err.println( mPlayer.getPerfString() );
575 lastPerfPos = currentPos;
576 }
577 screen.display(drawable);
578 }
579
580 static class MyGLMediaEventListener implements GLMediaEventListener {
581 void destroyWindow(final Window window) {
582 new InterruptSource.Thread( () -> { window.destroy(); } ).start();
583 }
584 @Override
585 public void attributesChanged(final GLMediaPlayer mp, final GLMediaPlayer.EventMask eventMask, final long when) {
586 System.err.println("MovieSimple.1 AttributesChanges: "+eventMask+", when "+when);
587 System.err.println("MovieSimple.1 State: "+mp);
588 final GLWindow window = (GLWindow) mp.getAttachedObject(WINDOW_KEY);
589 final MovieSimple ms = (MovieSimple)mp.getAttachedObject(PLAYER);
590 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Size) ) {
591 if( origSize ) {
592 window.setSurfaceSize(mp.getWidth(), mp.getHeight());
593 }
594 // window.disposeGLEventListener(ms, false /* remove */ );
595 // ms.resetGLState();
596 }
597 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Init) ) {
598 // Use GLEventListener in all cases [A+V, V, A]
599 final GLAnimatorControl anim = window.getAnimator();
600 anim.setUpdateFPSFrames(60, null);
601 anim.resetFPSCounter();
602 ms.resetGLState();
603
604 /**
605 * Kick off player w/o GLEventListener, i.e. for audio only.
606 *
607 new InterruptSource.Thread() {
608 public void run() {
609 try {
610 mp.initGL(null);
611 if ( GLMediaPlayer.State.Paused == mp.getState() ) { // init OK
612 mp.play();
613 }
614 System.out.println("play.1 "+mp);
615 } catch (Exception e) {
616 e.printStackTrace();
617 destroyWindow();
618 return;
619 }
620 }
621 }.start();
622 */
623 } else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Play) ) {
624 window.getAnimator().resetFPSCounter();
625 }
626
627 boolean destroy = false;
628 Throwable err = null;
629
630 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.EOS) ) {
631 err = ms.mPlayer.getStreamException();
632 if( null != err ) {
633 System.err.println("MovieSimple State: Exception");
634 destroy = true;
635 } else {
636 if( loopEOS ) {
637 new InterruptSource.Thread() {
638 @Override
639 public void run() {
640 mp.setPlaySpeed(1f);
641 mp.seek(0);
642 mp.resume();
643 }
644 }.start();
645 } else {
646 destroy = true;
647 }
648 }
649 }
650 if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Error) ) {
651 err = ms.mPlayer.getStreamException();
652 if( null != err ) {
653 System.err.println("MovieSimple State: Exception");
654 }
655 destroy = true;
656 }
657 if( destroy ) {
658 if( null != err ) {
659 err.printStackTrace();
660 }
661 destroyWindow(window);
662 }
663 }
664 };
665 public final static MyGLMediaEventListener myGLMediaEventListener = new MyGLMediaEventListener();
666
667 static boolean loopEOS = false;
668 static boolean origSize;
669
670 public static void main(final String[] args) throws IOException, URISyntaxException {
671 int swapInterval = 1;
672 float playSpeed = 1.0f;
673 int width = 800;
674 int height = 600;
675 int textureCount = 3; // default - threaded
676 boolean ortho = true;
677 boolean useOrigScale = false;
678
679 boolean forceES2 = false;
680 boolean forceES3 = false;
681 boolean forceGL3 = false;
682 boolean forceGLDef = false;
685 float audioVolume = 1.0f;
686
687 final int windowCount;
688 {
689 int _windowCount = 0;
690 for(int i=0; i<args.length; i++) {
691 if(args[i].equals("-url")) {
692 i++;
693 _windowCount++;
694 }
695 }
696 windowCount = Math.max(1, _windowCount);
697 }
698 final String[] urls_s = new String[windowCount];
699 {
700 boolean _origSize = false;
701 int url_idx = 0;
702 for(int i=0; i<args.length; i++) {
703 if(args[i].equals("-vid")) {
704 i++;
705 vid = MiscUtils.atoi(args[i], vid);
706 } else if(args[i].equals("-aid")) {
707 i++;
708 aid = MiscUtils.atoi(args[i], aid);
709 } else if(args[i].equals("-width")) {
710 i++;
711 width = MiscUtils.atoi(args[i], width);
712 } else if(args[i].equals("-height")) {
713 i++;
714 height = MiscUtils.atoi(args[i], height);
715 } else if(args[i].equals("-osize")) {
716 _origSize = true;
717 } else if(args[i].equals("-textureCount")) {
718 i++;
719 textureCount = MiscUtils.atoi(args[i], textureCount);
720 } else if(args[i].equals("-es2")) {
721 forceES2 = true;
722 } else if(args[i].equals("-es3")) {
723 forceES3 = true;
724 } else if(args[i].equals("-gl3")) {
725 forceGL3 = true;
726 } else if(args[i].equals("-gldef")) {
727 forceGLDef = true;
728 } else if(args[i].equals("-vsync")) {
729 i++;
730 swapInterval = MiscUtils.atoi(args[i], swapInterval);
731 } else if(args[i].equals("-speed")) {
732 i++;
733 playSpeed = MiscUtils.atof(args[i], playSpeed);
734 } else if(args[i].equals("-mute")) {
735 audioVolume = 0.0f;
736 } else if(args[i].equals("-projection")) {
737 ortho=false;
738 } else if(args[i].equals("-orig_scale")) {
739 useOrigScale=true;
740 } else if(args[i].equals("-loop")) {
741 loopEOS=true;
742 } else if(args[i].equals("-url")) {
743 i++;
744 urls_s[url_idx++] = args[i];
745 } else if(args[i].equals("-wait")) {
746 waitForKey = true;
747 }
748 }
749 origSize = _origSize;
750 }
751 Uri streamLoc0 = null;
752 if( null != urls_s[0] ) {
753 streamLoc0 = Uri.tryUriOrFile( urls_s[0] );
754 }
755 if( null == streamLoc0 ) {
756 streamLoc0 = defURI;
757 }
758 System.err.println("url_s "+urls_s[0]);
759 System.err.println("stream0 "+streamLoc0);
760 System.err.println("vid "+vid+", aid "+aid);
761 System.err.println("textureCount "+textureCount);
762 System.err.println("forceES2 "+forceES2);
763 System.err.println("forceES3 "+forceES3);
764 System.err.println("forceGL3 "+forceGL3);
765 System.err.println("forceGLDef "+forceGLDef);
766 System.err.println("swapInterval "+swapInterval);
767 System.err.println("playSpeed "+playSpeed);
768 System.err.println("audioVolume "+audioVolume);
769
770 final GLProfile glp;
771 if(forceGLDef) {
772 glp = GLProfile.getDefault();
773 } else if(forceGL3) {
774 glp = GLProfile.get(GLProfile.GL3);
775 } else if(forceES3) {
777 } else if(forceES2) {
779 } else {
780 glp = GLProfile.getGL2ES2();
781 }
782 System.err.println("GLProfile: "+glp);
783 final GLCapabilities caps = new GLCapabilities(glp);
784 // caps.setAlphaBits(4); // NOTE_ALPHA_BLENDING: We go w/o alpha and blending!
785
786 final MovieSimple[] mss = new MovieSimple[windowCount];
787 final GLWindow[] windows = new GLWindow[windowCount];
788 for(int i=0; i<windowCount; i++) {
789 final Animator anim = new Animator(0 /* w/o AWT */);
790 anim.start();
791 windows[i] = GLWindow.create(caps);
792 windows[i].addWindowListener(new WindowAdapter() {
793 @Override
794 public void windowDestroyed(final WindowEvent e) {
795 anim.stop();
796 }
797 });
798 mss[i] = new MovieSimple(null);
799 mss[i].setSwapInterval(swapInterval);
800 mss[i].setUseOriginalScale(useOrigScale);
801 mss[i].setOrthoProjection(ortho);
802 mss[i].mPlayer.setPlaySpeed(playSpeed);
803 mss[i].mPlayer.setAudioVolume(audioVolume);
804 mss[i].mPlayer.attachObject(WINDOW_KEY, windows[i]);
806
807 anim.add(windows[i]);
808 windows[i].addGLEventListener(mss[i]);
809 windows[i].setTitle("Player "+i);
810 windows[i].setSize(width, height);
811 windows[i].setVisible(true);
812
813 Uri streamLocN = null;
814 if( 0 == i ) {
815 streamLocN = streamLoc0;
816 } else {
817 if( null != urls_s[i] ) {
818 streamLocN = Uri.tryUriOrFile( urls_s[i] );
819 }
820 if( null == streamLocN ) {
821 streamLocN = defURI;
822 }
823 }
824 System.err.println("Win #"+i+": stream "+streamLocN);
825 mss[i].playStream(streamLocN, vid, aid, textureCount);
826 }
827 }
828
829}
Abstract Outline shape representation define the method an OutlineShape(s) is bound and rendered.
Definition: Region.java:62
static String getRenderModeString(final int renderModes)
Returns a unique technical description string for renderModes as follows:
Definition: Region.java:251
static final int DEFAULT_AA_SAMPLE_COUNT
Default pass2 AA sample count {@value} for Graph Region AA render-modes: VBAA_RENDERING_BIT or Region...
Definition: Region.java:177
static final int VBAA_RENDERING_BIT
Rendering-Mode bit for Region.
Definition: Region.java:115
A GLRegion is the OGL binding of one or more OutlineShapes Defined by its vertices and generated tria...
Definition: GLRegion.java:70
final GLRegion clear(final GL2ES2 gl)
Clears all buffers, i.e.
Definition: GLRegion.java:436
final void destroy(final GL2ES2 gl)
Delete and clear the associated OGL objects.
Definition: GLRegion.java:460
static GLRegion create(final GLProfile glp, int renderModes, final TextureSequence colorTexSeq, final int pass2TexUnit, final int initialVerticesCount, final int initialIndicesCount)
Create a GLRegion using the passed render mode.
Definition: GLRegion.java:109
static final GLCallback defaultBlendDisable
Default GL#GL_BLEND disable GLCallback, simply turning-off the GL#GL_BLEND state and turning-on depth...
static final GLCallback defaultBlendEnable
Default GL#GL_BLEND enable GLCallback, turning-off depth writing via GL#glDepthMask(boolean) if Rende...
Pointer event of type PointerType.
Definition: MouseEvent.java:74
NEWT Window events are provided for notification purposes ONLY.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final void setTitle(final String title)
Definition: GLWindow.java:297
final void setSize(final int width, final int height)
Sets the size of the window's client area in window units, excluding decorations.
Definition: GLWindow.java:625
final void setVisible(final boolean visible)
Calls setVisible(true, visible), i.e.
Definition: GLWindow.java:615
final void addWindowListener(final WindowListener l)
Appends the given com.jogamp.newt.event.WindowListener to the end of the list.
Definition: GLWindow.java:882
static GLWindow create(final GLCapabilitiesImmutable caps)
Creates a new GLWindow attaching a new Window referencing a new default Screen and default Display wi...
Definition: GLWindow.java:169
Specifies a set of OpenGL capabilities.
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static final String GLES3
The embedded OpenGL profile ES 3.x, with x >= 0.
Definition: GLProfile.java:588
static final String GL3
The desktop OpenGL core profile 3.x, with x >= 1.
Definition: GLProfile.java:576
static final String GLES2
The embedded OpenGL profile ES 2.x, with x >= 0.
Definition: GLProfile.java:585
static GLProfile getDefault(final AbstractGraphicsDevice device)
Returns a default GLProfile object, reflecting the best for the running platform.
Definition: GLProfile.java:739
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
static GLProfile getGL2ES2(final AbstractGraphicsDevice device)
Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.
Definition: GLProfile.java:913
static StringBuilder getGLInfo(final GL gl, final StringBuilder sb)
Simple planar movie player w/ orthogonal 1:1 projection.
static final MyGLMediaEventListener myGLMediaEventListener
void playStream(final Uri streamLoc, final int vid, final int aid, final int textureCount)
void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height)
Called by the drawable during the first repaint after the component has been resized.
static void main(final String[] args)
void printScreenOnGLThread(final GLAutoDrawable drawable)
void dispose(final GLAutoDrawable drawable)
Notifies the listener to perform the release of all OpenGL resources per GLContext,...
void init(final GLAutoDrawable drawable)
Called by the drawable immediately after the OpenGL context is initialized.
void setTransparency(final float alpha)
void setUseOriginalScale(final boolean v)
MovieSimple()
Default constructor which also issues playStream(URI, int, int, int) w/ default values and polls unti...
void display(final GLAutoDrawable drawable)
Called by the drawable to initiate OpenGL rendering by the client.
void setOrthoProjection(final boolean v)
defaults to true
static final Uri defURI
Blender's Big Buck Bunny: 24f 416p H.264, AAC 48000 Hz, 2 ch, mpeg stream.
void printScreen(final GLAutoDrawable drawable)
MovieSimple(final GLMediaPlayer sharedMediaPlayer)
Custom constructor, user needs to issue playStream(URI, int, int, int) afterwards.
Simple planar movie player w/ orthogonal 1:1 projection.
void display(final GLAutoDrawable drawable)
Called by the drawable to initiate OpenGL rendering by the client.
void init(final GLAutoDrawable drawable)
Called by the drawable immediately after the OpenGL context is initialized.
void dispose(final GLAutoDrawable drawable)
Notifies the listener to perform the release of all OpenGL resources per GLContext,...
void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height)
Called by the drawable during the first repaint after the component has been resized.
void renderString(final GLAutoDrawable drawable, final Font font, final float pixelSize, final CharSequence text, final int column, final float tx, final float ty, final float tz, final boolean cacheRegion)
static void waitForKey(final String preMessage)
Definition: MiscUtils.java:167
static int atoi(final String str, final int def)
Definition: MiscUtils.java:60
static void destroyWindow(final GLAutoDrawable glad)
Definition: MiscUtils.java:269
static float atof(final String str, final float def)
Definition: MiscUtils.java:78
final synchronized void add(final GLAutoDrawable drawable)
Adds a drawable to this animator's list of rendering drawables.
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
final synchronized boolean stop()
Stops this animator.
Definition: Animator.java:368
Utility to read out the current FB to TextureData, optionally writing the data back to a texture obje...
void write(final File dest)
Write the TextureData filled by readPixels(GLAutoDrawable, boolean) to file.
boolean readPixels(final GL gl, final boolean mustFlipVertically)
Read the drawable's pixels to TextureData and Texture, if requested at construction.
Interface wrapper for font implementation.
Definition: Font.java:60
boolean isBackgroundOpaque()
Returns whether an opaque or translucent surface is requested, supported or chosen.
int getSurfaceWidth()
Returns the width of the client area excluding insets (window decorations) in pixel units.
int getSurfaceHeight()
Returns the height of the client area excluding insets (window decorations) in pixel units.
Specifying NEWT's Window functionality:
Definition: Window.java:115
void addKeyListener(KeyListener l)
Appends the given com.jogamp.newt.event.KeyListener to the end of the list.
void addMouseListener(MouseListener l)
Appends the given MouseListener to the end of the list.
void destroy()
Destroys this window incl.releasing all related resources.
void resetFPSCounter()
Reset all performance counter (startTime, currentTime, frame number)
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
boolean invoke(boolean wait, GLRunnable glRunnable)
Enqueues a one-shot GLRunnable, which will be executed within the next display() call after all regis...
GLAnimatorControl getAnimator()
GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove)
Disposes the given listener via dispose(..) if it has been initialized and added to this queue.
GL getGL()
Returns the GL pipeline object this GLAutoDrawable uses.
Object getUpstreamWidget()
Method may return the upstream UI toolkit object holding this GLAutoDrawable instance,...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
GL2ES2 getGL2ES2()
Casts this object to the GL2ES2 interface.
GLProfile getGLProfile()
Returns the GLProfile associated with this GL object.
void setSwapInterval(int interval)
Set the swap interval of the current context and attached onscreen GLDrawable.
int getSwapInterval()
Return the current swap interval.
boolean getSampleBuffers()
Returns whether sample buffers for full-scene antialiasing (FSAA) should be allocated for this drawab...
GLCapabilitiesImmutable getChosenGLCapabilities()
Fetches the GLCapabilitiesImmutable corresponding to the chosen OpenGL capabilities (pixel format / v...
int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.
As the contract of GLMediaFrameListener and TexSeqEventListener requests, implementations of GLMediaE...
GLMediaPlayer interface specifies a TextureSequence state machine using a multiplexed audio/video str...
State pause(boolean flush)
Pauses the StreamWorker decoding thread.
int getVID()
Return the video stream id, see audio and video Stream IDs.
float getAudioVolume()
Returns the audio volume.
int getDuration()
Return total duration of stream in msec.
int getWidth()
Returns the width of the video.
State destroy(GL gl)
Releases the GL, stream and other resources, including attached user objects.
boolean setAudioVolume(float v)
Sets the audio volume, [0f..1f].
static final int STREAM_ID_NONE
Constant {@value} for mute or not available.
void initGL(GL gl)
Initializes OpenGL related resources.
float getPlaySpeed()
Returns the playback speed.
Uri getUri()
Return the stream location, as set by playStream(Uri, int, int, int, int).
boolean setPlaySpeed(float rate)
Sets the playback speed.
void playStream(Uri streamLoc, int vid, int aid, int sid, int textureCount)
Issues asynchronous stream initialization.
int getHeight()
Returns the height of the video.
void addEventListener(GLMediaEventListener l)
Adds a GLMediaEventListener to this player.
int getAID()
Return the audio stream id, see audio and video Stream IDs.
int getAudioBitrate()
Warning: Optional information, may not be supported by implementation.
float getFramerate()
Warning: Optional information, may not be supported by implementation.
int seek(int msec)
Seeks to the new absolute position.
String getVideoCodec()
Warning: Optional information, may not be supported by implementation.
Object attachObject(String name, Object obj)
Attaches the user object for the given name.
State resume()
Starts or resumes the StreamWorker decoding thread.
int getVideoBitrate()
Warning: Optional information, may not be supported by implementation.
PTS getPTS()
Returns current System Clock Reference (SCR) presentation timestamp (PTS).
static final int STREAM_ID_AUTO
Constant {@value} for auto or unspecified.
State stop()
Stops streaming and releases the GL, stream and other resources, but keeps attached user objects.
String getAudioCodec()
Warning: Optional information, may not be supported by implementation.