Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java

Issue 1401023003: Make VideoCapturerAndroid work on SDK level 16 (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2015 Google Inc. 3 * Copyright 2015 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 10 matching lines...) Expand all
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 package org.webrtc; 28 package org.webrtc;
29 29
30 import android.content.Context; 30 import android.content.Context;
31 import android.graphics.SurfaceTexture;
31 import android.hardware.Camera; 32 import android.hardware.Camera;
32 import android.hardware.Camera.PreviewCallback; 33 import android.hardware.Camera.PreviewCallback;
33 import android.opengl.EGL14; 34 import android.opengl.EGL14;
34 import android.opengl.EGLContext; 35 import android.opengl.EGLContext;
36 import android.opengl.GLES11Ext;
37 import android.opengl.GLES20;
35 import android.os.Handler; 38 import android.os.Handler;
36 import android.os.HandlerThread; 39 import android.os.HandlerThread;
37 import android.os.SystemClock; 40 import android.os.SystemClock;
38 import android.text.StaticLayout;
39 import android.view.Surface; 41 import android.view.Surface;
40 import android.view.WindowManager; 42 import android.view.WindowManager;
41 43
42 import org.json.JSONException; 44 import org.json.JSONException;
43 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; 45 import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
44 import org.webrtc.Logging; 46 import org.webrtc.Logging;
45 47
46 import java.io.IOException; 48 import java.io.IOException;
47 import java.nio.ByteBuffer; 49 import java.nio.ByteBuffer;
48 import java.util.ArrayList; 50 import java.util.ArrayList;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 private int requestedWidth; 88 private int requestedWidth;
87 private int requestedHeight; 89 private int requestedHeight;
88 private int requestedFramerate; 90 private int requestedFramerate;
89 // The capture format will be the closest supported format to the requested fo rmat. 91 // The capture format will be the closest supported format to the requested fo rmat.
90 private CaptureFormat captureFormat; 92 private CaptureFormat captureFormat;
91 private final Object pendingCameraSwitchLock = new Object(); 93 private final Object pendingCameraSwitchLock = new Object();
92 private volatile boolean pendingCameraSwitch; 94 private volatile boolean pendingCameraSwitch;
93 private CapturerObserver frameObserver = null; 95 private CapturerObserver frameObserver = null;
94 private final CameraErrorHandler errorHandler; 96 private final CameraErrorHandler errorHandler;
95 private final boolean isCapturingToTexture; 97 private final boolean isCapturingToTexture;
98 // |cameraGlTexture| is used with setPreviewTexture if the capturer is capturi ng to
99 // ByteBuffers.
100 private int cameraGlTexture;
101 // |cameraSurfaceTexture| is used with setPreviewTexture if the capturer is ca pturing to
102 // ByteBuffers. Must be a member, see issue webrtc:5021.
103 private SurfaceTexture cameraSurfaceTexture;
104 //|surfaceHelper| is used if the capturer is capturing to a texture. Capturing to textures require
105 // API level 17.
96 private final SurfaceTextureHelper surfaceHelper; 106 private final SurfaceTextureHelper surfaceHelper;
97 // The camera API can output one old frame after the camera has been switched or the resolution 107 // The camera API can output one old frame after the camera has been switched or the resolution
98 // has been changed. This flag is used for dropping the first frame after came ra restart. 108 // has been changed. This flag is used for dropping the first frame after came ra restart.
99 private boolean dropNextFrame = false; 109 private boolean dropNextFrame = false;
100 110
101 // Camera error callback. 111 // Camera error callback.
102 private final Camera.ErrorCallback cameraErrorCallback = 112 private final Camera.ErrorCallback cameraErrorCallback =
103 new Camera.ErrorCallback() { 113 new Camera.ErrorCallback() {
104 @Override 114 @Override
105 public void onError(int error, Camera camera) { 115 public void onError(int error, Camera camera) {
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 // Invoked on failure, e.g. camera is stopped or only one camera available. 208 // Invoked on failure, e.g. camera is stopped or only one camera available.
199 void onCameraSwitchError(String errorDescription); 209 void onCameraSwitchError(String errorDescription);
200 } 210 }
201 211
202 public static VideoCapturerAndroid create(String name, 212 public static VideoCapturerAndroid create(String name,
203 CameraErrorHandler errorHandler) { 213 CameraErrorHandler errorHandler) {
204 return VideoCapturerAndroid.create(name, errorHandler, null); 214 return VideoCapturerAndroid.create(name, errorHandler, null);
205 } 215 }
206 216
207 public static VideoCapturerAndroid create(String name, 217 public static VideoCapturerAndroid create(String name,
208 CameraErrorHandler errorHandler, EGLContext sharedContext) { 218 CameraErrorHandler errorHandler, Object sharedEglContext) {
209 final int cameraId = lookupDeviceName(name); 219 final int cameraId = lookupDeviceName(name);
210 if (cameraId == -1) { 220 if (cameraId == -1) {
211 return null; 221 return null;
212 } 222 }
213 223
214 final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, err orHandler, 224 final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, err orHandler,
215 sharedContext); 225 sharedEglContext);
216 capturer.setNativeCapturer(nativeCreateVideoCapturer(capturer)); 226 capturer.setNativeCapturer(nativeCreateVideoCapturer(capturer));
217 return capturer; 227 return capturer;
218 } 228 }
219 229
220 // Switch camera to the next valid camera id. This can only be called while 230 // Switch camera to the next valid camera id. This can only be called while
221 // the camera is running. 231 // the camera is running.
222 public void switchCamera(final CameraSwitchHandler handler) { 232 public void switchCamera(final CameraSwitchHandler handler) {
223 if (Camera.getNumberOfCameras() < 2) { 233 if (Camera.getNumberOfCameras() < 2) {
224 if (handler != null) { 234 if (handler != null) {
225 handler.onCameraSwitchError("No camera to switch to."); 235 handler.onCameraSwitchError("No camera to switch to.");
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 private String getSupportedFormatsAsJson() throws JSONException { 309 private String getSupportedFormatsAsJson() throws JSONException {
300 return CameraEnumerationAndroid.getSupportedFormatsAsJson(getCurrentCameraId ()); 310 return CameraEnumerationAndroid.getSupportedFormatsAsJson(getCurrentCameraId ());
301 } 311 }
302 312
303 // Called from native VideoCapturer_nativeCreateVideoCapturer. 313 // Called from native VideoCapturer_nativeCreateVideoCapturer.
304 private VideoCapturerAndroid(int cameraId) { 314 private VideoCapturerAndroid(int cameraId) {
305 this(cameraId, null, null); 315 this(cameraId, null, null);
306 } 316 }
307 317
308 private VideoCapturerAndroid(int cameraId, CameraErrorHandler errorHandler, 318 private VideoCapturerAndroid(int cameraId, CameraErrorHandler errorHandler,
309 EGLContext sharedContext) { 319 Object sharedContext) {
310 Logging.d(TAG, "VideoCapturerAndroid"); 320 Logging.d(TAG, "VideoCapturerAndroid");
311 this.id = cameraId; 321 this.id = cameraId;
312 this.errorHandler = errorHandler; 322 this.errorHandler = errorHandler;
313 cameraThread = new HandlerThread(TAG); 323 cameraThread = new HandlerThread(TAG);
314 cameraThread.start(); 324 cameraThread.start();
315 cameraThreadHandler = new Handler(cameraThread.getLooper()); 325 cameraThreadHandler = new Handler(cameraThread.getLooper());
316 videoBuffers = new FramePool(cameraThread); 326 videoBuffers = new FramePool(cameraThread);
317 surfaceHelper = SurfaceTextureHelper.create(
318 sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext, cameraThre adHandler);
319 if (sharedContext != null) { 327 if (sharedContext != null) {
328 surfaceHelper = SurfaceTextureHelper.create((EGLContext)sharedContext, cam eraThreadHandler);
320 surfaceHelper.setListener(this); 329 surfaceHelper.setListener(this);
330 isCapturingToTexture = true;
331 } else {
332 surfaceHelper = null;
333 isCapturingToTexture = false;
321 } 334 }
322 isCapturingToTexture = sharedContext != null;
323 } 335 }
324 336
325 private void checkIsOnCameraThread() { 337 private void checkIsOnCameraThread() {
326 if (Thread.currentThread() != cameraThread) { 338 if (Thread.currentThread() != cameraThread) {
327 throw new IllegalStateException("Wrong thread"); 339 throw new IllegalStateException("Wrong thread");
328 } 340 }
329 } 341 }
330 342
331 // Returns the camera index for camera with name |deviceName|, or -1 if no suc h camera can be 343 // Returns the camera index for camera with name |deviceName|, or -1 if no suc h camera can be
332 // found. If |deviceName| is empty, the first available device is used. 344 // found. If |deviceName| is empty, the first available device is used.
(...skipping 13 matching lines...) Expand all
346 return -1; 358 return -1;
347 } 359 }
348 360
349 // Called by native code to quit the camera thread. This needs to be done manu ally, otherwise the 361 // Called by native code to quit the camera thread. This needs to be done manu ally, otherwise the
350 // thread and handler will not be garbage collected. 362 // thread and handler will not be garbage collected.
351 private void release() { 363 private void release() {
352 Logging.d(TAG, "release"); 364 Logging.d(TAG, "release");
353 if (isReleased()) { 365 if (isReleased()) {
354 throw new IllegalStateException("Already released"); 366 throw new IllegalStateException("Already released");
355 } 367 }
356 cameraThreadHandler.post(new Runnable() { 368 ThreadUtils.invokeUninterruptibly(cameraThreadHandler, new Runnable() {
357 @Override 369 @Override
358 public void run() { 370 public void run() {
359 if (camera != null) { 371 if (camera != null) {
360 throw new IllegalStateException("Release called while camera is runnin g"); 372 throw new IllegalStateException("Release called while camera is runnin g");
361 } 373 }
362 if (cameraStatistics.pendingFramesCount() != 0) { 374 if (cameraStatistics.pendingFramesCount() != 0) {
363 throw new IllegalStateException("Release called with pending frames le ft"); 375 throw new IllegalStateException("Release called with pending frames le ft");
364 } 376 }
365 } 377 }
366 }); 378 });
367 surfaceHelper.disconnect(); 379 if (isCapturingToTexture) {
368 380 surfaceHelper.disconnect();
369 cameraThread.quitSafely(); 381 }
382 cameraThread.quit();
370 ThreadUtils.joinUninterruptibly(cameraThread); 383 ThreadUtils.joinUninterruptibly(cameraThread);
371 cameraThread = null; 384 cameraThread = null;
372 } 385 }
373 386
374 // Used for testing purposes to check if release() has been called. 387 // Used for testing purposes to check if release() has been called.
375 public boolean isReleased() { 388 public boolean isReleased() {
376 return (cameraThread == null); 389 return (cameraThread == null);
377 } 390 }
378 391
379 // Called by native code. 392 // Called by native code.
(...skipping 30 matching lines...) Expand all
410 this.applicationContext = applicationContext; 423 this.applicationContext = applicationContext;
411 this.frameObserver = frameObserver; 424 this.frameObserver = frameObserver;
412 try { 425 try {
413 synchronized (cameraIdLock) { 426 synchronized (cameraIdLock) {
414 Logging.d(TAG, "Opening camera " + id); 427 Logging.d(TAG, "Opening camera " + id);
415 camera = Camera.open(id); 428 camera = Camera.open(id);
416 info = new Camera.CameraInfo(); 429 info = new Camera.CameraInfo();
417 Camera.getCameraInfo(id, info); 430 Camera.getCameraInfo(id, info);
418 } 431 }
419 try { 432 try {
420 camera.setPreviewTexture(surfaceHelper.getSurfaceTexture()); 433 if (isCapturingToTexture) {
434 camera.setPreviewTexture(surfaceHelper.getSurfaceTexture());
435 } else {
436 cameraGlTexture = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL _OES);
437 cameraSurfaceTexture = new SurfaceTexture(cameraGlTexture);
438 camera.setPreviewTexture(cameraSurfaceTexture);
439 }
421 } catch (IOException e) { 440 } catch (IOException e) {
422 Logging.e(TAG, "setPreviewTexture failed", error); 441 Logging.e(TAG, "setPreviewTexture failed", error);
423 throw new RuntimeException(e); 442 throw new RuntimeException(e);
424 } 443 }
425 444
426 Logging.d(TAG, "Camera orientation: " + info.orientation + 445 Logging.d(TAG, "Camera orientation: " + info.orientation +
427 " .Device orientation: " + getDeviceOrientation()); 446 " .Device orientation: " + getDeviceOrientation());
428 camera.setErrorCallback(cameraErrorCallback); 447 camera.setErrorCallback(cameraErrorCallback);
429 startPreviewOnCameraThread(width, height, framerate); 448 startPreviewOnCameraThread(width, height, framerate);
430 frameObserver.onCapturerStarted(true); 449 frameObserver.onCapturerStarted(true);
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 Logging.d(TAG, "stopReturnBuffersToCamera called." 569 Logging.d(TAG, "stopReturnBuffersToCamera called."
551 + (cameraStatistics.pendingFramesCount() == 0? 570 + (cameraStatistics.pendingFramesCount() == 0?
552 " All buffers have been returned." 571 " All buffers have been returned."
553 : " Pending buffers: " + cameraStatistics.pendingFramesTimeStamps () + ".")); 572 : " Pending buffers: " + cameraStatistics.pendingFramesTimeStamps () + "."));
554 } 573 }
555 captureFormat = null; 574 captureFormat = null;
556 575
557 Logging.d(TAG, "Release camera."); 576 Logging.d(TAG, "Release camera.");
558 camera.release(); 577 camera.release();
559 camera = null; 578 camera = null;
579
580 if (cameraGlTexture != 0) {
581 GLES20.glDeleteTextures(1, new int[] {cameraGlTexture}, 0);
582 cameraGlTexture = 0;
583 }
584 if (cameraSurfaceTexture != null) {
585 cameraSurfaceTexture.release();
586 }
560 } 587 }
561 588
562 private void switchCameraOnCameraThread() { 589 private void switchCameraOnCameraThread() {
563 checkIsOnCameraThread(); 590 checkIsOnCameraThread();
564 Logging.d(TAG, "switchCameraOnCameraThread"); 591 Logging.d(TAG, "switchCameraOnCameraThread");
565 stopCaptureOnCameraThread(); 592 stopCaptureOnCameraThread();
566 synchronized (cameraIdLock) { 593 synchronized (cameraIdLock) {
567 id = (id + 1) % Camera.getNumberOfCameras(); 594 id = (id + 1) % Camera.getNumberOfCameras();
568 } 595 }
569 dropNextFrame = true; 596 dropNextFrame = true;
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 private native void nativeOnByteBufferFrameCaptured(long nativeCapturer, 881 private native void nativeOnByteBufferFrameCaptured(long nativeCapturer,
855 byte[] data, int length, int width, int height, int rotation, long timeS tamp); 882 byte[] data, int length, int width, int height, int rotation, long timeS tamp);
856 private native void nativeOnTextureFrameCaptured(long nativeCapturer, int wi dth, int height, 883 private native void nativeOnTextureFrameCaptured(long nativeCapturer, int wi dth, int height,
857 int oesTextureId, float[] transformMatrix, long timestamp); 884 int oesTextureId, float[] transformMatrix, long timestamp);
858 private native void nativeOnOutputFormatRequest(long nativeCapturer, 885 private native void nativeOnOutputFormatRequest(long nativeCapturer,
859 int width, int height, int framerate); 886 int width, int height, int framerate);
860 } 887 }
861 888
862 private static native long nativeCreateVideoCapturer(VideoCapturerAndroid vide oCapturer); 889 private static native long nativeCreateVideoCapturer(VideoCapturerAndroid vide oCapturer);
863 } 890 }
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698