当前位置: 首页 > news >正文

FFmpeg: 自实现ijkplayer播放器--04消息队列设计

文章目录

      • 播放器状态转换图
        • 播放器状态对应的消息:
      • 消息对象
      • 消息队列
      • 消息队列api
        • 插入消息
        • 获取消息
        • 初始化消息
        • 插入消息加锁
        • 初始化消息
        • 设置消息参数
        • 消息队列初始化
        • 清空消息
        • 销毁消息
        • 启动消息队列
        • 终止消息队列
        • 删除消息

消息队列,用于发送,设置播放器的状态,实现ui界面,jikpalyer以及ffplay之间的通信

播放器状态转换图

实线箭头连接的状态变化通过 API 调⽤完成
虚线箭头连接的状态变化是通过 播放器内部执⾏完特定任务或者发⽣错误 ⽽⾃动发⽣的状态
变化
请添加图片描述

播放器状态对应的消息:
  • idle: MP_STATE_IDLE 闲置状态,刚完成构造的 FijkPlaye
  • initialized: MP_STATE_INITIALIZED 初始化完成状态,和 idle 状态相⽐,仅是多了输⼊媒体
    数据源的信息
  • async_preparing:MP_STATE_ASYNC_PREPARING 异步准备状态,进行打开媒体⽂件,打开解码器以及新建解码线程,新建数据 read 线程,打开⾳频输出设备,新建视频输出线程等
  • prepared:MP_STATE_PREPARED,完成指定任务后⾃动转化为此状态。此状态下已经缓冲并解码了⼀部分⾳视频数据,可以随时进⾏播放
  • started:MP_STATE_STARTED 媒体(视频、⾳频)正在播放中
  • paused:MP_STATE_PAUSED 媒体(视频、⾳频)播放暂停
  • completed:MP_STATE_COMPLETED 媒体(视频、⾳频)播放完成。 可重新从头开始播
    放。
  • stop: MP_STATE_STOPPED 播放器各种线程占⽤资源都已经释放。 ⾳频设备关闭
  • error: MP_STATE_ERROR 播放器出现错误

消息对象

typedef struct AVMessage {int what;           // 消息类型int arg1;           // 参数1int arg2;           // 参数2void *obj;          // 如果arg1 arg2还不够存储消息则使⽤该参数void (*free_l)(void *obj);  // 释放obj指向的函数struct AVMessage *next; // 下⼀个消息
} AVMessage;

消息队列

typedef struct MessageQueue {   // 消息队列AVMessage *first_msg, *last_msg;    // 消息头,消息尾部int nb_messages;    // 有多少个消息int abort_request;  // 请求终⽌消息队列SDL_mutex *mutex;   // 互斥量SDL_cond *cond;     // 条件变量AVMessage *recycle_msg; // 消息循环使⽤int recycle_count;  // 循环的次数,利⽤局部性原理int alloc_count;    // 分配的次数
} MessageQueue;

recycle_msg:
用于回收消息,消息使用链表进行存储,当消息取出时,通过recycle_msg链接该消息,重新用做新消息使用
作用:节省了对新消息申请空间,以及对取出的消息释放内存操作

消息队列api

