自学内容网 自学内容网

FFmpeg: 简易ijkplayer播放器实现--05ijkplayer–连接UI界面和ffplay.c

ijkplayer时序图

请添加图片描述
stream_open:
frame_queue_init
packet_queue_init
init_clock
创建read_thread线程
创建video_refresh_thread线程

消息循环–回调函数实现

ui 和播放器核心直接的交互有以下几种方式:

  1. ui直接调用IjkMediaPlayer的接口
  2. ui发送消息给消息循环线程,然后调⽤IjkMediaPlayer的接口
  3. 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;
    }
}

原文地址:https://blog.csdn.net/qq_43538607/article/details/137666283

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!