核间解码器(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核间解码固件使用

results matching ""

    No results matching ""