OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 // copies frame to texture and then removes it from a queue using poll(). | 141 // copies frame to texture and then removes it from a queue using poll(). |
142 private final LinkedBlockingQueue<I420Frame> frameToRenderQueue; | 142 private final LinkedBlockingQueue<I420Frame> frameToRenderQueue; |
143 // Local copy of incoming video frame. Synchronized on |frameToRenderQueue|. | 143 // Local copy of incoming video frame. Synchronized on |frameToRenderQueue|. |
144 private I420Frame yuvFrameToRender; | 144 private I420Frame yuvFrameToRender; |
145 private I420Frame textureFrameToRender; | 145 private I420Frame textureFrameToRender; |
146 // Type of video frame used for recent frame rendering. | 146 // Type of video frame used for recent frame rendering. |
147 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; | 147 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; |
148 private RendererType rendererType; | 148 private RendererType rendererType; |
149 private ScalingType scalingType; | 149 private ScalingType scalingType; |
150 private boolean mirror; | 150 private boolean mirror; |
| 151 private RendererEvents rendererEvents; |
151 // Flag if renderFrame() was ever called. | 152 // Flag if renderFrame() was ever called. |
152 boolean seenFrame; | 153 boolean seenFrame; |
153 // Total number of video frames received in renderFrame() call. | 154 // Total number of video frames received in renderFrame() call. |
154 private int framesReceived; | 155 private int framesReceived; |
155 // Number of video frames dropped by renderFrame() because previous | 156 // Number of video frames dropped by renderFrame() because previous |
156 // frame has not been rendered yet. | 157 // frame has not been rendered yet. |
157 private int framesDropped; | 158 private int framesDropped; |
158 // Number of rendered video frames. | 159 // Number of rendered video frames. |
159 private int framesRendered; | 160 private int framesRendered; |
160 // Time in ns when the first video frame was rendered. | 161 // Time in ns when the first video frame was rendered. |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 this.mirror = mirror; | 424 this.mirror = mirror; |
424 updateTextureProperties = true; | 425 updateTextureProperties = true; |
425 } | 426 } |
426 } | 427 } |
427 | 428 |
428 private void setSize(final int videoWidth, final int videoHeight, final int
rotation) { | 429 private void setSize(final int videoWidth, final int videoHeight, final int
rotation) { |
429 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight | 430 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight |
430 && rotation == rotationDegree) { | 431 && rotation == rotationDegree) { |
431 return; | 432 return; |
432 } | 433 } |
| 434 if (rendererEvents != null) { |
| 435 Log.d(TAG, "ID: " + id + |
| 436 ". Reporting frame resolution changed to " + videoWidth + " x " + vi
deoHeight); |
| 437 rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotatio
n); |
| 438 } |
433 | 439 |
434 // Frame re-allocation need to be synchronized with copying | 440 // Frame re-allocation need to be synchronized with copying |
435 // frame to textures in draw() function to avoid re-allocating | 441 // frame to textures in draw() function to avoid re-allocating |
436 // the frame while it is being copied. | 442 // the frame while it is being copied. |
437 synchronized (frameToRenderQueue) { | 443 synchronized (frameToRenderQueue) { |
438 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " + | 444 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " + |
439 videoWidth + " x " + videoHeight + " rotation " + rotation); | 445 videoWidth + " x " + videoHeight + " rotation " + rotation); |
440 | 446 |
441 this.videoWidth = videoWidth; | 447 this.videoWidth = videoWidth; |
442 this.videoHeight = videoHeight; | 448 this.videoHeight = videoHeight; |
(...skipping 11 matching lines...) Expand all Loading... |
454 Log.d(TAG, " YuvImageRenderer.setSize done."); | 460 Log.d(TAG, " YuvImageRenderer.setSize done."); |
455 } | 461 } |
456 } | 462 } |
457 | 463 |
458 @Override | 464 @Override |
459 public synchronized void renderFrame(I420Frame frame) { | 465 public synchronized void renderFrame(I420Frame frame) { |
460 if (surface == null) { | 466 if (surface == null) { |
461 // This object has been released. | 467 // This object has been released. |
462 return; | 468 return; |
463 } | 469 } |
| 470 if (!seenFrame && rendererEvents != null) { |
| 471 Log.d(TAG, "ID: " + id + ". Reporting first rendered frame."); |
| 472 rendererEvents.onFirstFrameRendered(); |
| 473 } |
464 setSize(frame.width, frame.height, frame.rotationDegree); | 474 setSize(frame.width, frame.height, frame.rotationDegree); |
465 long now = System.nanoTime(); | 475 long now = System.nanoTime(); |
466 framesReceived++; | 476 framesReceived++; |
467 synchronized (frameToRenderQueue) { | 477 synchronized (frameToRenderQueue) { |
468 // Skip rendering of this frame if setSize() was not called. | 478 // Skip rendering of this frame if setSize() was not called. |
469 if (yuvFrameToRender == null || textureFrameToRender == null) { | 479 if (yuvFrameToRender == null || textureFrameToRender == null) { |
470 framesDropped++; | 480 framesDropped++; |
471 return; | 481 return; |
472 } | 482 } |
473 // Check input frame parameters. | 483 // Check input frame parameters. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
511 surface.requestRender(); | 521 surface.requestRender(); |
512 } | 522 } |
513 | 523 |
514 // TODO(guoweis): Remove this once chrome code base is updated. | 524 // TODO(guoweis): Remove this once chrome code base is updated. |
515 @Override | 525 @Override |
516 public boolean canApplyRotation() { | 526 public boolean canApplyRotation() { |
517 return true; | 527 return true; |
518 } | 528 } |
519 } | 529 } |
520 | 530 |
| 531 /** Interface for reporting rendering events. */ |
| 532 public static interface RendererEvents { |
| 533 /** |
| 534 * Callback fired once first frame is rendered. |
| 535 */ |
| 536 public void onFirstFrameRendered(); |
| 537 |
| 538 /** |
| 539 * Callback fired when rendered frame resolution or rotation has changed. |
| 540 */ |
| 541 public void onFrameResolutionChanged(int videoWidth, int videoHeight, int ro
tation); |
| 542 } |
| 543 |
521 /** Passes GLSurfaceView to video renderer. */ | 544 /** Passes GLSurfaceView to video renderer. */ |
522 public static synchronized void setView(GLSurfaceView surface, | 545 public static synchronized void setView(GLSurfaceView surface, |
523 Runnable eglContextReadyCallback) { | 546 Runnable eglContextReadyCallback) { |
524 Log.d(TAG, "VideoRendererGui.setView"); | 547 Log.d(TAG, "VideoRendererGui.setView"); |
525 instance = new VideoRendererGui(surface); | 548 instance = new VideoRendererGui(surface); |
526 eglContextReady = eglContextReadyCallback; | 549 eglContextReady = eglContextReadyCallback; |
527 } | 550 } |
528 | 551 |
529 public static synchronized EGLContext getEGLContext() { | 552 public static synchronized EGLContext getEGLContext() { |
530 return eglContext; | 553 return eglContext; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 } | 628 } |
606 synchronized (instance.yuvImageRenderers) { | 629 synchronized (instance.yuvImageRenderers) { |
607 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { | 630 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { |
608 if (yuvImageRenderer == renderer) { | 631 if (yuvImageRenderer == renderer) { |
609 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror)
; | 632 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror)
; |
610 } | 633 } |
611 } | 634 } |
612 } | 635 } |
613 } | 636 } |
614 | 637 |
| 638 public static synchronized void setRendererEvents( |
| 639 VideoRenderer.Callbacks renderer, RendererEvents rendererEvents) { |
| 640 Log.d(TAG, "VideoRendererGui.setRendererEvents"); |
| 641 if (instance == null) { |
| 642 throw new RuntimeException( |
| 643 "Attempt to set renderer events before setting GLSurfaceView"); |
| 644 } |
| 645 synchronized (instance.yuvImageRenderers) { |
| 646 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { |
| 647 if (yuvImageRenderer == renderer) { |
| 648 yuvImageRenderer.rendererEvents = rendererEvents; |
| 649 } |
| 650 } |
| 651 } |
| 652 } |
| 653 |
615 public static synchronized void remove(VideoRenderer.Callbacks renderer) { | 654 public static synchronized void remove(VideoRenderer.Callbacks renderer) { |
616 Log.d(TAG, "VideoRendererGui.remove"); | 655 Log.d(TAG, "VideoRendererGui.remove"); |
617 if (instance == null) { | 656 if (instance == null) { |
618 throw new RuntimeException( | 657 throw new RuntimeException( |
619 "Attempt to remove yuv renderer before setting GLSurfaceView"); | 658 "Attempt to remove yuv renderer before setting GLSurfaceView"); |
620 } | 659 } |
621 synchronized (instance.yuvImageRenderers) { | 660 synchronized (instance.yuvImageRenderers) { |
622 final int index = instance.yuvImageRenderers.indexOf(renderer); | 661 final int index = instance.yuvImageRenderers.indexOf(renderer); |
623 if (index == -1) { | 662 if (index == -1) { |
624 Log.w(TAG, "Couldn't remove renderer (not present in current list)"); | 663 Log.w(TAG, "Couldn't remove renderer (not present in current list)"); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 GLES20.glViewport(0, 0, screenWidth, screenHeight); | 718 GLES20.glViewport(0, 0, screenWidth, screenHeight); |
680 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | 719 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
681 synchronized (yuvImageRenderers) { | 720 synchronized (yuvImageRenderers) { |
682 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { | 721 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { |
683 yuvImageRenderer.draw(drawer); | 722 yuvImageRenderer.draw(drawer); |
684 } | 723 } |
685 } | 724 } |
686 } | 725 } |
687 | 726 |
688 } | 727 } |
OLD | NEW |