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

本文主要是介绍FFmpeg: 简易ijkplayer播放器实现--05ijkplayer–连接UI界面和ffplay.c,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • ijkplayer时序图
      • 消息循环--回调函数实现
      • 播放器播放时状态转换
        • 播放
        • 停止
      • ijkmediaPlay
        • 成员变量
        • 成员函数

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 设置urlmp_->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;//字符串,就是一个播放urlchar *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);// 调用ffplayerint 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;}
}

这篇关于FFmpeg: 简易ijkplayer播放器实现--05ijkplayer–连接UI界面和ffplay.c的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/899723

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义