数据结构分析

VideoState

其实主要作用和800行代码写一个播放器作用中一样 就是一个主要封装类
保存 其中各项的主要内容

个人觉得比较需要注意到的 几个非重点常用对象

1 abort_request 就是判断这个时候有没有 退出播放 如果退出了 那就一系列退出操作

2 force_refresh 视频播放时候用的

3 av_sync_type ffplay 支持3种同步方式

typedef struct VideoState {SDL_Thread    *read_tid;      // 读线程句柄AVInputFormat   *iformat;   // 指向demuxerint     abort_request;      // =1时请求退出播放int        force_refresh;      // =1时需要刷新画面,请求立即刷新画面的意思int     paused;             // =1时暂停,=0时播放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;        // iformat的上下文int     realtime;           // =1为实时流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;           // 音视频同步类型, 默认audio masterdouble            audio_clock;            // 当前音频帧的PTS+当前帧Durationint             audio_clock_serial;     // 播放序列,seek可改变此值// 以下4个参数 非audio master同步方式使用double            audio_diff_cum;         // used for AV difference average computationdouble         audio_diff_avg_coef;double          audio_diff_threshold;int            audio_diff_avg_count;// endAVStream     *audio_st;              // 音频流PacketQueue       audioq;                 // 音频packet队列int            audio_hw_buf_size;          // SDL音频缓冲区的大小(字节为单位)// 指向待播放的一帧音频数据,指向的数据区将被拷入SDL音频缓冲区。若经过重采样则指向audio_buf1,// 否则指向frame中的音频uint8_t           *audio_buf;             // 指向需要重采样的数据uint8_t            *audio_buf1;            // 指向重采样后的数据unsigned int        audio_buf_size;     // 待播放的一帧音频数据(audio_buf指向)的大小unsigned int       audio_buf1_size;    // 申请到的音频缓冲区audio_buf1的实际尺寸int          audio_buf_index;            // 更新拷贝位置 当前音频帧中已拷入SDL音频缓冲区// 的位置索引(指向第一个待拷贝字节)// 当前音频帧中尚未拷入SDL音频缓冲区的数据量:// audio_buf_size = audio_buf_index + audio_write_buf_sizeint            audio_write_buf_size;int            audio_volume;               // 音量int            muted;                      // =1静音,=0则正常struct AudioParams audio_src;           // 音频frame的参数
#if CONFIG_AVFILTERstruct AudioParams audio_filter_src;
#endifstruct AudioParams audio_tgt;       // SDL支持的音频参数,重采样转换:audio_src->audio_tgtstruct SwrContext *swr_ctx;         // 音频重采样contextint 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;       // 音频TextureSDL_Texture *sub_texture;       // 字幕显示SDL_Texture *vid_texture;       // 视频显示int subtitle_stream;            // 字幕流索引AVStream *subtitle_st;          // 字幕流PacketQueue subtitleq;          // 字幕packet队列double frame_timer;             // 记录最后一帧播放的时刻double frame_last_returned_time;    // 上一次返回时间double frame_last_filter_delay;     // 上一个过滤器延时int video_stream;               // 视频流索引AVStream *video_st;             // 视频流PacketQueue videoq;             // 视频队列double max_frame_duration;      // 一帧最大间隔. 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; // 宽、高,x起始坐标,y起始坐标int step;           // =1 步进播放模式, =0 其他模式#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;SDL_cond *continue_read_thread; // 当读取数据队列满了后进入休眠时,可以通过该condition唤醒读线程
} VideoState;

MyAVPacketList

和名字一样 就是 解封装出来的packet 用链表的形式开始保存 啦啦啦啦
可以理解为是队列的⼀个节点。可以通过其 next 字段访问下⼀个节点

重点!!! 1 serial

ffplay中多处⽤到serial的概念,主要⽤来区分是否连续 数据,每做⼀次seek,该serial都会做+1的递增,以区分不同的播放序列。

说人话就是: 就是 seek 一次以后 以前的队列中的东西当然就不能用了呗 应该放弃的放弃 要free 的 free

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

PacketQueue

这里这个packeQueue 逻辑和前面800行代码播放器 逻辑一样
保存一些基本信息

这个packetqueue 是 同时作用于 视频 音频 和 字幕的
⾳频、视频、字幕流都有⾃⼰独⽴的PacketQueue

这⾥也看到了serial字段, MyAVPacketList的serial字段的赋值来⾃PacketQueue的serial,每个PacketQueue的serial是独⽴的。

typedef struct PacketQueue {MyAVPacketList   *first_pkt, *last_pkt;  // 队首,队尾指针int        nb_packets;   // 包数量,也就是队列元素数量int        size;         // 队列所有元素的数据大小总和int64_t       duration; // 队列所有元素的数据播放持续时间int     abort_request; // 用户退出请求标志int       serial;         // 播放序列号,和MyAVPacketList的serial作用相同,但改变的时序稍微有点不同SDL_mutex *mutex;     // 用于维持PacketQueue的多线程安全(SDL_mutex可以按pthread_mutex_t理解)SDL_cond  *cond;      // 用于读、写线程相互通知(SDL_cond可以按pthread_cond_t理解)
} PacketQueue;

