获取所有示例都可以在工程的OrbbecSdkExamples目录中找到
名称 |
语言 |
描述 |
---|---|---|
HelloOrbbec |
Java |
演示连接到设备获取SDK版本和设备信息 |
深度示例 |
Java |
通过Pipeline开启指定配置彩色流并渲染 |
彩色示例 |
Java |
通过Pipeline开启指定配置深度流并渲染 |
红外示例 |
Java |
通过Pipeline开启指定配置红外流并渲染 |
流对齐示例 |
Java |
演示对传感器数据流对齐的操作 |
热拔插示例 |
Java |
演示设备 拔插回调的设置,并获取到插拔后处理的流 |
IMU示例 |
Java |
获取IMU数据并输出显示 |
多设备示例 |
Java |
演示对多设备进行操作 |
点云示例 |
Java |
演示生成 深度点云或RGBD点云并保存成ply格式文件 |
存储示例 |
Java |
获取彩色存储为png格式,深度存 储为raw格式以及通过filter进行格式转换 |
传感器控制示例 |
Java |
演示对设备和传感器控制命令的操作 |
录制与回放示例 |
Java |
:连接设备开流 , 录制当 前视频流到文件,载入视频文件进行回放。 |
Android¶
HelloOrbbec¶
功能描述:用于演示SDK初始化、获取SDK版本、获取设备型号、获取设备序列号、获取固件版本号、SDK释放资源。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
StringBuilder builder = new StringBuilder();
// 2.查看SDK版本
builder.append("SDK Version = " + OBContext.getVersionName() + "\n");
// 3.获取设备个数
int deviceCount = deviceList.getDeviceCount();
for (int i = 0; i < deviceCount; ++i) {
// 4.根据设备索引创建设备
Device device = deviceList.getDevice(i);
// 5.获取设备信息
DeviceInfo info = device.getInfo();
// 6.获取设备版本信息
builder.append("Name: " + info.getName() + "\n");
builder.append("Vid: " + LocalUtils.formatHex04(info.getVid()) + "\n");
builder.append("Pid: " + LocalUtils.formatHex04(info.getPid()) + "\n");
builder.append("Uid: " + info.getUid() + "\n");
builder.append("SN: " + info.getSerialNumber() + "\n");
String firmwareVersion = info.getFirmwareVersion();
builder.append("FirmwareVersion: " + firmwareVersion + "\n");
String hardwareVersion = info.getHardwareVersion();
builder.append("HardwareVersion: " + hardwareVersion + "\n");
// 7.遍历当前设备的传感器
for (Sensor sensor : device.querySensors()) {
// 8.查询传感器类型
builder.append("Sensor : type = " + sensor.getType() + "\n");
}
runOnUiThread(() -> txtInfo.setText(builder.toString()));
// 9.释放设备信息
info.close();
// 10.释放设备资源
device.close();
}
// 11.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
查看SDK版本号
// 获取SDK版本名称
String version = OBContext.getVersionName();
// 获取SDK内核版本名称(Orbbec SDK so的版本)
String coreVersion = OBContext.getCoreVersionName();
通过回调可得到设备索引,根据设备索引创建设备,此处以创建第一个设备为例
Device device = deviceList.getDevice(0);
接下来就可以获取和这个设备相关的信息了,下面这些信息都可以通过DeviceInfo来获取
// 5.获取设备信息
DeviceInfo info = device.getInfo();
// 6.获取设备版本信息
builder.append("Name: " + info.getName() + "\n");
builder.append("Vid: " + LocalUtils.formatHex04(info.getVid()) + "\n");
builder.append("Pid: " + LocalUtils.formatHex04(info.getPid()) + "\n");
builder.append("Uid: " + info.getUid() + "\n");
builder.append("SN: " + info.getSerialNumber() + "\n");
String firmwareVersion = info.getFirmwareVersion();
builder.append("FirmwareVersion: " + firmwareVersion + "\n");
String hardwareVersion = info.getHardwareVersion();
builder.append("HardwareVersion: " + hardwareVersion + "\n");
// 7.遍历当前设备的传感器
for (Sensor sensor : device.querySensors()) {
// 8.查询传感器类型
builder.append("Sensor : type = " + sensor.getType() + "\n");
}
runOnUiThread(() -> txtInfo.setText(builder.toString()));
// 9.释放设备信息
info.close();
遍历传感器类型
for (Sensor sensor : device.querySensors()) {
// 查询传感器类型
Log.d(TAG,"Sensor : type = " + sensor.getType() + "\n");
}
资源释放
// 关闭设备
device.close();
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
mOBContext = null;
}
彩色示例-ColorViewer¶
功能描述:本示例主要演示了SDK的初始化、设备创建、Pipeline的初始化及配置以及通过Pipeline开启指定配置彩色流并渲染。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.创建Device,并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.创建Pipeline配置
Config config = new Config();
// 4.获取彩色流配置,并配置到Config,这里配置为640x480 YUYV格式或者是640x480 I420格式
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile streamProfile = null;
if (null != colorProfileList) {
streamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == streamProfile) {
streamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.如果配置格式为I420,则创建格式转换filter,用于将I420格式转换为RGB888格式来进行渲染
if (streamProfile.getFormat() == Format.I420) {
mFormatConvertFilter = new FormatConvertFilter();
mFormatConvertFilter.setFormatType(FormatConvertType.FORMAT_I420_TO_RGB888);
}
// 6.使能彩色配置
config.enableStream(streamProfile);
// 7.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_COLOR_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_COLOR_MIRROR_BOOL, true);
}
// 8.开流
mPipeline.start(config);
// 9.释放config
config.close();
// 10.释放streamProfile
streamProfile.close();
// 11.创建获取Pipeline数据线程
start();
}
// 12.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.创建Device,并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
// 3.创建Pipeline配置
Config config = new Config();
获取彩色流配置,并配置到Config,这里配置为640x480 YUYV格式或者是640x480 I420格式
// 4.获取彩色流配置,并配置到Config,这里配置为640x480 YUYV格式或者是640x480 I420格式
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile streamProfile = null;
if (null != colorProfileList) {
streamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == streamProfile) {
streamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.如果配置格式为I420,则创建格式转换filter,用于将I420格式转换为RGB888格式来进行渲染
if (streamProfile.getFormat() == Format.I420) {
mFormatConvertFilter = new FormatConvertFilter();
mFormatConvertFilter.setFormatType(FormatConvertType.FORMAT_I420_TO_RGB888);
}
// 6.使能彩色配置
config.enableStream(streamProfile);
通过Device属性接口设置镜像
// 7.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_COLOR_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_COLOR_MIRROR_BOOL, true);
}
使用Config配置通过Pipeline开流,并释放局部资源
// 8.开流
mPipeline.start(config);
// 9.释放config
config.close();
// 10.释放streamProfile
streamProfile.close();
创建获取Pipeline数据线程
private void start() {
mIsStreamRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamRunnable);
mStreamThread.start();
}
}
阻塞方式获取数据集,等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
数据处理及渲染
// 获取彩色流数据
ColorFrame colorFrame = frameSet.getColorFrame();
// 数据处理及渲染
if (null != colorFrame) {
if (colorFrame.getFormat() == Format.I420) {
// 通过filter将I420格式的彩色数据帧转换为RGB888格式的数据帧
Frame frame = mFormatConvertFilter.process(colorFrame);
if (null != frame) {
// 获取数据并进行渲染
byte[] frameData = new byte[colorFrame.getWidth() * colorFrame.getHeight() * 3];
frame.getData(frameData);
mColorView.update(frameData, colorFrame.getWidth(), colorFrame.getHeight(), StreamType.COLOR, Format.RGB888);
frame.close();
}
} else {
// 获取数据并进行渲染
byte[] frameData = new byte[colorFrame.getDataSize()];
colorFrame.getData(frameData);
mColorView.update(frameData, colorFrame.getWidth(), colorFrame.getHeight(), StreamType.COLOR, colorFrame.getFormat());
}
// 释放彩色数据帧
colorFrame.close();
}
// 释放数据集
frameSet.close();
停止获取Pipeline数据
private void stop() {
mIsStreamRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(300);
} catch (InterruptedException e) {
}
mStreamThread = null;
}
}
资源释放
// 释放filter资源
if (null != mFormatConvertFilter) {
try {
mFormatConvertFilter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 停止Pipeline,并释放
if (null != mPipeline) {
mPipeline.stop();
mPipeline.close();
}
// 释放Device
if (mDevice != null) {
mDevice.close();
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
// 释放渲染窗口资源
if (mColorView != null) {
mColorView.release();
}
深度示例-DepthViewer¶
功能描述:本示例主要演示了SDK的初始化、设备创建、Pipeline的初始化及配置以及通过Pipeline开启指定配置深度流并渲染。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.创建Pipeline配置
Config config = new Config();
// 4.获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile streamProfile = null;
if (null != depthProfileList) {
streamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.使能深度流配置
config.enableStream(streamProfile);
// 6.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, true);
}
// 7.开流
mPipeline.start(config);
// 8.释放config
config.close();
// 9.释放streamProfile
streamProfile.close();
// 10.创建获取Pipeline数据线程
start();
}
// 11.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
Config config = new Config();
获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
// 4.获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile streamProfile = null;
if (null != depthProfileList) {
streamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.使能深度流配置
config.enableStream(streamProfile);
通过Device属性接口设置镜像
// 6.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, true);
}
使用Config配置通过Pipeline开流,并释放局部资源
mPipeline.start(config);
// 8.释放config
config.close();
// 9.释放streamProfile
streamProfile.close();
创建获取Pipeline数据线程
private void start() {
mIsStreamRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamRunnable);
mStreamThread.start();
}
}
阻塞方式获取数据集,等待100ms后如果获取不到,则超时
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
数据处理及渲染
// 获取深度流数据
DepthFrame frame = frameSet.getDepthFrame();
if (frame != null) {
// 获取深度数据并进行渲染
byte[] frameData = new byte[frame.getDataSize()];
frame.getData(frameData);
mDepthView.update(frameData, frame.getWidth(), frame.getHeight(), StreamType.DEPTH, frame.getFormat());
// 释放深度数据帧
frame.close();
}
// 释放数据集
frameSet.close();
停止获取Pipeline数据
private void stop() {
mIsStreamRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(300);
} catch (InterruptedException e) {
}
mStreamThread = null;
}
}
资源释放
// 停止Pipeline,并释放
if (null != mPipeline) {
mPipeline.stop();
mPipeline.close();
}
// 释放Device
if (mDevice != null) {
mDevice.close();
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
// 释放渲染窗口资源
if (mDepthView != null) {
mDepthView.release();
}
红外示例-InfraredViewer¶
功能描述:本示例主要演示了SDK的初始化、设备创建、Pipeline的初始化及配置以及通过Pipeline开启指定配置红外流并渲染。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.创建Pipeline配置
Config config = new Config();
// 4.获取流配置,并配置到Config
StreamProfileList irProfileList = mPipeline.getStreamProfileList(SensorType.IR);
StreamProfile streamProfile = null;
if (null != irProfileList) {
streamProfile = irProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
irProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.使能红外流配置
config.enableStream(streamProfile);
// 6.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_IR_MIRROR_BOOL, PermissionType.OB_PERMISSION_READ)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_IR_MIRROR_BOOL, true);
}
// 7.开流
mPipeline.start(config);
// 8.释放config
config.close();
// 9.释放streamProfile
streamProfile.close();
// 10.创建获取Pipeline数据线程
start();
}
// 11.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
// 3.创建Pipeline配置
Config config = new Config();
获取红外流配置,并配置到Config,这里配置的为640x480 Y16格式
// 4.获取流配置,并配置到Config
StreamProfileList irProfileList = mPipeline.getStreamProfileList(SensorType.IR);
StreamProfile streamProfile = null;
if (null != irProfileList) {
streamProfile = irProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
irProfileList.close();
}
if (streamProfile == null) {
return;
}
// 5.使能红外流配置
config.enableStream(streamProfile);
通过Device属性接口设置镜像
// 6.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_IR_MIRROR_BOOL, PermissionType.OB_PERMISSION_READ)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_IR_MIRROR_BOOL, true);
}
使用Config配置通过Pipeline开流,并释放局部资源
// 7.开流
mPipeline.start(config);
// 8.释放config
config.close();
// 9.释放streamProfile
streamProfile.close();
创建获取Pipeline数据线程
private void start() {
mIsStreamRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamRunnable);
mStreamThread.start();
}
}
阻塞方式获取数据集,等待100ms后如果获取不到,则超时
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
数据处理及渲染
// 获取红外流数据
IRFrame frame = frameSet.getIrFrame();
if (frame != null) {
// 获取红外数据并进行渲染
byte[] frameData = new byte[frame.getDataSize()];
frame.getData(frameData);
mIrView.update(frameData, frame.getWidth(), frame.getHeight(), StreamType.IR, frame.getFormat());
// 释放红外数据帧
frame.close();
}
// 释放数据集
frameSet.close();
停止获取Pipeline数据
private void stop() {
mIsStreamRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(300);
} catch (InterruptedException e) {
}
mStreamThread = null;
}
}
资源释放
// 停止Pipeline,并释放
if (null != mPipeline) {
mPipeline.stop();
mPipeline.close();
}
if (null != mDevice) {
mDevice.close();
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
// 释放渲染窗口资源
if (null != mIrView) {
mIrView.release();
}
流对齐示例-SyncAlignViewer¶
功能描述:本示例主要演示了对数据流控制对齐的操作。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(this, new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.获取Device并通过Device创建Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.创建格式转换filter,用于将I420格式的数据转换为RGB888格式
mFormatConvertFilter = new FormatConvertFilter();
mFormatConvertFilter.setFormatType(FormatConvertType.FORMAT_I420_TO_RGB888);
// 4.创建Pipeline配置
mConfig = new Config();
// 5.默认关闭D2C
mConfig.setAlignMode(AlignMode.ALIGN_D2C_DISABLE);
// 6.获取指定格式的彩色流配置
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile colorStreamProfile = null;
if (null != colorProfileList) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == colorStreamProfile) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
if (colorStreamProfile == null) {
return;
}
// 7.使能彩色流配置
mConfig.enableStream(colorStreamProfile);
// 8.获取深度流配置
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile depthStreamProfile = null;
if (null != depthProfileList) {
depthStreamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (depthStreamProfile == null) {
return;
}
// 9.使能深度流配置
mConfig.enableStream(depthStreamProfile);
// 10.通过config开流
mPipeline.start(mConfig);
// 11.释放colorStreamProfile
colorStreamProfile.close();
// 12.释放depthStreamProfile
depthStreamProfile.close();
// 13.创建获取Pipeline数据线程
start();
}
// 14.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.获取Device并通过Device创建Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
mConfig = new Config();
创建格式转换filter,用于将I420格式的数据转换为RGB888格式
// 3.创建格式转换filter,用于将I420格式的数据转换为RGB888格式
mFormatConvertFilter = new FormatConvertFilter();
mFormatConvertFilter.setFormatType(FormatConvertType.FORMAT_I420_TO_RGB888);
创建Pipeline配置
// 4.创建Pipeline配置
mConfig = new Config();
默认关闭D2C
// 5.默认关闭D2C
mConfig.setAlignMode(AlignMode.ALIGN_D2C_DISABLE);
获取彩色流配置,并配置到Config,这里配置为640x480 YUYV格式或者是640x480 I420格式
// 6.获取指定格式的彩色流配置
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile colorStreamProfile = null;
if (null != colorProfileList) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == colorStreamProfile) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
if (colorStreamProfile == null) {
return;
}
// 7.使能彩色流配置
mConfig.enableStream(colorStreamProfile);
获取深度流配置,并配置到Config,这里配置为640x480 Y16格式
// 8.获取深度流配置
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile depthStreamProfile = null;
if (null != depthProfileList) {
depthStreamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (depthStreamProfile == null) {
return;
}
// 9.使能深度流配置
mConfig.enableStream(depthStreamProfile);
使用Config配置通过Pipeline开流,并释放局部资源
// 10.通过config开流
mPipeline.start(mConfig);
// 11.释放colorStreamProfile
colorStreamProfile.close();
// 12.释放depthStreamProfile
depthStreamProfile.close();
创建获取Pipeline数据线程
private void start() {
mIsStreamRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamRunnable);
mStreamThread.start();
}
}
阻塞方式获取数据集,等待100ms后如果获取不到,则超时
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
获取彩色数据及深度数据
// 获取深度流数据
DepthFrame depthFrame = frameSet.getDepthFrame();
// 获取彩色流数据
ColorFrame colorFrame = frameSet.getColorFrame();
数据处理及渲染,并释放局部资源
if (null != depthFrame && null != colorFrame) {
//深度转RGB888
ByteBuffer depthSrcBytebuffer = ByteBuffer.allocateDirect(depthFrame.getDataSize());
depthSrcBytebuffer.rewind();
byte[] depthSrcBytes = new byte[depthFrame.getDataSize()];
depthFrame.getData(depthSrcBytes);
depthSrcBytebuffer.put(depthSrcBytes);
ByteBuffer depthDstBytebuffer = ByteBuffer.allocateDirect(depthFrame.getWidth() * depthFrame.getHeight() * 3);
YuvUtil.depth2RGB888(depthSrcBytebuffer, depthDstBytebuffer, depthFrame.getWidth(), depthFrame.getHeight(), 1);
depthData = new byte[depthFrame.getWidth() * depthFrame.getHeight() * 3];
depthDstBytebuffer.get(depthData, 0, depthData.length);
if (colorFrame.getFormat() == Format.I420) {
// I420格式数据转RGB888
Frame frame = mFormatConvertFilter.process(colorFrame);
if (null != frame) {
colorData = new byte[colorFrame.getWidth() * colorFrame.getHeight() * 3];
frame.getData(colorData);
// 释放数据帧
frame.close();
}
} else {
// YUYV格式数据转RGB888
ByteBuffer colorSrcBytebuffer = ByteBuffer.allocateDirect(colorFrame.getDataSize());
colorSrcBytebuffer.rewind();
byte[] colorSrcBytes = new byte[colorFrame.getDataSize()];
colorFrame.getData(colorSrcBytes);
colorSrcBytebuffer.put(colorSrcBytes);
ByteBuffer colorDstBytebuffer = ByteBuffer.allocateDirect(colorFrame.getWidth() * colorFrame.getHeight() * 3);
YuvUtil.yuyv2Rgb888(colorSrcBytebuffer, colorDstBytebuffer, colorFrame.getWidth() * colorFrame.getHeight() * 3);
colorData = new byte[colorFrame.getWidth() * colorFrame.getHeight() * 3];
colorDstBytebuffer.get(colorData, 0, colorData.length);
}
}
if (depthData != null && colorData != null) {
byte[] depthColorData = depthToColor(depthData, colorData, 640, 480, mAlpha);
mColorView.update(depthColorData, 640, 480, StreamType.COLOR, Format.RGB888);
}
// 释放深度帧
if (null != depthFrame) {
depthFrame.close();
}
// 释放彩色帧
if (null != colorFrame) {
colorFrame.close();
}
// 释放数据集
frameSet.close();
设置帧同步
// 设置帧同步
private void setSync(boolean isChecked) {
try {
if (isChecked) {
mPipeline.enableFrameSync();
} else {
mPipeline.disableFrameSync();
}
} catch (Exception e) {
e.printStackTrace();
}
}
设置D2C
// 设置D2C
private void setAlignToColor(boolean isChecked, boolean isHardware) {
try {
if (mPipeline == null || mDevice == null) {
return;
}
try {
if (isChecked) {
mConfig.setAlignMode((isHardware ? AlignMode.ALIGN_D2C_HW_ENABLE : AlignMode.ALIGN_D2C_SW_ENABLE));
} else {
mConfig.setAlignMode(AlignMode.ALIGN_D2C_DISABLE);
}
mPipeline.switchConfig(mConfig);
} catch (Exception e) {
Log.w(TAG, "setAlignToColor: " + e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
停止获取Pipeline数据
private void stop() {
mIsStreamRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(300);
} catch (InterruptedException e) {
}
}
}
资源释放
// 停止Pipeline,并关闭
if (null != mPipeline) {
mPipeline.stop();
mPipeline.close();
}
// 释放格式转换filter
if (null != mFormatConvertFilter) {
try {
mFormatConvertFilter.close();
} catch (Exception e) {
}
mFormatConvertFilter = null;
}
// 释放Config
if (null != mConfig) {
mConfig.close();
}
// 释放Device
if (null != mDevice) {
mDevice.close();
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
// 释放渲染窗口资源
if (null != mColorView) {
mColorView.release();
}
热拔插示例-HotPlugin¶
功能描述:本示例主要演示设备拔插回调的设置,以及拔插之后处理获取到的流
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
定义Color的FrameCallback
private FrameCallback mColorFrameCallback = frame -> {
printFrameInfo(frame.as(FrameType.COLOR), mColorFps);
// 释放frame资源
frame.close();
};
定义Depth的FrameCallback
private FrameCallback mColorFrameCallback = frame -> {
printFrameInfo(frame.as(FrameType.COLOR), mColorFps);
// 释放frame资源
frame.close();
};
定义IR的FrameCallback
private FrameCallback mIrFrameCallback = frame -> {
printFrameInfo(frame.as(FrameType.IR), mIrFps);
// 释放frame资源
frame.close();
};
打印数据帧信息
private void printFrameInfo(VideoFrame frame, int fps) {
try {
String frameInfo = "FrameType:" + frame.getStreamType()
+ ", index:" + frame.getFrameIndex()
+ ", width:" + frame.getWidth()
+ ", height:" + frame.getHeight()
+ ", format:" + frame.getFormat()
+ ", fps:" + fps
+ ", timeStampUs:" + frame.getTimeStampUs();
if (frame.getStreamType() == FrameType.DEPTH) {
frameInfo += ", middlePixelValue:" + getMiddlePixelValue(frame);
}
Log.i(TAG, frameInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (deviceList == null || deviceList.getDeviceCount() <= 0) {
setText(mNameTv, "No device connected !");
}
// 2.创建设备,并获取设备名称
mDevice = deviceList.getDevice(0);
DeviceInfo devInfo = mDevice.getInfo();
String deviceName = devInfo.getName();
setText(mNameTv, deviceName);
devInfo.close();
// 3.获取深度传感器
mDepthSensor = mDevice.getSensor(SensorType.DEPTH);
// 4.打开深度流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mDepthSensor) {
mDepthSensor.start(null, mDepthFrameCallback);
}
// 5.获取彩色传感器
mColorSensor = mDevice.getSensor(SensorType.COLOR);
// 6.打开彩色流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mColorSensor) {
mColorSensor.start(null, mColorFrameCallback);
}
// 7.获取红外传感器
mIrSensor = mDevice.getSensor(SensorType.IR);
// 8.打开红外流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mIrSensor) {
mIrSensor.start(null, mIrFrameCallback);
}
// 9.更新开流配置信息
setText(mProfileInfoTv, formatProfileInfo());
// 10.释放deviceList资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
setText(mNameTv, "No device connected !");
setText(mProfileInfoTv, "");
mDepthFps = 0;
mColorFps = 0;
mIrFps = 0;
// 停止深度流
if (null != mDepthSensor) {
mDepthSensor.stop();
}
// 停止彩色流
if (null != mColorSensor) {
mColorSensor.stop();
}
// 停止红外流
if (null != mIrSensor) {
mIrSensor.stop();
}
// 释放Device
if (null != mDevice) {
mDevice.close();
mDevice = null;
}
// 释放deviceList
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
设备连接回调(onDeviceAttach)中的处理
try {
if (deviceList == null || deviceList.getDeviceCount() <= 0) {
setText(mNameTv, "No device connected !");
}
// 2.创建设备,并获取设备名称
mDevice = deviceList.getDevice(0);
DeviceInfo devInfo = mDevice.getInfo();
String deviceName = devInfo.getName();
setText(mNameTv, deviceName);
devInfo.close();
// 3.获取深度传感器
mDepthSensor = mDevice.getSensor(SensorType.DEPTH);
// 4.打开深度流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mDepthSensor) {
mDepthSensor.start(null, mDepthFrameCallback);
}
// 5.获取彩色传感器
mColorSensor = mDevice.getSensor(SensorType.COLOR);
// 6.打开彩色流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mColorSensor) {
mColorSensor.start(null, mColorFrameCallback);
}
// 7.获取红外传感器
mIrSensor = mDevice.getSensor(SensorType.IR);
// 8.打开红外流,profile传入null,表示使用配置文件中配置的参数开流,
// 如果设备中没有该配置,或不存在配置文件,则表示使用Profile列表中的第一个配置
if (null != mIrSensor) {
mIrSensor.start(null, mIrFrameCallback);
}
// 9.更新开流配置信息
setText(mProfileInfoTv, formatProfileInfo());
// 10.释放deviceList资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
设备断开连接回调(onDeviceDetach)中的处理
try {
setText(mNameTv, "No device connected !");
setText(mProfileInfoTv, "");
mDepthFps = 0;
mColorFps = 0;
mIrFps = 0;
// 停止深度流
if (null != mDepthSensor) {
mDepthSensor.stop();
}
// 停止彩色流
if (null != mColorSensor) {
mColorSensor.stop();
}
// 停止红外流
if (null != mIrSensor) {
mIrSensor.stop();
}
// 释放Device
if (null != mDevice) {
mDevice.close();
mDevice = null;
}
// 释放deviceList
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
资源释放
try {
// 停止深度流
if (null != mDepthSensor) {
mDepthSensor.stop();
}
// 停止彩色流
if (null != mColorSensor) {
mColorSensor.stop();
}
// 停止红外流
if (null != mIrSensor) {
mIrSensor.stop();
}
// 释放Device
if (null != mDevice) {
mDevice.close();
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
} catch (Exception e) {
e.printStackTrace();
}
IMU示例-IMU¶
功能描述:本示例主要演示了使用SDK获取IMU数据并输出显示。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
定义IMU相关的sensor
// 加速度计传感器
private AccelFrame mAccelFrame;
// 陀螺仪传感器
private GyroFrame mGyroFrame;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (deviceList == null || deviceList.getDeviceCount() == 0) {
showToast("请接入设备");
} else {
// 2.创建Device
mDevice = deviceList.getDevice(0);
// 3.通过Device获取加速度Sensor
mSensorAccel = mDevice.getSensor(SensorType.ACCEL);
// 4.通过Device获取陀螺仪Sensor
mSensorGyro = mDevice.getSensor(SensorType.GYRO);
if (mSensorAccel == null || mSensorGyro == null) {
showToast("本设备不支持IMU");
deviceList.close();
return;
} else {
runOnUiThread(() -> {
mSurfaceViewImu.setVisibility(View.VISIBLE);
});
}
if (mSensorAccel != null && mSensorGyro != null) {
// 5.获取加速度计配置
StreamProfileList accelProfileList = mSensorAccel.getStreamProfileList();
if (null != accelProfileList) {
mAccelStreamProfile = accelProfileList.getStreamProfile(0).as(StreamType.ACCEL);
accelProfileList.close();
}
// 6.获取陀螺仪配置
StreamProfileList gyroProfileList = mSensorGyro.getStreamProfileList();
if (null != gyroProfileList) {
mGyroStreamProfile = gyroProfileList.getStreamProfile(0).as(StreamType.GYRO);
gyroProfileList.close();
}
}
}
// 8.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
showToast("请接入设备");
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备,并通过设备获取加速度计传感器和陀螺仪传感器
// 2.创建Device
mDevice = deviceList.getDevice(0);
// 3.通过Device获取加速度Sensor
mSensorAccel = mDevice.getSensor(SensorType.ACCEL);
// 4.通过Device获取陀螺仪Sensor
mSensorGyro = mDevice.getSensor(SensorType.GYRO);
if (mSensorAccel == null || mSensorGyro == null) {
showToast("本设备不支持IMU");
deviceList.close();
return;
} else {
runOnUiThread(() -> {
mSurfaceViewImu.setVisibility(View.VISIBLE);
});
}
获取加速度计开流配置以及陀螺仪开流配置
if (mSensorAccel != null && mSensorGyro != null) {
// 5.获取加速度计配置
StreamProfileList accelProfileList = mSensorAccel.getStreamProfileList();
if (null != accelProfileList) {
mAccelStreamProfile = accelProfileList.getStreamProfile(0).as(StreamType.ACCEL);
accelProfileList.close();
}
// 6.获取陀螺仪配置
StreamProfileList gyroProfileList = mSensorGyro.getStreamProfileList();
if (null != gyroProfileList) {
mGyroStreamProfile = gyroProfileList.getStreamProfile(0).as(StreamType.GYRO);
gyroProfileList.close();
}
}
通过指定配置开流
private void startIMU() {
// 7.1.初始化IMU数据刷新线程
mIsRefreshIMUDataRunning = true;
mRefreshIMUDataThread = new Thread(mRefreshIMUDataRunnable);
mRefreshIMUDataThread.setName("RefreshIMUDataThread");
// 7.2.开启IMU数据刷新线程
mRefreshIMUDataThread.start();
// 7.3.开始陀螺仪采样
startGyroStream();
// 7.4.开始加速度计采样
startAccelStream();
}
开启加速度计采样
private void startAccelStream() {
try {
// 开启加速度计采样
if (null != mAccelStreamProfile) {
mSensorAccel.start(mAccelStreamProfile, new FrameCallback() {
@Override
public void onFrame(Frame frame) {
AccelFrame accelFrame = frame.as(FrameType.ACCEL);
if (null == mAccelFrame) {
mAccelFrame = accelFrame;
return;
}
frame.close();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
开启陀螺仪采样
private void startGyroStream() {
try {
// 开启陀螺仪采样
if (null != mGyroStreamProfile) {
mSensorGyro.start(mGyroStreamProfile, new FrameCallback() {
@Override
public void onFrame(Frame frame) {
GyroFrame gyroFrame = frame.as(FrameType.GYRO);
if (null == mGyroFrame) {
mGyroFrame = gyroFrame;
return;
}
frame.close();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
创建AccelFrame和GyroFrame数据绘制方法,并在数据刷新线程实时绘制
private void drawImuInfo() {
try {
Canvas canvas = mSurfaceViewImu.getHolder().lockCanvas();
if (null != canvas) {
mPaintIMU.setTextSize(25.0f);
Paint.FontMetrics fm = mPaintIMU.getFontMetrics();
float offsetY = fm.descent - fm.ascent;
float x = canvas.getWidth() / 8;
float y = canvas.getHeight() / 8;
canvas.drawColor(Color.WHITE);
if (mAccelFrame != null) {
canvas.drawText("AccelTimestamp:" + mAccelFrame.getTimeStamp(), x, y, mPaintIMU);
canvas.drawText("AccelTemperature:" + mAccelFrame.getTemperature() + "dC", x, (y += offsetY), mPaintIMU);
canvas.drawText("Accel.x:" + mAccelFrame.getAccelData()[0] + "g", x, (y += 2 * offsetY), mPaintIMU);
canvas.drawText("Accel.y:" + mAccelFrame.getAccelData()[1] + "g", x, (y += offsetY), mPaintIMU);
canvas.drawText("Accel.z:" + mAccelFrame.getAccelData()[2] + "g", x, (y += offsetY), mPaintIMU);
// 释放AccelFrame资源
mAccelFrame.close();
mAccelFrame = null;
}
if (mGyroFrame != null) {
canvas.drawText("GyroTimestamp:" + mGyroFrame.getTimeStamp(), x, (y += 2 * offsetY), mPaintIMU);
canvas.drawText("GyroTemperature:" + mGyroFrame.getTemperature() + "dC", x, (y += offsetY), mPaintIMU);
canvas.drawText("Gyro.x:" + mGyroFrame.getGyroData()[0] + "dps", x, (y += 2 * offsetY), mPaintIMU);
canvas.drawText("Gyro.y:" + mGyroFrame.getGyroData()[1] + "dps", x, (y += offsetY), mPaintIMU);
canvas.drawText("Gyro.z:" + mGyroFrame.getGyroData()[2] + "dps", x, (y += offsetY), mPaintIMU);
// 释放GyroFrame资源
mGyroFrame.close();
mGyroFrame = null;
}
mSurfaceViewImu.getHolder().unlockCanvasAndPost(canvas);
}
} catch (Exception e) {
e.printStackTrace();
}
}
停止数据采样
private void stopIMU() {
try {
// 停止加速度计采样
if (null != mSensorAccel) {
mSensorAccel.stop();
}
// 停止陀螺仪采样
if (null != mSensorGyro) {
mSensorGyro.stop();
}
// 停止IMU数据刷新线程并释放
mIsRefreshIMUDataRunning = false;
if (null != mRefreshIMUDataThread) {
try {
mRefreshIMUDataThread.join(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
mRefreshIMUDataThread = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
资源释放
try {
// 释放加速度计配置
if (null != mAccelStreamProfile) {
mAccelStreamProfile.close();
mAccelStreamProfile = null;
}
// 释放陀螺仪配置
if (null != mGyroStreamProfile) {
mGyroStreamProfile.close();
mGyroStreamProfile = null;
}
// 释放Device
if (null != mDevice) {
mDevice.close();
mDevice = null;
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
mOBContext = null;
}
} catch (Exception e) {
e.printStackTrace();
}
多设备示例-MultiDevice¶
功能描述:本示例主要演示了对多设备进行操作。 首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 初始化SDK
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
int count = deviceList.getDeviceCount();
for (int i = 0; i < count; i++) {
// 创建设备
Device device = deviceList.getDevice(i);
// 获取DeviceInfo
DeviceInfo devInfo = device.getInfo();
// 获取设备名称
String name = devInfo.getName();
// 获取设备uid
String uid = devInfo.getUid();
// 获取设备usb接口类型
String usbType = devInfo.getUsbType();
// 释放DeviceInfo资源
devInfo.close();
runOnUiThread(() -> {
mDeviceControllerAdapter.addItem(new DeviceBean(name, uid, usbType, device));
});
}
// 释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
for (DeviceBean deviceBean : mDeviceBeanList) {
// 通过uid判断下线设备
if (deviceBean.getDeviceUid().equals(deviceList.getUid(0))) {
// 释放下线设备资源
deviceBean.getDevice().close();
runOnUiThread(() -> {
mDeviceControllerAdapter.deleteItem(deviceBean);
});
}
}
// 释放设备列表资源
deviceList.close();
} catch (Exception e) {
Log.w(TAG, "onDeviceDetach: " + e.getMessage());
}
}
});
在设备连接回调方法中创建设备列表
int count = deviceList.getDeviceCount();
for (int i = 0; i < count; i++) {
// 创建设备
Device device = deviceList.getDevice(i);
// 获取DeviceInfo
DeviceInfo devInfo = device.getInfo();
// 获取设备名称
String name = devInfo.getName();
// 获取设备uid
String uid = devInfo.getUid();
// 获取设备usb接口类型
String usbType = devInfo.getUsbType();
// 释放DeviceInfo资源
devInfo.close();
runOnUiThread(() -> {
mDeviceControllerAdapter.addItem(new DeviceBean(name, uid, usbType, device));
});
}
选择对应的设备开流
private void startStream(Sensor sensor, GLView glView) {
try {
// 获取传感器的流配置列表
StreamProfileList profileList = sensor.getStreamProfileList();
if (null == profileList) {
Log.w(TAG, "start stream failed, profileList is null !");
return;
}
switch (sensor.getType()) {
case DEPTH:
GLView depthGLView = glView;
// 通过StreamProfileList获取开流配置
StreamProfile depthProfile = profileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
if (null != depthProfile) {
// 通过指定配置开流
sensor.start(depthProfile, frame -> {
DepthFrame depthFrame = frame.as(FrameType.DEPTH);
byte[] bytes = new byte[depthFrame.getDataSize()];
depthFrame.getData(bytes);
// 渲染数据
depthGLView.update(bytes, depthFrame.getWidth(), depthFrame.getHeight(),
StreamType.DEPTH, depthFrame.getFormat());
// 释放frame资源
frame.close();
});
// 释放profile资源
depthProfile.close();
} else {
Log.w(TAG, "start depth stream failed, depthProfile is null!");
}
break;
case COLOR:
GLView colorGLView = glView;
// 通过StreamProfileList获取开流配置
StreamProfile colorProfile = profileList.getVideoStreamProfile(640, 480, Format.RGB888, 0);
if (null != colorProfile) {
// 通过指定配置开流
sensor.start(colorProfile, frame -> {
ColorFrame colorFrame = frame.as(FrameType.COLOR);
byte[] bytes = new byte[colorFrame.getDataSize()];
// 获取frame数据
colorFrame.getData(bytes);
// 渲染数据
colorGLView.update(bytes, colorFrame.getWidth(), colorFrame.getHeight(), StreamType.COLOR, Format.RGB888);
// 释放frame资源
frame.close();
});
// 释放profile资源
colorProfile.close();
} else {
Log.w(TAG, "start color stream failed, colorProfile is null!");
}
break;
case IR:
GLView irGLView = glView;
// 通过StreamProfileList获取开流配置
StreamProfile irProfile = profileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
if (null != irProfile) {
// 通过指定配置开流
sensor.start(irProfile, frame -> {
IRFrame irFrame = frame.as(FrameType.IR);
byte[] bytes = new byte[irFrame.getDataSize()];
// 获取frame数据
irFrame.getData(bytes);
// 渲染数据
irGLView.update(bytes, irFrame.getWidth(), irFrame.getHeight(),
StreamType.IR, irFrame.getFormat());
// frame资源
frame.close();
});
// 释放profile资源
irProfile.close();
} else {
Log.w(TAG, "start ir stream failed, irProfile is null!");
}
break;
}
// 释放profileList资源
profileList.close();
} catch (Exception e) {
Log.w(TAG, "startStream: " + e.getMessage());
}
}
对指定的设备关流指定sensor流
private void stopStream(Sensor sensor) {
try {
sensor.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
在设备断开连接回调中做对应的资源释放并刷新设备列表
try {
for (DeviceBean deviceBean : mDeviceBeanList) {
// 通过uid判断下线设备
if (deviceBean.getDeviceUid().equals(deviceList.getUid(0))) {
// 释放下线设备资源
deviceBean.getDevice().close();
runOnUiThread(() -> {
mDeviceControllerAdapter.deleteItem(deviceBean);
});
}
}
} catch (Exception e) {
Log.w(TAG, "onDeviceDetach: " + e.getMessage());
}
资源释放
try {
// 释放资源
for (DeviceBean deviceBean : mDeviceBeanList) {
try {
// 释放设备资源
deviceBean.getDevice().close();
} catch (Exception e) {
Log.w(TAG, "onDestroy: " + e.getMessage());
}
}
mDeviceBeanList.clear();
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
} catch (Exception e) {
e.printStackTrace();
}
点云示例-PointCloud¶
功能描述:本示例主要演示了连接设备开流 ,生成深度点云或RGBD点云并保存成ply格式文件。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.通过deviceList获取Device
mDevice = deviceList.getDevice(0);
// 3.通过Device创建Pipeline
mPipeline = new Pipeline(mDevice);
// 4.创建Config,用于配置pipeline开流
Config config = new Config();
// 5.获取彩色配置列表,并获取640x480 YUYV或者I420格式配置开流
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
VideoStreamProfile colorProfileTarget = null;
if (null != colorProfileList) {
colorProfileTarget = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == colorProfileTarget) {
colorProfileTarget = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
// 6.获取到指定彩色配置后使能配置
if (null != colorProfileTarget) {
config.enableStream(colorProfileTarget);
colorProfileTarget.close();
}
// 7.获取深度配置列表,并获取640x480 YUYV或者Y16格式配置开流
VideoStreamProfile depthProfileTarget = null;
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
if (null != depthProfileList) {
depthProfileTarget = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
depthProfileList.close();
}
// 8.获取到指定深度配置后使能配置
if (null != depthProfileTarget) {
config.enableStream(depthProfileTarget);
depthProfileTarget.close();
}
// 9.开启硬件D2C
config.setAlignMode(AlignMode.ALIGN_D2C_HW_ENABLE);
// 10.使用回调方式开流
mPipeline.start(config, mPointCloudFrameSetCallback);
// 11.启动点云异步处理线程
start();
// 12.通过Pipeline创建点云filter
mPointCloudFilter = new PointCloudFilter();
// 13.设置点云filter的格式
mPointCloudFilter.setPointFormat(mPointFormat);
// 14.获取相机内参并且将参数设置到点云filter中
CameraParamList cameraParamList = mDevice.getCalibrationCameraParamList();
CameraParam cameraParam = null;
if (null != cameraParamList) {
int count = cameraParamList.getCameraParamCount();
for (int i = 0; i < count; i++) {
cameraParam = cameraParamList.getCameraParam(i);
int depthW = cameraParam.getDepthIntrinsic().getWidth();
int depthH = cameraParam.getDepthIntrinsic().getHeight();
int colorW = cameraParam.getColorIntrinsic().getWidth();
int colorH = cameraParam.getColorIntrinsic().getHeight();
// 14.1.需要获取标定的分辨率比例与开流分辨率比例一致的内参
if ((depthW / depthH == 640 / 480) && (colorW / colorH == 640 / 480)) {
break;
}
}
cameraParamList.close();
}
mPointCloudFilter.setCameraParam(cameraParam);
// 15.释放config资源
config.close();
}
// 16.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.通过deviceList获取Device
mDevice = deviceList.getDevice(0);
// 3.通过Device创建Pipeline
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
// 4.创建Config,用于配置pipeline开流
Config config = new Config();
获取彩色流配置,并配置到Config,这里配置为640x480 YUYV格式或者是640x480 I420格式
// 5.获取彩色配置列表,并获取640x480 YUYV或者I420格式配置开流
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
VideoStreamProfile colorProfileTarget = null;
if (null != colorProfileList) {
colorProfileTarget = colorProfileList.getVideoStreamProfile(640, 480, Format.YUYV, 0);
if (null == colorProfileTarget) {
colorProfileTarget = colorProfileList.getVideoStreamProfile(640, 480, Format.I420, 0);
}
colorProfileList.close();
}
// 6.获取到指定彩色配置后使能配置
if (null != colorProfileTarget) {
config.enableStream(colorProfileTarget);
colorProfileTarget.close();
}
获取深度流配置,并配置到Config,这里配置为640x480 YUYV格式或者是Y16格式
// 7.获取深度配置列表,并获取640x480 YUYV或者Y16格式配置开流
VideoStreamProfile depthProfileTarget = null;
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
if (null != depthProfileList) {
depthProfileTarget = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
depthProfileList.close();
}
// 8.获取到指定深度配置后使能配置
if (null != depthProfileTarget) {
config.enableStream(depthProfileTarget);
depthProfileTarget.close();
}
判断设备是否支持硬件D2C并开启
// 9.开启硬件D2C
config.setAlignMode(AlignMode.ALIGN_D2C_HW_ENABLE);
创建Pipeline开流的回调方法
// Pipeline开流的回调
private FrameSetCallback mPointCloudFrameSetCallback = frameSet -> {
if (null != frameSet) {
if (mIsPointCloudRunning) {
if (null == mPointFrameSet) {
mPointFrameSet = frameSet;
return;
}
}
frameSet.close();
}
};
使用Config配置通过Pipeline回调方式开流
// 10.使用回调方式开流
mPipeline.start(config, mPointCloudFrameSetCallback);
启动点云异步处理线程
private void start() {
mIsPointCloudRunning = true;
if (null == mPointFilterThread) {
mPointFilterThread = new Thread(mPointFilterRunnable);
mPointFilterThread.start();
}
}
通过Pipeline创建点云filter,并设置点云filter的格式(如果需要保存深度点云,则需要将格式设置为Format.POINT,如果需要保存RGBD点云则需要将格式设置为Format.RGB_POINT)
// 12.通过Pipeline创建点云filter
mPointCloudFilter = new PointCloudFilter();
// 13.设置点云filter的格式
mPointCloudFilter.setPointFormat(mPointFormat);
获取相机内参并将参数设置到点云filter中
// 14.获取相机内参并且将参数设置到点云filter中
CameraParamList cameraParamList = mDevice.getCalibrationCameraParamList();
CameraParam cameraParam = null;
if (null != cameraParamList) {
int count = cameraParamList.getCameraParamCount();
for (int i = 0; i < count; i++) {
cameraParam = cameraParamList.getCameraParam(i);
int depthW = cameraParam.getDepthIntrinsic().getWidth();
int depthH = cameraParam.getDepthIntrinsic().getHeight();
int colorW = cameraParam.getColorIntrinsic().getWidth();
int colorH = cameraParam.getColorIntrinsic().getHeight();
// 14.1.需要获取标定的分辨率比例与开流分辨率比例一致的内参
if ((depthW / depthH == 640 / 480) && (colorW / colorH == 640 / 480)) {
break;
}
}
cameraParamList.close();
}
mPointCloudFilter.setCameraParam(cameraParam);
点云filter线程数据处理
while (mIsPointCloudRunning) {
try {
if (null != mPointFrameSet) {
Frame frame = null;
if (mPointFormat == Format.POINT) {
// 设置保存格式为深度点云
mPointCloudFilter.setPointFormat(Format.POINT);
} else {
// 设置保存格式为彩色点云
mPointCloudFilter.setPointFormat(Format.RGB_POINT);
}
// 点云filter处理生成对应的点云数据
frame = mPointCloudFilter.process(mPointFrameSet);
if (null != frame) {
// 获取点云帧
PointFrame pointFrame = frame.as(FrameType.POINTS);
if (mIsSavePoints) {
if (mPointFormat == Format.POINT) {
// 获取深度点云数据并保存,深度点云的数据大小为w * h * 3
float[] depthPoints = new float[pointFrame.getDataSize() / Float.BYTES];
pointFrame.getPointCloudData(depthPoints);
String depthPointsPath = mSdcardDir.toString() + "/points.ply";
FileUtils.savePointCloud(depthPointsPath, depthPoints);
runOnUiThread(new Runnable() {
@Override
public void run() {
mInfoTv.append("Save Path:" + depthPointsPath + "\n");
}
});
} else {
// 获取彩色点云数据并保存,彩色点云的数据大小为w * h * 6
float[] colorPoints = new float[pointFrame.getDataSize() / Float.BYTES];
pointFrame.getPointCloudData(colorPoints);
String colorPointsPath = mSdcardDir.toString() + "/rgb_points.ply";
FileUtils.saveRGBPointCloud(colorPointsPath, colorPoints);
runOnUiThread(new Runnable() {
@Override
public void run() {
mInfoTv.append("Save Path:" + colorPointsPath + "\n");
}
});
}
mIsSavePoints = false;
}
// 释放新生成的frame
frame.close();
}
// 释放原始数据frameSet
mPointFrameSet.close();
mPointFrameSet = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
保存深度点云数据
public static void savePointCloud(String fileName, float[] data) {
try {
File file = new File(fileName);
FileOutputStream fos = new FileOutputStream(file);
PrintWriter writer = new PrintWriter(fos);
writer.write("ply\n");
writer.write("format ascii 1.0\n");
writer.write("element vertex 307200\n");
writer.write("property float x\n");
writer.write("property float y\n");
writer.write("property float z\n");
writer.write("end_header\n");
writer.flush();
for (int i = 0; i < data.length; i += 3) {
writer.print(data[i]);
writer.print(" ");
writer.print(data[i + 1]);
writer.print(" ");
writer.print(data[i + 2]);
writer.print("\n");
}
writer.close();
fos.close();
} catch (Exception e) {
Log.e(TAG, "exception: " + e.getMessage());
}
}
保存彩色点云数据
public static void saveRGBPointCloud(String fileName, float[] data) {
try {
File file = new File(fileName);
FileOutputStream fos = new FileOutputStream(file);
PrintWriter writer = new PrintWriter(fos);
writer.write("ply\n");
writer.write("format ascii 1.0\n");
writer.write("element vertex 307200\n");
writer.write("property float x\n");
writer.write("property float y\n");
writer.write("property float z\n");
writer.write("property uchar red\n");
writer.write("property uchar green\n");
writer.write("property uchar blue\n");
writer.write("end_header\n");
writer.flush();
for (int i = 0; i < data.length; i += 6) {
writer.print(data[i]);
writer.print(" ");
writer.print(data[i + 1]);
writer.print(" ");
writer.print(data[i + 2]);
writer.print(" ");
writer.print((int) data[i + 3]);
writer.print(" ");
writer.print((int) data[i + 4]);
writer.print(" ");
writer.print((int) data[i + 5]);
writer.print("\n");
}
writer.close();
fos.close();
} catch (Exception e) {
Log.e(TAG, "exception: " + e.getMessage());
}
}
退出点云filter处理线程
private void stop() {
mIsPointCloudRunning = false;
if (null != mPointFilterThread) {
try {
mPointFilterThread.join(300);
} catch (InterruptedException e) {
}
mPointFilterThread = null;
}
}
资源释放
try {
// 停止Pipeline,并关闭
if (null != mPipeline) {
mPipeline.stop();
mPipeline.close();
mPipeline = null;
}
// 释放点云filter
if (null != mPointCloudFilter) {
try {
mPointCloudFilter.close();
} catch (Exception e) {
}
mPointCloudFilter = null;
}
// 释放Device
if (mDevice != null) {
mDevice.close();
mDevice = null;
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
mOBContext = null;
}
} catch (Exception e) {
e.printStackTrace();
}
存储示例-SaveToDisk¶
功能描述:本示例用于演示连接设备开流 , 获取彩色存储为png格式,深度存储为raw格式以及通过filter进行格式转换。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.初始化格式转换filter
mFormatConvertFilter = new FormatConvertFilter();
// 4.创建Pipeline配置
Config config = new Config();
// 5.获取彩色流配置,并配置到Config
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile colorStreamProfile = null;
if (null != colorProfileList) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.MJPG, 0);
colorProfileList.close();
}
if (null == colorStreamProfile) {
Log.e(TAG, "onDeviceAttach: get color stream profile failed !");
deviceList.close();
return;
}
// 6.通过获取到的彩色流配置使能彩色流
config.enableStream(colorStreamProfile);
// 7.获取深度流配置,并配置到Config
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile depthStreamProfile = null;
if (null != depthProfileList) {
depthStreamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
depthProfileList.close();
}
if (null == depthStreamProfile) {
Log.e(TAG, "onDeviceAttach: get depth stream profile failed !");
deviceList.close();
return;
}
// 8.通过获取到的深度流配置使能深度流
config.enableStream(depthStreamProfile);
// 9.使用Config开启Pipeline
mPipeline.start(config);
// 10.释放colorStreamProfile
colorStreamProfile.close();
// 11.释放depthStreamProfile
depthStreamProfile.close();
// 12.释放config资源
config.close();
// 13.创建获取Pipeline数据线程以及图片保存线程
start();
}
// 14.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
通过Pipeline初始化格式转换filter
// 3.初始化格式转换filter
mFormatConvertFilter = new FormatConvertFilter();
创建Pipeline配置
// 4.创建Pipeline配置
Config config = new Config();
获取彩色流配置,并配置到Config,这里配置为640x480 MJPG格式
// 5.获取彩色流配置,并配置到Config
StreamProfileList colorProfileList = mPipeline.getStreamProfileList(SensorType.COLOR);
StreamProfile colorStreamProfile = null;
if (null != colorProfileList) {
colorStreamProfile = colorProfileList.getVideoStreamProfile(640, 480, Format.MJPG, 0);
colorProfileList.close();
}
if (null == colorStreamProfile) {
Log.e(TAG, "onDeviceAttach: get color stream profile failed !");
deviceList.close();
return;
}
// 6.通过获取到的彩色流配置使能彩色流
config.enableStream(colorStreamProfile);
获取深度流配置,并配置到Config,这里配置为640x480 Y16格式
// 7.获取深度流配置,并配置到Config
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile depthStreamProfile = null;
if (null != depthProfileList) {
depthStreamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 0);
depthProfileList.close();
}
if (null == depthStreamProfile) {
Log.e(TAG, "onDeviceAttach: get depth stream profile failed !");
deviceList.close();
return;
}
// 8.通过获取到的深度流配置使能深度流
config.enableStream(depthStreamProfile);
使用Config配置通过Pipeline开流
// 9.使用Config开启Pipeline
mPipeline.start(config);
创建获取Pipeline数据线程以及图片保存线程
private void start() {
colorCount = 0;
depthCount = 0;
mIsStreamRunning = true;
mIsPicSavingRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamRunnable);
mStreamThread.start();
}
if (null == mPicSavingThread) {
mPicSavingThread = new Thread(mPicSavingRunnable);
mPicSavingThread.start();
}
}
数据流处理
int count = 0;
while (mIsStreamRunning) {
try {
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
if (null == frameSet) {
continue;
}
if (count < 5) {
frameSet.close();
count++;
continue;
}
// 获取彩色流数据
ColorFrame colorFrame = frameSet.getColorFrame();
if (null != colorFrame) {
mFormatConvertFilter.setFormatType(FormatConvertType.FORMAT_MJPEG_TO_RGB888);
Frame rgbFrame = mFormatConvertFilter.process(colorFrame);
FrameCopy frameT = copyToFrameT(rgbFrame.as(FrameType.VIDEO));
mFrameSaveQueue.offer(frameT);
colorFrame.close();
rgbFrame.close();
}
// 获取深度流数据
DepthFrame depthFrame = frameSet.getDepthFrame();
if (null != depthFrame) {
FrameCopy frameT = copyToFrameT(depthFrame);
mFrameSaveQueue.offer(frameT);
depthFrame.close();
}
// 释放数据集
frameSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
数据保存
while (mIsPicSavingRunning) {
try {
FrameCopy frameT = mFrameSaveQueue.poll(300, TimeUnit.MILLISECONDS);
if (null != frameT) {
Log.d(TAG, "colorCount :" + colorCount);
if (frameT.getStreamType() == FrameType.COLOR && colorCount < 5) {
FileUtils.saveImage(frameT);
colorCount++;
}
Log.d(TAG, "depthCount :" + depthCount);
if (frameT.getStreamType() == FrameType.DEPTH && depthCount < 5) {
FileUtils.saveImage(frameT);
depthCount++;
}
}
} catch (Exception e) {
}
if (colorCount == 5 && depthCount == 5) {
mIsPicSavingRunning = false;
break;
}
}
mFrameSaveQueue.clear();
退出数据处理线程和存图线程
private void stop() {
mIsStreamRunning = false;
mIsPicSavingRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(1000);
} catch (InterruptedException e) {
}
mStreamThread = null;
}
if (null != mPicSavingThread) {
try {
mPicSavingThread.join(1000);
} catch (InterruptedException e) {
}
mPicSavingThread = null;
}
}
资源释放
// 释放filter资源
if (null != mFormatConvertFilter) {
try {
mFormatConvertFilter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 停止Pipeline,并关闭
if (null != mPipeline) {
mPipeline.close();
mPipeline = null;
}
// 释放Device资源
if (null != mDevice) {
mDevice.close();
mDevice = null;
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
mOBContext = null;
}
传感器控制示例-SensorControl¶
功能描述:本示例主要演示了对device控制命令的操作、对Sensor控制命令的操作。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 2.初始化SDK
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
// 3.将获取到的设备添加到设备列表
mDeviceList.add(deviceList.getDevice(0));
// 4.更新设备列表
updateDeviceSpinnerList();
// 5.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
// 有设备断开连接,释放设备列表资源
for (Device device : mDeviceList) {
device.close();
}
mDeviceList.clear();
// 重新获取设备并更新设备列表
DeviceList curDeviceList = mOBContext.queryDevices();
for (int i = 0; i < curDeviceList.getDeviceCount(); i++) {
mDeviceList.add(curDeviceList.getDevice(i));
}
curDeviceList.close();
updateDeviceSpinnerList();
// 没有设备连接,清空传感器列表和属性列表
if (mDeviceList.size() <= 0) {
clearPropertySpinnerList();
}
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
设备连接回调方法(onDeviceAttach)处理
try {
// 3.将获取到的设备添加到设备列表
mDeviceList.add(deviceList.getDevice(0));
// 4.更新设备列表
updateDeviceSpinnerList();
// 5.释放设备列表资源
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
设备断开连接回调方法(onDeviceDetach)处理
try {
// 有设备断开连接,释放设备列表资源
for (Device device : mDeviceList) {
device.close();
}
mDeviceList.clear();
// 重新获取设备并更新设备列表
DeviceList curDeviceList = mOBContext.queryDevices();
for (int i = 0; i < curDeviceList.getDeviceCount(); i++) {
mDeviceList.add(curDeviceList.getDevice(i));
}
curDeviceList.close();
updateDeviceSpinnerList();
// 没有设备连接,清空传感器列表和属性列表
if (mDeviceList.size() <= 0) {
clearPropertySpinnerList();
}
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
根据选择的设备更新属性列表
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (parent.getId()) {
case R.id.spi_device:
// 设备切换,更新传属性列表
mSelectDevice = mDeviceList.get(position);
updatePropertySpinnerList();
String deviceName = mDeviceSp.getSelectedItem().toString();
addNewMessage("选择设备名:" + deviceName);
addNewMessage(getVersionInfo(mDeviceList.get(position)));
// 其他case
}
}
// 更新属性列表
private void updatePropertySpinnerList() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDevicePropertyMap.clear();
mPropertyNameList.clear();
try {
List<DevicePropertyInfo> devicePropertyList = mSelectDevice.getSupportedPropertyList();
for (DevicePropertyInfo deviceProperty : devicePropertyList) {
if (deviceProperty.getPropertyType() != PropertyType.STRUCT_PROPERTY
&& deviceProperty.getPermissionType() != PermissionType.OB_PERMISSION_DENY) {
mPropertyNameList.add(deviceProperty.getPropertyName());
mDevicePropertyMap.put(deviceProperty.getPropertyName(), deviceProperty);
}
}
addNewMessage("选择设备指令");
mPropertyAdapter.clear();
mPropertyAdapter.addAll(mPropertyNameList);
mPropertyAdapter.notifyDataSetChanged();
mPropertySp.setSelection(0, true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
根据选择的属性更新设置范围提示
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (parent.getId()) {
case R.id.spi_instructions:
// 指令切换
String instructionTypeName = mPropertySp.getSelectedItem().toString();
PermissionType permissionType = mDevicePropertyMap.get(instructionTypeName).getPermissionType();
addNewMessage("选择操作指令:" + instructionTypeName + " 读写权限:" + permissionType);
updateControlPanel(permissionType);
updateSetEditTextHint(instructionTypeName);
break;
// 其他case
}
}
根据选择的设备更新属性列表的方法
private void updatePropertySpinnerList() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDevicePropertyMap.clear();
mPropertyNameList.clear();
try {
List<DevicePropertyInfo> devicePropertyList = mSelectDevice.getSupportedPropertyList();
for (DevicePropertyInfo deviceProperty : devicePropertyList) {
if (deviceProperty.getPropertyType() != PropertyType.STRUCT_PROPERTY
&& deviceProperty.getPermissionType() != PermissionType.OB_PERMISSION_DENY) {
mPropertyNameList.add(deviceProperty.getPropertyName());
mDevicePropertyMap.put(deviceProperty.getPropertyName(), deviceProperty);
}
}
addNewMessage("选择设备指令");
mPropertyAdapter.clear();
mPropertyAdapter.addAll(mPropertyNameList);
mPropertyAdapter.notifyDataSetChanged();
mPropertySp.setSelection(0, true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
根据选择的属性更新属性的设置范围提示
private void updateSetEditTextHint(String instructionTypeName) {
mSetEt.setText("");
mGetTv.setText("");
try {
switch (mDevicePropertyMap.get(instructionTypeName).getPropertyType()) {
case INT_PROPERTY:
int minI = mSelectDevice.getMinRangeI(mDevicePropertyMap.get(instructionTypeName).getProperty());
int maxI = mSelectDevice.getMaxRangeI(mDevicePropertyMap.get(instructionTypeName).getProperty());
mSetEt.setHint("[" + minI + "-" + maxI + "]");
break;
case BOOL_PROPERTY:
mSetEt.setHint("[" + 0 + "-" + 1 + "]");
break;
case FLOAT_PROPERTY:
float minF = mSelectDevice.getMinRangeF(mDevicePropertyMap.get(instructionTypeName).getProperty());
float maxF = mSelectDevice.getMaxRangeF(mDevicePropertyMap.get(instructionTypeName).getProperty());
mSetEt.setHint("[" + minF + "-" + maxF + "]");
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
设置属性
try {
String setValue = mSetEt.getText().toString();
// 设置设备指令
DevicePropertyInfo devProperty = mDevicePropertyMap.get(mPropertySp.getSelectedItem().toString());
switch (devProperty.getPropertyType()) {
case INT_PROPERTY:
//曝光和增益需要关闭AE才能调节, 亮度需要打开AE才能调节, 白平衡(色温)需要关闭自动白平衡才能调节
if (devProperty.getProperty() == DeviceProperty.OB_PROP_COLOR_EXPOSURE_INT
|| devProperty.getProperty() == DeviceProperty.OB_PROP_COLOR_GAIN_INT) { //曝光或增益
//获取自动曝光状态
boolean propertyExposureBool = false;
try {
propertyExposureBool = mSelectDevice.getPropertyValueB(DeviceProperty.OB_PROP_COLOR_AUTO_EXPOSURE_BOOL);
} catch (Exception e) {
}
Log.d(TAG, "propertyExposureBool:" + propertyExposureBool);
if (propertyExposureBool) {
showToast("自动曝光未关闭,不能设置曝光或增益");
return;
}
}
if (devProperty.getProperty() == DeviceProperty.OB_PROP_COLOR_BRIGHTNESS_INT) { //亮度
//获取自动曝光状态
boolean propertyExposureBool = mSelectDevice.getPropertyValueB(DeviceProperty.OB_PROP_COLOR_AUTO_EXPOSURE_BOOL);
Log.d(TAG, "propertyExposureBool:" + propertyExposureBool);
if (!propertyExposureBool) {
showToast("自动曝光未开启,不能设置亮度");
return;
}
}
if (devProperty.getProperty() == DeviceProperty.OB_PROP_COLOR_WHITE_BALANCE_INT) { //白平衡
//获取自动白平衡状态
boolean propertyWhiteBool = mSelectDevice.getPropertyValueB(DeviceProperty.OB_PROP_COLOR_AUTO_WHITE_BALANCE_BOOL);
Log.d(TAG, "propertyWhiteBool:" + propertyWhiteBool);
if (propertyWhiteBool) {
showToast("自动白平衡未关闭,不能设置白平衡");
return;
}
}
mSelectDevice.setPropertyValueI(devProperty.getProperty(), Integer.parseInt(setValue));
break;
case BOOL_PROPERTY:
// 0:false 1:true
mSelectDevice.setPropertyValueB(devProperty.getProperty(), ("1".equals(setValue) ? true : false));
break;
case FLOAT_PROPERTY:
mSelectDevice.setPropertyValueF(devProperty.getProperty(), Float.parseFloat(setValue));
break;
}
} catch (Exception e) {
e.printStackTrace();
}
获取属性
try {
// 获取设备指令
DevicePropertyInfo devProperty = mDevicePropertyMap.get(mPropertySp.getSelectedItem().toString());
switch (devProperty.getPropertyType()) {
case INT_PROPERTY:
int valueI = mSelectDevice.getPropertyValueI(devProperty.getProperty());
mGetTv.setText(Integer.toString(valueI));
break;
case BOOL_PROPERTY:
boolean valueB = mSelectDevice.getPropertyValueB(devProperty.getProperty());
mGetTv.setText(Boolean.toString(valueB));
break;
case FLOAT_PROPERTY:
float valueF = mSelectDevice.getPropertyValueF(devProperty.getProperty());
mGetTv.setText(Float.toString(valueF));
break;
}
} catch (Exception e) {
e.printStackTrace();
}
资源释放
private void release() {
try {
// 设备列表资源释放
for (Device device : mDeviceList) {
device.close();
}
mDeviceList.clear();
// OBContext资源释放
if (null != mOBContext) {
mOBContext.close();
mOBContext = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
录制与回放示例-Recorder & Playback¶
功能描述: :连接设备开流 , 录制当前视频流到文件,载入视频文件进行回放。
首先需要创建一个Context,用于获取设备信息列表和创建设备
private OBContext mOBContext;
初始化SDK,并监听设备变化
// 1.初始化SDK, 并监听设备变化
mOBContext = new OBContext(getApplicationContext(), new DeviceChangedCallback() {
@Override
public void onDeviceAttach(DeviceList deviceList) {
try {
if (null == mPipeline) {
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
// 3.更新设备信息ui
updateDeviceInfoView(false);
// 4.创建Pipeline配置
mConfig = new Config();
// 5.获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile streamProfile = null;
if (null != depthProfileList) {
streamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (streamProfile == null) {
return;
}
// 6.使能深度流配置
mConfig.enableStream(streamProfile);
// 7.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, true);
}
// 8.开流
mPipeline.start(mConfig);
// 9.释放streamProfile
streamProfile.close();
// 10.创建获取Pipeline数据线程
start();
}
// 11.释放deviceList
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onDeviceDetach(DeviceList deviceList) {
try {
release();
updateCtlPanel(mRecordCtlPanelLL, View.VISIBLE);
updateCtlPanel(mPlaybackCtlPanelLL, View.VISIBLE);
deviceList.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
创建设备并通过设备创建Pipeline
// 2.创建Device, 并通过Device初始化Pipeline
mDevice = deviceList.getDevice(0);
mPipeline = new Pipeline(mDevice);
创建Pipeline配置
// 4.创建Pipeline配置
mConfig = new Config();
获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
// 5.获取深度流配置,并配置到Config,这里配置的为640x480 Y16格式
StreamProfileList depthProfileList = mPipeline.getStreamProfileList(SensorType.DEPTH);
StreamProfile streamProfile = null;
if (null != depthProfileList) {
streamProfile = depthProfileList.getVideoStreamProfile(640, 480, Format.Y16, 30);
depthProfileList.close();
}
if (streamProfile == null) {
return;
}
// 6.使能深度流配置
mConfig.enableStream(streamProfile);
通过Device属性接口设置镜像
// 7.设置镜像
if (mDevice.isPropertySupported(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, PermissionType.OB_PERMISSION_WRITE)) {
mDevice.setPropertyValueB(DeviceProperty.OB_PROP_DEPTH_MIRROR_BOOL, true);
}
使用Config配置通过Pipeline开流,并释放局部资源
// 8.开流
mPipeline.start(mConfig);
// 9.释放streamProfile
streamProfile.close();
开启数据流预览线程
private void start() {
mIsStreamRunning = true;
if (null == mStreamThread) {
mStreamThread = new Thread(mStreamPrevRunnable);
mStreamThread.start();
}
}
预览线程
// 预览线程
private Runnable mStreamPrevRunnable = () -> {
while (mIsStreamRunning) {
try {
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPipeline.waitForFrameSet(100);
if (null == frameSet) {
continue;
}
// 获取深度流数据
if (!mIsPlaying) {
DepthFrame frame = frameSet.getDepthFrame();
if (frame != null) {
// 获取深度数据并进行渲染
byte[] frameData = new byte[frame.getDataSize()];
frame.getData(frameData);
synchronized (mSync) {
mDepthGLView.update(frameData, frame.getWidth(), frame.getHeight(), StreamType.DEPTH, frame.getFormat());
}
// 释放深度数据帧
frame.close();
}
}
// 释放数据集
frameSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
};
定义录制文件保存路径
private static final String BAG_FILE_PATH = "/sdcard/Orbbec/recorder.bag";
开始录制
private void startRecord() {
try {
if (!mIsRecording) {
if (null != mPipeline) {
// 开始录制
mPipeline.startRecord(BAG_FILE_PATH);
mIsRecording = true;
updateCtlPanel(mPlaybackCtlPanelLL, View.INVISIBLE);
} else {
Log.w(TAG, "mPipeline is null !");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
停止录制
private void stopRecord() {
try {
if (mIsRecording) {
mIsRecording = false;
if (null != mPipeline) {
// 停止录制
mPipeline.stopRecord();
}
updateCtlPanel(mPlaybackCtlPanelLL, View.VISIBLE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
停止数据流预览线程
private void stop() {
mIsStreamRunning = false;
if (null != mStreamThread) {
try {
mStreamThread.join(300);
} catch (InterruptedException e) {
}
mStreamThread = null;
}
}
定义回放状态回调
private MediaStateCallback mMediaStateCallback = new MediaStateCallback() {
@Override
public void onState(MediaState state) {
if (state == MediaState.OB_MEDIA_END) {
stopPlayback();
}
}
};
定义回放线程的Runnable
while (mIsPlaying) {
try {
// 等待100ms后如果获取不到,则超时
FrameSet frameSet = mPlaybackPipe.waitForFrameSet(100);
if (null == frameSet) {
continue;
}
// 获取深度流数据
DepthFrame depthFrame = frameSet.getDepthFrame();
if (null != depthFrame) {
// 获取深度数据并进行渲染
byte[] frameData = new byte[depthFrame.getDataSize()];
depthFrame.getData(frameData);
synchronized (mSync) {
mDepthGLView.update(frameData, depthFrame.getWidth(), depthFrame.getHeight(), StreamType.DEPTH, depthFrame.getFormat());
}
// 释放深度数据帧
depthFrame.close();
}
// 释放数据集
frameSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
开始回放
private void startPlayback() {
try {
if (!FileUtils.isFileExists(BAG_FILE_PATH)) {
Toast.makeText(RecordPlaybackActivity.this, "File not found!", Toast.LENGTH_LONG).show();
return;
}
if (!mIsPlaying) {
mIsPlaying = true;
// 释放Playback资源
if (null != mPlayback) {
mPlayback.close();
mPlayback = null;
}
// 创建回放pipeline
if (null != mPlaybackPipe) {
mPlaybackPipe.close();
mPlaybackPipe = null;
}
mPlaybackPipe = new Pipeline(BAG_FILE_PATH);
// 通过回放Pipeline获取回放器
mPlayback = mPlaybackPipe.getPlayback();
// 设置回放状态回调
mPlayback.setMediaStateCallback(mMediaStateCallback);
// 开始回放
mPlaybackPipe.start(null);
// 创建回放线程
if (null == mPlaybackThread) {
mPlaybackThread = new Thread(mPlaybackRunnable);
mPlaybackThread.start();
}
// 更新UI
updateDeviceInfoView(true);
updateCtlPanel(mRecordCtlPanelLL, View.INVISIBLE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
停止回放
private void stopPlayback() {
try {
if (mIsPlaying) {
mIsPlaying = false;
// 停止回放线程
if (null != mPlaybackThread) {
try {
mPlaybackThread.join(300);
} catch (InterruptedException e) {
}
mPlaybackThread = null;
}
// 停止回放
if (null != mPlaybackPipe) {
mPlaybackPipe.stop();
}
// 更新UI
updateDeviceInfoView(false);
updateCtlPanel(mRecordCtlPanelLL, View.VISIBLE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
释放资源
try {
// 释放回放器
if (null != mPlayback) {
mPlayback.close();
mPlayback = null;
}
// 释放回放pipeline
if (null != mPlaybackPipe) {
mPlaybackPipe.close();
mPlaybackPipe = null;
}
// 释放config
if (null != mConfig) {
mConfig.close();
mConfig = null;
}
// 释放预览pipeline
if (null != mPipeline) {
mPipeline.close();
mPipeline = null;
}
// 释放Device
if (null != mDevice) {
mDevice.close();
mDevice = null;
}
// 释放SDK
if (null != mOBContext) {
mOBContext.close();
}
// 释放渲染窗口资源
if (mDepthGLView != null) {
mDepthGLView.release();
}
} catch (Exception e) {
e.printStackTrace();
}