目录

🌈前言🌈    

📁 整体架构 + 详细流程

📁 数据流向​

📁 队列设计​编辑

📁 线程设计

 📁 音视频同步

📁 音频输出设计

📁 视频输出设计

📁 总结


🌈前言🌈    

        这篇文章是我在学习FFmpeg时,看到一位UP主的开源项目。我认为还是比较好认,通过和这个项目可以快速入门FFmpeg 7。

        因为种种原因,目前网上关于FFmpeg 7.x 版本相关介绍太少,并且相较于之前版本,接口有很大变化,学习途中可能有很大困恼。因此,我希望通过这个项目和我的理解,带大家快速入门FFmpeg以及7版本以上的接口使用流程。

        这篇文章的图片和源码均来自B站UP主:程序员老廖音视频入门必备项目-最新FFmpeg7.1播放器开发_哔哩哔哩_bilibili。

        我也将该项目做了一遍,并且将源码上传至Gitee,大家可以直接进行下载。

AVPlayer: 本地音乐播放器(FFmpeg + SDL)

📁 整体架构 + 详细流程

1. 初始化:创建并初始化必要的队列、线程和组件。

2. 媒体处理:

        i. 解复用线程从文件读取数据包。

       ii. 解码线程将数据包解码为帧。

      iii. 音视频输出模块将帧渲染输出。

3. 用户交互: 处理用户事件,如暂停、退出等。

4.  资源释放: 程序结束时按照正确的顺序释放资源,避免内存泄露

📁 数据流向

1. 解复用阶段:
        DemuxThread读取媒体文件
        分离音视频数据包
        将音视频包放入对应的AVPacketQueue
2. 解码阶段:
        DecodeThread从AVPacketQueue获取数据包
        使用FFmpeg解码器解码数据包
        生成音视频帧并放入AVFrameQueue
3. 渲染阶段:
        AudioOutput/VideoOutput从AVFrameQueue获取帧
        处理帧数据(重采样、格式转换等)
        通过SDL渲染到输出设备

📁 队列设计

1. 模板设计:使用C++模板实现通用队列结构,提高代码复用率

2. 线程安全:使用互斥锁和条件变量保证多线程环境下的数据一致性

3. 特化实现:为AVPacket和AVFrame提供特化队列,处理FFmpeg资源的引用计数

4. 终止机制:通过abort标志控制队列终止,实现优雅退出

5. 资源管理:

        AVPacketQueue负责管理AVPacket资源,使用av_packet_free释放
        AVFrameQueue负责管理AVFrame资源,使用av_frame_free释放

        在Queue中加锁解锁的操作会用到两个管理类 (当然可以都使用第二个):

std::lock_guard (简单锁): 
        1. 轻量级, 性能更高, 无额外开销
        2. 严格作用域锁: 不能手动控制
        3. 不可转移所有权
        4. 不支持条件变量

std::unique_lock (灵活锁):
        1. 功能更强大, 有额外的状态存储
        2. 支持手动的加锁解锁
        3. 支持所有权转移
        4. 支持条件变量

📁 线程设计

1. 基类封装:Thread基类封装线程创建,启动和停止的通用逻辑

2. 虚函数机制:通过纯虚函数Run要求派生类实现具体的业务逻辑

3. 状态控制:使用abort控制线程循环状态,实现退出

4. 资源管理:

        DemuxThread管理文件读取和格式解析资源(AVFormatContext)
        DecodeThread管理解码器资源(AVCodecContext)

5. 线程协作

        通过队列实现线程间数据传递,解耦生产者和消费者

 📁 音视频同步

1. 主时钟选择:
        i. 使用音频PTS作为主时钟基准
       ii. 音频在回调函数中更新时钟值
2. 视频同步策略:
        i. 计算视频帧PTS与当前音频时钟的差值
       ii. 差值为正(视频超前):延迟显示
      iii. 差值为负(视频滞后):立即显示
     iiii. 差值过大:考虑跳帧或重复帧

3. 时钟管理:
        i. AVSync类提供时钟读写接口
       ii. 音频线程设置时钟
      iii. 视频线程读取时钟

        AVSync中记录一个动态变差值,可以简单理解为记录音频的pts。

为什么不能直接保存音频的pts呢?

  1. pts只在音频回调时更新​​,而视频可能在任意时刻查询 GetClock()

    • 如果音频回调间隔是 10ms,而视频在两次回调之间查询 GetClock(),它拿到的 pts是 ​​过时的​​(没有考虑这期间的时间流逝)。

    • ​结果​​:视频计算的时间偏差不准确,导致音画不同步。

  2. ​无法处理音频播放速度变化​​(如加速、卡顿)。

    • 如果音频因缓冲不足而卡顿,pts更新变慢,但系统时间仍在流逝。

    • 直接返回 _current_audio_pts无法反映这种延迟。

📁 音频输出设计

        声音输出模块负责从帧队列取出音频帧,进行必要的重采样,并通过SDL输出音频。

