视频采集
音频采集
AVCaptureVideoPreviewLayer
本地存储
切换摄像头
1.创建捕获会话AVCaptureSession
fileprivate lazy var session : AVCaptureSession = AVCaptureSession()
//其他属性
fileprivate var videoOutpu : AVCaptureVideoDataOutput?
fileprivate var videoInout : AVCaptureDeviceInput?
fileprivate var previewLayer : AVCaptureVideoPreviewLayer?
fileprivate var movieOutput : AVCaptureMovieFileOutput?
2.初始化视频输入和输出
①获取设备device
②获取设备上的输入流Input,并保存
③获取输出流output
④输出流设置代理
⑤Session会话中添加输入流和输出流
fileprivate func setupVideoInputOutout(){
//添加视频的输入
/*
let device = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .front)
*/
let devices = AVCaptureDevice.devices()
guard let device = devices.filter({ $0.position == .back }).first else { return }
guard let input = try? AVCaptureDeviceInput(device: device) else { return }
self.videoInout = input
//添加视频的输出
let output = AVCaptureVideoDataOutput()
let queue = DispatchQueue.global()
output.setSampleBufferDelegate(self, queue: queue)
self.videoOutpu = output
//添加输入&输出
addInputAndOutpuSession(input, output)
}
3.初始化音频输入和输出流
①获取设备
②获取输入流
③获取输出流,并设置代理
④在会话中添加Session
fileprivate func setupAudioInputOutout(){
//创建输入
guard let device = AVCaptureDevice.default(for: .audio) else { return }
guard let input = try? AVCaptureDeviceInput(device: device) else { return }
//创建输出
let output = AVCaptureAudioDataOutput()
let queue = DispatchQueue.global()
output.setSampleBufferDelegate(self, queue: queue)
//添加输入&输出
addInputAndOutpuSession(input, output)
}
添加输入输出流
//添加 输入 输出
private func addInputAndOutpuSession(_ input : AVCaptureInput, _ output : AVCaptureOutput){
//添加输入 & 输出
session.beginConfiguration()
if session.canAddInput(input){
session.addInput(input)
}
if session.canAddOutput(output){
session.addOutput(output)
}
session.commitConfiguration()
}
④添加预览
fileprivate func setupPreviewLayer (){
//1 创建预览图层
previewLayer = AVCaptureVideoPreviewLayer(session: session)
//2设置 preview属性
previewLayer?.frame = view.bounds
//3将图层添加到控制器的View的Layer 中
view.layer.insertSublayer(previewLayer!, at: 0)
}
⑤代理方法
// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate -- AVCaptureAudioDataOutputSampleBufferDelegate 同一个方法
extension ViewController : AVCaptureVideoDataOutputSampleBufferDelegate , AVCaptureAudioDataOutputSampleBufferDelegate{
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
if videoOutpu?.connection(with: .video) == connection {
print("采集到一针画面\(Thread.current)")
}else {
print("音频数据")
}
}
}
⑥切换摄像头
获取之前的VideoInput,创建新的Input,切换AVCaptureDevice.Position ,切换Input
@IBAction func changeCamera(_ sender: UIButton) {
//取出之前镜头的方向
guard let videoInput = videoInout else { return }
let postion : AVCaptureDevice.Position = videoInput.device.position == .front ? .back : .front
let devices = AVCaptureDevice.devices()
guard let device = devices.filter({ $0.position == postion }).first else { return }
guard let newInput = try? AVCaptureDeviceInput(device: device) else { return }
//移除之前的Input 添加新的Input
session.beginConfiguration()
session.removeInput(videoInput)
if session.canAddInput(newInput){
session.addInput(newInput)
}
session.commitConfiguration()
//保存最新的Input
self.videoInout = newInput
}
⑦写入本地
获取AVCaptureMovieFileOutput,并保存
写入是主线程!不知道有没有方法可以解决卡顿
//写入文件
fileprivate func setupMoveFileOutput(){
if (self.movieOutput != nil) {
session.removeOutput(movieOutput!)
}
//1创建写入文件的输出
let fileOutput = AVCaptureMovieFileOutput()
self.movieOutput = fileOutput
//必须设置
let connection = fileOutput.connection(with: AVMediaType.video)
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(to: fileURL, recordingDelegate: self)
}
代理是在主线程调度的
extension ViewController : AVCaptureFileOutputRecordingDelegate{
func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
print("开始写入文件\(Thread.current)")
}
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
print("完成写入文件\(Thread.current)")
}
}
开和暂停
@IBAction func startCaptuer(_ sender: UIButton) {
session.startRunning()
// setupPreviewLayer()
previewLayer?.isHidden = false
//录制写入文件
self.setupMoveFileOutput()
}
@IBAction func stopCaptuer(_ sender: UIButton) {
//先停止输入
movieOutput?.stopRecording()
session.stopRunning()
previewLayer?.isHidden = true
}
网友评论