整章目录:Android------- IjkPlayer 源码学习目录
本篇会有很多源代码,请注意阅读每行代码上面的注释。

本篇介绍的主要内容为上图红框圈起部分:
IjkMediaPlayer_prepareAsync的作用为播放器播放前做准备。其被Java层的IjkMediaPlayer.prepareAsync调用。
IjkMediaPlayer_prepareAsync :

static int ijkmp_prepare_async_l(IjkMediaPlayer *mp)
{
省略。。。。
// 1.向消息链表发送一个FFP_MSG_PLAYBACK_STATE_CHANGED消息,改变IjkMediaPlayer的状态为MP_STATE_ASYNC_PREPARING,向native层发送一次测试消息
ijkmp_change_state_l(mp, MP_STATE_ASYNC_PREPARING);
// 2.向消息链表发送一个FFP_MSG_FLUSH消息,表示向向Java层发送一次测试通信。
msg_queue_start(&mp->ffplayer->msg_queue);
// 3.创建一个线程用来运行消息队列ijkmp_msg_loop
mp->msg_thread = SDL_CreateThreadEx(&mp->_msg_thread, ijkmp_msg_loop, mp, "ff_msg_loop");
// 4.设置请求uri、创建和初始化音轨、打开数据流,启动视频刷新线程和读取数据线程
int retval = ffp_prepare_async_l(mp->ffplayer, mp->data_source);
return 0;
}
上面为省略版的ijkmp_prepare_async_l,一共做了4件事。下面将按照事件顺序阅读。
事件1、事件2:
向消息链表中发送两条消息,一条测试Java层的消息处理机制是否通了,一条测试native的消息处理机制是否通了。可以忽略不用管,估计是开发者自己用的。
事件3:创建一个线程来运行native的消息处理机制:详细请看:Android --- Ijkplayer源码阅读native层之自定义消息处理机制(四)

事件4:设置请求uri、创建和初始化音轨、打开数据流,启动视频刷新线程和读取数据线程;
ffp_prepare_async_l:
int ffp_prepare_async_l(FFPlayer *ffp, const char *file_name)
{
省略代码。。。。
//如果是rtmp或者rtsp开头的,表示直播,将超时选项置空
if (av_stristart(file_name, "rtmp", NULL) ||
av_stristart(file_name, "rtsp", NULL)) {
av_dict_set(&ffp->format_opts, "timeout", NULL, 0);
}
// 防止名字过长
if (strlen(file_name) + 1 > 1024) {
//返回将处理传递的URL的协议的名称。如果没有找到针对给定URL的协议,则返回NULL。
if (avio_find_protocol_name("ijklongurl:")) {
av_dict_set(&ffp->format_opts, "ijklongurl-url", file_name, 0);
file_name = "ijklongurl:";
}
}
// 将所有的选项设置到ffp对象的AvClass中
av_opt_set_dict(ffp, &ffp->player_opts);
// 判断是否有音频信号量
if (!ffp->aout) {
// 创建并初始化音轨
ffp->aout = ffpipeline_open_audio_output(ffp->pipeline, ffp);
}
// 打开数据流,并启动视频刷新线程和读取数据线程
VideoState *is = stream_open(ffp, file_name, NULL);
return 0;
}
上面加了注解,找到我们的主线stream_open:
static VideoState *stream_open(FFPlayer *ffp, const char *filename, AVInputFormat *iformat)
{
VideoState *is;
// 创建VideoState结构体
is = av_mallocz(sizeof(VideoState));
// 如果是Android平台
#if defined(__ANDROID__)
// SoundTouch是一个开源的音频处理库,主要实现包含变速、变调、变速同时变调等三个功能模块
// 是否开启SoundTouch,在这里只有变速,是否使用SoundTouch来改变音频速度
if (ffp->soundtouch_enable) {
is->handle = ijk_soundtouch_create();
}
#endif
// ffp->pictq_size=3
// 初始化is中的视频帧、音频帧、字幕帧队列,以一帧为单位存储
if (frame_queue_init(&is->pictq, &is->videoq, ffp->pictq_size, 1) < 0)
goto fail;
if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
goto fail;
if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
goto fail;
// 初始化视频、音频、字幕链表,
// 一帧中可能会用多个AvPacket构成,该链表以一AvPacket为单位存储
if (packet_queue_init(&is->videoq) < 0 ||
packet_queue_init(&is->audioq) < 0 ||
packet_queue_init(&is->subtitleq) < 0)
goto fail;
// 创建控制线程的条件变量,类似于Java的信号量,这里默认为1
if (!(is->continue_read_thread = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
goto fail;
}
// 初始化锁状态
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
// 用户设置的播放器音量大小,av_clip限制其值在0到100之间
ffp->startup_volume = av_clip(ffp->startup_volume, 0, 100);
// 将0~100的音量转化为系统对应的音量大小。
ffp->startup_volume = av_clip(SDL_MIX_MAXVOLUME * ffp->startup_volume / 100, 0, SDL_MIX_MAXVOLUME);
// 设置音量
is->audio_volume = ffp->startup_volume;
// 标识是否无声
is->muted = 0;
// 音视频的同步类型:1.按音频时间轴;2.视频时间轴;3.外部时间轴
is->av_sync_type = ffp->av_sync_type;
// 请求暂停播放,1为暂停
is->pause_req = !ffp->start_on_prepared;
// 启动视频刷新线程
is->video_refresh_tid = SDL_CreateThreadEx(&is->_video_refresh_tid, video_refresh_thread, ffp, "ff_vout");
//注意:开启网络流数据

&spm=1001.2101.3001.5002&articleId=108573848&d=1&t=3&u=9c83b62c48704b21b82cf75a6f5c58b9)
2595

被折叠的 条评论
为什么被折叠?



