iOS使用AVCaptureSession实现音视频采集
AVCaptureSession配置采集行为并协调从输入设备到采集输出的数据流。要执行实时音视频采集,需要实例化采集会话并添加适当的输入和输出。
- AVCaptureSession:管理输入输出音视频流
- AVCaptureDevice:相机硬件的接口,用于控制硬件特性,诸如镜头的位置(前后摄像头)、曝光、闪光灯等。
- AVCaptureInput:配置输入设备,提供来自设备的数据
- AVCaptureOutput:管理输出的音视频数据流
- AVCaptureConnection:输入与输出的连接
- AVCaptureVideoPreviewLayer:显示当前相机正在采集的状况
- AVAssetWriter:将媒体数据写入到容器文件
初始化AVCaptureSession
- (AVCaptureSession *)captureSession {if (_captureSession == nil){_captureSession = [[AVCaptureSession alloc] init];if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {_captureSession.sessionPreset = AVCaptureSessionPreset1280x720;}}return _captureSession;
}- (dispatch_queue_t)videoQueue {if (!_videoQueue) {_videoQueue = dispatch_queue_create("VideoCapture", DISPATCH_QUEUE_SERIAL);}return _videoQueue;
}
添加视频输入
- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position {AVCaptureDeviceDiscoverySession *deviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:position];for (AVCaptureDevice *device in deviceDiscoverySession.devices) {if ([device position] == position) {return device;}}return nil;
}- (void)setupVideoInput {AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];if (!captureDevice){NSLog(@"captureDevice failed");return;}NSError *error = nil;self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];if (error) {NSLog(@"videoInput error:%@", error);return;}if ([self.captureSession canAddInput:self.videoInput]) {[self.captureSession addInput:self.videoInput];}
}
添加音频输入
- (void)setupAudioInput {AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];NSError *error = nil;self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];if (error) {NSLog(@"audioInput error:%@", error);return;}if ([self.captureSession canAddInput:self.audioInput]) {[self.captureSession addInput:self.audioInput];}
}
添加视频输出
- (void)setupVideoOutput {self.videoOutput = [[AVCaptureVideoDataOutput alloc] init];self.videoOutput.alwaysDiscardsLateVideoFrames = YES;[self.videoOutput setSampleBufferDelegate:self queue:self.videoQueue];if ([self.captureSession canAddOutput:self.videoOutput]) {[self.captureSession addOutput:self.videoOutput];}
}
添加音频输出
- (void)setupAudioOutput {self.audioOutput = [[AVCaptureAudioDataOutput alloc] init];[self.audioOutput setSampleBufferDelegate:self queue:self.videoQueue];if ([self.captureSession canAddOutput:self.audioOutput]) {[self.captureSession addOutput:self.audioOutput];}
}
设置视频预览
- (void)setupCaptureVideoPreviewLayer:(UIView *)previewView {_captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];CALayer *layer = previewView.layer;_captureVideoPreviewLayer.frame = previewView.bounds;_captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspect;_captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;_captureVideoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;[layer insertSublayer:_captureVideoPreviewLayer atIndex:0];
}
开始和结束采集会话
- (void)startSession {if (![self.captureSession isRunning]) {[self.captureSession startRunning];}
}- (void)stopSession{if ([self.captureSession isRunning]) {[self.captureSession stopRunning];}
}
初始化AVAssetWriter,将音视频保存到视频文件
- (void)setUpWriter {if (self.videoURL == nil) {return;}self.assetWriter = [AVAssetWriter assetWriterWithURL:self.videoURL fileType:AVFileTypeMPEG4 error:nil];NSInteger numPixels = kScreenWidth * kScreenHeight;CGFloat bitsPerPixel = 12.0;NSInteger bitsPerSecond = numPixels * bitsPerPixel;NSDictionary *compressionProperties = @{ AVVideoAverageBitRateKey : @(bitsPerSecond),AVVideoExpectedSourceFrameRateKey : @(15),AVVideoMaxKeyFrameIntervalKey : @(15),AVVideoProfileLevelKey : AVVideoProfileLevelH264BaselineAutoLevel };self.videoCompressionSettings = @{ AVVideoCodecKey : AVVideoCodecTypeH264,AVVideoWidthKey : @(width * 2),AVVideoHeightKey : @(height * 2),AVVideoScalingModeKey : AVVideoScalingModeResizeAspect,AVVideoCompressionPropertiesKey : compressionProperties };_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:self.videoCompressionSettings];_assetWriterVideoInput.expectsMediaDataInRealTime = YES;self.audioCompressionSettings = @{ AVEncoderBitRatePerChannelKey : @(28000),AVFormatIDKey : @(kAudioFormatMPEG4AAC),AVNumberOfChannelsKey : @(1),AVSampleRateKey : @(22050) };_assetWriterAudioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:self.audioCompressionSettings];_assetWriterAudioInput.expectsMediaDataInRealTime = YES;if ([_assetWriter canAddInput:_assetWriterVideoInput]){[_assetWriter addInput:_assetWriterVideoInput];}else{NSLog(@"AssetWriter videoInput append Failed");}if ([_assetWriter canAddInput:_assetWriterAudioInput]){[_assetWriter addInput:_assetWriterAudioInput];}else{NSLog(@"AssetWriter audioInput Append Failed");}_canWrite = NO;
}
AVCaptureVideoDataOutputSampleBufferDelegate和AVCaptureAudioDataOutputSampleBufferDelegate音视频处理
#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate|AVCaptureAudioDataOutputSampleBufferDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {@autoreleasepool{if (connection == [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]) {@synchronized(self){[self appendSampleBuffer:sampleBuffer ofMediaType:AVMediaTypeVideo];}}if (connection == [self.audioOutput connectionWithMediaType:AVMediaTypeAudio]) {@synchronized(self) {[self appendSampleBuffer:sampleBuffer ofMediaType:AVMediaTypeAudio];}}}
}- (void)appendSampleBuffer:(CMSampleBufferRef)sampleBuffer ofMediaType:(NSString *)mediaType {if (sampleBuffer == NULL){NSLog(@"empty sampleBuffer");return;}@autoreleasepool{if (!self.canWrite && mediaType == AVMediaTypeVideo){[self.assetWriter startWriting];[self.assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];self.canWrite = YES;}if (mediaType == AVMediaTypeVideo){if (self.assetWriterVideoInput.readyForMoreMediaData){BOOL success = [self.assetWriterVideoInput appendSampleBuffer:sampleBuffer];if (!success){NSLog(@"assetWriterVideoInput appendSampleBuffer fail");@synchronized (self){[self stopVideoRecorder];}}}}if (mediaType == AVMediaTypeAudio){if (self.assetWriterAudioInput.readyForMoreMediaData){BOOL success = [self.assetWriterAudioInput appendSampleBuffer:sampleBuffer];if (!success){NSLog(@"assetWriterAudioInput appendSampleBuffer fail");@synchronized (self){[self stopVideoRecorder];}}}}}
}
停止视频录制
- (void)stopVideoRecorder {__weak __typeof(self)weakSelf = self;if(_assetWriter && _assetWriter.status == AVAssetWriterStatusWriting) {[_assetWriter finishWritingWithCompletionHandler:^{weakSelf.canWrite = NO;weakSelf.assetWriter = nil;weakSelf.assetWriterAudioInput = nil;weakSelf.assetWriterVideoInput = nil;}];}
}
相关文章:
iOS使用AVCaptureSession实现音视频采集
AVCaptureSession配置采集行为并协调从输入设备到采集输出的数据流。要执行实时音视频采集,需要实例化采集会话并添加适当的输入和输出。 AVCaptureSession:管理输入输出音视频流AVCaptureDevice:相机硬件的接口,用于控制硬件特性…...
springboot和flask整合nacos,使用openfeign实现服务调用,使用gateway实现网关的搭建(附带jwt续约的实现)
环境准备: 插件版本jdk21springboot 3.0.11 springcloud 2022.0.4 springcloudalibaba 2022.0.0.0 nacos2.2.3(稳定版)python3.8 nacos部署(docker) 先创建目录,分别创建config,logs…...
深入浅出排序算法之基数排序
目录 1. 前言 1.1 什么是基数排序⭐⭐⭐ 1.2 执行流程⭐⭐⭐⭐⭐ 2. 代码实现⭐⭐⭐ 3. 性能分析⭐⭐ 3.1 时间复杂度 3.2 空间复杂度 1. 前言 一个算法,只有理解算法的思路才是真正地认识该算法,不能单纯记住某个算法的实现代码! 1.…...
CSS选择器、CSS属性相关
CSS选择器 CSS属性选择器 通过标签的属性来查找标签,标签都有属性 <div class"c1" id"d1"></div>id值和class值是每个标签都自带的属性,还有另外一种:自定义属性 <div class"c1" id"d1&…...
设计模式(21)中介者模式
一、介绍: 1、定义:中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象来降低多个对象之间的耦合度。在中介者模式中,各个对象之间不直接进行通信,而是通过中介者对象…...
JVM虚拟机:通过一个例子解释JVM中栈结构的使用
代码 代码解析 main方法执行,创建栈帧并压栈。 int d8,d为局部变量,是基础类型,它位于虚拟机栈的局部变量表中 然后创建了一个TestDemo的对象,这个对象在堆中,并且这个对象的成员变量(day&am…...
会自动写代码的AI大模型来了!阿里云推出智能编码助手通义灵码
用大模型写代码是什么样的体验?10月31日,杭州云栖大会上,阿里云对外展示了一款可自动编写代码的 AI 助手,在编码软件的对话窗口输入“帮我用 python 写一个飞机游戏”,短短几秒,这款名为“通义灵码”的 AI …...
如何公网远程访问本地WebSocket服务端
本地websocket服务端暴露至公网访问【cpolar内网穿透】 文章目录 本地websocket服务端暴露至公网访问【cpolar内网穿透】1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功…...
python 练习 在列表元素中合适的位置插入 输入值
目的: 有一列从小到大排好的数字元素列表, 现在想往其插入一个值,要求: 大于右边数字小于左边数字 列表元素: [1,4,6,13,16,19,28,40,100] # 方法: 往列表中添加一个数值,其目的方便元素位置往后…...
企业级JAVA、数据库等编程规范之命名风格 —— 超详细准确无误
🧸欢迎来到dream_ready的博客,📜相信你对这两篇博客也感兴趣o (ˉ▽ˉ;) 📜 表白墙/留言墙 —— 初级SpringBoot项目,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学 📜 用户登录前后端…...
有什么可以自动保存微信收到的图片和视频的方法么
8-1 在一些有外勤工作的公司里,经常会需要在外面工作的同事把工作情况的图片发到指定微信或者指定的微信群里,以记录工作进展等,或者打卡等,对于外勤人员来说,也就发个图片的事,但是对于在公司里收图片的人…...
面试算法46:二叉树的右侧视图
题目 给定一棵二叉树,如果站在该二叉树的右侧,那么从上到下看到的节点构成二叉树的右侧视图。例如,图7.6中二叉树的右侧视图包含节点8、节点10和节点7。请写一个函数返回二叉树的右侧视图节点的值。 分析 既然这个题目和二叉树的层相关&a…...
R语言使用surveyCV包对NHANES数据(复杂调查加权数据)进行10折交叉验证
美国国家健康与营养调查( NHANES, National Health and Nutrition Examination Survey)是一项基于人群的横断面调查,旨在收集有关美国家庭人口健康和营养的信息。 地址为:https://wwwn.cdc.gov/nchs/nhanes/Default.aspx 既往咱们…...
WOS与CNKI数据库的citespace分析教程及常见问题解决
本教程为面向新手的基于citespace的数据可视化教程,旨在帮助大家更快了解行业前沿的研究内容。 获取最新版本的citespace软件 在citespace官网下载最新的版本(如果是老版本,可能会提示让你去官网更新为最新版,老版本不再提供服务…...
NEFU数字图像处理(三)图像分割
一、图像分割的基本概念 1.1专有名词 前景和背景 在图像分割中,我们通常需要将图像分为前景和背景两个部分。前景是指图像中我们感兴趣、要分割出来的部分,背景是指和前景不相关的部分。例如,对于一张人物照片,人物就是前景&…...
UEditorPlus v3.6.0 图标补全,精简代码,快捷操作重构,问题修复
UEditor是由百度开发的所见即所得的开源富文本编辑器,基于MIT开源协议,该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器,主要做了样式的定制,更符…...
C++ Set
定义 set不同于vector,strin,list这种存储容器,set是一种关联式容器,底层是搜二叉; 功能 set可以确定唯一的值,可以排序去重。 接口 insert() #include <iostream> #include<set> using namespace std;int main…...
基于知识库的chatbot或者FAQ
背景 最近突然想做一个基于自己的知识库(knowlegebase)的chatbot或者FAQ的项目。未来如果可以在公司用chatgpt或者gpt3.5之后的模型的话,还可以利用gpt强大的语言理解力和搜索出来的用户问题的相关业务文档来回答用户在业务中的问题。 Chat…...
ZOC8 for Mac:超越期待的终端仿真器
在Mac上,一个优秀的终端仿真器是每位开发者和系统管理员的必备工具。ZOC8,作为一款广受好评的终端仿真器,以其强大的功能和易用性,已经在Mac用户中积累了良好的口碑。本文将为您详细介绍ZOC8的各项特性,以及为什么它会…...
背包问题优化指南:从二维数组到一维数组的空间压缩技巧(以0-1背包为例)
背包问题优化指南:从二维数组到一维数组的空间压缩技巧(以0-1背包为例) 在算法竞赛和性能敏感的开发场景中,动态规划的空间复杂度优化往往能带来显著的性能提升。0-1背包问题作为动态规划的经典案例,其空间优化路径具…...
3步解锁:让老旧电脑流畅运行Windows 11的终极精简方案
3步解锁:让老旧电脑流畅运行Windows 11的终极精简方案 【免费下载链接】tiny11builder Scripts to build a trimmed-down Windows 11 image. 项目地址: https://gitcode.com/GitHub_Trending/ti/tiny11builder 在数字时代,系统性能直接影响工作效…...
SillyTavern终极指南:如何构建沉浸式AI角色聊天体验
SillyTavern终极指南:如何构建沉浸式AI角色聊天体验 【免费下载链接】SillyTavern LLM Frontend for Power Users. 项目地址: https://gitcode.com/GitHub_Trending/si/SillyTavern 想要创建栩栩如生的AI角色对话体验吗?SillyTavern作为专为高级用…...
Packet Tracer实战:交换机基础配置与常见问题排查
1. Packet Tracer与交换机配置入门 第一次接触网络设备配置的朋友可能会觉得交换机是个神秘的黑盒子。其实用Cisco Packet Tracer这个仿真工具,你完全可以在自己的电脑上搭建一个虚拟实验室。我刚开始学习时也是从这个工具入手的,它比真机操作更友好——…...
二进制魔法:解密Windows平台消息防撤回的底层实现
二进制魔法:解密Windows平台消息防撤回的底层实现 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.com/Gi…...
深度解析GARbro:如何高效破解200+视觉小说资源格式的技术奥秘
深度解析GARbro:如何高效破解200视觉小说资源格式的技术奥秘 【免费下载链接】GARbro Visual Novels resource browser 项目地址: https://gitcode.com/gh_mirrors/gar/GARbro GARbro是一款面向视觉小说爱好者和游戏资源研究者的专业工具,基于.NE…...
GitHub Copilot 默认启用训练之后 企业安全如何应对
文章目录前言一、这次政策改动,到底改了什么二、为什么企业不能只看“Business 和 Enterprise 不受影响”三、content exclusion 为什么挡不住所有风险四、从 IDE 到 Agent,企业研发边界已经变了五、企业现在就该做的几件事总结前言 GitHub 这次关于 Co…...
异步流式响应总卡顿、丢帧、OOM?FastAPI 2.0三大核心配置必须在上线前重写,否则AI服务将不可用
第一章:FastAPI 2.0异步AI流式响应的典型故障图谱在 FastAPI 2.0 中启用异步流式响应(如 StreamingResponse 配合 async generator)处理大语言模型推理输出时,常见故障并非源于逻辑错误,而是由异步生命周期、客户端兼容…...
QAnything混合检索实战:ElasticSearch与向量搜索的协同优化
QAnything混合检索实战:ElasticSearch与向量搜索的协同优化 1. 为什么电商搜索总在“猜”用户心思? 你有没有遇到过这样的情况:在电商平台搜索“轻便透气运动鞋”,结果首页全是厚重的登山靴?或者搜“适合夏天穿的连衣…...
如何快速掌握PDF对比工具:5个实用场景完全指南
如何快速掌握PDF对比工具:5个实用场景完全指南 【免费下载链接】diff-pdf A simple tool for visually comparing two PDF files 项目地址: https://gitcode.com/gh_mirrors/di/diff-pdf PDF对比工具diff-pdf是一款开源的视觉化PDF文件对比神器,它…...
