github:https://github.com/OpenVisualCloud/Immersive-Video-Sample.git
Commit ID: 9ce286edf4d5976802bf488b4dd90a16ecc28c36
1. 概述
360SCVP是一个通用的库,它为流和视窗提供了一些基本的功能。它主要应用在OMAF解决方案的服务器端(编码器和打包)和客户端(dashacess和播放器)。除此之外,这个库也被应用在基于WebRTC的低延迟解决方案中。因此,360SCVP是可扩展的,可以根据用户的要求便捷地扩展到更多的功能。
下图显示了四种使用类型和基本功能。
2. 主要的数据结构
(1)UsageType枚举类型
/*!
*
* currently the library can support three types
* 0(only merge), similar to our before usage
* 1(merge + viewport), used in webrtc use case
* 2(parsing one nal), used in the omaf
* 3(parsing for client), used in the client player
* 4(only viewport calculation), can be used in OMAF DASH access
*/
typedef enum UsageType
{
E_STREAM_STITCH_ONLY = 0,
E_MERGE_AND_VIEWPORT,
E_PARSER_ONENAL,
E_PARSER_FOR_CLIENT,
E_VIEWPORT_ONLY,
E_PARSER_TYPE_NUM,
}UsageType;
下面对四种UsageType枚举类型进行介绍(主要对前三种类型进行了实现)
-
E_STREAM_STITCH_ONLY: 对多个tile-based的clip进行拼接,输出一个clip。
-
E_MERGE_AND_VIEWPORT: 输入视场信息和一帧的比特流的时候,该库能计算当前帧中的视场区域并输出对应的比特流。除此之外,当输入两帧的比特流时(一帧高码率,另一帧低码率),这个库能够计算视角区域并且将两路比特流融合成一路比特流。(用于WebRTC)
-
E_PARSER_ONENAL: 输入一路NAL比特流(SPS,PPS,SLICE…)时,这个库可以解析位流并返回一些用户感兴趣的关键变量。如果给出一些关键变量,库可以生成相应的NAL位流。(用于OMAF)
HEVC编码分成两个层次,高层处理编码具体细节的被称为VCL(视频编码层)、底层处理比特流的被称为NAL(网络适配层)。预测编码、变换、量化、环路滤波以及熵编码都属于VCL。而处理比特流封装细节的部分则属于NAL。
-
E_PARSER_FOR_CLIENT: 该库可以在客户端解析一些反馈信息,目前支持RWPK解析器。(用于客户端)
-
E_VIEWPORT_ONLY: 从Omaf Dash Access库中获取视口信息时,可以计算FOV的内容覆盖率,生成所选tile的相关信息。(用于OMAF DASH ACCESS)
(2)关键数据结构
----> param_PicInfo
这是图片信息结构,例如图片宽度,图片高度,水平和垂直的tile数量。当使用类型为E_STREAM_STITCH_ONLY时,它是输入参数。
//!
//! \brief This structure is for the pitcure parameters
//!
typedef struct PARAM_PICTURE
{
int32_t picWidth;
int32_t picHeight;
int32_t tileWidthNum;
int32_t tileHeightNum;
int32_t tileIsUniform;
int32_t maxCUWidth;
}Param_PicInfo;
----> param_ViewPortInfo
这个结构针对视场参数,包含视场信息,投影类型,视场端口宽度,视场端口高度。当使用类型为E_MERGE_AND_VIEWPORT时,它是输入参数。
typedef struct PARAM_VIEWPORT
{
int32_t viewportWidth;
int32_t viewportHeight;
float viewPortPitch;
float viewPortYaw;
float viewPortFOVH;
float viewPortFOVV;
EGeometryType geoTypeOutput;
EGeometryType geoTypeInput;
uint32_t faceWidth;
uint32_t faceHeight;
uint32_t tileNumRow;
uint32_t tileNumCol;
UsageType usageType;
Param_VideoFPStruct paramVideoFP;
}Param_ViewPortInfo;
----> param_streamStitchInfo
这个结构提供输入比特流的clips以及一些帧级别的参数。它在类型为E_STREAM_STITCH_ONLY时作为输入参数。对于每一个比特流clip,都有一个param_streamStitchInfo的结构提供相关信息。
typedef struct PARAM_STREAMSTITCHINFO
{
bool AUD_enable;
bool VUI_enable;
param_oneStream_info **pTiledBitstream;
uint32_t sliceType;
uint32_t pts;
}param_streamStitchInfo;
----> param_oneStream_info
该结构提供了水平和垂直的tile数量、tile索引、比特流流数据缓冲区和每个输入比特流的数据长度,包含在PARAM_STREAMSTITCHINFO中。在使用类型为E_STREAM_STITCH_ONLY时作为输入参数。
typedef struct INPUT_ONESTREAM_IFO
{
int32_t tilesWidthCount;
int32_t tilesHeightCount;
uint8_t* pTiledBitstreamBuffer;
uint32_t inputBufferLen;
uint32_t tilesIdx;
uint32_t curBufferLen;
uint32_t outputBufferLen;
}param_oneStream_info;
----> param_360SCVP(主要)
这个结构是最主要的数据结构,提供了所有在库中需要使用的输入输出参数,因此包含上述的四种数据结构。
typedef struct PARAM_360SCVP
{
uint8_t usedType;
uint8_t *pInputBitstream;
uint32_t inputBitstreamLen;
uint8_t *pOutputBitstream;
uint32_t outputBitstreamLen;
Param_PicInfo paramPicInfo;
Param_ViewPortInfo paramViewPort;
param_streamStitchInfo paramStitchInfo;
int32_t sourceResolutionNum;
float accessInterval;
Stream_Info *pStreamInfo;
int32_t destWidth;
int32_t destHeight;
unsigned int frameWidth;
unsigned int frameHeight;
unsigned int frameWidthLow;
unsigned int frameHeightLow;
unsigned char *pInputLowBitstream;
unsigned int inputLowBistreamLen;
unsigned char *pOutputSEI;
unsigned int outputSEILen;
PluginDef pluginDef;
uint32_t timeStamp;
void *logFunction; //external log callback function pointer, NULL if external log is not used
}param_360SCVP;
----> Param_VideoFPStruct
该结构描述了输入几何图形的face属性,包括tile行/列号、每个face的宽度/高度等。
typedef struct PARAM_VIDEOFPSTRUCT
{
int rows;
int cols;
Param_FaceProperty faces[6][6];
}Param_VideoFPStruct;
----> PluginDef
该结构是提供插件信息的插件定义。
typedef struct PLUGIN_DEF
{
PluginType pluginType;
PluginFormat pluginFormat;
char* pluginLibPath;
}PluginDef;
3. 函数调用
360SCVP中有两个最主要的函数,分别是I360SCVP_Init和I360SCVP_process,前者进行库的初始化,选择位于视窗内的tile,后者将tile组合成一帧的码流,一般的调用顺序如下图所示。
(1)I360SCVP_Init()
I360SCVP_Init()首先调用pStitchstream->init(pParam360SCVP),然后根据不同的UsageType进行不同的操作,包含传递相关参数,分配所需的内存等,如下图。本节主要对WebRTC使用的E_MERGE_AND_VIEWPORT类型进行分析。
当UserType为E_MERGE_AND_VIEWPORT时,360SCVP将依次调用5个函数,各函数功能如下表所示。其中,getViewPortTiles()的操作最复杂。
函数 | 功能 |
---|---|
parseNals() | 解析流的头信息 |
initViewport() | 根据不同的投影方式对viewport library进行初始化 |
getViewPortTiles() | 根据FoV信息,选择位于viewport内的tile |
genViewport_setMaxSelTiles() | 返回被选中的tile的最大数量 |
initMerge() | 初始化merge library |
getViewPortTiles()
先后调用genViewport_postprocess()和genViewport_getFixedNumTiles()两个函数。
- genViewport_postprocess()
首先调用CalculateViewportBoundaryPoints()计算上下左右4个边界。然后根据投影方式选择函数确定viewport区域,E_SVIDEO_EQUIRECT方式调用ERPSelectRegion(),E_SVIDEO_CUBEMAP方式调用cubemapSelectRegion()。
- genViewport_getFixedNumTiles()
该函数负责根据viewport信息输出固定数量的区域内tile,这些tile按照原始图像顺序摆放。首先调用calcTilesInViewport确定位于视窗内的tile,然后将这些tile的写入输入参数中。
(2)I360SCVP_process()
同样的,I360SCVP_process()将根据不同的UserType进行不同的操作。当UserType为E_MERGE_AND_VIEWPORT时,I360SCVP_process()首先调用两次parseNals分别对high resolution和low resolution两路流进行解析。然后调用feedParamToGenStream()将相关参数传递至stitch library。最后调用doMerge()完成两路流组合的过程。
parseNals()
依次调用以下三个函数:
-
genTiledStream_unInit():执行初始化,将输入参数传递给genTiledstream库,分配所需的内存。
-
genTiledStream_parseNals():提供了NAL解析功能,可以给出slice类型、tileCols、tilrows和NAL信息。
-
genTiledStream_unInit():释放无用内存。
feedParamToGenStream()
给stitch library喂参数。
doMerge()
调用tile_merge_Process(),在tile_merge_Process()中依次调用以下函数。
-
get_merge_solution:将所有的LR tiles放在HR tiles的右侧。
-
gts_bs_new:写入新的merge流。
-
merge_header:写入头信息。
-
gts_bs_del:释放内存。