| 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 import android.hardware.Camera; | 9 import android.hardware.Camera; |
| 10 import android.util.Log; | 10 import android.util.Log; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 if (id == DEPTH_CAMERA_ID) { | 63 if (id == DEPTH_CAMERA_ID) { |
| 64 formatList.add(new CaptureFormat(320, 180, 5, ImageFormat.YV12)); | 64 formatList.add(new CaptureFormat(320, 180, 5, ImageFormat.YV12)); |
| 65 } else if (id == FISHEYE_CAMERA_ID) { | 65 } else if (id == FISHEYE_CAMERA_ID) { |
| 66 formatList.add(new CaptureFormat(640, 480, 30, ImageFormat.YV12)); | 66 formatList.add(new CaptureFormat(640, 480, 30, ImageFormat.YV12)); |
| 67 } else if (id == FOURMP_CAMERA_ID) { | 67 } else if (id == FOURMP_CAMERA_ID) { |
| 68 formatList.add(new CaptureFormat(1280, 720, 20, ImageFormat.YV12)); | 68 formatList.add(new CaptureFormat(1280, 720, 20, ImageFormat.YV12)); |
| 69 } | 69 } |
| 70 return formatList.toArray(new CaptureFormat[formatList.size()]); | 70 return formatList.toArray(new CaptureFormat[formatList.size()]); |
| 71 } | 71 } |
| 72 | 72 |
| 73 VideoCaptureTango(Context context, | 73 VideoCaptureTango(Context context, int id, long nativeVideoCaptureDeviceAndr
oid) { |
| 74 int id, | 74 // All Tango cameras are like the back facing one for the generic VideoC
apture code. |
| 75 long nativeVideoCaptureDeviceAndroid) { | |
| 76 // All Tango cameras are like the back facing one for the generic | |
| 77 // VideoCapture code. | |
| 78 super(context, 0, nativeVideoCaptureDeviceAndroid); | 75 super(context, 0, nativeVideoCaptureDeviceAndroid); |
| 79 mTangoCameraId = id; | 76 mTangoCameraId = id; |
| 80 } | 77 } |
| 81 | 78 |
| 82 @Override | 79 @Override |
| 83 protected void setCaptureParameters( | 80 protected void setCaptureParameters(int width, int height, int frameRate, |
| 84 int width, | |
| 85 int height, | |
| 86 int frameRate, | |
| 87 Camera.Parameters cameraParameters) { | 81 Camera.Parameters cameraParameters) { |
| 88 mCaptureFormat = new CaptureFormat(CAM_PARAMS[mTangoCameraId].mWidth, | 82 mCaptureFormat = new CaptureFormat(CAM_PARAMS[mTangoCameraId].mWidth, |
| 89 CAM_PARAMS[mTangoCameraId].mHeight, | 83 CAM_PARAMS[mTangoCameraId].mHeight, |
| 90 frameRate, | 84 frameRate, |
| 91 ImageFormat.YV12); | 85 ImageFormat.YV12); |
| 92 // Connect Tango SuperFrame mode. Available sf modes are "all", | 86 // Connect Tango SuperFrame mode. Available sf modes are "all", |
| 93 // "big-rgb", "small-rgb", "depth", "ir". | 87 // "big-rgb", "small-rgb", "depth", "ir". |
| 94 cameraParameters.set("sf-mode", "all"); | 88 cameraParameters.set("sf-mode", "all"); |
| 95 } | 89 } |
| 96 | 90 |
| 97 @Override | 91 @Override |
| 98 protected void allocateBuffers() { | 92 protected void allocateBuffers() { |
| 99 mFrameBuffer = ByteBuffer.allocateDirect( | 93 mFrameBuffer = ByteBuffer.allocateDirect( |
| 100 mCaptureFormat.mWidth * mCaptureFormat.mHeight * 3 / 2); | 94 mCaptureFormat.mWidth * mCaptureFormat.mHeight * 3 / 2); |
| 101 // Prefill Chroma to their zero-equivalent for the cameras that only | 95 // Prefill Chroma to their zero-equivalent for the cameras that only |
| 102 // provide Luma component. | 96 // provide Luma component. |
| 103 Arrays.fill(mFrameBuffer.array(), CHROMA_ZERO_LEVEL); | 97 Arrays.fill(mFrameBuffer.array(), CHROMA_ZERO_LEVEL); |
| 104 } | 98 } |
| 105 | 99 |
| 106 @Override | 100 @Override |
| 107 protected void setPreviewCallback(Camera.PreviewCallback cb) { | 101 protected void setPreviewCallback(Camera.PreviewCallback cb) { |
| 108 mCamera.setPreviewCallback(cb); | 102 mCamera.setPreviewCallback(cb); |
| 109 } | 103 } |
| 110 | 104 |
| 111 @Override | 105 @Override |
| 112 public void onPreviewFrame(byte[] data, Camera camera) { | 106 public void onPreviewFrame(byte[] data, Camera camera) { |
| 113 mPreviewBufferLock.lock(); | 107 mPreviewBufferLock.lock(); |
| 114 try { | 108 try { |
| 115 if (!mIsRunning) { | 109 if (!mIsRunning) return; |
| 116 return; | 110 |
| 117 } | |
| 118 if (data.length == SF_WIDTH * SF_FULL_HEIGHT) { | 111 if (data.length == SF_WIDTH * SF_FULL_HEIGHT) { |
| 119 int rotation = getDeviceOrientation(); | 112 int rotation = getDeviceOrientation(); |
| 120 if (rotation != mDeviceOrientation) { | 113 if (rotation != mDeviceOrientation) { |
| 121 mDeviceOrientation = rotation; | 114 mDeviceOrientation = rotation; |
| 122 } | 115 } |
| 123 if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) { | 116 if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) { |
| 124 rotation = 360 - rotation; | 117 rotation = 360 - rotation; |
| 125 } | 118 } |
| 126 rotation = (mCameraOrientation + rotation) % 360; | 119 rotation = (mCameraOrientation + rotation) % 360; |
| 127 | 120 |
| 128 if (mTangoCameraId == DEPTH_CAMERA_ID) { | 121 if (mTangoCameraId == DEPTH_CAMERA_ID) { |
| 129 int sizeY = SF_WIDTH * SF_LINES_DEPTH; | 122 int sizeY = SF_WIDTH * SF_LINES_DEPTH; |
| 130 int startY = | 123 int startY = |
| 131 SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE + | 124 SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE + SF_
LINES_RESERVED); |
| 132 SF_LINES_RESERVED); | |
| 133 // Depth is composed of 16b samples in which only 12b are | 125 // Depth is composed of 16b samples in which only 12b are |
| 134 // used. Throw away lowest 4 resolution bits. Android | 126 // used. Throw away lowest 4 resolution bits. Android |
| 135 // platforms are big endian, LSB in lowest address. In this | 127 // platforms are big endian, LSB in lowest address. In this |
| 136 // case Chroma components are unused. No need to write them | 128 // case Chroma components are unused. No need to write them |
| 137 // explicitly since they're filled to 128 on creation. | 129 // explicitly since they're filled to 128 on creation. |
| 138 byte depthsample; | 130 byte depthsample; |
| 139 for (int j = startY; j < startY + 2 * sizeY; j += 2) { | 131 for (int j = startY; j < startY + 2 * sizeY; j += 2) { |
| 140 depthsample = (byte)((data[j + 1] << 4) | | 132 depthsample = (byte) ((data[j + 1] << 4) | ((data[j] & 0
xF0) >> 4)); |
| 141 ((data[j] & 0xF0) >> 4)); | |
| 142 mFrameBuffer.put(depthsample); | 133 mFrameBuffer.put(depthsample); |
| 143 } | 134 } |
| 144 for (int j = 0; | 135 for (int j = 0; j < mCaptureFormat.mWidth * mCaptureFormat.m
Height - sizeY; |
| 145 j < mCaptureFormat.mWidth * mCaptureFormat.mHeight - | 136 ++j) { |
| 146 sizeY; | 137 mFrameBuffer.put((byte) 0); |
| 147 ++j) | 138 } |
| 148 mFrameBuffer.put((byte)0); | |
| 149 } else if (mTangoCameraId == FISHEYE_CAMERA_ID) { | 139 } else if (mTangoCameraId == FISHEYE_CAMERA_ID) { |
| 150 int sizeY = SF_WIDTH * SF_LINES_FISHEYE; | 140 int sizeY = SF_WIDTH * SF_LINES_FISHEYE; |
| 151 int startY = SF_WIDTH * SF_LINES_HEADER; | 141 int startY = SF_WIDTH * SF_LINES_HEADER; |
| 152 // Fisheye is black and white so Chroma components are | 142 // Fisheye is black and white so Chroma components are unuse
d. No need to write |
| 153 // unused. No need to write them explicitly since they're | 143 // them explicitly since they're filled to 128 on creation. |
| 154 // filled to 128 on creation. | 144 ByteBuffer.wrap(data, startY, sizeY).get(mFrameBuffer.array(
), 0, sizeY); |
| 155 ByteBuffer.wrap(data, startY, sizeY) | |
| 156 .get(mFrameBuffer.array(), 0, sizeY); | |
| 157 } else if (mTangoCameraId == FOURMP_CAMERA_ID) { | 145 } else if (mTangoCameraId == FOURMP_CAMERA_ID) { |
| 158 int startY = | 146 int startY = SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE
+ |
| 159 SF_WIDTH * (SF_LINES_HEADER + SF_LINES_FISHEYE + | |
| 160 SF_LINES_RESERVED + SF_LINES_DEPTH_PADDED); | 147 SF_LINES_RESERVED + SF_LINES_DEPTH_PADDED); |
| 161 int sizeY = SF_WIDTH * SF_LINES_BIGIMAGE; | 148 int sizeY = SF_WIDTH * SF_LINES_BIGIMAGE; |
| 162 | 149 |
| 163 // The spec is completely inaccurate on the location, sizes | 150 // The spec is completely inaccurate on the location, sizes |
| 164 // and format of these channels. | 151 // and format of these channels. |
| 165 int startU = SF_WIDTH * (SF_HEIGHT + SF_OFFSET_4MP_CHROMA); | 152 int startU = SF_WIDTH * (SF_HEIGHT + SF_OFFSET_4MP_CHROMA); |
| 166 int sizeU = SF_WIDTH * SF_LINES_BIGIMAGE / 4; | 153 int sizeU = SF_WIDTH * SF_LINES_BIGIMAGE / 4; |
| 167 int startV = (SF_WIDTH * SF_HEIGHT * 5 / 4) + | 154 int startV = (SF_WIDTH * SF_HEIGHT * 5 / 4) + SF_WIDTH * SF_
OFFSET_4MP_CHROMA; |
| 168 SF_WIDTH * SF_OFFSET_4MP_CHROMA; | |
| 169 int sizeV = SF_WIDTH * SF_LINES_BIGIMAGE / 4; | 155 int sizeV = SF_WIDTH * SF_LINES_BIGIMAGE / 4; |
| 170 | 156 |
| 171 // Equivalent to the following |for| loop but much faster: | 157 // Equivalent to the following |for| loop but much faster: |
| 172 // for (int i = START; i < START + SIZE; ++i) | 158 // for (int i = START; i < START + SIZE; ++i) |
| 173 // mFrameBuffer.put(data[i]); | 159 // mFrameBuffer.put(data[i]); |
| 174 ByteBuffer.wrap(data, startY, sizeY) | 160 ByteBuffer.wrap(data, startY, sizeY) |
| 175 .get(mFrameBuffer.array(), 0, sizeY); | 161 .get(mFrameBuffer.array(), 0, sizeY); |
| 176 ByteBuffer.wrap(data, startU, sizeU) | 162 ByteBuffer.wrap(data, startU, sizeU) |
| 177 .get(mFrameBuffer.array(), sizeY, sizeU); | 163 .get(mFrameBuffer.array(), sizeY, sizeU); |
| 178 ByteBuffer.wrap(data, startV, sizeV) | 164 ByteBuffer.wrap(data, startV, sizeV) |
| 179 .get(mFrameBuffer.array(), sizeY + sizeU, sizeV); | 165 .get(mFrameBuffer.array(), sizeY + sizeU, sizeV); |
| 180 } else { | 166 } else { |
| 181 Log.e(TAG, "Unknown camera, #id: " + mTangoCameraId); | 167 Log.e(TAG, "Unknown camera, #id: " + mTangoCameraId); |
| 182 return; | 168 return; |
| 183 } | 169 } |
| 184 mFrameBuffer.rewind(); // Important! | 170 mFrameBuffer.rewind(); // Important! |
| 185 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, | 171 nativeOnFrameAvailable(mNativeVideoCaptureDeviceAndroid, mFrameB
uffer.array(), |
| 186 mFrameBuffer.array(), | 172 mFrameBuffer.capacity(), rotation); |
| 187 mFrameBuffer.capacity(), | |
| 188 rotation); | |
| 189 } | 173 } |
| 190 } finally { | 174 } finally { |
| 191 mPreviewBufferLock.unlock(); | 175 mPreviewBufferLock.unlock(); |
| 192 } | 176 } |
| 193 } | 177 } |
| 194 } | 178 } |
| OLD | NEW |