(未完成)ffmpeg tutorial 4 (播放视频) 解读

来源:互联网 发布:阿里云搭建网站多久 编辑:程序博客网 时间:2024/05/18 00:05

 

基础:显示过程


1) 设定显示区域,//video mode
2) Yuv覆盖 //
3) 显示图像//rgb格式转yuv,操作力实际操作用 yv12来填充yuv420,
4) 绘制图像//位置,高度,宽度,缩放大小的矩阵参数。
一届理解:桌子,白底桌布,原始花纹,变化的花纹。

 

【待补充 SDL 显示过程 csdn】


关于播放声音的小结


1) 声音的回调函数,尤其那个参数的设置过程(get decode...)
2) Event事件,联系到消费者、生产者问题。其他处理比如为了预防死循环,自己sleep让系统调度,以方便做其他事
3) 一个数据结构,audioq,队列。
4) 声音播放对应的函数。


关于播放图像的小结


1) 程序的调用框架
Video_thread  ----call--->     可能  queue_picture(分配空间 等)...............         send event............收到事件,执行 alloc_picture;

                           --->(空间分配好后的事件处理)         【待补充】

Main timer--->      schedule_refresh ----> send event......................... 收到事件,执行 video_refresh_timer--->播放函数video_play

待更新一个函数调用框架



2) 大量的使用事件机制


a) 刷新事件(细心的话,你会发现schedule_refresh触发了timer事件,而后者又调用了schedule_refresh,所谓的形成回路;在此我推断这里的定时器一般情形只能执行一次)
b) 退出事件
c) 处理 生产者 消费者 问题(细心的话,会发现针对 video_q有两处上锁,有两处解锁,具体的情景后续分析)


3) 图像的处理过程在这里 “形散而神不散”,说句俗话,就是跟tutorial 2不一样,这里 buffer 申请,yuv覆盖申请,拷贝buffer 到yuv覆盖 等等都独立成函数;


4) 有一个全局的数据结构,videoState ,所谓的大数据结构,这个结构涵盖大部分的信息;


5) 在使用音频队列的基础上,同时普及视频队列;


 场景分析 简要交互过程

 
Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3197C video_thread,【wait】while (!vp->allocated && !is->quit)
Function: alloc_picture(void *), Thread: 0x31844 主线程,【signal】,分配ok
Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3197C video_thread,验证一下,写到满?
Function: video_display(VideoState *), Thread: 0x31844 主线程,play core,SDL_DisplayYUVOverlay
Function: video_refresh_timer(void *), Thread: 0x31844 主线程, size=1,验证 是否会 消费到底
Function: video_refresh_timer(void *), Thread: 0x31844 主线程,【signal】timer中 队列数目减少

Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3197C video_thread,【wait】while (!vp->allocated && !is->quit)
Function: alloc_picture(void *), Thread: 0x31844 主线程,【signal】,分配ok
Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3197C video_thread,验证一下,写到满?
【线程调度,再次发现没有分配,下一条记录可以发现】

//Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3197C video_thread,【wait】while (!vp->allocated && !is->quit)


Function: video_display(VideoState *), Thread: 0x31844 主线程,play core,SDL_DisplayYUVOverlay
Function: video_refresh_timer(void *), Thread: 0x31844 主线程, size=1,验证 是否会 消费到底
Function: video_refresh_timer(void *), Thread: 0x31844 主线程,【signal】timer中 队列数目减少

我在下面的图片,对每一帧的过程 进行了标示,细心甚至会发现第4帧出现时  有一个申请内存的小插曲。

 




场景分析二:一个完整的交互过程

 

直接上图。




//分析如上,不同,主要就是timer 还没有触发,所以就执行下一次的wait.

//其实场景切换,不过与vedio_thread,主线程的分配,还有timer的播放;

. ps:如果wait满足的话,那么下一次还是在原来线程里执行;

鉴定真实的wait就是下一次执行不在这个线程里;

一句话,这里的wait表示执行到这块代码,并不表示一定会wait.



队列的数目,从来没有超过1,这就是作者说的有了就要用,没有就要取;想起这里使用的同步量是mutex;

其他:程序中有2个wait, 但下面这个wait从来没有执行过,后续可以增加分析


while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) {        SDL_CondWait(is->pictq_cond, is->pictq_mutex);    }





唯一长期执行的wait是如下代码:

  /* wait until we have a picture allocated */        SDL_LockMutex(is->pictq_mutex);        while (!vp->allocated && !is->quit) {            SDL_CondWait(is->pictq_cond, is->pictq_mutex);        }        SDL_UnlockMutex(is->pictq_mutex);



 最后一帧的处理


那就是当所有的12帧图像播放完毕后,代码的行为。以下是log


经过分析,这是图像的最后一帧,当前的vedio picture已经分配,所以不会出现分配的情景。


Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3AD14 video_thread, 队列增加 size=1
Function: video_display(VideoState *), Thread: 0x3ABEC 主线程,play core,SDL_DisplayYUVOverlay
Function: video_refresh_timer(void *), Thread: 0x3ABEC 主线程, size=1,验证 是否会 消费到底
Function: video_refresh_timer(void *), Thread: 0x3ABEC 主线程,【signal】timer中 队列数目减少

Function: queue_picture(VideoState *, AVFrame *), Thread: 0x3AD14 video_thread, 队列增加 size=1
Function: video_display(VideoState *), Thread: 0x3ABEC 主线程,play core,SDL_DisplayYUVOverlay
Function: video_refresh_timer(void *), Thread: 0x3ABEC 主线程, size=1,验证 是否会 消费到底
Function: video_refresh_timer(void *), Thread: 0x3ABEC 主线程,【signal】timer中 队列数目减少


其他问题


(有同事提出,可能哪个锁没有打开,此时待后续分析)
具体说,就是上锁的位置就是那个vp 没有分配的情形,
解锁就是alloc 完毕,或者播放完毕的情形;至于播放完毕会导致锁解开的情形待分析。

解决方案:就是在上锁的位置打log,看上锁代码的log和后续的关键区log 是否会相继出现。\

如果是相继出现,就证明queue_picture里没有出现 锁mutex等待的情形;//mutex要么0要么1



视频刷新的时间 可能会打乱播放的顺序。待考证
解决方案:那就是修改播放刷新的时间,


小结:


这是第一次使用日志的方式处理异步调试
针对关键区域的断点放置,是个学问,针对读取变量或者锁的轮询有不同的方案;
一个视频流完整的对应过程(忽略细节不同),如下代码:,一句话,找到开头和结尾。

Function: queue_picture(VideoState *, AVFrame *), Thread: 0x48CB0 video_thread,【wait】while (!vp->allocated && !is->quit)
...忽略
Function: video_refresh_timer(void *), Thread: 0x48AEC 主线程,【signal】timer中 队列数目减少



附件:完整的调试log(待补充,将会在csdn网盘补充)

0 0
原创粉丝点击