ffmpeg-ffplay代码架构简述
全局变量
/* Minimum SDL audio buffer size, in samples. */
// 最小音频缓冲
#define SDL_AUDIO_MIN_BUFFER_SIZE 512
/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
// 计算实际音频缓冲大小,并不需要太频繁回调,这里设置的是最大音频回调次数是每秒30次
#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30/* Step size for volume control in dB */
// 音频控制 以db为单位的步进
#define SDL_VOLUME_STEP (0.75)/* no AV sync correction is done if below the minimum AV sync threshold */
// 最低同步阈值,如果低于该值,则不需要同步校正
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
// 最大同步阈值,如果大于该值,则需要同步校正
#define AV_SYNC_THRESHOLD_MAX 0.1
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
// 帧补偿同步阈值,如果帧持续时间比这更长,则不用来补偿同步
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
/* no AV correction is done if too big error */
// 同步阈值。如果误差太大,则不进行校正
#define AV_NOSYNC_THRESHOLD 10.0/* maximum audio speed change to get correct sync */
// 正确同步的最大音频速度变化值(百分比)
#define SAMPLE_CORRECTION_PERCENT_MAX 10/* external clock speed adjustment constants for realtime sources based on buffer fullness */
// 根据实时码流的缓冲区填充时间做外部时钟调整
// 最小值
#define EXTERNAL_CLOCK_SPEED_MIN 0.900
// 最大值
#define EXTERNAL_CLOCK_SPEED_MAX 1.010
// 步进
#define EXTERNAL_CLOCK_SPEED_STEP 0.001/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
// 使用差值来实现平均值
#define AUDIO_DIFF_AVG_NB 20/* polls for possible required screen refresh at least this often, should be less than 1/fps */
// 刷新频率 应该小于 1/fps
#define REFRESH_RATE 0.01/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
/* TODO: We assume that a decoded and resampled frame fits into this buffer */
// 采样大小
#define SAMPLE_ARRAY_SIZE (8 * 65536)#define CURSOR_HIDE_DELAY 1000000#define USE_ONEPASS_SUBTITLE_RENDER 1// 冲采样标志
static unsigned sws_flags = SWS_BICUBIC;// 包列表结构
typedef struct MyAVPacketList {AVPacket pkt;struct MyAVPacketList *next;int serial;
} MyAVPacketList;// 待解码包队列
typedef struct PacketQueue {MyAVPacketList *first_pkt, *last_pkt;int nb_packets;int size;int64_t duration;int abort_request;int serial;SDL_mutex *mutex;SDL_cond *cond;
} PacketQueue;#define VIDEO_PICTURE_QUEUE_SIZE 3
#define SUBPICTURE_QUEUE_SIZE 16
#define SAMPLE_QUEUE_SIZE 9
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))// 音频参数
typedef struct AudioParams {int freq; // 频率int channels; // 声道数int64_t channel_layout; // 声道设计,单声道,双声道还是立体声enum AVSampleFormat fmt; // 采样格式int frame_size; // 采样大小int bytes_per_sec; // 每秒多少字节
} AudioParams;// 时钟
typedef struct Clock {double pts; // 时钟基准 /* clock base */double pts_drift; // 更新时钟的差值 /* clock base minus time at which we updated the clock */double last_updated; // 上一次更新的时间double speed; // 速度int serial; // 时钟基于使用该序列的包 /* clock is based on a packet with this serial */int paused; // 停止标志int *queue_serial; // 指向当前数据包队列序列的指针,用于过时的时钟检测 /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;/* Common struct for handling all types of decoded data and allocated render buffers. */
// 解码帧结构
typedef struct Frame {AVFrame *frame; // 帧数据AVSubtitle sub; // 字幕int serial; // 序列double pts; // 帧的显示时间戳 /* presentation timestamp for the frame */double duration; // 帧显示时长 /* estimated duration of the frame */int64_t pos; // 文件中的位置 /* byte position of the frame in the input file */int width; // 帧的宽度int height; // 帧的高度int format; // 格式AVRational sar; // 额外参数int uploaded; // 上载int flip_v; // 反转
} Frame;// 解码后的帧队列
typedef struct FrameQueue {Frame queue[FRAME_QUEUE_SIZE]; // 队列数组int rindex; // 读索引int windex; // 写索引int size; // 大小int max_size; // 最大大小int keep_last; // 保持上一个int rindex_shown; // 读显示SDL_mutex *mutex; // 互斥变量SDL_cond *cond; // 条件变量PacketQueue *pktq;
} FrameQueue;// 时钟同步类型
enum {AV_SYNC_AUDIO_MASTER, // 音频作为同步,默认以音频同步 /* default choice */AV_SYNC_VIDEO_MASTER, // 视频作为同步AV_SYNC_EXTERNAL_CLOCK, // 外部时钟作为同步 /* synchronize to an external clock */
};// 解码器结构
typedef struct Decoder {AVPacket pkt; // 包AVPacket pkt_temp; // 中间包PacketQueue *queue; // 包队列AVCodecContext *avctx; // 解码上下文int pkt_serial; // 包序列int finished; // 是否已经结束int packet_pending; // 是否有包在等待SDL_cond *empty_queue_cond; // 空队列条件变量int64_t start_pts; // 开始的时间戳AVRational start_pts_tb; // 开始的额外参数int64_t next_pts; // 下一帧时间戳AVRational next_pts_tb; // 下一帧的额外参数SDL_Thread *decoder_tid; // 解码线程
} Decoder;// 视频状态结构
typedef struct VideoState {SDL_Thread *read_tid; // 读取线程AVInputFormat *iformat; // 输入格式int abort_request; 终止int force_refresh; 强制刷新int paused; // 停止int last_paused; // 最后停止int queue_attachments_req; // 队列附件请求int seek_req; // 查找请求int seek_flags; // 查找标志int64_t seek_pos; // 查找位置int64_t seek_rel; // int read_pause_return; // 读停止返回AVFormatContext *ic; // 解码格式上下文int realtime; // 是否实时码流Clock audclk; // 音频时钟Clock vidclk; // 视频时钟Clock extclk; // 外部时钟FrameQueue pictq; // 视频队列FrameQueue subpq; // 字幕队列FrameQueue sampq; // 音频队列Decoder auddec; // 音频解码器Decoder viddec; // 视频解码器Decoder subdec; // 字幕解码器int audio_stream; // 音频码流Idint av_sync_type; // 同步类型double audio_clock; // 音频时钟int audio_clock_serial; // 音频时钟序列double audio_diff_cum; // 用于音频差分计算 /* used for AV difference average computation */double audio_diff_avg_coef; // double audio_diff_threshold; // 音频差分阈值int audio_diff_avg_count; // 平均差分数量AVStream *audio_st; // 音频码流PacketQueue audioq; // 音频包队列int audio_hw_buf_size; // 硬件缓冲大小uint8_t *audio_buf; // 音频缓冲区uint8_t *audio_buf1; // 音频缓冲区1unsigned int audio_buf_size; // 音频缓冲大小 /* in bytes */unsigned int audio_buf1_size; // 音频缓冲大小1int audio_buf_index; // 音频缓冲索引 /* in bytes */int audio_write_buf_size; // 音频写入缓冲大小int audio_volume; // 音量int muted; // 是否静音struct AudioParams audio_src; // 音频参数
#if CONFIG_AVFILTER struct AudioParams audio_filter_src; // 音频过滤器
#endifstruct AudioParams audio_tgt; // 音频参数struct SwrContext *swr_ctx; // 音频转码上下文int frame_drops_early; // int frame_drops_late; // enum ShowMode { // 显示类型SHOW_MODE_NONE = -1, // 无显示SHOW_MODE_VIDEO = 0, // 显示视频SHOW_MODE_WAVES, // 显示波浪,音频SHOW_MODE_RDFT, // 自适应滤波器SHOW_MODE_NB // } show_mode;int16_t sample_array[SAMPLE_ARRAY_SIZE]; // 采样数组int sample_array_index; // 采样索引int last_i_start; // 上一开始RDFTContext *rdft; // 自适应滤波器上下文int rdft_bits; // 自使用比特率FFTSample *rdft_data; // 快速傅里叶采样int xpos; // double last_vis_time; // SDL_Texture *vis_texture; // 音频TextureSDL_Texture *sub_texture; // 字幕TextureSDL_Texture *vid_texture; // 视频Textureint subtitle_stream; // 字幕码流IdAVStream *subtitle_st; // 字幕码流PacketQueue subtitleq; // 字幕包队列double frame_timer; // 帧计时器double frame_last_returned_time; // 上一次返回时间double frame_last_filter_delay; // 上一个过滤器延时int video_stream; // 视频码流IdAVStream *video_st; // 视频码流PacketQueue videoq; // 视频包队列double max_frame_duration; // 最大帧显示时间 // maximum duration of a frame - above this, we consider the jump a timestamp discontinuitystruct SwsContext *img_convert_ctx; // 视频转码上下文struct SwsContext *sub_convert_ctx; // 字幕转码上下文int eof; // 结束标志char *filename; // 文件名int width, height, xleft, ytop; // 宽高,其实坐标int step; // 步进#if CONFIG_AVFILTERint vfilter_idx; // 过滤器索引AVFilterContext *in_video_filter; // 第一个视频滤镜 // the first filter in the video chainAVFilterContext *out_video_filter; // 最后一个视频滤镜 // the last filter in the video chainAVFilterContext *in_audio_filter; // 第一个音频过滤器 // the first filter in the audio chainAVFilterContext *out_audio_filter; // 最后一个音频过滤器 // the last filter in the audio chainAVFilterGraph *agraph; // 音频过滤器 // audio filter graph
#endif// 上一个视频码流Id、上一个音频码流Id、上一个字幕码流Idint last_video_stream, last_audio_stream, last_subtitle_stream;SDL_cond *continue_read_thread; // 连续读线程
} VideoState;/* options specified by the user */
static AVInputFormat *file_iformat; // 文件输入格式
static const char *input_filename; // 输入文件名
static const char *window_title; // 标题
static int default_width = 640; // 默认宽度
static int default_height = 480; // 默认高度
static int screen_width = 0; // 屏幕宽度
static int screen_height = 0; // 屏幕高度
static int audio_disable; // 是否禁止播放声音
static int video_disable; // 是否禁止播放视频
static int subtitle_disable; // 是否禁止播放字幕
static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};
static int seek_by_bytes = -1; //
static int display_disable; // 显示禁止
static int borderless; //
static int startup_volume = 100; // 起始音量
static int show_status = 1; // 显示状态
static int av_sync_type = AV_SYNC_AUDIO_MASTER; // 同步类型
static int64_t start_time = AV_NOPTS_VALUE; // 开始时间
static int64_t duration = AV_NOPTS_VALUE; // 间隔
static int fast = 0; // 快速
static int genpts = 0; //
static int lowres = 0; // 慢速
static int decoder_reorder_pts = -1; // 解码器重新排列时间戳
static int autoexit; // 否自动退出
static int exit_on_keydown; // 是否按下退出
static int exit_on_mousedown; // 是否鼠标按下退出
static int loop = 1; // 循环
static int framedrop = -1; // 舍弃帧
static int infinite_buffer = -1; // 缓冲区大小限制 =1表示不限制(is->realtime实时传输时不限制
static enum ShowMode show_mode = SHOW_MODE_NONE; // 显示类型
static const char *audio_codec_name; // 音频解码器名称
static const char *subtitle_codec_name; // 字幕解码器名称
static const char *video_codec_name; // 视频解码器名称
double rdftspeed = 0.02; // 自适应滤波器的速度
static int64_t cursor_last_shown; // 上一次显示光标
static int cursor_hidden = 0; // 光标隐藏
#if CONFIG_AVFILTER
static const char **vfilters_list = NULL; // 视频滤镜
static int nb_vfilters = 0; // 视频滤镜数量
static char *afilters = NULL; // 音频滤镜
#endif
static int autorotate = 1; // 是否自动旋转/* current context */
static int is_full_screen; // 是否全屏
static int64_t audio_callback_time; // 音频回调时间static AVPacket flush_pkt; // 刷新的包#define FF_QUIT_EVENT (SDL_USEREVENT + 2)static SDL_Window *window; // 窗口
static SDL_Renderer *renderer; // 渲染器
设计的流程
包含文件读取、解封装、解码、音视频输出、音视频同步,流程如下图所示:
ffplay中使用的线程
(1)读线程。读取文件、解封装
(2)音频解码线程。解码音频压缩数据为PCM数据。
(3)视频解码线程。解码视频压缩数据为图像数据。
(4)音频输出线程。基于SDL播放,该线程实际上是SDL的内部线程。
(5)视频输出线程。基于SDL播放,该线程为程序主线程。
相关文章:

