Data structure analysis of ffplay

"Ffplay analysis (from startup to read thread operation)"
"ffplay analysis (video decoding thread operation)"
"ffplay analysis (audio decoding thread operation)"

The playback and display of ffplay is processed by SDL (Simple DirectMedia Layer Cross-platform Multimedia Development Library).

The elements in the ffplay structure are also the same as ffmpeg. The elements in a structure do not correspond to a single function point. For example, the same structure will have video, audio, and subtitle information, because they are all stored in the same structure. A function interface can be used when calling a function.

struct VideoState (the largest package structure in ffplay, all information is included)

typedef struct VideoState {
    
    
	
	//读线程SDL线程句柄
    SDL_Thread *read_tid;
	
	//指向输入的封装格式
    AVInputFormat *iformat;
	
	//退出请求,(1 = 请求退出)
    int abort_request;
	
	//立即刷新请求(1 = 请求刷新)
    int force_refresh;
	
	//播放暂停状态(1 = 暂停, 0 = 播放)
    int paused;
	
	//暂存播放暂停状态(最近一次的状态)
    int last_paused;
	
	
    int queue_attachments_req;
	
	//标识一次seek的请求
    int seek_req;
	
	//seek标志(AVSEEK_FLAG_BYTE等)
    int seek_flags;
	
	//请求seek的目标位置(当前位置 + 增量 )
    int64_t seek_pos;
	
	//本次请求seek的位置增量
    int64_t seek_rel;
	
	
    int read_pause_return;
    
	//iformat 输入封装格式的上下文
	AVFormatContext *ic;
	
	//标志是否为实时流数据(1 = 实时流)
    int realtime;

	//音频时钟
    Clock audclk;
	
	//视频时钟
    Clock vidclk;
	
	//外部时钟
    Clock extclk;

	//视频Frame队列(解码后)
    FrameQueue pictq;
	
	//字幕Frame队列(解码后)
    FrameQueue subpq;
	
	//音频Frame队列(解码后)
    FrameQueue sampq;

	//音频解码器
    Decoder auddec;
	
	//视频解码器
    Decoder viddec;
	
	//字幕解码器
    Decoder subdec;

	//音频流索引(比如有国语、粤语就是不同音频流的)
    int audio_stream;

	//音视频同步类型(默认audio master)
    int av_sync_type;

	//当前音频帧的PTS + 当前帧的Duration
    double audio_clock;
	
	//播放序列,seek可改变这个值
    int audio_clock_serial;
	
	//当av_sync_type != audio master时使用
    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;
	
	//音频Packet队列(解码前)
    PacketQueue audioq;
	
	//SDL音频缓冲区的大小(字节)
    int audio_hw_buf_size;
	
	//指向待播放的一帧音频数据,指向的数据区将被拷贝到SDL音频缓冲区
	//重采样后就是audio_buf1
	//需要重采样的数据
    uint8_t *audio_buf;
	
	//重采样后的数据
    uint8_t *audio_buf1;
	
	//audio_buf的大小
    unsigned int audio_buf_size; /* in bytes */
	
	//audio_buf1的大小
	unsigned int audio_buf1_size;
	
	//更新拷贝位置 当前音频帧中已拷入SDL音频缓冲区
    // 的位置索引(指向第一个待拷贝字节,因为拷贝到SDL可能不是完整一帧音频数据拷贝的)
    int audio_buf_index; /* in bytes */
	
	//当前音频帧中尚未拷入SDL音频缓冲区的数据量
    int audio_write_buf_size;
	
	//音量
    int audio_volume;
	
	//是否静音(1 = 静音, 0 = 正常)
    int muted;
	
	//音频参数
    struct AudioParams audio_src;
#if CONFIG_AVFILTER
    struct AudioParams audio_filter_src;
#endif
	//SDL支持的音频参数,重采样转换(文件的音频参数SDL不支持就要转:audio_src->audio_tgt)
    struct AudioParams audio_tgt;
	
	//音频重采样的上下文
    struct SwrContext *swr_ctx;
	
	//丢弃视频Packet计数
    int frame_drops_early;
	
	//丢弃视频Frame计数
    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;
	
	//字幕显示
    SDL_Texture *sub_texture;
	
	//视频显示
    SDL_Texture *vid_texture;

	//字幕流索引
    int subtitle_stream;
	
	//字幕流索引 
    AVStream *subtitle_st;
	
	//字幕Packet队列(解码前)
    PacketQueue subtitleq;

	//记录最后一帧播放的时间
    double frame_timer;
    double frame_last_returned_time;
    double frame_last_filter_delay;
	
	//视频流索引
    int video_stream;
	
	//视频流
    AVStream *video_st;
	
	//视频Packet队列(解码前)
    PacketQueue videoq;
	
	//一帧最大间隔
    double max_frame_duration;      // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
    
	//视频格式尺寸转换
	struct SwsContext *img_convert_ctx;
	
	//字幕格式尺寸转换
    struct SwsContext *sub_convert_ctx;
	
	//是否读取结束
    int eof;

	//文件名
    char *filename;
	//宽、高、x坐标起始、y坐标起始
    int width, height, xleft, ytop;
	
	//1 = 步进模式播放 ,0 = 其他模式 
    int step;

#if CONFIG_AVFILTER
    int vfilter_idx;
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
    AVFilterContext *in_audio_filter;   // the first filter in the audio chain
    AVFilterContext *out_audio_filter;  // the last filter in the audio chain
    AVFilterGraph *agraph;              // audio filter graph
#endif

	//保留最近一次的相应audio、video、subtitle流的steam index
    int last_video_stream, last_audio_stream, last_subtitle_stream;

	//条件变量,当读取数据队列满了后进入休眠时,可以通过该condition唤醒读线程
    SDL_cond *continue_read_thread;
} VideoState;

