AV组件适配对接

简介

AV组件主要提供了音频服务播放器AV基础框架三个不同层次的设计及接口实现。这三个层次之间的关系如下图所示:

音频服务基于播放器和YoC微服务框架来开发,支持提示音、语音合成(TTS)、音乐等资源播放状态的切换与维护等功能。基于此层次开发,对于开发者的能力要求最低,但灵活性较差。用户可直接基于平头哥提供的硬件和智能语音方案快速上手开发。若开发者本就有一套完善的音频播放组件、应用开发框架及语音方案,基于该层开发就不太合适。音频服务的适配和扩展请参考YoC微服务音频服务

AV组件中同时提供了一个简洁的音频播放器实现,支持wav、mp3、m4a、amrnb、amrwb、flac、adts、opus、speex、adpcm_ms、alaw、mulaw等音频格式播放。其直接基于AV基础框架开发,提供了播放器创建、播放、暂停、恢复、停止等接口。若产品类型是类似智能音箱方案,需要开发者自行维护与控制提示音、TTS等资源的播放状态。播放器的适配和扩展请参考

AV基础框架是一个轻量级的多媒体开发框架。其采用典型的4层多媒体模型设计及面向对象的思想开发,使得开发者在此基础上易于复用与扩展。若开发者需要增加媒体取流格式、扩展媒体解封装格式、增加音频解码器类型或者视频播放支持,可直接基于该框架开发和扩展。同时用户也可仅使用框架中的某一层或某个模块开发,如音频输出层和核间解码。对音频输出层来说,其提供了软件音量配置、重采样等功能。开发者可直接对该音频输出层封装一下,即可应用到原有播放器中。基于该层开发,灵活性最高,但要求开发者有一定的音视频开发基础。

综上,开发者可基于已有软硬件资源和功能需要,灵活选择AV组件的不同层次来开发、扩展多媒体相关功能。下表汇总了基于各个层次开发的优缺点:

层次 开发速度 灵活性 开发者能力要求
音频服务
播放器
AV基础框架

AV框架的适配扩展

AV框架中的4层多媒体模型均采用面向对象的设计思想开发。开发者仅需按照相应层次的struct xxx_ops结构定义实现子类并且将该子类实现注册进框架即可使用。如对媒体层进行扩展m3u8取流支持,需要实现结构struct stream_ops定义的子类stream_ops_m3u8。并且需要调用stream_ops_register接口将该子类注册进系统中。

媒体接入层(stream)

UML设计

  • stream_ops_http、stream_ops_mem、stream_ops_file、stream_ops_fifo等子类继承自基类stream_cls_t。分别对应于网络流、内存流、本地文件流、队列流取流播放。

类型定义

用户若需要实现新的媒体接入类型,需要实现struct stream_ops结构中的定义。其具体类型如下所示:

struct stream_ops {
    const char                *name;                           ///< 子类名称,自定义
    uint8_t                   type;                            ///< 支持的stream类型,可扩展定义
    const char*               protocols[STREAM_PROTOCOLS_MAX]; ///< 支持的协议,可参考stream_ops_file中定义。通过stream_open传入的url可通过此字段找到对应的子类实现

    int      (*open)          (stream_cls_t *o, int mode);
    int      (*read)          (stream_cls_t *o, uint8_t *buf, 
                               size_t count);
    int      (*write)         (stream_cls_t *o, const uint8_t *buf,
                               size_t count);
    int      (*seek)          (stream_cls_t *o, int32_t pos);
    int      (*control)       (stream_cls_t *o, int cmd, void *arg, 
                               size_t *arg_size);
    int      (*close)         (stream_cls_t *o);
};

子类注册

int stream_ops_register(const struct stream_ops *ops);

通过该接口,用户可以将自己扩展定义的stream_ops子类型注册到系统中。

返回值:

调用成功时返回0,否则返回-1。

注意事项:

当前stream子类型最大支持注册16个,定义在stream.h中的STREAM_OPS_MAX。用户可根据需要修改

解复用层(avformat)

UML设计

  • demux_ops_wav、demux_ops_mp3、demux_ops_m4a等子类继承自基类demux_cls_t。分别对应于wav、mp3、m4a音频格式解复用。解复用出来的一帧音频数据会被送到对应的解码器进行解码。

类型定义

用户若需要实现新的解复用类型,需要实现struct demux_ops结构中的定义。其具体类型如下所示:

