Chromium Code Reviews| Index: media/base/android/java/src/org/chromium/media/VideoCapture.java |
| diff --git a/media/base/android/java/src/org/chromium/media/VideoCapture.java b/media/base/android/java/src/org/chromium/media/VideoCapture.java |
| index 7e53b7c0232ede40ed0b8d59e77a50816ffeebdd..2cf67f7b7f46ecf6a3af35f4d85b20dd73c91a5a 100644 |
| --- a/media/base/android/java/src/org/chromium/media/VideoCapture.java |
| +++ b/media/base/android/java/src/org/chromium/media/VideoCapture.java |
| @@ -18,7 +18,7 @@ import org.chromium.base.CalledByNative; |
| import org.chromium.base.JNINamespace; |
| import java.io.IOException; |
| -import java.util.Iterator; |
| +import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.locks.ReentrantLock; |
| @@ -30,10 +30,34 @@ import java.util.concurrent.locks.ReentrantLock; |
| **/ |
| @JNINamespace("media") |
| public class VideoCapture implements PreviewCallback { |
| - static class CaptureCapability { |
| + static class CaptureFormat { |
| + public CaptureFormat( |
| + int width, int height, int framerate, int pixelformat) { |
| + mWidth = width; |
| + mHeight = height; |
| + mFramerate = framerate; |
| + mPixelFormat = pixelformat; |
| + } |
| public int mWidth; |
| public int mHeight; |
| - public int mDesiredFps; |
| + public final int mFramerate; |
| + public final int mPixelFormat; |
| + @CalledByNative("CaptureFormat") |
| + public int getWidth() { |
| + return mWidth; |
| + } |
| + @CalledByNative("CaptureFormat") |
| + public int getHeight() { |
| + return mHeight; |
| + } |
| + @CalledByNative("CaptureFormat") |
| + public int getFramerate() { |
| + return mFramerate; |
| + } |
| + @CalledByNative("CaptureFormat") |
| + public int getPixelFormat() { |
| + return mPixelFormat; |
| + } |
| } |
| // Some devices don't support YV12 format correctly, even with JELLY_BEAN or |
| @@ -63,17 +87,17 @@ public class VideoCapture implements PreviewCallback { |
| "ODROID-U2", |
| }; |
| - static void applyMinDimensions(CaptureCapability capability) { |
| + static void applyMinDimensions(CaptureFormat format) { |
| // NOTE: this can discard requested aspect ratio considerations. |
| for (IdAndSizes buggyDevice : s_CAPTURESIZE_BUGGY_DEVICE_LIST) { |
| if (buggyDevice.mModel.contentEquals(android.os.Build.MODEL) && |
| buggyDevice.mDevice.contentEquals(android.os.Build.DEVICE)) { |
| - capability.mWidth = (buggyDevice.mMinWidth > capability.mWidth) |
| + format.mWidth = (buggyDevice.mMinWidth > format.mWidth) |
| ? buggyDevice.mMinWidth |
| - : capability.mWidth; |
| - capability.mHeight = (buggyDevice.mMinHeight > capability.mHeight) |
| + : format.mWidth; |
| + format.mHeight = (buggyDevice.mMinHeight > format.mHeight) |
| ? buggyDevice.mMinHeight |
| - : capability.mHeight; |
| + : format.mHeight; |
| } |
| } |
| } |
| @@ -94,7 +118,6 @@ public class VideoCapture implements PreviewCallback { |
| private Camera mCamera; |
| public ReentrantLock mPreviewBufferLock = new ReentrantLock(); |
| - private int mImageFormat = ImageFormat.YV12; |
| private Context mContext = null; |
| // True when native code has started capture. |
| private boolean mIsRunning = false; |
| @@ -112,7 +135,7 @@ public class VideoCapture implements PreviewCallback { |
| private int mCameraFacing = 0; |
| private int mDeviceOrientation = 0; |
| - CaptureCapability mCurrentCapability = null; |
| + CaptureFormat mCaptureFormat = null; |
| private static final String TAG = "VideoCapture"; |
| @CalledByNative |
| @@ -121,6 +144,44 @@ public class VideoCapture implements PreviewCallback { |
| return new VideoCapture(context, id, nativeVideoCaptureDeviceAndroid); |
| } |
| + @CalledByNative |
| + public static CaptureFormat[] getDeviceSupportedFormats(int id) { |
| + Camera camera; |
| + try { |
| + camera = Camera.open(id); |
| + } catch (RuntimeException ex) { |
| + Log.e(TAG, "Camera.open: " + ex); |
| + return null; |
| + } |
| + Camera.Parameters parameters = camera.getParameters(); |
| + |
| + ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>(); |
| + int pixelFormat = AndroidImageFormatList.ANDROID_IMAGEFORMAT_UNKNOWN; |
|
bulach
2014/02/13 14:08:23
nit: looks like this can be moved to 164, inside t
mcasas
2014/02/14 11:28:39
Done.
|
| + // getSupportedPreview{Formats,FpsRange,PreviewSizes}() returns Lists |
| + // with at least one element. |
| + List<Integer> pixelFormats = parameters.getSupportedPreviewFormats(); |
|
wjia(left Chromium)
2014/02/12 23:13:20
sanity check. see below.
mcasas
2014/02/14 11:28:39
Done.
On the sanity checks, please note that the
|
| + for (Integer previewFormat : pixelFormats) { |
| + if (previewFormat == ImageFormat.YV12) |
|
wjia(left Chromium)
2014/02/12 23:13:20
add {} for "if" unless both condition and body fit
mcasas
2014/02/14 11:28:39
Done.
|
| + pixelFormat = AndroidImageFormatList.ANDROID_IMAGEFORMAT_YV12; |
| + else if (previewFormat == ImageFormat.NV21) |
| + pixelFormat = AndroidImageFormatList.ANDROID_IMAGEFORMAT_NV21; |
|
wjia(left Chromium)
2014/02/12 23:13:20
Any reason to expose NV21 format? We always pass I
mcasas
2014/02/14 11:28:39
CaptureFormats contains the camera supported data
wjia(left Chromium)
2014/02/14 18:33:00
Sounds like adding NV21 is for possible "future" d
|
| + else |
| + pixelFormat = AndroidImageFormatList.ANDROID_IMAGEFORMAT_UNKNOWN; |
| + |
| + List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); |
|
wjia(left Chromium)
2014/02/12 23:13:20
sanity check.
mcasas
2014/02/14 11:28:39
Done.
|
| + for (int[] fpsRange : listFpsRange) { |
| + List<Camera.Size> supportedSizes = |
| + parameters.getSupportedPreviewSizes(); |
| + for (Camera.Size size : supportedSizes) { |
| + formatList.add(new CaptureFormat(size.width, size.height, |
| + (fpsRange[0] + 999 ) / 1000, pixelFormat)); |
| + } |
| + } |
| + } |
|
wjia(left Chromium)
2014/02/12 23:13:20
Are you sure all combined results are supported?
mcasas
2014/02/14 11:28:39
Indeed. The TestingCam App allows to experiment wi
|
| + camera.release(); |
| + return formatList.toArray(new CaptureFormat[formatList.size()]); |
| + } |
| + |
| public VideoCapture( |
| Context context, int id, long nativeVideoCaptureDeviceAndroid) { |
| mContext = context; |
| @@ -136,7 +197,7 @@ public class VideoCapture implements PreviewCallback { |
| try { |
| mCamera = Camera.open(mId); |
| } catch (RuntimeException ex) { |
| - Log.e(TAG, "allocate:Camera.open: " + ex); |
| + Log.e(TAG, "allocate: Camera.open: " + ex); |
| return false; |
| } |
| @@ -150,25 +211,16 @@ public class VideoCapture implements PreviewCallback { |
| Camera.Parameters parameters = mCamera.getParameters(); |
| - // Calculate fps. |
| + // Calculate fps. getSupportedPreviewFpsRange() returns a List with at |
| + // least one element. |
| List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); |
|
wjia(left Chromium)
2014/02/12 23:13:20
The sanity check shouldn't be removed. Refer to ht
mcasas
2014/02/14 11:28:39
Done. Added some comment about why the sanity chec
|
| - if (listFpsRange == null || listFpsRange.size() == 0) { |
| - Log.e(TAG, "allocate: no fps range found"); |
| - return false; |
| - } |
| int frameRateInMs = frameRate * 1000; |
| - Iterator itFpsRange = listFpsRange.iterator(); |
| - int[] fpsRange = (int[]) itFpsRange.next(); |
| // Use the first range as default. |
| - int fpsMin = fpsRange[0]; |
| - int fpsMax = fpsRange[1]; |
| - int newFrameRate = (fpsMin + 999) / 1000; |
| - while (itFpsRange.hasNext()) { |
| - fpsRange = (int[]) itFpsRange.next(); |
| - if (fpsRange[0] <= frameRateInMs && |
| - frameRateInMs <= fpsRange[1]) { |
| - fpsMin = fpsRange[0]; |
| - fpsMax = fpsRange[1]; |
| + 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; |
| } |
| @@ -176,21 +228,16 @@ public class VideoCapture implements PreviewCallback { |
| frameRate = newFrameRate; |
| Log.d(TAG, "allocate: fps set to " + frameRate); |
| - mCurrentCapability = new CaptureCapability(); |
| - mCurrentCapability.mDesiredFps = frameRate; |
| - |
| // Calculate size. |
| List<Camera.Size> listCameraSize = |
| parameters.getSupportedPreviewSizes(); |
| int minDiff = Integer.MAX_VALUE; |
| int matchedWidth = width; |
| int matchedHeight = height; |
| - Iterator itCameraSize = listCameraSize.iterator(); |
| - while (itCameraSize.hasNext()) { |
| - Camera.Size size = (Camera.Size) itCameraSize.next(); |
| + for (Camera.Size size : listCameraSize) { |
| int diff = Math.abs(size.width - width) + |
| Math.abs(size.height - height); |
| - Log.d(TAG, "allocate: support resolution (" + |
| + Log.d(TAG, "allocate: supported (" + |
| size.width + ", " + size.height + "), diff=" + diff); |
| // TODO(wjia): Remove this hack (forcing width to be multiple |
| // of 32) by supporting stride in video frame buffer. |
| @@ -206,16 +253,15 @@ public class VideoCapture implements PreviewCallback { |
| Log.e(TAG, "allocate: can not find a multiple-of-32 resolution"); |
| return false; |
| } |
| - mCurrentCapability.mWidth = matchedWidth; |
| - mCurrentCapability.mHeight = matchedHeight; |
| + |
| + mCaptureFormat = new CaptureFormat( |
| + matchedWidth, matchedHeight, frameRate, |
| + BuggyDeviceHack.getImageFormat()); |
| // Hack to avoid certain capture resolutions under a minimum one, |
| // see http://crbug.com/305294 |
| - BuggyDeviceHack.applyMinDimensions(mCurrentCapability); |
| - |
| - Log.d(TAG, "allocate: matched (" + mCurrentCapability.mWidth + "x" + |
| - mCurrentCapability.mHeight + ")"); |
| - |
| - mImageFormat = BuggyDeviceHack.getImageFormat(); |
| + BuggyDeviceHack.applyMinDimensions(mCaptureFormat); |
| + Log.d(TAG, "allocate: matched (" + mCaptureFormat.mWidth + "x" + |
| + mCaptureFormat.mHeight + ")"); |
| if (parameters.isVideoStabilizationSupported()) { |
| Log.d(TAG, "Image stabilization supported, currently: " |
| @@ -224,11 +270,10 @@ public class VideoCapture implements PreviewCallback { |
| } else { |
| Log.d(TAG, "Image stabilization not supported."); |
| } |
| - |
| - parameters.setPreviewSize(mCurrentCapability.mWidth, |
| - mCurrentCapability.mHeight); |
| - parameters.setPreviewFormat(mImageFormat); |
| - parameters.setPreviewFpsRange(fpsMin, fpsMax); |
| + parameters.setPreviewSize(mCaptureFormat.mWidth, |
| + mCaptureFormat.mHeight); |
| + parameters.setPreviewFormat(mCaptureFormat.mPixelFormat); |
| + parameters.setPreviewFpsRange(fpsMinMax[0], fpsMinMax[1]); |
| mCamera.setParameters(parameters); |
| // Set SurfaceTexture. Android Capture needs a SurfaceTexture even if |
| @@ -258,9 +303,10 @@ public class VideoCapture implements PreviewCallback { |
| return false; |
| } |
| - int bufSize = mCurrentCapability.mWidth * |
| - mCurrentCapability.mHeight * |
| - ImageFormat.getBitsPerPixel(mImageFormat) / 8; |
| + int bufSize = mCaptureFormat.mWidth * |
| + mCaptureFormat.mHeight * |
| + ImageFormat.getBitsPerPixel( |
| + mCaptureFormat.mPixelFormat) / 8; |
| for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) { |
| byte[] buffer = new byte[bufSize]; |
| mCamera.addCallbackBuffer(buffer); |
| @@ -272,22 +318,22 @@ public class VideoCapture implements PreviewCallback { |
| @CalledByNative |
| public int queryWidth() { |
| - return mCurrentCapability.mWidth; |
| + return mCaptureFormat.mWidth; |
| } |
| @CalledByNative |
| public int queryHeight() { |
| - return mCurrentCapability.mHeight; |
| + return mCaptureFormat.mHeight; |
| } |
| @CalledByNative |
| public int queryFrameRate() { |
| - return mCurrentCapability.mDesiredFps; |
| + return mCaptureFormat.mFramerate; |
| } |
| @CalledByNative |
| public int getColorspace() { |
| - switch (mImageFormat) { |
| + switch (mCaptureFormat.mPixelFormat) { |
| case ImageFormat.YV12: |
| return AndroidImageFormatList.ANDROID_IMAGEFORMAT_YV12; |
| case ImageFormat.NV21: |
| @@ -351,7 +397,7 @@ public class VideoCapture implements PreviewCallback { |
| mCamera.setPreviewTexture(null); |
| if (mGlTextures != null) |
| GLES20.glDeleteTextures(1, mGlTextures, 0); |
| - mCurrentCapability = null; |
| + mCaptureFormat = null; |
| mCamera.release(); |
| mCamera = null; |
| } catch (IOException ex) { |