如何在 Intel® RealSense™ SDK 中录制和回放流式传输序列
Intel® RealSense™ SDK 为开发人员提供了一项新功能,可以将摄像机流序列录制到磁盘文件以供将来播放。此功能在调试和故障排除应用程序中的摄像机问题时非常有用。
Intel® RealSense™ SDK 为开发人员提供了一项新功能,可以将摄像机流序列录制到磁盘文件以供将来播放。此功能在调试和故障排除应用程序中的摄像机问题时非常有用。
将原始彩色和深度流录制到磁盘文件会对主机系统的磁盘 IO 带宽提出挑战。例如,对于彩色配置 RGB32 1920x1080x30fps 和深度配置 640x480x30fps,SDK 需要约 272MB/s 的磁盘 I/O 带宽才能将样本写入磁盘。这使得大多数旋转硬盘和某些慢速 SSD 无法进行此类文件录制作业。
为了解决这个问题,SDK 提供了一项实验性功能,可以在将样本写入磁盘之前对其进行压缩。该功能基于 H.264 编码(仅 I 帧,恒定 QP)彩色样本和无损 Lempel–Ziv–Oberhumer (LZO) 编码深度样本。彩色样本的压缩率约为 10:1,深度样本的压缩率约为 2:1。对于前面的示例,磁盘 I/O 带宽现已降至约 32MB/s。要使用此功能,您需要使用带有最新 Intel Iris 图形驱动程序的 Intel® Iris™ 图形。您可以使用以下注册表设置来控制录制功能
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 图形的系统上播放。
在 C++、C# 或 Java 代码中,使用 `CaptureManager` 实例的 `SetFileName` 来设置文件名和模式(录制或播放)
| C++ pxcStatus SetFileName(pxcCHAR *file, pxcBool record); 参数 | 
将流序列录制到文件的步骤
- 使用 `CaptureManager` 实例的 `SetFileName` 函数。
- 提供文件名并将录制模式设置为 true。文件名没有限制,除了在录制模式下,文件必须是可写的。
- 如果要录制未压缩的流,请更改注册表设置
以下是录制或播放流序列的示例代码
       void RecordORPlayback(pxcCHAR *file, bool record) {  
	   // Create a SenseManager instance  
	   PXCSenseManager *sm=PXCSenseManager::CreateInstance();  
	   
	   // Set file recording or playback  
	   sm->QueryCaptureManager()->SetFileName(file,record);  
	   
	   // Select the color stream  
	   sm->EnableStream(PXCCapture.STREAM_TYPE_COLOR,640,480,0);   
	   
	   // Initialize and Record 300 frames  
	   sm->Init();   
	   for (int i=0;i<300;i++) {  
	       // This function blocks until a color sample is ready  
	       if (sm->AcquireFrame(true)<PXC_STATUS_NO_ERROR) break;   
	   
	       // Retrieve the sample  
	       PXCCapture::Sample *sample=sm->QuerySample();  
	   
	       // Work on the image sample->color  
	       ...  
	   
	       // Go fetching the next sample  
	       sm->ReleaseFrame();  
	   }  
	   
	   // close down  
	   sm->Release();  
	}
在录制过程中,样本在应用程序处理后按原样录制到磁盘。例如,如果应用程序捕获未对齐的彩色和深度样本,则磁盘上的样本是未对齐的。如果应用程序对样本进行对齐,则磁盘上的样本也是对齐的。
录制的文件包含一个固定大小的头,结构如下
struct Header {  
   pxcI32    ID;                    // PXC_UID('R','S','C','F')  
   pxcI32    fileVersion;           // file version  
   pxcI32    firstFrameOffset;      // The byte offset to the meta data of the first frame.  
   pxcI32    nstreams;              // The number of streams.  
   pxcI64    frameIndexingOffset;   // Optional frame indexing offset, zero if not available.    	     
   PXCSession::CoordinateSystem coordinateSystem; // The coordinate system setting.  
   pxcI32    reserved[26];  
};
任何流的图像帧都按顺序记录在头信息之后。它从 `ChunkFrameMetaData` 开始,以 `ChunkFrameData` 结束。在这之间,可能存在多个配置帧,用于描述图像帧的元数据。元数据应解释为相对于文件头部分定义的元数据的增量或更改。这可以减小某些元数据对所有帧通用的情况下的文件大小。帧结构如下
	struct StreamFrame {  
	   ChunkFrameMetaData frame_header;  
	  
	   // in no defined order  
	   ChunkImageMetaData image_meta_data;      // if any.  
	  
	  // there could be more chunks here.  
	  ChunkFrameData     frame_data;  
	} frames[]
