FFmpeg獲取視頻正確的寬高比

說起音視頻開發,很多問題不遇到是不知道的。就在昨天,有一朋友問我:我的視頻解析出來 “寬*高=640*480”,明顯寬高比是4:3的,但是實際要正常播放時,寬高比是:16:9的,市面上大部分視頻播放器都能按照16:9正常播放,少數是按照4:3播放的,而他自己根據640:480計算出來也是4:3的,這樣畫面就是錯誤的變形的了。

其實在沒發現這個問題之前,我也是完全不知道還有這種情況的,沒辦法已經問我了,總得拿自己的播放器試一下,萬一是他計算錯了呢,然兒我自己的播放器也是4:3的,這就尷尬了,只有想辦法解決這個問題,下面是我沒解決這個問題之前的播放畫面:

從圖中,很明顯的能看出畫面被變形了,那麼開始解決問題吧。

爲了測試,分別用VLC和愛奇藝播放器來測試,測試結果他們都是以16:9來渲染的畫面,這樣再次說明自己的計算比例(用的是寬高比)是錯誤的,用MediaInfo查看視頻信息,也是一樣的16:9:

雖然知道了這個問題,但是用VLC、愛奇藝播放器和MediaInfo並不能解決問題的。不過還是有一點點收穫,知道了“Diaplay aspect ratio”這個名詞,然後加上ffempg關鍵字網上搜索這個詞,非常驚喜的發現竟然FFmpeg的AVStream裏面有display_aspect_ratio這個屬性,那麼解決這個問題就簡單了,直接通過這個屬性獲取比值就可以了(當然不可能這麼簡單)。最爲直觀的我們還是打印出來看一下:

LOG_E("display_aspect_ratio: %d:%d", pFormatCtx->streams[i]->display_aspect_ratio.den, pFormatCtx->streams[i]->display_aspect_ratio.num);

看到結果是很崩潰的,竟然是0:0,欲哭無淚啊。只有再找其他線索了。思考中(難道FFmpeg不支持)......

既然是FFmpeg解碼,那麼ffplay也是用的FFmpeg,那麼就用ffplay來播放一下就知道了,非常幸運的是ffplay也是16:9正常播放的:

這就看到了光明瞭,說明FFmpeg是能解決這個問題的(那是肯定能的),然後就去看ffplay的日誌,發現了ffplay竟然打印出來了dar(display_aspect_ratio)值的,附帶的還打印了sar(sample_aspect_ratio)值的,而且前面還有“Input”、“Metadata”等日誌:

那麼解決這個問題就很簡單了,看ffplay的源碼找這個日誌打印的地方(雖然我基於FFmpeg已經寫出了播放器,但還真的沒去看過ffplay的源碼,不過對FFmpeg的api也算是熟悉,看源碼也不是很難)。源碼過程如下:

1、找到ffplay的main方法,這就是入口(基於版本:FFmpeg v3.3.2):

2、入口找到了,就要看ffplay日誌打印的過程是怎樣的,通過日誌可以發現是:先打印輸入的url地址和一些支持的解碼器類型,對應於日誌中“Input”開頭那一句,那麼開始找這個(因爲這就涉及到音視頻解碼流程、解碼線程知識了,這裏就不細說了,只列出相關方法跳轉路徑):

這樣我們就順利的找到了日誌中的“Input”信息了。

3、按照順序再找“Metadata”日誌,在“av_dump_format”方法中開始找:

這樣我們就找到了“Metadata”日誌了,但是這個日誌所在方法裏面並沒有我們需要的信息,所以繼續返回“av_dump_format”中開始往下找:

4、找到我們需要的信息:

這樣我們就可以看到日誌中的數據是怎麼得到的了,是通過函數“av_reduce”得到的實際的“dar”,函數實現還是蠻複雜的:

av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
                  st->codecpar->width  * (int64_t)st->sample_aspect_ratio.num,
                  st->codecpar->height * (int64_t)st->sample_aspect_ratio.den,
                  1024 * 1024);

就是這一句,就能從“sar”、寬和高中得到“dar”,(哈哈有點興奮,馬上驗證一下):

av_reduce(&wlVideo->dvr.num, &wlVideo->dvr.den,
                              pFormatCtx->streams[i]->codecpar->width  * (int64_t)pFormatCtx->streams[i]->sample_aspect_ratio.num,
                              pFormatCtx->streams[i]->codecpar->height * (int64_t)pFormatCtx->streams[i]->sample_aspect_ratio.den,
                              1024 * 1024);
                    LOG_E("display_aspect_ratio: %d:%d", wlVideo->dvr.den, wlVideo->dvr.num);

 

這樣就正常把視頻渲染出來了。

總結:問題我們是解決不完的,但是我們要培養解決問題的能力,首先分析問題,然後想辦法測試問題,當在測試中找到突破口時就要去驗證,去找源碼等來解決,這不是一蹴而就的,而是一個慢慢成長的過程。

**** 這裏給出我的(Android)視頻庫地址:wlmedia

測試視頻下載 密碼:0ok7

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章