This source file includes following definitions.
- JNINamespace
- getWidth
- getHeight
- getFramerate
- getPixelFormat
- allocate
- startCapture
- stopCapture
- deallocate
- setCaptureParameters
- allocateBuffers
- setPreviewCallback
- queryWidth
- queryHeight
- queryFrameRate
- getColorspace
- getDeviceOrientation
- nativeOnFrameAvailable
- getCameraParameters
- getCameraInfo
package org.chromium.media;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.opengl.GLES20;
import android.util.Log;
import android.view.Surface;
import android.view.WindowManager;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@JNINamespace("media")
public abstract class VideoCapture implements PreviewCallback {
protected static class CaptureFormat {
int mWidth;
int mHeight;
final int mFramerate;
final int mPixelFormat;
public CaptureFormat(
int width, int height, int framerate, int pixelformat) {
mWidth = width;
mHeight = height;
mFramerate = framerate;
mPixelFormat = pixelformat;
}
public int getWidth() {
return mWidth;
}
public int getHeight() {
return mHeight;
}
public int getFramerate() {
return mFramerate;
}
public int getPixelFormat() {
return mPixelFormat;
}
}
protected Camera mCamera;
protected CaptureFormat mCaptureFormat = null;
protected ReentrantLock mPreviewBufferLock = new ReentrantLock();
protected Context mContext = null;
protected boolean mIsRunning = false;
protected int mId;
protected long mNativeVideoCaptureDeviceAndroid;
protected int[] mGlTextures = null;
protected SurfaceTexture mSurfaceTexture = null;
protected static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
protected int mCameraOrientation;
protected int mCameraFacing;
protected int mDeviceOrientation;
private static final String TAG = "VideoCapture";
VideoCapture(Context context,
int id,
long nativeVideoCaptureDeviceAndroid) {
mContext = context;
mId = id;
mNativeVideoCaptureDeviceAndroid = nativeVideoCaptureDeviceAndroid;
}
@CalledByNative
boolean allocate(int width, int height, int frameRate) {
Log.d(TAG, "allocate: requested (" + width + "x" + height + ")@" +
frameRate + "fps");
try {
mCamera = Camera.open(mId);
} catch (RuntimeException ex) {
Log.e(TAG, "allocate: Camera.open: " + ex);
return false;
}
Camera.CameraInfo cameraInfo = getCameraInfo(mId);
if (cameraInfo == null) {
mCamera.release();
mCamera = null;
return false;
}
mCameraOrientation = cameraInfo.orientation;
mCameraFacing = cameraInfo.facing;
mDeviceOrientation = getDeviceOrientation();
Log.d(TAG, "allocate: orientation dev=" + mDeviceOrientation +
", cam=" + mCameraOrientation + ", facing=" + mCameraFacing);
Camera.Parameters parameters = getCameraParameters(mCamera);
if (parameters == null) {
mCamera = null;
return false;
}
List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
if (listFpsRange == null || listFpsRange.size() == 0) {
Log.e(TAG, "allocate: no fps range found");
return false;
}
int frameRateInMs = frameRate * 1000;
int[] fpsMinMax = listFpsRange.get(0);
int newFrameRate = (fpsMinMax[0] + 999) / 1000;
for (int[] fpsRange : listFpsRange) {
if (fpsRange[0] <= frameRateInMs && frameRateInMs <= fpsRange[1]) {
fpsMinMax = fpsRange;
newFrameRate = frameRate;
break;
}
}
frameRate = newFrameRate;
Log.d(TAG, "allocate: fps set to " + frameRate);
List<Camera.Size> listCameraSize =
parameters.getSupportedPreviewSizes();
int minDiff = Integer.MAX_VALUE;
int matchedWidth = width;
int matchedHeight = height;
for (Camera.Size size : listCameraSize) {
int diff = Math.abs(size.width - width) +
Math.abs(size.height - height);
Log.d(TAG, "allocate: supported (" +
size.width + ", " + size.height + "), diff=" + diff);
if (diff < minDiff && (size.width % 32 == 0)) {
minDiff = diff;
matchedWidth = size.width;
matchedHeight = size.height;
}
}
if (minDiff == Integer.MAX_VALUE) {
Log.e(TAG, "allocate: can not find a multiple-of-32 resolution");
return false;
}
Log.d(TAG, "allocate: matched (" + matchedWidth + "x" + matchedHeight + ")");
if (parameters.isVideoStabilizationSupported()) {
Log.d(TAG, "Image stabilization supported, currently: " +
parameters.getVideoStabilization() + ", setting it.");
parameters.setVideoStabilization(true);
} else {
Log.d(TAG, "Image stabilization not supported.");
}
setCaptureParameters(matchedWidth, matchedHeight, frameRate, parameters);
parameters.setPreviewSize(mCaptureFormat.mWidth,
mCaptureFormat.mHeight);
parameters.setPreviewFpsRange(fpsMinMax[0], fpsMinMax[1]);
parameters.setPreviewFormat(mCaptureFormat.mPixelFormat);
mCamera.setParameters(parameters);
mGlTextures = new int[1];
GLES20.glGenTextures(1, mGlTextures, 0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mGlTextures[0]);
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
mSurfaceTexture = new SurfaceTexture(mGlTextures[0]);
mSurfaceTexture.setOnFrameAvailableListener(null);
try {
mCamera.setPreviewTexture(mSurfaceTexture);
} catch (IOException ex) {
Log.e(TAG, "allocate: " + ex);
return false;
}
allocateBuffers();
return true;
}
@CalledByNative
public int startCapture() {
if (mCamera == null) {
Log.e(TAG, "startCapture: camera is null");
return -1;
}
mPreviewBufferLock.lock();
try {
if (mIsRunning) {
return 0;
}
mIsRunning = true;
} finally {
mPreviewBufferLock.unlock();
}
setPreviewCallback(this);
try {
mCamera.startPreview();
} catch (RuntimeException ex) {
Log.e(TAG, "startCapture: Camera.startPreview: " + ex);
return -1;
}
return 0;
}
@CalledByNative
public int stopCapture() {
if (mCamera == null) {
Log.e(TAG, "stopCapture: camera is null");
return 0;
}
mPreviewBufferLock.lock();
try {
if (!mIsRunning) {
return 0;
}
mIsRunning = false;
} finally {
mPreviewBufferLock.unlock();
}
mCamera.stopPreview();
setPreviewCallback(null);
return 0;
}
@CalledByNative
public void deallocate() {
if (mCamera == null)
return;
stopCapture();
try {
mCamera.setPreviewTexture(null);
if (mGlTextures != null)
GLES20.glDeleteTextures(1, mGlTextures, 0);
mCaptureFormat = null;
mCamera.release();
mCamera = null;
} catch (IOException ex) {
Log.e(TAG, "deallocate: failed to deallocate camera, " + ex);
return;
}
}
abstract void setCaptureParameters(
int width,
int height,
int frameRate,
Camera.Parameters cameraParameters);
abstract void allocateBuffers();
abstract void setPreviewCallback(Camera.PreviewCallback cb);
@CalledByNative
public int queryWidth() {
return mCaptureFormat.mWidth;
}
@CalledByNative
public int queryHeight() {
return mCaptureFormat.mHeight;
}
@CalledByNative
public int queryFrameRate() {
return mCaptureFormat.mFramerate;
}
@CalledByNative
public int getColorspace() {
switch (mCaptureFormat.mPixelFormat) {
case ImageFormat.YV12:
return AndroidImageFormatList.ANDROID_IMAGEFORMAT_YV12;
case ImageFormat.NV21:
return AndroidImageFormatList.ANDROID_IMAGEFORMAT_NV21;
case ImageFormat.UNKNOWN:
default:
return AndroidImageFormatList.ANDROID_IMAGEFORMAT_UNKNOWN;
}
}
protected int getDeviceOrientation() {
int orientation = 0;
if (mContext != null) {
WindowManager wm = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
switch(wm.getDefaultDisplay().getRotation()) {
case Surface.ROTATION_90:
orientation = 90;
break;
case Surface.ROTATION_180:
orientation = 180;
break;
case Surface.ROTATION_270:
orientation = 270;
break;
case Surface.ROTATION_0:
default:
orientation = 0;
break;
}
}
return orientation;
}
public native void nativeOnFrameAvailable(
long nativeVideoCaptureDeviceAndroid,
byte[] data,
int length,
int rotation);
protected static Camera.Parameters getCameraParameters(Camera camera) {
Camera.Parameters parameters;
try {
parameters = camera.getParameters();
} catch (RuntimeException ex) {
Log.e(TAG, "getCameraParameters: Camera.getParameters: " + ex);
camera.release();
return null;
}
return parameters;
}
private Camera.CameraInfo getCameraInfo(int id) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
try {
Camera.getCameraInfo(id, cameraInfo);
} catch (RuntimeException ex) {
Log.e(TAG, "getCameraInfo: Camera.getCameraInfo: " + ex);
return null;
}
return cameraInfo;
}