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

Unified Diff: talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java

Issue 1323453002: VideoCapturerAndroid: Move to android folder and split out camera enumeration into separate file (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java
diff --git a/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6fa1274e415abc02311876adef05fb9de1d297d
--- /dev/null
+++ b/talk/app/webrtc/java/android/org/webrtc/CameraEnumerationAndroid.java
@@ -0,0 +1,293 @@
+/*
+ * libjingle
+ * Copyright 2015 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.webrtc;
+
+import static java.lang.Math.abs;
+import static java.lang.Math.ceil;
+
+import android.hardware.Camera;
+import android.util.Log;
+import android.graphics.ImageFormat;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+@SuppressWarnings("deprecation")
+public class CameraEnumerationAndroid {
+ private final static String TAG = "CameraEnumerationAndroid";
+ // List of formats supported by all cameras. This list is filled once in order
+ // to be able to switch cameras.
+ public static List<List<CaptureFormat>> supportedFormats;
+
+ public static class CaptureFormat {
+ public final int width;
+ public final int height;
+ public final int maxFramerate;
+ public final int minFramerate;
+ // TODO(hbos): If VideoCapturerAndroid.startCapture is updated to support
+ // other image formats then this needs to be updated and
+ // VideoCapturerAndroid.getSupportedFormats need to return CaptureFormats of
+ // all imageFormats.
+ public final int imageFormat = ImageFormat.YV12;
+
+ public CaptureFormat(int width, int height, int minFramerate,
+ int maxFramerate) {
+ this.width = width;
+ this.height = height;
+ this.minFramerate = minFramerate;
+ this.maxFramerate = maxFramerate;
+ }
+
+ // Calculates the frame size of this capture format.
+ public int frameSize() {
+ return frameSize(width, height, imageFormat);
+ }
+
+ // Calculates the frame size of the specified image format. Currently only
+ // supporting ImageFormat.YV12. The YV12's stride is the closest rounded up
+ // multiple of 16 of the width and width and height are always even.
+ // Android guarantees this:
+ // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29
+ public static int frameSize(int width, int height, int imageFormat) {
+ if (imageFormat != ImageFormat.YV12) {
+ throw new UnsupportedOperationException("Don't know how to calculate "
+ + "the frame size of non-YV12 image formats.");
+ }
+ int yStride = roundUp(width, 16);
+ int uvStride = roundUp(yStride / 2, 16);
+ int ySize = yStride * height;
+ int uvSize = uvStride * height / 2;
+ return ySize + uvSize * 2;
+ }
+
+ // Rounds up |x| to the closest value that is a multiple of |alignment|.
+ private static int roundUp(int x, int alignment) {
+ return (int)ceil(x / (double)alignment) * alignment;
+ }
+
+ @Override
+ public String toString() {
+ return width + "x" + height + "@[" + minFramerate + ":" + maxFramerate + "]";
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (!(that instanceof CaptureFormat)) {
+ return false;
+ }
+ final CaptureFormat c = (CaptureFormat) that;
+ return width == c.width && height == c.height && maxFramerate == c.maxFramerate
+ && minFramerate == c.minFramerate;
+ }
+ }
+
+ // Returns device names that can be used to create a new VideoCapturerAndroid.
+ public static String[] getDeviceNames() {
+ String[] names = new String[Camera.getNumberOfCameras()];
+ for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
+ names[i] = getDeviceName(i);
+ }
+ return names;
+ }
+
+ // Returns number of cameras on device.
+ public static int getDeviceCount() {
+ 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) {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ try {
+ Camera.getCameraInfo(index, info);
+ } catch (Exception e) {
+ Log.e(TAG, "getCameraInfo failed on index " + index,e);
+ return null;
+ }
+
+ String facing =
+ (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) ? "front" : "back";
+ return "Camera " + index + ", Facing " + facing
+ + ", 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() {
+ for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ try {
+ Camera.getCameraInfo(i, info);
+ 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;
+ }
+
+ // 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() {
+ for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ try {
+ Camera.getCameraInfo(i, info);
+ 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;
+ }
+
+ public static boolean initStatics() {
+ if (supportedFormats != null)
+ return true;
+ try {
+ Log.d(TAG, "Get supported formats.");
+ supportedFormats =
+ new ArrayList<List<CaptureFormat>>(Camera.getNumberOfCameras());
+ // Start requesting supported formats from camera with the highest index
+ // (back camera) first. If it fails then likely camera is in bad state.
+ for (int i = Camera.getNumberOfCameras() - 1; i >= 0; i--) {
+ ArrayList<CaptureFormat> supportedFormat = getSupportedFormats(i);
+ if (supportedFormat.size() == 0) {
+ Log.e(TAG, "Fail to get supported formats for camera " + i);
+ supportedFormats = null;
+ return false;
+ }
+ supportedFormats.add(supportedFormat);
+ }
+ // Reverse the list since it is filled in reverse order.
+ Collections.reverse(supportedFormats);
+ Log.d(TAG, "Get supported formats done.");
+ return true;
+ } catch (Exception e) {
+ supportedFormats = null;
+ Log.e(TAG, "InitStatics failed",e);
+ }
+ return false;
+ }
+
+ public static String getSupportedFormatsAsJson(int id) throws JSONException {
+ List<CaptureFormat> formats = supportedFormats.get(id);
+ JSONArray json_formats = new JSONArray();
+ for (CaptureFormat format : formats) {
+ JSONObject json_format = new JSONObject();
+ json_format.put("width", format.width);
+ json_format.put("height", format.height);
+ json_format.put("framerate", (format.maxFramerate + 999) / 1000);
+ json_formats.put(json_format);
+ }
+ Log.d(TAG, "Supported formats for camera " + id + ": "
+ + json_formats.toString(2));
+ return json_formats.toString();
+ }
+
+ // Returns a list of CaptureFormat for the camera with index id.
+ public static ArrayList<CaptureFormat> getSupportedFormats(int id) {
+ ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
+
+ Camera camera;
+ try {
+ Log.d(TAG, "Opening camera " + id);
+ camera = Camera.open(id);
+ } catch (Exception e) {
+ Log.e(TAG, "Open camera failed on id " + id, e);
+ return formatList;
+ }
+
+ try {
+ Camera.Parameters parameters;
+ parameters = camera.getParameters();
+ // 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) {
+ formatList.add(new CaptureFormat(size.width, size.height,
+ range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
+ range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "getSupportedFormats failed on id " + id, e);
+ }
+ camera.release();
+ camera = null;
+ return formatList;
+ }
+
+ // Helper class for finding the closest supported format for the two functions below.
+ private static abstract class ClosestComparator<T> implements Comparator<T> {
+ // Difference between supported and requested parameter.
+ abstract int diff(T supportedParameter);
+
+ @Override
+ public int compare(T t1, T t2) {
+ return diff(t1) - diff(t2);
+ }
+ }
+
+ public static int[] getFramerateRange(Camera.Parameters parameters, final int framerate) {
+ List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
+ if (listFpsRange.isEmpty()) {
+ Log.w(TAG, "No supported preview fps range");
+ return new int[]{0, 0};
+ }
+ return Collections.min(listFpsRange,
+ new ClosestComparator<int[]>() {
+ @Override int diff(int[] range) {
+ return abs(framerate - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX])
+ + abs(framerate - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ }
+ });
+ }
+
+ public static Camera.Size getClosestSupportedSize(
+ List<Camera.Size> supportedSizes, final int requestedWidth, final int requestedHeight) {
+ return Collections.min(supportedSizes,
+ new ClosestComparator<Camera.Size>() {
+ @Override int diff(Camera.Size size) {
+ return abs(requestedWidth - size.width) + abs(requestedHeight - size.height);
+ }
+ });
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698