本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10301253.html
ffplay是FFmpeg工程自带的简单播放器,使用FFmpeg提供的解码器和SDL库进行视频播放。本文基于FFmpeg工程4.1版本进行分析,其中ffplay源码清单如下:
https://github.com/FFmpeg/FFmpeg/blob/n4.1/fftools/ffplay.c
在尝试分析源码前,可先阅读如下参考文章作为铺垫:
[1]. 雷霄骅,视音频编解码技术零基础学习方法
[2]. 视频编解码基础概念
[3]. 色彩空间与像素格式
[4]. 音频参数解析
[5]. FFmpeg基础概念
“ffplay源码分析”系列文章如下:
[1]. ffplay源码分析1-概述
[2]. ffplay源码分析2-数据结构
[3]. ffplay源码分析3-代码框架
[4]. ffplay源码分析4-音视频同步
[5]. ffplay源码分析5-图像格式转换
[6]. ffplay源码分析6-音频重采样
[7]. ffplay源码分析7-播放控制
2. 数据结构
几个关键的数据结构如下:
2.1 struct VideoState
typedef struct VideoState {
SDL_Thread *read_tid; // demux解复用线程
AVInputFormat *iformat;
int abort_request;
int force_refresh;
int paused;
int last_paused;
int queue_attachments_req;
int seek_req; // 标识一次SEEK请求
int seek_flags; // SEEK标志,诸如AVSEEK_FLAG_BYTE等
int64_t seek_pos; // SEEK的目标位置(当前位置+增量)
int64_t seek_rel; // 本次SEEK的位置增量
int read_pause_return;
AVFormatContext *ic;
int realtime;
Clock audclk; // 音频时钟
Clock vidclk; // 视频时钟
Clock extclk; // 外部时钟
FrameQueue pictq; // 视频frame队列
FrameQueue subpq; // 字幕frame队列
FrameQueue sampq; // 音频frame队列
Decoder auddec; // 音频解码器
Decoder viddec; // 视频解码器
Decoder subdec; // 字幕解码器
int audio_stream; // 音频流索引
int av_sync_type;
double audio_clock; // 每个音频帧更新一下此值,以pts形式表示
int audio_clock_serial; // 播放序列,seek可改变此值
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; // 音频packet队列
int audio_hw_buf_size; // SDL音频缓冲区大小(单位字节)
uint8_t *audio_buf; // 指向待播放的一帧音频数据,指向的数据区将被拷入SDL音频缓冲区。若经过重采样则指向audio_buf1,否则指向frame中的音频
uint8_t *audio_buf1; // 音频重采样的输出缓冲区
unsigned int audio_buf_size; /* in bytes */ // 待播放的一帧音频数据(audio_buf指向)的大小
unsigned int audio_buf1_size; // 申请到的音频缓冲区audio_buf1的实际尺寸
int audio_buf_index; /* in bytes */ // 当前音频帧中已拷入SDL音频缓冲区的位置索引(指向第一个待拷贝字节)
int audio_write_buf_size; // 当前音频帧中尚未拷入SDL音频缓冲区的数据量,audio_buf_size = audio_buf_index + audio_write_buf_size
int audio_volume; // 音量
int muted; // 静音状态
struct AudioParams audio_src; // 音频frame的参数
#if CONFIG_AVFILTER
struct AudioParams audio_filter_src;
#endif
struct AudioParams audio_tgt; // SDL支持的音频参数,重采样转换:audio_src->audio_tgt
struct SwrContext *swr_ctx; // 音频重采样context
int frame_drops_early; // 丢弃视频packet计数
int frame_drops_late; // 丢弃视频frame计数
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;
SDL_Texture *sub_texture;
SDL_Texture *vid_texture;
int subtitle_stream; // 字幕流索引
AVStream *subtitle_st; // 字幕流
PacketQueue subtitleq;