1. 初始化流程:

        i. 初始化SDL音频播放子系统

       ii. 设置音频参数

      iii. 设置音频回调函数

     iiii. 创建重采样上下文(如果需要)

2. 回调机制:

        i. SDL音频系统在需要数据时调用设置的回调函数

       ii. 回调函数从帧队列获取音频帧

      iii. 根据需要进行重采样 (使用SwrContext)

     iiii. 将处理后的音频数据填充到SDL提供的缓冲区

3. 音频时钟:

        i. 以音频PTS为主时钟

       ii. 在每次回调中更新音频时钟

      iii. 作为视频同步的基准

4. 资源管理:

        i. 管理重采样上下文(SwrContext)

       ii. 管理音频缓冲区

      iii. 在Delnit和析构函数中释放资源

        AVRational 是 FFmpeg 中用于表示 ​​分数(有理数)​​ 的结构体,主要用于时间基(time base)、帧率(frame rate)、采样率(sample rate)等场景

📁 视频输出设计

        画面输出模块负责从帧队列获取视频帧,与音频同步,并通过SDL渲染到屏幕

1. 初始化流程:
        初始化SDL视频子系统
        创建窗口和渲染器
        创建纹理用于视频渲染
2. 主循环机制:
        处理SDL事件(如退出、按键等)
        刷新视频帧
        控制帧率以实现音视频同步
3. 同步策略:
        比较视频帧PTS与音频时钟
        如果视频超前,等待适当时间再显示
        如果视频滞后,立即显示并可能丢帧
4. 渲染过程:
        将YUV数据更新到SDL纹理
        将纹理渲染到窗口
        释放已显示的帧

5. 资源管理:
        管理SDL资源(窗口、渲染器、纹理)
        在DeInit和析构函数中释放资源

📁 总结

        以上就是该项目的整体流程,相对来说还是比较简单的。我认为将这个项目跑一边,对于重点代码写一遍,那么对FFmpeg 7版本的接口就会有比较深刻的印象了,例如解封装,解码,转码等内容。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven dependencyManagement标签 properties标签

dependencyManagement标签properties标签

前端埋坑之element Ui 组件el-progress display:flex后不显示进度条解决方案

项目适用场景&#xff1a; <divs style"display&#xff1a;flex"> <span>这里是进度条前标题说明</span> <el-progress :percentage"50"></el-progress> </div> 问题呈现&#xff1a; el-progress进度条没啦&#xf…

嵌入式学习-土堆PyTorch(7)-day23

损失函数的调用import torch from torch import nn from torch.nn import L1Lossinputs torch.tensor([1.0,2.0,3.0]) target torch.tensor([1.0,2.0,5.0])inputs torch.reshape(inputs, (1, 1, 1, 3)) target torch.reshape(target, (1, 1, 1, 3)) #损失函数 loss L1Loss…

【2025最新】使用neo4j实现GraphRAG所需的向量检索

学习笔记&#xff0c;比较混乱&#xff0c;介意慎点。 背景 在将UMLS或者LightRAG构造的数据库存入neo4j之后&#xff0c;我开始将知识图谱运用到实际场景的使用中、例如查询、推理。然而&#xff0c;由于字符串匹配导致大量术语在检索时出现缺失。导致检索效果不佳。我们需要…

【AI深究】随机森林(Random Forest)全网最详细全流程详解与案例(附Python代码演示)|集成学习|数学原理、案例流程、代码演示及结果解读|参数与调优、工程启示、单棵决策树的对比、优缺点

大家好&#xff0c;我是爱酱。本篇将会系统地讲解随机森林&#xff08;Random Forest&#xff09;的原理、核心思想、数学表达、算法流程、代码实现与工程应用。内容适合初学者和进阶读者&#xff0c;配合公式和可视化示例。 注&#xff1a;本文章含大量数学算式、详细例子说明…

6.String、StringBuffer、StringBuilder区别及使用场景

String固定长度&#xff0c;引用的字符串内容无法改变例如&#xff0c;String s abc;s def;那么 s 字符串对应的地址已经改变了StringBuider 声明一个对象时&#xff0c;指向堆中的一块空间&#xff0c;包括两个属性 value 和 count其中 value 属性类似动态数组&#xff0c;可…

Qualcomm Linux 蓝牙指南学习--验证 Fluoride 协议栈的功能(2)

前言 Qualcomm Technologies推出的Linux蓝牙指南详细介绍了基于Qualcomm RB3 Gen 2和IQ-9100 Beta开发套件的蓝牙解决方案。该文档涵盖BlueZ和Fluoride协议栈的功能验证流程,支持蓝牙5.2核心规范,包括WCN6750/WCN6856/QCA6698AQ芯片组的特性。主要内容分为三部分: ‌1. 功…

Spring Boot中REST与gRPC并存架构设计与性能优化实践指南

Spring Boot中REST与gRPC并存架构设计与性能优化实践指南 在微服务架构日益复杂的当下&#xff0c;单一协议往往难以满足高并发低延迟与生态兼容的双重需求。本文基于真实生产环境的项目经验&#xff0c;分享了如何在Spring Boot中同时提供RESTful API和gRPC接口的架构设计、性…