ffmpeg-ffplay代码架构简述
全局变量 /* Minimum SDL audio buffer size, in samples. */ // 最小音频缓冲 #define SDL_AUDIO_MIN_BUFFER_SIZE 512 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */ // 计算实际音频缓冲大小,并不需要太频繁…...

⛳ 多线程面试-什么是多线程上下文切换?
目录 ⛳ 多线程面试-什么是多线程上下文切换?🎁 Java中用到的线程调度算法是什么?🎨 什么是线程饥饿 ?你对线程优先级的理解是什么? ⛳ 多线程面试-什么是多线程上下文切换ÿ…...

vb+SQL车辆管理系统设计与实现
摘 要 随着信息时代的到来,信息高速公路的兴起,全球信息化进入了一个新的发展时期。人们越来越认识到计算机强大的信息模块处理功能,使之成为信息产业的基础和支柱。 我国经济的快速发展,汽车已经成为人们不可缺少的交通工具。对于拥有大量车辆的机关企事业来说,车辆的…...

java的枚举类
枚举类的概念和使用 1.枚举类的理解:类的对象只有有限个,确定的。我们称此为枚举类。 2.当需要定义一组常量时,强烈建议使用枚举类。对象便是所指的常量。 3.如果枚举类中只有一个对象,则可以作为单例模式的实现方式。 定义枚举类…...

