Index: talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java |
diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java |
index 50fbdf9f75fee8912ad669ad18962b6ef5184654..00ac2e50faf27d850e45cedf6b02484442461f51 100644 |
--- a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java |
+++ b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java |
@@ -31,7 +31,6 @@ import android.content.Context; |
import android.graphics.SurfaceTexture; |
import android.hardware.Camera; |
import android.hardware.Camera.PreviewCallback; |
-import android.opengl.EGL14; |
import android.opengl.EGLContext; |
import android.opengl.GLES11Ext; |
import android.opengl.GLES20; |
@@ -93,7 +92,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
private final Object pendingCameraSwitchLock = new Object(); |
private volatile boolean pendingCameraSwitch; |
private CapturerObserver frameObserver = null; |
- private final CameraErrorHandler errorHandler; |
+ private final CameraEventsHandler eventsHandler; |
+ private boolean firstFrameReported; |
private final boolean isCapturingToTexture; |
// |cameraGlTexture| is used with setPreviewTexture if the capturer is capturing to |
// ByteBuffers. |
@@ -120,8 +120,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
errorMessage = "Camera error: " + error; |
} |
Logging.e(TAG, errorMessage); |
- if (errorHandler != null) { |
- errorHandler.onCameraError(errorMessage); |
+ if (eventsHandler != null) { |
+ eventsHandler.onCameraError(errorMessage); |
} |
} |
}; |
@@ -138,8 +138,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
". Pending buffers: " + cameraStatistics.pendingFramesTimeStamps()); |
if (cameraFramesCount == 0) { |
Logging.e(TAG, "Camera freezed."); |
- if (errorHandler != null) { |
- errorHandler.onCameraError("Camera failure."); |
+ if (eventsHandler != null) { |
+ eventsHandler.onCameraError("Camera failure."); |
} |
} else { |
cameraThreadHandler.postDelayed(this, CAMERA_OBSERVER_PERIOD_MS); |
@@ -194,10 +194,19 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
} |
} |
- // Camera error handler - invoked when camera stops receiving frames |
- // or any camera exception happens on camera thread. |
- public static interface CameraErrorHandler { |
- public void onCameraError(String errorDescription); |
+ public static interface CameraEventsHandler { |
+ // Camera error handler - invoked when camera stops receiving frames |
+ // or any camera exception happens on camera thread. |
+ void onCameraError(String errorDescription); |
+ |
+ // Callback invoked when camera is opening. |
+ void onCameraOpening(int cameraId); |
+ |
+ // Callback invoked when first camera frame is available after camera is opened. |
+ void onFirstFrameAvailable(); |
+ |
+ // Callback invoked when camera closed. |
+ void onCameraClosed(); |
} |
// Camera switch handler - one of these functions are invoked with the result of switchCamera(). |
@@ -210,18 +219,18 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
} |
public static VideoCapturerAndroid create(String name, |
- CameraErrorHandler errorHandler) { |
- return VideoCapturerAndroid.create(name, errorHandler, null); |
+ CameraEventsHandler eventsHandler) { |
+ return VideoCapturerAndroid.create(name, eventsHandler, null); |
} |
public static VideoCapturerAndroid create(String name, |
- CameraErrorHandler errorHandler, Object sharedEglContext) { |
+ CameraEventsHandler eventsHandler, Object sharedEglContext) { |
final int cameraId = lookupDeviceName(name); |
if (cameraId == -1) { |
return null; |
} |
- final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, errorHandler, |
+ final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, eventsHandler, |
sharedEglContext); |
capturer.setNativeCapturer(nativeCreateVideoCapturer(capturer)); |
return capturer; |
@@ -327,11 +336,11 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
this(cameraId, null, null); |
} |
- private VideoCapturerAndroid(int cameraId, CameraErrorHandler errorHandler, |
+ private VideoCapturerAndroid(int cameraId, CameraEventsHandler eventsHandler, |
Object sharedContext) { |
Logging.d(TAG, "VideoCapturerAndroid"); |
this.id = cameraId; |
- this.errorHandler = errorHandler; |
+ this.eventsHandler = eventsHandler; |
cameraThread = new HandlerThread(TAG); |
cameraThread.start(); |
cameraThreadHandler = new Handler(cameraThread.getLooper()); |
@@ -437,6 +446,10 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
try { |
synchronized (cameraIdLock) { |
Logging.d(TAG, "Opening camera " + id); |
+ firstFrameReported = false; |
+ if (eventsHandler != null) { |
+ eventsHandler.onCameraOpening(id); |
+ } |
camera = Camera.open(id); |
info = new Camera.CameraInfo(); |
Camera.getCameraInfo(id, info); |
@@ -469,8 +482,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
Logging.e(TAG, "startCapture failed", error); |
stopCaptureOnCameraThread(); |
frameObserver.onCapturerStarted(false); |
- if (errorHandler != null) { |
- errorHandler.onCameraError("Camera can not be started."); |
+ if (eventsHandler != null) { |
+ eventsHandler.onCameraError("Camera can not be started."); |
} |
return; |
} |
@@ -588,6 +601,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
Logging.d(TAG, "Release camera."); |
camera.release(); |
camera = null; |
+ if (eventsHandler != null) { |
+ eventsHandler.onCameraClosed(); |
+ } |
if (cameraGlTexture != 0) { |
GLES20.glDeleteTextures(1, new int[] {cameraGlTexture}, 0); |
@@ -680,6 +696,10 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba |
final long captureTimeNs = |
TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime()); |
+ if (eventsHandler != null && !firstFrameReported) { |
+ eventsHandler.onFirstFrameAvailable(); |
+ firstFrameReported = true; |
+ } |
// Mark the frame owning |data| as used. |
// Note that since data is directBuffer, |