`ChunkFrameMetaData` 结构如下
	struct ChunkFrameMetaData {  
	   ChunkId   chunkId=CHUNK_FRAME_META_DATA;  
	   pxcI32    chunkSize=sizeof(metaData);  
	   struct {  
	       pxcI32    frameNumber;  // frame number in the current stream  
	       PXCCapture::StreamType streamType;     
	       pxcI64    timeStamp;  
	       PXCImage::Option options;  
	   } metaData;  
	};
您可以在帧中放置 `ChunkImageMetaData`,其结构如下
	struct ChunkImageMetaData {  
	   ChunkId   chunkId=CHUNK_IMAGE_META_DATA;  
	   pxcI32    chunkSize=sizeof(buffer)+sizeof(id);  
	   pxcUID    id;  // meta data identifier  
	   pxcBYTE   buffer[chunkSize-sizeof(id)];  
	};
未压缩流的结构如下
	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  
	};
压缩流的结构如下
    struct ChunkFrameDataCompressed {
	   ChunkId   chunkId=CHUNK_FRAME_DATA;  
	   pxcI32    chunkSize=sizeof(imageData);  
	   struct {  
	       pxcI32  pitches[PXCImage::NUM_OF_PLANES]; // pitches of uncompressed image planes.  
	       enum {  
	           H264=0x343632,  
	           LZO=0x4f5a4c,  
	       } CompressionIdentifier;  
	       pxcBYTE compressed_data[];  
	   } imageData  
	};
RealSense™ SDK 捕获模块会将配置帧添加到文件中。配置帧可以包含由块标识符和块大小标识的任何任意数据。块数据在文件中的呈现顺序并不重要,但有一个通用规则:如果两个块之间存在依赖关系,则依赖块应放在文件后面。`ChunkData` 结构如下
	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;               // The chunk identifier  
	   pxcI32    chunkSize;             // The chunk size in bytes-8.  
	   pxcBYTE   chunkData[chunkSize];  // The chunk data buffer  
	} chunks[];
文件中需要包含一些配置帧
- `CHUNK_DEVICEINFO` 用于设备信息
- `CHUNK_STREAMINFO` 用于流信息
- `CHUNK_PROPERTIES` 用于设备属性
- `CHUNK_PROFILES` 用于流配置
- `CHUNK_SERIALIZEABLE` 用于设备校准
- `CHUNK_FRAME_INDEXING` 用于帧索引
播放流序列文件的步骤
- 使用 `CaptureManager` 实例的 `SetFileName` 函数。
- 提供 rssdk 格式的文件名并将录制模式设置为 false。
对于文件播放,SDK 会立即创建 Capture 实例(使用 `QueryCapture` 函数),以便应用程序可以查询录制内容的特性。您可以按如下方式配置 SDK 文件播放行为
| 函数 | 默认值 | 描述 | 
| 
 | false | 如果为 true,则文件播放会重复返回当前帧的相同样本。 | 
| 
 | true | 如果为 true,则文件播放会返回当前帧样本的显示时间(根据样本时间戳)。如果为 false,则文件播放会立即返回样本。 | 
如果要准确地定位播放过程中的任何帧数据,请选择 pause=true 和 realtime=false。以下是展示如何使用 `SetRealtime` 和 `SetPause` 的示例代码
// Create a SenseManager instance
	PXCSenseManager* sm = PXCSenseManager::CreateInstance();  
	  
	// Set file playback name  
	sm->QueryCaptureManager()->SetFileName(filename, false);  
	  
	// Enable stream and Initialize  
	sm->EnableStream(PXCCapture::STREAM_TYPE_COLOR, 0, 0);  
	sm->Init();  
	  
	// Set realtime=false and pause=true  
	sm->QueryCaptureManager()->SetRealtime(false);  
	sm->QueryCaptureManager()->SetPause(true);  
	  
	// Streaming loop  
	for (int i = 0; i < nframes; i+=3) {  
	  
	   // Set to work on every 3rd frame of data  
	   sm->QueryCaptureManager()->SetFrameByIndex(i);  
	   sm->FlushFrame();  
	  
	   // Ready for the frame to be ready  
	   pxcStatus sts = sm->AcquireFrame(true);  
	   if (sts < PXC_STATUS_NO_ERROR) break;  
	  
	   // Retrieve the sample and work on it. The image is in sample->color.  
	   PXCCapture::Sample* sample = sm->QuerySample();  
	   ....  
	  
	   // Resume processing the next frame  
	   sm->ReleaseFrame();  
	}  
	  
	// Clean up  
	sm->Release();
在上述讨论中,我们可以看到通过这项新的 Intel® RealSense™ SDK 功能,开发人员可以嵌入代码将摄像机流序列录制到磁盘上的压缩文件中,并在之后进行播放。此功能在调试和故障排除应用程序问题时非常有用。


