CRI ADX  Last Updated: 2024-07-17 10:48 p
关于工作区内存
CRI Atom运行时库的某些函数在运行时需要用于作业的内存区域(工作区内存)。
本节将介绍工作区内存的用途及如何分配工作区内存。

需要工作区内存的处理

需要工作区内存的处理如下。
  • 初始化运行时库
  • Voice池的创建
  • ACF文件的读取
  • ACB文件的读取
  • D-BAS的创建
  • AtomExPlayer的创建
各项处理的详细说明如下。

(1) 初始化运行时库

CRI Atom运行时库在初始化时创建线程等时,需要工作区内存。
可以使用 criAtomEx_CalculateWorkSize 函数计算初始化时需要的工作区内存大小。
运行时库初始化时所需的工作区内存大小取决于初始化时指定的框架等设置( CriAtomExConfig )。
例如,如果线程模型是 CRIATOMEX_THREAD_MODEL_MULTI ,则CRI Atom运行时库将创建线程,需要用于创建线程的内存区域。
但是,如果线程模型是 CRIATOMEX_THREAD_MODEL_USER_MULTI 和::CRIATOMEX_THREAD_MODEL_SINGLE ,则CRI Atom运行时库不会创建线程,因此不需要用于创建线程的内存区域。
所以,与为线程模型指定::CRIATOMEX_THREAD_MODEL_MULTI 时相比,指定 CRIATOMEX_THREAD_MODEL_USER_MULTICRIATOMEX_THREAD_MODEL_SINGLE 时,可减少所需的工作区内存大小。
[注意]
如果为线程模型指定::CRIATOMEX_THREAD_MODEL_USER_MULTI 和::CRIATOMEX_THREAD_MODEL_SINGLE ,则所需的内存大小减少,但会增加Server处理负荷。
(因为指定::CRIATOMEX_THREAD_MODEL_MULTI 时,在其他线程上执行的处理将全部转到Server处理中执行。)
因此,用户需要实现自行进行吸收Server处理的负荷变化的机制,令实现难度增大。

(2) Voice池的创建

创建Voice池时,需要工作区内存以确保在读取数据的缓冲区使用的音频数据的解码的作业区域、及在声音输出时的资源等。
创建Voice池时所需的工作区内存大小取决于创建VoicePlayer的函数。
Voice池创建函数与工作区内存大小计算函数之间的对应关系如下。
Voice池创建函数与工作区内存大小计算函数
Voice池创建函数 工作区内存计算函数
criAtomExVoicePool_AllocateStandardVoicePool criAtomExVoicePool_CalculateWorkSizeForStandardVoicePool
criAtomExVoicePool_AllocateAdxVoicePool criAtomExVoicePool_CalculateWorkSizeForAdxVoicePool
criAtomExVoicePool_AllocateHcaVoicePool criAtomExVoicePool_CalculateWorkSizeForHcaVoicePool
criAtomExVoicePool_AllocateHcaMxVoicePool criAtomExVoicePool_CalculateWorkSizeForHcaMxVoicePool



与运行时库初始化一样,创建Voice池时所需的工作区内存大小取决于创建Voice池时的设置( CriAtomExAdxVoicePoolConfig 等)。
具体来说,对于最大输出频道数量和最大采样频率,指定值越小,所需的工作区内存越小。
例如,当在Voice池中仅播放单声道音频时,将最大输出频道数量指定为1的工作区内存比指定2时的工作区内存小。
同样,如果仅播放采样频率24kHz或更低的声音,为最大采样频率指定为24000时的工作区内存比指定为48000时的工作区内存小。
[注意]
如果将最大输出频道数量设置为1并创建Voice池,则无法用创建的Voice池播放立体音频。
同样,如果将最大采样频率设置为24kHz并创建Voice池,则无法用创建的Voice池播放32kHz和48kHz的音频。

(3) ACF的注册

