v2panda的技术专题iOS进阶iOS

AVFoundation 『入门』-- 以微信小视屏为例

2016-08-30  本文已影响3167人  Damonwong

仿微信小视屏 - iOS 技术路线实践笔记【录制篇】

一周之前拿到这个需求时,我当时是懵逼的,因为自己对 视频 这一块几乎可以说是一无所知。在断断续续一周的研究过程之后,准备写点笔记记录一下。

需求分析


先讲讲视频录制 - 技术路线

(因为自己对视频是个小白,只能借助谷歌来搜索一些相关技术,一定有什么不对的地方)

看上去很懵逼是不是,其实我也是懵逼的。更甚至于AVFoundation 和 ffmpeg 两者关系我最开始都摸不透。如果你和我一样懵逼可以看一下。我写的AVFoundation和视频捕捉相关的总结。ffmpeg 则 需要去看雷神的博客了,很详细,也很入门。


废话不多说,上代码。

对于 AVFoundation 捕捉只是还不是很清楚的可以点击这里查看。

录制前的准备工作

@property (nonatomic, strong) AVCaptureSession *captureSession;/**< 捕捉会话 */
self.captureSession = ({
    // 分辨率设置
  AVCaptureSession *session = [[AVCaptureSession alloc] init];
    if ([session canSetSessionPreset:AVCaptureSessionPresetHigh]) {
        [session setSessionPreset:AVCaptureSessionPresetHigh];
    }
    session;    
}); 
/// 初始化 捕捉输入
- (BOOL)setupSessionInputs:(NSError **)error {
    
    // 添加 摄像头
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:({
        
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
    }) error:error];
    
    if (!videoInput) { return NO; }
    
    if ([self.captureSession canAddInput:videoInput]) {
        [self.captureSession addInput:videoInput];
    }else{
        return NO;
    }
    
    // 添加 话筒
    AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:({
        
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
        
    }) error:error];
    
    if (!audioInput)  { return NO; }
    
    if ([self.captureSession canAddInput:audioInput]) {
        [self.captureSession addInput:audioInput];
    }else{
        return NO;
    }
    
    return YES;
}
    //初始化设备输出对象,用于获得输出数据
    self.captureMovieFileOutput = ({
        AVCaptureMovieFileOutput *output = [[AVCaptureMovieFileOutput alloc]init];
        // 设置录制模式
        AVCaptureConnection *captureConnection=[output connectionWithMediaType:AVMediaTypeVideo];
        if ([captureConnection isVideoStabilizationSupported ]) {
            captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
        }
        //将设备输出添加到会话中
        if ([self.captureSession canAddOutput:output]) {
            [self.captureSession addOutput:output];
        }
        output;
    });
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer; /**< 相机拍摄预览图层 */
    //创建视频预览层,用于实时展示摄像头状态
    self.captureVideoPreviewLayer = ({
        AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
        previewLayer.frame=  CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
        previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
        [self.view.layer addSublayer:previewLayer];
        self.view.layer.masksToBounds = YES;
        previewLayer;
        
    });

录制视频

用 AVCaptureMovieFileOutput 录制视频很简单。代码如下。


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if (![self.captureMovieFileOutput isRecording]) {
        AVCaptureConnection *captureConnection=[self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
        captureConnection.videoOrientation=[self.captureVideoPreviewLayer connection].videoOrientation;
        [self.captureMovieFileOutput startRecordingToOutputFileURL:({
            // 录制 缓存地址。
            NSURL *url = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"temp.mov"]];
            if ([[NSFileManager defaultManager] fileExistsAtPath:url.path]) {
                [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
            }
            url;
        }) recordingDelegate:self];
    }else{
        [self.captureMovieFileOutput stopRecording];//停止录制
    }
}

查看录制视频

压缩视频

-(void)videoCompression{
    
    NSLog(@"begin");
    NSURL *tempurl = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"temp.mov"]];
    //加载视频资源
    AVAsset *asset = [AVAsset assetWithURL:tempurl];
    //创建视频资源导出会话
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];
    //创建导出视频的URL
    session.outputURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"tempLow.mov"]];
    //必须配置输出属性
    session.outputFileType = @"com.apple.quicktime-movie";
    //导出视频
    [session exportAsynchronouslyWithCompletionHandler:^{
                NSLog(@"end");
    }];

}

ok!利用 AVFoundation 模仿小视屏功能就这么实现了~ 总结一下,如图

哈哈哈,那是不可能的


优化方案

总体分析

因为代码比较多,就不贴出来了,需要的可以在这里下载

DWPreviewView

DWVideoRecoder

DWVideoWriter

Key
AVVideoCodecKey 编码格式,一般选h264,硬件编码
AVVideoScalingModeKey 填充模式,AVVideoScalingModeResizeAspectFill拉伸填充
AVVideoWidthKey 视频宽度,以手机水平,home 在右边的方向
AVVideoHeightKey 视频高度,以手机水平,home 在右边的方向
AVVideoCompressionPropertiesKey 压缩参数
Key
AVVideoAverageBitRateKey 视频尺寸*比率 比率10.1相当于AVCaptureSessionPresetHigh数值越大越精细
AVVideoMaxKeyFrameIntervalKey 关键帧最大间隔,1为每个都是关键帧,数值越大压缩率越高
AVVideoProfileLevelKey 默认选择 AVVideoProfileLevelH264BaselineAutoLevel

后记


番外篇

<a name="AVFoundation"/>
<a name="AVFoundation1"/>

关于AVFoundation 捕捉

<a name="AVCaptureSession"/>

<a name="AVCaptureDevice"/>

<a name="AVCaptureDeviceInput"/>

<a name="AVCaptureOutput"/>

<a name="AVCaptureConnection"/>

<a name="SandBox"/>

如何查看真机沙盒里面的文件

<a name="SessionPreset"/>

可选预设

NSString *const  AVCaptureSessionPresetPhoto;
NSString *const  AVCaptureSessionPresetHigh;
NSString *const  AVCaptureSessionPresetMedium;
NSString *const  AVCaptureSessionPresetLow;
NSString *const  AVCaptureSessionPreset352x288;
NSString *const  AVCaptureSessionPreset640x480;
NSString *const  AVCaptureSessionPreset1280x720;
NSString *const  AVCaptureSessionPreset1920x1080;
NSString *const  AVCaptureSessionPresetiFrame960x540;
NSString *const  AVCaptureSessionPresetiFrame1280x720;
NSString *const  AVCaptureSessionPresetInputPriority;

参考文章:
Android & IOS视频录制技术方案
iOS微信小视频优化心得
iOS仿微信小视频功能开发优化记录
在 iOS 上捕获视频
参考书本:
《AV Foundation 开发秘籍》
Github:
SCRecorder
VideoCaptureDemo

更多

工作之余,写了点笔记,如果需要可以在我的 GitHub 看。

上一篇下一篇

猜你喜欢

热点阅读