iOS - 采集音视频及写入文件

�音视频采集包括两部分:视频采集和音频采集。在iOS中可以同步采集视频与音频,通过系统框架AVFoundation,可以帮助我们采集音频与视频,对于视频还可以进行切换前后摄像头,最终我们将录制好的视频写入沙盒中

DEMO

音视频数据的采集与展示

一、初始化视频的输入与输出

// 懒加载一个session,所有的操作都需要session来执行
fileprivate lazy var session: AVCaptureSession = AVCaptureSession()
// 保存�视频输出
fileprivate var videoOutput: AVCaptureVideoDataOutput?
// 保存视频输入
fileprivate var videoInput: AVCaptureDeviceInput?
// 保存预览图层
fileprivate var previewLayer: AVCaptureVideoPreviewLayer?

设置视频输入源与输出源

// 设置视频输入源
guard let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] else { return }
// 获取我们的前置摄像头(后置为.back)
guard let device = devices.filter({ $0.position == .front }).first else { return }
guard let input = try? AVCaptureDeviceInput(device: device) else { return }
self.videoInput = input

// 设置视频输出源
let output = AVCaptureVideoDataOutput()
let queue = DispatchQueue.global()
// 设置代理,并在代理中获取采集到的数据,需要遵守 AVCaptureVideoDataOutputSampleBufferDelegate
output.setSampleBufferDelegate(self, queue: queue)
self.videoOutput = output

设置音频的输入源与输出源

// 设置音频的输入源
guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) else { return }
guard let input = try? AVCaptureDeviceInput(device: device) else {return}

// 设置音频输出源
let output = AVCaptureAudioDataOutput()
let queue = DispatchQueue.global()
// 需要遵守 AVCaptureAudioDataOutputSampleBufferDelegate
output.setSampleBufferDelegate(self, queue: queue)

添加音频与视频的输入与输出到session中,但是每次添加之前需要先判断是否可以添加

// 添加输入与输出

// 注意:每次对session进行设置之前都需要调用session的【beginConfiguration】方法
// 来告诉系统你现在要开始进行配置,结束配置后再调用【commitConfiguration】方法来提交配置
session.beginConfiguration()
if session.canAddInput(input) {
    session.addInput(input)
}
if session.canAddOutput(output) {
    session.addOutput(output)
}
session.commitConfiguration()

二、实现音视频的采集代理

音视频虽然需要遵守的代理名称不一样,但是需要实现的方法是一致的,所以要拿到音频或者视频就得先进行判断,需要用到AVCaptureOutput的这个方法

// This convenience method returns the first AVCaptureConnection in the receiver's
// connections array that has an AVCaptureInputPort of the specified mediaType. If 
// no connection with the specified mediaType is found, nil is returned.

open func connection(withMediaType mediaType: String!) -> AVCaptureConnection!
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        if videoOutput?.connection(withMediaType: AVMediaTypeVideo) == connection {
            print("视频数据")
        } else {
            print("音频数据")
        }
    }
}

三、初始化一个预览图层用来显示采集到的视频(非采集所必须的步骤)

// 创建预览图层
guard let previewLayer = AVCaptureVideoPreviewLayer(session: session) else {return}
previewLayer.frame = view.bounds

// 将图层添加到控制器的view的layer中
view.layer.insertSublayer(previewLayer, at: 0)
self.previewLayer = previewLayer

现在基本功能都有了,如果想要开始采集音视频只需要调用

// 开始录制
session.startRunning()
// 结束录制
session.stopRunning()

切换镜头

其实就是换掉当前的视频输入法制,这里的过程跟上面的设置输入源一样。

// 1.取出之前镜头的方向
guard let videoInput = videoInput else { return }
let position: AVCaptureDevicePosition = videoInput.device.position == .front ? .back : .front

guard let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] else { return }
guard let device = devices.filter({ $0.position == position }).first else { return }
guard let newInput = try? AVCaptureDeviceInput(device: device) else { return }

