一、插件框架
插件和主体的数据结构设计。
将插件看作黑盒,提供统一的接口给主体,主体调用该接口时不需要知道内部具体的实现。
插件的数据结构设计如下,包括插件描述信息(名字,描述,版本号)和接口集。
typedef struct node_boot_func
{
const char *name;
const char *desc;
int category_id;
int sub_id;
void (*getversion)(char buffer[VERSION_MAX_LENGTH]);
int (*available)(const int parm);
void* (*create)(void *parm, int size);
void (*release)(void*p);
} node_boot_func;
用前插法将这些插件存储在一个
单链表中。
插件的依赖:降低与其他插件的耦合。
消息通信机制的实现:插件如何将自身的公共信息传达给其他插件(或:外环境),或外环境怎样将消息反馈给插件。
源插件和解码插件有什么异同。
二、系统设计
(1)分别启动两个线程:一个音视频解码线程slave,一个播放显示和状态管理线程master。中间用一个缓冲队列来连接两个线程,线程slave把数据放到队列,线程master从缓存队列取数据。
(2)层次架构与函数指针:回调函数是通过函数指针调用的函数。因为可以把调用者与被调用者分开。调用者不关心谁是被调用者,所有它需知道的,只是存在一个具有某种特定原型、某些限制条件(如返回值为int)的被调用函数。
例如:插件里的函数集是函数指针,主体和插件耦合度降低。主体通过回调函数来操控插件。
(3)C语言的消息机制:使用函数指针来实现。
例如:插件将自身信息传达给主体。
【主体】
void msg_gateway (void* key,int notify_id, int param1, int param2)
{
tmpc_context *ptx = (tmpc_context*)key;
if( !ptx) return;
switch(notify_id)
{
case MSG_BY_PASS:
...
case MSG_AFTER_SEEK:
...
case MSG_RECONNECT_SEEK:
...
case MSG_MEDIA_FMT:
...
case MSG_END_OF_FILE:
...
}
}
指定该函数指针到插件的公共接口中,使得该插件可以调用msg_gateway回调函数来传递消息。
source->set_notify(source, msg_gateway,ptx);
【插件】
mfs->notify_routine( mfs->key, MSG_AFTER_SEEK, seekedpos, 0 );
三、音视频同步
音频根据自带时间戳和系统时间的差异关系对声卡时钟(tick值)作调整。根据音频的线性特征,视频以音频的声卡时钟(ret= dev->tick+ ((now - dev->time_ref))作参考来进行音视频同步。每次在填充满一个缓冲区时进行音频时钟的调整。
视频在显示之前 和 在解码之前,进行视频播放的延时或丢帧,来达到音频和视频同步。
移植