基于java早餐店点餐系统源码设计与实现
摘 要 多姿多彩的世界带来了美好的生活,行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方面,信息技术至始至终都是成就行业发展的重要秘密。不论何种行业,大到国家、企业,小到团体、个人都在多方位的结合信息化技…...

ODOO16如何处理采购运输正常损耗的成本价核算?
《会计准则》规定:商品流通企业在采购商品过程中发生的运输费、装卸费、运输途中的合理损耗都归为采购存货成本中。 例如:采购A产品1000个,单价10元/个,途中运输正常损耗率是5%,因此实际入库是950个,入库金…...

【数据预测】基于白鲸优化算法BWO的VMD-KELM光伏发电功率预测 短期功率预测【Matlab代码#54】
文章目录 【可更换其他算法,获取资源请见文章第6节:资源获取】1. 白鲸优化算法BWO2. 变分模态分解VMD3. 核极限学习机KELM4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他算法,获取资源请见文章第6节:资源获取】 1. 白鲸…...

函数式编程-将过程作为返回值的应用:分步过程
之前的文章提到函数式编程的一等函数(First-class Function)四个性质中有“可以将过程作为返回值”这一点,但这一点在实际使用中不如“将过程作为参数”(高阶函数)用得多。本文介绍一种这个性质用于分步函数的应用。 …...

