Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Unified Diff: media/capture/video/android/java/src/org/chromium/media/VideoCaptureTango.java

Issue 2983473002: Android Tango depth camera capture support.
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/capture/video/android/java/src/org/chromium/media/VideoCaptureTango.java
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureTango.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureTango.java
new file mode 100644
index 0000000000000000000000000000000000000000..429c08f63c4b6c39f2ec75958593b3673d0eda8d
--- /dev/null
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureTango.java
@@ -0,0 +1,270 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.media;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+
+import com.google.atap.tangoservice.Tango;
+import com.google.atap.tangoservice.TangoCameraIntrinsics;
+import com.google.atap.tangoservice.TangoConfig;
+import com.google.atap.tangoservice.TangoCoordinateFramePair;
+import com.google.atap.tangoservice.TangoErrorException;
+import com.google.atap.tangoservice.TangoEvent;
+import com.google.atap.tangoservice.TangoInvalidException;
+import com.google.atap.tangoservice.TangoOutOfDateException;
+import com.google.atap.tangoservice.TangoPointCloudData;
+import com.google.atap.tangoservice.TangoPoseData;
+import com.google.atap.tangoservice.TangoXyzIjData;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.util.ArrayList;
+
+/**
+ * This class extends the VideoCapture base class for manipulating a Tango Depth
+ * video capture device.
+ **/
+@JNINamespace("media")
+@SuppressWarnings("deprecation")
+public class VideoCaptureTango extends VideoCapture {
+ // Tango devices have additional depth, color and fisheye cameras. Those devices are identified
+ // by model & device.
+ private static final String[][] TANGO_DEVICE_LIST = {
+ {"Project Tango Tablet Development Kit", "yellowstone"}, {"Lenovo PB2-690M", "PB2PRO"}};
+
+ private static class CamParams {
+ final String mName;
+ final int mCaptureApiType;
+ final int mWidth;
+ final int mHeight;
+
+ CamParams(String name, int captureApiType, int width, int height) {
+ mName = name;
+ mCaptureApiType = captureApiType;
+ mWidth = width;
+ mHeight = height;
+ }
+ }
+
+ private Tango mTango;
+ private TangoCameraIntrinsics mIntrinsics;
+ private final int mTangoCameraId;
+ // The indexes must coincide with |CAM_PARAMS| defined below.
+ private static final int DEPTH_CAMERA_ID = 0;
+ private static final int FISHEYE_CAMERA_ID = 1;
+ private static final int FOURMP_CAMERA_ID = 2;
+ // As pointcloud is in color camera 3D space coordinates, we will project it to e.g. down-scaled
+ // 1920x1080 fitting the depth resolution but keeping the camera frame aspect ratio, e.g. to 214
+ // x 120. When we project 3d pointcloud produced by depth camera of e.g. 224x172 (Lenovo Phab2
+ // Pro) or larger resolutions, we get continues depth frame (214x120) synchronized to color
+ // camera frame with easy mapping color -> depth: color frame coordinates divided by scale gives
+ // the position in the depth buffer.
+ private static final CamParams CAM_PARAMS[] = {
+ new CamParams("Tango depth", VideoCaptureApi.ANDROID_TANGO, 214, 120)};
+
+ private static final String TAG = "cr.mediatango";
+
+ private static boolean isTangoDevice() {
+ for (String[] device : TANGO_DEVICE_LIST) {
+ if (device[0].contentEquals(android.os.Build.MODEL)
+ && device[1].contentEquals(android.os.Build.DEVICE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Checks if it is Tango device; returns 0 if it is not.
+ static int getNumberOfCameras() {
+ if (isTangoDevice()) return CAM_PARAMS.length;
+ return 0;
+ }
+
+ private void setupTangoConfig() {
+ TangoConfig config = mTango.getConfig(TangoConfig.CONFIG_TYPE_DEFAULT);
+ config.putBoolean(TangoConfig.KEY_BOOLEAN_DEPTH, true);
+
+ config.putInt(TangoConfig.KEY_INT_DEPTH_MODE, TangoConfig.TANGO_DEPTH_MODE_POINT_CLOUD);
+ mTango.connect(config);
+ assert mTangoCameraId == DEPTH_CAMERA_ID : "Only depth camera capture supported";
+ try {
+ mIntrinsics = mTango.getCameraIntrinsics(TangoCameraIntrinsics.TANGO_CAMERA_COLOR);
+ } catch (TangoErrorException e) {
+ Log.e(TAG, "setupTangoConfig", e);
+ }
+ }
+
+ static int getCaptureApiType(int index) {
+ if (index < CAM_PARAMS.length) return CAM_PARAMS[index].mCaptureApiType;
+ return VideoCaptureApi.UNKNOWN;
+ }
+
+ static String getName(int index) {
+ if (index < CAM_PARAMS.length) return CAM_PARAMS[index].mName;
+ return null;
+ }
+
+ static VideoCaptureFormat[] getDeviceSupportedFormats(int id) {
+ ArrayList<VideoCaptureFormat> formatList = new ArrayList<VideoCaptureFormat>();
+ if (id == DEPTH_CAMERA_ID) {
+ formatList.add(new VideoCaptureFormat(CAM_PARAMS[DEPTH_CAMERA_ID].mWidth,
+ CAM_PARAMS[DEPTH_CAMERA_ID].mHeight, 5, ImageFormat.DEPTH16));
+ }
+ return formatList.toArray(new VideoCaptureFormat[formatList.size()]);
+ }
+
+ VideoCaptureTango(int id, long nativeVideoCaptureDeviceAndroid) {
+ super(0, nativeVideoCaptureDeviceAndroid);
+ mTangoCameraId = id;
+ }
+
+ private void setTangoListeners() {
+ final ArrayList<TangoCoordinateFramePair> framePairs =
+ new ArrayList<TangoCoordinateFramePair>();
+ // Listen for new Tango data.
+ mTango.connectListener(framePairs, new Tango.OnTangoUpdateListener() {
+ @Override
+ public void onPointCloudAvailable(final TangoPointCloudData pointCloudData) {
+ if (pointCloudData.points != null) {
+ nativeOnPointCloudAvailable(mNativeVideoCaptureDeviceAndroid,
+ pointCloudData.points, pointCloudData.numPoints,
+ pointCloudData.timestamp);
+ }
+ }
+
+ @Override
+ public void onPoseAvailable(final TangoPoseData pose) {}
+
+ @Override
+ public void onFrameAvailable(int id) {}
+
+ @Override
+ public void onXyzIjAvailable(final TangoXyzIjData d) {}
+
+ @Override
+ public void onTangoEvent(final TangoEvent event) {}
+ });
+ }
+
+ @Override
+ public boolean startCapture() {
+ if (mUseBackgroundThreadForTesting) {
+ // Mock the data for the tests; this way tests are run on Tango and non-Tango devices.
+ mIntrinsics = new TangoCameraIntrinsics();
+ mIntrinsics.width = 1920;
+ mIntrinsics.height = 1080;
+ mIntrinsics.cx = mIntrinsics.width / 2;
+ mIntrinsics.cy = mIntrinsics.height / 2;
+ mIntrinsics.fx = mIntrinsics.width;
+ mIntrinsics.fy = mIntrinsics.width;
+ return true;
+ }
+ final Context context = ContextUtils.getApplicationContext();
+ mTango = new Tango(context, new Runnable() {
+ @Override
+ public void run() {
+ synchronized (context) {
+ try {
+ setupTangoConfig();
+ setTangoListeners();
+ nativeOnStarted(mNativeVideoCaptureDeviceAndroid);
+ } catch (TangoOutOfDateException e) {
+ Log.e(TAG, "exception_out_of_date", e);
+ } catch (TangoErrorException e) {
+ Log.e(TAG, "exception_tango_error", e);
+ } catch (TangoInvalidException e) {
mcasas 2017/07/15 00:12:36 I think you could bundle these three and Log() wil
+ Log.e(TAG, "R.string.exception_tango_invalid", e);
+ }
+ }
+ }
+ });
+ return true;
+ }
+
+ @Override
+ public boolean stopCapture() {
+ if (!mUseBackgroundThreadForTesting) mTango.disconnect();
+ mTango = null;
+ return true;
+ }
+
+ @Override
+ public boolean allocate(int width, int height, int frameRate) {
+ mCaptureFormat = new VideoCaptureFormat(CAM_PARAMS[DEPTH_CAMERA_ID].mWidth,
+ CAM_PARAMS[DEPTH_CAMERA_ID].mHeight, 5, ImageFormat.DEPTH16);
+ return true;
+ }
+
+ @Override
+ public void deallocate() {}
+
+ @Override
+ public boolean takePhoto(final long callbackId) {
+ Log.e(TAG, "takePhoto is not supported with Tango depth camera");
+ return false;
+ }
+
+ @Override
+ public void setPhotoOptions(double zoom, int focusMode, int exposureMode, double width,
+ double height, float[] pointsOfInterest2D, boolean hasExposureCompensation,
+ double exposureCompensation, int whiteBalanceMode, double iso,
+ boolean hasRedEyeReduction, boolean redEyeReduction, int fillLightMode,
+ boolean hasTorch, boolean torch, double colorTemperature) {
+ Log.e(TAG, "setPhotoOptions is not supported with Tango depth camera");
+ }
+
+ @Override
+ public PhotoCapabilities getPhotoCapabilities() {
+ PhotoCapabilities.Builder builder = new PhotoCapabilities.Builder();
+ builder.setMinIso(0).setMaxIso(0).setCurrentIso(0).setStepIso(0);
+ int width = CAM_PARAMS[DEPTH_CAMERA_ID].mWidth;
+ int height = CAM_PARAMS[DEPTH_CAMERA_ID].mHeight;
+ builder.setMinHeight(height).setMaxHeight(height).setStepHeight(1);
+ builder.setMinWidth(width).setMaxWidth(width).setStepWidth(1);
+ builder.setCurrentHeight(height).setCurrentWidth(width);
+ builder.setMinZoom(0).setMaxZoom(0);
+ builder.setCurrentZoom(0).setStepZoom(0);
+ builder.setExposureMode(AndroidMeteringMode.CONTINUOUS);
+ builder.setWhiteBalanceMode(AndroidMeteringMode.CONTINUOUS);
+ builder.setFocusMode(AndroidMeteringMode.CONTINUOUS);
+ return builder.build();
+ }
+
+ @CalledByNative
+ public double getFocalLengthX() {
+ assert mTangoCameraId == DEPTH_CAMERA_ID : "Only depth camera capture supported";
+ final double scale =
+ Math.ceil((double) mIntrinsics.width / (double) CAM_PARAMS[DEPTH_CAMERA_ID].mWidth);
+ return mIntrinsics.fx / scale;
+ }
+
+ @CalledByNative
+ public double getFocalLengthY() {
+ assert mTangoCameraId == DEPTH_CAMERA_ID : "Only depth camera capture supported";
+ final double scale =
+ Math.ceil((double) mIntrinsics.width / (double) CAM_PARAMS[DEPTH_CAMERA_ID].mWidth);
+ return mIntrinsics.fy / scale;
+ }
+
+ @CalledByNative
+ public double getPrincipalPointX() {
+ assert mTangoCameraId == DEPTH_CAMERA_ID : "Only depth camera capture supported";
+ final double scale =
+ Math.ceil((double) mIntrinsics.width / (double) CAM_PARAMS[DEPTH_CAMERA_ID].mWidth);
+ return mIntrinsics.cx / scale;
+ }
+
+ @CalledByNative
+ public double getPrincipalPointY() {
+ assert mTangoCameraId == DEPTH_CAMERA_ID : "Only depth camera capture supported";
+ final double scale =
+ Math.ceil((double) mIntrinsics.width / (double) CAM_PARAMS[DEPTH_CAMERA_ID].mWidth);
+ return mIntrinsics.cy / scale;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698