H264 視訊檔案如何縮放解析度?

語言: CN / TW / HK

前幾天在知識星球裡面有位朋友請教問題:如何將 H264 視訊縮放解析度?

具體的問題詳情如下:

將 800x600 的 H264 檔案縮放成 400x300 的,大概的流程是先解碼,得到 AVFrame 後對其做縮放操作,然後再編碼,得到 AVPacket 後寫入檔案即可。

思路沒錯的話,就可以看看這位同學的寫法了,擷取部分程式碼:

大家一起來挑錯,看看遇到問題一般解決思路是什麼樣的。

問題一

首先提問者一直在 av_parser_parse2 函式處報錯。

遇到這種情況不要慌,必現的問題先斷點一下看看輸入引數是否正確。

IDE 的斷點除錯是常見操作了,工程師進階必備。

我沒有除錯提問者的程式碼,但也懷疑輸入引數 pkt 有異常,順著程式碼往下看,果然在函式最末尾幾行呼叫了 av_packet_free 方法。

一般通過 av_packet_alloc 去申請 AVPacket ,而 av_packet_free 就是直接釋放並置 nullptr ,這樣下次在執行 av_parser_parse2 方法肯定就掛了。

void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return;

av_packet_unref(*pkt);
av_freep(pkt);
}

所以這裡肯定有問題呀。

問題二

接著看其他問題,想要縮放解析度,可是程式碼截圖中並沒有看到任何縮放的程式碼,直接將解碼後的 AVFrame 送去編碼就可以縮放嗎?

我猜想,提問者應該在設定編碼的 AVCodecContext 時就已經指定好了縮放後的解析度 400x300 ,但送去編碼的 AVFrame 還是 800x600 的,這樣編碼的結果會是縮放的嗎?

經過試驗證明,編碼的視訊確實是 400x300 的,但畫面卻是從 800x600 擷取的一部分,並沒有顯示完全,所以這樣是不能起到縮放效果的。

要縮放還是得用 FFmpeg 中 SwsContext 提供的方法。

// 初始化
swsCtx = sws_getContext(800,600,AV_PIX_FMT_YUV420P,400,300,AV_PIX_FMT_YUV420P,SWS_BILINEAR, nullptr, nullptr,nullptr);
// 縮放
sws_scale(swsCtx,decodeFrame->data,decodeFrame->linesize,0,decodeFrame->height,encodeFrame->data,encodeFrame->linesize);

將縮放後的 AVFrame 送去編碼就可以得到正確的效果了。

問題三

再仔細看提問者的程式碼,有必要在解碼 avcodec_receive_frame 之前呼叫 av_frame_make_writable 嗎?

由於提問者的程式碼本身不對,其實也不用呼叫 av_frame_make_writable 的,正常的縮放應該要兩個 AVFrame 的,解碼的 AVFrame 不需要,反而編碼的 AVFrame 需要保證可寫。

以上就是關於這次提問的一些問題反饋了,我自己也實現了一個簡單的 H264 視訊檔案縮放解析度的例子, 完整的程式碼就放在知識星球裡 了。

關於播放器實踐的專欄,後續大部分進展都會放在知識星球裡面了,尤其是原始碼會在星球內同步更新,當然也會挑一些乾貨在公眾號同步。

目前 音視訊開發進階知識星球 還在讓利中, 非常低的價格就可以獲得業內一線開發人員的答疑解惑

與其在 群裡面提問石沉大海,不如來星球有問必答 ,而且這個價格還是管一年的哦,一年的時間可以說是相當划算了。

同時星球內非常歡迎大家提問,尤其是我不會的問題,我會去找業內好朋友請教,既回答了你的問題又幫助了我提高。

想要加入的可以通過掃如下二維碼進星球哦,iPhone 使用者如果不能訪問小程式的話,也可以加我微信 ezglumes 拉你進星球。

一個音視訊領域專業問答的小圈子!

加我微信 ezglumes 拉你入技術交流群

推薦閱讀:

音視訊開發工作經驗分享 || 視訊版

OpenGL ES 學習資源分享

開通專輯 | 細數那些年寫過的技術文章專輯

Android NDK 免費視訊線上學習!!!

你想要的音視訊開發資料庫來了

推薦幾個堪稱教科書級別的 Android 音視訊入門專案

覺得不錯,點個在看唄~