Mysql-学习笔记
文章目录 1. 数据库1.1 Mysql安装及常用代码1.2 SQL介绍1.3 SQL分类1. DDL-操作数据库,表2. DML-对表中的数据进行增删改3. DQL-对表中的数据进行查询条件查询模糊查询排序查询分组查询分页查询 4. DCL-对数据库进行权限控制外键约束表关系-多对多多表查询事务 1. 数…...

【雕爷学编程】Arduino动手做(187)---1.3寸OLED液晶屏模块2
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…...

Windows用户如何安装新版本cpolar内网穿透
Windows用户如何安装新版本cpolar内网穿透 文章目录 Windows用户如何安装新版本cpolar内网穿透 在科学技术高度发达的今天,我们身边充斥着各种电子产品,这些电子产品不仅为我们的工作带来极大的便利,也让生活变得丰富多彩。我们可以使用便携的…...

MacBookPro安装Win10,Wifi不能用了,触控板不能用了(2)
一、问题 去年在MacBookPro上装过Win10,当初只分配了60G空间。各方面原因需要重装系统,上个月装了一晚上,也无法连接Wifi,触控板只能当鼠标左键用。 后来发现是没有相关驱动造成的,于是从Mac系统联网找到网卡驱动&am…...

理解C++中变量的作用域
理解C中变量的作用域 常规变量(如前面定义的所有变量)的作用域很明确,只能在作用域内使用它们,如果您在作用域外使用它们,编译器将无法识别,导致程序无法通过编译。在作用域外面,变量是未定义的…...

vue+element-ui给全局请求设置一个loading样式
老项目后台管理,要在每个页面请求的时候都添加一个loading,为了统一和防止一个页面多次请求页面出现闪烁的情况同意在request.js中添加了一个全局loading。 想要的效果: 1.在请求的时候创建一个loading样式,请求结束是关闭。 2…...

传球游戏
题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个…...

智能卡通用安全检测指南 思度文库
范围 本标准规定了智能卡类产品进行安全性检测的一般性过程和方法。 本标准适用于智能卡安全性检测评估和认证。 规范性引用文件 下列文件对于本文件的应用是必不可少的。凡是注日期的引用文件,仅注日期的版本适用于本文件。凡是不注日期的引用文件,…...

