stream_open函数分析

news2024/11/16 19:27:20

在讲 stream_open() 函数之前,需要先了解 stream_open() 里面使用到的一些基本的数据结构。如下:

第一个数据结构是 struct VideoState ,VideoState 可以说是播放器的全局管理器。字段非常多,时钟,队列,解码器,各种状态 都放在 VideoState 里面。

但是本文不会把 VideoState 的所有字段都讲一遍,只会讲 stream_open() 函数用到的字段,如下是精简过的字段,顺序也经过调整,方便阅读。:

typedef struct VideoState {
    int last_video_stream, last_audio_stream, last_subtitle_stream;
    char* filename;
    AVInputFormat* iformat;
    int width, height, xleft, ytop;
    FrameQueue pictq;
    FrameQueue sampq;
    PacketQueue videoq;
    PacketQueue audioq;
    SDL_cond *continue_read_thread;
    SDL_Thread *read_tid;
    Clock audclk;
    Clock vidclk;
    Clock extclk;    
    int audio_clock_serial;
    int audio_volume;
    int muted;
    int av_sync_type;
} VideoState;

1,int last_video_stream 代表最后一个视频流,如果你的音视频文件 里面有多个视频流,last_video_stream 就代表最后一个视频流。另外两个 last_audio_streamlast_subtitle_stream 一样代表最后一个。

2,char* filename 存储的是打开的 音视频文件名,或者是网络地址url。

3,AVInputFormat* iformat,容器格式,ffplay 默认是根据 filename 的后缀来确定容器格式,但是你也可以指定按某种容器格式来解析文件。命令如下:

ffplay -i juren-5s.mp4 -f flv

通过命令行参数指定的 -f flv 就会被存储到 AVInputFormat* iformat,当然不是存的字符,有一个根据字符串找到 AVInputFormat 的过程。

4,int width, height, xleft, ytop;,分别代表播放器窗口的 宽高 跟 位置。位置通过 xleft 跟 ytop 来定位的。

5,FrameQueue pictq, FrameQueue sampq,视频跟音频的 AVFrame 队列。

6,PacketQueue videoqPacketQueue audioq,视频跟音频的 AVPacket 队列。

7,SDL_cond *continue_read_thread,这是一个 SDL 的条件变量,用于线程间通信的。read_thread() 线程在以下两种情况会进入休眠 10ms。

第一种情况PacketQueue 队列满了,无法再塞数据进去。

第二种情况:超过最小缓存size。

如果在 10ms 内,PacketQueue 队列全部被消耗完毕,audio_thread() 或者 video_thread() 线程 没有 AVPakcet 能读了,就需要尽快唤醒 read_thread() 线程。

还有,如果进行了 seek 操作,也需要快速把 read_thread() 线程 从休眠中唤醒。

所以 SDL_cond *continue_read_thread 条件变量,主要用于 read_thread 跟 audio_thread ,video_thread 线程进行通信的。

8,SDL_Thread *read_tid;read_thread 的线程ID。

C++14 标准库有跨平台的线程库,但是 C语言 是没有跨平台的线程库,所以 ffplay 取巧了,使用了 SDL 库的线程跟条件变量,SDL 是跨平台的。

9,Clock audclk;,音频时钟,记录音频流的目前的播放时刻 。

10,Clock vidclk;,视频时钟,记录视频流的目前的播放时刻 。

11,Clock extclk;,外部时钟,取第一帧 音频 或 视频的 pts 作为 起始时间,然后随着物理时间的消逝增长,所以是物理时间的当前时刻。到底是以音频的第一帧,还是视频的第一帧?取决于 av_read_frame() 函数第一次读到的是音频还是视频。

12,int audio_clock_serial;,这个字段比较独特,只有音频有,视频没有,没有一个 video_clock_serial 字段。

audio_clock_serial 只是一个用做临时用途的变量,实际上存储的就是 AVFrame 的 serial 字段。不用特别关注。而视频直接用的 AVFrame 的 serial

13,int audio_volume,播放器的声音大小。

14,int muted,是否静音,C语言C99标准是没有 bool 类型的,都用 int 代替。

15,int av_sync_type,音视频同步方式,有 3 种同步方式,以音频时钟为准,以视频时钟为准,以外部时钟为准。默认方式是以音频时钟为准。


上面的数据结构,有一些字段我会说得比较简洁,因为现在只需你对这些字段有个简单的了解,后面文章会具体详细用到这些字段的场景。

由于 FrameQueue 跟 PacketQueue 这两个数据结构非常重要,所以放一整图片方便理解。

FrameQueue 里面的 queue 是一个数组,16 在代码里是一个宏,那个宏通常等于 16。PacketQueue 里面的 pkt_list 是一个 AVFifoBuffer,推荐阅读《FifoBuffer函数库详解》。

FrameQueue 跟 PakcetQueue 是通过一个 pktq 指针来关联的。这两个队列都有自己的 锁 mutex 跟 条件变量 cond。操作这两个队列都需要加锁操作的。


下面开始分析 stream_open() 函数,流程图,代码如下:

从上面的图可以看出来, stream_open() 函数的内部实现非常的简单。无非就是 初始化 队列,初始化时钟,然后创建一个 read_thread() 线程去跑。

其中 frame_queue_init() 的内部实现也比较简单,不过有几个重点,如下:

 这个 !! 操作没有什么特别,实际上就是把大于 1 的数字转成 1。如果 keep_last 等于 5,取反两次之后,就会变成 1 了。keep_last字段的作用 请看《FFplay的keep_last分析》。


packet_queue_init() 函数里面也有一句代码需要注意。

q->abort_request = 1;

abort_request 字段如果置为 1, audio_thread() 跟 video_thread() 解码线程就会退出。所以在创建解码线程 之前,ffplay 会把 abort_request 置为 0 ,如下:


至此,stream_open() 函数已经讲解完毕,现在逻辑流程已经流转到新的线程 read_thread() 函数里面了,下面文章继续分析 read_thread() 函数的内部原理。


推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:

Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 11 的状态栏的隐藏

概述 Android 11 的状态栏与导航栏较之前的版本有较大的差异, 在Android 7.0 SystemUI 状态/导航栏的隐藏与显示中所描述的部分内容已不再适用. 比如, 自动隐藏的时间, 隐藏的动画, 较之前的版本已面目全非, 本文将对隐藏状态栏部分的内容进行一些补充. APP如何隐藏状态栏 参…

Yield Guild Games 成功举办首届 SubDAO 峰会

Yield Guild Games(YGG)于 2022 年 11 月 18 日在菲律宾马尼拉举行了第一届 SubDAO 峰会。 SubDAO 峰会与菲律宾 Web3 狂欢节两个活动同时举行,为 YGG 的区域 SubDAO 提供了在 Web3 应用中心——菲律宾进行面对面交流的机会。此次活动旨在传达…

运维开发实践 - helm

1. helm介绍 helm 是一个用于管理部署在kubernetes上的应用的工具 使用要求:一个Kubernetes集群 2.下载安装 Helm Github Download Helm Huawei Source 按照自己的操作系统版本下载相应的helm压缩包 并将helm添加到环境变量中; # 检查是否安装成功 helm version…

read_thread解复用线程分析

read_thread() 线程的主要作用从 MP4 里面读取 AVPacket,然后丢进去 PacketQueue 队列。所以需要先学习一下 strcut PacketQueue 跟 struct MyAVPacketList 数据结构。如下: typedef struct MyAVPacketList {AVPacket *pkt;int serial; } MyAVPacketLis…

html文件里怎么引用vue组件?

这里我们使用 http-vue-loader 来实现&#xff1a;https://www.npmjs.com/package/http-vue-loader Load .vue files directly from your html/js. No node.js environment, no build step. 我做了个demo如下&#xff1a; html文件里面写下面的代码 <!DOCTYPE html> &l…

计算机研究生就业方向之当老师(中小学)

我一直跟学生们说你考计算机的研究生之前一定要想好你想干什么&#xff0c;如果你只是转码&#xff0c;那么你不一定要考研&#xff0c;至少以下几个职位研究生是没有啥优势的&#xff1a; 1&#xff0c;软件测试工程师&#xff08;培训一下就行&#xff09; 2&#xff0c;前…

股票购买接口系统怎么使用vn.py进行量化策略?

一般情况下&#xff0c;股票购买接口系统主要是可以运用在股票量化交易系统开发的一个大方向&#xff0c;也就是说&#xff0c;股票购买接口系统是根据这些量化的特点来开发的&#xff0c;就比如使用vn.py进行量化策略&#xff0c;在这方面&#xff0c;对交易者进行量化分析也起…

Web前端105天-day-41-JSCORE

JSCORE01 目录 前言 一、声明提升 二、宿主 window 三、断点功能 四、匿名函数解决全局污染 五、作用域链 六、闭包 七、私有 八、arguments 九、函数重载 十、方括号属性语法 十一、重载练习 十二、this 总结 前言 JSCORE01学习开始 一、声明提升 报错方案: 让…

走进SpringCloud微服务