注册ACF时,直接从ACF信息存储区域或从ACF文件直接注册时,则需要工作区内存来确保用于读取数据的缓冲区。
注册ACF所需的工作区内存大小取决于注册ACF的方法。
ACF注册函数与工作区内存大小计算函数的对应关系如下。
ACF注册函数与工作区内存大小计算函数
ACF注册函数 工作区内存计算函数
criAtomEx_RegisterAcfData criAtomEx_CalculateWorkSizeForRegisterAcfData
criAtomEx_RegisterAcfFile criAtomEx_CalculateWorkSizeForRegisterAcfFile


(4) ACB的加载

加载ACB时,如果从ACB信息存储区域或从ACB文件加载,则需要工作区内存来确保用于读取数据的缓冲区。
ACB的加载所需的工作区内存大小取决于加载ACB的方法。
ACB加载函数与工作区内存大小计算函数的对应关系如下。
ACB加载函数与工作区内存大小计算函数
ACB加载函数 工作区内存计算函数
criAtomExAcb_LoadAcbData criAtomExAcb_CalculateWorkSizeForLoadAcbData
criAtomExAcb_LoadAcbFile criAtomExAcb_CalculateWorkSizeForLoadAcbFile


(5) D-BAS的创建

由于D-BAS是串流缓冲区管理的功能,因此需要工作区内存用于串流缓冲区和管理串流缓冲区。
创建D-BAS时所需的工作区内存大小取决于使用串流播放的应用程序或场景。
D-BAS创建函数与工作区内存大小计算函数
D-BAS创建函数 工作区内存计算函数
criAtomExDbas_Create criAtomExDbas_CalculateWorkSize

使用以下函数计算为D-BAS设置的消耗比特率。
各编解码器的消耗比特率计算函数
ADX HCA(HCA-MX)
criAtomEx_CalculateAdxBitrate criAtomEx_CalculateHcaBitrate

如果存在各机型专用的编解码器,则在机型专用的头文件中声明与上面相同的函数。

(6) AtomExPlayer的创建

创建AtomExPlayer时,需要工作区内存来确保Player区域和保存文件路径的区域。
创建AtomExPlayer时所需的工作区内存大小取决于是否指定文件路径播放。
AtomExPlayer创建函数与工作区内存大小计算函数的对应关系如下。
AtomExPlayer创建函数与工作区内存大小计算函数
AtomExPlayer创建函数 工作区内存计算函数
criAtomExPlayer_Create criAtomExPlayer_CalculateWorkSize


如何分配工作区内存

如果使用CRI Atom运行时库,则在初始化运行时库时和创建AtomExPlayer时,必须分配"工作区内存"作为库使用的作业区域。
CRI Atom运行时库提供以下两种方式为CRI Atom库分配工作区内存。
  • Fixed Memory方式:分配应用程序提供的内存区域的方法
  • User Allocator方式:将内存分配函数注册到CRI Atom库的方法
两种方式的详细说明如下。

(1) 关于Fixed Memory方式

Fixed Memory方式是在执行需要工作区内存的函数时,将所需的工作区内存设置为函数的参数。
对于需要为运行时库分配内存的API,如::criAtomEx_Initialize 函数(初始化运行时库)和::criAtomExPlayer_Create 函数(AtomExPlayer的创建)等,函数的参数中必须包含以下两个参数。
  • 缓存地址
  • 缓冲区大小
例如 criAtomEx_Initialize 函数的第二个参数“void *work”和第三个参数“CriSint32 size”对应上述内容。
执行这些API时,用户必须事先将想要确保的内存区域设置为函数的参数。
使用专用的工作区内存大小计算函数,计算为函数设置的工作区内存大小。
例如 criAtomEx_Initialize 函数,可以使用 criAtomEx_CalculateWorkSize 函数来计算执行函数所需的工作区内存大小。
总结上述步骤,采用Fixed Memory方式分配工作区内存的步骤如下。
  1. 计算工作区内存请求函数(※)所需的工作区内存大小。
  2. 确保作为计算结果返回的相应大小的内存。
  3. 将确保的内存作为参数,执行工作区内存请求函数。
