10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.javafx.webkit.prism;
27
28 import java.net.URI;
29 import java.util.List;
30 import java.util.logging.Level;
31 import com.sun.javafx.media.PrismMediaFrameHandler;
32 import com.sun.media.jfxmedia.Media;
33 import com.sun.media.jfxmedia.MediaManager;
34 import com.sun.media.jfxmedia.MediaPlayer;
35 import com.sun.media.jfxmedia.control.VideoDataBuffer;
36 import com.sun.media.jfxmedia.events.BufferListener;
37 import com.sun.media.jfxmedia.events.BufferProgressEvent;
38 import com.sun.media.jfxmedia.events.MediaErrorListener;
39 import com.sun.media.jfxmedia.events.NewFrameEvent;
40 import com.sun.media.jfxmedia.events.PlayerStateEvent;
41 import com.sun.media.jfxmedia.events.PlayerStateListener;
42 import com.sun.media.jfxmedia.events.PlayerTimeListener;
43 import com.sun.media.jfxmedia.events.VideoRendererListener;
44 import com.sun.media.jfxmedia.events.VideoTrackSizeListener;
45 import com.sun.media.jfxmedia.locator.Locator;
46 import com.sun.media.jfxmedia.track.AudioTrack;
47 import com.sun.media.jfxmedia.track.Track;
48 import com.sun.media.jfxmedia.track.VideoTrack;
49 import com.sun.prism.Graphics;
50 import com.sun.prism.Texture;
90 player = p;
91 installListeners();
92 frameHandler = PrismMediaFrameHandler.getHandler(player);
93 }
94
95 finished = 0;
96 }
97
98 private final class CreateThread extends Thread {
99 private boolean cancelled = false;
100 private final String url;
101 private final String userAgent;
102 private CreateThread(String url, String userAgent) {
103 this.url = url;
104 this.userAgent = userAgent;
105 gotFirstFrame = false;
106 }
107
108 @Override
109 public void run() {
110 if (verbose) log.log(Level.FINE, "CreateThread: started, url={0}", url);
111
112 notifyNetworkStateChanged(NETWORK_STATE_LOADING);
113 notifyReadyStateChanged(READY_STATE_HAVE_NOTHING);
114
115 MediaPlayer p = null;
116
117 try {
118 Locator locator = new Locator(new URI(url));
119 if (userAgent != null) {
120 locator.setConnectionProperty("User-Agent", userAgent);
121 }
122 locator.init();
123 if (verbose) {
124 log.fine("CreateThread: locator created");
125 }
126
127 p = MediaManager.getPlayer(locator);
128 } catch (Exception ex) {
129 if (verbose) {
130 log.log(Level.WARNING, "CreateThread ERROR: {0}", ex.toString());
131 ex.printStackTrace(System.out);
132 }
133 onError(this, 0, ex.getMessage());
134 return;
135 }
136
137 synchronized (lock) {
138 if (cancelled) {
139 if (verbose) log.log(Level.FINE, "CreateThread: cancelled");
140 p.dispose();
141 return;
142 }
143 createThread = null;
144 setPlayer(p);
145 }
146 if (verbose) log.log(Level.FINE, "CreateThread: completed");
147 }
148
149 private void cancel() {
150 synchronized (lock) {
151 cancelled = true;
152 }
153 }
154 }
155
156
157 protected void load(String url, String userAgent) {
158 synchronized (lock) {
159 if (createThread != null) {
160 createThread.cancel();
161 }
162 disposePlayer();
163 createThread = new CreateThread(url, userAgent);
164 }
165 // fx media player does not support loading only metadata,
166 // so handle PRELOAD_METADATA as PRELOAD_AUTO (start loading)
323 }
324 }
325
326 protected void setSize(int w, int h) {
327 // nothing to do
328 }
329
330 protected void setPreservesPitch(boolean preserve) {
331 // nothing to do
332 }
333
334 protected void renderCurrentFrame(WCGraphicsContext gc, int x, int y, int w, int h) {
335 // TODO: need a render lock in MediaFrameHandler
336 synchronized (lock) {
337 renderImpl(gc, x, y, w, h);
338 }
339 }
340
341
342 private void renderImpl(WCGraphicsContext gc, int x, int y, int w, int h) {
343 if (verbose) log.log(Level.FINER, ">>(Prism)renderImpl");
344 Graphics g = (Graphics)gc.getPlatformGraphics();
345
346 Texture texture = null;
347 VideoDataBuffer currentFrame = frameListener.getLatestFrame();
348
349 if (null != currentFrame) {
350 if (null != frameHandler) {
351 texture = frameHandler.getTexture(g, currentFrame);
352 }
353 currentFrame.releaseFrame();
354 }
355
356 if (texture != null) {
357 g.drawTexture(texture,
358 x, y, x + w, y + h,
359 0f, 0f, texture.getContentWidth(), texture.getContentHeight());
360 texture.unlock();
361 } else {
362 if (verbose) log.log(Level.FINEST, " (Prism)renderImpl, texture is null, draw black rect");
363 gc.fillRect(x, y, w, h, 0xFF000000);
364 }
365 if (verbose) log.log(Level.FINER, "<<(Prism)renderImpl");
366 }
367
368 // PlayerStateListener
369 @Override
370 public void onReady(PlayerStateEvent pse) {
371 MediaPlayer p = getPlayer();
372 if (verbose) log.log(Level.FINE, "onReady");
373 Media media = p.getMedia();
374 boolean hasVideo = false;
375 boolean hasAudio = false;
376 if (media != null) {
377 List<Track> tracks = media.getTracks();
378 if (tracks != null) {
379 if (verbose) log.log(Level.INFO, "{0} track(s) detected:", tracks.size());
380 for (Track track : tracks) {
381 if (track instanceof VideoTrack) {
382 hasVideo = true;
383 } else if (track instanceof AudioTrack) {
384 hasAudio = true;
385 }
386 if (verbose) log.log(Level.INFO, "track: {0}", track);
387 }
388 } else {
389 if (verbose) log.log(Level.WARNING, "onReady, tracks IS NULL");
390 }
391 } else {
392 if (verbose) log.log(Level.WARNING, "onReady, media IS NULL");
393 }
394 if (verbose) {
395 log.log(Level.FINE, "onReady, hasVideo:{0}, hasAudio: {1}",
396 new Object[]{hasVideo, hasAudio});
397 }
398 notifyReady(hasVideo, hasAudio, (float)p.getDuration());
399
400 // if we have no video, report READY_STATE_HAVE_ENOUGH_DATA right now
401 if (!hasVideo) {
402 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
403 } else {
404 if (getReadyState() < READY_STATE_HAVE_METADATA) {
405 if (gotFirstFrame) {
406 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
407 } else {
408 notifyReadyStateChanged(READY_STATE_HAVE_METADATA);
409 }
410 }
411 }
412 }
413
414 @Override
415 public void onPlaying(PlayerStateEvent pse) {
416 if (verbose) log.log(Level.FINE, "onPlaying");
417 notifyPaused(false);
418 }
419
420 @Override
421 public void onPause(PlayerStateEvent pse) {
422 if (verbose) log.log(Level.FINE, "onPause, time: {0}", pse.getTime());
423 notifyPaused(true);
424 }
425
426 @Override
427 public void onStop(PlayerStateEvent pse) {
428 if (verbose) log.log(Level.FINE, "onStop");
429 notifyPaused(true);
430 }
431
432 @Override
433 public void onStall(PlayerStateEvent pse) {
434 if (verbose) log.log(Level.FINE, "onStall");
435 }
436
437 @Override
438 public void onFinish(PlayerStateEvent pse) {
439 MediaPlayer p = getPlayer();
440 if (p != null) {
441 finished = p.getRate() > 0 ? 1 : -1;
442 if (verbose) log.log(Level.FINE, "onFinish, time: {0}", pse.getTime());
443 notifyFinished();
444 }
445 }
446
447 @Override
448 public void onHalt(PlayerStateEvent pse) {
449 if (verbose) log.log(Level.FINE, "onHalt");
450 }
451
452 // MediaErrorListener
453 @Override
454 public void onError(Object source, int errCode, String message) {
455 //MediaPlayer p = getPlayer();
456 if (verbose) {
457 log.log(Level.WARNING, "onError, errCode={0}, msg={1}",
458 new Object[]{errCode, message});
459 }
460 // TODO: parse errCode to detect NETWORK_STATE_FORMAT_ERROR/
461 // NETWORK_STATE_NETWORK_ERROR/NETWORK_STATE_DECODE_ERROR
462 notifyNetworkStateChanged(NETWORK_STATE_NETWORK_ERROR);
463 notifyReadyStateChanged(READY_STATE_HAVE_NOTHING);
464 }
465
466 //PlayerTimeListener
467 @Override
468 public void onDurationChanged(double duration) {
469 if (verbose) log.log(Level.FINE, "onDurationChanged, duration={0}", duration);
470 notifyDurationChanged((float)duration);
471 }
472
473 // VideoTrackSizeListener
474 @Override
475 public void onSizeChanged(int width, int height) {
476 //MediaPlayer p = getPlayer();
477 if (verbose) {
478 log.log(Level.FINE, "onSizeChanged, new size = {0} x {1}",
479 new Object[]{width, height});
480 }
481 notifySizeChanged(width, height);
482 }
483
484 private void notifyFrameArrived() {
485 if (!gotFirstFrame) {
486 // this is the first frame
487 // don't set HAVE_ENOUGH_DATA state before onReady
488 if (getReadyState() >= READY_STATE_HAVE_METADATA) {
489 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
490 }
491 gotFirstFrame = true;
492 }
493 if (verbose && finished != 0) {
494 log.log(Level.FINE, "notifyFrameArrived (after finished) time: {0}", getPlayer().getPresentationTime());
495 }
496 notifyNewFrame();
497 }
498
499 private float bufferedStart = 0f;
500 private float bufferedEnd = 0f;
501 private boolean buffering = false;
502
503 private void updateBufferingStatus() {
504 int newNetworkState =
505 buffering ? NETWORK_STATE_LOADING
506 : bufferedStart > 0 ? NETWORK_STATE_IDLE : NETWORK_STATE_LOADED;
507 if (verbose) {
508 log.log(Level.FINE, "updateBufferingStatus, buffered: [{0} - {1}], buffering = {2}",
509 new Object[]{bufferedStart, bufferedEnd, buffering});
510 }
511 notifyNetworkStateChanged(newNetworkState);
512 }
513
514 // BufferListener
515 @Override
516 public void onBufferProgress(BufferProgressEvent event) {
517 /* event (in the current API):
518 * double getDuration(): duration of the movie (seconds);
519 * long getBufferStart(): start of the buffered data (bytes)
520 * long getBufferStop(): end of the movie (bytes)
521 * long getBufferPosition(): end of the buffered data (bytes)
522 */
523 // if duration is not yet known, we cannot calculate buffered ranges
524 if (event.getDuration() < 0) {
525 return;
526 }
527 double bytes2seconds = event.getDuration() / (double)event.getBufferStop();
528 bufferedStart = (float)(bytes2seconds * event.getBufferStart());
529 bufferedEnd = (float)(bytes2seconds * event.getBufferPosition());
530 buffering = event.getBufferPosition() < event.getBufferStop();
531
532 float ranges[] = new float[2];
533 ranges[0] = bufferedStart;
534 ranges[1] = bufferedEnd;
535 int bytesLoaded = (int)(event.getBufferPosition() - event.getBufferStart());
536 if (verbose) {
537 log.log(Level.FINER, "onBufferProgress, "
538 + "bufferStart={0}, bufferStop={1}, bufferPos={2}, duration={3}; "
539 + "notify range [{4},[5]], bytesLoaded: {6}",
540 new Object[]{event.getBufferStart(), event.getBufferStop(),
541 event.getBufferPosition(), event.getDuration(),
542 ranges[0], ranges[1], bytesLoaded});
543 }
544 notifyBufferChanged(ranges, bytesLoaded);
545 updateBufferingStatus();
546 }
547
548 /* Inner class that will listen for new frames from the jfxmedia player and
549 * manage our own texture cache to remove the dependency on
550 * PrismMediaFrameHandler
551 */
552 private final class MediaFrameListener implements VideoRendererListener {
553 private final Object frameLock = new Object();
554 private VideoDataBuffer currentFrame;
555 private VideoDataBuffer nextFrame;
556
557 public void videoFrameUpdated(NewFrameEvent nfe) {
558 synchronized (frameLock) {
559 if (null != nextFrame) {
560 nextFrame.releaseFrame();
561 }
562 nextFrame = nfe.getFrameData();
563 if (null != nextFrame) {
|
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.javafx.webkit.prism;
27
28 import java.net.URI;
29 import java.util.List;
30
31 import com.sun.javafx.media.PrismMediaFrameHandler;
32 import com.sun.media.jfxmedia.Media;
33 import com.sun.media.jfxmedia.MediaManager;
34 import com.sun.media.jfxmedia.MediaPlayer;
35 import com.sun.media.jfxmedia.control.VideoDataBuffer;
36 import com.sun.media.jfxmedia.events.BufferListener;
37 import com.sun.media.jfxmedia.events.BufferProgressEvent;
38 import com.sun.media.jfxmedia.events.MediaErrorListener;
39 import com.sun.media.jfxmedia.events.NewFrameEvent;
40 import com.sun.media.jfxmedia.events.PlayerStateEvent;
41 import com.sun.media.jfxmedia.events.PlayerStateListener;
42 import com.sun.media.jfxmedia.events.PlayerTimeListener;
43 import com.sun.media.jfxmedia.events.VideoRendererListener;
44 import com.sun.media.jfxmedia.events.VideoTrackSizeListener;
45 import com.sun.media.jfxmedia.locator.Locator;
46 import com.sun.media.jfxmedia.track.AudioTrack;
47 import com.sun.media.jfxmedia.track.Track;
48 import com.sun.media.jfxmedia.track.VideoTrack;
49 import com.sun.prism.Graphics;
50 import com.sun.prism.Texture;
90 player = p;
91 installListeners();
92 frameHandler = PrismMediaFrameHandler.getHandler(player);
93 }
94
95 finished = 0;
96 }
97
98 private final class CreateThread extends Thread {
99 private boolean cancelled = false;
100 private final String url;
101 private final String userAgent;
102 private CreateThread(String url, String userAgent) {
103 this.url = url;
104 this.userAgent = userAgent;
105 gotFirstFrame = false;
106 }
107
108 @Override
109 public void run() {
110 log.fine("CreateThread: started, url={0}", url);
111
112 notifyNetworkStateChanged(NETWORK_STATE_LOADING);
113 notifyReadyStateChanged(READY_STATE_HAVE_NOTHING);
114
115 MediaPlayer p = null;
116
117 try {
118 Locator locator = new Locator(new URI(url));
119 if (userAgent != null) {
120 locator.setConnectionProperty("User-Agent", userAgent);
121 }
122 locator.init();
123 log.fine("CreateThread: locator created");
124
125 p = MediaManager.getPlayer(locator);
126 } catch (Exception ex) {
127 log.warning("CreateThread ERROR: {0}", ex.toString());
128 ex.printStackTrace(System.out);
129 onError(this, 0, ex.getMessage());
130 return;
131 }
132
133 synchronized (lock) {
134 if (cancelled) {
135 log.fine("CreateThread: cancelled");
136 p.dispose();
137 return;
138 }
139 createThread = null;
140 setPlayer(p);
141 }
142 log.fine("CreateThread: completed");
143 }
144
145 private void cancel() {
146 synchronized (lock) {
147 cancelled = true;
148 }
149 }
150 }
151
152
153 protected void load(String url, String userAgent) {
154 synchronized (lock) {
155 if (createThread != null) {
156 createThread.cancel();
157 }
158 disposePlayer();
159 createThread = new CreateThread(url, userAgent);
160 }
161 // fx media player does not support loading only metadata,
162 // so handle PRELOAD_METADATA as PRELOAD_AUTO (start loading)
319 }
320 }
321
322 protected void setSize(int w, int h) {
323 // nothing to do
324 }
325
326 protected void setPreservesPitch(boolean preserve) {
327 // nothing to do
328 }
329
330 protected void renderCurrentFrame(WCGraphicsContext gc, int x, int y, int w, int h) {
331 // TODO: need a render lock in MediaFrameHandler
332 synchronized (lock) {
333 renderImpl(gc, x, y, w, h);
334 }
335 }
336
337
338 private void renderImpl(WCGraphicsContext gc, int x, int y, int w, int h) {
339 log.finer(">>(Prism)renderImpl");
340 Graphics g = (Graphics)gc.getPlatformGraphics();
341
342 Texture texture = null;
343 VideoDataBuffer currentFrame = frameListener.getLatestFrame();
344
345 if (null != currentFrame) {
346 if (null != frameHandler) {
347 texture = frameHandler.getTexture(g, currentFrame);
348 }
349 currentFrame.releaseFrame();
350 }
351
352 if (texture != null) {
353 g.drawTexture(texture,
354 x, y, x + w, y + h,
355 0f, 0f, texture.getContentWidth(), texture.getContentHeight());
356 texture.unlock();
357 } else {
358 log.finest(" (Prism)renderImpl, texture is null, draw black rect");
359 gc.fillRect(x, y, w, h, 0xFF000000);
360 }
361 log.finer("<<(Prism)renderImpl");
362 }
363
364 // PlayerStateListener
365 @Override
366 public void onReady(PlayerStateEvent pse) {
367 MediaPlayer p = getPlayer();
368 log.fine("onReady");
369 Media media = p.getMedia();
370 boolean hasVideo = false;
371 boolean hasAudio = false;
372 if (media != null) {
373 List<Track> tracks = media.getTracks();
374 if (tracks != null) {
375 log.fine("{0} track(s) detected:", tracks.size());
376 for (Track track : tracks) {
377 if (track instanceof VideoTrack) {
378 hasVideo = true;
379 } else if (track instanceof AudioTrack) {
380 hasAudio = true;
381 }
382 log.fine("track: {0}", track);
383 }
384 } else {
385 log.warning("onReady, tracks IS NULL");
386 }
387 } else {
388 log.warning("onReady, media IS NULL");
389 }
390 log.fine("onReady, hasVideo:{0}, hasAudio: {1}", new Object[]{hasVideo, hasAudio});
391 notifyReady(hasVideo, hasAudio, (float)p.getDuration());
392
393 // if we have no video, report READY_STATE_HAVE_ENOUGH_DATA right now
394 if (!hasVideo) {
395 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
396 } else {
397 if (getReadyState() < READY_STATE_HAVE_METADATA) {
398 if (gotFirstFrame) {
399 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
400 } else {
401 notifyReadyStateChanged(READY_STATE_HAVE_METADATA);
402 }
403 }
404 }
405 }
406
407 @Override
408 public void onPlaying(PlayerStateEvent pse) {
409 log.fine("onPlaying");
410 notifyPaused(false);
411 }
412
413 @Override
414 public void onPause(PlayerStateEvent pse) {
415 log.fine("onPause, time: {0}", pse.getTime());
416 notifyPaused(true);
417 }
418
419 @Override
420 public void onStop(PlayerStateEvent pse) {
421 log.fine("onStop");
422 notifyPaused(true);
423 }
424
425 @Override
426 public void onStall(PlayerStateEvent pse) {
427 log.fine("onStall");
428 }
429
430 @Override
431 public void onFinish(PlayerStateEvent pse) {
432 MediaPlayer p = getPlayer();
433 if (p != null) {
434 finished = p.getRate() > 0 ? 1 : -1;
435 log.fine("onFinish, time: {0}", pse.getTime());
436 notifyFinished();
437 }
438 }
439
440 @Override
441 public void onHalt(PlayerStateEvent pse) {
442 log.fine("onHalt");
443 }
444
445 // MediaErrorListener
446 @Override
447 public void onError(Object source, int errCode, String message) {
448 //MediaPlayer p = getPlayer();
449 log.warning("onError, errCode={0}, msg={1}", new Object[]{errCode, message});
450 // TODO: parse errCode to detect NETWORK_STATE_FORMAT_ERROR/
451 // NETWORK_STATE_NETWORK_ERROR/NETWORK_STATE_DECODE_ERROR
452 notifyNetworkStateChanged(NETWORK_STATE_NETWORK_ERROR);
453 notifyReadyStateChanged(READY_STATE_HAVE_NOTHING);
454 }
455
456 //PlayerTimeListener
457 @Override
458 public void onDurationChanged(double duration) {
459 log.fine("onDurationChanged, duration={0}", duration);
460 notifyDurationChanged((float)duration);
461 }
462
463 // VideoTrackSizeListener
464 @Override
465 public void onSizeChanged(int width, int height) {
466 //MediaPlayer p = getPlayer();
467 log.fine("onSizeChanged, new size = {0} x {1}", new Object[]{width, height});
468 notifySizeChanged(width, height);
469 }
470
471 private void notifyFrameArrived() {
472 if (!gotFirstFrame) {
473 // this is the first frame
474 // don't set HAVE_ENOUGH_DATA state before onReady
475 if (getReadyState() >= READY_STATE_HAVE_METADATA) {
476 notifyReadyStateChanged(READY_STATE_HAVE_ENOUGH_DATA);
477 }
478 gotFirstFrame = true;
479 }
480 if (finished != 0) {
481 log.fine("notifyFrameArrived (after finished) time: {0}", getPlayer().getPresentationTime());
482 }
483 notifyNewFrame();
484 }
485
486 private float bufferedStart = 0f;
487 private float bufferedEnd = 0f;
488 private boolean buffering = false;
489
490 private void updateBufferingStatus() {
491 int newNetworkState =
492 buffering ? NETWORK_STATE_LOADING
493 : bufferedStart > 0 ? NETWORK_STATE_IDLE : NETWORK_STATE_LOADED;
494 log.fine("updateBufferingStatus, buffered: [{0} - {1}], buffering = {2}",
495 new Object[]{bufferedStart, bufferedEnd, buffering});
496 notifyNetworkStateChanged(newNetworkState);
497 }
498
499 // BufferListener
500 @Override
501 public void onBufferProgress(BufferProgressEvent event) {
502 /* event (in the current API):
503 * double getDuration(): duration of the movie (seconds);
504 * long getBufferStart(): start of the buffered data (bytes)
505 * long getBufferStop(): end of the movie (bytes)
506 * long getBufferPosition(): end of the buffered data (bytes)
507 */
508 // if duration is not yet known, we cannot calculate buffered ranges
509 if (event.getDuration() < 0) {
510 return;
511 }
512 double bytes2seconds = event.getDuration() / (double)event.getBufferStop();
513 bufferedStart = (float)(bytes2seconds * event.getBufferStart());
514 bufferedEnd = (float)(bytes2seconds * event.getBufferPosition());
515 buffering = event.getBufferPosition() < event.getBufferStop();
516
517 float ranges[] = new float[2];
518 ranges[0] = bufferedStart;
519 ranges[1] = bufferedEnd;
520 int bytesLoaded = (int)(event.getBufferPosition() - event.getBufferStart());
521 log.finer("onBufferProgress, "
522 + "bufferStart={0}, bufferStop={1}, bufferPos={2}, duration={3}; "
523 + "notify range [{4},[5]], bytesLoaded: {6}",
524 new Object[]{event.getBufferStart(), event.getBufferStop(),
525 event.getBufferPosition(), event.getDuration(),
526 ranges[0], ranges[1], bytesLoaded});
527 notifyBufferChanged(ranges, bytesLoaded);
528 updateBufferingStatus();
529 }
530
531 /* Inner class that will listen for new frames from the jfxmedia player and
532 * manage our own texture cache to remove the dependency on
533 * PrismMediaFrameHandler
534 */
535 private final class MediaFrameListener implements VideoRendererListener {
536 private final Object frameLock = new Object();
537 private VideoDataBuffer currentFrame;
538 private VideoDataBuffer nextFrame;
539
540 public void videoFrameUpdated(NewFrameEvent nfe) {
541 synchronized (frameLock) {
542 if (null != nextFrame) {
543 nextFrame.releaseFrame();
544 }
545 nextFrame = nfe.getFrameData();
546 if (null != nextFrame) {
|