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的各项特性,以及为什么它会…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
机器学习的数学基础:线性模型
线性模型 线性模型的基本形式为: f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法,得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...