※工作区内存请求函数:执行函数时需要工作区内存的函数。
[例]
采用Fixed Memory方式执行初始化处理的示例如下。
main()
{
void *work; // 工作区内存地址
CriSint32 size; // 工作区内存大小
:
// 计算初始化运行时库所需的工作区内存大小
size = criAtomEx_CalculateWorkSize(&config);
// 工作区内存的确保
work = malloc((size_t)size);
// 初始化运行时库
// →指定确保了的工作区内存。
criAtomEx_Initialize(&config, work, size);
:
// 应用程序的主处理
// →在此期间,继续保持所分配的内存。
:
// 结束应用程序时执行结束处理
// 释放不需要的工作区内存
free(work);
:
}
CriSint32 criAtomEx_CalculateWorkSize(const CriAtomExConfig *config)
Calculate the size of the work buffer required to initialize the library
void criAtomEx_Finalize(void)
Finalize the library
CriBool criAtomEx_Initialize(const CriAtomExConfig *config, void *work, CriSint32 work_size)
Initialize the library


[注意]
设置为工作区内存的区域用于运行时库中的各种用途,直至执行运行时库的结束处理。
用户需要持续保持初始化时设置的工作区内存,直至执行结束处理为止。
(请勿将工作区内存释放或用于其他用途。)

(2) 关于User Allocator方式

除了每次执行函数时分配工作区内存的方法外,还可以将用户创建的内存分配函数设置到CRI Atom库。
这种方法称为User Allocator方式
使用User Allocator方式时,用户必须事先准备内存分配函数和内存释放函数,并将其设置在CRI Atom运行时库中。
内存分配函数相当于标准库的malloc函数,是动态分配指定大小的内存并返回内存块地址的函数。
同样,内存释放函数相当于标准库的free函数,是释放由内存分配函数分配的内存块的函数。 用户需要根据CRI Atom库规定的接口,实现并注册这两个功能。
具体的接口和注册函数如下。
实现接口和注册函数
实现接口 注册函数
内存分配函数
CriAtomMallocFunc
criAtomEx_SetUserAllocator
内存释放函数
CriAtomFreeFunc
criAtomEx_SetUserAllocator



通过在CRI Atom库中设置内存分配函数和内存释放函数,CRI Atom库将更改操作,以便使所有注册的函数执行工作区内存的分配/释放。
因此,使用User Allocator方式时,即使在执行工作区内存请求函数时也不需要为函数指定工作区内存。
(为内存地址指定为NULL、内存大小指定为0。)
总结上述步骤,采用User Allocator方式分配工作区内存的步骤如下。
  1. 在CRI Atom运行时库中注册内存分配函数和内存释放函数。
  2. 执行工作区内存请求函数。
    (内存地址指定为NULL,内存大小指定为0。)
[例]
采用User Allocator方式执行初始化处理的示例如下。
// 自定义内存分配函数
void *user_malloc(void *obj, CriUint32 size)
{
void *mem;
// 内存的分配
mem = malloc(size);
return (mem);
}
// 准备自定义内存释放函数
void user_free(void *obj, void *mem)
{
// 释放内存
free(mem);
return;
}
main()
{
// 注册自定义的内存分配函数
criAtomEx_SetUserAllocator(user_malloc, user_free, NULL);
// 初始化运行时库
// 为工作区内存指定NULL和0。
// →使用注册的内存分配函数分配必要的内存。
criAtomEx_Initialize(NULL, NULL, 0);
:
// 应用程序的主处理
:
// 结束应用程序时执行结束处理
// →使用注册的内存释放函数释放初始化时分配的内存。
:
}
#define criAtomEx_SetUserAllocator(p_malloc_func, p_free_func, p_obj)
Register a custom memory allocator
Definition: cri_le_atom_ex.h:309