Chamadas de áudio e vídeo WebRTC - obtenha o efeito de filtro de beleza de vídeo GPUImage
A imagem do efeito de embelezamento GPUImage na chamada de áudio e vídeo WebRTC é a seguinte
Você pode dar uma olhada na
versão anterior do serviço ossrs, você pode conferir: https://blog.csdn.net/gloryFlow/article/details/132257196
Antes de implementar o iOS para fazer chamadas de áudio e vídeo ossrs, você pode verificar : https://blog.csdn.net /gloryFlow/article/details/132262724
Chamadas de áudio e vídeo WebRTC antes de alta resolução não exibem o problema de tela, você pode visualizar: https://blog.csdn.net/gloryFlow/article /details/132262724
modifique a taxa de bits no SDP, você pode visualizar: https://blog.csdn.net/gloryFlow/article/details/132263021
1. O que é GPUImage?
GPUImage é uma estrutura de código aberto para processamento de imagens baseada em OpenGL no iOS. Possui um grande número de filtros integrados e uma arquitetura flexível. Ele pode implementar facilmente várias funções de processamento de imagens com base nele.
GPUImage contém vários filtros, não vou usar tantos aqui, uso GPUImageLookupFilter e GPUImagePicture
Existe uma função de filtro GPUImageLookupFilter em GPUImage que é especialmente processada para tabelas de pesquisa. Usando esta função, você pode adicionar filtros diretamente às imagens. código mostrado abaixo
/**
GPUImage中有一个专门针对lookup table进行处理的滤镜函数GPUImageLookupFilter,使用这个函数就可以直接对图片进行滤镜添加操作了。
originalImg是你希望添加滤镜的原始图片
@param image 原图
@return 处理后的图片
*/
+ (UIImage *)applyLookupFilter:(UIImage *)image lookUpImage:(UIImage *)lookUpImage {
if (lookUpImage == nil) {
return image;
}
UIImage *inputImage = image;
UIImage *outputImage = nil;
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage];
//添加滤镜
GPUImageLookupFilter *lookUpFilter = [[GPUImageLookupFilter alloc] init];
//导入之前保存的NewLookupTable.png文件
GPUImagePicture *lookupImg = [[GPUImagePicture alloc] initWithImage:lookUpImage];
[lookupImg addTarget:lookUpFilter atTextureLocation:1];
[stillImageSource addTarget:lookUpFilter atTextureLocation:0];
[lookUpFilter useNextFrameForImageCapture];
if([lookupImg processImageWithCompletionHandler:nil] && [stillImageSource processImageWithCompletionHandler:nil]) {
outputImage= [lookUpFilter imageFromCurrentFramebuffer];
}
return outputImage;
}
Isso requer lookUpImage, a lista de imagens é a seguinte
Porque o git da demonstração ainda não foi resolvido
Aqui está usando applyLomofiFilter para tentar o efeito novamente
Vários métodos em SDApplyFilter.m
+ (UIImage *)applyBeautyFilter:(UIImage *)image {
GPUImageBeautifyFilter *filter = [[GPUImageBeautifyFilter alloc] init];
[filter forceProcessingAtSize:image.size];
GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image];
[pic addTarget:filter];
[pic processImage];
[filter useNextFrameForImageCapture];
return [filter imageFromCurrentFramebuffer];
}
/**
Amatorka滤镜 Rise滤镜,可以使人像皮肤得到很好的调整
@param image image
@return 处理后的图片
*/
+ (UIImage *)applyAmatorkaFilter:(UIImage *)image
{
GPUImageAmatorkaFilter *filter = [[GPUImageAmatorkaFilter alloc] init];
[filter forceProcessingAtSize:image.size];
GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image];
[pic addTarget:filter];
[pic processImage];
[filter useNextFrameForImageCapture];
return [filter imageFromCurrentFramebuffer];
}
/**
复古型滤镜,感觉像旧上海滩
@param image image
@return 处理后的图片
*/
+ (UIImage *)applySoftEleganceFilter:(UIImage *)image
{
GPUImageSoftEleganceFilter *filter = [[GPUImageSoftEleganceFilter alloc] init];
[filter forceProcessingAtSize:image.size];
GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image];
[pic addTarget:filter];
[pic processImage];
[filter useNextFrameForImageCapture];
return [filter imageFromCurrentFramebuffer];
}
/**
图像黑白化,并有大量噪点
@param image 原图
@return 处理后的图片
*/
+ (UIImage *)applyLocalBinaryPatternFilter:(UIImage *)image
{
GPUImageLocalBinaryPatternFilter *filter = [[GPUImageLocalBinaryPatternFilter alloc] init];
[filter forceProcessingAtSize:image.size];
GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image];
[pic addTarget:filter];
[pic processImage];
[filter useNextFrameForImageCapture];
return [filter imageFromCurrentFramebuffer];
}
/**
单色滤镜
@param image 原图
@return 处理后的图片
*/
+ (UIImage *)applyMonochromeFilter:(UIImage *)image
{
GPUImageMonochromeFilter *filter = [[GPUImageMonochromeFilter alloc] init];
[filter forceProcessingAtSize:image.size];
GPUImagePicture *pic = [[GPUImagePicture alloc] initWithImage:image];
[pic addTarget:filter];
[pic processImage];
[filter useNextFrameForImageCapture];
return [filter imageFromCurrentFramebuffer];
}
Usando o filtro retro GPUImageSoftEleganceFilter, parece que as antigas renderizações de Shanghai Beach são as seguintes
Usando GPUImageLocalBinaryPatternFilter para preto e branco a imagem é a seguinte
O efeito do uso de GPUImageMonochromeFilter é o seguinte
2. WebRTC implementa processamento de filtro de vídeo em chamadas de áudio e vídeo
Antes de realizar a chamada de áudio e vídeo do ossrs no lado iOS, você pode conferir: https://blog.csdn.net/gloryFlow/article/details/132262724
Isso já tem um código completo, aqui está um ajuste temporário.
Aponte para o proxy do delegado do RTCCameraVideoCapturer
- (RTCVideoTrack *)createVideoTrack {
RTCVideoSource *videoSource = [self.factory videoSource];
self.localVideoSource = videoSource;
// 如果是模拟器
if (TARGET_IPHONE_SIMULATOR) {
if (@available(iOS 10, *)) {
self.videoCapturer = [[RTCFileVideoCapturer alloc] initWithDelegate:self];
} else {
// Fallback on earlier versions
}
} else{
self.videoCapturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:self];
}
RTCVideoTrack *videoTrack = [self.factory videoTrackWithSource:videoSource trackId:@"video0"];
return videoTrack;
}
Implemente o método didCaptureVideoFrame de RTCVideoCapturerDelegate
#pragma mark - RTCVideoCapturerDelegate处理代理
- (void)capturer:(RTCVideoCapturer *)capturer didCaptureVideoFrame:(RTCVideoFrame *)frame {
// DebugLog(@"capturer:%@ didCaptureVideoFrame:%@", capturer, frame);
// 调用SDWebRTCBufferFliter的滤镜处理
RTCVideoFrame *aFilterVideoFrame;
if (self.delegate && [self.delegate respondsToSelector:@selector(webRTCClient:didCaptureVideoFrame:)]) {
aFilterVideoFrame = [self.delegate webRTCClient:self didCaptureVideoFrame:frame];
}
// 操作C 需要手动释放 否则内存暴涨
// CVPixelBufferRelease(_buffer)
// 拿到pixelBuffer
// ((RTCCVPixelBuffer*)frame.buffer).pixelBuffer
if (!aFilterVideoFrame) {
aFilterVideoFrame = frame;
}
[self.localVideoSource capturer:capturer didCaptureVideoFrame:frame];
}
Em seguida, chame SDWebRTCBufferFliter para obter o efeito de filtro.
Realize a renderização ((RTCCVPixelBuffer *)frame.buffer).pixelBuffer, onde EAGLContext e CIContext são usados
EAGLContext é um identificador ou contexto de desenho OpenGL. Antes de desenhar a visualização, você precisa especificar o uso do contexto criado para desenhar.
CIContext é usado para renderizar CIImage e aplicar a cadeia de filtros que atua no CIImage aos dados da imagem original. Preciso converter UIImage em CIImage aqui.
O código específico é implementado da seguinte forma
SDWebRTCBufferFliter.h
#import <Foundation/Foundation.h>
#import "WebRTCClient.h"
@interface SDWebRTCBufferFliter : NSObject
- (RTCVideoFrame *)webRTCClient:(WebRTCClient *)client didCaptureVideoFrame:(RTCVideoFrame *)frame;
@end
SDWebRTCBufferFliter.m
#import "SDWebRTCBufferFliter.h"
#import <VideoToolbox/VideoToolbox.h>
#import "SDApplyFilter.h"
@interface SDWebRTCBufferFliter ()
// 滤镜
@property (nonatomic, strong) EAGLContext *eaglContext;
@property (nonatomic, strong) CIContext *coreImageContext;
@property (nonatomic, strong) UIImage *lookUpImage;
@end
@implementation SDWebRTCBufferFliter
- (instancetype)init
{
self = [super init];
if (self) {
self.eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
self.coreImageContext = [CIContext contextWithEAGLContext:self.eaglContext options:nil];
self.lookUpImage = [UIImage imageNamed:@"lookup_jiari"];
}
return self;
}
- (RTCVideoFrame *)webRTCClient:(WebRTCClient *)client didCaptureVideoFrame:(RTCVideoFrame *)frame {
CVPixelBufferRef pixelBufferRef = ((RTCCVPixelBuffer *)frame.buffer).pixelBuffer;
// CFRetain(pixelBufferRef);
if (pixelBufferRef) {
CIImage *inputImage = [CIImage imageWithCVPixelBuffer:pixelBufferRef];
CGImageRef imgRef = [_coreImageContext createCGImage:inputImage fromRect:[inputImage extent]];
UIImage *fromImage = nil;
if (!fromImage) {
fromImage = [UIImage imageWithCGImage:imgRef];
}
UIImage *toImage;
toImage = [SDApplyFilter applyMonochromeFilter:fromImage];
//
// if (toImage == nil) {
// toImage = [SDApplyFilter applyLookupFilter:fromImage lookUpImage:self.lookUpImage];
// } else {
// toImage = [SDApplyFilter applyLookupFilter:fromImage lookUpImage:self.lookUpImage];
// }
if (toImage == nil) {
toImage = fromImage;
}
CGImageRef toImgRef = toImage.CGImage;
CIImage *ciimage = [CIImage imageWithCGImage:toImgRef];
[_coreImageContext render:ciimage toCVPixelBuffer:pixelBufferRef];
CGImageRelease(imgRef);//必须释放
fromImage = nil;
toImage = nil;
ciimage = nil;
inputImage = nil;
}
RTCCVPixelBuffer *rtcPixelBuffer =
[[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBufferRef];
RTCVideoFrame *filteredFrame =
[[RTCVideoFrame alloc] initWithBuffer:rtcPixelBuffer
rotation:frame.rotation
timeStampNs:frame.timeStampNs];
return filteredFrame;
}
@end
Até agora você pode ver o efeito específico do filtro de beleza de vídeo GPUImage na chamada de áudio e vídeo WebRTC.
3. Resumo
Chamadas de áudio e vídeo WebRTC - obtenha o efeito de filtro de beleza de vídeo GPUImage. Use GPUImage principalmente para processar a tela de vídeo CVPixelBufferRef, gerar RTCVideoFrame a partir do CVPixelBufferRef processado e chamar o método didCaptureVideoFrame implementado em localVideoSource. Existem muitos conteúdos e a descrição pode ser imprecisa, por favor, me perdoe.
Endereço deste artigo: https://blog.csdn.net/gloryFlow/article/details/132265842
Registros de aprendizagem, continue melhorando a cada dia.