### 基礎:顯示過程
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網盤補充)