1, Animoji
Animoji是在iPhone X上的动画表情。是iPhone在十周年特别版iPhone X发布的新功能。其使用面部识别传感器来检测用户面部表情变化, 并最终生成可爱的3D动画表情符号, 目前只能在iMessage中使用. 但有人破解了Animoji, 并提取相应的头文件供大家在产品中使用.
2, Factime
FaceTime 是苹果公司iOS和Mac OS X内置的一款视频通话软件,通过Wi-Fi或者蜂窝数据接入互联网,在两个装有FaceTime 的设备之间实现视频通话. 用通俗的话讲就是视频电话.
之前在试用Animoji的时候觉得很神奇, 在想如果和实时的视频聊天配合起来应该很有意思, 大概花了半天的时间, 写出了这个小玩具.
首先Animoji:
在网上找到有人封装好的Animoji 头文件 github.com/efremidze/A…, 研究了之后发现并没有可以获得Animoji 一帧的接口, 我继续把这个库完善了一下, 暴漏出了可以获得每一帧数据的接口. 我fork 了一份代码在这里 github.com/notedit/Ani…, 修改之后的代码也已经PR到原来的项目中.
帧数据处理:
后面在做视频传输的时候需要CVPixelBuffer, 而我们这里从Animoji里只能获得CIImage, 另外我们需要对取得的数据做一次缩放处理, 避免图片过大. 这里主要使用了CoreImage 和 CVPixelBuffer的一些处理, 直接上代码:
-(CVPixelBufferRef)processCIImage:(CIImage*)image {
@autoreleasepool {
[filter setValue:image forKey:kCIInputImageKey];
CIImage *outimage = [filter outputImage];
NSLog(@"outimage widthxheight %dx%d", (int)outimage.extent.size.width,(int)outimage.extent.size.height);
CVPixelBufferRef outPixelBuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
(int)outimage.extent.size.width,
(int)outimage.extent.size.height,
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ,
(__bridge CFDictionaryRef) @{(__bridge NSString *) kCVPixelBufferIOSurfacePropertiesKey: @{}},
&outPixelBuffer);
if (status != 0) {
NSLog(@"CVPixelBufferCreate error %d", (int)status);
CFRelease(outPixelBuffer);
return nil;
}
[ciContext render:outimage toCVPixelBuffer:outPixelBuffer bounds:outimage.extent colorSpace:nil];
return outPixelBuffer;
}
}
到这里你已经可以很happy的拿到Animoji的帧数据了.
视频通话:
为了快速完成这一部分我直接使用了我们的音视频通话SDK — dotEngine , 支持自定义的YUV 数据输入, 然后我们就可以很愉快的把上一步拿到的数据喂给这个SDK.
大概的流程如下
dotEngine = DotEngine.sharedInstance(with:self)
localStream = DotStream(audio: true, video: true, videoProfile: DotEngineVideoProfile.DotEngine_VideoProfile_360P, delegate: self)videoCapturer = DotVideoCapturer()localStream.videoCaptuer = videoCapturer// some other code
let image = self.animoji.snapshot(with:self.animoji.frame.size)
let ciimage = CIImage(image: image!)
let pixelBuffer = self.convert.processCIImage(ciimage)
if pixelBuffer != nil {
self.videoCapturer?.send(pixelBuffer!.takeUnretainedValue(), rotation: VideoRotation.roation_0)
pixelBuffer?.release()
}运行效果如下图:
完整的代码在 github.com/dotEngine/a…
我们的音视频通讯SDK dotEngine github.com/dotEngine