Java tutorial
/* * Copyright 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ package org.webrtc; import static java.lang.Math.abs; import static java.lang.Math.ceil; import android.graphics.ImageFormat; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.webrtc.Logging; import java.util.Collections; import java.util.Comparator; import java.util.List; @SuppressWarnings("deprecation") public class CameraEnumerationAndroid { private final static String TAG = "CameraEnumerationAndroid"; // Synchronized on |CameraEnumerationAndroid.this|. private static Enumerator enumerator = new CameraEnumerator(); public interface Enumerator { /** * Returns a list of supported CaptureFormats for the camera with index |cameraId|. */ List<CaptureFormat> getSupportedFormats(int cameraId); } public static synchronized void setEnumerator(Enumerator enumerator) { CameraEnumerationAndroid.enumerator = enumerator; } public static synchronized List<CaptureFormat> getSupportedFormats(int cameraId) { return enumerator.getSupportedFormats(cameraId); } public static class CaptureFormat { public final int width; public final int height; public final int maxFramerate; public final int minFramerate; // TODO(hbos): If VideoCapturer.startCapture is updated to support other image formats then this // needs to be updated and VideoCapturer.getSupportedFormats need to return CaptureFormats of // all imageFormats. public final int imageFormat = ImageFormat.NV21; 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.NV21. // The size is width * height * number of bytes per pixel. // http://developer.android.com/reference/android/hardware/Camera.html#addCallbackBuffer(byte[]) public static int frameSize(int width, int height, int imageFormat) { if (imageFormat != ImageFormat.NV21) { throw new UnsupportedOperationException( "Don't know how to calculate " + "the frame size of non-NV21 image formats."); } return (width * height * ImageFormat.getBitsPerPixel(imageFormat)) / 8; } @Override public String toString() { return width + "x" + height + "@[" + minFramerate + ":" + maxFramerate + "]"; } public boolean isSameFormat(final CaptureFormat that) { if (that == null) { return false; } return width == that.width && height == that.height && maxFramerate == that.maxFramerate && minFramerate == that.minFramerate; } } // Returns device names that can be used to create a new VideoCapturerAndroid. public static String[] getDeviceNames() { String[] names = new String[android.hardware.Camera.getNumberOfCameras()]; for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { names[i] = getDeviceName(i); } return names; } // Returns number of cameras on device. public static int getDeviceCount() { return android.hardware.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) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); try { android.hardware.Camera.getCameraInfo(index, info); } catch (Exception e) { Logging.e(TAG, "getCameraInfo failed on index " + index, e); return null; } String facing = (info.facing == android.hardware.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() { return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT); } // 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() { return getNameOfDevice(android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK); } public static String getSupportedFormatsAsJson(int id) throws JSONException { List<CaptureFormat> formats = getSupportedFormats(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); } Logging.d(TAG, "Supported formats for camera " + id + ": " + json_formats.toString(2)); return json_formats.toString(); } // 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(android.hardware.Camera.Parameters parameters, final int framerate) { List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); if (listFpsRange.isEmpty()) { Logging.w(TAG, "No supported preview fps range"); return new int[] { 0, 0 }; } return Collections.min(listFpsRange, new ClosestComparator<int[]>() { @Override int diff(int[] range) { final int maxFpsWeight = 10; return range[android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + maxFpsWeight * abs(framerate - range[android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); } }); } public static android.hardware.Camera.Size getClosestSupportedSize( List<android.hardware.Camera.Size> supportedSizes, final int requestedWidth, final int requestedHeight) { return Collections.min(supportedSizes, new ClosestComparator<android.hardware.Camera.Size>() { @Override int diff(android.hardware.Camera.Size size) { return abs(requestedWidth - size.width) + abs(requestedHeight - size.height); } }); } private static String getNameOfDevice(int facing) { final android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); for (int i = 0; i < android.hardware.Camera.getNumberOfCameras(); ++i) { try { android.hardware.Camera.getCameraInfo(i, info); if (info.facing == facing) { return getDeviceName(i); } } catch (Exception e) { Logging.e(TAG, "getCameraInfo() failed on index " + i, e); } } return null; } }