| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.media; | 5 package org.chromium.media; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.graphics.ImageFormat; | 8 import android.graphics.ImageFormat; |
| 9 | 9 |
| 10 import org.chromium.base.Log; | 10 import org.chromium.base.Log; |
| 11 | 11 |
| 12 import java.util.ArrayList; | 12 import java.util.ArrayList; |
| 13 import java.util.List; | 13 import java.util.List; |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * This class extends the VideoCaptureCamera base class for manipulating normal | 16 * This class extends the VideoCaptureCamera base class for manipulating normal |
| 17 * video capture devices in Android, including receiving copies of preview | 17 * video capture devices in Android, including receiving copies of preview |
| 18 * frames via Java-allocated buffers. It also includes class BuggyDeviceHack to | 18 * frames via Java-allocated buffers. It also includes class BuggyDeviceHack to |
| 19 * deal with troublesome devices. | 19 * deal with troublesome devices. |
| 20 **/ | 20 **/ |
| 21 @SuppressWarnings("deprecation") | 21 @SuppressWarnings("deprecation") |
| 22 public class VideoCaptureAndroid extends VideoCaptureCamera { | 22 public class VideoCaptureAndroid extends VideoCaptureCamera { |
| 23 | |
| 24 // Some devices don't support YV12 format correctly, even with JELLY_BEAN or | 23 // Some devices don't support YV12 format correctly, even with JELLY_BEAN or |
| 25 // newer OS. To work around the issues on those devices, we have to request | 24 // newer OS. To work around the issues on those devices, we have to request |
| 26 // NV21. This is supposed to be a temporary hack. | 25 // NV21. This is supposed to be a temporary hack. |
| 27 private static class BuggyDeviceHack { | 26 private static class BuggyDeviceHack { |
| 28 private static final String[] COLORSPACE_BUGGY_DEVICE_LIST = { | 27 private static final String[] COLORSPACE_BUGGY_DEVICE_LIST = { |
| 29 "SAMSUNG-SGH-I747", | 28 "SAMSUNG-SGH-I747", "ODROID-U2", |
| 30 "ODROID-U2", | 29 // See https://crbug.com/577435 for more info. |
| 31 // See https://crbug.com/577435 for more info. | 30 "XT1092", "XT1095", "XT1096", |
| 32 "XT1092", | |
| 33 "XT1095", | |
| 34 "XT1096", | |
| 35 }; | 31 }; |
| 36 | 32 |
| 37 static int getImageFormat() { | 33 static int getImageFormat() { |
| 38 for (String buggyDevice : COLORSPACE_BUGGY_DEVICE_LIST) { | 34 for (String buggyDevice : COLORSPACE_BUGGY_DEVICE_LIST) { |
| 39 if (buggyDevice.contentEquals(android.os.Build.MODEL)) { | 35 if (buggyDevice.contentEquals(android.os.Build.MODEL)) { |
| 40 return ImageFormat.NV21; | 36 return ImageFormat.NV21; |
| 41 } | 37 } |
| 42 } | 38 } |
| 43 return ImageFormat.YV12; | 39 return ImageFormat.YV12; |
| 44 } | 40 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 56 if (VideoCaptureCamera.getCameraInfo(id) == null) { | 52 if (VideoCaptureCamera.getCameraInfo(id) == null) { |
| 57 return CaptureApiType.API_TYPE_UNKNOWN; | 53 return CaptureApiType.API_TYPE_UNKNOWN; |
| 58 } | 54 } |
| 59 return CaptureApiType.API1; | 55 return CaptureApiType.API1; |
| 60 } | 56 } |
| 61 | 57 |
| 62 static String getName(int id) { | 58 static String getName(int id) { |
| 63 android.hardware.Camera.CameraInfo cameraInfo = VideoCaptureCamera.getCa
meraInfo(id); | 59 android.hardware.Camera.CameraInfo cameraInfo = VideoCaptureCamera.getCa
meraInfo(id); |
| 64 if (cameraInfo == null) return null; | 60 if (cameraInfo == null) return null; |
| 65 | 61 |
| 66 return "camera " + id + ", facing " + (cameraInfo.facing | 62 return "camera " + id + ", facing " |
| 67 == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? "fro
nt" : "back"); | 63 + (cameraInfo.facing == android.hardware.Camera.CameraInfo.CAMER
A_FACING_FRONT |
| 64 ? "front" |
| 65 : "back"); |
| 68 } | 66 } |
| 69 | 67 |
| 70 static VideoCaptureFormat[] getDeviceSupportedFormats(int id) { | 68 static VideoCaptureFormat[] getDeviceSupportedFormats(int id) { |
| 71 android.hardware.Camera camera; | 69 android.hardware.Camera camera; |
| 72 try { | 70 try { |
| 73 camera = android.hardware.Camera.open(id); | 71 camera = android.hardware.Camera.open(id); |
| 74 } catch (RuntimeException ex) { | 72 } catch (RuntimeException ex) { |
| 75 Log.e(TAG, "Camera.open: ", ex); | 73 Log.e(TAG, "Camera.open: ", ex); |
| 76 return null; | 74 return null; |
| 77 } | 75 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 for (int[] fpsRange : listFpsRange) { | 108 for (int[] fpsRange : listFpsRange) { |
| 111 List<android.hardware.Camera.Size> supportedSizes = | 109 List<android.hardware.Camera.Size> supportedSizes = |
| 112 parameters.getSupportedPreviewSizes(); | 110 parameters.getSupportedPreviewSizes(); |
| 113 if (supportedSizes == null) { | 111 if (supportedSizes == null) { |
| 114 supportedSizes = new ArrayList<android.hardware.Camera.Size>
(); | 112 supportedSizes = new ArrayList<android.hardware.Camera.Size>
(); |
| 115 } | 113 } |
| 116 if (supportedSizes.size() == 0) { | 114 if (supportedSizes.size() == 0) { |
| 117 supportedSizes.add(camera.new Size(0, 0)); | 115 supportedSizes.add(camera.new Size(0, 0)); |
| 118 } | 116 } |
| 119 for (android.hardware.Camera.Size size : supportedSizes) { | 117 for (android.hardware.Camera.Size size : supportedSizes) { |
| 120 formatList.add(new VideoCaptureFormat(size.width, | 118 formatList.add(new VideoCaptureFormat( |
| 121 size.height, | 119 size.width, size.height, (fpsRange[1] + 999) / 1000,
pixelFormat)); |
| 122 (fpsRange[1] + 999) / 1000, | |
| 123 pixelFormat)); | |
| 124 } | 120 } |
| 125 } | 121 } |
| 126 } | 122 } |
| 127 camera.release(); | 123 camera.release(); |
| 128 return formatList.toArray(new VideoCaptureFormat[formatList.size()]); | 124 return formatList.toArray(new VideoCaptureFormat[formatList.size()]); |
| 129 } | 125 } |
| 130 | 126 |
| 131 VideoCaptureAndroid(Context context, | 127 VideoCaptureAndroid(Context context, int id, long nativeVideoCaptureDeviceAn
droid) { |
| 132 int id, | |
| 133 long nativeVideoCaptureDeviceAndroid) { | |
| 134 super(context, id, nativeVideoCaptureDeviceAndroid); | 128 super(context, id, nativeVideoCaptureDeviceAndroid); |
| 135 } | 129 } |
| 136 | 130 |
| 137 @Override | 131 @Override |
| 138 protected void setCaptureParameters( | 132 protected void setCaptureParameters(int width, int height, int frameRate, |
| 139 int width, | |
| 140 int height, | |
| 141 int frameRate, | |
| 142 android.hardware.Camera.Parameters cameraParameters) { | 133 android.hardware.Camera.Parameters cameraParameters) { |
| 143 mCaptureFormat = new VideoCaptureFormat( | 134 mCaptureFormat = |
| 144 width, height, frameRate, BuggyDeviceHack.getImageFormat()); | 135 new VideoCaptureFormat(width, height, frameRate, BuggyDeviceHack
.getImageFormat()); |
| 145 } | 136 } |
| 146 | 137 |
| 147 @Override | 138 @Override |
| 148 protected void allocateBuffers() { | 139 protected void allocateBuffers() { |
| 149 mExpectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight | 140 mExpectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight |
| 150 * ImageFormat.getBitsPerPixel(mCaptureFormat.mPixelFormat) / 8; | 141 * ImageFormat.getBitsPerPixel(mCaptureFormat.mPixelFormat) / 8; |
| 151 for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) { | 142 for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) { |
| 152 byte[] buffer = new byte[mExpectedFrameSize]; | 143 byte[] buffer = new byte[mExpectedFrameSize]; |
| 153 mCamera.addCallbackBuffer(buffer); | 144 mCamera.addCallbackBuffer(buffer); |
| 154 } | 145 } |
| 155 } | 146 } |
| 156 | 147 |
| 157 @Override | 148 @Override |
| 158 protected void setPreviewCallback(android.hardware.Camera.PreviewCallback cb
) { | 149 protected void setPreviewCallback(android.hardware.Camera.PreviewCallback cb
) { |
| 159 mCamera.setPreviewCallbackWithBuffer(cb); | 150 mCamera.setPreviewCallbackWithBuffer(cb); |
| 160 } | 151 } |
| 161 | 152 |
| 162 @Override | 153 @Override |
| 163 public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { | 154 public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { |
| 164 mPreviewBufferLock.lock(); | 155 mPreviewBufferLock.lock(); |
| 165 try { | 156 try { |
| 166 if (!mIsRunning) { | 157 if (!mIsRunning) { |
| 167 return; | 158 return; |
| 168 } | 159 } |
| 169 if (data.length == mExpectedFrameSize) { | 160 if (data.length == mExpectedFrameSize) { |
| 170 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, | 161 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, data, m
ExpectedFrameSize, |
| 171 data, mExpectedFrameSize, getCameraRotation()); | 162 getCameraRotation()); |
| 172 } | 163 } |
| 173 } finally { | 164 } finally { |
| 174 mPreviewBufferLock.unlock(); | 165 mPreviewBufferLock.unlock(); |
| 175 if (camera != null) { | 166 if (camera != null) { |
| 176 camera.addCallbackBuffer(data); | 167 camera.addCallbackBuffer(data); |
| 177 } | 168 } |
| 178 } | 169 } |
| 179 } | 170 } |
| 180 | 171 |
| 181 // TODO(wjia): investigate whether reading from texture could give better | 172 // TODO(wjia): investigate whether reading from texture could give better |
| 182 // performance and frame rate, using onFrameAvailable(). | 173 // performance and frame rate, using onFrameAvailable(). |
| 183 } | 174 } |
| OLD | NEW |