struct demux_ops {
#define MAX_EXTENTSIONS (5)
    const char                  *name;                        ///< 子类名称,自定义
    uint8_t                     type;                         ///< 支持的解复用类型,可扩展定义
    const char                  *extensions[MAX_EXTENTSIONS]; ///< 此种解复用类型对应的文件后缀。可用于媒体复用类型的探测功能。可参考已有子类实现。

    int      (*read_probe)      (const avprobe_data_t *pd);   ///< 解复用类型探测接口。返回值为0~100。当探测到确定是该类型时,返回100。否则自行根据复用格式符合程度,返回相应类型。最终会根据各个已注册的解复用类型的read_probe返回值,返回匹配度最高的子类。

    int      (*open)            (demux_cls_t *o);
    int      (*read_packet)     (demux_cls_t *o, avpacket_t *pkt); ///< 解封装一帧音视频包
    int      (*seek)            (demux_cls_t *o, uint64_t timestamp); ///< 跳转到指定时间戳
    int      (*control)         (demux_cls_t *o, int cmd, void *arg, size_t *arg_size);
    int      (*close)           (demux_cls_t *o);
};

子类注册

int demux_ops_register(const struct demux_ops *ops);

通过该接口,用户可以将自己扩展定义的demux_ops子类型注册到系统中。

返回值:

调用成功时返回0,否则返回-1。

注意事项:

当前demux子类型最大支持注册16个,定义在demux.h中的DEMUX_OPS_MAX。用户可根据需要修改

解码层(avcodec)

UML设计

  • 该层将demux解复用后出来的一帧帧编码数据解码成音视频裸数据(pcm/yuv)。
  • 在某些情况下,某些编码类型解码时可能占用很高的主频(如在ck803ef上,HE-AAC解码主频需求在240M左右),此时可能需要通过核间通信(mailbox/IPC)将解码工作放到另一核上执行。
  • 核间解码接口使用请参考此处介绍。开发者可略过AV框架,直接使用核间解码功能。
  • 解码层为考虑扩展性,支持本地(核内)与跨核(核间)解码。其中核间解码适配层请参考av/avcodec/ad_ipc.c使用。
  • ad_ops_pvmp3、ad_ops_rawaudio等子类继承自基类ad_cls_t。分别对应于mp3、裸pcm(解码透传)、aac音频编码格式解码

类型定义

用户若需要实现新的音频解码类型,需要实现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);
///< 将pkt结构中的一帧音频解码成pcm,结果存放在frame结构中   
    int      (*control)     (ad_cls_t *o, int cmd, void *arg, 
                            size_t *arg_size);
    int      (*reset)       (ad_cls_t *o); ///< 重置解码器,可用于seek跳转时将解码器内部数据清除重新开始解码
    int      (*close)       (ad_cls_t *o);
};

子类注册

int ad_ops_register(const struct ad_ops *ops);

通过该接口,用户可以将自己扩展定义的ad_ops子类型注册到系统中。

返回值:

调用成功时返回0,否则返回-1。

注意事项:

当前音频解码器子类型最大支持注册16个,定义在ad.h中的AD_OPS_MAX。用户可根据需要修改

输出层(output)

UML设计

  • ao_ops_alsa子类继承自基类ao_cls_t,对应于采用alsa标准音频输出接口实现。通过alsa层来屏蔽各产品不同codec的实现

类型定义

用户若需要实现新的音频输出类型,需要实现struct ao_ops结构中的定义。其具体类型如下所示:

struct ao_ops {
    const char          *name;     ///< 子类名称,自定义。ao_open可通过该名称打开相应子类

    int (*open)         (ao_cls_t *o, sf_t sf);
    int (*start)        (ao_cls_t *o); ///< 开始音频输出。当调用此接口后,才能调用write接口
    int (*stop)         (ao_cls_t *o); ///< 停止音频输出
    int (*drain)        (ao_cls_t *o); ///< 将写入到音频缓存中全部音频数据均播放完才返回,阻塞操作
    int (*close)        (ao_cls_t *o);
    int (*write)        (ao_cls_t *o, const uint8_t *buf, size_t count); ///< 将音频写入到音频输出中。阻塞操作,当完全写完或出错是返回
};
子类注册
int ao_ops_register(const struct ao_ops *ops);

通过该接口,用户可以将自己扩展定义的ao_ops子类型注册到系统中。

返回值:

调用成功时返回0,否则返回-1。

注意事项:

当前音频解码器子类型最大支持注册6个,定义在ao.h中的AO_OPS_MAX。用户可根据需要修改。

results matching ""

    No results matching ""