ffmpeg編解碼視頻導致噪聲增大的一種解決方法


一、前言

       ffmpeg在視音頻編解碼領域算是一個比較成熟的解決方案了。公司的一款視頻編輯軟件正是基於ffmpeg做了二次封裝,並在此基礎上進行音視頻的編解碼處理。然而,在觀察編碼后的視頻質量時,發現圖像幀出現了較為明顯噪聲,類似於水面波紋一般散發開來,在運動場景下尤為明顯。初步懷疑應該是碼率太低導致的畫面失真。於是增大碼率重新編碼一次,噪聲仍然很明顯。基本上可以排除是碼率太低的問題。

       仔細觀察原片,也可發現有類似的圖像噪聲出現,但是微乎其微到幾乎不可察覺。於是再次懷疑是ffmpeg在編解碼的過程中,將這個噪聲放大了,導致最終產出的視頻出現了明顯的噪聲干擾。而代碼中我們正好用了ffmpeg實現的swscale()方法。在正式編碼之前,我們需要用該方法將YUV數據轉換為RGB數據來處理。因此,此處調用正是症結所在。

二、解決方案

      前面說了,在正式編碼之前我們需要將YUV數據轉換為RGB來渲染。既然是swscale()方法的原因,那么是否可以在渲染的時候通過多重采樣來降低圖形噪聲呢?事實上還是too young too simple。開啟多重采樣還是沒有卵用。我們的渲染庫又必須采用RGB格式的數據,難道不用swscale()方法么?是否有替代品呢?

      這么一搜索還真有!google開源的 libyuv庫正是這樣一個替代品,可以用於在RGB和YUV之間進行轉換:
libyuv is an open source project that includes YUV scaling and conversion functionality.

      於是馬上下載下來進行測試。

git clone https://chromium.googlesource.com/libyuv/libyuv

  網上關於libyuv的資料貌似比較少,官方也沒看到什么文檔。好在項目也不大,把頭文件看一看,基本上可以了解具體的使用方法的。使用CMake生成VS編譯工程,可以產出靜態庫和動態庫兩種類型:

      使用實例:

      

// yuv420p -> bgr24
if (mOutputFormat == AV_PIX_FMT_BGR24)
{
	I420ToRGB24(src_frame->data[0], 
		src_frame->linesize[0], 
		src_frame->data[1], 
		src_frame->linesize[1], 
		src_frame->data[2], 
		src_frame->linesize[2],
		scale_frame->data[0],
		mOutputWidth*3,
		mOutputWidth,
		mOutputHeight);
}
// bgr24 -> yuv420p
else if (mOutputFormat == AV_PIX_FMT_YUV420P)
{
	RGB24ToI420(src_frame->data[0],
		src_frame->linesize[0],
		scale_frame->data[0],
		scale_frame->linesize[0],
		scale_frame->data[1],
		scale_frame->linesize[1],
		scale_frame->data[2],
		scale_frame->linesize[2],
		mOutputWidth,
		mOutputHeight);
}
else { 
	return false;
}

  接口非常簡潔明了。編碼的視頻效果對比如下(上圖是libyuv實現,下圖是ffmpeg的swscale實現):

      可以看出來,下圖有類似於水面波紋一樣的噪聲,而上圖則幾乎不可見。

三、參考鏈接

1. https://trac.ffmpeg.org/wiki/HWAccelIntro


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM