Llamada de audio y video WebRTC: realice el efecto de filtro de belleza de video GPUImage iOS

Llamadas de audio y video WebRTC: realice el efecto de filtro de belleza de video GPUImage

La imagen del efecto de embellecimiento GPUImage en la llamada de audio y video WebRTC es la siguiente

inserte la descripción de la imagen aquí

Puede echar un vistazo a
la versión anterior del servicio ossrs, puede consultarlo: https://blog.csdn.net/gloryFlow/article/details/132257196
Antes de implementar iOS para realizar llamadas de audio y video de ossrs, puede verificarlo : https://blog.csdn.net /gloryFlow/article/details/132262724
Las llamadas de audio y video WebRTC antes de que la alta resolución no muestre el problema de la pantalla, puede ver: https://blog.csdn.net/gloryFlow/article /details/132262724
modifique la tasa de bits en SDP, puede ver: https://blog.csdn.net/gloryFlow/article/details/132263021

1. ¿Qué es GPUImage?

GPUImage es un marco de código abierto para el procesamiento de imágenes basado en OpenGL en iOS. Tiene una gran cantidad de filtros integrados y una arquitectura flexible. Puede implementar fácilmente varias funciones de procesamiento de imágenes sobre esta base.

GPUImage contiene varios filtros, no usaré tantos aquí, uso GPUImageLookupFilter y GPUImagePicture

Hay una función de filtro GPUImageLookupFilter en GPUImage que se procesa especialmente para tablas de búsqueda. Con esta función, puede agregar filtros directamente a las imágenes. El código se muestra a continuación.

/**
 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;
}

Esto requiere lookUpImage, la lista de imágenes es la siguiente

inserte la descripción de la imagen aquí

Porque el git de la demostración no se ha resuelto por el momento.

Aquí se utiliza applyLomofiFilter para probar el efecto nuevamente.

Varios métodos en 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 el filtro retro GPUImageSoftEleganceFilter, parece que las representaciones antiguas de Shanghai Beach son las siguientes
inserte la descripción de la imagen aquí

Usando GPUImageLocalBinaryPatternFilter en blanco y negro, la imagen es la siguiente

inserte la descripción de la imagen aquí

El efecto de usar GPUImageMonochromeFilter es el siguiente

inserte la descripción de la imagen aquí

2. WebRTC implementa procesamiento de filtro de video en llamadas de audio y video

Antes de realizar la llamada de audio y video de ossrs en el lado de iOS, puedes consultar: https://blog.csdn.net/gloryFlow/article/details/132262724
Esto ya tiene el código completo, aquí hay un ajuste temporal.

Señale el proxy del delegado de 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;
}

Implementar el 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];
}

Luego llame a SDWebRTCBufferFliter para realizar el efecto de filtro.
Realice la representación ((RTCCVPixelBuffer *)frame.buffer).pixelBuffer, donde se utilizan EAGLContext y CIContext

EAGLContext es un contexto o identificador de dibujo OpenGL. Antes de dibujar la vista, debe especificar si desea utilizar el contexto creado para dibujar.
CIContext se utiliza para representar CIImage y aplicar la cadena de filtros que actúa sobre CIImage a los datos de la imagen original. Necesito convertir UIImage a CIImage aquí.

El código específico se implementa de la siguiente manera.

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

Hasta ahora puede ver el efecto específico del filtro de belleza de video GPUImage en la llamada de audio y video WebRTC.

Tres.Resumen

Llamadas de audio y video WebRTC: realice el efecto de filtro de belleza de video GPUImage. Utilice principalmente GPUImage para procesar la pantalla de video CVPixelBufferRef, generar RTCVideoFrame a partir del CVPixelBufferRef procesado y llamar al método didCaptureVideoFrame implementado en localVideoSource. Hay muchos contenidos y la descripción puede ser inexacta, perdóneme.

Dirección de este artículo: https://blog.csdn.net/gloryFlow/article/details/132265842

Registros de aprendizaje, sigue mejorando cada día.

Supongo que te gusta

Origin blog.csdn.net/gloryFlow/article/details/132265842
Recomendado
Clasificación