年如果问什么技术领域最火?毫无疑问:音视频。年远程办公和在线教育的强势发展,都离不开音视频的身影,视频会议、在线教学、娱乐直播等都是音视频的典型应用场景。
更加丰富的使用场景更需要我们考虑如何提供更多的可配置能力项,比如分辨率、帧率、码率等,以实现更好的用户体验。本文将主要从“分辨率”展开具体分享。
如何实现自定义编码分辨率
我们先来看看“分辨率”的定义。分辨率:是度量图像内像素数据量多少的一个参数,是衡量一帧图像或视频质量的关键指标。分辨率越高,图像体积(字节数)越大,画质越好。对于一个YUVi格式、分辨率p的视频流来说,一帧图像的体积为xx1.5x8//≈23.73Mbit,帧率30,则1s的大小是30x23.73≈.9Mbit。可见数据量之大,对码率要求之高,所以在实际传输过程中就需要对视频进行压缩编码。因此,视频采集设备采集出的原始数据分辨率我们称采集分辨率,实际送进编码器的数据分辨率我们就称之为编码分辨率。
视频画面是否清晰、比例是否合适,这些都会直接影响用户体验。摄像头采集分辨率的选择是有限的,有时我们想要的分辨率并不能直接通过摄像头采集到。那么,根据场景配置合适编码分辨率的能力就至关重要了。如何将采集到的视频转换成我们想要的编码分辨率去发送?这就是我们今天的主要分享的内容。
WebRTC是Google开源的,功能强大的实时音视频项目,市面上大多开发者都是基于WebRTC构建实时音视频通信的解决方案。在WebRTC中各个模块都有很好的抽象解耦处理,对我们进行二次开发非常友好。在我们构建实时音视频通信解决方案时,需要去了解和学习WebRTC的设计思想及代码模块,并具备二次开发和扩展的能力。本文我们基于WebRTCRelease72版本,聊聊如何实现自定义编码分辨率。
首先,我们思考下面几个问题:
视频数据从采集到编码发送,其Pipeline是怎样的?怎么根据设置的编码分辨率选择合适的采集分辨率?怎么能得到想要的编码分辨率?本文内容也将从以上三点展开具体分享。
视频数据的Pipeline
首先,我们来了解一下视频数据的Pipeline。视频数据由VideoCapturer产生,VideoCapturer采集数据后经过VideoAdapter处理,然后经由VideoSource的VideoBroadcaster分发给注册的VideoSink,VideoSink即编码器EncoderSink和本地预览PreviewSink。
对视频分辨率来说,流程是:将想要的分辨率设置给VideoCapturer,VideoCapturer选择合适的分辨率去采集,原始的采集分辨率数据再经过VideoAdapter计算,不符合预期后再进行缩放裁剪得到编码分辨率的视频数据,将数据再送进编码器编码后发送。
这里就有两个关键性问题:
VideoCapturer如何选择合适的采集分辨率?VideoAdapter如何将采集分辨率转换成编码分辨率?如何选择合适的采集分辨率
采集分辨率的选择
WebRTC中对视频采集抽象出一个Base类:videocapturer.cc,我们把抽象称为VideoCapturer,在VideoCapturer中设置参数属性,比如视频分辨率、帧率、支持的像素格式等,VideoCapturer将根据设置的参数,计算出最佳的采集格式,再用这个采集格式去调用各个平台的VDM(VideoDeviceModule,视频硬件设备模块)。具体的设置如下:
代码摘自WebRTC中src/media/base/videocapturer.h
根据设置的参数,有时GetBestCaptureFormat()并不能得到比较符合我们设置的采集格式,因为不同的设备采集能力不同,iOS、Android、PC、Mac原生的摄像采集和外置USB摄像采集对分辨率的支持是不同的,尤其外置USB摄像采集能力参差不齐。因此,我们需要对GetFormatDistance()稍作调整以满足我们的需求,下面我们就来聊聊具体应该如何进行代码调整以满足需求。
选择策略源码分析
我们先分析一下GetFormatDistance()的源码,摘取部分代码:
代码摘自WebRTC中src/media/base/videocapturer.cc
我们主要