前言
VLC 播放流程大概是先加载解封装器,然后通过es_out控制所有的stream。然后会加载decoder。最终通过resource文件的方法交给输出 模块。下面简要介绍。
正文
播放器主要分为三层。主要通过两个接口实现了功能隔离。分别是es_out.c和decoder.c的实现了:
//控制解封装后的的数据,通过send增加数据
static const struct es_out_callbacks es_out_cbs =
{.add = EsOutAdd,.send = EsOutSend,.del = EsOutDel,.control = EsOutControl,.destroy = EsOutDelete,.priv_control = EsOutPrivControl,
};//解封装后的数据传给输出
static const struct decoder_owner_callbacks dec_video_cbs =
{.video = {.get_device = ModuleThread_GetDecoderDevice,.format_update = ModuleThread_UpdateVideoFormat,.buffer_new = ModuleThread_NewVideoBuffer,.queue = ModuleThread_QueueVideo,.queue_cc = ModuleThread_QueueCc,.get_display_date = ModuleThread_GetDisplayDate,.get_display_rate = ModuleThread_GetDisplayRate,},.get_attachments = InputThread_GetInputAttachments,
};
static const struct decoder_owner_callbacks dec_audio_cbs =
{.audio = {.format_update = ModuleThread_UpdateAudioFormat,.queue = ModuleThread_QueueAudio,},.get_attachments = InputThread_GetInputAttachments,
};
解封装部分主要通过Run方法开启的线程实现多线程的解封装。
int input_Start( input_thread_t *p_input )
{void *(*func)(void *) = Run;/* Create thread and wait for its readiness. */priv->is_running = !vlc_clone( &priv->thread, func, priv );
}static void *Run( void *data )
{if( !Init( p_input ) ){MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */End( p_input );}
}
这是核心问题,主要是初始化,加载读取存储截至的资源(比如网络资源,硬盘等)加载stream filter(比如缓存控制等),最后加载解封装器。然后通过MainLoop,的MainLoopDemux的demux_Demux。本质上就是调用demux模块的demux_pf的。
拿到的结果交给第二部分。EsOutSend。最终交给decoder。然后返回给dec.c中。
第三部分则通过ModuleThread_QueueAudio。拿到解码后的数据,然后调用audiofilter,处理声音,最终交给aout 的play函数,最终初始化audiotrack,播放数据。