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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 // copies frame to texture and then removes it from a queue using poll(). | 118 // copies frame to texture and then removes it from a queue using poll(). |
119 LinkedBlockingQueue<I420Frame> frameToRenderQueue; | 119 LinkedBlockingQueue<I420Frame> frameToRenderQueue; |
120 // Local copy of incoming video frame. | 120 // Local copy of incoming video frame. |
121 private I420Frame yuvFrameToRender; | 121 private I420Frame yuvFrameToRender; |
122 private I420Frame textureFrameToRender; | 122 private I420Frame textureFrameToRender; |
123 // Type of video frame used for recent frame rendering. | 123 // Type of video frame used for recent frame rendering. |
124 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; | 124 private static enum RendererType { RENDERER_YUV, RENDERER_TEXTURE }; |
125 private RendererType rendererType; | 125 private RendererType rendererType; |
126 private ScalingType scalingType; | 126 private ScalingType scalingType; |
127 private boolean mirror; | 127 private boolean mirror; |
128 private RendererEvents rendererEvents; | |
128 // Flag if renderFrame() was ever called. | 129 // Flag if renderFrame() was ever called. |
129 boolean seenFrame; | 130 boolean seenFrame; |
130 // Total number of video frames received in renderFrame() call. | 131 // Total number of video frames received in renderFrame() call. |
131 private int framesReceived; | 132 private int framesReceived; |
132 // Number of video frames dropped by renderFrame() because previous | 133 // Number of video frames dropped by renderFrame() because previous |
133 // frame has not been rendered yet. | 134 // frame has not been rendered yet. |
134 private int framesDropped; | 135 private int framesDropped; |
135 // Number of rendered video frames. | 136 // Number of rendered video frames. |
136 private int framesRendered; | 137 private int framesRendered; |
137 // Time in ns when the first video frame was rendered. | 138 // Time in ns when the first video frame was rendered. |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
391 this.mirror = mirror; | 392 this.mirror = mirror; |
392 updateTextureProperties = true; | 393 updateTextureProperties = true; |
393 } | 394 } |
394 } | 395 } |
395 | 396 |
396 private void setSize(final int videoWidth, final int videoHeight, final int rotation) { | 397 private void setSize(final int videoWidth, final int videoHeight, final int rotation) { |
397 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight | 398 if (videoWidth == this.videoWidth && videoHeight == this.videoHeight |
398 && rotation == rotationDegree) { | 399 && rotation == rotationDegree) { |
399 return; | 400 return; |
400 } | 401 } |
402 if (rendererEvents != null) { | |
403 Log.d(TAG, "ID: " + id + | |
404 ". Reporting frame resolution changed to " + videoWidth + " x " + vi deoHeight); | |
wzh
2015/08/14 16:53:28
nit: + ". Reporting ..."
AlexG
2015/08/14 18:28:12
I think for Chrome Java standard is a little diffe
| |
405 rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotatio n); | |
406 } | |
401 | 407 |
402 // Frame re-allocation need to be synchronized with copying | 408 // Frame re-allocation need to be synchronized with copying |
403 // frame to textures in draw() function to avoid re-allocating | 409 // frame to textures in draw() function to avoid re-allocating |
404 // the frame while it is being copied. | 410 // the frame while it is being copied. |
405 synchronized (frameToRenderQueue) { | 411 synchronized (frameToRenderQueue) { |
406 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " + | 412 Log.d(TAG, "ID: " + id + ". YuvImageRenderer.setSize: " + |
407 videoWidth + " x " + videoHeight + " rotation " + rotation); | 413 videoWidth + " x " + videoHeight + " rotation " + rotation); |
408 | 414 |
409 this.videoWidth = videoWidth; | 415 this.videoWidth = videoWidth; |
410 this.videoHeight = videoHeight; | 416 this.videoHeight = videoHeight; |
411 rotationDegree = rotation; | 417 rotationDegree = rotation; |
412 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 }; | 418 int[] strides = { videoWidth, videoWidth / 2, videoWidth / 2 }; |
413 | 419 |
414 // Clear rendering queue. | 420 // Clear rendering queue. |
415 frameToRenderQueue.poll(); | 421 frameToRenderQueue.poll(); |
416 // Re-allocate / allocate the frame. | 422 // Re-allocate / allocate the frame. |
417 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree , | 423 yuvFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDegree , |
418 strides, null); | 424 strides, null); |
419 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe gree, | 425 textureFrameToRender = new I420Frame(videoWidth, videoHeight, rotationDe gree, |
420 null, -1); | 426 null, -1); |
421 updateTextureProperties = true; | 427 updateTextureProperties = true; |
422 Log.d(TAG, " YuvImageRenderer.setSize done."); | 428 Log.d(TAG, " YuvImageRenderer.setSize done."); |
423 } | 429 } |
424 } | 430 } |
425 | 431 |
426 @Override | 432 @Override |
427 public synchronized void renderFrame(I420Frame frame) { | 433 public synchronized void renderFrame(I420Frame frame) { |
434 if (!seenFrame && rendererEvents != null) { | |
435 Log.d(TAG, "ID: " + id + ". Reporting first rendered frame."); | |
436 rendererEvents.onFirstFrameRendered(); | |
437 } | |
428 setSize(frame.width, frame.height, frame.rotationDegree); | 438 setSize(frame.width, frame.height, frame.rotationDegree); |
429 long now = System.nanoTime(); | 439 long now = System.nanoTime(); |
430 framesReceived++; | 440 framesReceived++; |
431 // Skip rendering of this frame if setSize() was not called. | 441 // Skip rendering of this frame if setSize() was not called. |
432 if (yuvFrameToRender == null || textureFrameToRender == null) { | 442 if (yuvFrameToRender == null || textureFrameToRender == null) { |
433 framesDropped++; | 443 framesDropped++; |
434 return; | 444 return; |
435 } | 445 } |
436 // Check input frame parameters. | 446 // Check input frame parameters. |
437 if (frame.yuvFrame) { | 447 if (frame.yuvFrame) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
473 surface.requestRender(); | 483 surface.requestRender(); |
474 } | 484 } |
475 | 485 |
476 // TODO(guoweis): Remove this once chrome code base is updated. | 486 // TODO(guoweis): Remove this once chrome code base is updated. |
477 @Override | 487 @Override |
478 public boolean canApplyRotation() { | 488 public boolean canApplyRotation() { |
479 return true; | 489 return true; |
480 } | 490 } |
481 } | 491 } |
482 | 492 |
493 /** Interface for reporting rendering events. */ | |
494 public static interface RendererEvents { | |
495 /** | |
496 * Callback fired once first frame is rendered. | |
497 */ | |
498 public void onFirstFrameRendered(); | |
499 | |
500 /** | |
501 * Callback fired when rendered frame resolution or rotation has changed. | |
502 */ | |
503 public void onFrameResolutionChanged(int videoWidth, int videoHeight, int ro tation); | |
504 } | |
505 | |
483 /** Passes GLSurfaceView to video renderer. */ | 506 /** Passes GLSurfaceView to video renderer. */ |
484 public static void setView(GLSurfaceView surface, | 507 public static void setView(GLSurfaceView surface, |
485 Runnable eglContextReadyCallback) { | 508 Runnable eglContextReadyCallback) { |
486 Log.d(TAG, "VideoRendererGui.setView"); | 509 Log.d(TAG, "VideoRendererGui.setView"); |
487 instance = new VideoRendererGui(surface); | 510 instance = new VideoRendererGui(surface); |
488 eglContextReady = eglContextReadyCallback; | 511 eglContextReady = eglContextReadyCallback; |
489 } | 512 } |
490 | 513 |
491 public static EGLContext getEGLContext() { | 514 public static EGLContext getEGLContext() { |
492 return eglContext; | 515 return eglContext; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
567 } | 590 } |
568 synchronized (instance.yuvImageRenderers) { | 591 synchronized (instance.yuvImageRenderers) { |
569 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { | 592 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { |
570 if (yuvImageRenderer == renderer) { | 593 if (yuvImageRenderer == renderer) { |
571 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror) ; | 594 yuvImageRenderer.setPosition(x, y, width, height, scalingType, mirror) ; |
572 } | 595 } |
573 } | 596 } |
574 } | 597 } |
575 } | 598 } |
576 | 599 |
600 public static void setRendererEvents( | |
601 VideoRenderer.Callbacks renderer, RendererEvents rendererEvents) { | |
602 Log.d(TAG, "VideoRendererGui.setRendererEvents"); | |
603 if (instance == null) { | |
604 throw new RuntimeException( | |
605 "Attempt to set renderer events before setting GLSurfaceView"); | |
606 } | |
607 synchronized (instance.yuvImageRenderers) { | |
608 for (YuvImageRenderer yuvImageRenderer : instance.yuvImageRenderers) { | |
609 if (yuvImageRenderer == renderer) { | |
610 yuvImageRenderer.rendererEvents = rendererEvents; | |
611 } | |
612 } | |
613 } | |
614 } | |
615 | |
577 public static void remove(VideoRenderer.Callbacks renderer) { | 616 public static void remove(VideoRenderer.Callbacks renderer) { |
578 Log.d(TAG, "VideoRendererGui.remove"); | 617 Log.d(TAG, "VideoRendererGui.remove"); |
579 if (instance == null) { | 618 if (instance == null) { |
580 throw new RuntimeException( | 619 throw new RuntimeException( |
581 "Attempt to remove yuv renderer before setting GLSurfaceView"); | 620 "Attempt to remove yuv renderer before setting GLSurfaceView"); |
582 } | 621 } |
583 synchronized (instance.yuvImageRenderers) { | 622 synchronized (instance.yuvImageRenderers) { |
584 if (!instance.yuvImageRenderers.remove(renderer)) { | 623 if (!instance.yuvImageRenderers.remove(renderer)) { |
585 Log.w(TAG, "Couldn't remove renderer (not present in current list)"); | 624 Log.w(TAG, "Couldn't remove renderer (not present in current list)"); |
586 } | 625 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 GLES20.glViewport(0, 0, screenWidth, screenHeight); | 674 GLES20.glViewport(0, 0, screenWidth, screenHeight); |
636 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); | 675 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); |
637 synchronized (yuvImageRenderers) { | 676 synchronized (yuvImageRenderers) { |
638 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { | 677 for (YuvImageRenderer yuvImageRenderer : yuvImageRenderers) { |
639 yuvImageRenderer.draw(drawer); | 678 yuvImageRenderer.draw(drawer); |
640 } | 679 } |
641 } | 680 } |
642 } | 681 } |
643 | 682 |
644 } | 683 } |
OLD | NEW |