ffplay的数据结构分析

《ffplay分析(从启动到读取线程的操作)》
《ffplay分析(视频解码线程的操作)》
《ffplay分析(音频解码线程的操作)》
《ffplay 分析(音频从Frame(解码后)队列取数据到SDL输出)》
《ffplay分析 (视频从Frame(解码后)队列取数据到SDL输出)》
《ffplay分析 (音视频同步:主时钟为音频)》
《ffplay分析 (暂停 / 播放处理)》
《ffplay分析 (seek操作处理)》

ffplay的数据结构分析 (版本:ffmpeg-4.2.1)

    • struct VideoState(ffplay中最大的一个封装结构,所有信息被包含在内)
    • struct Clock(时间封装)
    • struct MyAVPacketList(解码前数据,PacketQueue的一个节点)
    • struct PacketQueue(解码前的Packet队列)
    • struct Frame(解码后数据,FrameQueue队列的元素)
    • struct FrameQueue(解码后的Frame队列)
    • struct AudioParams(音频参数)
    • struct Decoder(解码器数据封装)

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 + 当前帧的Durationdouble 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_AVFILTERstruct 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_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//保留最近一次的相应audio、video、subtitle流的steam indexint 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;//一个采样单元占用的字节数(channels * fmt)int frame_size;//一秒中音频占用字节数(channels * fmt * freq)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 timeint64_t start_pts;//初始化时stream的time baseAVRational start_pts_tb;//记录最后一次解码的frame的pts,如果解码出来的帧是无效的pts就用这个值来//推算int64_t next_pts;//next_pts的单位AVRational next_pts_tb;//解码线程SDL_Thread *decoder_tid;
} Decoder;

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

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

相关文章

tolowercase_Java String toLowerCase()方法与示例

tolowercase字符串toLowerCase()方法 (String toLowerCase() Method) toLowerCase() method is a String class method, it is used to convert given string into the lowercase. toLowerCase()方法是String类方法,用于将给定的字符串转换为小写。 Syntax: 句法&a…

python web 服务器实时监控 websocket_python websocket网页实时显示远程服务器日志信息...

功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上的日志信息一般我们在运维工具部署环境的时候,需要实时展现部署过程中的信息,或者在浏览器中实时显示程序日志给开发人员看。你还在用ajax每隔段时间去获取服务器日…

磁盘调度算法

1,假设磁头当前位于第105道,正在向磁道序号增加的方向移动,现有一个磁道访问请求序列为:35,45,12,68,100,180,170,195,试用先来先服务…

C# Using用法三则

(1)引用命名空间 using作为引入命名空间指令的用法准则为: using Namespace; 在.NET程序中,最多见的代码莫过于在程序文件的开头引入System命名空间,其原由在于System命名空间中封装了许多最基本最常用的操作&#xff…

iOS开发 工程

一直没正儿八经的写过技术文章。今日开个小窗,准备写点东西。。。完了 1、传统的MVC结构需要至少M、V、C三个模块,在实际开发中往往需要添加额外的模块,添加的模块当然也大体上属于这三个模块之内。以下为较为常用的子模块。 (1&a…

C++11 std::shared_ptr的std::move()移动语义底层分析

std::shared_ptr的std::move()移动语义底层分析 执行std::move()之前: 执行std::move()之后: 结论:一个浅拷贝 sizeof(std::shared_ptr) 8字节 pss1 : 0x0028fea8 pss2 : 0x0028fea0 (栈是逆增长的) 观察执行std::m…

一个使用numpy.ones()的矩阵| 使用Python的线性代数

Ones Matrix - When all the entries of a matrix are one, then it is called as ones matrix. It may be of any dimension (MxN). 一个矩阵 -当矩阵的所有条目均为1时,则称为一个矩阵。 它可以是任何尺寸( MxN )。 Properties: 特性: The determina…

python去掉字符串最外侧的引号_疯狂Python讲义第二章读书笔记

本章讲解变量和简单类型2.1 从注释讲起单行注释使用#,#后面的代码被注释掉不会运行,如:# print(123) 注释掉后123不会输出。多行注释使用""" """,三个双引号,双引号中的内容注释掉&…

Xpath[转]

Xpath[转] XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。 XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 同时被构建于 XPath 表达之上。 因此,对 XPath 的理解是很多高级 XML 应用的基础。 …

【转】深入分析 ASP.NET Mvc 1.0 – 1. 深入MvcHandler

MvcHandler是一个mvc程序真正开始的地方,因为你可以直接看到并调试它的源码。 MvcHandler的主要代码如下:protected internal virtual void ProcessRequest(HttpContextBase httpContext) {AddVersionHeader(httpContext);// Get the controller typestring control…

C++11 右值引用与常量左值引用保存临时变量(函数返回值)的底层分析

右值引用保存临时变量(函数返回值)的问题 :临时变量是右值 1、普通变量接收函数返回值: 2、右值引用变量接收函数返回值: 3、用const int& 和右值引用是一样的效果,只是const int& 就不可以修改…

JavaScript中的位置协议属性

JavaScript | 位置协议属性 (JavaScript | Location protocol property) A protocol by definition simply implies a set or working rules that must be adhered to. A network protocol thus defines rules for communication between network devices. You must be familia…

axure源文件_Axure教程:实现网易云音乐有声播放效果

为了方便讲解,我们首先在桌面新建一个文件夹,命名为音乐。1、将自己想要演示播放的MP3音乐文件放在这个文件夹里面。2、给播放页添加一个中继器,随便命名,我给它命名为【音乐地址链接器】,用来链接播放本地音乐文件。并…

2012年终总结

工作: 原来的文章也写过,今年年初的时候,因为一些原因,成了另外一家公司的员工,但办公地点还是在原来的公司。 这是一家外包公司,技术实力当然是比较强的,不过自己对于编程方面的兴趣止不住的一…

PYTHON解析PE的模块

RT,从GOOGLE CODE上找的。。虽然拿PYTHON解析PE的意义不大还有点麻烦…… 示例代码: #coding:gbk import sys import pefile #from struct import * import structdef main():pe pefile.PE("ccalc.exe")pe.print_info()if __name__ "__…

ffplay分析(从启动到读取数据线程插入到字幕、音频、视频解码前的队列操作)

《ffplay的数据结构分析》 《ffplay分析(视频解码线程的操作)》 《ffplay分析(音频解码线程的操作)》 《ffplay 分析(音频从Frame(解码后)队列取数据到SDL输出)》 《ffplay分析 (视频从Frame(解…

python3和python2 优势_python3和python2的区别

1.性能Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可以取得很好的优化结果。Py3.1性能比Py2.5慢15%,还有很大的提升空间。2.编码Py3.X源码文件默认使用utf-8编码,这就使得以下代码…

并发进程同步

P是荷兰语Proberen(测试)的首字母。为阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。也就是不好的一方面。 V是荷兰语Verhogen(增加)的首字母。为唤醒原语,负责把一…

寄存器和pin_16x2 LCD的PIN图和寄存器

寄存器和pinIn these years the LCD is finding widespread use. It has replaced the LEDs or other multi-segment LEDs.This is due to the following reasons: 近年来, LCD正在广泛使用。 它已替换LED或其他多段LED,原因如下: The decli…

【Java IO知识】读取中文乱码问题解决

读取文件主要是要设置读取的输入流如InputStreamReader时要设置读取的解码格式,要和文件本身的编码格式相同,这样读取出来的才不会乱码。 InputStreamReader reader new InputStreamInputReader(input, "编码格式"); ANSI是"gbk" 注:必须是在读取的时候就…