Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / base / android / java / src / org / chromium / media / VideoCaptureTango.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.nio.ByteBuffer;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14
15 /**
16  * This class extends the VideoCapture base class for manipulating a Tango
17  * device's cameras, namely the associated Depth (z-Buffer), Fisheye and back-
18  * facing 4MP video capture devices. These devices are differentiated via the
19  * |id| passed on constructor, according to the index correspondence in
20  * |s_CAM_PARAMS|; all devices |id| are index 0 towards the parent VideoCapture.
21  **/
22 @SuppressWarnings("deprecation")
23 public class VideoCaptureTango extends VideoCapture {
24     private ByteBuffer mFrameBuffer = null;
25     private final int mTangoCameraId;
26     // The indexes must coincide with the s_CAM_PARAMS used below.
27     private static final int DEPTH_CAMERA_ID = 0;
28     private static final int FISHEYE_CAMERA_ID = 1;
29     private static final int FOURMP_CAMERA_ID = 2;
30     private static final VideoCaptureFactory.CamParams CAM_PARAMS[] = {
31          new VideoCaptureFactory.CamParams(DEPTH_CAMERA_ID, "depth", 320, 240),
32          new VideoCaptureFactory.CamParams(FISHEYE_CAMERA_ID, "fisheye", 640, 480),
33          new VideoCaptureFactory.CamParams(FOURMP_CAMERA_ID, "4MP", 1280, 720)};
34
35     // SuperFrame size definitions. Note that total size is the amount of lines
36     // multiplied by 3/2 due to Chroma components following.
37     private static final int SF_WIDTH = 1280;
38     private static final int SF_HEIGHT = 1168;
39     private static final int SF_FULL_HEIGHT = SF_HEIGHT * 3 / 2;
40     private static final int SF_LINES_HEADER = 16;
41     private static final int SF_LINES_FISHEYE = 240;
42     private static final int SF_LINES_RESERVED = 80;  // Spec says 96.
43     private static final int SF_LINES_DEPTH = 60;
44     private static final int SF_LINES_DEPTH_PADDED = 112;  // Spec says 96.
45     private static final int SF_LINES_BIGIMAGE = 720;
46     private static final int SF_OFFSET_4MP_CHROMA = 112;
47
48     private static final byte CHROMA_ZERO_LEVEL = 127;
49     private static final String TAG = "VideoCaptureTango";
50
51     static int numberOfCameras() {
52         return CAM_PARAMS.length;
53     }
54
55     static VideoCaptureFactory.CamParams getCamParams(int index) {
56         if (index >= CAM_PARAMS.length) return null;
57         return CAM_PARAMS[index];
58     }
59
60     static CaptureFormat[] getDeviceSupportedFormats(int id) {
61       ArrayList<CaptureFormat> formatList = new ArrayList<CaptureFormat>();
62       if (id == DEPTH_CAMERA_ID) {
63           formatList.add(new CaptureFormat(320, 180, 5, ImageFormat.YV12));
64       } else if (id == FISHEYE_CAMERA_ID) {
65           formatList.add(new CaptureFormat(640, 480, 30, ImageFormat.YV12));
66       } else if (id == FOURMP_CAMERA_ID) {
67           formatList.add(new CaptureFormat(1280, 720, 20, ImageFormat.YV12));
68       }
69       return formatList.toArray(new CaptureFormat[formatList.size()]);
70     }
71
72     VideoCaptureTango(Context context, int id, long nativeVideoCaptureDeviceAndroid) {
73         // All Tango cameras are like the back facing one for the generic VideoCapture code.
74         super(context, 0, nativeVideoCaptureDeviceAndroid);
75         mTangoCameraId = id;
76     }
77
78     @Override
79     protected void setCaptureParameters(int width, int height, int frameRate,
80             android.hardware.Camera.Parameters cameraParameters) {
81         mCaptureFormat = new CaptureFormat(CAM_PARAMS[mTangoCameraId].mWidth,
82                                            CAM_PARAMS[mTangoCameraId].mHeight,
83                                            frameRate,
84                                            ImageFormat.YV12);
85         // Connect Tango SuperFrame mode. Available sf modes are "all",
86         // "big-rgb", "small-rgb", "depth", "ir".
87         cameraParameters.set("sf-mode", "all");
88     }
89
90     @Override
91     protected void allocateBuffers() {
92         mFrameBuffer = ByteBuffer.allocateDirect(
93                 mCaptureFormat.mWidth * mCaptureFormat.mHeight * 3 / 2);
94         // Prefill Chroma to their zero-equivalent for the cameras that only
95         // provide Luma component.
96         Arrays.fill(mFrameBuffer.array(), CHROMA_ZERO_LEVEL);
97     }
98
99     @Override
100     protected void setPreviewCallback(android.hardware.Camera.PreviewCallback cb) {
101         mCamera.setPreviewCallback(cb);
102     }
103
104     @Override
105     public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
106         mPreviewBufferLock.lock();
107         try {
108             if (!mIsRunning) return;
109
110             if (data.length == SF_WIDTH * SF_FULL_HEIGHT) {
111                 int rotation = getDeviceOrientation();
112                 if (rotation != mDeviceOrientation) {
113                     mDeviceOrientation = rotation;
114                 }
115                 if (mCameraFacing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
116                     rotation = 360 - rotation;
117                 }
118                 rotation = (mCameraOrientation + rotation) % 360;
119
120                 if (mTangoCameraId == DEPTH_CAMERA_ID) {
121                     int sizeY = SF_WIDTH * SF_LINES_DEPTH;
122                     int startY =
123                             SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE + SF_LINES_RESERVED);
124                     // Depth is composed of 16b samples in which only 12b are
125                     // used. Throw away lowest 4 resolution bits. Android
126                     // platforms are big endian, LSB in lowest address. In this
127                     // case Chroma components are unused. No need to write them
128                     // explicitly since they're filled to 128 on creation.
129                     byte depthsample;
130                     for (int j = startY; j < startY + 2 * sizeY; j += 2) {
131                         depthsample = (byte) ((data[j + 1] << 4) | ((data[j] & 0xF0) >> 4));
132                         mFrameBuffer.put(depthsample);
133                     }
134                     for (int j = 0; j < mCaptureFormat.mWidth * mCaptureFormat.mHeight - sizeY;
135                             ++j) {
136                         mFrameBuffer.put((byte) 0);
137                     }
138                 } else if (mTangoCameraId == FISHEYE_CAMERA_ID) {
139                     int sizeY = SF_WIDTH * SF_LINES_FISHEYE;
140                     int startY = SF_WIDTH * SF_LINES_HEADER;
141                     // Fisheye is black and white so Chroma components are unused. No need to write
142                     // them explicitly since they're filled to 128 on creation.
143                     ByteBuffer.wrap(data, startY, sizeY).get(mFrameBuffer.array(), 0, sizeY);
144                 } else if (mTangoCameraId == FOURMP_CAMERA_ID) {
145                     int startY = SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE +
146                                     SF_LINES_RESERVED + SF_LINES_DEPTH_PADDED);
147                     int sizeY = SF_WIDTH * SF_LINES_BIGIMAGE;
148
149                     // The spec is completely inaccurate on the location, sizes
150                     // and format of these channels.
151                     int startU = SF_WIDTH * (SF_HEIGHT + SF_OFFSET_4MP_CHROMA);
152                     int sizeU = SF_WIDTH * SF_LINES_BIGIMAGE / 4;
153                     int startV = (SF_WIDTH * SF_HEIGHT * 5 / 4) + SF_WIDTH * SF_OFFSET_4MP_CHROMA;
154                     int sizeV = SF_WIDTH * SF_LINES_BIGIMAGE / 4;
155
156                     // Equivalent to the following |for| loop but much faster:
157                     // for (int i = START; i < START + SIZE; ++i)
158                     //     mFrameBuffer.put(data[i]);
159                     ByteBuffer.wrap(data, startY, sizeY)
160                               .get(mFrameBuffer.array(), 0, sizeY);
161                     ByteBuffer.wrap(data, startU, sizeU)
162                               .get(mFrameBuffer.array(), sizeY, sizeU);
163                     ByteBuffer.wrap(data, startV, sizeV)
164                               .get(mFrameBuffer.array(), sizeY + sizeU, sizeV);
165                 } else {
166                     Log.e(TAG, "Unknown camera, #id: " + mTangoCameraId);
167                     return;
168                 }
169                 mFrameBuffer.rewind();  // Important!
170                 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, mFrameBuffer.array(),
171                         mFrameBuffer.capacity(), rotation);
172             }
173         } finally {
174             mPreviewBufferLock.unlock();
175         }
176     }
177 }