插入消息
// 消息队列内部重新去构建 AVMessage(重新申请AVMessage,或者来自于recycle_msg)
// 新的消息插入到尾部
int msg_queue_put_private(MessageQueue *q, AVMessage *msg)
{AVMessage *msg1;if(q->abort_request)return -1;//1. 消息体使用回收的资源还是重新mallocmsg1 = q->recycle_msg;if(msg1) {q->recycle_msg = msg1->next;q->recycle_count++;} else {q->alloc_count++;msg1 = (AVMessage *)av_malloc(sizeof(AVMessage));}*msg1 = *msg;msg1->next = NULL;if(!q->first_msg) {q->first_msg = msg1;} else {q->last_msg->next = msg1;}q->last_msg = msg1;q->nb_messages++;SDL_CondSignal(q->cond);return 0;
}
获取消息
int msg_queue_get(MessageQueue *q, AVMessage *msg, int block)
{AVMessage *msg1;int ret;SDL_LockMutex(q->mutex);for(;;) {if(q->abort_request) {ret = -1;break;}//获取消息msg1 = q->first_msg;if(msg1) {q->first_msg = msg1->next;if(!q->first_msg)q->last_msg = NULL;q->nb_messages--;*msg = *msg1;msg1->obj = NULL;msg1->next = q->recycle_msg;q->recycle_msg = msg1;ret =1;break;      // 记得这里有个break的} else if (!block) {ret = 0;break;} else {SDL_CondWait(q->cond, q->mutex);}}SDL_UnlockMutex(q->mutex);return ret;
}
初始化消息
// 消息队列初始化
void msg_queue_init(MessageQueue *q)
{memset(q, 0, sizeof(MessageQueue));q->mutex = SDL_CreateMutex();q->cond = SDL_CreateCond();q->abort_request = 1;
}
插入消息加锁
int msg_queue_put(MessageQueue *q, AVMessage *msg)
{int ret;SDL_LockMutex(q->mutex);ret = msg_queue_put_private(q, msg);SDL_UnlockMutex(q->mutex);return ret;
}
初始化消息
void msg_init_msg(AVMessage *msg)
{memset(msg, 0, sizeof(AVMessage));
}
设置消息参数
void msg_queue_put_simple1(MessageQueue *q, int what)
{AVMessage msg;msg_init_msg(&msg);msg.what = what;msg_queue_put(q, &msg);
}// 释放msg的obj资源
void msg_obj_free_l(void *obj)
{av_free(obj);
}
//插入消息,带消息类型,带2个参数,带obj
void msg_queue_put_simple4(MessageQueue *q, int what, int arg1, int arg2, void *obj, int obj_len)
{AVMessage msg;msg_init_msg(&msg);msg.what = what;msg.arg1 = arg1;msg.arg2 = arg2;msg.obj = av_malloc(obj_len);memcpy(msg.obj, obj, obj_len);msg.free_l = msg_obj_free_l;msg_queue_put(q, &msg);
}
消息队列初始化
void msg_queue_init(MessageQueue *q)
{memset(q, 0, sizeof(MessageQueue));q->mutex = SDL_CreateMutex();q->cond = SDL_CreateCond();q->abort_request = 1;
}
清空消息
 // 消息队列flush,清空所有的消息
void msg_queue_flush(MessageQueue *q)
{AVMessage *msg, *msg1;SDL_LockMutex(q->mutex);for (msg = q->first_msg; msg != NULL; msg = msg1) { // 这个时候的obj没有清空?那会导致泄漏,实际是把消息对象暂存到了recycle_msgmsg1 = msg->next;msg->next = q->recycle_msg;q->recycle_msg = msg;}q->last_msg = NULL;q->first_msg = NULL;q->nb_messages = 0;SDL_UnlockMutex(q->mutex);}
销毁消息
void msg_queue_destroy(MessageQueue *q)
{msg_queue_flush(q);SDL_LockMutex(q->mutex);while(q->recycle_msg) {AVMessage *msg = q->recycle_msg;if (msg)q->recycle_msg = msg->next;msg_free_res(msg);av_freep(&msg);}SDL_UnlockMutex(q->mutex);SDL_DestroyMutex(q->mutex);SDL_DestroyCond(q->cond);
}
启动消息队列
void msg_queue_start(MessageQueue *q)
{SDL_LockMutex(q->mutex);q->abort_request = 0;// 插入一个消息AVMessage msg;msg_init_msg(&msg);msg.what = FFP_MSG_FLUSH;msg_queue_put_private(q, &msg);SDL_UnlockMutex(q->mutex);
}
终止消息队列
void msg_queue_abort(MessageQueue *q)
{SDL_LockMutex(q->mutex);q->abort_request = 1;SDL_CondSignal(q->cond);SDL_UnlockMutex(q->mutex);
}
删除消息
// 消息删除 把队列里同一消息类型的消息全删除掉
void msg_queue_remove(MessageQueue *q, int what)
{AVMessage **p_msg, *msg, *last_msg;SDL_LockMutex(q->mutex);last_msg = q->first_msg;if (!q->abort_request && q->first_msg) {p_msg = &q->first_msg;while (*p_msg) {msg = *p_msg;if (msg->what == what) {        // 同类型的消息全部删除*p_msg = msg->next;msg_free_res(msg);msg->next = q->recycle_msg;     // 消息体回收q->recycle_msg = msg;q->nb_messages--;} else {last_msg = msg;p_msg = &msg->next;}}if (q->first_msg) {q->last_msg = last_msg;} else {q->last_msg = NULL;}}SDL_UnlockMutex(q->mutex);
}

相关文章:

FFmpeg: 自实现ijkplayer播放器--04消息队列设计

文章目录 播放器状态转换图播放器状态对应的消息: 消息对象消息队列消息队列api插入消息获取消息初始化消息插入消息加锁初始化消息设置消息参数消息队列初始化清空消息销毁消息启动消息队列终止消息队列删除消息 消息队列,用于发送,设置播放…...

Redis中的集群(四)

集群 槽指派 CLUSTER ADDSLOTS命令的实现 CLUSTER ADDSLOTS命令接受一个或多个槽作为参数&#xff0c;并将所有输入的槽指派给接收该命令的节点负责: CLUSTER ADDSLOTS <slot> [slot ...]CLUSTER ADDSLOTS命令的实现可以用以下伪代码来表示: def CLUSTER_ADDSLOTS(*…...

JookDB下载安装使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

百度OCR身份证识别C++离线SDKV3.0 C#对接

百度OCR身份证识别C离线SDKV3.0 C#对接 目录 说明 效果 问题 项目 代码 下载 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 SDK 简介 本 SDK 适应于于 Windows 平台下的⾝份证识别系统,⽀持 C接⼜开发的 SDK,开发者可在VS2015 下⾯进⾏开发&#xff08;推荐…...

Web前端 Javascript笔记1

为什么学习 JavaScript? JavaScript 是 web 开发人员必须学习的 3 门语言中的一门&#xff1a; HTML 定义了网页的内容CSS 描述了网页的布局JavaScript 控制了网页的行为 JavaScript 是可插入 HTML 页面的编程代码。 JavaScript 插入 HTML 页面后&#xff0c;可由所有的现代浏…...

Git回滚版本并push到远端master

1、查看日志 git log 2、还原最近的版本 () --git reset --hard commit-id 如&#xff1a;git reset --hard d84da14bf2743683eca7a015f56114faaa344f42 3、覆盖分支版本 git push -f origin dev 回滚本地master完成后&#xff0c;将回滚后的代码push到远端master&#xf…...

MAC: 自己制作https的ssl证书(自己签发免费ssl证书)(OPENSSL生成SSL自签证书)

MAC: 自己制作https的ssl证书(自己签发免费ssl证书)(OPENSSL生成SSL自签证书) 前言 现在https大行其道, ssl又是必不可少的环节. 今天就教大家用开源工具openssl自己生成ssl证书的文件和私钥 环境 MAC电脑 openssl工具自行搜索安装 正文 1、终端执行命令 //生成rsa私钥&…...

mac配置Jmeter环境

mac配置Jmeter环境 一、安装jmeter二、Jmeter目录结构三、汉化Jmeter四、改变主题外观五、jmeter安装第三方插件六、jmeter基础入门案例 一、安装jmeter 第一步先自行配置好电脑的jdk环境 1、官网下载jar包 https://jmeter.apache.org/download_jmeter.cgi 2、解压到软件你自己…...

Linux虚拟化————KVM

1、安装kvm虚拟化套件 [rootbogon ~]# yum -y install virt* 2、启动服务 [rootbogon ~]# systemctl start libvirtd [rootbogon ~]# systemctl status libvirtd ● libvirtd.service - Virtualization daemonLoaded: loaded (/usr/lib/systemd/system/libvirtd.service; di…...

【b站李同学的Lee】Part 2 模块化开发 NodeJS+Gulp基础入门+实战

课程地址&#xff1a;【NodeJSGulp基础入门实战】 https://www.bilibili.com/video/BV1aE411n737/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 4 Node.js模块化开发 4.1 JavaScript开发弊端 4.1.1 文件依赖 4.1.2 命名冲突 4.2 生活中的…...

AI大模型日报#0415:贾佳亚团队新作王炸、马斯克首款多模态大模型、ChatGPT to B

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 融合ChatGPTDALLE3&#xff0c;贾佳亚团队新作开源&#xff1a;识图推理生图一站解决 摘要: 贾佳亚团队推出了多模态模型Mini-Gem…...

基于GRU实现评论文本情感分析

一、问题建模 在线评论的细粒度情感分析对于深刻理解商家和用户、挖掘用户情感等方面有至关重要的价值&#xff0c;并且在互联网行业有极其广泛的应用&#xff0c;主要用于个性化推荐、智能搜索、产品反馈、业务安全等。此博文&#xff0c;共包含6大类20个细粒度要素的情感倾…...

【C 数据结构】线性表

文章目录 【 1. 线性表 】【 2. 顺序存储结构、链式存储结构 】【 3. 前驱、后继 】 【 1. 线性表 】 线性表&#xff0c;全名为线性存储结构&#xff0c;线性表结构存储的数据往往是可以依次排列的&#xff08;不考虑数值大小顺序&#xff09;。 例如&#xff0c;存储类似 {1…...

C++初级----list(STL)

1、 list介绍 1.1、 list介绍 1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 1. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向 其前一…...

web安全学习笔记(9)

记一下第十三课的内容。 准备工作&#xff1a;在根目录下创建template目录&#xff0c;将login.html放入其中&#xff0c;在该目录下新建一个reg.html。在根目录下创建一个function.php 一、函数声明与传参 PHP中的函数定义和其他语言基本上是相同的。我们编辑function.php …...

【Python-基础】字符串合集

字符串格式化 f # 例如: # f{train_path}/{f}: 将train_path字符串和f字符串结合 # f{root}.csv:将root字符串和.csv字符串结合判断字符串是否以…结尾 root.endswith(".csv") # True未待完续…...

Scala之List

列表 不可变列表(List) 在Scala中&#xff0c;通过List来定义不可变列表&#xff0c;需要注意的是&#xff0c;List本身是一个抽象类&#xff0c;所以并不能直接使用List来构建对象&#xff0c;需要使用它的伴生对象来构建 package com.fesco.listimport scala.::object ListD…...

Springboot+Vue项目-基于Java+MySQL的在线视频教育平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…...

Java IO流-字节流

简介 IO流的输入与输出&#xff0c;都在站在内存的角度来看的&#xff0c;因为毕竟是和内促你打交道的嘛&#xff01; 分类 IO流是可以根据方向&#xff0c;或者最小单位进行划分的 上述两两结合一下&#xff0c;就得到四种大的分类 IO流的继承体系 字节输入流InputStream 创建…...

第十五届蓝桥杯复盘python大学A组——试题B 召唤数学精灵

按照正常思路解决&#xff0c;由于累乘消耗大量时间&#xff0c;因此这不是一个明智的解决方案。 这段代码执行速度非常慢的原因在于它试图计算非常大的数的阶乘&#xff08;累乘&#xff09;&#xff0c;并且对于每一个i的值都执行这个计算。阶乘的增长是极其迅速的&#xff…...

如何选择适合的单北斗变形监测一体机以提升基础设施安全?

本文将重点讨论如何选择适合的单北斗变形监测一体机&#xff0c;以增强基础设施的安全性。在当前基础设施建设快速发展的背景下&#xff0c;单北斗GNSS的应用显得尤为重要。通过深入理解单北斗变形监测的原理&#xff0c;用户能够更好地把握设备的核心优势&#xff0c;尤其是在…...

tkinter表格神器tkintertable实战:5分钟搞定可拖拽编辑的数据表格(附完整代码)

tkinter表格神器tkintertable实战&#xff1a;5分钟搞定可拖拽编辑的数据表格&#xff08;附完整代码&#xff09; 在Python GUI开发中&#xff0c;表格控件一直是刚需但实现起来又颇为棘手的组件。传统tkinter自带的Treeview虽然能勉强实现表格功能&#xff0c;但在交互体验上…...

ms-swift微调框架入门:快速掌握LoRA微调与模型合并技巧

ms-swift微调框架入门&#xff1a;快速掌握LoRA微调与模型合并技巧 1. 引言 在当今大模型技术快速发展的背景下&#xff0c;如何高效地对大型语言模型进行微调成为了许多开发者和研究者的关注焦点。ms-swift作为一款强大的微调框架&#xff0c;提供了丰富的功能和技术支持&am…...

文明降级运动:回归纸笔抵抗AI监控

在AI技术席卷软件测试领域的浪潮中&#xff0c;一个看似“倒退”却极具战略意义的趋势正在兴起——文明降级运动。这场运动的核心是主动回归纸笔工具&#xff0c;以抵抗AI监控带来的系统性风险。作为软件测试从业者&#xff0c;我们身处技术前沿&#xff0c;见证了AI在缺陷预测…...

Linux下RTL8188无线网卡变身AP热点:从驱动安装到自动分配IP全流程(附避坑指南)

Linux下RTL8188无线网卡配置AP热点全攻略&#xff1a;从驱动到自动IP分配的实战指南 在嵌入式开发和物联网应用中&#xff0c;将无线网卡配置为接入点&#xff08;AP&#xff09;是常见需求。RTL8188系列USB无线网卡因其高性价比和广泛兼容性&#xff0c;成为开发者的热门选择。…...

从.bib到.bbl:手把手教你搞定LaTeX参考文献的完整流程

从.bib到.bbl&#xff1a;手把手教你搞定LaTeX参考文献的完整流程 如果你曾被LaTeX的参考文献格式折磨得焦头烂额&#xff0c;这篇文章就是为你准备的。我们将从零开始&#xff0c;完整走一遍从文献管理到最终PDF生成的每个步骤&#xff0c;特别关注那些让新手困惑的.bib、.bbl…...

寻音捉影·侠客行多场景落地:覆盖会议/媒体/司法/金融/教育五大垂直领域

寻音捉影侠客行多场景落地&#xff1a;覆盖会议/媒体/司法/金融/教育五大垂直领域 1. 产品核心功能解析 寻音捉影侠客行是一款基于先进语音识别技术的音频关键词检索工具&#xff0c;它能够像江湖中的隐士高手一样&#xff0c;在浩瀚的音频海洋中精准定位特定关键词。这款工具…...

科研加速器:GLM-4.7-Flash驱动OpenClaw自动整理文献综述

科研加速器&#xff1a;GLM-4.7-Flash驱动OpenClaw自动整理文献综述 1. 为什么需要自动化文献整理 作为每天需要阅读十几篇论文的科研工作者&#xff0c;我发现自己至少有30%的时间花在了机械性劳动上——下载PDF、重命名文件、提取关键结论、整理参考文献格式。这些工作虽然…...

实战LangGraph构建智能客服系统:在快马平台实现工单自动分类与处理全流程

今天想和大家分享一个用LangGraph构建智能客服系统的实战经验。这个项目主要解决工单自动分类和处理的问题&#xff0c;整个过程在InsCode(快马)平台上完成&#xff0c;从开发到部署一气呵成。 项目背景与需求分析 传统客服系统需要人工处理大量工单&#xff0c;效率低下且容易…...

快马平台快速原型:十分钟用AI生成你的第一个龙虾养殖系统Docker部署方案

最近在研究如何用Docker快速搭建一个龙虾养殖模拟系统&#xff0c;发现用InsCode(快马)平台可以大大简化这个过程。作为一个快速原型验证工具&#xff0c;它让我在十分钟内就完成了从构思到部署的全流程。下面分享下我的实践心得&#xff1a; 项目构思阶段 这个模拟系统需要展示…...