ffplay的数据结构分析

《ffplay分析(从启动到读取线程的操作)》
《ffplay分析(视频解码线程的操作)》
《ffplay分析(音频解码线程的操作)》

ffplay的播放显示是使用SDL(Simple DirectMedia Layer 跨平台多媒体开发库)处理的。

ffplay结构体内的元素也是和ffmpeg一样,一个结构体内的元素不是对应单一的功能点,比如同一个结构体就会有视频、音频、字幕的信息,因为都是用同一个结构体来存储,在函数调用时就可以用一个函数接口。

struct VideoState(ffplay中最大的一个封装结构,所有信息被包含在内)

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(时间封装)

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(解码前数据,PacketQueue的一个节点)

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

struct PacketQueue(解码前的Packet队列)


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(解码后数据,FrameQueue队列的元素)

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队列)


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(音频参数)

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(解码器数据封装)

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;

猜你喜欢

转载自blog.csdn.net/m0_37599645/article/details/112800386