文章目录
- ijkplayer时序图
- 消息循环--回调函数实现
- 播放器播放时状态转换
- 播放
- 停止
- ijkmediaPlay
- 成员变量
- 成员函数
ijkplayer时序图
stream_open:
frame_queue_init
packet_queue_init
init_clock
创建read_thread线程
创建video_refresh_thread线程
消息循环–回调函数实现
ui 和播放器核心直接的交互有以下几种方式:
- ui直接调用IjkMediaPlayer的接口
- ui发送消息给消息循环线程,然后调⽤IjkMediaPlayer的接口
- IjkMediaPlayer发消息给消息循环线程,线程调⽤ui的接口
UI发送消息给循环线程,通过c++11中bind实现回调函数:
void MainWind::OnPlayOrPause() {
mp_ = new IjkMediaPlayer();
mp_->ijkmp_create(std::bind(&MainWind::message_loop, this, std::placeholders::_1))
mp_->ijkmp_prepare_async();
}
ijkmp_create: msg_loop函数赋值给ijkMediaPlay函数指针msg_loop
int IjkMediaPlayer::ijkmp_create(std::function<int (void *)> msg_loop)
{
msg_loop_ = msg_loop;
}
ijkMediaPlay的成员函数ijk_msg_loop,调用msg_loop_函数指针
int IjkMediaPlayer::ijkmp_msg_loop(void *arg)
{
msg_loop_(arg);
return 0;
}
jikMediaPlay在ijkmp_prepare_async中启动线程,调用ijk_msg_loop
int IjkMediaPlayer::ijkmp_prepare_async()
{
// 创建循环线程
msg_thread_ = new std::thread(&IjkMediaPlayer::ijkmp_msg_loop, this, this);
}
至此,调用MainWind中调用ijkmp_prepare_async即可实现message_loop消息循环函数回调
void MainWind::OnPlayOrPause()
{
qDebug() << "OnPlayOrPause call";
int ret = 0;
// 1. 先检测mp是否已经创建
if(!mp_) {
mp_ = new IjkMediaPlayer();
//1.1 创建
ret = mp_->ijkmp_create(std::bind(&MainWind::message_loop, this, std::placeholders::_1));
if(ret <0) {
qDebug() << "IjkMediaPlayer create failed";
delete mp_;
mp_ = NULL;
return;
}
// 1.2 设置url
mp_->ijkmp_set_data_source("2_audio.mp4");
// 1.3 准备工作
ret = mp_->ijkmp_prepare_async();
if(ret <0) {
qDebug() << "IjkMediaPlayer create failed";
delete mp_;
mp_ = NULL;
return;
}
} else {
// 已经准备好了,则暂停或者恢复播放
}
}
播放器播放时状态转换
IjkMediaPlayer 成员函数:mp_state_,表示播放状态
播放
ijkmp_create
ijkmp_set_data_source
ijkmp_prepare_async
然后等待消息MP_STATE_PREPARED再调⽤ijkmp_start启动播放。
停止
先调⽤ijkmp_stop
再调⽤ijkmp_destroy (ijkplayer⾥⾯是通过release调⽤destro
ijkmediaPlay
成员变量
std::mutex mutex_;
// 真正的播放器
FFPlayer *ffplayer_ = NULL;
//函数指针, 指向创建的message_loop,即消息循环函数
// int (*msg_loop)(void*);
std::function<int(void *)> msg_loop_ = NULL; // ui处理消息的循环
//消息机制线程
std::thread *msg_thread_; // 执行msg_loop
// SDL_Thread _msg_thread;
//字符串,就是一个播放url
char *data_source_;
//播放器状态,例如prepared,resumed,error,completed等
int mp_state_; // 播放状态
成员函数
- ijkmp_create
创建IjkMediaPlayer
创建FFPlayer(ffplay.c)
保存ui传⼊的回调msg_loop函数
初始化mutex
最终如果失败则调⽤destroy_p
int IjkMediaPlayer::ijkmp_create(std::function<int (void *)> msg_loop)
{
int ret = 0;
ffplayer_= new FFPlayer();
if(!ffplayer_) {
std::cout << " new FFPlayer() failed\n ";
return -1;
}
// msg_loop_ 函数指针
msg_loop_ = msg_loop;
ret = ffplayer_->ffp_create();
if(ret < 0) {
return -1;
}
return 0;
}
- ijkmp_destroy
停⽌msg_loop线程
释放mutex
释放自己delete this
int IjkMediaPlayer::ijkmp_destroy()
{
ffplayer_->ffp_destroy();
return 0;
}
- ijkmp_prepare_async
状态设置为MP_STATE_ASYNC_PREPARING(正在准备)
启动消息队列msg_queue_start
调用FFplayer的prepare_async_l
int IjkMediaPlayer::ijkmp_prepare_async()
{
// 判断mp的状态
// 正在准备中
mp_state_ = MP_STATE_ASYNC_PREPARING;
// 启用消息队列
msg_queue_start(&ffplayer_->msg_queue_);
// 创建循环线程
msg_thread_ = new std::thread(&IjkMediaPlayer::ijkmp_msg_loop, this, this);
// 调用ffplayer
int ret = ffplayer_->ffp_prepare_async_l(data_source_);
if(ret < 0) {
mp_state_ = MP_STATE_ERROR;
return -1;
}
return 0;
}
- ijkmp_start
先检测当前的状态是否可以转为start,删除队列⾥的FFP_REQ_START消息,删除队列⾥的FFP_REQ_PAUSE消息
发送FFP_REQ_START消息,jkMediaPlayer的循环⾥,ijkmp_get_msg处理FFP_REQ_START,然后调⽤ffp_start_l触发播放
int IjkMediaPlayer::ijkmp_start()
{
ffp_notify_msg1(ffplayer_, FFP_REQ_START);
}
- ijkmp_stop
先检测当前的状态是否可以执⾏stop,⽐如MP_STATE_IDLE状态就没有必要调⽤stop,删除队列⾥的FFP_REQ_START/PAUSE消息
调⽤FFPlayer的ffp_stop_l,先请求abort_request = 1,然后暂停输出toggle_pause
int IjkMediaPlayer::ijkmp_stop()
{
int retval = ffplayer_->ffp_stop_l();
if (retval < 0) {
return retval;
}
}