Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / base / android / java / src / org / chromium / media / VideoCaptureAndroid.java
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
3 // found in the LICENSE file.
4
5 package org.chromium.media;
6
7 import android.content.Context;
8 import android.graphics.ImageFormat;
9 import android.util.Log;
10
11 import java.util.ArrayList;
12 import java.util.List;
13
14 /**
15  * This class extends the VideoCaptureCamera base class for manipulating normal
16  * video capture devices in Android, including receiving copies of preview
17  * frames via Java-allocated buffers. It also includes class BuggyDeviceHack to
18  * deal with troublesome devices.
19  **/
20 @SuppressWarnings("deprecation")
21 public class VideoCaptureAndroid extends VideoCaptureCamera {
22
23     // Some devices don't support YV12 format correctly, even with JELLY_BEAN or
24     // newer OS. To work around the issues on those devices, we have to request
25     // NV21. This is supposed to be a temporary hack.
26     private static class BuggyDeviceHack {
27         private static final String[] COLORSPACE_BUGGY_DEVICE_LIST = {
28             "SAMSUNG-SGH-I747",
29             "ODROID-U2",
30         };
31
32         static int getImageFormat() {
33             if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
34                 return ImageFormat.NV21;
35             }
36
37             for (String buggyDevice : COLORSPACE_BUGGY_DEVICE_LIST) {
38                 if (buggyDevice.contentEquals(android.os.Build.MODEL)) {
39                     return ImageFormat.NV21;
40                 }
41             }
42             return ImageFormat.YV12;
43         }
44     }
45
46     private int mExpectedFrameSize;
47     private static final int NUM_CAPTURE_BUFFERS = 3;
48     private static final String TAG = "VideoCaptureAndroid";
49
50     static int getNumberOfCameras() {
51         return android.hardware.Camera.getNumberOfCameras();
52     }
53
54     static String getName(int id) {
55         android.hardware.Camera.CameraInfo cameraInfo = VideoCaptureCamera.getCameraInfo(id);
56         if (cameraInfo == null) return null;
57         return "camera " + id + ", facing " + (cameraInfo.facing
58                 == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT ? "front" : "back");
59     }
60
61     static CaptureFormat[] getDeviceSupportedFormats(int id) {
62         android.hardware.Camera camera;
63         try {
64             camera = android.hardware.Camera.open(id);
65         } catch (RuntimeException ex) {
66             Log.e(TAG, "Camera.open: " + ex);
67             return null;
68         }
69         android.hardware.Camera.Parameters parameters = getCameraParameters(camera);
70         if (parameters == null) {
71             return null;
72         }
73
74         ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
75         // getSupportedPreview{Formats,FpsRange,PreviewSizes}() returns Lists
76         // with at least one element, but when the camera is in bad state, they
77         // can return null pointers; in that case we use a 0 entry, so we can
78         // retrieve as much information as possible.
79         List<Integer> pixelFormats = parameters.getSupportedPreviewFormats();
80         if (pixelFormats == null) {
81             pixelFormats = new ArrayList<Integer>();
82         }
83         if (pixelFormats.size() == 0) {
84             pixelFormats.add(ImageFormat.UNKNOWN);
85         }
86         for (Integer previewFormat : pixelFormats) {
87             int pixelFormat = AndroidImageFormat.UNKNOWN;
88             if (previewFormat == ImageFormat.YV12) {
89                 pixelFormat = AndroidImageFormat.YV12;
90             } else if (previewFormat == ImageFormat.NV21) {
91                 continue;
92             }
93
94             List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
95             if (listFpsRange == null) {
96                 listFpsRange = new ArrayList<int[]>();
97             }
98             if (listFpsRange.size() == 0) {
99                 listFpsRange.add(new int[] {0, 0});
100             }
101             for (int[] fpsRange : listFpsRange) {
102                 List<android.hardware.Camera.Size> supportedSizes =
103                         parameters.getSupportedPreviewSizes();
104                 if (supportedSizes == null) {
105                     supportedSizes = new ArrayList<android.hardware.Camera.Size>();
106                 }
107                 if (supportedSizes.size() == 0) {
108                     supportedSizes.add(camera.new Size(0, 0));
109                 }
110                 for (android.hardware.Camera.Size size : supportedSizes) {
111                     formatList.add(new CaptureFormat(size.width,
112                                                      size.height,
113                                                      (fpsRange[1] + 999) / 1000,
114                                                      pixelFormat));
115                 }
116             }
117         }
118         camera.release();
119         return formatList.toArray(new CaptureFormat[formatList.size()]);
120     }
121
122     VideoCaptureAndroid(Context context,
123                         int id,
124                         long nativeVideoCaptureDeviceAndroid) {
125         super(context, id, nativeVideoCaptureDeviceAndroid);
126     }
127
128     @Override
129     protected void setCaptureParameters(
130             int width,
131             int height,
132             int frameRate,
133             android.hardware.Camera.Parameters cameraParameters) {
134         mCaptureFormat = new CaptureFormat(
135                 width, height, frameRate, BuggyDeviceHack.getImageFormat());
136     }
137
138     @Override
139     protected void allocateBuffers() {
140         mExpectedFrameSize = mCaptureFormat.mWidth * mCaptureFormat.mHeight
141                 * ImageFormat.getBitsPerPixel(mCaptureFormat.mPixelFormat) / 8;
142         for (int i = 0; i < NUM_CAPTURE_BUFFERS; i++) {
143             byte[] buffer = new byte[mExpectedFrameSize];
144             mCamera.addCallbackBuffer(buffer);
145         }
146     }
147
148     @Override
149     protected void setPreviewCallback(android.hardware.Camera.PreviewCallback cb) {
150         mCamera.setPreviewCallbackWithBuffer(cb);
151     }
152
153     @Override
154     public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
155         mPreviewBufferLock.lock();
156         try {
157             if (!mIsRunning) {
158                 return;
159             }
160             if (data.length == mExpectedFrameSize) {
161                 int rotation = getDeviceOrientation();
162                 if (rotation != mDeviceOrientation) {
163                     mDeviceOrientation = rotation;
164                 }
165                 if (mCameraFacing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
166                     rotation = 360 - rotation;
167                 }
168                 rotation = (mCameraOrientation + rotation) % 360;
169                 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid,
170                         data, mExpectedFrameSize, rotation);
171             }
172         } finally {
173             mPreviewBufferLock.unlock();
174             if (camera != null) {
175                 camera.addCallbackBuffer(data);
176             }
177         }
178     }
179
180     // TODO(wjia): investigate whether reading from texture could give better
181     // performance and frame rate, using onFrameAvailable().
182 }