### 基础:显示过程
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帧出现时 有一个申请内存的小插曲。
### ![](https://box.kancloud.cn/2016-02-22_56cae4b7e4165.jpg)
场景分析二:一个完整的交互过程
直接上图。
![](https://box.kancloud.cn/2016-02-22_56cae4b80e031.jpg)
//分析如上,不同,主要就是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网盘补充)