本篇分析一下ffplay的数据结构。

(1)VideoState

VideoState结构体,正如名字的含义,管理了一些全局的播放状态。

typedef struct VideoState {SDL_Thread *read_tid;   //读文件线程idAVInputFormat *iformat; //输入格式/*丢弃标志,在切换音视频流和关闭流时,会置为1。当为1时,读文件线程和解码线程会退出循环或返回错误,以此来终止线程。*/int abort_request;int force_refresh;  //强制刷新int paused; //是否暂停int last_paused;int queue_attachments_req;  //是否请求attachments(对于mp3来说,就是封面图片)int seek_req;   //seek(前进/后退)标志,为1时表示要seekint seek_flags; //按字节还是时间seekint64_t seek_pos;   //seek目标位置int64_t seek_rel;   //seek增量int read_pause_return;AVFormatContext *ic;int realtime;/*ffplay提供了三种音视频同步的方法:视频同步到音频,音频同步到视频,音视频同步到外部时钟,*/Clock audclk;   //音频时钟Clock vidclk;   //视频时钟Clock extclk;   //外部时钟/*解码后,frame要存于队列中。*/FrameQueue pictq;   //视频帧队列FrameQueue subpq;   //字幕帧队列FrameQueue sampq;   //音频帧队列/*三种解码器,音频解码器、视频解码器、字幕解码器*/Decoder auddec;Decoder viddec;Decoder subdec;int audio_stream;   //音频流indexint av_sync_type;   //音视频同步类型,默认视频同步到音频//音频时钟,值为当前音频帧的pts+当前帧所含采样点所占的时间double audio_clock;int audio_clock_serial;//音频时钟序列,seek操作会改变serial值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音频缓冲区大小//指向待播放的音频缓冲区,后续将会拷贝进sdl进行播放。如果经过重采样,则指向audio_buf1,否则指向frame.data[0]uint8_t *audio_buf;uint8_t *audio_buf1;    //重采样的音频指针unsigned int audio_buf_size; //audio_buf的大小unsigned int audio_buf1_size;   //audio_buf1的大小//由于audio_buf向SDL缓冲区拷贝时,可能一次拷贝不完,所以用audio_buf_index来记录上次拷贝的位置。int audio_buf_index;//audio_buf中未拷入SDL中的数据大小,用于计算时钟值int audio_write_buf_size;int audio_volume;   //音量int muted;  //是否静音struct AudioParams audio_src;   //音频参数struct AudioParams audio_tgt;   //sdl支持的音频参数struct SwrContext *swr_ctx;int frame_drops_early;  //丢弃的packet数量。packet还未解码时,满足一定条件则丢弃int frame_drops_late;   //丢弃的frame数量。如果视频落后音频太多,则丢弃frameenum 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;    //字幕流indexAVStream *subtitle_st;  //字幕流PacketQueue subtitleq;  //字幕packet队列double frame_timer; //最后一帧播放的时刻double frame_last_returned_time;double frame_last_filter_delay;int video_stream;   //视频流indexAVStream *video_st; //视频流PacketQueue videoq; //视频packet队列double max_frame_duration;      // maximum duration of a frame - 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;int step;int last_video_stream, last_audio_stream, last_subtitle_stream;//读文件线程的线程互斥锁的条件变量SDL_cond *continue_read_thread;
} VideoState;

(2)PacketQueue

PacketQueue是用链表构造的队列。节点是MyAVPacketList。存放音视频、字幕的packet。

typedef struct PacketQueue {//第一、最后一个节点MyAVPacketList *first_pkt, *last_pkt;//队列中packet的数量int nb_packets;//队列中所有packet所占的字节,包括packet.data。int size;//队列中所有packet的时长总和int64_t duration;//丢弃标志int abort_request;//队列的序列号,每一次seek操作,此值都会+1int serial;//队列锁SDL_mutex *mutex;//条件变量SDL_cond *cond;
} PacketQueue;typedef struct MyAVPacketList {//数据AVPacket pkt;//下一节点指针struct MyAVPacketList *next;/*节点的序列号,每一次seek操作后,新放入的节点序列号和队列的序列号相同,这样如果节点的序列号和队列的序列号不一样的话,就要丢弃不解码,只解码seek操作后的节点。*/int serial;
} MyAVPacketList;

(3)FrameQueue

FrameQueue是用数组构造的环形队列,用于存储解码后的音视频frame。

typedef struct FrameQueue {Frame queue[FRAME_QUEUE_SIZE];  //节点数组int rindex; //读索引int windex; //写索引int size;   //队列中的帧的总数int max_size;   //可存储的最大帧数int keep_last;  //是否保留上一已播放的帧,音频和视频为真,字幕为假int rindex_shown;   //值为1,和keep_last配合使用,用于访问下一待播放的帧SDL_mutex *mutex;SDL_cond *cond;PacketQueue *pktq;  //帧队列对应的packet队列
} FrameQueue;typedef struct Frame {AVFrame *frame;    //帧数据AVSubtitle sub;int serial; //帧序列号,seek操作会改变此值,用于判断seek操作后的相关逻辑double pts; //理论显示时间double duration;    //此帧的播放时长int64_t pos;          /* byte position of the frame in the input file */int width;    //宽int height;    //高int format;    //格式AVRational sar;int uploaded;   int flip_v;
} Frame;

(4)Decoder

包含了解码所需要的相关信息。

