iOS 录制视频时,添加水印

想要实现这个功能,能够先了解一下有关录制视频的相关知识:素材库、素材的轨道、合成视频的工程文件等等,具体能够参考视频编辑素材
html

相关术语:ios

AVAsset:素材库里的素材; 
AVAssetTrack:素材的轨道; 
AVMutableComposition:一个用来合成视频的工程文件; 
AVMutableCompositionTrack:工程文件中的轨道,有音频轨、视频轨等,里面能够插入各类对应的素材; 
AVMutableVideoCompositionLayerInstruction:视频轨道中的一个视频,能够缩放、旋转等; 
AVMutableVideoCompositionInstruction:一个视频轨道,包含了这个轨道上的全部视频素材; 
AVMutableVideoComposition:管理全部视频轨道,能够决定最终视频的尺寸,裁剪须要在这里进行; 
AVAssetExportSession:配置渲染参数并渲染。复制代码


问题记录:git

下面带横线的是错误思路,一开始走进了误区,这种方式并不能解决点击view触发toucherBegan的问题github

长按拍摄,利用的是touchesbegan开始录制,touchesEnded结束录制;存在一个小问题就是点击这个view的时候,会触发touchesBegan,然而不会触发touchesEnded。这里使用了一个延时机制去触发touchesBegan事件的触发,代码以下
bash

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"开始触摸");
    if ([[touches anyObject] view] == self.progressView) {
        if (!self.capture) {    // 表示是否正在录制
            double delayInSeconds = 0.5; // 长按0.5s触发录制事件
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                [self startCapture]; // 开始录制
            });
        }else {
            [self startCapture];
        }
        
    }
}复制代码

解决方案就是用长按手势来触发ide

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(LongPressProgressView:)];
        longPress.minimumPressDuration = 0.5;
        [progressView addGestureRecognizer:longPress];复制代码

- (void)LongPressProgressView:(UILongPressGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        [self startCapture];
    }else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        if ([self.mediaCaptureDelegate respondsToSelector:@selector(stopCapture)]) {
            self.capture = NO;
            self.bgView.hidden = YES;
            [self.mediaCaptureDelegate stopCapture];
            [self.progressView clearProgress];
        }
    }
    
}复制代码

其次有个能够拖动、缩放、旋转的文本框,点击能够从新编辑,我是封装了一个类FWTextView,具体代码能够从下面的demo里找到,如图fetch



最关键的一点就是水印的添加,主要功能就是这个么。先说下思路:ui

首先咱们要知道咱们能看到的视频其实是由一个叫作videoLayer负责显示的,和他同级的有个layer叫作animationLayer,咱们可以控制的其实就是这个东西,他能够由咱们本身建立,他们有一个共同的父类叫作parentLayer。spa

添加图片水印的代码:.net

CALayer *imgLayer = [CALayer layer];
    imgLayer.contents = (id)img.CGImage;
    imgLayer.frame = CGRectMake(0, 0, size.width, size.height);复制代码

建立好了图片layer后,就须要建立videoLayer

//把文字和图标都添加到layer
    CALayer *overlayLayer = [CALayer layer];
    [overlayLayer addSublayer:imgLayer];
    overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
    [overlayLayer setMasksToBounds:YES];
    [overlayLayer addSublayer:imgLayer];
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
    parentLayer.backgroundColor = [UIColor redColor].CGColor;
    videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:overlayLayer];
    
    composition.animationTool = [AVVideoCompositionCoreAnimationTool
                                 videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];复制代码

这里主要是告诉系统咱们的layer层时parentLayer,在parentLayer里负责video显示的是咱们的videoLayer。想详细了解的可参考视频特效制做

最后就是录制完的视频保存本地,这里使用的不是系统的,ios10开始ALAssetsLibrary被标志为弃用(DEPRECATED),并建议使用Photos framework的PHPhotoLibrary,使用需先引用#import <Photos/Photos.h>

方法1:同步存到系统相册(iOS10系统执行该方法,没法保存成功)

__block NSString *createdAssetID =nil;//惟一标识,能够用于图片资源获取
    NSError *error =nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        createdAssetID = [PHAssetChangeRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset.localIdentifier;
    } error:&error];复制代码

补充:

上面的方法1在系统是10的真机上出现保存视频失败,更新一下新的方法:

NSString *path = [SNSImageEngine getRealHouseVideoPathWithVideoPath:videoPath];
            if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)) {
                UISaveVideoAtPathToSavedPhotosAlbum(path , self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
            }else {
                [MBProgressHUD showMessage:@"保存失败"];
            }


// 视频保存回调
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    if (error == nil) {
        [MBProgressHUD showMessage:@"已保存至手机"];
    }else {
        [MBProgressHUD showMessage:@"保存失败"];
    }
}
复制代码

上面代码里的path是视频在本地的路径,还有一个回调方法提供。

方法2:存到某个自定义相册

[[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
        PHAssetChangeRequest *changeAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        PHAssetCollection *targetCollection = [[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]lastObject];
        PHAssetCollectionChangeRequest *changeCollectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:targetCollection];
        PHObjectPlaceholder *assetPlaceholder = [changeAssetRequest placeholderForCreatedAsset];
        [changeCollectionRequest addAssets:@[assetPlaceholder]];
    } completionHandler:^(BOOL success,NSError * _Nullable error) {
        NSLog(@"finished adding");
    }];复制代码

详细了解参考保存照片到相册


demo连接:github.com/SXDgit/ZB_A…

到此基本结束了,后期有更新的话,会继续更新。


需求更改,要求录制时间加长,大于10s,会出现新的bug。视频超过10s后,声音会丢失。

  • 问题所在:AVCaptureMovieFileOutput他有默认的时间限制,默认值是 10 秒
  • 更改办法:设置 AVCaptureMovieFileOutput 的 movieFragmentInterval 属性为 kCMTimeInvalid,视频录制就不会受到限制

-(AVCaptureMovieFileOutput *)movieFileOutput{
    
    if (!_movieFileOutput) {
        _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
        /*  默认的录制视频时间是10秒,若是视频大于10秒必须禁用他,不然录制的视频将会没有声音*/
        _movieFileOutput.movieFragmentInterval = kCMTimeInvalid;
    }
    return _movieFileOutput;
}

复制代码
相关文章
相关标签/搜索