Handle borked Android cameras gracefully.

It turns out that Camera.getCameraInfo can throw an exception if the camera does not work.

TESTED=added a throw before all calls to Camera.open and Camera.getCameraInfo and made sure APPRtcDemo does not crash.

BUG=4371
R=glaznev@webrtc.org, magjed@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/44909004

Cr-Commit-Position: refs/heads/master@{#8876}
This commit is contained in:
Per
2015-03-27 11:15:19 +01:00
parent 8324b525dc
commit 75a0255627

View File

@ -103,31 +103,51 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
return Camera.getNumberOfCameras(); return Camera.getNumberOfCameras();
} }
// Returns the name of the camera with camera index. Returns null if the
// camera can not be used.
public static String getDeviceName(int index) { public static String getDeviceName(int index) {
Camera.CameraInfo info = new Camera.CameraInfo(); Camera.CameraInfo info = new Camera.CameraInfo();
try {
Camera.getCameraInfo(index, info); Camera.getCameraInfo(index, info);
} catch (Exception e) {
Log.e(TAG, "getCameraInfo failed on index " + index,e);
return null;
}
String facing = String facing =
(info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back"; (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back";
return "Camera " + index + ", Facing " + facing return "Camera " + index + ", Facing " + facing
+ ", Orientation " + info.orientation; + ", Orientation " + info.orientation;
} }
// Returns the name of the front facing camera. Returns null if the
// camera can not be used or does not exist.
public static String getNameOfFrontFacingDevice() { public static String getNameOfFrontFacingDevice() {
for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
Camera.CameraInfo info = new Camera.CameraInfo(); Camera.CameraInfo info = new Camera.CameraInfo();
try {
Camera.getCameraInfo(i, info); Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
return getDeviceName(i); return getDeviceName(i);
} catch (Exception e) {
Log.e(TAG, "getCameraInfo failed on index " + i, e);
}
} }
return null; return null;
} }
// Returns the name of the back facing camera. Returns null if the
// camera can not be used or does not exist.
public static String getNameOfBackFacingDevice() { public static String getNameOfBackFacingDevice() {
for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
Camera.CameraInfo info = new Camera.CameraInfo(); Camera.CameraInfo info = new Camera.CameraInfo();
try {
Camera.getCameraInfo(i, info); Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
return getDeviceName(i); return getDeviceName(i);
} catch (Exception e) {
Log.e(TAG, "getCameraInfo failed on index " + i, e);
}
} }
return null; return null;
} }
@ -152,10 +172,10 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
return false; return false;
} }
id = ++id % Camera.getNumberOfCameras(); int new_id = (id + 1) % Camera.getNumberOfCameras();
CaptureFormat formatToUse = null; CaptureFormat formatToUse = null;
List<CaptureFormat> formats = supportedFormats.get(id); List<CaptureFormat> formats = supportedFormats.get(new_id);
for (CaptureFormat format : formats) { for (CaptureFormat format : formats) {
if (format.width == width && format.height == height) { if (format.width == width && format.height == height) {
formatToUse = format; formatToUse = format;
@ -168,6 +188,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
return false; return false;
} }
id = new_id;
cameraThreadHandler.post(new Runnable() { cameraThreadHandler.post(new Runnable() {
@Override public void run() { @Override public void run() {
switchCameraOnCameraThread(); switchCameraOnCameraThread();
@ -188,7 +209,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
// compatible with the generic VideoCapturer class. // compatible with the generic VideoCapturer class.
boolean init(String deviceName) { boolean init(String deviceName) {
Log.d(TAG, "init " + deviceName); Log.d(TAG, "init " + deviceName);
if (!initStatics()) if (deviceName == null || !initStatics())
return false; return false;
boolean foundDevice = false; boolean foundDevice = false;
@ -197,7 +218,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
foundDevice = true; foundDevice = true;
} else { } else {
for (int i = 0; i < Camera.getNumberOfCameras(); ++i) { for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
if (deviceName.equals(getDeviceName(i))) { String existing_device = getDeviceName(i);
if (existing_device != null && deviceName.equals(existing_device)) {
this.id = i; this.id = i;
foundDevice = true; foundDevice = true;
} }
@ -259,12 +281,19 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
// Returns a list of CaptureFormat for the camera with index id. // Returns a list of CaptureFormat for the camera with index id.
static ArrayList<CaptureFormat> getSupportedFormats(int id) { static ArrayList<CaptureFormat> getSupportedFormats(int id) {
ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
Camera camera; Camera camera;
try {
camera = Camera.open(id); camera = Camera.open(id);
} catch (Exception e) {
Log.e(TAG, "Open camera failed on id " + id, e);
return formatList;
}
try {
Camera.Parameters parameters; Camera.Parameters parameters;
parameters = camera.getParameters(); parameters = camera.getParameters();
ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
// getSupportedPreviewFpsRange returns a sorted list. // getSupportedPreviewFpsRange returns a sorted list.
List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
int[] range = {0, 0}; int[] range = {0, 0};
@ -276,8 +305,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
if (size.width % 16 != 0) { if (size.width % 16 != 0) {
// If the width is not a multiple of 16, the frames received from the // If the width is not a multiple of 16, the frames received from the
// camera will have a stride != width when YV12 is used. Since we // camera will have a stride != width when YV12 is used. Since we
// currently only support tightly packed images, we simply ignore those // currently only support tightly packed images, we simply ignore
// resolutions. // those resolutions.
continue; continue;
} }
formatList.add(new CaptureFormat(size.width, size.height, formatList.add(new CaptureFormat(size.width, size.height,
@ -285,6 +314,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX])); range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
} }
camera.release(); camera.release();
} catch (Exception e) {
Log.e(TAG, "getSupportedFormats failed on id " + id, e);
}
return formatList; return formatList;
} }