ffmpeg-ffplay代码架构简述

news2024/11/13 20:44:11

全局变量

/* 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播放,该线程为程序主线程。

在这里插入图片描述

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

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

相关文章

c语言基础知识帮助理解(详解数组)

前面梳理完函数和递归的知识后,来进行数组知识的梳理 对函数有疑惑的同学,可以看我之前的文章:c语言基础知识帮助理解(详解函数)_总之就是非常唔姆的博客-CSDN博客 c语言基础知识帮助理解(函数递归详解&am…

类的6个默认成员函数 构造函数

类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生…

ruoyi-cloud-notes01

1、Maven中的dependencyManagement Maven中的dependencyManagement元素提供了一种管理依赖版本号的方式。在dependencyManagement元素中声明所依赖的jar包的版本号等信息,那么所有子项目再次引入此依赖jar包时则无需显式的列出版本号。Maven会沿着父子层级向上寻找…

HCIP MPLS总结

一、MPLS--多协议标签交换 多协议:可以基于多种不同的3层协议来生成2.5层的标签信息; 包交换:包为网络层的PDU,故包交换是基于IP地址进行数据转发;就是路由器的路由行为; 原始的包交换:数据包…

STM32 CubeMX USB_CDC(USB_转串口)

STM32 CubeMX STM32 CubeMX 定时器(普通模式和PWM模式) STM32 CubeMX一、STM32 CubeMX 设置USB时钟设置USB使能UBS功能选择 二、代码部分添加代码实验效果 ![请添加图片描述](https://img-blog.csdnimg.cn/a7333bba478441ab950a66fc63f204fb.png)printf发…

分库分表概念、原理、拆分策略和实现技术讲解

文章目录 1.什么是分库分表2.分库分表拆分策略2.1 垂直拆分2.2 水平拆分 3.分库分表实现技术简介 1.什么是分库分表 分库分表的中心思想就是将数据分散存储,使得单一数据库/表的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的。 …

python中使用yt-dlp模块实现带进程条下载音视频

当代的互联网时代,视频内容的流行无疑是其中的重要组成部分。作为全球最大的视频分享平台,每天吸引着数以亿计的用户观看各种各样的视频内容。有时候,我们可能希望将某些喜欢的视频保存到本地进行观看,或者将它们用于其他用途。在…

406 · 和大于S的最小子数组

链接:LintCode 炼码 - ChatGPT!更高效的学习体验! 题解:同向双指针 九章算法 - 帮助更多程序员找到好工作,硅谷顶尖IT企业工程师实时在线授课为你传授面试技巧 class Solution { public:/*** param nums: an array …

任务12、Quality指令加持,Midjourney生成电影级数码作品

12.1 任务概述 本次实验任务旨在帮助你掌握Midjourney AI绘画中的Quality指令。通过深入介绍Quality指令的概念和作用,我们将解释为什么它在绘画中至关重要。通过测试不同的Quality参数对绘画效果的影响,并提供实战演示,你将学会如何在Midjourney中设置Quality参数以达到更…

Spring 事务详解(注解方式)

目 录 序言 1、编程式事务 2、配置声明式事务 2.1 基于TransactionProxyFactoryBean的方式(不常用,因为要为每一个类配置TransactionProxyFactoryBean) 2.2 基于AspectJ的XML方式(常用,可配置在某些类下的所有子…

⛳ StringBuffer and StringBuilder 处理字符串

目录 ⛳ StringBuffer and StringBuilder 处理字符串🎨 一,简介🏭 二,常用方法🚜 三 ,StringBugger🐾 四,StringBuilder⭐ 五,StringBuffer和StringBuilder面试 ⛳ Strin…

【李宏毅机器学习·学习笔记】Tips for Training: Adaptive Learning Rate

本节课主要介绍了Adaptive Learning Rate的基本思想和方法。通过使用Adaptive Learning Rate的策略,在训练深度神经网络时程序能实现在不同参数、不同iteration中,学习率不同。 本节课涉及到的算法或策略有:Adgrad、RMSProp、Adam、Learning …

Qt应用开发(基础篇)——时间微调输入框QDateTimeEdit、QDateEdit、QTimeEdit

一、前言 QAbstractSpinBox是全部微调输入框的父类,这是一种允许用户通过点击上下箭头按钮或输入数字来调整数值的图形用户界面控件,父类提供了当前值text、对齐方式align、只读readOnly等通用属性和方法。在上一篇数值微调输入框中有详细介绍。 QDateTi…

【雕爷学编程】Arduino动手做(186)---WeMos ESP32开发板4

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

PyTorch深度学习实战(9)——学习率优化

PyTorch深度学习实战(9)——学习率优化 0. 前言1. 学习率简介2. 梯度值、学习率和权重之间的相互作用3. 学习率优化实战3.1 学习率对缩放后的数据集的影响3.2 学习率对未缩放数据集的影响 小结系列链接 0. 前言 学习率( learning rate )是神经网络训练中…

(十二)大数据实战——hadoop集群之HDFS高可用自动故障转移

前言 本节内容主要介绍一下hadoop集群下实现HDFS高可用的自动故障转移,HDFS高可用的自动故障转移主要通过zookeeper实现故障的监控和主节点的切换。自动故障转移为 HDFS 部署增加了两个新组件:ZooKeeper 和 ZKFailoverController (ZKFC&…

【笔记】湖仓一体架构演进与发展

https://www.bilibili.com/video/BV1oF411F7rQ/?spm_id_from333.788.recommend_more_video.0&vd_sourcefa36a95b3c3fa4f32dd400f8cabddeaf

Linux中的firewall-cmd

2023年8月4日,周五上午 目录 打开端口关闭端口查看某个端口是否打开查看当前防火墙设置firewall-cmd中的服务在防火墙中什么是服务?为什么会有服务?打开或关闭服务查看某个服务是否打开firewall-cmd中的 zones查看所有可用的zones&#xff0…

elementui Cascader 级联选择使用心得

相信大家对于elementui并不陌生,作为适配Vue的优秀UI框架之一,一直被所有的开发者痛并快乐着。今天要记录的就是里边的主角之一Cascader。 首先先介绍一下Cascader ---> 当一个数据集合有清晰的层级结构时,可通过级联选择器逐级查看并选择…

OBS视频视频人物实时扣图方法(四种方式)

图片擦除一些杂乱图像 参考:https://www.bilibili.com/video/BV1va411G7be https://github.com/Sanster/lama-cleaner第一种:色度键选项 第二种:浏览器建立窗口选项 参考视频:https://www.bilibili.com/video/BV1WS4y1C7QY http…