内容简介:直播SDK提供了默认美颜,效果一般,不支持Mac。项目要求能自定义美颜,并支持Mac,iOS双端。找了好多的文章,试了都不行,谷歌了几篇文章,加上自己摸索,凑起来总算搞通了。写下来给要接直播美颜SDK的伙伴捋一捋,PS:玩音视频的各路大神别见笑。查了SDK暴露出来的接口,跟系统AVFoundation的回调方法一致,直播SDK提供了Block回调,返回封装好的CMSampleBufferRef数据,然后在Block里把CMSampleBufferRef数据传输到SDK内部方法推流。采取的美颜滤镜(非第三方
直播SDK提供了默认美颜,效果一般,不支持Mac。项目要求能自定义美颜,并支持Mac,iOS双端。找了好多的文章,试了都不行,谷歌了几篇文章,加上自己摸索,凑起来总算搞通了。写下来给要接直播美颜SDK的伙伴捋一捋,PS:玩音视频的各路大神别见笑。
了解情况
查了SDK暴露出来的接口,跟系统AVFoundation的回调方法一致,直播SDK提供了Block回调,返回封装好的CMSampleBufferRef数据,然后在Block里把CMSampleBufferRef数据传输到SDK内部方法推流。
- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer { // do something [[SDK sharedSDK].netCallManager sendVideoSampleBuffer:sampleBuffer]; } 复制代码
大概思路:
- 取出图像数据CVPixelBufferRef,时间戳CMSampleTimingInfo
- 对CVPixelBufferRef进行美颜处理
- 重新封装CMSampleBufferRef发送到SDK方法内推流
采取的美颜滤镜(非第三方SDK,支持Mac,iOS):
- iOS自带的CIFilter (单一滤镜多,貌似没现成组合美颜滤镜)
- 强大的GPUImage(有现成组合过成的GPUImageBeautifyFilter美颜滤镜,且Demo有各种效果预览)
GPUImage用法 input -》do something -》output
网上很多关于GPUImage的用法是对视频文件,或者直接用Camera作为输入源。缺少直接对一帧图像进行处理,所以问题在于如何对CVPixelBufferRef进行滤镜处理,然后得到处理完的CVPixelBufferRef数据。对为此特意查阅很多资料(参考的网址在最后),并翻了翻GPUImage的代码。
-
GPUImage Framework的文件很清晰,Sources输入源,Filters是各种滤镜,Outputs输出源。
用法基本可以列为管道式,addTarget 相当于 -》: [Sources初始化对象 addTarget:Filter]; // 输入源 -》滤镜 [filter addTarget:output输出源对象]; // 滤镜 -》输出源 复制代码
-
输入源采用GPUImageMovie,因为里面有一个- (void)processMovieFrame:(CMSampleBufferRef)movieSampleBuffer方法,支持输入一帧进行处理。(注意初始化Movie一定要用initWithAsset的方法,传入nil,否则内部的GPUImageContext不会初始化)
-
滤镜采取已经组合成美颜滤镜的GPUImageBeautifyFilter,它是一个FilterGroup。
-
输出的时候, 使用GPUImageRawDataOutput,newFrameAvailableBlock里取出图像数据,屏幕一片灰色 。如果用GPUImageView直接addSubview显示,能成功显示用滤镜处理过的画面。
证明数据已经成功处理,在GPUImageMovie的processMovieFrame方法里也找到newFrameAvailableBlock的回调,回调确实有执行。
问题则是我在lockFramebufferForReading和unlockFramebufferAfterReading中间读取帧数据的操作不对,想到这边读数据这么复杂,就想着这个渲染完的数据到底放在哪里了,有没有别的办法取出?
在前面说过GPUImageBeautifyFilter是一个GPUImageFilterGroup,GPUImageFilterGroup的父类是GPUImageOutput,这就意味着,即使我不添加任何output的target,数据也是可以拿到的。
再翻了下资料,GPUImageOutput的头文件,发现一个frameProcessingCompletionBlock,这个跟我原来的processMovieFrame好像很对应。网上也有说怎么从GPUImageOutput取出帧数据。那就行了,直接从GPUImageBeautifyFilter里取,不用设置output的Target,大功告成。
代码代码代码
**说了一堆废话,不好意思。献上代码:**GPUImageBeautifyFilter代码在参考链接的最后一个
// 初始化Filter和GPUImageMovie _beautifyFilter = [[GPUImageBeautifyFilter alloc] init]; _gpumovie = [[GPUImageMovie alloc] initWithAsset:nil]; // 初始化内部数据结构 [_gpumovie addTarget:_beautifyFilter]; //连接过滤器 复制代码
// 重新封装CMSampleBufferRef,并交给SDK推流 // 如果是rtmp协议传输视频流,自己用VideoToolBox封装。 - (void)sendVideoSampleBuffer:(CVPixelBufferRef)bufferRef time:(CMSampleTimingInfo)timingInfo { CMSampleBufferRef newSampleBuffer = NULL; CMFormatDescriptionRef outputFormatDescription = NULL; CMVideoFormatDescriptionCreateForImageBuffer( kCFAllocatorDefault, bufferRef, &outputFormatDescription ); OSStatus err = CMSampleBufferCreateForImageBuffer( kCFAllocatorDefault, bufferRef, true, NULL, NULL, outputFormatDescription, &timingInfo, &newSampleBuffer ); if(newSampleBuffer) { [[SDK sharedSDK].netCallManager sendVideoSampleBuffer:newSampleBuffer]; }else { NSString *exceptionReason = [NSString stringWithFormat:@"sample buffer create failed (%i)", (int)err]; @throw [NSException exceptionWithName:NSInvalidArgumentException reason:exceptionReason userInfo:nil]; } } 复制代码
最重要的处理部分:
// 此方法由直播SDK负责回调或者代理执行 // 自定义美颜时最好把直播SDK默认美颜关闭 - (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer { CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); //取出帧数据/时间戳 -》处理帧数据美颜 -》根据时间戳与像素数据重新封装包: [_gpumovie processMovieFrame:sampleBuffer]; // kCVPixelFormatType_420YpCbCr8BiPlanarFullRange 可能需要检查 CMSampleTimingInfo timingInfo = { .duration = CMSampleBufferGetDuration(sampleBuffer), .presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer), .decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer) }; __weak typeof(self) weakSelf = self; [_beautifyFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) { GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput; glFinish(); [weakSelf sendVideoSampleBuffer: [imageFramebuffer getRenderTarget] time:timingInfo]; }]; } 复制代码
参考:
- stackoverflow.com/questions/2…
- www.jianshu.com/p/dde412cab…
- www.jianshu.com/p/a20995e1a…
- blog.csdn.net/weixin_4243… ( GPUImageBeautifyFilter代码 )
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- iOS给一张照片美颜
- 美颜重磅技术之 GPUImage 源码分析
- iOS实现实时美颜滤镜并获取原图
- 美颜相机中的设计模式——装饰者模式
- 开发者回应 iPhone XS 美颜:没内置滤镜、算法可改进
- 算法美颜过的月亮还是真实的月亮吗?华为P月算法深陷舆论漩涡
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解SPARK
耿嘉安 / 机械工业出版社 / 2016-1-1 / 99
《深入理解SPARK:核心思想与源码分析》结合大量图和示例,对Spark的架构、部署模式和工作模块的设计理念、实现源码与使用技巧进行了深入的剖析与解读。 《深入理解SPARK:核心思想与源码分析》一书对Spark1.2.0版本的源代码进行了全面而深入的分析,旨在为Spark的优化、定制和扩展提供原理性的指导。阿里巴巴集团专家鼎力推荐、阿里巴巴资深Java开发和大数据专家撰写。 本书分为......一起来看看 《深入理解SPARK》 这本书的介绍吧!