struct Clock (time package)

typedef struct Clock {
    
    
	//当前帧(待播放)显示时间戳, 播放后当前帧变成上一帧
    double pts;           /* clock base */
	
	//当前pts与当前系统时钟的差值,audio、video对于该值是独立
    double pts_drift;     /* clock base minus time at which we updated the clock */
    
	//最后一次更新的系统时钟
	double last_updated;
	
	//时钟速度控制,用于控制播放速度
    double speed;

	//播放序列,就是一段连续的播放动作,一个seek操作会启动一段新的播放序列
    int serial;           /* clock is based on a packet with this serial */
    
	//播放标识 (1 = 暂停状态)
	int paused;
	
	//指向当前 PacketQueue 的序列
    int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;

struct MyAVPacketList (data before decoding, a node of PacketQueue)

typedef struct MyAVPacketList {
    
    
	//解封装后的数据(解码前)
    AVPacket pkt;
	
	//下一个节点
    struct MyAVPacketList *next;
	
	//播放序列
    int serial;
} MyAVPacketList;

struct PacketQueue (Packet queue before decoding)


typedef struct PacketQueue {
    
    
	//队列头,队列尾
    MyAVPacketList *first_pkt, *last_pkt;
	
	//包数量,队列元素数量
    int nb_packets;
	
	//队列所有元素的数据大小总和
    int size;
	
	//队列所有元素的数据播放持续时间总和
    int64_t duration;
	
	//用户退出标志
    int abort_request;
	
	//播放序列号
    int serial;
	
	//维护PacketQueue的互斥量
    SDL_mutex *mutex;
	
	//条件变量,读、写相互通知
    SDL_cond *cond;
} PacketQueue;

struct Frame (decoded data, elements of FrameQueue queue)

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;
	
	// 对于图像为(enum AVPixelFormat),
	// 对于声音则为(enum AVSampleFormat)
    int format;
	
	//图像宽高比
    AVRational sar;
	
	//记录该帧是否已经显示过
    int uploaded;
	
	//垂直翻转(1 = 180度 , 0 = 正常 )
    int flip_v;
} Frame;

struct FrameQueue (Frame queue after decoding)


typedef struct FrameQueue {
    
    
	
	//Frame数组
    Frame queue[FRAME_QUEUE_SIZE];
	
	//读索引
    int rindex;
	
	//写索引
    int windex;
	
	//当前总帧数
    int size;
	
	//可存储最大帧数
    int max_size;
	
	//  等于 1 时,表示队列里保持最后一帧的数据不释放,只有在销毁队列在释放
    int keep_last;
	
	//初始化为0 ,和keep_last一起使用
    int rindex_shown;
	
	//互斥量
    SDL_mutex *mutex;
	
	//条件变量
    SDL_cond *cond;
	
	//数据包缓冲队列(解码前队列)
    PacketQueue *pktq;
} FrameQueue;

struct AudioParams (audio parameters)

typedef struct AudioParams {
    
    
	
	//采样率
    int freq;
	
	//通道数
    int channels;
	
	//通道布局(比如:立体声)
    int64_t channel_layout;
	
	//采样格式(比如:AV_SAMPLE_FMT_S16)
    enum AVSampleFormat fmt;
	
	//一个采样单元占用的字节数
    int frame_size;
	
	//一秒中音频占用字节数
    int bytes_per_sec;
} AudioParams;

struct Decoder (decoder data package)

typedef struct Decoder {
    
    
    
	AVPacket pkt;
	
	//数据包队列(解码前)
    PacketQueue *queue;
	
	//解码器上下文
    AVCodecContext *avctx;
	
	//包序列
    int pkt_serial;
	
	//解码器工作状态(0 = 工作, !0= 空闲)
    int finished;
	
	//解码器异常状态(0 = 异常,1 = 正常)
    int packet_pending;
	
	//条件变量
    SDL_cond *empty_queue_cond;
	
	//初始化时stream的start time
    int64_t start_pts;
	
	//初始化时stream的time base
    AVRational start_pts_tb;
	
	//记录最后一次解码的frame的pts,如果解码出来的帧是无效的pts就用这个值来
	//推算
    int64_t next_pts;
	
	//next_pts的单位
    AVRational next_pts_tb;
	
	//解码线程
    SDL_Thread *decoder_tid;
} Decoder;

Guess you like

Origin blog.csdn.net/m0_37599645/article/details/112800386