// 2.移除之前的input,添加新的input
session.beginConfiguration()
session.removeInput(videoInput)
if session.canAddInput(newInput) {
    session.addInput(newInput)
}
session.commitConfiguration()

// 3.保存最新的input
self.videoInput = newInput

录制视频写入文件

fileprivate var movieOutput: AVCaptureMovieFileOutput?

在开始采集音视频的时候就要开始写入文件

// 开始写入文件 

// 1、创建写入文件的输出
let fileOutput = AVCaptureMovieFileOutput()
self.movieOutput = fileOutput // 保存起来,用于停止写入文件

// 设置类型,不然报错(这两句很重要)
let connection = fileOutput.connection(withMediaType: AVMediaTypeVideo)
connection?.automaticallyAdjustsVideoMirroring = true

if session.canAddOutput(fileOutput) {
    session.addOutput(fileOutput)
}

// 2、直接开始写入文件
let filePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/abc.mp4"
let fileUrl = URL(fileURLWithPath: filePath)
fileOutput.startRecording(toOutputFileURL: fileUrl, recordingDelegate: self)

在停止采集音视频的时候停止写入文件

// 停止写入文件
movieOutput?.stopRecording()

详情请看 DEMO

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JackieZheng

AngularJS in Action读书笔记5(实战篇)——在directive中引入D3饼状图显示

前言:   "宁肯像种子一样等待    也不愿像疲惫的陀螺    旋转得那样勉强"   这是前几天在查资料无意间看到的一位园友的签名,看完后又读了两遍,觉得很有...

2156
来自专栏吴小龙同學

Android App Shortcuts

简介 Android 7.1允许您定义应用程序中特定操作的快捷方式。这些快捷键可以显示桌面,例如Nexus和Pixel设备。快捷键可让您的用户在应用程序中快速启...

3367
来自专栏前端新视界

构建具有用户身份认证的 React + Flux 应用程序

React 的生态系统很大,为了解决 React 中比较困难的问题,你可以选择多种模块。大多数实际的 React 应用程序都有一些共同的需求,这些需求主要包括状...

1010
来自专栏前端进阶之路

带你五步学会Vue SSR

SSR大家肯定都不陌生,通过服务端渲染,可以优化SEO抓取,提升首页加载速度等,我在学习SSR的时候,看过很多文章,有些对我有很大的启发作用,有些就只是照搬官网...

844
来自专栏前端架构与工程

《微信小程序七日谈》- 第一天:人生若只如初见

《微信小程序七日谈》系列文章: 本系列的文章并非初学教程,而是笔者在具体开发过程中遇到的问题以及部分解决方案。 微信小程序自公布以来就被捧上了天,新闻一波接一...

1908
来自专栏用户2442861的专栏

构建自己的JavaScript模板小引擎

有时候,我们不需要太牛逼太强大的JavaScript模板引擎(比如jQuery tmpl或者handlebarsjs),我们只是需要在简单的模板里绑定一些非常简...

681
来自专栏数据小魔方

这个包绝对值得你用心体验一次!

这一段时间在研究R里面的数据抓取相关包,时不时的能发掘出一些惊喜。 比如今天,我找到了一个自带请求器的解析包,而且还是嵌入的pantomjs无头浏览器,这样就不...

2896
来自专栏逸鹏说道

GeetTest~下一代验证(附C#案例)

基本介绍 极验验证除了在服务器端提供了广泛的语言支持外,在客户端也提供了多平台的扩展支持。 客户端主要涵盖了如下平台: pcWeb 普通台式电脑,笔记本电脑w...

33311
来自专栏前端新视界

构建具有用户身份认证的 React + Flux 应用程序

原文:Build a React + Flux App with User Authentication 译者:nzbin 译者的话:这是一篇内容详实的 Rea...

3817
来自专栏熊二哥

Vue快速入门

终于进入国内当前最火的前端框架Vue.js的学习了,最近周边的哥们也开始用该框架做线上项目,闲暇之余,做个快速的了解,重在基础部分。 ? 基础概念 目前在国...

2928

扫码关注云+社区