前言
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,播放數據。