webrtc_m130/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java
Magnus Jedvert 5e7834e151 Android: Make VideoCapturer an interface for all VideoCapturers to implement
This CL factors out the interface that AndroidVideoCapturerJni is using to communicate with the Java counterpart. This interface is moved into VideoCapturer. The interface is not touched in this CL, and a follow-up CL is planned to simplify and improve it.

Another change is that the native part of VideoCapturer is created in PeerConnectionFactory.createVideoSource() instead of doing it immediately in the ctor.

BUG=webrtc:5519
R=perkj@webrtc.org

Review URL: https://codereview.webrtc.org/1696553003 .

Cr-Commit-Position: refs/heads/master@{#11606}
2016-02-12 16:05:36 +00:00

210 lines
7.5 KiB
Java

/*
* 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;
}
}