万事娱乐注册 万事娱乐登录 万事娱乐招商QQ

Navigation menu

来源:未知 责任编辑:admin

万 事 娱 乐 平 台 登 陆 (今日更新知乎) - 的个人空间 - OSCHINA

  FFmpeg 框架由命令行工具和函数库组成, ffplay 是其中的一种命令行工具,提供了播放音视频文件的功能,不仅可以播放本地多媒体文件,还可以播放网络流媒体文件。本文从 ffplay 的整体播放流程出发,借鉴其设计思路,学习如何设计一款简易的播放器。

  在学习 ffplay 源码之前,为了方便理解,我们先宏观了解一下播放器在播放媒体文件时的工作流程。

  解协议:媒体文件在网络上传输时,需要经过流媒体协议将媒体数据分段成若干个数据包,这样就可以满足用户一边下载一边观看的需求,而不需要等整个媒体文件都下载完成才能观看。常见的流媒体协议有 RTMP、HTTP、HLS、MPEG-DASH、MSS、HDS 等。由于流媒体协议中不仅仅包含媒体数据,还包含控制播放的信令数据。因此,解协议是移除协议中的信令数据,输出音视频封装格式数据。

  解封装:封装格式也叫容器,就是将已经编码压缩好的视频流和音频流按照一定的格式放到一个文件中,常见的封装格式有 MP4、FLV、MPEG2-TS、AVI、MKV、MOV 等。解封装是将封装格式数据中的音频流压缩编码数据和视频流压缩编码数据分离,方便在解码阶段使用不同的解码器解码。

  解码:压缩编码数据是在原始数据基础上采用不同的编码压缩得到的数据,而解码阶段就是编码的逆向操作。常见的视频压缩编码标准有 H.264/H.265 、MPEG-2 、AV1 、V8/9 等,音频压缩编码标准有 AAC 、MP3 等。解压后得到的视频图像数据是 YUV 或 RGB ,音频采样数据是 PCM 。

  音视频同步:解码后的视频数据和音频数据是独立的,在送给显卡和声卡播放前,需要将视频和音频同步,避免播放进度不一致。

  parse_loglevel:解析 log 的级别,会匹配命令中的-loglevel字段。如果命令中添加-report,会将播放日志输出成文件。

  SDL_Init:初始化 SDL 库,传入的参数 flags,默认支持视频、音频和定时器,如果命令中配置了-an则禁用音频,配置了-vn则禁用视频。

  SDL_CreateWindow:创建播放视频的窗口,该函数可以指定窗口的位置、大小,默认是 640*480 大小。

  SDL_CreateRenderer:为指定的窗口创建渲染器上下文,对应的结构体是 SDL_Render 。我们既可以使用渲染器创建纹理,也可以渲染视图。

  stream_open函数是 ffplay 开始播放流程的起点,该函数传入两个参数,分别是文件名input_filename和文件格式file_iformat。下面是函数内部的处理流程:

  (1) 初始化VideoState:VideoState 是 ffplay 中最大的结构体,所有的视频信息都定义在其中。初始化 VideoState 时,先定义 VideoState 结构体指针类型的局部变量is,分配堆内存。然后初始化结构体中的变量,例如视频流、音频流、字幕流的索引,并赋值函数入参 filename 和 iformat。

  (2)初始化FrameQueue:FrameQueue 是解码后的 Frame 队列, Frame 是解码后的数据,例如视频解码后是 YUV 或 RGB 数据,音频解码后是 PCM 数据。初始化 FrameQueue 时,会对 VideoState 中的 pictq(视频帧队列)、subpq(字幕帧队列)、sampq(音频帧队列)依次调用frame_queue_init函数进行初始化。FrameQueue 内部是通过数组实现了一个先进先出的环形缓冲区,windex 是写指针,被解码线程使用;rindex 是读指针,被播放线程使用。使用环形缓冲区的好处是,缓冲区内的元素被移除后,其它元素不需要移动位置,适用于事先知道缓冲区最大容量的场景。

  (3)初始化PacketQueue:PacketQueue 是解码前的 Packet 队列,用于保存解封装后的数据。初始化 PacketQueue 时,会对 VideoState 中的 videoq(视频包队列)、audio(音频包队列)、subtitleq(字幕包队列)依次调用packet_queue_init函数进行初始化。不同于 FrameQueue , PacketQueue 采用链表的方式实现队列。由于解码前的包大小不可控,无法明确缓冲区的最大容量,如果使用环形缓冲区,容易触发缓冲区扩容,需要移动缓冲区内的数据。因此,使用链表实现队列更加合适。

  (4)初始化Clock:Clock 是时钟,在音视频同步阶段,有三种同步方法:视频同步到音频,音频同步到视频,以及音频和视频同步到外部时钟。初始化 Clock 时,会对 VideoState 中的 vidclk(视频时钟)、audclk(音频时钟)、extclk(外部时钟)依次调用init_clock函数进行初始化。

  (5)限制音量范围:先限制音量范围在 0~100 之间,然后再根据 SDL 的音量范围作进一步限制。

  (7)创建读线程:调用SDL_CreateThread创建读线程,同时设置了线程创建成功的回调read_thread函数以及接收参数is( stream_open 函数最开始创建的 VideoState 指针类型的局部变量)。如果线程创建失败,则调用stream_close做销毁逻辑。

  (8)返回值:将局部变量is作为函数返回值返回,用于处理下面的各种 SDL 事件。

  event_loop函数内部是一个 for 循环,使用 SDL 监听用户的键盘按键事件、鼠标点击事件、窗口事件、退出事件等。

  read_thread函数的作用是从磁盘或者网络中获取流,包括音频流、视频流和字幕流,然后根据可用性创建对应流的解码线程。因此read_thread所在的线程实际上起到了解协议/解封装的作用。核心处理流程可以分为以下步骤:

  RuleGo v0.13.0 正式发布:Go 轻量级、高性能、嵌入式、编排式的规则引擎

  JumpServer 堡垒机 v3.6.0 发布,支持批量连接资产、账号密钥支持使用第三方密钥存储系统

  COSCLC 社区畅聊第八期: 1 周岁发布 MVP 版本,凹语言有话说!

  PicList V2.5.0 云存储-图床管理和图片上传工具,大版本更新发布

  Countly 23.06.9 发布,实时移动和 Web 分析报告平台

  Salesforce 领投 Hugging Face 新一轮融资,预计筹集 2 亿美元

  OpenAI 为 GPT-3.5 Turbo 推出微调功能 (fine-tuning)

  WPS Office 远程代码执行漏洞(WPSSRC-2023-0701绕过)

  【我和openGauss的故事】第六届openGauss技术文章征集活动来啦!

  CloudWeGo - Sonic 入选北大研究生课程,开启校企合作新篇章

  【我和openGauss的故事】openGauss预安装gs_preinstall代码学习

  【我和openGauss的故事】 openGauss 5.0.0 事务相关语法

  10 亿月活用户下,快手基于 Dragonfly 的超大规模镜像分发实践

  Solon2 常用注解之 @Component 与 @ProxyComponent 的区别

  【我与openGauss的故事】openGauss 5.0企业版主从部署,实战狂飙

  预告 Cocos CEO 林顺受邀出席吉利 2023 智能汽车技术论坛

  HarmonyOS 极客马拉松2023 正式启动,诚邀极客们用键盘码出无限可能!

  Timnit Gebru 谈到她被谷歌解雇、人工智能的危险和大型科技公司的偏见

  统一观测丨使用 Prometheus 监控云原生网关,我们该关注哪些指标?

  【我和openGauss的故事】openGauss 5.0.0 资源管控功能介绍

  看了下今晚微信备案文档,和域名备案需要的东西差不多吧,,不过这种方式,真的可以有效在 的阻止一些假冒 诈骗应用吗?另外在网站的打击力度方面呢?

  这下der了,APP,不备案,就不能联网,不联网就不能调试和开发,不调试和开发就不能备案,死循环了

  美国人在80/90年代搞的UNIX SystemV现在看起来就是笑话,没办法实现完全二进制兼容,还创新停滞

  一句话,信创国产化,有一天gson作者说看不惯你们收腹tw,最新版本给你迭代个中国用了就出bug

  很久以前,用vba在excel里给客户写程序。当时有python就好了

  虽然有点想象过激,但是个人就是国产必须支持才能崛起,作者大佬开源不容易,辛苦

  一项备案就是一项权力,把权力搞得多多的,把责任推的少少的.真要干点实事好好整治侵犯隐私的APP吧,别掐个人开发者的脖子,就会少被别人掐脖子

  这你就不懂了(dogee),反正我按照你的方法做了,至于好不好用,又不是我的责任