美文网首页即时通迅和直播iOS 直播视频iOS直播入门及进阶
1小时学会:最简单的iOS直播推流(四)如何使用GPUImage

1小时学会:最简单的iOS直播推流(四)如何使用GPUImage

作者: hard_man | 来源:发表于2016-11-16 00:12 被阅读2341次

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!!

    源代码:https://github.com/hardman/AWLive

    上一篇文章介绍了如何使用系统方法捕获视频数据,但是更多的时候,为了使用美颜滤镜,我们会选择GPUImage来获取视频数据。

    GPUImage是一个可以为录制视频添加实时滤镜的一个著名第三方库。

    该框架大概原理是,使用OpenGL着色器对视频图像进行颜色处理,然后存到frameBuffer,之后可以对此数据再次处理。重复上述过程,即可达到多重滤镜效果。

    具体实现不细说,这里简要介绍一下GPUImage的使用,如何美颜,如何获取音视频数据。

    使用GPUImage

    GPUImage的主要代码在 AWGPUImageAVCapture 这个类中。

    初始化AWAVCaptureManager对象时将captureType设为AWAVCaptureTypeGPUImage,就会自动调用AWGPUImageAVCapture类来捕获视频数据。

    代码在 onInit 方法中:

    -(void)onInit{
        //摄像头初始化
        // AWGPUImageVideoCamera 继承自 GPUImageVideoCamera。继承是为了获取音频数据,原代码中,默认情况下音频数据发送给了 audioEncodingTarget。
        // 这个东西一看类型是GPUImageMovieWriter,应该是文件写入功能。果断覆盖掉processAudioSampleBuffer方法,拿到音频数据后自己处理。
        // 音频就这样可以了,GPUImage主要工作还是在视频处理这里。
        // 设置预览分辨率 self.captureSessionPreset是根据AWVideoConfig的设置,获取的分辨率。设置前置、后置摄像头。
        _videoCamera = [[AWGPUImageVideoCamera alloc] initWithSessionPreset:self.captureSessionPreset cameraPosition:AVCaptureDevicePositionFront];
    
        //开启捕获声音
        [_videoCamera addAudioInputsAndOutputs];
    
        //设置输出图像方向,可用于横屏推流。
        _videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
    
        //镜像策略,这里这样设置是最自然的。跟系统相机默认一样。
        _videoCamera.horizontallyMirrorRearFacingCamera = NO;
        _videoCamera.horizontallyMirrorFrontFacingCamera = YES;
        
        //设置预览view
        _gpuImageView = [[GPUImageView alloc] initWithFrame:self.preview.bounds];
        [self.preview addSubview:_gpuImageView];
        
        //初始化美颜滤镜
        _beautifyFilter = [[GPUImageBeautifyFilter alloc] init];
    
        //相机获取视频数据输出至美颜滤镜
        [_videoCamera addTarget:_beautifyFilter];
        
        //美颜后输出至预览
        [_beautifyFilter addTarget:_gpuImageView];
        
        // 到这里我们已经能够打开相机并预览了。
        // 因为要推流,除了预览之外,我们还要截取到视频数据。这就需要使用GPUImage中的GPUImageRawDataOutput,它能将美颜后的数据输出,便于我们处理后发送出去。
        // AWGPUImageAVCaptureDataHandler继承自GPUImageRawDataOutput,从 newFrameReadyAtTime 方法中就可以获取到美颜后输出的数据。
        // 输出的图片格式为BGRA。
        _dataHandler = [[AWGPUImageAVCaptureDataHandler alloc] initWithImageSize:CGSizeMake(self.videoConfig.width, self.videoConfig.height) resultsInBGRAFormat:YES capture:self];
        [_beautifyFilter addTarget:_dataHandler];
    
        // 令AWGPUImageAVCaptureDataHandler实现AWGPUImageVideoCameraDelegate协议,并且让camera的awAudioDelegate指向_dataHandler对象。
        // 将音频数据转到_dataHandler中处理。然后音视频数据就可以都在_dataHandler中处理了。
        _videoCamera.awAudioDelegate = _dataHandler;
        
        //开始捕获视频
        [self.videoCamera startCameraCapture];
        
        //修改帧率
        [self updateFps:self.videoConfig.fps];
    }
    

    美颜滤镜使用的是:https://github.com/Guikunzhi/BeautifyFaceDemo
    感谢Guikunzhi的分享。想了解美颜详细算法的同学,可以自行学习。

    AWGPUImageAVCaptureDataHandler中音视频处理方法:

    // 获取到音频数据,通过sendAudioSampleBuffer发送出去
    -(void)processAudioSample:(CMSampleBufferRef)sampleBuffer{
        if(!self.capture || !self.capture.isCapturing){
            return;
        }
        [self.capture sendAudioSampleBuffer:sampleBuffer];
    }
    
    // 获取到视频数据,转换格式后,使用sendVideoYuvData 发送出去。
    -(void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex{
        [super newFrameReadyAtTime:frameTime atIndex:textureIndex];
        if(!self.capture || !self.capture.isCapturing){
            return;
        }
        // GPUImage获取到的数据是BGRA格式。
        // 而各种编码器最适合编码的格式还是yuv(NV12格式)。
        // 所以在此将BGRA格式的视频数据转成yuv格式。(后面会介绍yuv和pcm格式)
        // 将bgra转为yuv
        int width = imageSize.width;
        int height = imageSize.height;
        int w_x_h = width * height;
        // 1帧yuv数据长度为 宽x高 * 3 / 2
        int yuv_len = w_x_h * 3 / 2;
        
        uint8_t *yuv_bytes = malloc(yuv_len);
        
        //使用libyuv库,做格式转换。libyuv中的格式都是大端(高位存高位,低位存低位),而iOS设备是小端(高位存低位,低位存高位),小端为BGRA,则大端为ARGB,所以这里使用ARGBToNV12。
        //self.rawBytesForImage就是美颜后的图片数据,格式是BGRA。
        //关于大端小端,请自行baidu。
        //NV12格式介绍请看下一篇文章:[1小时学会:最简单的iOS直播推流(五)yuv、pcm数据的介绍和获取](http://www.jianshu.com/p/d5489a8fe2a9)
        [self lockFramebufferForReading];
        ARGBToNV12(self.rawBytesForImage, width * 4, yuv_bytes, width, yuv_bytes + w_x_h, width, width, height);
        [self unlockFramebufferAfterReading];
        
        NSData *yuvData = [NSData dataWithBytesNoCopy:yuv_bytes length:yuv_len];
        
        //将获取到的yuv420数据发送出去
        [self.capture sendVideoYuvData:yuvData];
    }
    

    至此,已经成功使用GPUImage获取视频,美颜,格式转换,准备发送数据。还是很简单的。

    我们现在能够使用2种方法来获取音频数据,接下来会介绍音视频编码相关内容。

    文章列表

    1. 1小时学会:最简单的iOS直播推流(一)项目介绍
    2. 1小时学会:最简单的iOS直播推流(二)代码架构概述
    3. 1小时学会:最简单的iOS直播推流(三)使用系统接口捕获音视频
    4. 1小时学会:最简单的iOS直播推流(四)如何使用GPUImage,如何美颜
    5. 1小时学会:最简单的iOS直播推流(五)yuv、pcm数据的介绍和获取
    6. 1小时学会:最简单的iOS直播推流(六)h264、aac、flv介绍
    7. 1小时学会:最简单的iOS直播推流(七)h264/aac 硬编码
    8. 1小时学会:最简单的iOS直播推流(八)h264/aac 软编码
    9. 1小时学会:最简单的iOS直播推流(九)flv 编码与音视频时间戳同步
    10. 1小时学会:最简单的iOS直播推流(十)librtmp使用介绍
    11. 1小时学会:最简单的iOS直播推流(十一)sps&pps和AudioSpecificConfig介绍(完结)

    相关文章

      网友评论

      • Hello_kid:能直接处理yuv数据吗
      • 60916fc63567:请问 您有没有swift版本呢
      • 格调main:感觉流程什么的都很清楚, 但是运行你的demo 发现拍摄感觉卡顿,移动摄像头的时候, 推流出去SRS 服务器,解码也有点问题, 虽然也能播 但是效果很差
      • gitKong:感谢开源,这里有问题不太清楚,请教一下,1、`newFrameReadyAtTime ` 这个方法里面的注释,其中说“libyuv中的格式都是大端(高位存高位,低位存低位)” ,不是数据的高字节存在低位么?2、还有您使用自定义的 `aw_alloc ` 是不是只是用来方便跟踪内存分配释放,那我直接使用 malloc 直接分配,使用完free就可以了?
        hard_man:@gitKong 文件和网络中数据流一般是大端,我们用的电脑内存一般是小端。这个并不绝对。
        看具体情况。
        可以使用malloc。aw_malloc可以调试内存泄露。

      本文标题:1小时学会:最简单的iOS直播推流(四)如何使用GPUImage

      本文链接:https://www.haomeiwen.com/subject/bxwlpttx.html