微服务概述一、注册中心&#xff1a;Eureka ⭐⭐⭐1.1 原理1.2 代码二、负载均衡&#xff1a;Ribbon ⭐三、远程调用&#xff1a;Feigh ⭐⭐⭐3.1 原理3.2 代码四、熔断限流&#xff1a;Hystrix ⭐⭐⭐4.1线程池策略4.2 信号量隔离策略4.3 方法降级4.4 断路器、熔断器五、网关&…

MongoDB和MongoTemplate对于嵌套数据的判空查询

前言&#xff1a; 不知道有没有和小名一样&#xff0c;接触MongDB时间不长的小伙伴。由于MongoDB是以文档形式存储数据的&#xff0c;所以其中的数据类型相对MySql或者Oracle关系型数据库丰富一些&#xff08;MongoDB是NoSQL数据库这里比较不是很准确&#xff09; 我们在关系…

Dropout方法原理和使用方法

来源&#xff1a;投稿 作者&#xff1a;梦飞翔 编辑&#xff1a;学姐 为什么提出这种方法&#xff1f; 神经网络在训练过程中&#xff0c;由于正负样本不均衡、样本特征显著性不足、训练参数不合适等原因会导致发生过拟合现象&#xff0c;即模型参数陷入局部最优&#xff0c;仅…

QT6操作连接mysql数据库方法_增删改查

QT6操作mysql方法_增删改查 mysql数据库搭建相关方法&#xff1a; MySQL - 随笔分类 - txwtech - 博客园https://www.cnblogs.com/txwtech/category/1973054.htmlMySQL解压版配置方法 MySQL解压版配置方法 - txwtech - 博客园1.下载 https://downloads.mysql.com/archives/co…

【知识学习】C++QT配置opencv遇到的坑

最近要搞图像&#xff0c;老师说尽量用C&#xff0c;就开始研究配置opencv 当然&#xff0c;说在前面&#xff0c;C的比python的要麻烦特别多&#xff0c;所以如果不是必要的话&#xff0c;建议用python pip配opencv吧 C麻烦就在于要自己在本地编译一遍才能跑&#xff0c;直接…

如何将亚马逊Seller Central 用到极致~

不论是新手卖家还是有经验的老手&#xff0c;亚马逊卖家中心都是一个可以帮助卖家发展业务的好工具&#xff0c;对于许多新手小白来说&#xff0c;亚马逊这样巨大的平台仍有许多功能与服务等着挖掘。 什么是亚马逊卖家中心&#xff1f; 亚马逊卖家中心是第三方卖家用来管理和…

微信支付-全面详解(学习总结---从入门到深化)

微信支付_产品介绍 微信支付介绍 微信支付&#xff08;https://pay.weixin.qq.com&#xff09;是腾讯集团旗下中国领先 的第三方支付平台&#xff0c;一直致力于为用户和企业提供安全、便捷、专业的在线支付服务。 付款码支付 付款码支付是指用户展示微信钱包内的“付款码”给商…

指纹浏览器是什么?可以用来解决网络爬虫的什么问题?

在大数据时代的今天&#xff0c;各行各业的许多企业多多少少都会因为涉及到海外市场需要收集大量的市场信息&#xff0c;特别是对于跨境电商领域的商家来说&#xff0c;网络爬虫是必不可少的。因此&#xff0c;一定有很多从业者接触过网络爬虫&#xff0c;但对于刚打算进入这个…

ADI Blackfin DSP处理器-BF533的开发详解36:图像处理专题-RGB888 转 RGB565(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 作为一个最高600M主频&#xff0c;单核或双核的定点DSP&#xff0c;做图像处理还是挺行的&#xff0c;属于是老本行&#xff0c;那么我…

广州蓝景分享—HTML+CSS功能,让页面加载速度提高数倍

Hello&#xff0c;各位小伙伴&#xff0c;今天跟大家分享前端技术干货&#xff0c;页面加载速度问题。 首先我们都讨厌加载缓慢的页面&#xff01; 要知道加载时间每增加1秒&#xff08;0-5秒之间&#xff09;&#xff0c;网站转化率就会平均下降4.42%。页面加载时间的前五秒…

linux 虚拟机nat模式网络配置

文章目录1. linux 版本&#xff1a;2. 下载地址 Index of /centos-store/7.6.1810/isos/x86_64/ (liu.se)3. 账号密码&#xff1a;root root4.选择nat 模式&#xff0c;勾选 将主机虚拟适配器连接到此网络&#xff0c;勾选 使用本地DHCP服务将iP地址分配给虚拟机5.点击Nat 设置…

数据仓库分享

前言 数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所有类型数据支持的战略集合。它出于分析性报告和决策支持的目的而创建的。 数据仓库是一个数据集合 数据仓库是一个为业务决策提供数据支持的数据集合 数据仓库是通过监控业务流程的形式为业务决策提…