1抵知、初始化入口
打開ijkplayer-ios/ios/IJKMediaDemo里面的工程文件,查看IJKFFMoviePlayerController的聲明實現(xiàn)文件蝗羊,實際上它并不繼承自UIViewController,不是iOS傳統(tǒng)意義上的VC控制器,而是iOS層與底層進行通信的控制層,是播放器類哮翘。
- (id)initWithContentURLString:(NSString *)aUrlString
withOptions:(IJKFFOptions *)options
{
if (aUrlString == nil)
return nil;
self = [super init];
if (self) {
//主要是ffmpeg的初始化工作, ijkplayer是對ffmpeg的封裝
ijkmp_global_init();
//注冊ijkplayer事件相關的回調(diào)函數(shù)
ijkmp_global_set_inject_callback(ijkff_inject_callback);
//檢查ijkplayer版本號是否匹配
[IJKFFMoviePlayerController checkIfFFmpegVersionMatch:NO];
// 見http://www.reibang.com/p/97f4f0fab3b6
if (options == nil)
options = [IJKFFOptions optionsByDefault];
// 監(jiān)控類,可以提供fps,碼率,網(wǎng)絡狀況,視頻尺寸等信息
_monitor = [[IJKFFMonitor alloc] init];
// 源地址
_urlString = aUrlString;
//關鍵api,后面會深入展開
_mediaPlayer = ijkmp_ios_create(media_player_msg_loop);
// 向FFmpeg注冊IJKFFMoviePlayerController
ijkmp_set_weak_thiz(_mediaPlayer, (__bridge_retained void *) self);
ijkmp_set_inject_opaque(_mediaPlayer, (__bridge_retained void *) weakHolder);
ijkmp_set_ijkio_inject_opaque(_mediaPlayer, (__bridge_retained void *)weakHolder);
ijkmp_set_option_int(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "start-on-prepared", _shouldAutoplay ? 1 : 0);
// 渲染視圖
_glView = [[IJKSDLGLView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_glView.isThirdGLView = NO;
_view = _glView;
//ffplayer與glView想關聯(lián)
ijkmp_ios_set_glview(_mediaPlayer, _glView);
ijkmp_set_option(_mediaPlayer, IJKMP_OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2");
......
}
return self;
}
2仔涩、初始化關鍵Api的深入學習
// 播放器創(chuàng)建
_mediaPlayer = ijkmp_ios_create(media_player_msg_loop);
IjkMediaPlayer *ijkmp_ios_create(int (*msg_loop)(void*))
{
IjkMediaPlayer *mp = ijkmp_create(msg_loop);
if (!mp)
goto fail;
mp->ffplayer->vout = SDL_VoutIos_CreateForGLES2();//創(chuàng)建圖像渲染對象SDL_Vout
if (!mp->ffplayer->vout)
goto fail;
mp->ffplayer->pipeline = ffpipeline_create_from_ios(mp->ffplayer);//創(chuàng)建平臺相關的IJKFF_Pipeline對象
if (!mp->ffplayer->pipeline)
goto fail;
return mp;
fail:
ijkmp_dec_ref_p(&mp);
return NULL;
}
在該方法中主要完成了三個動作:
2.1創(chuàng)建IJKMediaPlayer對象:延伸到ffp_create()方法
2.2創(chuàng)建圖像渲染對象SDL_Vout:調(diào)用OpenGL繪制圖像
2.3創(chuàng)建平臺相關的IJKFF_Pipeline對象忍坷,包括視頻解碼以及音頻輸出部分 : 輸出管線需單獨開篇幅學習了
說明:
ijkmp_ios_create:ios平臺下對ijkplayer.c的封裝
ijkmp_create:底層播放控制的C代碼 和 上層的ios平臺上操作控制的OC代碼的中間層,是消息循環(huán)函數(shù)運行在這一層
IjkMediaPlayer結構體如下:
struct IjkMediaPlayer {
volatile int ref_count;
pthread_mutex_t mutex;
FFPlayer *ffplayer;
int (*msg_loop)(void*);
SDL_Thread *msg_thread;
SDL_Thread _msg_thread;
int mp_state;
char *data_source;
void *weak_thiz;
int restart;
int restart_from_beginning;
int seek_req;
long seek_msec;
};
IjkMediaPlayer結構體對象在創(chuàng)建完成以后將msg_loop消息循環(huán)函數(shù)指針賦值保存到msg_loop成員變量中。
3佩研、消息循環(huán)初探
在播放器初始化方法中柑肴,可以看到media_player_msg_loop函數(shù)地址作為參數(shù)傳入了ijkmp_ios_create
_mediaPlayer = ijkmp_ios_create(media_player_msg_loop);
int media_player_msg_loop(void* arg)
{
@autoreleasepool {
IjkMediaPlayer *mp = (IjkMediaPlayer*)arg;
__weak IJKFFMoviePlayerController *ffpController = ffplayerRetain(ijkmp_set_weak_thiz(mp, NULL));
while (ffpController) {
@autoreleasepool {
// 由底層通過msg_loop傳出IJKFFMoviePlayerMessage對象,以便上層進行業(yè)務相關處理
IJKFFMoviePlayerMessage *msg = [ffpController obtainMessage];
if (!msg)
break;
int retval = ijkmp_get_msg(mp, &msg->_msg, 1);
if (retval < 0)
break;
// block-get should never return 0
assert(retval > 0);
[ffpController performSelectorOnMainThread:@selector(postEvent:) withObject:msg waitUntilDone:NO];
}
}
// retained in prepare_async, before SDL_CreateThreadEx
ijkmp_dec_ref_p(&mp);
return 0;
}
}
在播放過程中,某些行為的完成或者變化旬薯,如prepare完成晰骑,開始渲染等,需要以事件形式通知到外部绊序,以便上層(這里是iOS層)作出具體的業(yè)務處理硕舆。ijkplayer支持的事件比較多,具體定義在ijkplayer/ijkmedia/ijkplayer/ff_ffmsg.h中骤公。
而最終抚官,該函數(shù)地址被賦值給了IjkMediaPlayer中的msg_loop函數(shù)指針
IjkMediaPlayer *ijkmp_create(int (*msg_loop)(void*))
{
......
mp->msg_loop = msg_loop;
......
}
當開始播放時,會開啟一個消息線程
static int ijkmp_prepare_async_l(IjkMediaPlayer *mp)
{
......
mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, ijkmp_msg_loop, mp, "ff_msg_loop");
......
}
其中ijkmp_msg_loop函數(shù)就是mp->msg_loop阶捆,至此已經(jīng)完成了播放消息發(fā)送的準備工作凌节。
參考:https://blog.csdn.net/xipiaoyouzi/article/details/74280170
金山視頻云:http://www.reibang.com/u/b2227c3472fd