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

赞 (0) 评论 分享 ()