• 1366阅读
  • 5回复

[经验分享]iOS网络通话本地回调画面(美颜)相关的格式转换 [复制链接]

上一主题 下一主题
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-10-10
— 本帖被 云信小小 执行加亮操作(2016-10-10) —
1. kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 转换为 kCVPixelFormatType_32BGRA 格式

某些 iOS 第三方美颜 SDK 不接受 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange 格式的 pixelBuffer,这里分享把它转成
kCVPixelFormatType_32BGRA 格式的示例代码。

VideoBufferConverter.zip (43 K) 下载次数:78


用到了云信改过的第三方库libyuv,二进制已经包含在云信SDK里面,需要把include里面libyuv的头文件都放到你得工程目录下,并在你得工程中正确设置 Header Search Paths。
这个改过的libyuv只能通过c++/object c++ 源文件调用,如果感觉不适,请自行编译libyuv,和云信并不冲突。


NTESVideoBufferConverter 类提供创建 BGRA 格式的pixelBuffer/sampleBuffer 的方法,创建并使用完以后需要你自己手动释放。


比如收到云信本地画面回调的sampleBuffer以后:
  1. CMSampleBufferRef sampleBufferBGRA = [NTESVideoBufferConverter createBGRASampleBufferFromNV12:sampleBuffer];
  2. if (sampleBufferBGRA) {
  3.     //use the sampleBuffer
  4.     CFRelease(sampleBufferBGRA);
  5. }


2. 第三方的yuv420p(I420)转换成sampleBuffer给云信发送

某些 iOS 第三方美颜 SDK 输出的画面是yuv420p/I420 格式的,这里贴一段把它转成 pixelBuffer的示例代码:
  1. - (CVPixelBufferRef)i420FrameToPixelBuffer:(NVSI420Frame *)i420Frame
  2. {
  3.     if (i420Frame == nil) {
  4.         return NULL;
  5.     }
  6.     CVPixelBufferRef pixelBuffer = NULL;
  7.     NSDictionary *pixelBufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
  8.     [NSDictionary dictionary], (id)kCVPixelBufferIOSurfacePropertiesKey, nil];
  9.     CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
  10.                                                                           i420Frame.width,
  11.                                                                           i420Frame.height,
  12.                                                                           kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
  13.                                                                           (__bridge CFDictionaryRef)pixelBufferAttributes,
  14.                                                                           &pixelBuffer);
  15.     
  16.     if (result != kCVReturnSuccess) {
  17.         NVSLogErr(@"Failed to create pixel buffer: %d", result);
  18.         return NULL;
  19.     }
  20.     result = CVPixelBufferLockBaseAddress(pixelBuffer, 0);
  21.     
  22.     if (result != kCVReturnSuccess) {
  23.         CFRelease(pixelBuffer);
  24.         NVSLogErr(@"Failed to lock base address: %d", result);
  25.         return NULL;
  26.     }
  27.     uint8 *dstY = (uint8 *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
  28.     int dstStrideY = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
  29.     uint8* dstUV = (uint8*)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
  30.     int dstStrideUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
  31.     int ret = libyuv_nvs::I420ToNV12([i420Frame dataOfPlane:NVSI420FramePlaneY], [i420Frame strideOfPlane:NVSI420FramePlaneY],
  32.                                                             [i420Frame dataOfPlane:NVSI420FramePlaneU], [i420Frame strideOfPlane:NVSI420FramePlaneU],
  33.                                                             [i420Frame dataOfPlane:NVSI420FramePlaneV], [i420Frame strideOfPlane:NVSI420FramePlaneV],
  34.                                                             dstY, dstStrideY, dstUV, dstStrideUV,
  35.                                                             i420Frame.width, i420Frame.height);
  36.     CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
  37.     if (ret) {
  38.         NVSLogErr(@"Error converting I420 VideoFrame to NV12: %d", result);
  39.         CFRelease(pixelBuffer);
  40.         return NULL;
  41.     }
  42.     
  43.     return pixelBuffer;
  44. }

NVSI420Frame 是我自己的内部格式,你需要从你的第三方 SDK 获取 yuv 数据的地址data、宽高信息width、height,以及stride。一般来说,各个分量地址的计算如下:
plane0 = data
plane1 = data + stride * height
plane2 = plane1 + stride * height / 4

stride0 = stride
stride1 = stride2 = stride /2

有兴趣的同学可以百度下yuv数据格式,方便理解 :)

pixelBuffer 转成 sampleBuffer 的方法可以参考上面 NTESVideoBufferConverter 里面的实现。

用到了云信改过的 libyuv,头文件请去上面的压缩包里面获取。







只看该作者 沙发  发表于: 2016-10-10
顶顶顶

只看该作者 板凳  发表于: 2016-11-03
请问一下有对CMSampleBufferRef数据进行美颜的示例吗,想用GPUImage进行处理,可不知道如何下手.网上也没有找到相关的美颜示例.

只看该作者 地板  发表于: 2016-11-04
回 huanglei1926 的帖子
huanglei1926:
请问一下有对CMSampleBufferRef数据进行美颜的示例吗,想用GPUImage进行处理,可不知道如何下手.网上也没有找到相关的美颜示例.

[attachment=875]

加我,给你发一个美颜的示例吧

只看该作者 4楼 发表于: 2016-11-29
回 hzfangtiankui 的帖子
hzfangtiankui:[图片]
加我,给你发一个美颜的示例吧 (2016-11-04 11:00) 

已加好友,麻烦给发一个GPUImage美颜的示例哈

只看该作者 5楼 发表于: 01-16
回 hzfangtiankui 的帖子
hzfangtiankui:[图片]
加我,给你发一个美颜的示例吧 (2016-11-04 11:00) 

加您好友了。正在做视频的处理美颜效果。麻烦您给发一下demo。万分感谢