PacketQueue的函数们

太多了 写了一篇新的 连接在这里

Frame

真正存储解码后⾳视频数据的结构体为AVFrame ,存储字幕则使⽤AVSubtitle,该Frame的设计是为了⾳频、视频、字幕帧通⽤,所以Frame结构体的设计类似AVFrame,部分成员变量只对不同类型有作⽤,⽐ 如sar只对视频有作⽤。 ⾥⾯也包含了serial播放序列(每次seek时都切换serial),sar(图像的宽⾼⽐(16:9,4:3…),该值来 ⾃AVFrame的sample_aspect_ratio变量。

typedef struct Frame {AVFrame        *frame;         // 指向数据帧AVSubtitle  sub;            // 用于字幕int      serial;             // 帧序列,在seek的操作时serial会变化double      pts;            // 时间戳,单位为秒double        duration;       // 该帧持续时间,单位为秒int64_t        pos;            // 该帧在输入文件中的字节位置int     width;              // 图像宽度int      height;             // 图像高读int      format;             // 对于图像为(enum AVPixelFormat),// 对于声音则为(enum AVSampleFormat)AVRational    sar;            // 图像的宽高比(16:9,4:3...),如果未知或未指定则为0/1int     uploaded;           // 用来记录该帧是否已经显示过?int     flip_v;             // =1则垂直翻转, = 0则正常播放
} Frame;

FrameQueue

FrameQueue是⼀个环形缓冲区(ring buffer),是⽤数组实现的⼀个FIFO。数组⽅式的环形缓冲区适合于 事先明确了缓冲区的最⼤容量的情形。 ffplay中创建了三个frame_queue:⾳频frame_queue,视频frame_queue,字幕frame_queue。每⼀ 个frame_queue⼀个写端⼀个读端,写端位于解码线程,读端位于播放线程。

typedef struct FrameQueue {Frame queue[FRAME_QUEUE_SIZE];        // FRAME_QUEUE_SIZE  最大size, 数字太大时会占用大量的内存,需要注意该值的设置int      rindex;                         // 读索引。待播放时读取此帧进行播放,播放后此帧成为上一帧int        windex;                         // 写索引int       size;                           // 当前总帧数int     max_size;                       // 可存储最大帧数int       keep_last;                      // = 1说明要在队列里面保持最后一帧的数据不释放,只在销毁队列的时候才将其真正释放int      rindex_shown;                   // 初始化为0,配合keep_last=1使用SDL_mutex   *mutex;                     // 互斥量SDL_cond  *cond;                      // 条件变量PacketQueue  *pktq;                      // 数据包缓冲队列
} FrameQueue;

FrameQueue的设计⽐如PacketQueue复杂,引⼊了读取节点但节点不出队列的操作、读取下⼀节点也不出队列等等的操作,FrameQueue具体操作函数见连接xxx

在这里插入代码片

AudioParams

int          bytes_per_sec;          // 一秒时间的字节数,比如采样率48Khz,2 channel,16bit,则一秒48000*2*16/8=192000
typedef struct AudioParams {int          freq;                   // 采样率int           channels;               // 通道数int64_t       channel_layout;         // 通道布局,比如2.1声道,5.1声道等enum AVSampleFormat fmt;            // 音频采样格式,比如AV_SAMPLE_FMT_S16表示为有符号16bit深度,交错排列模式。int         frame_size;             // 一个采样单元占用的字节数(比如2通道时,则左右通道各采样一次合成一个采样单元)int          bytes_per_sec;          // 一秒时间的字节数,比如采样率48Khz,2 channel,16bit,则一秒48000*2*16/8=192000
} AudioParams;

struct Decoder解码器封装

typedef struct Decoder {AVPacket pkt;PacketQueue *queue;         // 数据包队列AVCodecContext  *avctx;     // 解码器上下文int        pkt_serial;         // 包序列int       finished;           // =0,解码器处于工作状态;=非0,解码器处于空闲状态int     packet_pending;     // =0,解码器处于异常状态,需要考虑重置解码器;=1,解码器处于正常状态SDL_cond    *empty_queue_cond;  // 检查到packet队列空时发送 signal缓存read_thread读取数据int64_t       start_pts;          // 初始化时是stream的start timeAVRational start_pts_tb;       // 初始化时是stream的time_baseint64_t     next_pts;           // 记录最近一次解码后的frame的pts,当解出来的部分帧没有有效的pts时则使用next_pts进行推算AVRational    next_pts_tb;        // next_pts的单位SDL_Thread    *decoder_tid;       // 线程句柄
} Decoder;

ffplay-主要数据结构分析相关推荐

  1. ffplay的数据结构分析

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

  2. 【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )

    文章目录 一.GOT 表数据结构分析 二.函数根据 GOT 表进行跳转的流程 一.GOT 表数据结构分析 GOT 表分为 222 部分 , 一部分在 调用者部分 ( 可执行文件 ) 中 , 一部分在 ...

  3. 硬盘扇区数据结构分析

    来自 http://hi.baidu.com/qtycr/blog/item/f6cc9b2b74e2d7fee7cd40da.html 硬盘扇区数据结构分析 初买来一块硬盘,我们是没有办法使用的,你 ...

  4. 音视频从入门到精通——FFmpeg数据结构分析

    FFmpeg数据结构分析 FFmpeg解码流程 重要结构体之间的关系 AVFormatContext iformat:输入媒体的AVInputFormat,比如指向AVInputFormat ff_f ...

  5. 数据结构分析:红黑树、B+树

    数据结构分析:红黑树.B+树 前言 常见的数据结构大概分为以下8种,作为一个开发人员,数据结构是内功之一. 本文参考了网络上相关知识,加之自己的理解.简单说明红黑树.B+树的特性. 1. 二叉搜索树( ...

  6. MYSEE:Sp数据结构分析初稿

    以前写了MYSEE 服务器端源码分析文档,主要是对其中的消息机制(sp,cp,ts,之间的交互)的分析.因为CU抽风,发表的文章无故给我删除了 ,所以这个不是完整的 Sp 数据结构分析(初稿) 一:准 ...

  7. 商品分类目录数据结构分析

    商品分类目录数据结构分析 说明:一般电商网站的商品分类信息,都是3级标题. 划分: 1级标题-2级标题-3级标题 标题是有所属关系的 /1.查询一级商品分类信息/ SELECT * FROM tb_i ...

  8. SICK LMS511开发及数据结构分析、坐标转换

    SICK LMS511开发及数据结构分析.坐标转换 最近公司有新上的项目,开始接触激光扫描仪,型号SICK LMS511. 获取数据 在网上看了一些资料,有通过SICK自带的软件看了一下激光扫描仪的配 ...

  9. 【JAVA进阶】java中的集合(番外篇3)- HashMap源码底层数据结构分析

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  10. 【Apache OFBiz 系列】OFBiz的数据结构分析(五)

    前面一系列的数据结构分析分别整理了ofbiz的通用模块.网站信息模块.内容模块.调查问卷模块,但是一直未呈现信息化中的主体--人员,这篇文章全面整理了ofbiz的会员管理模块数据模型,ofbiz对会员 ...

最新文章

  1. 数据结构——树、二叉树、森林、哈夫曼树、字符串模式匹配
  2. Java异常简单介绍
  3. echarts如何获取后端的值_Echarts 获取后台数据 使用后台数据展示 柱形图
  4. 自建Hive数据仓库跨版本迁移到阿里云Databricks数据洞察
  5. iScroll学习笔记
  6. 中点坐标公式 矩形_压轴题必备|中考数学“动点坐标”问题,这个万能解法人人都能学会!...
  7. 使用 Xunit.DependencyInjection 改造测试项目
  8. 一文教你使用java开发一款推箱子游戏
  9. python分析服务器日志_python实现web服务器日志分析脚本
  10. java中sql语句怎么把开始和结束时间作为参数写sql查询_JDBC数据库连接怎么操作?...
  11. 分区字段不在SQL过滤中,悲剧
  12. 量化交易策略matlab交易方案,【策略分享】Matlab量化交易策略源码分享
  13. samba add new smbpasswd recycle
  14. mysql之为表添加一个字段并设定默认值
  15. loadrunner 及 QTP 下载地址
  16. 线性代数学习心得(二)矩阵的逆和矩阵变换
  17. XJTU_选课小助手
  18. 今日头条推荐算法原理全文详解之六
  19. ae合成设置快捷键_这些AE技巧,相见恨晚
  20. ffmpeg 合并音乐+视频报错之[mp4 @ 000002b9bcfa1ec0] Non-monotonous DTS in output stream 0:1; previous: 1136042

热门文章

  1. 基于java的飞机大战雷电游戏的开发与设计#毕业设计
  2. 【转】WIFI-Direct(Wifi直连)、AirPlay、DLAN、Miracast功能介绍
  3. 利用EDA365 SKILLS 生成gerber和手动生成
  4. 3dsmax动画六、骨骼调整及蒙皮。
  5. 算法分析与设计课程总结
  6. 利用ENVI绘制土地利用图
  7. 游戏音效是用什么软件做的?
  8. java网上购物系统_Java Web 应用教程——网上购物系统的实现
  9. 2020-09-24L1-016 查验身份证 (15分) 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,
  10. Linux GCC编译详细