代码提交
This commit is contained in:
parent
bf8e9b02e6
commit
909ffb0815
117446
Log/OrbbecSDK.log.txt
117446
Log/OrbbecSDK.log.txt
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,10 +4,17 @@
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['app.py'],
|
||||
['app_simple.py'],
|
||||
pathex=[],
|
||||
binaries=[
|
||||
('dll/k4a.dll', '.'), # 包含K4A动态库
|
||||
('dll/femtobolt/bin/k4a.dll', '.'), # K4A动态库
|
||||
('dll/femtobolt/bin/k4arecord.dll', '.'), # K4A录制库
|
||||
('dll/femtobolt/bin/depthengine_2_0.dll', '.'), # 深度引擎
|
||||
('dll/femtobolt/bin/OrbbecSDK.dll', '.'), # Orbbec SDK
|
||||
('dll/femtobolt/bin/ob_usb.dll', '.'), # Orbbec USB库
|
||||
('dll/femtobolt/bin/live555.dll', '.'), # Live555库
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库
|
||||
('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', '.'), # Orbbec配置文件
|
||||
],
|
||||
datas=[
|
||||
('..\config.ini', '.'), # 配置文件
|
||||
|
@ -18,10 +18,17 @@ def create_spec_file():
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['app.py'],
|
||||
['app_simple.py'],
|
||||
pathex=[],
|
||||
binaries=[
|
||||
('dll/k4a.dll', '.'), # 包含K4A动态库
|
||||
('dll/femtobolt/bin/k4a.dll', '.'), # K4A动态库
|
||||
('dll/femtobolt/bin/k4arecord.dll', '.'), # K4A录制库
|
||||
('dll/femtobolt/bin/depthengine_2_0.dll', '.'), # 深度引擎
|
||||
('dll/femtobolt/bin/OrbbecSDK.dll', '.'), # Orbbec SDK
|
||||
('dll/femtobolt/bin/ob_usb.dll', '.'), # Orbbec USB库
|
||||
('dll/femtobolt/bin/live555.dll', '.'), # Live555库
|
||||
('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库
|
||||
('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', '.'), # Orbbec配置文件
|
||||
],
|
||||
datas=[
|
||||
('..\\config.ini', '.'), # 配置文件
|
||||
|
@ -23,6 +23,15 @@ from typing import Dict, List, Optional, Any, Tuple
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
|
||||
# matplotlib相关导入(用于深度图渲染)
|
||||
try:
|
||||
from matplotlib.colors import LinearSegmentedColormap
|
||||
import matplotlib.pyplot as plt
|
||||
MATPLOTLIB_AVAILABLE = True
|
||||
except ImportError:
|
||||
MATPLOTLIB_AVAILABLE = False
|
||||
print("警告: matplotlib库未安装,将使用默认深度图渲染")
|
||||
|
||||
# 数据库管理
|
||||
# from backend.app import get_detection_sessions
|
||||
from database import DatabaseManager
|
||||
@ -144,20 +153,20 @@ class DeviceManager:
|
||||
logger.warning('数据库管理器未初始化,使用默认摄像头索引0')
|
||||
|
||||
# 尝试连接指定索引的摄像头
|
||||
self.camera = cv2.VideoCapture(device_index)
|
||||
if self.camera.isOpened():
|
||||
# 设置摄像头参数
|
||||
self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
||||
self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
|
||||
self.camera.set(cv2.CAP_PROP_FPS, 30)
|
||||
# 设置缓冲区大小为1,避免帧积累
|
||||
self.camera.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
# self.camera = cv2.VideoCapture(device_index)
|
||||
# if self.camera.isOpened():
|
||||
# # 设置摄像头参数
|
||||
# self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
||||
# self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
|
||||
# self.camera.set(cv2.CAP_PROP_FPS, 30)
|
||||
# # 设置缓冲区大小为1,避免帧积累
|
||||
# self.camera.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
|
||||
self.device_status['camera'] = True
|
||||
logger.info(f'摄像头初始化成功,设备索引: {device_index}')
|
||||
else:
|
||||
logger.warning(f'摄像头连接失败,设备索引: {device_index}')
|
||||
self.camera = None
|
||||
self.device_status['camera'] = True
|
||||
# logger.info(f'摄像头初始化成功,设备索引: {device_index}')
|
||||
# else:
|
||||
# logger.warning(f'摄像头连接失败,设备索引: {device_index}')
|
||||
# self.camera = None
|
||||
except Exception as e:
|
||||
logger.error(f'摄像头初始化异常: {e}')
|
||||
self.camera = None
|
||||
@ -172,38 +181,17 @@ class DeviceManager:
|
||||
|
||||
try:
|
||||
# 初始化pykinect_azure库(优先使用指定SDK路径)
|
||||
sdk_initialized = False
|
||||
|
||||
# 首先尝试手动指定路径(优先级最高)
|
||||
sdk_paths = self._get_femtobolt_sdk_paths()
|
||||
for sdk_path in sdk_paths:
|
||||
if os.path.exists(sdk_path):
|
||||
try:
|
||||
logger.info(f'尝试使用FemtoBolt SDK路径: {sdk_path}')
|
||||
pykinect.initialize_libraries(track_body=False, module_k4a_path=sdk_path)
|
||||
logger.info(f'✓ 成功使用FemtoBolt SDK: {sdk_path}')
|
||||
sdk_initialized = True
|
||||
break
|
||||
except Exception as e:
|
||||
logger.warning(f'✗ FemtoBolt SDK路径失败: {sdk_path} - {e}')
|
||||
continue
|
||||
|
||||
# 如果手动指定路径失败,尝试自动检测
|
||||
if not sdk_initialized:
|
||||
try:
|
||||
logger.info('尝试自动检测FemtoBolt SDK...')
|
||||
pykinect.initialize_libraries(track_body=False)
|
||||
logger.info('✓ 自动检测FemtoBolt SDK成功')
|
||||
sdk_initialized = True
|
||||
except Exception as e:
|
||||
logger.warning(f'✗ 自动检测失败: {e}')
|
||||
|
||||
if not sdk_initialized:
|
||||
logger.warning('无法初始化FemtoBolt深度相机SDK,功能将不可用')
|
||||
self.femtobolt_camera = None
|
||||
self.device_status['femtobolt'] = False
|
||||
return
|
||||
|
||||
# 配置FemtoBolt设备参数
|
||||
self.femtobolt_config = pykinect.default_configuration
|
||||
logger.info('FemtoBolt配置参数。。。。。。。。。。。。。。。。。')
|
||||
@ -212,43 +200,44 @@ class DeviceManager:
|
||||
import configparser
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__), '..', 'config.ini'))
|
||||
color_res_str = config.get('DEFAULT', 'femtobolt_color_resolution', fallback='1080P')
|
||||
depth_range_min = config.getint('DEFAULT', 'femtobolt_depth_range_min', fallback=500)
|
||||
depth_range_max = config.getint('DEFAULT', 'femtobolt_depth_range_max', fallback=4500)
|
||||
# color_res_str = config.get('DEFAULT', 'femtobolt_color_resolution', fallback='1080P')
|
||||
# depth_range_min = config.getint('DEFAULT', 'femtobolt_depth_range_min', fallback=500)
|
||||
# depth_range_max = config.getint('DEFAULT', 'femtobolt_depth_range_max', fallback=4500)
|
||||
|
||||
# 解析分辨率配置,分为宽度和高度
|
||||
resolution_map = {
|
||||
'1024x1024': (1024, 1024),
|
||||
'1920x1080': (1920, 1080),
|
||||
'1280x720': (1280, 720),
|
||||
'720x720': (720, 720)
|
||||
}
|
||||
width, height = resolution_map.get(color_res_str, (1920, 1080))
|
||||
# # 解析分辨率配置,分为宽度和高度
|
||||
# resolution_map = {
|
||||
# '1024x1024': (1024, 1024),
|
||||
# '1920x1080': (1920, 1080),
|
||||
# '1280x720': (1280, 720),
|
||||
# '720x720': (720, 720)
|
||||
# }
|
||||
# width, height = resolution_map.get(color_res_str, (1920, 1080))
|
||||
# 假设SDK支持设置宽高参数,示例代码如下(需根据实际SDK调整)
|
||||
if hasattr(self.femtobolt_config, 'color_resolution_width') and hasattr(self.femtobolt_config, 'color_resolution_height'):
|
||||
self.femtobolt_config.color_resolution_width = width
|
||||
self.femtobolt_config.color_resolution_height = height
|
||||
else:
|
||||
logger.info('FemtoBolt存在分辨率参数。。。。。。。。。。。。。。。。。')
|
||||
# 兼容原有枚举设置
|
||||
if color_res_str == '720P':
|
||||
self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_720P
|
||||
elif color_res_str == '1080P':
|
||||
self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_1080P
|
||||
else:
|
||||
self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_1080P
|
||||
# if hasattr(self.femtobolt_config, 'color_resolution_width') and hasattr(self.femtobolt_config, 'color_resolution_height'):
|
||||
# self.femtobolt_config.color_resolution_width = width
|
||||
# self.femtobolt_config.color_resolution_height = height
|
||||
# else:
|
||||
# logger.info('FemtoBolt存在分辨率参数。。。。。。。。。。。。。。。。。')
|
||||
# # 兼容原有枚举设置
|
||||
# if color_res_str == '720P':
|
||||
# self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_720P
|
||||
# elif color_res_str == '1080P':
|
||||
# self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_1080P
|
||||
# else:
|
||||
# self.femtobolt_config.color_resolution = pykinect.K4A_COLOR_RESOLUTION_1080P
|
||||
|
||||
# self.femtobolt_config.depth_mode = pykinect.K4A_DEPTH_MODE_WFOV_2X2BINNED
|
||||
self.femtobolt_config.depth_mode = pykinect.K4A_DEPTH_MODE_NFOV_UNBINNED
|
||||
self.femtobolt_config.camera_fps = pykinect.K4A_FRAMES_PER_SECOND_30
|
||||
self.femtobolt_config.synchronized_images_only = True
|
||||
# self.femtobolt_config.depth_mode = pykinect.K4A_DEPTH_MODE_NFOV_UNBINNED
|
||||
self.femtobolt_config.camera_fps = pykinect.K4A_FRAMES_PER_SECOND_15
|
||||
self.femtobolt_config.synchronized_images_only = False
|
||||
self.femtobolt_config.color_resolution = 0
|
||||
# 视效范围参数示例,假设SDK支持depth_range_min和depth_range_max
|
||||
|
||||
# 直接尝试启动设备(pykinect_azure库没有设备数量检测API)
|
||||
logger.info('准备启动FemtoBolt设备...')
|
||||
# logger.info('准备启动FemtoBolt设备...')
|
||||
|
||||
# 启动FemtoBolt设备
|
||||
logger.info('尝试启动FemtoBolt设备...')
|
||||
logger.info(f'尝试启动FemtoBolt设备...,参数详情是{self.femtobolt_config}')
|
||||
self.femtobolt_camera = pykinect.start_device(config=self.femtobolt_config)
|
||||
if self.femtobolt_camera:
|
||||
self.device_status['femtobolt'] = True
|
||||
@ -272,41 +261,12 @@ class DeviceManager:
|
||||
def _get_femtobolt_sdk_paths(self) -> List[str]:
|
||||
"""获取FemtoBolt SDK可能的路径列表"""
|
||||
import platform
|
||||
|
||||
sdk_paths = []
|
||||
|
||||
if platform.system() == "Windows":
|
||||
# 优先使用Orbbec SDK K4A Wrapper(与azure_kinect_image_example.py一致)
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
dll_path = os.path.join(base_dir, "dll", "bin", "k4a.dll")
|
||||
orbbec_paths = []
|
||||
if os.path.exists(dll_path):
|
||||
orbbec_paths.append(dll_path)
|
||||
# orbbec_paths = [
|
||||
# r"D:\BodyBalanceEvaluation\backend\dll\bin\k4a.dll",
|
||||
# ]
|
||||
# Azure Kinect SDK标准安装路径(备用)
|
||||
standard_paths = [
|
||||
r"C:\Program Files\Azure Kinect SDK v1.4.1\sdk\windows-desktop\amd64\release\bin\k4a.dll",
|
||||
r"C:\Program Files\Azure Kinect SDK v1.4.0\sdk\windows-desktop\amd64\release\bin\k4a.dll",
|
||||
r"C:\Program Files\Azure Kinect SDK v1.4.2\sdk\windows-desktop\amd64\release\bin\k4a.dll",
|
||||
]
|
||||
|
||||
# 优先检查Orbbec路径
|
||||
for path in orbbec_paths:
|
||||
if os.path.exists(path):
|
||||
sdk_paths.append(path)
|
||||
|
||||
# 然后检查标准路径
|
||||
for path in standard_paths:
|
||||
if os.path.exists(path):
|
||||
sdk_paths.append(path)
|
||||
|
||||
# 项目内的dll目录
|
||||
project_dll_path = os.path.join(os.path.dirname(__file__), "dll", "k4a.dll")
|
||||
if os.path.exists(project_dll_path):
|
||||
sdk_paths.append(project_dll_path)
|
||||
|
||||
dll_path = os.path.join(base_dir, "dll","femtobolt","bin", "k4a.dll")
|
||||
sdk_paths.append(dll_path)
|
||||
return sdk_paths
|
||||
|
||||
def _init_imu(self):
|
||||
@ -513,16 +473,16 @@ class DeviceManager:
|
||||
|
||||
# 创建数据存储目录
|
||||
data_dir = Path(f'data/patients/{patient_id}/{session_id}/{timestamp}')
|
||||
# data_dir.mkdir(parents=True, exist_ok=True)
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# # 设置目录权限为777(完全权限)
|
||||
# try:
|
||||
# import os
|
||||
# import stat
|
||||
# os.chmod(str(data_dir), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 777权限
|
||||
# logger.debug(f"已设置目录权限为777: {data_dir}")
|
||||
# except Exception as perm_error:
|
||||
# logger.warning(f"设置目录权限失败: {perm_error},但目录创建成功")
|
||||
# 设置目录权限为777(完全权限)
|
||||
try:
|
||||
import os
|
||||
import stat
|
||||
os.chmod(str(data_dir), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 777权限
|
||||
logger.debug(f"已设置目录权限为777: {data_dir}")
|
||||
except Exception as perm_error:
|
||||
logger.warning(f"设置目录权限失败: {perm_error},但目录创建成功")
|
||||
|
||||
# 初始化数据字典
|
||||
data = {
|
||||
@ -749,22 +709,247 @@ class DeviceManager:
|
||||
logger.error(f'停止压力传感器数据推流失败: {e}')
|
||||
return False
|
||||
|
||||
# def _femtobolt_streaming_thread(self):
|
||||
# import matplotlib
|
||||
# matplotlib.use("Agg") # 无GUI后端
|
||||
# import matplotlib.pyplot as plt
|
||||
# from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
|
||||
# from matplotlib.colors import LinearSegmentedColormap
|
||||
|
||||
# frame_count = 0
|
||||
|
||||
# try:
|
||||
# # 读取一次配置,避免每帧IO
|
||||
# config = configparser.ConfigParser()
|
||||
# config.read('config.ini', encoding='utf-8')
|
||||
# try:
|
||||
# depth_range_min = int(config.get('DEFAULT', 'femtobolt_depth_range_min', fallback='1400'))
|
||||
# depth_range_max = int(config.get('DEFAULT', 'femtobolt_depth_range_max', fallback='1900'))
|
||||
# except Exception:
|
||||
# depth_range_min = None
|
||||
# depth_range_max = None
|
||||
|
||||
# # 如果可以用matplotlib,提前初始化绘图对象
|
||||
# if MATPLOTLIB_AVAILABLE and depth_range_min is not None and depth_range_max is not None:
|
||||
# colors = ['fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue'] * 4
|
||||
# mcmap = LinearSegmentedColormap.from_list("custom_cmap", colors)
|
||||
|
||||
# # 创建独立figure和axes
|
||||
# fig, ax = plt.subplots(figsize=(7, 7))
|
||||
# canvas = FigureCanvas(fig)
|
||||
|
||||
# # 灰色背景(假设分辨率不会超过)
|
||||
# max_h, max_w = 1080, 1920
|
||||
# background = np.ones((max_h, max_w)) * 0.5
|
||||
# ax.imshow(background, origin='lower', cmap='gray', alpha=0.3)
|
||||
# ax.grid(True, which='both', axis='both',
|
||||
# color='white', linestyle='-', linewidth=1, zorder=0)
|
||||
# ax.set_axis_off()
|
||||
# plt.tight_layout(pad=0)
|
||||
|
||||
# contour = None # 用于保存等高线对象
|
||||
|
||||
# while self.femtobolt_streaming and not self.streaming_stop_event.is_set():
|
||||
# if self.femtobolt_camera and self.socketio:
|
||||
# try:
|
||||
# capture = self.femtobolt_camera.update()
|
||||
# if capture is not None:
|
||||
# ret, depth_image = capture.get_depth_image()
|
||||
# if ret and depth_image is not None:
|
||||
# if MATPLOTLIB_AVAILABLE and depth_range_min is not None and depth_range_max is not None:
|
||||
# # 数据过滤
|
||||
# depth_image = depth_image.copy()
|
||||
# depth_image[(depth_image > depth_range_max) |
|
||||
# (depth_image < depth_range_min)] = 0
|
||||
# depth_masked = np.ma.masked_equal(depth_image, 0)
|
||||
|
||||
# # 删除旧等高线
|
||||
# if contour:
|
||||
# for coll in contour.collections:
|
||||
# coll.remove()
|
||||
|
||||
# # 绘制新等高线
|
||||
# contour = ax.contourf(
|
||||
# depth_masked,
|
||||
# levels=200,
|
||||
# cmap=mcmap,
|
||||
# vmin=depth_range_min,
|
||||
# vmax=depth_range_max,
|
||||
# origin='upper',
|
||||
# zorder=2
|
||||
# )
|
||||
|
||||
# # 渲染到numpy
|
||||
# canvas.draw()
|
||||
# img = np.frombuffer(canvas.tostring_rgb(), dtype=np.uint8)
|
||||
# img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
|
||||
# depth_colored = img
|
||||
# else:
|
||||
# # OpenCV伪彩模式
|
||||
# depth_normalized = np.clip(depth_image, depth_range_min, depth_range_max)
|
||||
# depth_normalized = ((depth_normalized - depth_range_min) /
|
||||
# (depth_range_max - depth_range_min) * 255).astype(np.uint8)
|
||||
# depth_colored = cv2.applyColorMap(depth_normalized, cv2.COLORMAP_JET)
|
||||
# mask_outside = (depth_image < depth_range_min) | (depth_image > depth_range_max)
|
||||
# depth_colored[mask_outside] = [0, 0, 0]
|
||||
|
||||
# # 裁剪
|
||||
# height, width = depth_colored.shape[:2]
|
||||
# target_width = height // 2
|
||||
# if width > target_width:
|
||||
# left = (width - target_width) // 2
|
||||
# right = left + target_width
|
||||
# depth_colored = depth_colored[:, left:right]
|
||||
|
||||
# # 缓存帧
|
||||
# self._save_frame_to_cache(depth_colored.copy(), 'femtobolt')
|
||||
|
||||
# # 发送
|
||||
# success, buffer = cv2.imencode('.jpg', depth_colored, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
|
||||
# if success and self.socketio:
|
||||
# jpg_as_text = base64.b64encode(buffer).decode('utf-8')
|
||||
# self.socketio.emit('depth_camera_frame', {
|
||||
# 'image': jpg_as_text,
|
||||
# 'frame_id': frame_count,
|
||||
# 'timestamp': time.time()
|
||||
# })
|
||||
# frame_count += 1
|
||||
# else:
|
||||
# time.sleep(0.01)
|
||||
# except Exception as e:
|
||||
# logger.debug(f'FemtoBolt帧推送失败: {e}')
|
||||
# time.sleep(0.1)
|
||||
|
||||
# time.sleep(1 / 30) # 30 FPS
|
||||
# except Exception as e:
|
||||
# logger.debug(f'FemtoBolt推流线程异常: {e}')
|
||||
# finally:
|
||||
# self.femtobolt_streaming = False
|
||||
|
||||
# def _femtobolt_streaming_thread(self):
|
||||
# """FemtoBolt深度相机推流线程(优化版本)"""
|
||||
# frame_count = 0
|
||||
# import matplotlib
|
||||
# matplotlib.use("Agg") # 使用无GUI的Agg后端,加速渲染
|
||||
# import matplotlib.pyplot as plt
|
||||
# from matplotlib.colors import LinearSegmentedColormap
|
||||
# from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
|
||||
# try:
|
||||
# # 读取深度范围配置(只读一次)
|
||||
# config = configparser.ConfigParser()
|
||||
# config.read('config.ini')
|
||||
# try:
|
||||
# depth_range_min = int(config.get('DEFAULT', 'femtobolt_depth_range_min', fallback='1400'))
|
||||
# depth_range_max = int(config.get('DEFAULT', 'femtobolt_depth_range_max', fallback='1900'))
|
||||
# except Exception:
|
||||
# depth_range_min = None
|
||||
# depth_range_max = None
|
||||
|
||||
# # 如果启用matplotlib模式,提前准备绘图对象
|
||||
# if MATPLOTLIB_AVAILABLE and depth_range_min is not None and depth_range_max is not None:
|
||||
# colors = ['fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue'] * 4
|
||||
# mcmap = LinearSegmentedColormap.from_list("custom_cmap", colors)
|
||||
|
||||
# fig, ax = plt.subplots(figsize=(7, 7))
|
||||
# canvas = FigureCanvas(fig)
|
||||
|
||||
# background = np.ones((720, 1280)) * 0.5 # 假设最大分辨率,后面裁剪
|
||||
# bg_img = ax.imshow(background, origin='lower', cmap='gray', alpha=0.3)
|
||||
# ax.grid(True, which='both', axis='both', color='white', linestyle='-', linewidth=1, zorder=0)
|
||||
|
||||
# contour = None # 等高线对象占位
|
||||
# ax.set_axis_off()
|
||||
# plt.tight_layout(pad=0)
|
||||
|
||||
# while self.femtobolt_streaming and not self.streaming_stop_event.is_set():
|
||||
# if self.femtobolt_camera and self.socketio:
|
||||
# try:
|
||||
# capture = self.femtobolt_camera.update()
|
||||
# if capture is not None:
|
||||
# ret, depth_image = capture.get_depth_image()
|
||||
# if ret and depth_image is not None:
|
||||
# if MATPLOTLIB_AVAILABLE and depth_range_min is not None and depth_range_max is not None:
|
||||
# # 过滤范围外值
|
||||
# depth_image = depth_image.copy()
|
||||
# depth_image[(depth_image > depth_range_max) | (depth_image < depth_range_min)] = 0
|
||||
# depth_masked = np.ma.masked_equal(depth_image, 0)
|
||||
|
||||
# # 清理旧的等高线
|
||||
# if contour:
|
||||
# for coll in contour.collections:
|
||||
# coll.remove()
|
||||
|
||||
# # 绘制新的等高线
|
||||
# contour = ax.contourf(
|
||||
# depth_masked, levels=200, cmap=mcmap,
|
||||
# vmin=depth_range_min, vmax=depth_range_max,
|
||||
# origin='upper', zorder=2
|
||||
# )
|
||||
|
||||
# # 渲染到 numpy
|
||||
# canvas.draw()
|
||||
# img = np.frombuffer(canvas.tostring_rgb(), dtype=np.uint8)
|
||||
# img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
|
||||
# depth_colored = img
|
||||
# else:
|
||||
# # OpenCV 伪彩
|
||||
# depth_normalized = np.clip(depth_image, depth_range_min, depth_range_max)
|
||||
# depth_normalized = ((depth_normalized - depth_range_min) /
|
||||
# (depth_range_max - depth_range_min) * 255).astype(np.uint8)
|
||||
# depth_colored = cv2.applyColorMap(depth_normalized, cv2.COLORMAP_JET)
|
||||
# mask_outside = (depth_image < depth_range_min) | (depth_image > depth_range_max)
|
||||
# depth_colored[mask_outside] = [0, 0, 0]
|
||||
|
||||
# # 裁剪
|
||||
# height, width = depth_colored.shape[:2]
|
||||
# target_width = height // 2
|
||||
# if width > target_width:
|
||||
# left = (width - target_width) // 2
|
||||
# right = left + target_width
|
||||
# depth_colored = depth_colored[:, left:right]
|
||||
|
||||
# # 保存到缓存
|
||||
# self._save_frame_to_cache(depth_colored.copy(), 'femtobolt')
|
||||
|
||||
# # 编码并推送
|
||||
# success, buffer = cv2.imencode('.jpg', depth_colored, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
|
||||
# if success and self.socketio:
|
||||
# jpg_as_text = base64.b64encode(buffer).decode('utf-8')
|
||||
# self.socketio.emit('depth_camera_frame', {
|
||||
# 'image': jpg_as_text,
|
||||
# 'frame_id': frame_count,
|
||||
# 'timestamp': time.time()
|
||||
# })
|
||||
# frame_count += 1
|
||||
# else:
|
||||
# time.sleep(0.01)
|
||||
# except Exception as e:
|
||||
# logger.debug(f'FemtoBolt帧推送失败: {e}')
|
||||
# time.sleep(0.1)
|
||||
|
||||
# time.sleep(1 / 30) # 控制帧率
|
||||
|
||||
# except Exception as e:
|
||||
# logger.debug(f'FemtoBolt推流线程异常: {e}')
|
||||
# finally:
|
||||
# self.femtobolt_streaming = False
|
||||
|
||||
def _femtobolt_streaming_thread(self):
|
||||
"""FemtoBolt深度相机推流线程"""
|
||||
frame_count = 0
|
||||
|
||||
try:
|
||||
while self.femtobolt_streaming and not self.streaming_stop_event.is_set():
|
||||
if self.femtobolt_camera and self.socketio:
|
||||
try:
|
||||
# 获取FemtoBolt帧
|
||||
capture = self.femtobolt_camera.update()
|
||||
|
||||
# 检查capture是否有效并获取彩色深度图像
|
||||
if capture is not None:
|
||||
ret, depth_image = capture.get_depth_image()
|
||||
height2, width2 = depth_image.shape[:2]
|
||||
logger.debug(f'FemtoBolt原始帧宽: {width2}')
|
||||
logger.debug(f'FemtoBolt原始帧高: {height2}')
|
||||
|
||||
if ret and depth_image is not None:
|
||||
# 读取config.ini中的深度范围配置
|
||||
import configparser
|
||||
@ -776,38 +961,51 @@ class DeviceManager:
|
||||
except Exception:
|
||||
depth_range_min = None
|
||||
depth_range_max = None
|
||||
|
||||
# 优化深度图彩色映射,范围外用黑色,区间内用Jet模型从蓝色到黄色到红色渐变
|
||||
if depth_range_min is not None and depth_range_max is not None:
|
||||
# 归一化深度值到0-255范围
|
||||
# 使用matplotlib渲染深度图,参考display_x.py
|
||||
if MATPLOTLIB_AVAILABLE and depth_range_min is not None and depth_range_max is not None:
|
||||
depth_image[depth_image > depth_range_max] = 0
|
||||
depth_image[depth_image < depth_range_min] = 0
|
||||
background = np.ones_like(depth_image) * 0.5
|
||||
depth_masked = np.ma.masked_equal(depth_image, 0)
|
||||
colors = ['fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue']
|
||||
mcmap = LinearSegmentedColormap.from_list("custom_cmap", colors)
|
||||
# plt.figure(figsize=(7, 7))
|
||||
plt.figure(figsize=(width2/100, height2/100), dpi=100)
|
||||
plt.imshow(background, origin='lower', cmap='gray', alpha=0.3)
|
||||
plt.grid(True, which='both', axis='both', color='white', linestyle='-', linewidth=1, zorder=0)
|
||||
plt.contourf(depth_masked, levels=200, cmap=mcmap, vmin=depth_range_min, vmax=depth_range_max, origin='upper', zorder=2)
|
||||
# plt.axis('off')
|
||||
plt.tight_layout(pad=0)
|
||||
plt.draw()
|
||||
|
||||
plt_canvas = plt.gca().figure.canvas
|
||||
plt_canvas.draw()
|
||||
img = np.frombuffer(plt_canvas.tostring_rgb(), dtype=np.uint8)
|
||||
img = img.reshape(plt_canvas.get_width_height()[::-1] + (3,))
|
||||
plt.clf()
|
||||
depth_colored = img
|
||||
else:
|
||||
# 如果没有matplotlib则使用原有OpenCV伪彩色映射
|
||||
depth_normalized = np.clip(depth_image, depth_range_min, depth_range_max)
|
||||
depth_normalized = ((depth_normalized - depth_range_min) / (depth_range_max - depth_range_min) * 255).astype(np.uint8)
|
||||
|
||||
# 应用OpenCV的COLORMAP_JET进行伪彩色映射
|
||||
depth_colored = cv2.applyColorMap(depth_normalized, cv2.COLORMAP_JET)
|
||||
|
||||
# 范围外用黑色
|
||||
mask_outside = (depth_image < depth_range_min) | (depth_image > depth_range_max)
|
||||
depth_colored[mask_outside] = [0, 0, 0] # BGR黑色
|
||||
else:
|
||||
# 如果没有配置,使用默认伪彩色映射
|
||||
depth_colored = cv2.convertScaleAbs(depth_image, alpha=0.03)
|
||||
depth_colored = cv2.applyColorMap(depth_colored, cv2.COLORMAP_JET)
|
||||
depth_colored[mask_outside] = [0, 0, 0]
|
||||
|
||||
# 转换颜色格式(如果需要)
|
||||
if len(depth_colored.shape) == 3 and depth_colored.shape[2] == 4:
|
||||
depth_colored = cv2.cvtColor(depth_colored, cv2.COLOR_BGRA2BGR)
|
||||
elif len(depth_colored.shape) == 3 and depth_colored.shape[2] == 3:
|
||||
pass
|
||||
height, width = depth_colored.shape[:2]
|
||||
# logger.debug(f'FemtoBolt帧宽: {width}')
|
||||
# logger.debug(f'FemtoBolt帧高: {height}')
|
||||
logger.debug(f'FemtoBolt帧宽: {width}')
|
||||
logger.debug(f'FemtoBolt帧高: {height}')
|
||||
target_width = height // 2
|
||||
if width > target_width:
|
||||
left = (width - target_width) // 2
|
||||
right = left + target_width
|
||||
depth_colored = depth_colored[:, left:right]
|
||||
|
||||
height1, width1 = depth_colored.shape[:2]
|
||||
logger.debug(f'FemtoBolt帧裁剪完以后得宽: {width1}')
|
||||
logger.debug(f'FemtoBolt帧裁剪完以后得宽: {height1}')
|
||||
# 保存处理好的身体帧到全局缓存
|
||||
self._save_frame_to_cache(depth_colored.copy(), 'femtobolt')
|
||||
|
||||
@ -892,7 +1090,7 @@ class DeviceManager:
|
||||
|
||||
if pressure_data and 'foot_pressure' in pressure_data:
|
||||
foot_pressure = pressure_data['foot_pressure']
|
||||
|
||||
logger.error(f"压力传感器数据{foot_pressure}")
|
||||
# 获取各区域压力值
|
||||
left_front = foot_pressure['left_front']
|
||||
left_rear = foot_pressure['left_rear']
|
||||
@ -1067,28 +1265,34 @@ class DeviceManager:
|
||||
logger.error(f'更新数据库视频路径失败: {db_error}')
|
||||
# 数据库更新失败不影响录制启动,继续执行
|
||||
|
||||
# 视频编码参数 - 尝试更兼容的编解码器
|
||||
# 首先尝试MJPG,这是最兼容的编解码器
|
||||
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
|
||||
# 视频编码参数
|
||||
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
||||
fps = 30
|
||||
logger.info(f'使用编解码器: MJPG')
|
||||
|
||||
# 初始化视频写入器
|
||||
if self.device_status['camera']:
|
||||
# 获取摄像头分辨率
|
||||
if self.camera and self.camera.isOpened():
|
||||
target_width,target_height = video_manager.MAX_FRAME_SIZE
|
||||
self.feet_video_writer = cv2.VideoWriter(
|
||||
feet_video_path, fourcc, fps, (target_width, target_height)
|
||||
)
|
||||
target_width,target_height = video_manager.MAX_FRAME_SIZE
|
||||
self.feet_video_writer = cv2.VideoWriter(feet_video_path, fourcc, fps, (target_width, target_height))
|
||||
|
||||
# 检查视频写入器是否初始化成功
|
||||
if self.feet_video_writer.isOpened():
|
||||
logger.info(f'脚部视频写入器初始化成功: {feet_video_path}')
|
||||
else:
|
||||
logger.error(f'脚部视频写入器初始化失败: {feet_video_path}')
|
||||
# 检查视频写入器是否初始化成功
|
||||
if self.feet_video_writer.isOpened():
|
||||
logger.info(f'脚部视频写入器初始化成功: {feet_video_path}')
|
||||
else:
|
||||
logger.error('摄像头未打开,无法初始化脚部视频写入器')
|
||||
logger.error(f'脚部视频写入器初始化失败: {feet_video_path}')
|
||||
# # 获取摄像头分辨率
|
||||
# if self.camera and self.camera.isOpened():
|
||||
# target_width,target_height = video_manager.MAX_FRAME_SIZE
|
||||
# self.feet_video_writer = cv2.VideoWriter(
|
||||
# feet_video_path, fourcc, fps, (target_width, target_height)
|
||||
# )
|
||||
|
||||
# # 检查视频写入器是否初始化成功
|
||||
# if self.feet_video_writer.isOpened():
|
||||
# logger.info(f'脚部视频写入器初始化成功: {feet_video_path}')
|
||||
# else:
|
||||
# logger.error(f'脚部视频写入器初始化失败: {feet_video_path}')
|
||||
# else:
|
||||
# logger.error('摄像头未打开,无法初始化脚部视频写入器')
|
||||
else:
|
||||
logger.warning('摄像头设备未启用,跳过脚部视频写入器初始化')
|
||||
if self.device_status['femtobolt']:
|
||||
@ -1096,66 +1300,36 @@ class DeviceManager:
|
||||
if frame1 is not None:
|
||||
actual_height,actual_width=frame1.shape[:2]
|
||||
logger.info(f'初始化身体视频写入器 裁剪后分辨率: {actual_height}x{actual_width}')
|
||||
logger.info(f'VideoWriter将使用分辨率: width={actual_width}, height={actual_height}')
|
||||
|
||||
# 确保图像数据类型正确
|
||||
if frame1.dtype != np.uint8:
|
||||
logger.warning(f'身体帧数据类型不是uint8: {frame1.dtype},将进行转换')
|
||||
|
||||
# 尝试多种编解码器和分辨率组合
|
||||
codecs_to_try = ['MJPG', 'XVID', 'mp4v', 'H264']
|
||||
resolutions_to_try = [(actual_width, actual_height), (288, 576), (640, 480)]
|
||||
|
||||
success = False
|
||||
for codec in codecs_to_try:
|
||||
if success:
|
||||
break
|
||||
fourcc_test = cv2.VideoWriter_fourcc(*codec)
|
||||
for resolution in resolutions_to_try:
|
||||
logger.info(f'尝试编解码器: {codec}, 分辨率: {resolution}')
|
||||
self.body_video_writer = cv2.VideoWriter(
|
||||
body_video_path, fourcc_test, fps, resolution
|
||||
)
|
||||
if self.body_video_writer.isOpened():
|
||||
logger.info(f'身体视频写入器初始化成功: {body_video_path}, 编解码器: {codec}, 分辨率: {resolution}')
|
||||
success = True
|
||||
break
|
||||
else:
|
||||
logger.warning(f'编解码器 {codec} 分辨率 {resolution} 初始化失败')
|
||||
if self.body_video_writer:
|
||||
self.body_video_writer.release()
|
||||
self.body_video_writer = None
|
||||
|
||||
if not success:
|
||||
logger.error(f'所有编解码器和分辨率组合都失败了,身体视频写入器初始化失败')
|
||||
self.body_video_writer = cv2.VideoWriter(
|
||||
body_video_path, fourcc, fps, (actual_width, actual_height)
|
||||
)
|
||||
if self.body_video_writer.isOpened():
|
||||
logger.info(f'身体视频写入器初始化成功: {body_video_path}, 分辨率: {actual_width}x{actual_height}')
|
||||
else:
|
||||
logger.error(f'身体视频写入器初始化失败: {body_video_path}, 分辨率: {actual_width}x{actual_height}')
|
||||
# 尝试使用默认分辨率重新初始化
|
||||
logger.info('尝试使用默认分辨率重新初始化身体视频写入器')
|
||||
self.body_video_writer = cv2.VideoWriter(
|
||||
body_video_path, fourcc, fps, (288, 576) # 默认分辨率
|
||||
)
|
||||
if self.body_video_writer.isOpened():
|
||||
logger.info(f'身体视频写入器使用默认分辨率初始化成功: {body_video_path}')
|
||||
else:
|
||||
logger.error(f'身体视频写入器使用默认分辨率初始化仍然失败: {body_video_path}')
|
||||
else:
|
||||
logger.warning('无法从缓存获取FemtoBolt帧数据,使用默认分辨率初始化身体视频写入器')
|
||||
# 使用相同的编解码器回退机制
|
||||
codecs_to_try = ['MJPG', 'XVID', 'mp4v', 'H264']
|
||||
resolutions_to_try = [(288, 576), (640, 480), (320, 240)]
|
||||
|
||||
success = False
|
||||
for codec in codecs_to_try:
|
||||
if success:
|
||||
break
|
||||
fourcc_test = cv2.VideoWriter_fourcc(*codec)
|
||||
for resolution in resolutions_to_try:
|
||||
logger.info(f'尝试默认编解码器: {codec}, 分辨率: {resolution}')
|
||||
self.body_video_writer = cv2.VideoWriter(
|
||||
body_video_path, fourcc_test, fps, resolution
|
||||
)
|
||||
if self.body_video_writer.isOpened():
|
||||
logger.info(f'身体视频写入器默认初始化成功: {body_video_path}, 编解码器: {codec}, 分辨率: {resolution}')
|
||||
success = True
|
||||
break
|
||||
else:
|
||||
logger.warning(f'默认编解码器 {codec} 分辨率 {resolution} 初始化失败')
|
||||
if self.body_video_writer:
|
||||
self.body_video_writer.release()
|
||||
self.body_video_writer = None
|
||||
|
||||
if not success:
|
||||
logger.error(f'所有默认编解码器和分辨率组合都失败了,身体视频写入器初始化失败')
|
||||
self.body_video_writer = cv2.VideoWriter(
|
||||
body_video_path, fourcc, fps, (288, 576) # 默认分辨率
|
||||
)
|
||||
if self.body_video_writer.isOpened():
|
||||
logger.info(f'身体视频写入器使用默认分辨率初始化成功: {body_video_path}')
|
||||
else:
|
||||
logger.error(f'身体视频写入器使用默认分辨率初始化失败: {body_video_path}')
|
||||
# FemtoBolt默认分辨率
|
||||
# capture = self.femtobolt_camera.update()
|
||||
# if capture is not None:
|
||||
@ -1195,13 +1369,13 @@ class DeviceManager:
|
||||
)
|
||||
self.feet_recording_thread.start()
|
||||
|
||||
if self.body_video_writer:
|
||||
self.body_recording_thread = threading.Thread(
|
||||
target=self._body_recording_thread,
|
||||
daemon=True,
|
||||
name='BodyRecordingThread'
|
||||
)
|
||||
self.body_recording_thread.start()
|
||||
# if self.body_video_writer:
|
||||
# self.body_recording_thread = threading.Thread(
|
||||
# target=self._body_recording_thread,
|
||||
# daemon=True,
|
||||
# name='BodyRecordingThread'
|
||||
# )
|
||||
# self.body_recording_thread.start()
|
||||
# #屏幕录制
|
||||
# if self.screen_video_writer:
|
||||
# self.screen_recording_thread = threading.Thread(
|
||||
@ -1353,7 +1527,7 @@ class DeviceManager:
|
||||
max_consecutive_failures = 10
|
||||
|
||||
# logger.info(f"足部录制线程已启动 - 会话ID: {self.current_session_id}")
|
||||
# logger.info(f"视频写入器状态: {self.feet_video_writer.isOpened() if self.feet_video_writer else 'None'}")
|
||||
logger.info(f"视频写入器状态: {self.feet_video_writer.isOpened() if self.feet_video_writer else 'None'}")
|
||||
|
||||
try:
|
||||
while self.sync_recording and not self.recording_stop_event.is_set():
|
||||
@ -1362,10 +1536,10 @@ class DeviceManager:
|
||||
frame, frame_timestamp = self._get_latest_frame_from_cache('camera')
|
||||
# 详细记录帧获取情况
|
||||
if frame is not None:
|
||||
#logger.debug(f"成功获取帧 - 尺寸: {frame.shape}, 数据类型: {frame.dtype}, 时间戳: {frame_timestamp}")
|
||||
logger.debug(f"成功获取帧 - 尺寸: {frame.shape}, 数据类型: {frame.dtype}, 时间戳: {frame_timestamp}")
|
||||
# 检查视频写入器状态
|
||||
if not self.feet_video_writer.isOpened():
|
||||
# logger.error(f"脚部视频写入器已关闭,无法写入帧 - 会话ID: {self.current_session_id}")
|
||||
logger.error(f"脚部视频写入器已关闭,无法写入帧 - 会话ID: {self.current_session_id}")
|
||||
break
|
||||
try:
|
||||
# 复制帧数据避免引用问题
|
||||
@ -1778,6 +1952,7 @@ class MockPressureDevice:
|
||||
}
|
||||
|
||||
def _generate_pressure_image(self, left_front, left_rear, right_front, right_rear) -> str:
|
||||
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
|
||||
"""生成足部压力图片的base64数据"""
|
||||
try:
|
||||
import base64
|
||||
@ -1866,7 +2041,7 @@ class VideoStreamManager:
|
||||
self.video_thread = None
|
||||
self.video_running = False
|
||||
|
||||
# 用于异步编码的线程池和队列
|
||||
# # 用于异步编码的线程池和队列
|
||||
self.encoding_executor = ThreadPoolExecutor(max_workers=2)
|
||||
self.frame_queue = queue.Queue(maxsize=1) # 只保留最新的一帧
|
||||
|
||||
@ -1876,7 +2051,7 @@ class VideoStreamManager:
|
||||
self.MAX_FRAME_SIZE = (640, 480) # 进一步减小帧尺寸以节省内存
|
||||
self.MAX_MEMORY_USAGE = 200 * 1024 * 1024 # 200MB内存限制
|
||||
self.memory_check_counter = 0
|
||||
self.MEMORY_CHECK_INTERVAL = 50 # 每50帧检查一次内存
|
||||
# 移除了MEMORY_CHECK_INTERVAL,改为每30帧检查一次内存
|
||||
|
||||
# 读取RTSP配置
|
||||
self._load_rtsp_config()
|
||||
@ -1933,7 +2108,7 @@ class VideoStreamManager:
|
||||
|
||||
# 使用更快的插值方法减少CPU使用
|
||||
frame = cv2.resize(frame, (new_width, new_height), interpolation=cv2.INTER_AREA)
|
||||
|
||||
self.device_manager._save_frame_to_cache(frame, 'camera')
|
||||
# 优化JPEG编码参数:优先考虑速度和内存
|
||||
encode_param = [
|
||||
int(cv2.IMWRITE_JPEG_QUALITY), 50, # 进一步降低质量以减少内存使用
|
||||
@ -1953,7 +2128,6 @@ class VideoStreamManager:
|
||||
|
||||
# 立即释放buffer内存
|
||||
del buffer
|
||||
|
||||
# 发送数据
|
||||
if self.socketio:
|
||||
self.socketio.emit('video_frame', {
|
||||
@ -1978,6 +2152,7 @@ class VideoStreamManager:
|
||||
try:
|
||||
# 从队列获取帧
|
||||
frame, frame_count = self.frame_queue.get(timeout=1)
|
||||
|
||||
# 提交到线程池进行异步编码
|
||||
self.encoding_executor.submit(self.async_encode_frame, frame, frame_count)
|
||||
except queue.Empty:
|
||||
@ -2036,16 +2211,15 @@ class VideoStreamManager:
|
||||
# 设置更低的分辨率以减少处理时间
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||||
logger.debug('视频监控流已打开,开始推送帧(激进实时模式)')
|
||||
if self.socketio:
|
||||
self.socketio.emit('video_status', {'status': 'started', 'message': '使用视频监控视频源(激进实时模式)'})
|
||||
|
||||
self.video_running = True
|
||||
|
||||
# 启动帧编码工作线程
|
||||
encoding_thread = threading.Thread(target=self.frame_encoding_worker)
|
||||
encoding_thread.daemon = True
|
||||
encoding_thread.start()
|
||||
# # 启动帧编码工作线程
|
||||
# encoding_thread = threading.Thread(target=self.frame_encoding_worker)
|
||||
# encoding_thread.daemon = True
|
||||
# encoding_thread.start()
|
||||
|
||||
while self.video_running:
|
||||
if use_test_mode:
|
||||
@ -2112,30 +2286,67 @@ class VideoStreamManager:
|
||||
continue
|
||||
|
||||
try:
|
||||
# 直接在主循环中执行帧处理逻辑(替代异步工作线程)
|
||||
|
||||
# 内存检查
|
||||
self.memory_check_counter += 1
|
||||
if self.memory_check_counter % 30 == 0:
|
||||
memory_usage = psutil.virtual_memory().percent
|
||||
if memory_usage > 85:
|
||||
logger.warning(f'内存使用率过高: {memory_usage}%,跳过当前帧')
|
||||
del frame
|
||||
continue
|
||||
|
||||
# 按照MAX_FRAME_SIZE裁剪帧
|
||||
cropped_frame = frame.copy()
|
||||
width, height = self.MAX_FRAME_SIZE
|
||||
if cropped_frame.shape[1] > width or cropped_frame.shape[0] > height:
|
||||
# 计算裁剪区域(居中裁剪)
|
||||
start_x = max(0, (cropped_frame.shape[1] - width) // 2)
|
||||
start_y = max(0, (cropped_frame.shape[0] - height) // 2)
|
||||
end_x = min(cropped_frame.shape[1], start_x + width)
|
||||
end_y = min(cropped_frame.shape[0], start_y + height)
|
||||
cropped_frame = cropped_frame[start_y:end_y, start_x:end_x]
|
||||
|
||||
# 保存帧到全局缓存
|
||||
if self.device_manager:
|
||||
self.device_manager._save_frame_to_cache(frame.copy(), 'camera')
|
||||
self.device_manager._save_frame_to_cache(cropped_frame, 'camera')
|
||||
# 每1000帧记录一次缓存保存状态
|
||||
if frame_count % 1000 == 0:
|
||||
logger.debug(f"视频推流已保存第 {frame_count} 帧到全局缓存")
|
||||
else:
|
||||
logger.warning("VideoStreamManager未关联DeviceManager,无法保存帧到缓存")
|
||||
|
||||
# 将帧放入队列进行异步处理
|
||||
# JPEG编码和socketio发送
|
||||
try:
|
||||
# 非阻塞方式放入队列,如果队列满了就丢弃旧帧
|
||||
self.frame_queue.put_nowait((frame.copy(), frame_count))
|
||||
except queue.Full:
|
||||
# 队列满了,清空队列并放入新帧
|
||||
try:
|
||||
old_frame, _ = self.frame_queue.get_nowait()
|
||||
del old_frame # 立即释放旧帧内存
|
||||
except queue.Empty:
|
||||
pass
|
||||
self.frame_queue.put_nowait((frame.copy(), frame_count))
|
||||
# 使用较低的JPEG质量以节省内存
|
||||
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 70]
|
||||
result, buffer = cv2.imencode('.jpg', cropped_frame, encode_param)
|
||||
|
||||
if result:
|
||||
# 转换为base64字符串
|
||||
jpg_as_text = base64.b64encode(buffer).decode('utf-8')
|
||||
|
||||
# 立即释放buffer内存
|
||||
del buffer
|
||||
|
||||
# 发送数据
|
||||
if self.socketio:
|
||||
self.socketio.emit('video_frame', {
|
||||
'image': jpg_as_text,
|
||||
'frame_id': frame_count,
|
||||
'timestamp': time.time()
|
||||
})
|
||||
|
||||
# 立即释放base64字符串
|
||||
del jpg_as_text
|
||||
|
||||
# 立即释放原始帧内存
|
||||
except Exception as e:
|
||||
logger.error(f'帧编码失败: {e}')
|
||||
|
||||
# 立即释放帧内存
|
||||
del frame
|
||||
del cropped_frame
|
||||
|
||||
if frame_count % 60 == 0: # 每60帧记录一次
|
||||
|
||||
@ -2161,10 +2372,10 @@ class VideoStreamManager:
|
||||
if self.video_thread and self.video_thread.is_alive():
|
||||
logger.warning('视频监控线程已在运行')
|
||||
return {'status': 'already_running', 'message': '视频监控已在运行'}
|
||||
|
||||
if not self.device_index:
|
||||
logger.error('视频监控相机未配置')
|
||||
return {'status': 'error', 'message': '视频监控相机未配置'}
|
||||
# logger.error(f'视频监控相机未配置2222222222{self.device_index}')
|
||||
# if not self.device_index:
|
||||
# logger.error('视频监控相机未配置')
|
||||
# return {'status': 'error', 'message': '视频监控相机未配置'}
|
||||
|
||||
logger.info(f'视频启动监控线程,设备号: {self.device_index}')
|
||||
self.video_thread = threading.Thread(target=self.generate_video_frames)
|
||||
|
70
backend/display_x.py
Normal file
70
backend/display_x.py
Normal file
@ -0,0 +1,70 @@
|
||||
import cv2
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import pdb
|
||||
|
||||
import os
|
||||
from matplotlib.colors import LinearSegmentedColormap,ListedColormap
|
||||
from matplotlib.animation import FuncAnimation, FFMpegWriter
|
||||
|
||||
# 指定文件夹路径
|
||||
folder_path = 'datas'
|
||||
|
||||
# 获取文件夹中的所有文件
|
||||
files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
|
||||
|
||||
# 根据文件的修改时间排序
|
||||
sorted_files = sorted(files, key=lambda x: os.path.getmtime(os.path.join(folder_path, x)))
|
||||
|
||||
|
||||
# 创建一个自定义的 colormap
|
||||
colors = ['red', 'yellow', 'green', 'blue']
|
||||
|
||||
# 自定义颜色
|
||||
colors = ['fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue',
|
||||
'fuchsia', 'red', 'yellow', 'lime', 'cyan', 'blue']
|
||||
mcmap = LinearSegmentedColormap.from_list("custom_cmap", colors)
|
||||
|
||||
plt.figure(figsize=(7, 7))
|
||||
# 打印排序后的文件名
|
||||
for file in sorted_files:
|
||||
data = np.load(os.path.join(folder_path,file))
|
||||
depth = data['arr1']
|
||||
points = data['arr2']
|
||||
color_image = data['arr3']
|
||||
|
||||
h,w,_ = color_image.shape
|
||||
points = points.reshape((h,w,3))
|
||||
|
||||
depth[depth > 1300] = 0
|
||||
depth[depth < 900] = 0
|
||||
depth = depth[50:200,50:210]
|
||||
|
||||
# 背景图
|
||||
background = np.ones_like(depth) * 0.5 # 设定灰色背景
|
||||
|
||||
# 使用 np.ma.masked_equal() 来屏蔽深度图中的零值。masked_array 中的值不会被绘制,从而避免了零值的显示。
|
||||
depth = np.ma.masked_equal(depth, 0)
|
||||
|
||||
# 绘制背景
|
||||
plt.imshow(background, origin='lower', cmap='gray', alpha=0.3)
|
||||
# 绘制白色栅格线,并将其置于底层
|
||||
plt.grid(True, which='both', axis='both', color='white', linestyle='-', linewidth=1, zorder=0)
|
||||
if False:
|
||||
plt.subplot(1,2,1)
|
||||
plt.imshow(depth, cmap='plasma', vmin=1000, vmax=1200)
|
||||
plt.subplot(1,2,2)
|
||||
# 绘制等高线图并设置原点在左下角
|
||||
# 通过设置 zorder 来控制它们的层级。例如,设置 zorder=2 或更大的值来确保它们位于栅格线之上。
|
||||
plt.contourf(depth, levels=200, cmap=mcmap,vmin=900, vmax=1300,origin='upper',zorder=2)
|
||||
plt.pause(0.1) # 暂停0.1秒
|
||||
plt.draw() # 重绘图像
|
||||
plt.clf() # 清除当前图像
|
||||
#plt.show()
|
||||
|
||||
|
||||
|
||||
|
@ -1,60 +0,0 @@
|
||||
# release v1.10.1
|
||||
1.adjust imu queue default size;
|
||||
2.adapt to image related Interface;
|
||||
3.remove excess compilation items;
|
||||
4.palyback pre-init ob_context;
|
||||
5.adjust the order of IMU starting;
|
||||
6.adapt to mega-i device;
|
||||
7.update orbbecsdk version to last.
|
||||
|
||||
## Product support
|
||||
| **products list** | **firmware version** |**platform**|
|
||||
| --- | --- | --- |
|
||||
| Orbbec Femto Bolt | 1.0.6/1.0.9/1.1.1 |Windows10+, Ubuntu18.04+ |
|
||||
| Orbbec Femto Mega | 1.1.5/1.1.7/1.2.8 |Windows10+, Ubuntu20.04+ |
|
||||
## Catalog Introduction
|
||||
- /
|
||||
- bin : Executable files and dynamic loading libraries
|
||||
- doc : Guidelines for accessing AKDK Application Software with Femto Bolt
|
||||
- include : software interface
|
||||
- lib : Library files
|
||||
- scripts : Script for obtaining device timestamps on the Windows platform (Linux : Essential scripts for running programs)
|
||||
## How to seamlessly replace the Azure Kinect camera with the Femto camera?
|
||||
https://orbbec.github.io/OrbbecSDK-K4A-Wrapper/src/orbbec/docs/Access_AKDK_Application_Software_with_Femto_Bolt.pdf
|
||||
## Q&A
|
||||
|
||||
1. The library of this branch is not support the K4A device, please use the [Native K4A](https://github.com/microsoft/Azure-Kinect-Sensor-SDK) library to access the K4A device.
|
||||
|
||||
2. The Orbbec SDK K4A Wrapper is aim to provide the same API as the K4A, but it's not full API for Orbbec SDK and feature for Orbbec camera. If you want to use the full feature of Orbbec camera, please use the [Orbbec SDK](https://github.com/orbbec/OrbbecSDK) directly.
|
||||
|
||||
3. For Linux user, there may be an issue with the initialization of DepthEngine when using Orbbec Femto Bolt due to modifications made by Microsoft in the new version of DepthEngine. This can cause failure during the start of the depth stream. The reason for this is that simultaneous use of multiple OpenGL contexts may result in conflicts. User can try to resolve it follow this: [https://www.khronos.org/opengl/wiki/OpenGL_and_multithreading](https://www.khronos.org/opengl/wiki/OpenGL_and_multithreading)
|
||||
|
||||
For example:
|
||||
|
||||
``` c++
|
||||
// file: tools/k4aviewer/k4adevicedockcontrol.cpp
|
||||
GLFWwindow *currentContext = glfwGetCurrentContext(); // store the current context
|
||||
glfwMakeContextCurrent(NULL); // make current context to NULL
|
||||
|
||||
StartCameras(); // will initialize the DepthEngine
|
||||
|
||||
glfwMakeContextCurrent(currentContext); // restore the current context
|
||||
```
|
||||
|
||||
4. Unable to obtain the device timestamp on the Windows platform
|
||||
``` powershell
|
||||
# Running as Administrator using PowerShell
|
||||
cd src/orbbec/OrbbecSDK/misc/scripts
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
.\obsensor_metadata_win10.ps1 -op install_all
|
||||
```
|
||||
|
||||
5. How to execute an application on the Linux platform without using sudo.
|
||||
Install udev rules file:
|
||||
|
||||
``` bash
|
||||
cd src/orbbec/OrbbecSDK/misc/scripts
|
||||
sudo chmod +x ./install_udev_rules.sh
|
||||
./install_udev_rules.sh
|
||||
# Once complete, the orbbec camera is available without being 'root'.
|
||||
```
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,42 +0,0 @@
|
||||
|
||||
#ifndef K4A_EXPORT_H
|
||||
#define K4A_EXPORT_H
|
||||
|
||||
#ifdef K4A_STATIC_DEFINE
|
||||
# define K4A_EXPORT
|
||||
# define K4A_NO_EXPORT
|
||||
#else
|
||||
# ifndef K4A_EXPORT
|
||||
# ifdef k4a_EXPORTS
|
||||
/* We are building this library */
|
||||
# define K4A_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define K4A_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef K4A_NO_EXPORT
|
||||
# define K4A_NO_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef K4A_DEPRECATED
|
||||
# define K4A_DEPRECATED __declspec(deprecated)
|
||||
#endif
|
||||
|
||||
#ifndef K4A_DEPRECATED_EXPORT
|
||||
# define K4A_DEPRECATED_EXPORT K4A_EXPORT K4A_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifndef K4A_DEPRECATED_NO_EXPORT
|
||||
# define K4A_DEPRECATED_NO_EXPORT K4A_NO_EXPORT K4A_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if 0 /* DEFINE_NO_DEPRECATED */
|
||||
# ifndef K4A_NO_DEPRECATED
|
||||
# define K4A_NO_DEPRECATED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* K4A_EXPORT_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the MIT License. */
|
||||
|
||||
#ifndef K4AVERSION_H
|
||||
#define K4AVERSION_H
|
||||
|
||||
#define K4A_VERSION_MAJOR 1
|
||||
#define K4A_VERSION_MINOR 4
|
||||
#define K4A_VERSION_PATCH 0
|
||||
#define K4A_VERSION_PRERELEASE "private"
|
||||
#define K4A_VERSION_BUILD_METADATA ""
|
||||
|
||||
#define K4A_VERSION_STR "1.4.0-private"
|
||||
|
||||
#endif
|
||||
|
@ -1,42 +0,0 @@
|
||||
|
||||
#ifndef K4ARECORD_EXPORT_H
|
||||
#define K4ARECORD_EXPORT_H
|
||||
|
||||
#ifdef K4ARECORD_STATIC_DEFINE
|
||||
# define K4ARECORD_EXPORT
|
||||
# define K4ARECORD_NO_EXPORT
|
||||
#else
|
||||
# ifndef K4ARECORD_EXPORT
|
||||
# ifdef k4arecord_EXPORTS
|
||||
/* We are building this library */
|
||||
# define K4ARECORD_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
/* We are using this library */
|
||||
# define K4ARECORD_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef K4ARECORD_NO_EXPORT
|
||||
# define K4ARECORD_NO_EXPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef K4ARECORD_DEPRECATED
|
||||
# define K4ARECORD_DEPRECATED __declspec(deprecated)
|
||||
#endif
|
||||
|
||||
#ifndef K4ARECORD_DEPRECATED_EXPORT
|
||||
# define K4ARECORD_DEPRECATED_EXPORT K4ARECORD_EXPORT K4ARECORD_DEPRECATED
|
||||
#endif
|
||||
|
||||
#ifndef K4ARECORD_DEPRECATED_NO_EXPORT
|
||||
# define K4ARECORD_DEPRECATED_NO_EXPORT K4ARECORD_NO_EXPORT K4ARECORD_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if 0 /* DEFINE_NO_DEPRECATED */
|
||||
# ifndef K4ARECORD_NO_DEPRECATED
|
||||
# define K4ARECORD_NO_DEPRECATED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* K4ARECORD_EXPORT_H */
|
@ -1,917 +0,0 @@
|
||||
/** \file playback.h
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* Kinect For Azure Recording Playback SDK.
|
||||
*/
|
||||
|
||||
#ifndef K4A_PLAYBACK_H
|
||||
#define K4A_PLAYBACK_H
|
||||
|
||||
#include <k4arecord/types.h>
|
||||
#include <k4arecord/k4arecord_export.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* \addtogroup Functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Opens an existing recording file for reading.
|
||||
*
|
||||
* \param path
|
||||
* Filesystem path of the existing recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* If successful, this contains a pointer to the recording handle. Caller must call k4a_playback_close() when
|
||||
* finished with the recording.
|
||||
*
|
||||
* \headerfile playback.h <k4arecord/playback.h>
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_open(const char *path, k4a_playback_t *playback_handle);
|
||||
|
||||
/** Get the raw calibration blob for the Azure Kinect device used during recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param data
|
||||
* Location to write the calibration data to. This field may optionally be set to NULL if the caller wants to query for
|
||||
* the needed data size.
|
||||
*
|
||||
* \param data_size
|
||||
* On passing \p data_size into the function this variable represents the available size to write the raw data to. On
|
||||
* return this variable is updated with the amount of data actually written to the buffer.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_BUFFER_RESULT_SUCCEEDED if \p data was successfully written. If \p data_size points to a buffer size that is
|
||||
* too small to hold the output, ::K4A_BUFFER_RESULT_TOO_SMALL is returned and \p data_size is updated to contain the
|
||||
* minimum buffer size needed to capture the calibration data.
|
||||
*
|
||||
* \remarks
|
||||
* The raw calibration may not exist if the device was not specified during recording.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_raw_calibration(k4a_playback_t playback_handle,
|
||||
uint8_t *data,
|
||||
size_t *data_size);
|
||||
|
||||
/** Get the camera calibration for Azure Kinect device used during recording. The output struct is used as input to all
|
||||
* transformation functions.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param calibration
|
||||
* Location to write the calibration.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_RESULT_SUCCEEDED if \p calibration was successfully written. ::K4A_RESULT_FAILED otherwise.
|
||||
*
|
||||
* \remarks
|
||||
* The calibration may not exist if the device was not specified during recording.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_get_calibration(k4a_playback_t playback_handle,
|
||||
k4a_calibration_t *calibration);
|
||||
|
||||
/** Get the device configuration used during recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param config
|
||||
* Location to write the recording configuration.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_RESULT_SUCCEEDED if \p config was successfully written. ::K4A_RESULT_FAILED otherwise.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_get_record_configuration(k4a_playback_t playback_handle,
|
||||
k4a_record_configuration_t *config);
|
||||
|
||||
/** Checks whether a track with the given track name exists in the playback file.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The track name to be checked to see whether it exists or not.
|
||||
*
|
||||
* \returns true if the track exists.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT bool k4a_playback_check_track_exists(k4a_playback_t playback_handle, const char *track_name);
|
||||
|
||||
/** Get the number of tracks in a playback file.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \returns the number of tracks in the playback file.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT size_t k4a_playback_get_track_count(k4a_playback_t playback_handle);
|
||||
|
||||
/** Gets the name of a track at a specific index.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_index
|
||||
* The index of the track to read the name form.
|
||||
*
|
||||
* \param track_name
|
||||
* Location to write the track name. This will be a UTF8 null terminated string. If a NULL buffer is specified,
|
||||
* \p track_name_size will be set to the size of buffer needed to store the string.
|
||||
*
|
||||
* \param track_name_size
|
||||
* On input, the size of the \p track_name buffer. On output, this is set to the length of the track_name value
|
||||
* (including the null terminator).
|
||||
*
|
||||
* \returns
|
||||
* A return of ::K4A_BUFFER_RESULT_SUCCEEDED means that the \p track_name has been filled in. If the buffer is too small
|
||||
* the function returns ::K4A_BUFFER_RESULT_TOO_SMALL and the needed size of the \p track_name buffer is returned in the
|
||||
* \p track_name_size parameter. ::K4A_BUFFER_RESULT_FAILED is returned if the track index does not exist. All other
|
||||
* failures return ::K4A_BUFFER_RESULT_FAILED.
|
||||
*
|
||||
* \remarks
|
||||
* When used along with k4a_playback_get_track_count(), this function can be used to enumerate all the available tracks
|
||||
* in a playback file. Additionally k4a_playback_track_is_builtin() can be used to filter custom tracks.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_track_name(k4a_playback_t playback_handle,
|
||||
size_t track_index,
|
||||
char *track_name,
|
||||
size_t *track_name_size);
|
||||
|
||||
/** Checks whether a track is one of the built-in tracks: "COLOR", "DEPTH", etc...
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The track name to be checked to see whether it is a built-in track.
|
||||
*
|
||||
* \returns true if the track is built-in. If the provided track name does not exist, false will be returned.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT bool k4a_playback_track_is_builtin(k4a_playback_t playback_handle, const char *track_name);
|
||||
|
||||
/** Gets the video-specific track information for a particular video track.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The track name to read video settings from.
|
||||
*
|
||||
* \param video_settings
|
||||
* Location to write the track's video settings.
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success, ::K4A_RESULT_FAILED is returned if the specified track does
|
||||
* not exist or is not a video track.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_track_get_video_settings(k4a_playback_t playback_handle,
|
||||
const char *track_name,
|
||||
k4a_record_video_settings_t *video_settings);
|
||||
|
||||
/** Gets the codec id string for a particular track.
|
||||
*
|
||||
* The codec ID is a string that corresponds to the codec of the track's data. Some of the existing formats are listed
|
||||
* here: https://www.matroska.org/technical/specs/codecid/index.html. It can also be custom defined by the user.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The track name to read the codec id from.
|
||||
*
|
||||
* \param codec_id
|
||||
* Location to write the codec id. This will be a UTF8 null terminated string. If a NULL buffer is specified,
|
||||
* \p codec_id_size will be set to the size of buffer needed to store the string.
|
||||
*
|
||||
* \param codec_id_size
|
||||
* On input, the size of the \p codec_id buffer. On output, this is set to the length of the codec_id value (including
|
||||
* the null terminator).
|
||||
*
|
||||
* \returns
|
||||
* A return of ::K4A_BUFFER_RESULT_SUCCEEDED means that the \p codec_id has been filled in. If the buffer is too small
|
||||
* the function returns ::K4A_BUFFER_RESULT_TOO_SMALL and the needed size of the \p codec_id buffer is returned in the
|
||||
* \p codec_id_size parameter. ::K4A_BUFFER_RESULT_FAILED is returned if the track_name does not exist. All other
|
||||
* failures return ::K4A_BUFFER_RESULT_FAILED.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_track_get_codec_id(k4a_playback_t playback_handle,
|
||||
const char *track_name,
|
||||
char *codec_id,
|
||||
size_t *codec_id_size);
|
||||
|
||||
/** Gets the codec context for a particular track.
|
||||
*
|
||||
* The codec context is a codec-specific buffer that contains any required codec metadata that is only known to the
|
||||
* codec. It is mapped to the matroska Codec Private field.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The track name to read the codec context from.
|
||||
*
|
||||
* \param codec_context
|
||||
* Location to write the codec context data. If a NULL buffer is specified, \p codec_context_size will be set to the
|
||||
* size of buffer needed to store the data.
|
||||
*
|
||||
* \param codec_context_size
|
||||
* On input, the size of the \p codec_context buffer. On output, this is set to the length of the codec_context data.
|
||||
*
|
||||
* \returns
|
||||
* A return of ::K4A_BUFFER_RESULT_SUCCEEDED means that the \p codec_context has been filled in. If the buffer is too
|
||||
* small the function returns ::K4A_BUFFER_RESULT_TOO_SMALL and the needed size of the \p codec_context buffer is
|
||||
* returned in the \p codec_context_size parameter. ::K4A_BUFFER_RESULT_FAILED is returned if the track_name does not
|
||||
* exist. All other failures return ::K4A_BUFFER_RESULT_FAILED.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_track_get_codec_context(k4a_playback_t playback_handle,
|
||||
const char *track_name,
|
||||
uint8_t *codec_context,
|
||||
size_t *codec_context_size);
|
||||
|
||||
/** Read the value of a tag from a recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param name
|
||||
* The name of the tag to read.
|
||||
*
|
||||
* \param value
|
||||
* Location to write the tag value. This will be a UTF8 null terminated string. If a NULL buffer is specified,
|
||||
* \p value_size will be set to the size of buffer needed to store the string.
|
||||
*
|
||||
* \param value_size
|
||||
* On input, the size of the \p value buffer. On output, this is set to the length of the tag value (including the null
|
||||
* terminator).
|
||||
*
|
||||
* \returns
|
||||
* A return of ::K4A_BUFFER_RESULT_SUCCEEDED means that the \p value has been filled in. If the buffer is too small the
|
||||
* function returns ::K4A_BUFFER_RESULT_TOO_SMALL and the needed size of the \p value buffer is returned in the
|
||||
* \p value_size parameter. ::K4A_BUFFER_RESULT_FAILED is returned if the tag does not exist. All other failures return
|
||||
* ::K4A_BUFFER_RESULT_FAILED.
|
||||
*
|
||||
* \remarks
|
||||
* Tags are global to a file, and should store data related to the entire recording, such as camera configuration or
|
||||
* recording location.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_tag(k4a_playback_t playback_handle,
|
||||
const char *name,
|
||||
char *value,
|
||||
size_t *value_size);
|
||||
|
||||
/** Set the image format that color captures will be converted to. By default the conversion format will be the same as
|
||||
* the image format stored in the recording file, and no conversion will occur.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param target_format
|
||||
* The target image format to be returned in captures.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_RESULT_SUCCEEDED if the format conversion is supported. ::K4A_RESULT_FAILED otherwise.
|
||||
*
|
||||
* \remarks
|
||||
* After the color conversion format is set, all \ref k4a_capture_t objects returned from the playback handle will have
|
||||
* their color images converted to the \p target_format.
|
||||
*
|
||||
* \remarks
|
||||
* Color format conversion occurs in the user-thread, so setting \p target_format to anything other than the format
|
||||
* stored in the file may significantly increase the latency of \p k4a_playback_get_next_capture() and
|
||||
* \p k4a_playback_get_previous_capture().
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_set_color_conversion(k4a_playback_t playback_handle,
|
||||
k4a_image_format_t target_format);
|
||||
|
||||
/** Reads an attachment file from a recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param file_name
|
||||
* The attachment file name.
|
||||
*
|
||||
* \param data
|
||||
* Location to write the attachment data. If a NULL buffer is specified, \p data_size will be set to the size of
|
||||
* buffer needed to store the data.
|
||||
*
|
||||
* \param data_size
|
||||
* On input, the size of the \p data buffer. On output, this is set to the length of the attachment data.
|
||||
*
|
||||
* \returns
|
||||
* A return of ::K4A_BUFFER_RESULT_SUCCEEDED means that the \p data has been filled in. If the buffer is too small the
|
||||
* function returns ::K4A_BUFFER_RESULT_TOO_SMALL and the needed size of the \p data buffer is returned in the
|
||||
* \p data_size parameter. ::K4A_BUFFER_RESULT_FAILED is returned if the attachment \p file_name does not exist. All
|
||||
* other failures return ::K4A_BUFFER_RESULT_FAILED.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_buffer_result_t k4a_playback_get_attachment(k4a_playback_t playback_handle,
|
||||
const char *file_name,
|
||||
uint8_t *data,
|
||||
size_t *data_size);
|
||||
|
||||
/** Read the next capture in the recording sequence.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param capture_handle
|
||||
* If successful this contains a handle to a capture object. Caller must call k4a_capture_release() when its done using
|
||||
* this capture
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a capture is returned, or ::K4A_STREAM_RESULT_EOF if the end of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_next_capture() always returns the next capture in sequence after the most recently returned capture.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_next_capture() after k4a_playback_seek_timestamp() will return the capture
|
||||
* in the recording closest to the seek time with an image timestamp greater than or equal to the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to k4a_playback_get_previous_capture() that returned ::K4A_STREAM_RESULT_EOF, the playback
|
||||
* position is at the beginning of the stream and k4a_playback_get_next_capture() will return the first capture in the
|
||||
* recording.
|
||||
*
|
||||
* \remarks
|
||||
* Capture objects returned by the playback API will always contain at least one image, but may have images missing if
|
||||
* frames were dropped in the original recording. When calling k4a_capture_get_color_image(),
|
||||
* k4a_capture_get_depth_image(), or k4a_capture_get_ir_image(), the image should be checked for NULL.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_next_capture(k4a_playback_t playback_handle,
|
||||
k4a_capture_t *capture_handle);
|
||||
|
||||
/** Read the previous capture in the recording sequence.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param capture_handle
|
||||
* If successful this contains a handle to a capture object. Caller must call k4a_capture_release() when its done using
|
||||
* this capture.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a capture is returned, or ::K4A_STREAM_RESULT_EOF if the start of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_previous_capture() always returns the previous capture in the sequence before the most
|
||||
* recently returned capture.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to k4a_playback_get_next_capture() that returned ::K4A_STREAM_RESULT_EOF, the playback position
|
||||
* is at the end of the stream and k4a_playback_get_previous_capture() will return the last capture in
|
||||
* the recording.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_previous_capture() after k4a_playback_seek_timestamp() will return the
|
||||
* capture in the recording closest to the seek time with all image timestamps less than the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* Capture objects returned by this API will always contain at least one image, but may have images missing if frames
|
||||
* were dropped in the original recording. When calling k4a_capture_get_color_image(), k4a_capture_get_depth_image(), or
|
||||
* k4a_capture_get_ir_image(), the image should be checked for NULL.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_previous_capture(k4a_playback_t playback_handle,
|
||||
k4a_capture_t *capture_handle);
|
||||
|
||||
/** Read the next IMU sample in the recording sequence.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param imu_sample
|
||||
* The location to write the IMU sample.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a sample is returned, or ::K4A_STREAM_RESULT_EOF if the end of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_next_imu_sample() always returns the IMU sample after the most recently returned sample.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to k4a_playback_get_previous_imu_sample() which returned ::K4A_STREAM_RESULT_EOF, then the
|
||||
* playback position is at the beginning of the recording and k4a_playback_get_next_imu_sample() will return the first
|
||||
* IMU sample in the recording.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_next_imu_sample() after k4a_playback_seek_timestamp() will return the IMU
|
||||
* sample in the recording closest to the seek time with a timestamp greater than or equal to the seek time.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_next_imu_sample(k4a_playback_t playback_handle,
|
||||
k4a_imu_sample_t *imu_sample);
|
||||
|
||||
/** Read the previous IMU sample in the recording sequence.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param imu_sample [OUT]
|
||||
* The location to write the IMU sample.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a sample is returned, or ::K4A_STREAM_RESULT_EOF if the start of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_previous_imu_sample() always returns the IMU sample before the most recently returned sample.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to to k4a_playback_get_next_imu_sample() which returned ::K4A_STREAM_RESULT_EOF, then the playback
|
||||
* position is at the end of the recording and k4a_playback_get_previous_imu_sample() will return the last IMU sample in
|
||||
* the recording.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_previous_imu_sample() after k4a_playback_seek_timestamp() will return the
|
||||
* IMU sample closest to the seek time with a timestamp less than the seek time.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_previous_imu_sample(k4a_playback_t playback_handle,
|
||||
k4a_imu_sample_t *imu_sample);
|
||||
|
||||
/** Read the next data block for a particular track.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The name of the track to read the next data block from.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* The location to write the data block handle.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a data block is returned, or ::K4A_STREAM_RESULT_EOF if the end of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_next_data_block() always returns the data block after the most recently returned data block for a
|
||||
* particular track.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to k4a_playback_get_previous_data_block() which returned ::K4A_STREAM_RESULT_EOF, then the
|
||||
* playback position is at the beginning of the recording and calling k4a_playback_get_next_data_block() with the same
|
||||
* track will return the first data block in the track.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_next_data_block() after k4a_playback_seek_timestamp() will return the data
|
||||
* block in the recording closest to the seek time with a timestamp greater than or equal to the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_next_data_block() cannot be used with the built-in tracks: "COLOR", "DEPTH", etc...
|
||||
* k4a_playback_track_is_builtin() can be used to determine if a track is a built-in track.
|
||||
*
|
||||
* \remarks
|
||||
* If the call is successful, callers must call k4a_playback_data_block_release() to return the allocated memory for
|
||||
* data_block_handle.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_next_data_block(k4a_playback_t playback_handle,
|
||||
const char *track_name,
|
||||
k4a_playback_data_block_t *data_block_handle);
|
||||
|
||||
/** Read the previous data block for a particular track.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param track_name
|
||||
* The name of the track to read the previous data block from.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* The location to write the data block.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_STREAM_RESULT_SUCCEEDED if a sample is returned, or ::K4A_STREAM_RESULT_EOF if the start of the recording is
|
||||
* reached. All other failures will return ::K4A_STREAM_RESULT_FAILED.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_previous_data_block() always returns the data block before the most recently returned data block for
|
||||
* a particular track.
|
||||
*
|
||||
* \remarks
|
||||
* If a call was made to to k4a_playback_get_next_data_block() which returned ::K4A_STREAM_RESULT_EOF, then the playback
|
||||
* position is at the end of the recording and calling k4a_playback_get_previous_data_block() with the same track will
|
||||
* return the last data block in the track.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_previous_data_block() after k4a_playback_seek_timestamp() will return the
|
||||
* data block closest to the seek time with a timestamp less than the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* If the call is successful, callers must call k4a_playback_data_block_release() to return the allocated memory for
|
||||
* data_block_handle.
|
||||
*
|
||||
* \remarks
|
||||
* k4a_playback_get_previous_data_block() cannot be used with the built-in tracks: "COLOR", "DEPTH", etc...
|
||||
* k4a_playback_track_is_builtin() can be used to determine if a track is a built-in track.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_stream_result_t k4a_playback_get_previous_data_block(k4a_playback_t playback_handle,
|
||||
const char *track_name,
|
||||
k4a_playback_data_block_t *data_block_handle);
|
||||
|
||||
/** Get the device timestamp of a data block in microseconds.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* Handle obtained by k4a_playback_get_next_data_block() or k4a_playback_get_previous_data_block().
|
||||
*
|
||||
* \returns
|
||||
* Returns the device timestamp of the data block. If the \p data_block_handle is invalid this function will return 0.
|
||||
* It is also possible for 0 to be a valid timestamp originating from when a device was first powered on.
|
||||
*
|
||||
* \relates k4a_playback_data_block_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT uint64_t
|
||||
k4a_playback_data_block_get_device_timestamp_usec(k4a_playback_data_block_t data_block_handle);
|
||||
|
||||
/** Get the buffer size of a data block.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* Handle obtained by k4a_playback_get_next_data_block() or k4a_playback_get_previous_data_block().
|
||||
*
|
||||
* \returns
|
||||
* Returns the buffer size of the data block, or 0 if the data block is invalid.
|
||||
*
|
||||
* \relates k4a_playback_data_block_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT size_t k4a_playback_data_block_get_buffer_size(k4a_playback_data_block_t data_block_handle);
|
||||
|
||||
/** Get the buffer of a data block.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* Handle obtained by k4a_playback_get_next_data_block() or k4a_playback_get_previous_data_block().
|
||||
*
|
||||
* \remarks
|
||||
* Use this buffer to access the data written to a custom recording track.
|
||||
*
|
||||
* \returns
|
||||
* Returns a pointer to the data block buffer, or NULL if the data block is invalid.
|
||||
*
|
||||
* \relates k4a_playback_data_block_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT uint8_t *k4a_playback_data_block_get_buffer(k4a_playback_data_block_t data_block_handle);
|
||||
|
||||
/** Release a data block handle.
|
||||
*
|
||||
* \param data_block_handle
|
||||
* Handle obtained by k4a_playback_get_next_data_block() or k4a_playback_get_previous_data_block().
|
||||
*
|
||||
* \remarks
|
||||
* Release the memory of a data block. The caller must not access the object after it is released.
|
||||
*
|
||||
* \relates k4a_playback_data_block_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT void k4a_playback_data_block_release(k4a_playback_data_block_t data_block_handle);
|
||||
|
||||
/** Seek to a specific timestamp within a recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \param offset_usec
|
||||
* The timestamp offset to seek to, relative to \p origin
|
||||
*
|
||||
* \param origin
|
||||
* Specifies how the given timestamp should be interpreted. Seek can be done relative to the beginning or end of the
|
||||
* recording, or using an absolute device timestamp.
|
||||
*
|
||||
* \returns
|
||||
* ::K4A_RESULT_SUCCEEDED if the seek operation was successful, or ::K4A_RESULT_FAILED if an error occurred. The current
|
||||
* seek position is left unchanged if a failure is returned.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* The first device timestamp in a recording is usually non-zero. The recording file starts at the device timestamp
|
||||
* defined by start_timestamp_offset_usec, which is accessible via k4a_playback_get_record_configuration().
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_next_capture() after k4a_playback_seek_timestamp() will return the first capture
|
||||
* containing an image timestamp greater than or equal to the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_previous_capture() after k4a_playback_seek_timestamp() will return the first
|
||||
* capture with all image timestamps less than the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_next_imu_sample() after k4a_playback_seek_timestamp() will return the first imu
|
||||
* sample with a timestamp greter than or equal to the seek time.
|
||||
*
|
||||
* \remarks
|
||||
* The first call to k4a_playback_get_previous_imu_sample() after k4a_playback_seek_timestamp() will return the first
|
||||
* imu sample with a timestamp less than the seek time.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_playback_seek_timestamp(k4a_playback_t playback_handle,
|
||||
int64_t offset_usec,
|
||||
k4a_playback_seek_origin_t origin);
|
||||
|
||||
/** Returns the length of the recording in microseconds.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \returns
|
||||
* The recording length, calculated as the difference between the first and last timestamp in the file.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* The recording length may be longer than an individual track if, for example, the IMU continues to run after the last
|
||||
* color image is recorded.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT uint64_t k4a_playback_get_recording_length_usec(k4a_playback_t playback_handle);
|
||||
|
||||
/** Gets the last timestamp in a recording, relative to the start of the recording.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \returns
|
||||
* The file timestamp of the last capture image or IMU sample in microseconds.
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \remarks
|
||||
* This function returns a file timestamp, not an absolute device timestamp, meaning it is relative to the start of the
|
||||
* recording. This function is equivalent to the length of the recording.
|
||||
*
|
||||
* \deprecated
|
||||
* Deprecated starting in 1.2.0. Please use k4a_playback_get_recording_length_usec().
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_DEPRECATED_EXPORT uint64_t k4a_playback_get_last_timestamp_usec(k4a_playback_t playback_handle);
|
||||
|
||||
/** Closes a recording playback handle.
|
||||
*
|
||||
* \param playback_handle
|
||||
* Handle obtained by k4a_playback_open().
|
||||
*
|
||||
* \headerfile playback.h <k4arecord/playback.h>
|
||||
*
|
||||
* \relates k4a_playback_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">playback.h (include k4arecord/playback.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT void k4a_playback_close(k4a_playback_t playback_handle);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* K4A_PLAYBACK_H */
|
@ -1,517 +0,0 @@
|
||||
/** \file playback.hpp
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* Kinect For Azure SDK - C++ wrapper.
|
||||
*/
|
||||
|
||||
#ifndef K4A_PLAYBACK_HPP
|
||||
#define K4A_PLAYBACK_HPP
|
||||
|
||||
#include <k4a/k4a.hpp>
|
||||
#include <k4arecord/playback.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace k4a
|
||||
{
|
||||
|
||||
/** \class data_block playback.hpp <k4arecord/playback.hpp>
|
||||
* Wrapper for \ref k4a_playback_data_block_t
|
||||
*
|
||||
* \sa k4a_playback_data_block_t
|
||||
*/
|
||||
class data_block
|
||||
{
|
||||
public:
|
||||
/** Creates a data_block from a k4a_playback_data_block_t
|
||||
* Takes ownership of the handle, you should not call k4a_playback_data_block_release on the handle after
|
||||
* giving it to the data_block; the data_block will take care of that.
|
||||
*/
|
||||
data_block(k4a_playback_data_block_t handle = nullptr) noexcept : m_handle(handle) {}
|
||||
|
||||
// No Copies allowed
|
||||
data_block(const data_block &) = delete;
|
||||
data_block &operator=(const data_block &) = delete;
|
||||
|
||||
/** Moves another data_block into a new data_block
|
||||
*/
|
||||
data_block(data_block &&other) noexcept
|
||||
{
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
~data_block()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/** Moves another data_block into this data_block; other is set to invalid
|
||||
*/
|
||||
data_block &operator=(data_block &&other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
reset();
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if the data_block is valid, false otherwise
|
||||
*/
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/** Returns true if the data_block is valid, false otherwise
|
||||
*/
|
||||
bool is_valid() const noexcept
|
||||
{
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
/** Releases the underlying k4a_playback_data_block_t; the data_block is set to invalid.
|
||||
*/
|
||||
void reset() noexcept
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
k4a_playback_data_block_release(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the time stamp in micro seconds for the given data_block
|
||||
*
|
||||
* \sa k4a_playback_data_block_get_device_timestamp_usec
|
||||
*/
|
||||
std::chrono::microseconds get_device_timestamp_usec() const noexcept
|
||||
{
|
||||
return std::chrono::microseconds(k4a_playback_data_block_get_device_timestamp_usec(m_handle));
|
||||
}
|
||||
|
||||
/** Get the size of the data_block buffer.
|
||||
*
|
||||
* \sa k4a_playback_data_block_get_buffer_size
|
||||
*/
|
||||
size_t get_buffer_size() const noexcept
|
||||
{
|
||||
return k4a_playback_data_block_get_buffer_size(m_handle);
|
||||
}
|
||||
|
||||
/** Get the data_block buffer.
|
||||
*
|
||||
* \sa k4a_playback_data_block_get_buffer
|
||||
*/
|
||||
const uint8_t *get_buffer() const noexcept
|
||||
{
|
||||
return k4a_playback_data_block_get_buffer(m_handle);
|
||||
}
|
||||
|
||||
private:
|
||||
k4a_playback_data_block_t m_handle;
|
||||
};
|
||||
|
||||
/** \class playback playback.hpp <k4arecord/playback.hpp>
|
||||
* Wrapper for \ref k4a_playback_t
|
||||
*
|
||||
* Wraps a handle for a playback object
|
||||
*
|
||||
* \sa k4a_playback_t
|
||||
*/
|
||||
class playback
|
||||
{
|
||||
public:
|
||||
/** Creates a k4a::playback from a k4a_playback_t
|
||||
* Takes ownership of the handle, i.e. you should not call
|
||||
* k4a_playback_close on the handle after giving it to the
|
||||
* k4a::playback; the k4a::playback will take care of that.
|
||||
*/
|
||||
playback(k4a_playback_t handle = nullptr) noexcept : m_handle(handle) {}
|
||||
|
||||
/** Moves another k4a::playback into a new k4a::playback
|
||||
*/
|
||||
playback(playback &&other) noexcept : m_handle(other.m_handle)
|
||||
{
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
playback(const playback &) = delete;
|
||||
|
||||
~playback()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
playback &operator=(const playback &) = delete;
|
||||
|
||||
/** Moves another k4a::playback into this k4a::playback; other is set to invalid
|
||||
*/
|
||||
playback &operator=(playback &&other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
close();
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if the k4a::playback is valid, false otherwise
|
||||
*/
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/** Returns true if the k4a::playback is valid, false otherwise
|
||||
*/
|
||||
bool is_valid() const noexcept
|
||||
{
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
/** Closes a K4A recording.
|
||||
*
|
||||
* \sa k4a_playback_close
|
||||
*/
|
||||
void close() noexcept
|
||||
{
|
||||
if (m_handle != nullptr)
|
||||
{
|
||||
k4a_playback_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the raw calibration blob for the K4A device that made the recording.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_raw_calibration
|
||||
*/
|
||||
std::vector<uint8_t> get_raw_calibration() const
|
||||
{
|
||||
std::vector<uint8_t> calibration;
|
||||
size_t buffer = 0;
|
||||
k4a_buffer_result_t result = k4a_playback_get_raw_calibration(m_handle, nullptr, &buffer);
|
||||
|
||||
if (result == K4A_BUFFER_RESULT_TOO_SMALL && buffer > 1)
|
||||
{
|
||||
calibration.resize(buffer);
|
||||
result = k4a_playback_get_raw_calibration(m_handle, &calibration[0], &buffer);
|
||||
}
|
||||
|
||||
if (result != K4A_BUFFER_RESULT_SUCCEEDED)
|
||||
{
|
||||
throw error("Failed to read raw device calibration from recording!");
|
||||
}
|
||||
|
||||
return calibration;
|
||||
}
|
||||
|
||||
/** Get the camera calibration for the K4A device that made the recording, which is used for all transformation
|
||||
* functions. Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_calibration
|
||||
*/
|
||||
calibration get_calibration() const
|
||||
{
|
||||
calibration calib;
|
||||
k4a_result_t result = k4a_playback_get_calibration(m_handle, &calib);
|
||||
|
||||
if (K4A_RESULT_SUCCEEDED != result)
|
||||
{
|
||||
throw error("Failed to read device calibration from recording!");
|
||||
}
|
||||
|
||||
return calib;
|
||||
}
|
||||
|
||||
/** Gets the configuration of the recording
|
||||
*
|
||||
* \sa k4a_playback_get_record_configuration
|
||||
*/
|
||||
k4a_record_configuration_t get_record_configuration() const
|
||||
{
|
||||
k4a_record_configuration_t config;
|
||||
k4a_result_t result = k4a_playback_get_record_configuration(m_handle, &config);
|
||||
|
||||
if (K4A_RESULT_SUCCEEDED != result)
|
||||
{
|
||||
throw error("Failed to read record configuration!");
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/** Get the next capture in the recording.
|
||||
* Returns true if a capture was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_next_capture
|
||||
*/
|
||||
bool get_next_capture(capture *cap)
|
||||
{
|
||||
k4a_capture_t capture_handle;
|
||||
k4a_stream_result_t result = k4a_playback_get_next_capture(m_handle, &capture_handle);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
*cap = capture(capture_handle);
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get next capture!");
|
||||
}
|
||||
|
||||
/** Get the previous capture in the recording.
|
||||
* Returns true if a capture was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_previous_capture
|
||||
*/
|
||||
bool get_previous_capture(capture *cap)
|
||||
{
|
||||
k4a_capture_t capture_handle;
|
||||
k4a_stream_result_t result = k4a_playback_get_previous_capture(m_handle, &capture_handle);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
*cap = capture(capture_handle);
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get previous capture!");
|
||||
}
|
||||
|
||||
/** Reads the value of a tag from the recording
|
||||
* Returns false if the tag does not exist.
|
||||
*
|
||||
* \sa k4a_playback_get_tag
|
||||
*/
|
||||
bool get_tag(const char *name, std::string *out) const
|
||||
{
|
||||
std::string tag;
|
||||
size_t buffer = 0;
|
||||
k4a_buffer_result_t result = k4a_playback_get_tag(m_handle, name, nullptr, &buffer);
|
||||
|
||||
if (result == K4A_BUFFER_RESULT_TOO_SMALL && buffer > 0)
|
||||
{
|
||||
tag.resize(buffer);
|
||||
result = k4a_playback_get_tag(m_handle, name, &tag[0], &buffer);
|
||||
if (result == K4A_BUFFER_RESULT_SUCCEEDED && tag[buffer - 1] == 0)
|
||||
{
|
||||
// std::string expects there to not be as null terminator at the end of its data but
|
||||
// k4a_playback_get_tag adds a null terminator, so we drop the last character of the string after we
|
||||
// get the result back.
|
||||
tag.resize(buffer - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != K4A_BUFFER_RESULT_SUCCEEDED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = std::move(tag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get the next IMU sample in the recording.
|
||||
* Returns true if a sample was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_next_imu_sample
|
||||
*/
|
||||
bool get_next_imu_sample(k4a_imu_sample_t *sample)
|
||||
{
|
||||
k4a_stream_result_t result = k4a_playback_get_next_imu_sample(m_handle, sample);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get next IMU sample!");
|
||||
}
|
||||
|
||||
/** Get the previous IMU sample in the recording.
|
||||
* Returns true if a sample was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_previous_imu_sample
|
||||
*/
|
||||
bool get_previous_imu_sample(k4a_imu_sample_t *sample)
|
||||
{
|
||||
k4a_stream_result_t result = k4a_playback_get_previous_imu_sample(m_handle, sample);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get previous IMU sample!");
|
||||
}
|
||||
|
||||
/** Seeks to a specific time point in the recording
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_seek_timestamp
|
||||
*/
|
||||
void seek_timestamp(std::chrono::microseconds offset, k4a_playback_seek_origin_t origin)
|
||||
{
|
||||
k4a_result_t result = k4a_playback_seek_timestamp(m_handle, offset.count(), origin);
|
||||
|
||||
if (K4A_RESULT_SUCCEEDED != result)
|
||||
{
|
||||
throw error("Failed to seek recording!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the last valid timestamp in the recording
|
||||
*
|
||||
* \sa k4a_playback_get_recording_length_usec
|
||||
*/
|
||||
std::chrono::microseconds get_recording_length() const noexcept
|
||||
{
|
||||
return std::chrono::microseconds(k4a_playback_get_recording_length_usec(m_handle));
|
||||
}
|
||||
|
||||
/** Set the image format that color captures will be converted to. By default the conversion format will be the
|
||||
* same as the image format stored in the recording file, and no conversion will occur.
|
||||
*
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_set_color_conversion
|
||||
*/
|
||||
void set_color_conversion(k4a_image_format_t format)
|
||||
{
|
||||
k4a_result_t result = k4a_playback_set_color_conversion(m_handle, format);
|
||||
|
||||
if (K4A_RESULT_SUCCEEDED != result)
|
||||
{
|
||||
throw error("Failed to set color conversion!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the next data block in the recording.
|
||||
* Returns true if a block was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_next_data_block
|
||||
*/
|
||||
bool get_next_data_block(const char *track, data_block *block)
|
||||
{
|
||||
k4a_playback_data_block_t block_handle;
|
||||
k4a_stream_result_t result = k4a_playback_get_next_data_block(m_handle, track, &block_handle);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
*block = data_block(block_handle);
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get next data block!");
|
||||
}
|
||||
|
||||
/** Get the previous data block from the recording.
|
||||
* Returns true if a block was available, false if there are none left.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_previous_data_block
|
||||
*/
|
||||
bool get_previous_data_block(const char *track, data_block *block)
|
||||
{
|
||||
k4a_playback_data_block_t block_handle;
|
||||
k4a_stream_result_t result = k4a_playback_get_previous_data_block(m_handle, track, &block_handle);
|
||||
|
||||
if (K4A_STREAM_RESULT_SUCCEEDED == result)
|
||||
{
|
||||
*block = data_block(block_handle);
|
||||
return true;
|
||||
}
|
||||
else if (K4A_STREAM_RESULT_EOF == result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error("Failed to get previous data block!");
|
||||
}
|
||||
|
||||
/** Get the attachment block from the recording.
|
||||
* Returns true if the attachment was available, false if it was not found.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_get_attachment
|
||||
*/
|
||||
bool get_attachment(const char *attachment, std::vector<uint8_t> *data)
|
||||
{
|
||||
size_t data_size = 0;
|
||||
k4a_buffer_result_t result = k4a_playback_get_attachment(m_handle, attachment, nullptr, &data_size);
|
||||
if (result == K4A_BUFFER_RESULT_TOO_SMALL)
|
||||
{
|
||||
data->resize(data_size);
|
||||
result = k4a_playback_get_attachment(m_handle, attachment, &(*data)[0], &data_size);
|
||||
if (result != K4A_BUFFER_RESULT_SUCCEEDED)
|
||||
{
|
||||
throw error("Failed to read attachment!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Opens a K4A recording for playback.
|
||||
* Throws error on failure.
|
||||
*
|
||||
* \sa k4a_playback_open
|
||||
*/
|
||||
static playback open(const char *path)
|
||||
{
|
||||
k4a_playback_t handle = nullptr;
|
||||
k4a_result_t result = k4a_playback_open(path, &handle);
|
||||
|
||||
if (K4A_RESULT_SUCCEEDED != result)
|
||||
{
|
||||
throw error("Failed to open recording!");
|
||||
}
|
||||
|
||||
return playback(handle);
|
||||
}
|
||||
|
||||
private:
|
||||
k4a_playback_t m_handle;
|
||||
};
|
||||
|
||||
} // namespace k4a
|
||||
|
||||
#endif
|
@ -1,473 +0,0 @@
|
||||
/** \file record.h
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* Kinect For Azure Recording SDK.
|
||||
*/
|
||||
|
||||
#ifndef K4A_RECORD_H
|
||||
#define K4A_RECORD_H
|
||||
|
||||
#include <k4arecord/types.h>
|
||||
#include <k4arecord/k4arecord_export.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* \addtogroup Functions
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Opens a new recording file for writing.
|
||||
*
|
||||
* \param path
|
||||
* Filesystem path for the new recording.
|
||||
*
|
||||
* \param device
|
||||
* The Azure Kinect device that is being recorded. The device handle is used to store device calibration and serial
|
||||
* number information. May be NULL if recording user-generated data.
|
||||
*
|
||||
* \param device_config
|
||||
* The configuration the Azure Kinect device was started with.
|
||||
*
|
||||
* \param recording_handle
|
||||
* If successful, this contains a pointer to the new recording handle. Caller must call k4a_record_close()
|
||||
* when finished with recording.
|
||||
*
|
||||
* \remarks
|
||||
* The file will be created if it doesn't exist, or overwritten if an existing file is specified.
|
||||
*
|
||||
* \remarks
|
||||
* Streaming does not need to be started on the device at the time this function is called, but when it is started
|
||||
* it should be started with the same configuration provided in \p device_config.
|
||||
*
|
||||
* \remarks
|
||||
* Subsequent calls to k4a_record_write_capture() will need to have images in the resolution and format defined
|
||||
* in \p device_config.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_create(const char *path,
|
||||
k4a_device_t device,
|
||||
const k4a_device_configuration_t device_config,
|
||||
k4a_record_t *recording_handle);
|
||||
|
||||
/** Adds a tag to the recording.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param name
|
||||
* The name of the tag to write.
|
||||
*
|
||||
* \param value
|
||||
* The string value to store in the tag.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success.
|
||||
*
|
||||
* \remarks
|
||||
* Tags are global to a file, and should store data related to the entire recording, such as camera configuration or
|
||||
* recording location.
|
||||
*
|
||||
* \remarks
|
||||
* Tag names must be ALL CAPS and may only contain A-Z, 0-9, '-' and '_'.
|
||||
*
|
||||
* \remarks
|
||||
* All tags need to be added before the recording header is written.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_add_tag(k4a_record_t recording_handle, const char *name, const char *value);
|
||||
|
||||
/** Adds the track header for recording IMU.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* The track needs to be added before the recording header is written.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_add_imu_track(k4a_record_t recording_handle);
|
||||
|
||||
/** Adds an attachment to the recording.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param attachment_name
|
||||
* The name of the attachment to be stored in the recording file. This name should be a valid filename with an
|
||||
* extension.
|
||||
*
|
||||
* \param buffer
|
||||
* The attachment data buffer.
|
||||
*
|
||||
* \param buffer_size
|
||||
* The size of the attachment data buffer.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* All attachments need to be added before the recording header is written.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_add_attachment(const k4a_record_t recording_handle,
|
||||
const char *attachment_name,
|
||||
const uint8_t *buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
/** Adds custom video tracks to the recording.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param track_name
|
||||
* The name of the custom video track to be added.
|
||||
*
|
||||
* \param codec_id
|
||||
* A UTF8 null terminated string containing the codec ID of the track. Some of the existing formats are listed here:
|
||||
* https://www.matroska.org/technical/specs/codecid/index.html. The codec ID can also be custom defined by the user.
|
||||
* Video codec ID's should start with 'V_'.
|
||||
*
|
||||
* \param codec_context
|
||||
* The codec context is a codec-specific buffer that contains any required codec metadata that is only known to the
|
||||
* codec. It is mapped to the matroska 'CodecPrivate' element.
|
||||
*
|
||||
* \param codec_context_size
|
||||
* The size of the codec context buffer.
|
||||
*
|
||||
* \param track_settings
|
||||
* Additional metadata for the video track such as resolution and framerate.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* Built-in video tracks like the DEPTH, IR, and COLOR tracks will be created automatically when the k4a_record_create()
|
||||
* API is called. This API can be used to add additional video tracks to save custom data.
|
||||
*
|
||||
* \remarks
|
||||
* Track names must be ALL CAPS and may only contain A-Z, 0-9, '-' and '_'.
|
||||
*
|
||||
* \remarks
|
||||
* All tracks need to be added before the recording header is written.
|
||||
*
|
||||
* \remarks
|
||||
* Call k4a_record_write_custom_track_data() with the same track_name to write data to this track.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_add_custom_video_track(const k4a_record_t recording_handle,
|
||||
const char *track_name,
|
||||
const char *codec_id,
|
||||
const uint8_t *codec_context,
|
||||
size_t codec_context_size,
|
||||
const k4a_record_video_settings_t *track_settings);
|
||||
|
||||
/** Adds custom subtitle tracks to the recording.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param track_name
|
||||
* The name of the custom subtitle track to be added.
|
||||
*
|
||||
* \param codec_id
|
||||
* A UTF8 null terminated string containing the codec ID of the track. Some of the existing formats are listed here:
|
||||
* https://www.matroska.org/technical/specs/codecid/index.html. The codec ID can also be custom defined by the user.
|
||||
* Subtitle codec ID's should start with 'S_'.
|
||||
*
|
||||
* \param codec_context
|
||||
* The codec context is a codec-specific buffer that contains any required codec metadata that is only known to the
|
||||
* codec. It is mapped to the matroska 'CodecPrivate' element.
|
||||
*
|
||||
* \param codec_context_size
|
||||
* The size of the codec context buffer.
|
||||
*
|
||||
* \param track_settings
|
||||
* Additional metadata for the subtitle track. If NULL, the default settings will be used.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* Built-in subtitle tracks like the IMU track will be created automatically when the k4a_record_add_imu_track() API is
|
||||
* called. This API can be used to add additional subtitle tracks to save custom data.
|
||||
*
|
||||
* \remarks
|
||||
* Track names must be ALL CAPS and may only contain A-Z, 0-9, '-' and '_'.
|
||||
*
|
||||
* \remarks
|
||||
* All tracks need to be added before the recording header is written.
|
||||
*
|
||||
* \remarks
|
||||
* Call k4a_record_write_custom_track_data() with the same track_name to write data to this track.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t
|
||||
k4a_record_add_custom_subtitle_track(const k4a_record_t recording_handle,
|
||||
const char *track_name,
|
||||
const char *codec_id,
|
||||
const uint8_t *codec_context,
|
||||
size_t codec_context_size,
|
||||
const k4a_record_subtitle_settings_t *track_settings);
|
||||
|
||||
/** Writes the recording header and metadata to file.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* This must be called before captures or any track data can be written.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_write_header(k4a_record_t recording_handle);
|
||||
|
||||
/** Writes a camera capture to file.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param capture_handle
|
||||
* The handle of a capture to write to file.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* Captures must be written in increasing order of timestamp, and the file's header must already be written.
|
||||
*
|
||||
* \remarks
|
||||
* k4a_record_write_capture() will write all images in the capture to the corresponding tracks in the recording file.
|
||||
* If any of the images fail to write, other images will still be written before a failure is returned.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_write_capture(k4a_record_t recording_handle, k4a_capture_t capture_handle);
|
||||
|
||||
/** Writes an imu sample to file.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param imu_sample
|
||||
* A structure containing the imu sample data and timestamps.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* Samples must be written in increasing order of timestamp, and the file's header must already be written.
|
||||
*
|
||||
* \remarks
|
||||
* When writing imu samples at the same time as captures, the samples should be within 1 second of the most recently
|
||||
* written capture.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_write_imu_sample(k4a_record_t recording_handle, k4a_imu_sample_t imu_sample);
|
||||
|
||||
/** Writes data for a custom track to file.
|
||||
*
|
||||
* \param recording_handle
|
||||
* The handle of a new recording, obtained by k4a_record_create().
|
||||
*
|
||||
* \param track_name
|
||||
* The name of the custom track that the data is going to be written to.
|
||||
*
|
||||
* \param device_timestamp_usec
|
||||
* The timestamp in microseconds for the custom track data. This timestamp should be in the same time domain as the
|
||||
* device timestamp used for recording.
|
||||
*
|
||||
* \param custom_data
|
||||
* The buffer of custom track data.
|
||||
*
|
||||
* \param custom_data_size
|
||||
* The size of the custom track data buffer.
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success
|
||||
*
|
||||
* \remarks
|
||||
* Custom track data must be written in increasing order of timestamp, and the file's header must already be written.
|
||||
* When writing custom track data at the same time as captures or IMU data, the custom data should be within 1 second of
|
||||
* the most recently written timestamp.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_write_custom_track_data(const k4a_record_t recording_handle,
|
||||
const char *track_name,
|
||||
uint64_t device_timestamp_usec,
|
||||
uint8_t *custom_data,
|
||||
size_t custom_data_size);
|
||||
|
||||
/** Flushes all pending recording data to disk.
|
||||
*
|
||||
* \param recording_handle
|
||||
* Handle obtained by k4a_record_create().
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \returns ::K4A_RESULT_SUCCEEDED is returned on success, or ::K4A_RESULT_FAILED if an error occurred.
|
||||
*
|
||||
* \remarks
|
||||
* k4a_record_flush() ensures that all data passed to the recording API prior to calling flush is written to disk.
|
||||
* If continuing to write recording data, care must be taken to ensure no new timestamps are added from before the
|
||||
* flush.
|
||||
*
|
||||
* \remarks
|
||||
* If an error occurs, best effort is made to flush as much data to disk as possible, but the integrity of the file is
|
||||
* not guaranteed.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT k4a_result_t k4a_record_flush(k4a_record_t recording_handle);
|
||||
|
||||
/** Closes a recording handle.
|
||||
*
|
||||
* \param recording_handle
|
||||
* Handle obtained by k4a_record_create().
|
||||
*
|
||||
* \headerfile record.h <k4arecord/record.h>
|
||||
*
|
||||
* \relates k4a_record_t
|
||||
*
|
||||
* \remarks
|
||||
* If there is any unwritten data it will be flushed to disk before closing the recording.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">record.h (include k4arecord/record.h)</requirement>
|
||||
* <requirement name="Library">k4arecord.lib</requirement>
|
||||
* <requirement name="DLL">k4arecord.dll</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4ARECORD_EXPORT void k4a_record_close(k4a_record_t recording_handle);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* K4A_RECORD_H */
|
@ -1,292 +0,0 @@
|
||||
/** \file record.hpp
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* Kinect For Azure SDK - C++ wrapper.
|
||||
*/
|
||||
#ifndef K4A_RECORD_HPP
|
||||
#define K4A_RECORD_HPP
|
||||
|
||||
#include <k4a/k4a.hpp>
|
||||
#include <k4arecord/record.h>
|
||||
|
||||
namespace k4a
|
||||
{
|
||||
|
||||
/** \class record record.hpp
|
||||
* Wrapper for \ref k4a_record_t
|
||||
*
|
||||
* Wraps a handle for a record object
|
||||
*
|
||||
* \sa k4a_record_t
|
||||
*/
|
||||
class record
|
||||
{
|
||||
public:
|
||||
/** Creates a k4a::record from a k4a_record_t
|
||||
* Takes ownership of the handle, i.e. you should not call
|
||||
* k4a_record_close on the handle after giving it to the
|
||||
* k4a::record; the k4a::record will take care of that.
|
||||
*/
|
||||
record(k4a_record_t handle = nullptr) noexcept : m_handle(handle) {}
|
||||
|
||||
/** Moves another k4a::record into a new k4a::record
|
||||
*/
|
||||
record(record &&other) noexcept : m_handle(other.m_handle)
|
||||
{
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
record(const record &) = delete;
|
||||
|
||||
~record()
|
||||
{
|
||||
// NOTE: flush is called internally when closing record
|
||||
close();
|
||||
}
|
||||
|
||||
record &operator=(const record &) = delete;
|
||||
|
||||
/** Moves another k4a::record into this k4a::record; other is set to invalid
|
||||
*/
|
||||
record &operator=(record &&other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
close();
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns true if the k4a::record is valid, false otherwise
|
||||
*/
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/** Returns true if the k4a::record is valid, false otherwise
|
||||
*/
|
||||
bool is_valid() const noexcept
|
||||
{
|
||||
return m_handle != nullptr;
|
||||
}
|
||||
|
||||
/** Closes a K4A recording.
|
||||
*
|
||||
* \sa k4a_record_close
|
||||
*/
|
||||
void close() noexcept
|
||||
{
|
||||
if (is_valid())
|
||||
{
|
||||
k4a_record_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Flushes all pending recording data to disk
|
||||
*
|
||||
* \sa k4a_record_flush
|
||||
*/
|
||||
void flush()
|
||||
{
|
||||
if (m_handle)
|
||||
{
|
||||
k4a_result_t result = k4a_record_flush(m_handle);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to flush!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a tag to the recording
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_add_tag
|
||||
*/
|
||||
void add_tag(const char *name, const char *value)
|
||||
{
|
||||
k4a_result_t result = k4a_record_add_tag(m_handle, name, value);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to add tag!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds the track header for recording IMU
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_add_imu_track
|
||||
*/
|
||||
void add_imu_track()
|
||||
{
|
||||
k4a_result_t result = k4a_record_add_imu_track(m_handle);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to add imu_track!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds an attachment to the recording
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_add_attachment
|
||||
*/
|
||||
void add_attachment(const char *attachment_name, const uint8_t *buffer, size_t buffer_size)
|
||||
{
|
||||
k4a_result_t result = k4a_record_add_attachment(m_handle, attachment_name, buffer, buffer_size);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to add attachment!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds custom video tracks to the recording
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_add_custom_video_track
|
||||
*/
|
||||
void add_custom_video_track(const char *track_name,
|
||||
const char *codec_id,
|
||||
const uint8_t *codec_context,
|
||||
size_t codec_context_size,
|
||||
const k4a_record_video_settings_t *track_settings)
|
||||
{
|
||||
k4a_result_t result = k4a_record_add_custom_video_track(m_handle,
|
||||
track_name,
|
||||
codec_id,
|
||||
codec_context,
|
||||
codec_context_size,
|
||||
track_settings);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to add custom video track!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds custom subtitle tracks to the recording
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_add_custom_subtitle_track
|
||||
*/
|
||||
void add_custom_subtitle_track(const char *track_name,
|
||||
const char *codec_id,
|
||||
const uint8_t *codec_context,
|
||||
size_t codec_context_size,
|
||||
const k4a_record_subtitle_settings_t *track_settings)
|
||||
{
|
||||
k4a_result_t result = k4a_record_add_custom_subtitle_track(m_handle,
|
||||
track_name,
|
||||
codec_id,
|
||||
codec_context,
|
||||
codec_context_size,
|
||||
track_settings);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to add custom subtitle track!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes the recording header and metadata to file
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_write_header
|
||||
*/
|
||||
void write_header()
|
||||
{
|
||||
k4a_result_t result = k4a_record_write_header(m_handle);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to write header!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes a camera capture to file
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_write_capture
|
||||
*/
|
||||
void write_capture(const capture &capture)
|
||||
{
|
||||
k4a_result_t result = k4a_record_write_capture(m_handle, capture.handle());
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to write capture!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes an imu sample to file
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_write_imu_sample
|
||||
*/
|
||||
void write_imu_sample(const k4a_imu_sample_t &imu_sample)
|
||||
{
|
||||
k4a_result_t result = k4a_record_write_imu_sample(m_handle, imu_sample);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to write imu sample!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes data for a custom track to file
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_write_custom_track_data
|
||||
*/
|
||||
void write_custom_track_data(const char *track_name,
|
||||
const std::chrono::microseconds device_timestamp_usec,
|
||||
uint8_t *custom_data,
|
||||
size_t custom_data_size)
|
||||
{
|
||||
k4a_result_t result = k4a_record_write_custom_track_data(m_handle,
|
||||
track_name,
|
||||
internal::clamp_cast<uint64_t>(
|
||||
device_timestamp_usec.count()),
|
||||
custom_data,
|
||||
custom_data_size);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to write custom track data!");
|
||||
}
|
||||
}
|
||||
|
||||
/** Opens a new recording file for writing
|
||||
* Throws error on failure
|
||||
*
|
||||
* \sa k4a_record_create
|
||||
*/
|
||||
static record create(const char *path, const device &device, const k4a_device_configuration_t &device_configuration)
|
||||
{
|
||||
k4a_record_t handle = nullptr;
|
||||
k4a_result_t result = k4a_record_create(path, device.handle(), device_configuration, &handle);
|
||||
|
||||
if (K4A_FAILED(result))
|
||||
{
|
||||
throw error("Failed to create recorder!");
|
||||
}
|
||||
|
||||
return record(handle);
|
||||
}
|
||||
|
||||
private:
|
||||
k4a_record_t m_handle;
|
||||
};
|
||||
|
||||
} // namespace k4a
|
||||
|
||||
#endif
|
@ -1,261 +0,0 @@
|
||||
/** \file types.h
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
* Kinect For Azure Playback/Record type definitions.
|
||||
*/
|
||||
|
||||
#ifndef K4ARECORD_TYPES_H
|
||||
#define K4ARECORD_TYPES_H
|
||||
|
||||
#include <k4a/k4atypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup Handles
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** \class k4a_record_t types.h <k4arecord/types.h>
|
||||
* Handle to a k4a recording opened for writing.
|
||||
*
|
||||
* \remarks
|
||||
* Handles are created with k4a_record_create(), and closed with k4a_record_close().
|
||||
* Invalid handles are set to 0.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4A_DECLARE_HANDLE(k4a_record_t);
|
||||
|
||||
/** \class k4a_playback_t types.h <k4arecord/types.h>
|
||||
* Handle to a k4a recording opened for playback.
|
||||
*
|
||||
* \remarks
|
||||
* Handles are created with k4a_playback_open(), and closed with k4a_playback_close().
|
||||
* Invalid handles are set to 0.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4A_DECLARE_HANDLE(k4a_playback_t);
|
||||
|
||||
/** \class k4a_playback_data_block_t types.h <k4arecord/types.h>
|
||||
* Handle to a block of data read from a k4a_playback_t custom track.
|
||||
*
|
||||
* \remarks
|
||||
* Handles are obtained from k4a_playback_get_next_data_block() or k4a_playback_get_previous_data_block(), and released
|
||||
* with k4a_playback_data_block_release(). Invalid handles are set to 0.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
K4A_DECLARE_HANDLE(k4a_playback_data_block_t)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
* \addtogroup Definitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Name of the built-in color track used in recordings.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
#define K4A_TRACK_NAME_COLOR "COLOR"
|
||||
|
||||
/** Name of the built-in depth track used in recordings.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
#define K4A_TRACK_NAME_DEPTH "DEPTH"
|
||||
|
||||
/** Name of the built-in IR track used in recordings.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
#define K4A_TRACK_NAME_IR "IR"
|
||||
|
||||
/** Name of the built-in imu track used in recordings.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
#define K4A_TRACK_NAME_IMU "IMU"
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
* \addtogroup Enumerations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Return codes returned by Azure Kinect playback API.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
K4A_STREAM_RESULT_SUCCEEDED = 0, /**< The result was successful. */
|
||||
K4A_STREAM_RESULT_FAILED, /**< The result was a failure. */
|
||||
K4A_STREAM_RESULT_EOF, /**< The end of the data stream was reached. */
|
||||
} k4a_stream_result_t;
|
||||
|
||||
/** Playback seeking positions.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
K4A_PLAYBACK_SEEK_BEGIN, /**< Seek relative to the beginning of a recording. */
|
||||
K4A_PLAYBACK_SEEK_END, /**< Seek relative to the end of a recording. */
|
||||
K4A_PLAYBACK_SEEK_DEVICE_TIME /**< Seek to an absolute device timestamp. */
|
||||
} k4a_playback_seek_origin_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
* \addtogroup Structures
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Structure containing the device configuration used to record.
|
||||
*
|
||||
* \see k4a_device_configuration_t
|
||||
* \see k4a_playback_get_record_configuration()
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
typedef struct _k4a_record_configuration_t
|
||||
{
|
||||
/** Image format used to record the color camera. */
|
||||
k4a_image_format_t color_format;
|
||||
|
||||
/** Image resolution used to record the color camera. */
|
||||
k4a_color_resolution_t color_resolution;
|
||||
|
||||
/** Mode used to record the depth camera. */
|
||||
k4a_depth_mode_t depth_mode;
|
||||
|
||||
/** Frame rate used to record the color and depth camera. */
|
||||
k4a_fps_t camera_fps;
|
||||
|
||||
/** True if the recording contains Color camera frames. */
|
||||
bool color_track_enabled;
|
||||
|
||||
/** True if the recording contains Depth camera frames. */
|
||||
bool depth_track_enabled;
|
||||
|
||||
/** True if the recording contains IR camera frames. */
|
||||
bool ir_track_enabled;
|
||||
|
||||
/** True if the recording contains IMU sample data. */
|
||||
bool imu_track_enabled;
|
||||
|
||||
/**
|
||||
* The delay between color and depth images in the recording.
|
||||
* A negative delay means depth images are first, and a positive delay means color images are first.
|
||||
*/
|
||||
int32_t depth_delay_off_color_usec;
|
||||
|
||||
/** External synchronization mode */
|
||||
k4a_wired_sync_mode_t wired_sync_mode;
|
||||
|
||||
/**
|
||||
* The delay between this recording and the externally synced master camera.
|
||||
* This value is 0 unless \p wired_sync_mode is set to ::K4A_WIRED_SYNC_MODE_SUBORDINATE
|
||||
*/
|
||||
uint32_t subordinate_delay_off_master_usec;
|
||||
|
||||
/**
|
||||
* The timestamp offset of the start of the recording. All recorded timestamps are offset by this value such that
|
||||
* the recording starts at timestamp 0. This value can be used to synchronize timestamps between 2 recording files.
|
||||
*/
|
||||
uint64_t start_timestamp_offset_usec;
|
||||
} k4a_record_configuration_t;
|
||||
|
||||
/** Structure containing additional metadata specific to custom video tracks.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
typedef struct _k4a_record_video_settings_t
|
||||
{
|
||||
uint64_t width; /**< Frame width of the video */
|
||||
uint64_t height; /**< Frame height of the video */
|
||||
uint64_t frame_rate; /**< Frame rate (frames-per-second) of the video */
|
||||
} k4a_record_video_settings_t;
|
||||
|
||||
/** Structure containing additional metadata specific to custom subtitle tracks.
|
||||
*
|
||||
* \xmlonly
|
||||
* <requirements>
|
||||
* <requirement name="Header">types.h (include k4arecord/types.h)</requirement>
|
||||
* </requirements>
|
||||
* \endxmlonly
|
||||
*/
|
||||
typedef struct _k4a_record_subtitle_settings_t
|
||||
{
|
||||
/**
|
||||
* If true, data will be grouped together in batches to reduce overhead. In this mode, only a single timestamp will
|
||||
* be stored per batch, and an estimated timestamp will be used by k4a_playback_seek_timestamp() and
|
||||
* k4a_playback_data_block_get_timestamp_usec(). The estimated timestamp is calculated with the assumption that
|
||||
* blocks are evenly spaced within a batch. If precise timestamps are required, the timestamp should be added to
|
||||
* each data block itself.
|
||||
*
|
||||
* If false, data will be stored as individual blocks with full timestamp information (Default).
|
||||
*/
|
||||
bool high_freq_data;
|
||||
} k4a_record_subtitle_settings_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* K4ARECORD_TYPES_H */
|
@ -1,7 +0,0 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Add the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/k4aTargets.cmake")
|
@ -1,43 +0,0 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
set(PACKAGE_VERSION "1.4.0")
|
||||
|
||||
if (PACKAGE_FIND_VERSION_RANGE)
|
||||
# Package version must be in the requested version range
|
||||
if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
|
||||
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
|
||||
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
@ -1,20 +0,0 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Release".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "k4a::k4a" for configuration "Release"
|
||||
set_property(TARGET k4a::k4a APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(k4a::k4a PROPERTIES
|
||||
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/k4a.lib"
|
||||
IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE "OrbbecSDK::OrbbecSDK"
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/k4a.dll"
|
||||
)
|
||||
|
||||
list(APPEND _cmake_import_check_targets k4a::k4a )
|
||||
list(APPEND _cmake_import_check_files_for_k4a::k4a "${_IMPORT_PREFIX}/lib/k4a.lib" "${_IMPORT_PREFIX}/bin/k4a.dll" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
@ -1,102 +0,0 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
|
||||
message(FATAL_ERROR "CMake >= 2.8.0 required")
|
||||
endif()
|
||||
if(CMAKE_VERSION VERSION_LESS "2.8.3")
|
||||
message(FATAL_ERROR "CMake >= 2.8.3 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.8.3...3.25)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_cmake_targets_defined "")
|
||||
set(_cmake_targets_not_defined "")
|
||||
set(_cmake_expected_targets "")
|
||||
foreach(_cmake_expected_target IN ITEMS k4a::k4a)
|
||||
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
|
||||
if(TARGET "${_cmake_expected_target}")
|
||||
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
|
||||
else()
|
||||
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_cmake_expected_target)
|
||||
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
|
||||
unset(_cmake_targets_defined)
|
||||
unset(_cmake_targets_not_defined)
|
||||
unset(_cmake_expected_targets)
|
||||
unset(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT _cmake_targets_defined STREQUAL "")
|
||||
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
|
||||
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
|
||||
endif()
|
||||
unset(_cmake_targets_defined)
|
||||
unset(_cmake_targets_not_defined)
|
||||
unset(_cmake_expected_targets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target k4a::k4a
|
||||
add_library(k4a::k4a SHARED IMPORTED)
|
||||
|
||||
set_target_properties(k4a::k4a PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
|
||||
)
|
||||
|
||||
# Load information for each installed configuration.
|
||||
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/k4aTargets-*.cmake")
|
||||
foreach(_cmake_config_file IN LISTS _cmake_config_files)
|
||||
include("${_cmake_config_file}")
|
||||
endforeach()
|
||||
unset(_cmake_config_file)
|
||||
unset(_cmake_config_files)
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
|
||||
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
|
||||
if(NOT EXISTS "${_cmake_file}")
|
||||
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
|
||||
\"${_cmake_file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_cmake_file)
|
||||
unset("_cmake_import_check_files_for_${_cmake_target}")
|
||||
endforeach()
|
||||
unset(_cmake_target)
|
||||
unset(_cmake_import_check_targets)
|
||||
|
||||
# This file does not depend on other imported targets which have
|
||||
# been exported from the same project but in a separate export set.
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
@ -1,7 +0,0 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Add the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/k4arecordTargets.cmake")
|
@ -1,43 +0,0 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
set(PACKAGE_VERSION "1.4.0")
|
||||
|
||||
if (PACKAGE_FIND_VERSION_RANGE)
|
||||
# Package version must be in the requested version range
|
||||
if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
|
||||
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
|
||||
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
@ -1,19 +0,0 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Release".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "k4a::k4arecord" for configuration "Release"
|
||||
set_property(TARGET k4a::k4arecord APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(k4a::k4arecord PROPERTIES
|
||||
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/k4arecord.lib"
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/k4arecord.dll"
|
||||
)
|
||||
|
||||
list(APPEND _cmake_import_check_targets k4a::k4arecord )
|
||||
list(APPEND _cmake_import_check_files_for_k4a::k4arecord "${_IMPORT_PREFIX}/lib/k4arecord.lib" "${_IMPORT_PREFIX}/bin/k4arecord.dll" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
@ -1,123 +0,0 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
|
||||
message(FATAL_ERROR "CMake >= 2.8.0 required")
|
||||
endif()
|
||||
if(CMAKE_VERSION VERSION_LESS "2.8.3")
|
||||
message(FATAL_ERROR "CMake >= 2.8.3 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.8.3...3.25)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_cmake_targets_defined "")
|
||||
set(_cmake_targets_not_defined "")
|
||||
set(_cmake_expected_targets "")
|
||||
foreach(_cmake_expected_target IN ITEMS k4a::k4arecord)
|
||||
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
|
||||
if(TARGET "${_cmake_expected_target}")
|
||||
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
|
||||
else()
|
||||
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_cmake_expected_target)
|
||||
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
|
||||
unset(_cmake_targets_defined)
|
||||
unset(_cmake_targets_not_defined)
|
||||
unset(_cmake_expected_targets)
|
||||
unset(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT _cmake_targets_defined STREQUAL "")
|
||||
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
|
||||
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
|
||||
endif()
|
||||
unset(_cmake_targets_defined)
|
||||
unset(_cmake_targets_not_defined)
|
||||
unset(_cmake_expected_targets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target k4a::k4arecord
|
||||
add_library(k4a::k4arecord SHARED IMPORTED)
|
||||
|
||||
set_target_properties(k4a::k4arecord PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
|
||||
INTERFACE_LINK_LIBRARIES "k4a::k4a;OrbbecSDK::OrbbecSDK"
|
||||
)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 2.8.12)
|
||||
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
|
||||
endif()
|
||||
|
||||
# Load information for each installed configuration.
|
||||
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/k4arecordTargets-*.cmake")
|
||||
foreach(_cmake_config_file IN LISTS _cmake_config_files)
|
||||
include("${_cmake_config_file}")
|
||||
endforeach()
|
||||
unset(_cmake_config_file)
|
||||
unset(_cmake_config_files)
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
|
||||
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
|
||||
if(NOT EXISTS "${_cmake_file}")
|
||||
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
|
||||
\"${_cmake_file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_cmake_file)
|
||||
unset("_cmake_import_check_files_for_${_cmake_target}")
|
||||
endforeach()
|
||||
unset(_cmake_target)
|
||||
unset(_cmake_import_check_targets)
|
||||
|
||||
# Make sure the targets which have been exported in some other
|
||||
# export set exist.
|
||||
unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)
|
||||
foreach(_target "k4a::k4a" )
|
||||
if(NOT TARGET "${_target}" )
|
||||
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets "${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets} ${_target}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(DEFINED ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)
|
||||
if(CMAKE_FIND_PACKAGE_NAME)
|
||||
set( ${CMAKE_FIND_PACKAGE_NAME}_FOUND FALSE)
|
||||
set( ${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "The following imported targets are referenced, but are missing: ${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}")
|
||||
else()
|
||||
message(FATAL_ERROR "The following imported targets are referenced, but are missing: ${${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets}")
|
||||
endif()
|
||||
endif()
|
||||
unset(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE_targets)
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
@ -1,35 +0,0 @@
|
||||
# obsensor_metadata_win10
|
||||
This document introduces two different methods for setting Metadata, explaining their advantages, disadvantages, and precautions.
|
||||
|
||||
## Registering Metadata Using a Script
|
||||
|
||||
To get device timestamps through UVC protocol, users need to modify the registry and complete registration first, because Windows system has default limitations.
|
||||
|
||||
1. Connect the device and confirm that the device is online;
|
||||
2. Open powershell with administrator privileges, then `cd` command to enter the `scripts` directory;
|
||||
3. Execute the `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` command, and enter `Y` as prompted to confirm;
|
||||
4. Execute `.\obsensor_metadata_win10.ps1 -op install_all` to complete the registration.
|
||||
|
||||
**Notes**
|
||||
|
||||
Users need to run this script every time a new device is connected. This process can be cumbersome and easy to forget, leading to an inability to obtain the device's Metadata.
|
||||
|
||||
|
||||
## Registering Metadata Using Code
|
||||
|
||||
The purpose of the WindowsMetaDataHelper code(Script\WindowsMetaDataHelper) is to demonstrate how to programmatically register Metadata on the Windows platform.
|
||||
|
||||
**Notes**
|
||||
|
||||
1. The code must be run with administrator privileges, and the PID and VID passed into the code must be in decimal format.
|
||||
2. If multiple different types of device(different PID) are used, the registration code must be called for the PID of each device.
|
||||
|
||||
|
||||
**Advantages**
|
||||
|
||||
Devices of the same type (same PID) only need to be registered once, and new devices can be recognized for Metadata without additional registration.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,126 +0,0 @@
|
||||
# Usage:
|
||||
#Launch Windows PowerShell, and navigate to the script directory
|
||||
#PS> .\obsensor_metadata_win10.ps1 - Add metadata reg. keys for the connected Orbbec devices
|
||||
#PS> .\obsensor_metadata_win10.ps1 -op install - See above
|
||||
#PS> .\obsensor_metadata_win10.ps1 -op install_all - Add metadata reg. keys for all Orbbec devices that were previously connected
|
||||
#PS> .\obsensor_metadata_win10.ps1 -op remove - Remove metadata reg. keys for the connected Orbbec devices
|
||||
#PS> .\obsensor_metadata_win10.ps1 -op remove_all - Remove metadata reg. keys for all Orbbec devices that were previously connected
|
||||
|
||||
|
||||
#Parse command-line argument
|
||||
param (
|
||||
[string]$op = "install"
|
||||
)
|
||||
|
||||
# Elevate to admin - https://stackoverflow.com/questions/7690994/powershell-running-a-command-as-administrator
|
||||
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
|
||||
{
|
||||
# The original script is modified to pass through the command-line parameter
|
||||
$arguments = "& '" + $myinvocation.mycommand.definition + "'" + " -op " + $op
|
||||
Start-Process powershell -Verb runAs -ArgumentList $arguments
|
||||
Break
|
||||
}
|
||||
|
||||
# Base location for the registry keys we need to add
|
||||
$DevConfigRegBase = "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceClasses"
|
||||
# The Registry subtrees for the Metadata keys shall be added
|
||||
$guid1 = "{e5323777-f976-4f5b-9b55-b94699c46e44}";
|
||||
$guid2 = "{65E8773D-8F56-11D0-A3B9-00A0C9223196}";
|
||||
|
||||
$SearchTrees = "$DevConfigRegBase\$guid1", "$DevConfigRegBase\$guid2"
|
||||
|
||||
# Multipin devices that need additional key MetadataBufferSizeInKB1 & MetadataBufferSizeInKB2 & etc...
|
||||
$MultiPinDevices = "USB\VID_2BC5&PID_06D0&MI_00", # Gemini 2 R // 3 pin for depth uvc
|
||||
"USB\VID_2BC5&PID_06D1&MI_00" # Gemini 2 RL // 3 pin for depth uvc
|
||||
|
||||
#Inhibit system warnings and erros, such as permissions or missing values
|
||||
$ErrorActionPreference = "silentlycontinue"
|
||||
|
||||
$ConnectedDev = @()
|
||||
#Retrieve all connected UVC devices
|
||||
$DevInReg = Get-ChildItem hklm:\SYSTEM\CurrentControlSet\Services\usbvideo | ForEach-Object {Get-ItemProperty $_.pspath}
|
||||
|
||||
#Transform output into a standard container
|
||||
for ($i=0; $i -lt $DevInReg[0].Count; $i++) { $ConnectedDev +=$DevInReg[0].$i}
|
||||
|
||||
#Filter Orbbec devices
|
||||
#$ConnectedDev = $ConnectedDev -like "*VID_8086*"
|
||||
$ConnectedDev = $ConnectedDev -like "*VID_2BC5*"
|
||||
|
||||
#Progress notification
|
||||
$rs_count = $ConnectedDev.Count
|
||||
echo "$rs_count connected Orbbec devices were found:" $ConnectedDev
|
||||
|
||||
#Search each subtree for values that correspond to the requested Orbbec devices
|
||||
foreach ($subtree in $SearchTrees)
|
||||
{
|
||||
"`nProcessing Registry branch $subtree"
|
||||
#Get records for all UVC devices records
|
||||
$Items = Get-ChildItem $subtree | Foreach-Object {Get-ItemProperty $_.PsPath }
|
||||
|
||||
#Filter Orbbec devices
|
||||
"There are " + $Items.Count +" total devices listed"
|
||||
# $Items = $Items | Where { $_.DeviceInstance -like "*VID_8086*" }
|
||||
$Items = $Items | Where { $_.DeviceInstance -like "*VID_2BC5*" }
|
||||
"" + $Items.Count + " of them are Orbbec devices"
|
||||
|
||||
$remove_keys = 0
|
||||
switch ($op)
|
||||
{
|
||||
"install" { $Items = $Items | Where { $ConnectedDev -contains $_.DeviceInstance }}
|
||||
"remove" { $Items = $Items | Where { $ConnectedDev -contains $_.DeviceInstance }; $remove_keys = 1 }
|
||||
"install_all" { }
|
||||
"remove_all" { $remove_keys = 1 }
|
||||
default { "Aborting: unrecognized argument "" + $op + "" provided.`nPossible values are:";
|
||||
"`t`t -op [install/install_all/remove/remove_all].`nRefer to the installation manual for details"; Sleep 2; Exit }
|
||||
}
|
||||
|
||||
foreach ($item in $Items)
|
||||
{
|
||||
|
||||
$fullPath = $item.PSPath+'\#global\Device Parameters'
|
||||
|
||||
if ($remove_keys -ge 1)
|
||||
{
|
||||
"Remove keys for device: " + $item.DeviceInstance.ToString()
|
||||
# Non-present value will be ignored as for script execution policy
|
||||
Remove-ItemProperty -path $fullPath -name MetadataBufferSizeInKB0
|
||||
Remove-ItemProperty -path $fullPath -name MetadataBufferSizeInKB1
|
||||
Remove-ItemProperty -path $fullPath -name MetadataBufferSizeInKB2
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = 0,0,0
|
||||
$val[0] = Get-ItemPropertyValue -Path $fullPath -Name MetadataBufferSizeInKB0
|
||||
$val[1] = Get-ItemPropertyValue -Path $fullPath -Name MetadataBufferSizeInKB1
|
||||
$val[2] = Get-ItemPropertyValue -Path $fullPath -Name MetadataBufferSizeInKB2
|
||||
|
||||
if ($val[0] -eq 0)
|
||||
{
|
||||
"Device " + $item.DeviceInstance.ToString() + ": adding metadata key"
|
||||
Set-ItemProperty -path $fullPath -name MetadataBufferSizeInKB0 -value 5
|
||||
}
|
||||
else
|
||||
{
|
||||
"Device " + $item.DeviceInstance.ToString() + ": skiping - metadata key already exists"
|
||||
}
|
||||
|
||||
if (($MultiPinDevices -contains $item.DeviceInstance.Substring(0,27)) -and ($val[1] -eq 0))
|
||||
{
|
||||
# Multi-pin interface requires an additional key
|
||||
"Device " + $item.DeviceInstance.ToString() +": adding extra key for multipin interface, pin 1"
|
||||
Set-ItemProperty -path $fullPath -name MetadataBufferSizeInKB1 -value 5
|
||||
}
|
||||
|
||||
if (($MultiPinDevices -contains $item.DeviceInstance.Substring(0,27)) -and ($val[2] -eq 0))
|
||||
{
|
||||
# Multi-pin interface requires an additional key
|
||||
"Device " + $item.DeviceInstance.ToString() +": adding extra key for multipin interface, pin 2"
|
||||
Set-ItemProperty -path $fullPath -name MetadataBufferSizeInKB2 -value 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"`nTask Completed"
|
||||
sleep 1
|
BIN
backend/dll/smitsense/SMiTSenseUsb-F3.0.dll
Normal file
BIN
backend/dll/smitsense/SMiTSenseUsb-F3.0.dll
Normal file
Binary file not shown.
BIN
backend/dll/smitsense/SMiTSenseUsb-F3.0.lib
Normal file
BIN
backend/dll/smitsense/SMiTSenseUsb-F3.0.lib
Normal file
Binary file not shown.
108
backend/testcamera.py
Normal file
108
backend/testcamera.py
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
# import cv2
|
||||
|
||||
# class CameraViewer:
|
||||
# def __init__(self, device_index=0):
|
||||
# self.device_index = device_index
|
||||
# self.window_name = "Camera Viewer"
|
||||
|
||||
# def start_stream(self):
|
||||
# cap = cv2.VideoCapture(self.device_index)
|
||||
# if not cap.isOpened():
|
||||
# print(f"无法打开摄像头设备 {self.device_index}")
|
||||
# return
|
||||
|
||||
# cv2.namedWindow(self.window_name, cv2.WINDOW_NORMAL)
|
||||
|
||||
# while True:
|
||||
# ret, frame = cap.read()
|
||||
# if not ret:
|
||||
# print("无法获取视频帧")
|
||||
# break
|
||||
|
||||
# cv2.imshow(self.window_name, frame)
|
||||
|
||||
# if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
# break
|
||||
|
||||
# cap.release()
|
||||
# cv2.destroyAllWindows()
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# # 修改这里的数字可以切换不同摄像头设备
|
||||
# viewer = CameraViewer(device_index=1)
|
||||
# viewer.start_stream()
|
||||
# import os
|
||||
# import pefile
|
||||
|
||||
# def list_dll_exports(dll_path):
|
||||
# """解析 DLL 并返回导出的函数列表"""
|
||||
# try:
|
||||
# pe = pefile.PE(dll_path)
|
||||
# exports = []
|
||||
# if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
|
||||
# for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
|
||||
# if exp.name:
|
||||
# exports.append(exp.name.decode('utf-8'))
|
||||
# else:
|
||||
# exports.append(f"Ordinal_{exp.ordinal}")
|
||||
# return exports
|
||||
# except Exception as e:
|
||||
# print(f"[错误] 无法解析 {dll_path}: {e}")
|
||||
# return []
|
||||
|
||||
# def scan_directory_for_dll_functions(directory):
|
||||
# """扫描目录下所有 DLL 文件并解析导出函数"""
|
||||
# results = {}
|
||||
# for root, _, files in os.walk(directory):
|
||||
# for file in files:
|
||||
# if file.lower().endswith(".dll"):
|
||||
# dll_path = os.path.join(root, file)
|
||||
# print(f"\n正在解析: {dll_path}")
|
||||
# funcs = list_dll_exports(dll_path)
|
||||
# results[dll_path] = funcs
|
||||
# for func in funcs:
|
||||
# print(f" {func}")
|
||||
# return results
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# folder_path = r"D:\BodyBalanceEvaluation\backend\tests" # 这里改成你的 DLL 文件目录
|
||||
# scan_directory_for_dll_functions(folder_path)
|
||||
import ctypes
|
||||
|
||||
dll_path = r"D:\BodyBalanceEvaluation\backend\tests\SMiTSenseUsb-F3.0.dll"
|
||||
mydll = ctypes.WinDLL(dll_path)
|
||||
|
||||
class FPMS_DEVICE_C(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("mn", ctypes.c_uint8),
|
||||
("sn", ctypes.c_char * 32),
|
||||
("swVersion", ctypes.c_char * 32),
|
||||
("rows", ctypes.c_uint16),
|
||||
("cols", ctypes.c_uint16)
|
||||
]
|
||||
|
||||
# 声明
|
||||
mydll.fpms_usb_init.argtypes = [ctypes.c_int]
|
||||
mydll.fpms_usb_init.restype = ctypes.c_int
|
||||
|
||||
mydll.fpms_usb_get_device_list.argtypes = [
|
||||
ctypes.POINTER(FPMS_DEVICE_C),
|
||||
ctypes.POINTER(ctypes.c_int)
|
||||
]
|
||||
mydll.fpms_usb_get_device_list.restype = ctypes.c_int
|
||||
|
||||
# 初始化
|
||||
print("init:", mydll.fpms_usb_init(0))
|
||||
|
||||
# 获取设备列表
|
||||
device_count = ctypes.c_int()
|
||||
devices = (FPMS_DEVICE_C * 10)()
|
||||
res = mydll.fpms_usb_get_device_list(devices, ctypes.byref(device_count))
|
||||
print("get_device_list 返回值:", res, "设备数量:", device_count.value)
|
||||
|
||||
# 打印设备信息
|
||||
for i in range(device_count.value):
|
||||
dev = devices[i]
|
||||
print(f"[设备 {i}] mn={dev.mn}, sn={dev.sn.decode(errors='ignore')}, "
|
||||
f"swVersion={dev.swVersion.decode(errors='ignore')}, rows={dev.rows}, cols={dev.cols}")
|
150
backend/tests/newtest.py
Normal file
150
backend/tests/newtest.py
Normal file
@ -0,0 +1,150 @@
|
||||
import ctypes
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
class FPMS_DEVICE_C(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("mn", ctypes.c_uint8),
|
||||
("sn", ctypes.c_char * 32),
|
||||
("swVersion", ctypes.c_char * 32),
|
||||
("rows", ctypes.c_uint16),
|
||||
("cols", ctypes.c_uint16)
|
||||
]
|
||||
|
||||
class SMiTSenseSensor:
|
||||
def __init__(self, dll_path = r"D:\BodyBalanceEvaluation\backend\tests\SMiTSenseUsb-F3.0.dll"):
|
||||
self.dll = ctypes.WinDLL(dll_path)
|
||||
|
||||
# 定义函数接口
|
||||
self.dll.fpms_usb_init_wrapper.argtypes = [ctypes.c_int]
|
||||
self.dll.fpms_usb_init_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.dll.fpms_usb_get_device_list_wrapper.argtypes = [ctypes.POINTER(FPMS_DEVICE_C), ctypes.POINTER(ctypes.c_int)]
|
||||
self.dll.fpms_usb_get_device_list_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.dll.fpms_usb_open_wrapper.argtypes = [FPMS_DEVICE_C, ctypes.POINTER(ctypes.c_void_p)]
|
||||
self.dll.fpms_usb_open_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.dll.fpms_usb_read_frame_wrapper.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint16)]
|
||||
self.dll.fpms_usb_read_frame_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.dll.fpms_usb_config_light_wrapper.argtypes = [ctypes.c_void_p, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8, ctypes.c_uint8]
|
||||
self.dll.fpms_usb_config_light_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.dll.fpms_usb_close_wrapper.argtypes = [ctypes.c_void_p]
|
||||
self.dll.fpms_usb_close_wrapper.restype = ctypes.c_int
|
||||
|
||||
self.device_handle = ctypes.c_void_p()
|
||||
self.device_info = None
|
||||
|
||||
def initialize(self):
|
||||
# 参数0是debug标志,参考示例
|
||||
return self.dll.fpms_usb_init_wrapper(0) == 0
|
||||
|
||||
def get_device_list(self, max_devices=10):
|
||||
devices = (FPMS_DEVICE_C * max_devices)()
|
||||
device_count = ctypes.c_int()
|
||||
ret = self.dll.fpms_usb_get_device_list_wrapper(devices, ctypes.byref(device_count))
|
||||
if ret != 0 or device_count.value == 0:
|
||||
return []
|
||||
return devices[:device_count.value]
|
||||
|
||||
def open_device(self, device: FPMS_DEVICE_C):
|
||||
handle = ctypes.c_void_p()
|
||||
ret = self.dll.fpms_usb_open_wrapper(device, ctypes.byref(handle))
|
||||
if ret == 0:
|
||||
self.device_handle = handle
|
||||
self.device_info = device
|
||||
return True
|
||||
return False
|
||||
|
||||
def config_light(self, r=1, g=56, b=183, a=214):
|
||||
if not self.device_handle:
|
||||
return False
|
||||
ret = self.dll.fpms_usb_config_light_wrapper(self.device_handle, r, g, b, a)
|
||||
return ret == 0
|
||||
|
||||
def read_frame(self):
|
||||
if not self.device_handle or not self.device_info:
|
||||
return None
|
||||
rows = self.device_info.rows
|
||||
cols = self.device_info.cols
|
||||
frame_buffer = (ctypes.c_uint16 * (rows * cols))()
|
||||
ret = self.dll.fpms_usb_read_frame_wrapper(self.device_handle, frame_buffer)
|
||||
if ret != 0:
|
||||
return None
|
||||
# 转成 numpy 二维数组方便处理
|
||||
data = np.ctypeslib.as_array(frame_buffer)
|
||||
return data.reshape((rows, cols))
|
||||
|
||||
def close_device(self):
|
||||
if self.device_handle:
|
||||
ret = self.dll.fpms_usb_close_wrapper(self.device_handle)
|
||||
self.device_handle = None
|
||||
self.device_info = None
|
||||
return ret == 0
|
||||
return True
|
||||
|
||||
def main():
|
||||
sensor = SMiTSenseSensor()
|
||||
|
||||
if not sensor.initialize():
|
||||
print("初始化失败")
|
||||
return
|
||||
|
||||
devices = sensor.get_device_list(20)
|
||||
if not devices:
|
||||
print("未发现设备")
|
||||
return
|
||||
print(f"发现设备数量: {len(devices)}")
|
||||
for idx, dev in enumerate(devices):
|
||||
print(f"设备{idx}: mn={dev.mn}, sn={dev.sn.decode(errors='ignore').strip()}, swVersion={dev.swVersion.decode(errors='ignore').strip()}, rows={dev.rows}, cols={dev.cols}")
|
||||
|
||||
# 依次尝试打开设备
|
||||
opened = False
|
||||
for device in devices:
|
||||
print(f"尝试打开设备 SN: {device.sn.decode(errors='ignore').strip()}")
|
||||
if sensor.open_device(device):
|
||||
print("打开成功")
|
||||
opened = True
|
||||
break
|
||||
else:
|
||||
print("打开失败")
|
||||
|
||||
if not opened:
|
||||
print("所有设备打开失败")
|
||||
return
|
||||
|
||||
# 配置灯光
|
||||
if sensor.config_light():
|
||||
print("配置灯光成功")
|
||||
else:
|
||||
print("配置灯光失败")
|
||||
|
||||
# 准备显示图像
|
||||
plt.ion()
|
||||
fig, ax = plt.subplots()
|
||||
img = None
|
||||
|
||||
try:
|
||||
while True:
|
||||
frame = sensor.read_frame()
|
||||
if frame is None:
|
||||
print("读取数据失败")
|
||||
break
|
||||
|
||||
if img is None:
|
||||
img = ax.imshow(frame, cmap='coolwarm', vmin=0, vmax=1023)
|
||||
plt.title("SMiTSense 足底压力分布")
|
||||
plt.colorbar(img, ax=ax)
|
||||
else:
|
||||
img.set_data(frame)
|
||||
plt.pause(0.05)
|
||||
except KeyboardInterrupt:
|
||||
print("用户中断,退出")
|
||||
finally:
|
||||
sensor.close_device()
|
||||
print("设备已关闭")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -40,7 +40,7 @@ session_timeout = 3600
|
||||
max_login_attempts = 5
|
||||
|
||||
[CAMERA]
|
||||
device_index = 1
|
||||
device_index = 3
|
||||
|
||||
[DEFAULT]
|
||||
# FemtoBolt深度相机配置
|
||||
|
@ -16,7 +16,7 @@ api.interceptors.request.use(
|
||||
if (window.electronAPI) {
|
||||
config.baseURL = window.electronAPI.getBackendUrl()
|
||||
} else {
|
||||
config.baseURL = 'http://192.168.1.58:5000'
|
||||
config.baseURL = 'http://192.168.1.173:5000'
|
||||
|
||||
}
|
||||
|
||||
@ -600,7 +600,7 @@ export const getBackendUrl = () => {
|
||||
if (window.electronAPI) {
|
||||
return window.electronAPI.getBackendUrl()
|
||||
} else {
|
||||
return 'http://192.168.1.58:5000'
|
||||
return 'http://192.168.1.173:5000'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -881,7 +881,7 @@ function connectWebSocket() {
|
||||
|
||||
// 监听压力传感器足部压力数据
|
||||
socket.on('pressure_data', (data) => {
|
||||
console.log('👣 压力传感器足部压力数据:', data)
|
||||
// console.log('👣 压力传感器足部压力数据:', data)
|
||||
handlePressureData(data)
|
||||
})
|
||||
|
||||
@ -984,11 +984,11 @@ function handleIMUData(data) {
|
||||
const headPose = data.head_pose
|
||||
|
||||
// 更新头部姿态数据
|
||||
console.log('🎯 更新IMU头部姿态数据:', {
|
||||
rotation: headPose.rotation, // 旋转角:左旋(-), 右旋(+)
|
||||
tilt: headPose.tilt, // 倾斜角:左倾(-), 右倾(+)
|
||||
pitch: headPose.pitch // 俯仰角:俯角(-), 仰角(+)
|
||||
})
|
||||
// console.log('🎯 更新IMU头部姿态数据:', {
|
||||
// rotation: headPose.rotation, // 旋转角:左旋(-), 右旋(+)
|
||||
// tilt: headPose.tilt, // 倾斜角:左倾(-), 右倾(+)
|
||||
// pitch: headPose.pitch // 俯仰角:俯角(-), 仰角(+)
|
||||
// })
|
||||
if (rotationCharts) {
|
||||
rotationCharts.setOption({
|
||||
series: [{
|
||||
|
Loading…
Reference in New Issue
Block a user