Intel RealSense SDK录制与回放功能详解

Intel RealSenseSDK提供了一种将摄像头流录制到磁盘文件并在未来进行回放的功能。这对于调试和解决应用程序中的摄像头问题非常有用。然而,将原始颜色和深度流录制到磁盘文件会对主机系统的磁盘IO带宽提出挑战。例如,如果颜色配置为RGB32 1920x1080x30fps,深度配置为640x480x30fps,SDK需要大约272MB/s的磁盘IO带宽来将样本写入磁盘。这使得大多数机械硬盘和某些慢速SSD无法胜任此类文件录制工作。

为了解决这个问题,SDK提供了一个实验性功能,即在写入磁盘之前对样本进行压缩。该功能基于颜色样本的H.264编码(仅I帧,恒定QP)和深度样本的无损Lempel-Ziv-Oberhumer(LZO)编码。颜色样本的压缩率大约为10:1,深度样本的压缩率大约为2:1。这样,对于前面的例子,磁盘IO带宽现在减少到大约32MB/s。要使用此功能,需要使用带有最新Intel Iris Graphics驱动程序的Intel® Iris™ Graphics。可以通过以下注册表设置来控制录制功能:

Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\SOFTWARE\Intel\RSSDK\FileRecording] "DisableH264Compression"=dword:0 "H264_QPI"=dword:8 "DisableLZOCompression"=dword:0

默认情况下,颜色流启用了H.264压缩,所有其他流启用了LZO压缩。H.264 QPI(I帧量化参数)值的范围是从0(压缩最少)到51(压缩最多)。

重要提示:带有H.264压缩的录制文件只能在具有Intel Iris Graphics的系统上回放。

在C++、C#或Java代码中,使用CaptureManager实例的SetFileName函数来设置文件名和模式(录制或回放)。

C++ pxcStatus SetFileName(pxcCHAR *file, pxcBool record); C# pxcmStatus SetFileName(String file, Boolean record); Java pxcmStatus SetFileName(string file, boolean record);

参数:

  • file - 要回放或录制的文件的完整路径。
  • record - 如果为true,则设置录制模式。否则,设置回放模式。

录制流序列到文件的步骤:

  1. 使用CaptureManager实例的SetFileName函数。
  2. 提供文件名并将录制模式设置为true。文件名没有限制,但在录制模式下,文件必须是可写的。
  3. 如果想录制未压缩的流,请更改注册表设置。

以下是录制或回放流序列的示例代码:

C++ void RecordORPlayback(pxcCHAR *file, bool record) { // 创建一个SenseManager实例 PXCSenseManager *sm=PXCSenseManager::CreateInstance(); // 设置文件录制或回放 sm->QueryCaptureManager()->SetFileName(file,record); // 选择颜色流 sm->EnableStream(PXCCapture.STREAM_TYPE_COLOR, 640, 480, 0); // 初始化并录制300帧 sm->Init(); for(int i=0; i<300; i++) { // 此函数在颜色样本准备好时阻塞 if(sm->AcquireFrame(true) < PXC_STATUS_NO_ERROR) break; // 检索样本 PXCCapture::Sample *sample=sm->QuerySample(); // 处理图像sample->color ... // 获取下一个样本 sm->ReleaseFrame(); } // 关闭 sm->Release(); }

在录制过程中,样本会随着应用程序的处理而被记录到磁盘上。例如,如果应用程序捕获了未对齐的颜色和深度样本,磁盘上的样本就是未对齐的。如果应用程序对样本进行了对齐,磁盘上的样本就是对齐的。

录制的文件包含一个固定大小的头部,结构如下:

C++ struct Header { pxcI32 ID; // PXC_UID('R','S','C','F') pxcI32 fileVersion; // 文件版本 pxcI32 firstFrameOffset; // 第一帧的元数据的字节偏移量。 pxcI32 nstreams; // 流的数量。 pxcI64 frameIndexingOffset; // 可选的帧索引偏移量,如果没有则为零。 PXCSession::CoordinateSystem coordinateSystem; // 坐标系统设置。 pxcI32 reserved[26]; };

任何流的图像帧都按顺序记录在头部之后。它从ChunkFrameMetaData开始,以ChunkFrameData结束。在两者之间,可能有多个配置帧描述图像帧的元数据。元数据应该被解释为与文件头部分定义的内容的差值或变化。这减少了如果某些元数据对所有帧都通用的大小。帧结构如下:

C++ struct StreamFrame { ChunkFrameMetaData frame_header; // 未定义顺序 ChunkImageMetaData image_meta_data; // 如果有的话。 // 这里可能有更多块。 ChunkFrameData frame_data; } frames[];

ChunkFrameMetaData结构如下:

C++ struct ChunkFrameMetaData { ChunkId chunkId=CHUNK_FRAME_META_DATA; pxcI32 chunkSize=sizeof(metaData); struct { pxcI32 frameNumber; // 当前流中的帧号 PXCCapture::StreamType streamType; pxcI64 timeStamp; PXCImage::Option options; } metaData; };

可以将ChunkImageMetaData放入帧中,其结构如下:

C++ struct ChunkImageMetaData { ChunkId chunkId=CHUNK_IMAGE_META_DATA; pxcI32 chunkSize=sizeof(buffer)+sizeof(id); pxcUID id; // 元数据标识符 pxcBYTE buffer[chunkSize-sizeof(id)]; };

未压缩流的结构如下:

C++ struct ChunkFrameDataUncompressed { ChunkId chunkId=CHUNK_FRAME_DATA; pxcI32 chunkSize=sizeof(imageData); struct { pxcI32 pitches[PXCImage::NUM_OF_PLANES]; pxcBYTE plane0[pitches[0]*height]; ... pxcBYTE planeN[pitches[PXCImage::NUM_OF_PLANES-1]*height]; } imageData };

压缩流的结构如下:

C++ struct ChunkFrameDataCompressed { ChunkId chunkId=CHUNK_FRAME_DATA; pxcI32 chunkSize=sizeof(imageData); struct { pxcI32 pitches[PXCImage::NUM_OF_PLANES]; enum { H264=0x343632, LZO=0x4f5a4c, } CompressionIdentifier; pxcBYTE compressed_data[]; } imageData };

RealSense™ SDK捕获模块将在文件中添加配置帧。配置帧可以包含任何由块标识符和块大小识别的任意数据。文件中块数据的呈现顺序并不重要,一般规则是,如果两个块之间存在依赖关系,依赖块应该放在文件的后面。ChunkData结构如下:

C++ struct ChunkData { enum ChunkId { CHUNK_DEVICEINFO = 1, CHUNK_STREAMINFO = 2, CHUNK_PROPERTIES = 3, CHUNK_PROFILES = 4, CHUNK_SERIALIZEABLE = 5, CHUNK_FRAME_META_DATA = 6, CHUNK_FRAME_DATA = 7, CHUNK_IMAGE_META_DATA = 8, CHUNK_FRAME_INDEXING = 9, }chunkId; pxcI32 chunkSize; pxcBYTE chunkData[chunkSize]; } chunks[];

文件中需要一些配置帧:

  • CHUNK_DEVICEINFO用于设备信息
  • CHUNK_STREAMINFO用于流信息
  • CHUNK_PROPERTIES用于设备属性
  • CHUNK_PROFILES用于流配置文件
  • CHUNK_SERIALIZEABLE用于设备校准
  • CHUNK_FRAME_INDEXING用于帧索引

播放流序列文件的步骤:

  1. 使用CaptureManager实例的SetFileName函数。
  2. 提供rssdk格式的文件名并将录制模式设置为false。

对于文件回放,SDK会立即创建Capture实例(使用QueryCapture函数),以便应用程序可以查询录制内容的功能。可以如下配置SDK文件回放行为:

函数 默认值 描述
SetPause false 如果为true,则文件回放会重复返回当前帧的相同样本。
SetRealtime true 如果为true,则文件回放会根据样本的时间戳(presentation time)返回当前帧样本。如果为false,则文件回放会立即返回样本。
C++ PXCSenseManager* sm = PXCSenseManager::CreateInstance(); // 设置文件回放名称 sm->QueryCaptureManager()->SetFileName(filename, false); // 启用流并初始化 sm->EnableStream(PXCCapture::STREAM_TYPE_COLOR, 0, 0); sm->Init(); // 设置realtime=false和pause=true sm->QueryCaptureManager()->SetRealtime(false); sm->QueryCaptureManager()->SetPause(true); // 流循环 for(int i = 0; i < nframes; i += 3) { // 设置每3帧数据工作一次 sm->QueryCaptureManager()->SetFrameByIndex(i); sm->FlushFrame(); // 准备帧就绪 pxcStatus sts = sm->AcquireFrame(true); if(sts < PXC_STATUS_NO_ERROR) break; // 检索样本并处理它。图像在sample->color中。 PXCCapture::Sample* sample = sm->QuerySample(); .... // 继续处理下一帧 sm->ReleaseFrame(); } // 清理 sm->Release();
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485