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:
@ -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();
|
||||||
Camera.getCameraInfo(index, info);
|
try {
|
||||||
|
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();
|
||||||
Camera.getCameraInfo(i, info);
|
try {
|
||||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
|
Camera.getCameraInfo(i, info);
|
||||||
return getDeviceName(i);
|
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
|
||||||
|
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();
|
||||||
Camera.getCameraInfo(i, info);
|
try {
|
||||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
|
Camera.getCameraInfo(i, info);
|
||||||
return getDeviceName(i);
|
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
|
||||||
|
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,32 +281,42 @@ 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) {
|
||||||
Camera camera;
|
|
||||||
camera = Camera.open(id);
|
|
||||||
Camera.Parameters parameters;
|
|
||||||
parameters = camera.getParameters();
|
|
||||||
|
|
||||||
ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
|
ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
|
||||||
// getSupportedPreviewFpsRange returns a sorted list.
|
|
||||||
List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
|
|
||||||
int[] range = {0, 0};
|
|
||||||
if (listFpsRange != null)
|
|
||||||
range = listFpsRange.get(listFpsRange.size() -1);
|
|
||||||
|
|
||||||
List<Camera.Size> supportedSizes = parameters.getSupportedPreviewSizes();
|
Camera camera;
|
||||||
for (Camera.Size size : supportedSizes) {
|
try {
|
||||||
if (size.width % 16 != 0) {
|
camera = Camera.open(id);
|
||||||
// If the width is not a multiple of 16, the frames received from the
|
} catch (Exception e) {
|
||||||
// camera will have a stride != width when YV12 is used. Since we
|
Log.e(TAG, "Open camera failed on id " + id, e);
|
||||||
// currently only support tightly packed images, we simply ignore those
|
return formatList;
|
||||||
// resolutions.
|
}
|
||||||
continue;
|
|
||||||
}
|
try {
|
||||||
formatList.add(new CaptureFormat(size.width, size.height,
|
Camera.Parameters parameters;
|
||||||
range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
|
parameters = camera.getParameters();
|
||||||
range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
|
// getSupportedPreviewFpsRange returns a sorted list.
|
||||||
|
List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
|
||||||
|
int[] range = {0, 0};
|
||||||
|
if (listFpsRange != null)
|
||||||
|
range = listFpsRange.get(listFpsRange.size() -1);
|
||||||
|
|
||||||
|
List<Camera.Size> supportedSizes = parameters.getSupportedPreviewSizes();
|
||||||
|
for (Camera.Size size : supportedSizes) {
|
||||||
|
if (size.width % 16 != 0) {
|
||||||
|
// 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
|
||||||
|
// currently only support tightly packed images, we simply ignore
|
||||||
|
// those resolutions.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
formatList.add(new CaptureFormat(size.width, size.height,
|
||||||
|
range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
|
||||||
|
range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
|
||||||
|
}
|
||||||
|
camera.release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "getSupportedFormats failed on id " + id, e);
|
||||||
}
|
}
|
||||||
camera.release();
|
|
||||||
return formatList;
|
return formatList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user