typedef struct Decoder {AVPacket pkt;   //要解码的packetPacketQueue *queue; //解码器所对应的packet队列AVCodecContext *avctx;int pkt_serial; //pkt的序列号int finished;   //是否解码结束的标志,结束时,finished和queue.serail相等int packet_pending; //send_packet特定错误,此标志为1,表示应该再发送一遍pkt。SDL_cond *empty_queue_cond;int64_t start_pts;AVRational start_pts_tb;int64_t next_pts;AVRational next_pts_tb;SDL_Thread *decoder_tid;    //解码线程id
} Decoder;

(5)Clock

typedef struct Clock {double pts;           /* 上一帧(已播放的最后一帧)的显示时间戳 */double pts_drift;     /* 等于pts减去更新pts时的系统时间 */double last_updated;    //更新pts时的系统时间double speed;int serial;           /* 此时钟的序列号,用于处理seek操作后的一些逻辑 */int paused;int *queue_serial;    /* 指向packet队列的serial */
} Clock;

34.FFmpeg学习笔记 - ffplay源码解读2之数据结构相关推荐

  1. 35.FFmpeg学习笔记 - ffplay源码解读3之读文件

    本篇文章看看ffplay是如何读取packet放入队列中的. 一.先看入口函数: int main(int argc, char **argv) {VideoState *is;...av_init_ ...

  2. yolov1-v5学习笔记及源码解读

    目录 深度学习网络分类 评价指标 原理 yolov1 yolov2 yolov3 yolov4 yolov5 源码解读(v3为例) 深度学习网络分类 深度学习经典检测方法 通常分为 two-stage ...

  3. Opencv学习笔记 - imread源码解读

    一.打开图片流程分析 1.读取图片头,进行解码器的寻找 2.根据参数flags,确定图像通道和是否缩放 3.给解码器指定缩放参数和源 4.使用解码器读取图像的头,确保没有问题,失败则输出错误并返回 5 ...

  4. sheng的学习笔记-Vector源码分析

    概述 Vector底层也是数组,跟ArrayList很像(先看下ArrayList,再看Vector会很轻松),ArrayList可参考下文,并且由于效率低,已经被淘汰了,大概瞅瞅得了 sheng的学 ...

  5. PixHawk学习笔记 之 源码浅析——mc_pos_control.cpp——task_main

    注意:基于"Firmware-1.6.0rc1" 献上固件源码分享链接:https://pan.baidu.com/s/1kUPocmF 密码:j55a 自己边学边写的,一定有错, ...

  6. 狂神说SpringCloud学习笔记(附带源码和笔记)

    狂神说Spring Cloud Netflix笔记-01(服务注册与发现) 狂神说Spring Cloud Netflix笔记-02(Eureka集群的搭建 ) 狂神说Spring Cloud Net ...

  7. android源码编译 简书,android学习笔记之源码编译

    编译环境 1.需要Ubuntu 64bit,建议Ubuntu14.04 64-bit 2.安装openJDK7 $ sudo apt-get update $ sudo apt-get install ...

  8. dubbo学习笔记 一 源码编译

    前面学习了netty和rocketmq,当然前面的文章还会继续更新,继续往下写 2016 没几天了,我打算写下dubbo 2017 继续深入源码,大家有啥问题 都可以一起来讨论 源码搭建 下载源码 同 ...

  9. as工程放到源码编译_方舟编译器学习笔记2 源码编译

    根据方舟官方文档编译了方舟编译器的源码,在这里简单谈谈其源码的编译过程: 1.操作系统环境: 64位版本的Ubuntu(官方推荐Ubuntu 16.04).我自己本身就有Ubuntu 16.04的虚拟 ...

最新文章

  1. 古巴雪茄高希霸世纪1.2.3.4.5.6.半世纪7款雪茄的区别?
  2. idea lombok安装后还是标红_小辣椒神器Lombok
  3. mysql 平均响应时间_Percona-Server/MySQL响应时间统计
  4. 基于机器学习的捡球机器人设计与实现(探索)第2篇——7步完成opencv的安装(20190112)
  5. WebService系列(三)--创建自己的WebService
  6. .Net Core 集成 Kafka
  7. 力扣429. N 叉树的层序遍历(JavaScript)
  8. python实现用户登录界面代码_python编辑用户登入界面的实现代码
  9. Docker网络之bridge0详解
  10. 1.3.1 互联网的边缘部分(资源子网)
  11. XShell配置跳板机访问最终目标主机
  12. Python 从入门到入魔
  13. r语言变量长度不一致怎么办_R语言实现数据离散化方法总结
  14. 排序算法——希尔排序的图解、代码实现以及时间复杂度分析
  15. python求所有参数的乘积_python 通过可变参数计算n个数的乘积方法
  16. 「智慧医疗」HL7消息解析实战Demo
  17. 【历史上的今天】10 月 29 日:互联网的正式诞生;MariaDB 发布首个版本;“天河一号”研制成功
  18. OID 用于公共设备
  19. Linux/redhat 有线网络配置
  20. WACV2020:开源基于深度学习方法DeOccNet用来去除透视光场中的前景遮挡

热门文章

  1. 双相机 单目三维重建
  2. 牛人分析如何高效学习嵌入式
  3. 文件管理android2.3,华为手机文件管理器(com.huawei.hidisk) - 10.11.11.301 - 应用 - 酷安...
  4. Unity - Timeline 之 Muting tracks(屏蔽轨道)
  5. 新冠疫情历史数据(COVID-19-Data)
  6. Unity Mesh(五) Mesh 立方体Cube贴图以及六个面分别贴不同的图片
  7. sql怎么撤回update_如何写好5000行的SQL代码
  8. 计算机显示没有可以的ip地址,w7电脑提示没有有效ip地址怎么处理
  9. mysq coun(*)时为啥这么慢
  10. linuxci‘pang磁盘管理的实验报告