[iOS]短视频录制(新)

作者: 阳眼的熊 | 来源:发表于2017-06-22 18:54 被阅读1916次

    简单介绍

    这篇文章是自己做短视频功能这几个月的一个总结,以下文字或代码有任何不妥的地方希望各位积极指出错误,并给出建议。

    从短视频拍摄基本功能来说,我想应该有以下,美颜,水印,断点拍摄,编辑功能,编辑功能包含,滤镜添加,背景音乐添加,贴图贴纸添加,高质量压缩(视频降低码率)。针对这些功能,我会逐一介绍其实现方法。

    使用到的第三方库:TZImagePickerController,GPUImage,SDAVAssetExportSession

    demo效果图

    文章末尾会附上demo地址

    预览画面支持美颜切换,前后相机切换


    5711487-e5b15cbaac9fd2ef.PNG

    录制中


    5711487-b8918b5001fef0f4.PNG

    暂停录制,支持断点回删


    5711487-499df69972480db7.PNG

    滤镜选择共8重


    5711487-b307e065acbd0435.PNG

    选择音乐


    5711487-93f479e492d36d8f.PNG

    贴纸选择,可随意调整贴纸位置


    5711487-61cc436cb1264c29.PNG

    预览发布页面,按各自实际app需求调整


    5711487-5839bcfb739bf35d.PNG

    录制功能实现

    录制功能是基于GPUImageVideoCamera实现的:

    相机初始化

    videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
    

    给相机添加滤镜

    filter = [[LFGPUImageEmptyFilter alloc] init];  //这个滤镜是一个空滤镜
    
    filteredVideoView = [[GPUImageView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; //创建预览画面
    
    [videoCamera addTarget:filter];
    
    [filter addTarget:filteredVideoView];
    

    开起预览

    [videoCamera startCameraCapture];  //启动相机
    

    切换至美颜滤镜

    [videoCamera removeAllTargets]; //移除其它滤镜
    
    filter = [[GPUImageBeautifyFilter alloc] init];//美颜滤镜
    
    [videoCamera addTarget:filter];
    
    [filter addTarget:filteredVideoView];
    

    视频录制以及断点续拍

    断点续拍的实质就是把多个视频合并成同一视频

    开始录制

    movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(720.0, 1280.0)];
    
    movieWriter.isNeedBreakAudioWhiter = YES;
    
    movieWriter.encodingLiveVideo = YES;
    
    movieWriter.shouldPassthroughAudio = YES;
    
    [filter addTarget:movieWriter];
    
    videoCamera.audioEncodingTarget = movieWriter;
    
    [movieWriter startRecording];
    

    暂停录制

    暂停录制就是把视频先保存起来,并将视频地址保存在数组中,这样就能实现断点续拍。

    [movieWriter finishRecording];
    
    [filter removeTarget:movieWriter];
    
    [urlArray addObject:[NSURL URLWithString:[NSString stringWithFormat:@"file://%@",pathToMovie]]];
    

    拍摄完成后的合成操作以及水印添加

    创建音视频合成体,以及视频通道容器,音频通道容器

    [[AVMutableComposition alloc] init];
    
    [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
    
    preferredTrackID:kCMPersistentTrackID_Invalid];
    
    [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
    
    preferredTrackID:kCMPersistentTrackID_Invalid];
    

    用AVAsset取出素材,并且分别取出音频轨道 与视频轨道按时间措添加至 上面创建的音视频容器中

    AVAsset* asset = [AVURLAsset URLAssetWithURL:videosPathArray[i] options:options];
    

    //获取AVAsset中的音频 或者视频

    AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
    

    //向通道内加入音频或者视频

    BOOL ba = [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
    
    ofTrack:assetAudioTrack
    
    atTime:totalDuration
    
    error:&erroraudio];
    

    //向通道内加入视频步骤与上面音频的添加差不多

    视频水印的添加,创建layer ,并将layer 添加AVMutableVideoComposition 这个对象中

    视频导出,创建AVAssetExportSession 对象 ,并为其设置videoComposition属性,以此添加水印

    //视频导出工具

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
    
    presetName:AVAssetExportPreset1280x720];
    
    exporter.videoComposition = videoComp;
    
    导出方法 - (void)exportAsynchronouslyWithCompletionHandler:(void (^)(void))handler;
    

    导出成功后进入下一个视频编辑页面

    视频滤镜处理

    创建视频预览,使用GPUImageMovie工具 并结合avPlayer

    mainPlayer = [[AVPlayer alloc] init];
    
    playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
    
    [mainPlayer replaceCurrentItemWithPlayerItem:playerItem];
    
    playerLayer = [AVPlayerLayer playerLayerWithPlayer:mainPlayer];
    
    movieFile = [[GPUImageMovie alloc] initWithPlayerItem:playerItem];
    
    movieFile.runBenchmark = YES; movieFile.playAtActualSpeed = YES;
    

    //新建一个空白滤镜添加至 movieFile

    filter = [[LFGPUImageEmptyFilter alloc] init];
    
    _filtClassName = @"LFGPUImageEmptyFilter";
    
    [movieFile addTarget:filter];
    

    //视频预览容器view

    _filterView = [[GPUImageView alloc] initWithFrame:self.view.bounds];
    
    [self.view addSubview:_filterView];
    
    [filter addTarget:_filterView];
    

    开始预览方法:- (void)startProcessing;

    //avplay开始播放

    [mainPlayer play];
    
    [movieFile startProcessing];
    
    切换滤镜效果
    
    [movieFile removeAllTargets];
    
    //新建一个新的滤镜文件
    
    filter = [[NSClassFromString(_filtClassName) alloc] init];
    
    //将滤镜添加至 movieFile上
    
    [movieFile addTarget:filter];
    
    //重新添加预览容器view
    
    [filter addTarget:_filterView];
    
    生成带滤镜处理后的视频
    
    //1.新建用于导出的MovieFile
    
    endMovieFile = [[GPUImageMovie alloc] initWithURL:sampleURL];
    
    endMovieFile.runBenchmark = YES;
    
    endMovieFile.playAtActualSpeed = NO;
    
    //2.给MovieFile添加滤镜
    
    endFilter = [[NSClassFromString(_filtClassName) alloc] init];
    
    [endMovieFile addTarget:endFilter];
    
    //3.新建GPUImageMovieWriter写入类
    
    movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:movieURL size:CGSizeMake(720.0, 1280.0)];
    
    [endFilter  addTarget:movieWriter];
    
    movieWriter.shouldPassthroughAudio = YES;
    
    endMovieFile.audioEncodingTarget = movieWriter;
    
    [endMovieFile enableSynchronizedEncodingUsingMovieWriter:movieWriter];
    
    //4.开始写入
    
    [movieWriter startRecording];
    
    [endMovieFile startProcessing];
    
    [movieWriter setCompletionBlock:^{
    
    //.完成后的逻辑处理
    
    }];
    

    音乐合成处理/贴图合成处理

    此处方法原理 与第一页视频合成,水印处理基本相同。前者就是将音频素材 添加到音频轨道中, 后者还是视频layer上加layer;

    视频的压缩处理

    NSDictionary* options = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES};
    
    AVAsset* asset = [AVURLAsset URLAssetWithURL:inputVideoUrl options:options];
    
    NSArray* keys = @[@"tracks",@"duration",@"commonMetadata"];
    
    [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
    
    SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:asset]; // provide inputVideo Url Here
    
    compressionEncoder.outputFileType = AVFileTypeMPEG4;//文件输出格式
    
    compressionEncoder.outputURL = outputVideoUrl; //文件输出地址
    
    //视频参数配置
    
    compressionEncoder.videoSettings = @
    
    {
    
    AVVideoCodecKey: AVVideoCodecH264,//编码方式
    
    AVVideoWidthKey: @720,  //视频宽
    
    AVVideoHeightKey: @1280,  //视频高
    
    AVVideoCompressionPropertiesKey: @
    
    {
    
    //2000*1000  建议800*1000-5000*1000
    
    //            AVVideoAverageBitRateKey: @2500000, // Give your bitrate here for lower size give low values
    
    AVVideoAverageBitRateKey: _bit,//比特lv
    
    AVVideoProfileLevelKey: AVVideoProfileLevelH264HighAutoLevel,
    
    AVVideoAverageNonDroppableFrameRateKey: _frameRate,//fps
    
    },
    
    };
    
    //音频参数配置
    
    compressionEncoder.audioSettings = @
    
    {
    
    AVFormatIDKey: @(kAudioFormatMPEG4AAC),//编码方式
    
    AVNumberOfChannelsKey: @2,//通道,双通道
    
    AVSampleRateKey: @44100,//菜样率
    
    AVEncoderBitRateKey: @128000,//编码比特lv
    
    };
    
    [compressionEncoder exportAsynchronouslyWithCompletionHandler:^
    
    {
    
    //处理成功
    
    }];
    
    }];
    

    Demo传送门:https://github.com/doubleYang1020/DYVideoCamera

    相关文章

      网友评论

      • 我是码神:你好 我看了代码 运行了demo 很有收获,只是可以就是一边录制 一边可以选择滤镜, 贴纸,音乐等等 比如 像抖音那样 .我发现demo是在视频拍摄成功后才加 滤镜 贴纸 音乐的.期待你的回复
      • 31e29168745f:点击短视频录制,崩溃了
        莦婼姑娘:@星空_M 设置了什么东西?我也是崩溃
        31e29168745f:第一次试了一下,没成功,现在添加了一些设置信息就可以了:+1:
        阳眼的熊:@星空_M 可以提供更多信息吗?
      • Lee0528:安卓的录制视频的demo能不能整到:joy:
        阳眼的熊:@Lee0528 这里向你推荐几个 https://github.com/wuhaoyu1990/MagicCamera
        https://github.com/qqchenjian318/VideoEditor-For-Android
        https://github.com/Skykai521/StickerCamera
        Lee0528:@阳眼的熊 好的 多谢:pray:
        阳眼的熊:@Lee0528 我找找 ,貌似是有的
      • PGOne爱吃饺子:楼主是做短视频的么
        阳眼的熊:@PGOne爱吃饺子 差不多吧 主要就是这个方向的
      • 2df6b75e5bec:大神,有个问题,这种方法加贴纸的话怎么控制贴纸显示的时间?比如说视频开始后3s钟添加5s之后移除。。
        2df6b75e5bec:@阳眼的熊 感谢!我试试~
        阳眼的熊:这是2s 出现 5s 消失的效果
        阳眼的熊:@QaQaQa 在 [parentLayer addSublayer:aLayer]; 下行添加如下代码。 aLayer.opacity = 0.0 ;
        CAAnimationGroup* myAnimaGroup = [CAAnimationGroup animation];
        myAnimaGroup.duration = 5.2f;
        myAnimaGroup.repeatCount = 0;
        myAnimaGroup.beginTime = AVCoreAnimationBeginTimeAtZero;
        CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"opacity"];
        anima.fromValue = [NSNumber numberWithFloat:0.0f];
        anima.toValue = [NSNumber numberWithFloat:1.0f];
        anima.duration = 0.1f;
        anima.beginTime = AVCoreAnimationBeginTimeAtZero + 2;
        [anima setRemovedOnCompletion:NO];
        [anima setFillMode:kCAFillModeForwards];
        myAnimaGroup.animations = @[anima];
        [aLayer addAnimation:myAnimaGroup forKey:@"opacityAniamtion"];
      • 回味岁月:有没有类似的安卓版的?
        阳眼的熊:首页展示的数据,抓的火山app的数据,不过现在已经失效了,没什么用了
        回味岁月:@阳眼的熊 大神 看你git中写到用了火山视频的api是什么意思呢?
        阳眼的熊:安卓我并不了解
      • 艾欧艾斯开花攻城狮:拜读了,写的非常棒,包括注释也很详尽!:+1: 我最近也在调研这方面的知识,希望能与作者一起学习、分享,可以的话加我qq或者微信 492871881:smile:
      • 大宝来巡山:果然是干货,谢谢大神的分享
      • 小小溪001:我来学习学习。:smile:
      • Callmewenxi:不知道是不是你的方案问题,视频合并速度太慢了,10秒钟的视频,在拍摄完进入编辑界面这个过程需要好几秒种.

        添加滤镜,背景音乐和贴纸后,再合成的话,10秒钟的视频花费大概13秒左右....

        我近期也是在做短视频功能,不过就刚刚完成录制功能,准备做添加背景声音的功能..
        你这里添加背景音是在一个已经合成好的视频中重新编解码?添加滤镜和和贴纸也是重复这个操作?
        阳眼的熊:@iOS小小白 性能上有些处理都是可以合并在一起处理的
        阳眼的熊:@iOS小小白 你可以把看看我代码逻辑,功能都实现了。
        阳眼的熊:@iOS小小白 可以优化,
      • 跨境大师兄:在iOS10以下 有木有可以像11里那样的录屏的呀:wink:
        阳眼的熊:@iOSReverse 并不是很了解录屏

      本文标题:[iOS]短视频录制(新)

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