1e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// found in the LICENSE file. 4e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochpackage org.chromium.media; 6e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 7e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport android.content.Context; 8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport android.graphics.ImageFormat; 9e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport android.util.Log; 10e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 11e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport java.util.ArrayList; 12e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport java.util.List; 13e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch/** 15e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * This class extends the VideoCapture base class for manipulating normal video 16e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * capture devices in Android, including receiving copies of preview frames via 17e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * Java-allocated buffers. It also includes class BuggyDeviceHack to deal with 18e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch * troublesome devices. 19e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch **/ 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci@SuppressWarnings("deprecation") 21e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochpublic class VideoCaptureAndroid extends VideoCapture { 22e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 23e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Some devices don't support YV12 format correctly, even with JELLY_BEAN or 24e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // newer OS. To work around the issues on those devices, we have to request 25e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // NV21. Some other devices have troubles with certain capture resolutions 26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // under a given one: for those, the resolution is swapped with a known 27e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // good. Both are supposed to be temporary hacks. 28e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private static class BuggyDeviceHack { 29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private static class IdAndSizes { 30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch IdAndSizes(String model, String device, int minWidth, int minHeight) { 31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mModel = model; 32e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mDevice = device; 33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mMinWidth = minWidth; 34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mMinHeight = minHeight; 35e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 36e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch public final String mModel; 37e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch public final String mDevice; 38e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch public final int mMinWidth; 39e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch public final int mMinHeight; 40e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 41e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private static final IdAndSizes CAPTURESIZE_BUGGY_DEVICE_LIST[] = { 43e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch new IdAndSizes("Nexus 7", "flo", 640, 480) 44e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch }; 45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) private static final String[] COLORSPACE_BUGGY_DEVICE_LIST = { 47e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch "SAMSUNG-SGH-I747", 48e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch "ODROID-U2", 49e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch }; 50e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 51e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch static void applyMinDimensions(CaptureFormat format) { 52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // NOTE: this can discard requested aspect ratio considerations. 536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (IdAndSizes buggyDevice : CAPTURESIZE_BUGGY_DEVICE_LIST) { 54e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (buggyDevice.mModel.contentEquals(android.os.Build.MODEL) && 55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch buggyDevice.mDevice.contentEquals(android.os.Build.DEVICE)) { 56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch format.mWidth = (buggyDevice.mMinWidth > format.mWidth) 57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ? buggyDevice.mMinWidth : format.mWidth; 58e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch format.mHeight = (buggyDevice.mMinHeight > format.mHeight) 59e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ? buggyDevice.mMinHeight : format.mHeight; 60e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 61e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 62e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 63e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 64e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch static int getImageFormat() { 65e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) { 66e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ImageFormat.NV21; 67e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 68e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (String buggyDevice : COLORSPACE_BUGGY_DEVICE_LIST) { 70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (buggyDevice.contentEquals(android.os.Build.MODEL)) { 71e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ImageFormat.NV21; 72e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 73e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 74e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ImageFormat.YV12; 75e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 76e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private int mExpectedFrameSize; 79e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private static final int NUM_CAPTURE_BUFFERS = 3; 80e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch private static final String TAG = "VideoCaptureAndroid"; 81e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 82e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch static CaptureFormat[] getDeviceSupportedFormats(int id) { 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci android.hardware.Camera camera; 84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch try { 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci camera = android.hardware.Camera.open(id); 86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } catch (RuntimeException ex) { 87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch Log.e(TAG, "Camera.open: " + ex); 88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return null; 89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci android.hardware.Camera.Parameters parameters = getCameraParameters(camera); 91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (parameters == null) { 92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return null; 93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>(); 96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // getSupportedPreview{Formats,FpsRange,PreviewSizes}() returns Lists 97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // with at least one element, but when the camera is in bad state, they 98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // can return null pointers; in that case we use a 0 entry, so we can 99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // retrieve as much information as possible. 100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch List<Integer> pixelFormats = parameters.getSupportedPreviewFormats(); 101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (pixelFormats == null) { 102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch pixelFormats = new ArrayList<Integer>(); 103e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 104e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (pixelFormats.size() == 0) { 105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch pixelFormats.add(ImageFormat.UNKNOWN); 106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch for (Integer previewFormat : pixelFormats) { 108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int pixelFormat = 109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch AndroidImageFormatList.ANDROID_IMAGEFORMAT_UNKNOWN; 110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (previewFormat == ImageFormat.YV12) { 111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch pixelFormat = AndroidImageFormatList.ANDROID_IMAGEFORMAT_YV12; 112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } else if (previewFormat == ImageFormat.NV21) { 113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch continue; 114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange(); 117e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (listFpsRange == null) { 118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch listFpsRange = new ArrayList<int[]>(); 119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (listFpsRange.size() == 0) { 121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch listFpsRange.add(new int[] {0, 0}); 122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch for (int[] fpsRange : listFpsRange) { 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci List<android.hardware.Camera.Size> supportedSizes = 125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch parameters.getSupportedPreviewSizes(); 126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (supportedSizes == null) { 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci supportedSizes = new ArrayList<android.hardware.Camera.Size>(); 128e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 129e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (supportedSizes.size() == 0) { 130e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch supportedSizes.add(camera.new Size(0, 0)); 131e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (android.hardware.Camera.Size size : supportedSizes) { 133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch formatList.add(new CaptureFormat(size.width, 134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch size.height, 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch (fpsRange[1] + 999) / 1000, 136e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch pixelFormat)); 137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch camera.release(); 141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return formatList.toArray(new CaptureFormat[formatList.size()]); 142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch VideoCaptureAndroid(Context context, 145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int id, 146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch long nativeVideoCaptureDeviceAndroid) { 147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch super(context, id, nativeVideoCaptureDeviceAndroid); 148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch @Override 151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch protected void setCaptureParameters( 152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int width, 153e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int height, 154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int frameRate, 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci android.hardware.Camera.Parameters cameraParameters) { 156e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mCaptureFormat = new CaptureFormat( 157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch width, height, frameRate, BuggyDeviceHack.getImageFormat()); 158e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Hack to avoid certain capture resolutions under a minimum one, 159e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // see http://crbug.com/305294. 160e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch BuggyDeviceHack.applyMinDimensions(mCaptureFormat); 161e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch @Override 164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch protected void allocateBuffers() { 165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mExpectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight * 166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ImageFormat.getBitsPerPixel(mCaptureFormat.mPixelFormat) / 8; 167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) { 168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch byte[] buffer = new byte[mExpectedFrameSize]; 169e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mCamera.addCallbackBuffer(buffer); 170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 171e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch @Override 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci protected void setPreviewCallback(android.hardware.Camera.PreviewCallback cb) { 175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mCamera.setPreviewCallbackWithBuffer(cb); 176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch @Override 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { 180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mPreviewBufferLock.lock(); 181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch try { 182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (!mIsRunning) { 183e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return; 184e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 185e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (data.length == mExpectedFrameSize) { 186e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch int rotation = getDeviceOrientation(); 187e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (rotation != mDeviceOrientation) { 188e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mDeviceOrientation = rotation; 189e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mCameraFacing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) { 191e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch rotation = 360 - rotation; 192e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 193e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch rotation = (mCameraOrientation + rotation) % 360; 194e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, 195e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch data, mExpectedFrameSize, rotation); 196e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 197e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } finally { 198e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch mPreviewBufferLock.unlock(); 199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (camera != null) { 200e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch camera.addCallbackBuffer(data); 201e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 202e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch } 204e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 205e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // TODO(wjia): investigate whether reading from texture could give better 206e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // performance and frame rate, using onFrameAvailable(). 207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 208