Maven设置阿里云路径(防止加载过慢)
<?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding …...

JavaScript原型链污染漏洞复现与防范
目录 什么是原型链污染漏洞? 复现原型链污染漏洞 防范原型链污染漏洞 什么是原型链污染漏洞? 原型链污染是JavaScript中的一种安全漏洞,利用该漏洞可以修改对象的原型,从而影响对象及其属性的行为。攻击者可以通过修改原型链来…...

初识MySQL数据库之用户管理
目录 一、用户管理 二、用户 1. 用户信息 2. 创建用户 3. 用户登录测试 4. 删除用户 5. 设置用户远端登录 6. 修改密码 6.1 修改当前用户的密码 6.2 root用户修改指定用户的密码 三、权限 1. 数据库中的各个权限含义 2. 给用户授权 3. 查看用户拥有权限 4. 授权…...

JVM 类文件结构(class文件)
JVM 本文链接:https://blog.csdn.net/feather_wch/article/details/132116849 类文件结构 1、class文件的组成 无符号数:基本数据类型 u1 u2 u3 u4 描述 数字字符串索引引用 表:复合数据类型,无符号数 表组, _inf…...

PAT乙题1011
答案 #include<iostream> #include<cstdio> using namespace std; typedef long long int ll; int main() {int n,cnt1;cin >> n;while (n--){ll a, b, c; cin >> a >> b >> c;printf("Case #%d: ", cnt);a b > c ? puts(…...

【并发专题】单例模式的线程安全(进阶理解篇)
目录 背景前置知识类加载运行全过程 单例模式的实现方式一、饿汉式基本介绍源码分析 二、懒汉式基本介绍源码分析改进 三、懒汉式单例终极解决方案(静态内部类)(推荐使用方案)基本介绍源码分析 感谢 背景 最近学习了JVM之后&…...

无涯教程-Perl - if...elsif...else语句函数
if 语句后可以跟可选的 elsif ... else 语句,这对于使用单个if ... elsif语句测试各种条件非常有用。 if...elsif...else - 语法 Perl编程语言中的 if ... elsif...else语句的语法是- if(boolean_expression 1) {# Executes when the boolean expression 1 is tr…...

uniapp 实现滑动元素并下方有滚动条显示
用uniapp实现下图的样式 代码如下: <template><view class"content"><view class"data-box" ref"dataBox" touchend"handleEnd"><view class"data-list"><view class"data-ite…...

QT充当客户端模拟浏览器等第三方客户端对https进行双向验证
在 ssl单向证书和双向证书校验测试及搭建流程 文章中,已经做了基于https的单向认证和双向认证,,, 在进行双向认证时,采用的是curl工具或浏览器充当客户端去验证。 此次采用QT提供的接口去开发客户端向服务器发送请求&a…...

【JVM】 垃圾回收篇——自问自答(1)
Q什么是垃圾: 运行程序中,没用任何指针指向的对象。 Q为什么需要垃圾回收? 内存只分配,不整理回收,迟早会被消耗完。 内存碎片的整理,为新对象腾出空间 没有GC程序无法正常进行。 Q 哪些区域有GC&#…...

Image Line FL Studio v21.0.3.3517 Producer版全插件版WIN免费下载完整版
FL Studio 21,也称为 Fruity Loops 21,是一款功能强大的数字音频工作站,被世界各地的音乐制作人和 DJ 使用。无论您是新手还是经验丰富的制作人,FL Studio 21都能为您提供创作专业品质音乐所需的工具。在这篇博文中,我…...

PHP8条件控制语句-PHP8知识详解
我们昨天说了流程控制的结构有顺序结构、选择结构和循环结构。选择结构就是条件结构。 条件控制语句就是对语句中不同条件的值进行判断,进而根据不同的条件执行不同的语句。 在本文中,学习的是if语句、if…else语句、if…elseif语句和switch语句。 1、…...

【PHP代码审计】ctfshow web入门 php特性 93-104
ctfshow web入门 php特性 93-104 web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102web 103web 104 web 93 这段PHP代码是一个简单的源码审计例子,让我们逐步分析它: include("flag.php");: 这行代码将flag.php文件包含进来。…...

CSS元素的显示模式
1、现在我想做成小米左侧边栏这样的效果,该怎么做呢? 2、小米商城触碰之后会显示出新的商品案例 3、一碰到之后会出现这个列表 4、这里涉及到了元素显示模式: 5、用人进行划分可以分为男人和女人,根据男人和女人的特性进行相应的…...