使用WebRTC直播时出现画面曝光异常解决方案

·  阅读 1847

最近在使用WebRTC进行直播时,遇到了主播画面曝光过度的问题,查了很久原因才查到,估分享出来避免大家采坑

  1. iOS中的像素格式

iOS视频采集支持三种数据格式输出:420v,420f,BGRA

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v', /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, video-range (luma=[16,235] chroma=[16,240]).  baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange  = '420f', /* Bi-Planar Component Y'CbCr 8-bit 4:2:0, full-range (luma=[0,255] chroma=[1,255]).  baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrBiPlanar struct */ 
kCVPixelFormatType_32BGRA                       = 'BGRA',     /* 32 bit BGRA */
复制代码

其中kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange中的YpCbCr分别指Y、U、V三个分量,即YUV格式的数据,后面的8指以8bit来保存一个分量,420指使用YUV的4:2:0格式存储。BiPlanar指双平面模式,即将Y和UV分开存储,VideoRange指颜色空间

420f和420v都是YUV格式的。YUV是一种颜色编码方法,分为三个分量,Y表示亮度(Luma),也称为灰度。U和V表示色度(chroma)描述色彩与饱和度 用于WebRTC编解码的像素格式是kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 420f和420v的区别在于Color Space。f指Full Range,v指Video Range。 Full Range的Y分量取值范围是[0,255] Video Range的Y分量取值范围是[16,235] 从采集编码到解码渲染,整个过程中,颜色空间的设置都必须保持一致,如果采集用了Full Range 而播放端用Video Range,那么就有可能看到曝光过度的效果。

  1. WebRTC70 branch会产生画面曝光过度问题原因

在WebRTC70 branch中,使用了iOS的新的activeFormat设置fps等formate格式,我们在选取AVCaptureDeviceFormat时,只判断了分辨率和帧率,未判断OutputPixelFormat,所以会选择第一个符合分辨率和帧率的formate格式进行设置,是Video Range格式,

Format: <AVCaptureDeviceFormat: 0x174006680 'vide'/'420v' 1280x 720, { 3-120 fps}, fov:58.080, binned, supports vis, max zoom:52.00 (upscales @1.16), AF System:1, ISO:34.0-1088.0, SS:0.000012-0.333333>
Format: <AVCaptureDeviceFormat: 0x174006680 'vide'/'420f' 1280x 720, { 3-120 fps}, fov:58.080, binned, supports vis, max zoom:52.00 (upscales @1.16), AF System:1, ISO:34.0-1088.0, SS:0.000012-0.333333>

复制代码

因为iOS系统formate数组中取到的数组中包含420v和420f格式,所以要进行选择,WebRTC是内部使用kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,所以要选取420f, 如果选择错误,因Full Range和Video Range的Y分量取值范围不同,会导致后续美颜,和显示对曝光值进行错误处理,从而导致曝光异常

修改代码

for (AVCaptureDeviceFormat *format in formats) {
        CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
        if ((dimension.width == targetWidth &&
            dimension.height == targetHeight) || (dimension.width == targetHeight && dimension.height == targetWidth)) {
          for (AVFrameRateRange* frameRateRange in
               [format videoSupportedFrameRateRanges]) {
            if (frameRateRange.minFrameRate <= self.fps &&
                self.fps <= frameRateRange.maxFrameRate) {
              if (CMFormatDescriptionGetMediaSubType(format.formatDescription) == [self preferredOutputPixelFormat]) {
                selectedFormat = format;
              }
              break;
            }
          }
        }
        if(selectedFormat){
          break;
        }
      }


复制代码
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改