接着第一篇总结
系列第一篇地址:AVFoundation 框架初探究(一)
在第一篇的文章中,我们总结了主要有下面几个点的知识:
1、对AVFoundation框架整体的一个认识
2、AVSpeechSynthesizer这个文字转音频类
3、AVAudioPlayer音频播放类
4、AVAudioRecorder音频录制类
5、AVAudioSession音频会话处理类
上面第一篇说的内容,大致都是关于上面总结的,接着说说我们这第二篇总结什么?其实刚开始的时候,我是想按照《AVFoundation开发秘籍》的内容总结的,但我又觉得上面第一篇写的内容大致其实都是音频的,那我们这第二篇是不是总结视频的内容会更好一点,多媒体的处理,最主要的也就是音频和视频了,在接触了第一篇的音频之后,趁热打铁在把视频的总结出来,这样就大致上让我们认识了一下这个AVFoundation,所有这篇文章就决定不再按照书中的知识点去总结,直接总结视频的内容,当然这并不是说说中关于其他的讨论我们就不总结了,既然是系列的文章,按我们在说完视频之后再接着回来总结书中的知识。
本文Demo地址
视频的播放
在这个系列最开始的时候我们有总结过视频播放的几个方式,所以关于AVPlayerItem、AVPlayerLayer、AVPlayer这几个播放类相关的定义、使用等等的我们就不再说了, 有需要的可以看看我们前面总结的文章 :
iOS 视频播放方式整理
上面写的也只是最基础的视频的播放功能,在后面涉及到其他功能的时候我们再仔细的总结,说说今天我们针对视频这一块要总结的重点内容,视频的录制。
视频录制 AVCaptureSession + AVCaptureMovieFileOutput
我们先把利用AVCaptureSession + AVCaptureMovieFileOutput录制视频的整个流程整理出来,然后我们对照着整个流程,总结这整个流程当中的点点滴滴:
1、初始化 AVCaptureSession 得到一个捕捉会话对象。
2、通过 AVCaptureDevice 的类方法 defaultDeviceWithMediaType 区别 MediaType 得到 AVCaptureDevice 对象。
3、得到上面的 AVCaptureDevice 对象之后,就是我们的 AVCaptureDeviceInput 输入对象了。把我们的输入对象添加到 AVCaptureSession ,当然这里输入对象是要区分音频和视频对象的,这个具体的代码里面我们说。
4、有了输入当然也就有 AVCaptureMovieFileOutput,把它添加给AVCaptureSession对象。
5、通过我们初始化的AVCaptureMovieFileOutput的connectionWithMediaType方法得到一个AVCaptureConnection对象,ACCaptureConnection可以控制input到output的数据传输也可以设置视频录制的一些属性。
6、也是通过前面得到的AVCaptureSession对象初始化得到一个AVCaptureVideoPreviewLayer对象,用来预览我们要录制的视频画面,注意这个时候我们的视频录制还没有开始。
7、现在看看AVCaptureSession对象,你就发现输入输出以及Connection还有预览层都有了,那就让它 startRunning。
8、好了,用我们的AVCaptureMovieFileOutput 的 startRecordingToOutputFileURL 开始录制吧。
9、录制到满足你的需求时候记得让你startRunning的AVCaptureSession 通过 stopRunning休息了,让你的AVCaptureMovieFileOutput也可以stopRecording。这样整个过程就结束了!
上面的过程我们就把使用AVCaptureSession + AVCaptureMovieFileOutput录制视频的过程说的清楚了,有些细节我们也提过了,我们看看下面我们的Demo效果,由于是在真机测试的就简单截两张图。具体的可以运行Demo看看:
录制
播放
(说点题外的,也是无意中发现用摄像头对着X的前置摄像头的时候真的看到有红点闪烁,这也就说网上说的住酒店的时候你可以用摄像头扫描黑暗的房间可以看到有没有针孔摄像头是有道理的!^_^生活小常识,给经常出差住酒店的伙伴!)
通过上面的这两张效果图就大概的展示出了一个录制与播放的过程,下面就是我们的重点了,解读总结一下关于AVCaptureSession + AVCaptureMovieFileOutput的代码:
代码解读第一步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
NOTE: 我在Demo中有写清楚为什么我们可以利用 self.captureSession =({ })的方式写,有兴趣的可以看看。我也是学习中看到才上网查为什么能这样写的,长见识!
解读代码第二、三步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
NOTE:这段代码需要注意的地方就是 captureSession addInput 的时候最好就是先利用 canAddInput 进行判断,看是否能添加,为了代码的健壮。我们接着看!
解读代码第四、五步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
NOTE: 前面我们也有说这个Connection,除了给输入和输出建立连接之外,还有一些录制属性是可以设置的,就像我们在代码中介绍的那样,具体的在代码注释中写的很详细,大家可以看代码。
解读代码第六步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
NOTE: 这里的AVCaptureVideoPreviewLayer对象利用 initWithSession: 初始化的时候这个session就是我们前面初始化的session。
解读代码......没了!剩下的开始和结束的就没有什么好说的了,还有一个点值得我们说说就是: AVCaptureFileOutputRecordingDelegate 你看它的名字就知道是什么了,它就是我们AVCaptureMovieFileOutput的代理,看看个代理里面的方法,首先这个代理是在我们的开始录制方法里面设置的:
1 |
|
就是这个开始的方法,最后的AVCaptureFileOutputRecordingDelegate就是我们需要注意的代理,我们看这个代理里面的方法解释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
|
以上就是我们总结的关于AVCaptureSession + AVCaptureMovieFileOutput录制视频我们需要注意的一些地方,可能直接这样分开的看代码和文章感觉不太友好,可读性比较差,其实最好的就是跟着文章文字内容读,具体的代码看Demo。至于我们这里写的具体的代码内容,推荐还是看Demo会好一点。毕竟Demo里面全都有!
视频录制 AVCaptureSession + AVAssetWriter
上面说了AVCaptureSession + AVCaptureMovieFileOutput,现在说说我们的AVCaptureSession + AVAssetWriter,这个过程比起我们前面提到的是要复杂的,先来一个大概的概括,然后把它在解析一下:
1、建录制会话
2、设置视频的输入 和 输出
3、设置音频的输入 和 输出
4、添加视频预览层
5、开始采集数据,这个时候还没有写入数据,用户点击录制后就可以开始写入数据
6、初始化AVAssetWriter, 我们会拿到视频和音频的数据流,用AVAssetWriter写入文件,这一步需要我们自己实现。
整个大概的过程我们可以整理成这六点,看着好像比前面的要简单,其实比前面的是要复杂的。我们再仔细把这六步拆分一下,你就知道这六步涉及到的内容是要比前面的多一点的:
1、初始化需要的线程队列(这个后面你可以了解到为什么需要这些队列)
2、初始化AVCaptureSession录制会话
3、需要一个视频流的输入类: 利用AVCaptureDevice 录制设备类,根据 AVMediaType 初始化 AVCaptureDeviceInput 录制输入设备类,是要分音频和视频的,这点和前面的类似。把他们添加到录制会话里面。
4、初始化 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput ,把它们添加到AVCaptureSession对象,根据你初始化的线程设置setSampleBufferDelegate代理对象
5、根据AVCaptureSession得到一个AVCaptureVideoPreviewLayer预览曾对象,用于预览你的拍摄画面
6、初始化AVAssetWrite 再给AVSssetWrite通过addInput添加AVAssetWriterInput,AVAssetWriterInput也是根据AVMediaType分为video和audio,这个是重点!!!有许多参数需要设置!
7、通过 AVCaptureSession startRunning 开始采集数据,采集到的数据就会走你设置的输出对象AVCaptureAudioDataOutput的代理,代理会遵守AVCaptureVideoDataOutputSampleBufferDelegate协议。你需要在这个协议的方法里面去开始通过 AVAssetWriter 对象 startWriting 开始写入数据
8、当写完数据之后就会走AVAssetWriter的finishWritingWithCompletionHandler方法,在这里你就可以拿到你录制的视频去做其他的处理了!
9、我们再Demo中使用了Photos框架,这个也是必要重新学习的。
我们和前面的一样,一步步的解析一下上面每一步的代码:
解读代码第一步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
解读代码第二、三步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
解读代码第四、五步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
NOTE: 注意这里的 setSampleBufferDelegate 这个方法,通过这个方法有两点你就理解了,一是为什么我们需要队列。二就是为什么我们处理采集到的视频、音频数据的时候是在这个 AVCaptureVideoDataOutputSampleBufferDelegate协议的方法里面。
解读代码第六步:(重点,要说的都在代码注释里面)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
|
后面的开始和结束的部分我们就不在说了,重点还是!!! 看Demo,因为这些注释Demo里面全都有,边看代码看注释应该效果会更好,比这样直白的看着文章效果肯定要好!最后我们比较一下上面的两种录制方式:
AVCaptureMovieFileOutput 和 AVAssetWriter 方式比较
相同点:数据采集都在AVCaptureSession中进行,视频和音频的输入都一样,画面的预览一致。
不同点:输出不一致
AVCaptureMovieFileOutput 只需要一个输出即可,指定一个文件路后,视频和音频会写入到指定路径,不需要其他复杂的操作。
AVAssetWriter 需要 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 两个单独的输出,拿到各自的输出数据后,然后自己进行相应的处理。可配参数不一致,AVAssetWriter可以配置更多的参数。
视频剪裁不一致,AVCaptureMovieFileOutput 如果要剪裁视频,因为系统已经把数据写到文件中了,我们需要从文件中独到一个完整的视频,然后处理;而AVAssetWriter我们拿到的是数据流,还没有合成视频,对数据流进行处理,所以两则剪裁方式也是不一样。
我们再说说第一种方式,在微信官方优化视频录制文章中有这样一段话:
“于是用AVCaptureMovieFileOutput(640*480)直接生成视频文件,拍视频很流畅。然而录制的6s视频大小有2M+,再用MMovieDecoder+MMovieWriter压缩至少要7~8s,影响聊天窗口发小视频的速度。”
这段话也反应出了第一种方式的缺点!然后在我看这类资料的时候,又看到这样一段话:
“如果你想要对影音输出有更多的操作,你可以使用 AVCaptureVideoDataOutput 和 AVCaptureAudioDataOutput 而不是我们上节讨论的 AVCaptureMovieFileOutput。 这些输出将会各自捕获视频和音频的样本缓存,接着发送到它们的代理。代理要么对采样缓冲进行处理 (比如给视频加滤镜),要么保持原样传送。使用 AVAssetWriter 对象可以将样本缓存写入文件”
转载自http://www.cocoachina.com/ios/20180423/23121.html