核间解码器(adicore.md)
简介
核间解码器(adicore.md),即inter-core audio decoder,实现包含在AV组件中。其需要搭配DSP核(实际解码算法所运行的核)上核间解码固件使用,具体可参考av_cp组件使用 。
该组件的使用是硬件相关的。目前在pangu芯片上默认支持mp3和aac核间解码。对于其他多核芯片,用户可基于此扩展实现。
为何需要核间解码
- 某些情况下,某些编码类型解码时可能占用很高的主频(如在ck803ef上,HE-AAC解码主频需求在240M左右),此时可能需要通过核间通信(mailbox/IPC)将解码工作放到另一核上(DSP核)执行。
- 对上层用户来说,adicore屏蔽了两个核解码交互的复杂性,用户仅在一个核上开发即可,感知不到核间解码的存在。
核间解码结构及时序
核间解码结构如下图所示:
核间解码时序图如下所示:
接口定义
注册核间解码器子类型
int ad_ops_register(onst struct ad_ops *ops);
通过该接口,用户可以将自己扩展定义的ops子类型注册到系统中。
返回值:
调用成功时返回0,否则返回-1。
打开核间解码器
核间解码器参数初始化
int ad_conf_init(ad_conf_t *ad_cnf);
初始化解码器配置参数,用于打开解码器。
用户通过该接口获取默认的配置参数后,可根据需要修改相关参数。配置参数由结构体ad_conf_t表示,其包括采样格式、额外解码配置参数等,详细定义如下:
typedef struct ad_conf {
sf_t sf; ///< 音频采样格式,如果有需要
uint8_t *extradata; ///< 额外编码参数,如果存在。如mp4
int32_t extradata_size;
uint32_t block_align; ///< 块大小,如果需要
uint32_t bps; ///< 比特率, if needed
} ad_conf_t;
返回值:
调用成功时返回0,否则返回-1。
注意事项:
- 对于裸流解码(透传),需要将sf传递给pcm解码器。
- 对于extradata和extradata_size,如果从封装格式中拆出核心解码信息是单独存储的,则需要传入。如mp4
- 对于block_align,则在adpcm_ms解码时需要从wav封装格式中拆出传入
- 对于运算量较小的音频解码算法,不建议使用核间解码
打开核间解码器
ad_cls_t* ad_open(avcodec_id_t id, const ad_conf_t *ad_cnf);
根据解码配置参数ad_cnf打开指定codec id的解码器。
返回值:
调用失败时,返回NULL。
核间解码及控制
核间解码
int ad_decode(ad_cls_t *o, avframe_t *frame,
int *got_frame, const avpacket_t *pkt);
将一帧音频包pkt解码,解码数据存储在frame结构中。got_frame表明本次是否可以解出数据(可能需要向解码器传入多个音频包才能解出来一帧)。avframe_t和avpacket_t结构体中各成员的详细说明请参见AV。
返回值:
调用失败时,返回-1,大于0表示解码一帧消耗的原始编码帧字节数。
重置解码器
int ad_reset(ad_cls_t *o);
重置解码器。当音频跳转到新的时间点播放时,需要重置解码器。防止可能出现爆音现象。
返回值:
调用成功时返回0,否则返回-1。
关闭核间解码器
int ad_close(ad_cls_t *o);
关闭解码器,销毁相关资源
返回值:
调用成功时返回0,否则返回-1。
控制解码器
int ad_control(ad_cls_t *o, int cmd, void *arg, size_t *arg_size);
通过控制命令字cmd控制流。
返回值:
调用成功时返回0,否则返回-1。
如何使用
开发者可基于两个层次使用。一是基于AV框架中的解码层,其通过解码器注册的方式兼容了本地解码和核间解码。我们推荐使用此种方式。二是直接调用核间解码相关接口使用。
基于AV框架使用与集成
- adicore在YoC平台上的具体使用请参见components/av/avcodec/ad_ipc.c中的实现。其主要实现struct ad_ops定义的几个接口,如下所示:
struct ad_ops {
const char *name;
avcodec_id_t id;
int (*open) (ad_cls_t *o);
int (*decode) (ad_cls_t *o, avframe_t *frame, int *got_frame, const avpacket_t *pkt);
int (*control) (ad_cls_t *o, int cmd, void *arg, size_t *arg_size);
int (*reset) (ad_cls_t *o);
int (*close) (ad_cls_t *o);
};
const struct ad_ops ad_ops_ipc = {
.name = "ipc",
.id = AVCODEC_ID_AAC | AVCODEC_ID_MP3, ///< 默认支持mp3和aac核间解码
.open = _ad_ipc_open,
.decode = _ad_ipc_decode,
.control = _ad_ipc_control,
.reset = _ad_ipc_reset,
.close = _ad_ipc_close,
};
- 在具体使用时,将ad_ops_ipc注册进av框架中。如下所示:
int ad_register_ipc()
{
extern struct ad_ops ad_ops_ipc;
return ad_ops_register(&ad_ops_ipc);
}
- adicore在player组件中的使用如下:
int player_init()
{
static int inited = 0;
if (!inited) {
stream_register_mem();
stream_register_file();
stream_register_http();
stream_register_fifo();
demux_register_wav();
demux_register_mp3();
demux_register_mp4();
demux_register_rawaudio();
ad_register_ipc(); ///< 注册adicore核间解码组件
ao_register_alsa();
inited = 1;
}
return 0;
}
注意事项:
- 也可通过解决方案下package.yaml加入CONFIG_DECODER_IPC: 1配置项使能核间解码
- 若核间解码支持了mp3,则没有必要本地解码也注册mp3解码支持。否则会根据对应解码注册的先后顺序使用
- 再次提醒,核间解码是硬件相关的。需要搭配DSP核间解码固件使用