Simulink仿真-model Setting关键配置

1.概述 Simulink 的仿真设置&#xff08;Model Settings&#xff09;是确保仿真准确性的关键配置&#xff0c;主要包括仿真时间、步长、解法器选择等核心参数的设定。 ‌可以通过快捷键‌CtrlE‌打开仿真设置界面2.核心参数 2.1 求解器Solver配置 时间范围&#xff1a;设置仿真…

内网与外网是通过什么进行传输的?内外网文件传输的安全方法

在当前企业信息化建设日益深入的背景下&#xff0c;出于安全防护与合规管理的需要&#xff0c;很多单位将网络划分为内网&#xff08;办公网/生产网&#xff09;与外网&#xff08;互联网/DMZ区&#xff09;。这种网络隔离策略虽然提升了安全性&#xff0c;但也带来了内外网文件…

RabbitMQ面试精讲 Day 4:Queue属性与消息特性

【RabbitMQ面试精讲 Day 4】Queue属性与消息特性 开篇 欢迎来到"RabbitMQ面试精讲"系列的第4天&#xff01;今天我们将深入探讨RabbitMQ中Queue的属性配置与消息特性&#xff0c;这是理解和优化RabbitMQ使用的关键知识点。掌握这些内容不仅能帮助你在面试中展现深厚…

uniapp vue3 vite项目使用微信云开发(云函数)

1、在根目录新建文件夹 cloudfunctions2、配置 manifest.json在项目根目录的 manifest.json 文件中&#xff0c;找到微信小程序配置部分&#xff0c;添加 cloudfunctionRoot 字段&#xff0c;指向你的云函数目录&#xff1a;{"mp-weixin": {"cloudfunctionRoot&…

AK视频下载工具:免费高效,多平台支持

近期小编又发现了一款更强大的新神器——AK视频下载&#xff08;电脑版&#xff09;&#xff0c;一起来了解下吧~ 软件亮点 完全免费&#xff0c;无需安装&#xff0c;操作便捷&#xff0c;直接打开即可使用。 支持多平台视频下载&#xff0c;包括抖音、B站、小红书、快手等主…

7月21日星期一今日早报简报微语报早读

7月21日星期一&#xff0c;农历六月廿七&#xff0c;早报#微语早读。1、广东佛山累计报告基孔肯雅热确诊病例1873例&#xff0c;均为轻症&#xff1b;2、祝贺&#xff01;石宇奇夺得日本羽毛球公开赛男单冠军&#xff1b;3、中国和匈牙利顺利完成引渡条约谈判&#xff1b;4、科…

基于Milvus Lite的轻量级向量数据库实战指南

一、为什么选择Milvus Lite&#xff1f; 在人工智能和语义搜索应用中&#xff0c;高效的向量检索是核心需求。相比需要部署Docker的完整版Milvus&#xff0c;Milvus Lite提供&#xff1a; 零依赖&#xff1a;纯Python实现&#xff0c;无需安装Docker或外部组件 开箱即用&…

深度学习时代下的社交媒体情感分析:方法、工具与未来挑战

摘要&#xff1a;基于Yue等学者2019年发表的权威综述&#xff0c;本文系统总结情感分析的技术框架、实战资源与前沿方向&#xff0c;附Python代码示例。 一、情感分析为何重要&#xff1f; 情感分析&#xff08;Sentiment Analysis&#xff09;旨在从文本中提取主观态度&…

Spring Boot 3.0新特性全面解析与实战应用

Spring Boot 3.0新特性全面解析与实战应用 引言 Spring Boot 3.0作为Spring生态系统的一个重要里程碑&#xff0c;带来了众多令人兴奋的新特性和改进。本文将深入解析Spring Boot 3.0的核心变化&#xff0c;并通过实战示例展示如何在项目中应用这些新特性。 核心变化概览 Java版…

C# sqlsugar 主子表 联合显示 LeftJoin

在C#中使用SqlSugar ORM进行Left Join操作是一种常见需求&#xff0c;尤其是在处理复杂数据库查询时。SqlSugar是一个轻量级、高性能的ORM框架&#xff0c;支持多种数据库。下面是如何使用SqlSugar进行Left Join操作的示例。1. 安装SqlSugar首先&#xff0c;确保你的项目中已经…

【ROS1】08-ROS通信机制——服务通信

目录 一、概念 二、何时使用服务 三、话题通信与服务通信的区别 四、案例 4.1 C实现 4.1.1 服务端 4.1.2 客户端 4.1.3 测试执行 4.2 Python实现 4.2.1 服务端 4.2.2 客户端 4.2.3 客户端优化——动态传参 4.2.4 客户端优化——等待服务端启动后再发起请求 一、概…

45.sentinel自定义异常

上文提到Blocked by Sentinel(flow limits) 限流异常,这样返给用户就不太友好,所以需要自定义异常。 默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口: BlockException有很多子类: pac…