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

在这里插入图片描述