360SCVP库中WebRTC部分代码走读

本文详细介绍了360SCVP库,包括其主要功能如流拼接、视场计算、NAL解析和客户端支持,关键数据结构以及在WebRTC和OMAF中的应用场景。核心函数I360SCVP_Init和I360SCVP_process的调用流程也做了深入解析。
摘要由CSDN通过智能技术生成

github:https://github.com/OpenVisualCloud/Immersive-Video-Sample.git
Commit ID: 9ce286edf4d5976802bf488b4dd90a16ecc28c36

1. 概述

360SCVP是一个通用的库,它为流和视窗提供了一些基本的功能。它主要应用在OMAF解决方案的服务器端(编码器和打包)和客户端(dashacess和播放器)。除此之外,这个库也被应用在基于WebRTC的低延迟解决方案中。因此,360SCVP是可扩展的,可以根据用户的要求便捷地扩展到更多的功能。

下图显示了四种使用类型和基本功能。

OMAF_Compliant-Video-Delivery-360scvp

2. 主要的数据结构

(1)UsageType枚举类型

截屏2022-03-21 09.34.33
/*!
*
*  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组合成一帧的码流,一般的调用顺序如下图所示。

OMAF_Compliant-Video-Delivery-360scvp_CallSeq

(1)I360SCVP_Init()

I360SCVP_Init()首先调用pStitchstream->init(pParam360SCVP),然后根据不同的UsageType进行不同的操作,包含传递相关参数,分配所需的内存等,如下图。本节主要对WebRTC使用的E_MERGE_AND_VIEWPORT类型进行分析。

image-20220322194910125

当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()完成两路流组合的过程。

截屏2022-03-22 19.44.10
parseNals()

依次调用以下三个函数:

  1. genTiledStream_unInit():执行初始化,将输入参数传递给genTiledstream库,分配所需的内存。

  2. genTiledStream_parseNals():提供了NAL解析功能,可以给出slice类型、tileCols、tilrows和NAL信息。

  3. genTiledStream_unInit():释放无用内存。

feedParamToGenStream()

给stitch library喂参数。

doMerge()

调用tile_merge_Process(),在tile_merge_Process()中依次调用以下函数。

  1. get_merge_solution:将所有的LR tiles放在HR tiles的右侧。

  2. gts_bs_new:写入新的merge流。

  3. merge_header:写入头信息。

  4. gts_bs_del:释放内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值