iOS使用AVCaptureSession实现音视频采集

这篇具有很好参考价值的文章主要介绍了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];
                    }
                }
            }
        }
    }
}

停止视频录制文章来源地址https://www.toymoban.com/news/detail-736850.html

- (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实现音视频采集的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

    iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

    iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动 在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。 在iOS需要为工程新建Target:NotificationServiceExtensi

    2024年02月14日
    浏览(15)
  • 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 )

    【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 )

    本篇文件主要分析 音视频文件 是怎么产生的 , 以及 音视频文件是如何播放的 ; 视频文件从录像到生成文件的全过程 : 采集图像帧 : 摄像头 硬件 负责 采集画面 , 采集的 初始画面 称为 \\\" 图像帧 \\\" , 一秒钟 采集 的 图像帧 数量 称为 \\\" 帧率 \\\" , 如 : 60 帧 就是 一秒钟采集 60 个画

    2024年02月11日
    浏览(47)
  • Python 爬虫 之 抖音视频采集

    Python 爬虫 之 抖音视频采集

    嗨喽,大家好呀~这里是爱看美女的茜茜呐 知识点: 动态数据抓包 requests发送请求 开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests pip install requests 如何安装python第三方模块: win + R 输入 cmd 点击确定, 输入安装命令 pip install 模块名 (pip install requests) 回车 在pycharm中点击

    2024年01月20日
    浏览(16)
  • 抖音视频批量提取采集软件|视频无水印下载工具

    抖音视频批量提取采集软件|视频无水印下载工具

    高效批量提取抖音视频,轻松应对营销需求! 在抖音视频营销中,如何高效地获取大量视频资源是许多市场人员面临的挑战。针对这一需求,我们开发了一款功能强大的抖音视频批量提取采集软件,帮助您快速、方便地获取所需视频,满足您的营销需求。 简介: 我们的软件

    2024年04月14日
    浏览(10)
  • 音视频开发:音频编码原理+采集+编码实战

    音视频开发:音频编码原理+采集+编码实战

    消除冗余信息,压缩量最大,也叫有损压缩 剔除人耳听觉范围外的音频信号20Hz以下和20000Hz以上; 去除被掩蔽的音频信号,信号的遮蔽可以分为频域遮蔽和时域遮蔽; 频域遮蔽效应 屏蔽70分贝以下,20HZ以下,20000HZ以上 屏蔽分贝小,频率小的声音 两个频率相近发出的声音,

    2024年02月05日
    浏览(10)
  • 抖音视频无水印采集拓客软件|视频批量下载提取工具

    抖音视频无水印采集拓客软件|视频批量下载提取工具

    抖音视频无水印批量采集拓客软件助力高效营销!         随着抖音平台的崛起,视频已成为各行各业进行营销的重要工具。但是,传统的视频下载方式往往效率低下,无法满足快速获取大量视频的需求。针对这一问题,我们开发了一款视频无水印批量采集拓客软件。 工具

    2024年04月14日
    浏览(12)
  • 抖音视频评论采集软件|抖音数据抓取工具

    抖音视频评论采集软件|抖音数据抓取工具

            抖音视频评论采集软件是一款基于C#开发的高效、便捷的工具,旨在为用户提供全面的数据采集和分析服务。该软件不仅支持通过进行搜索抓取,还能够通过分享链接进行单个视频的抓取和下载,让用户轻松获取抖音视频评论数据。         其中,批量视频提

    2024年04月11日
    浏览(9)
  • Qt音视频开发40-ffmpeg采集桌面并录制

    之前用ffmpeg打通了各种视频文件和视频流以及本地摄像头设备的采集,近期有个客户需求要求将整个桌面屏幕采集下来,并可以录制保存成MP4文件,以前也遇到过类似的需求,由于没有搞过,也没有精力去摸索和测试,所以也就一直耽搁着,近期刚好这个需求又来了,定下心

    2023年04月25日
    浏览(14)
  • iOS】AVPlayer 播放音视频

    iOS开发中不可避免地会遇到音视频播放方面的需求。 常用的音频播放器有 AVAudioPlayer、AVPlayer 等。不同的是,AVAudioPlayer 只支持本地音频的播放,而 AVPlayer 既支持本地音频播放,也支持网络音频播放。 常用的视频播放器有 MPMoviePlayerController、AVPlayer 等。不同的是,MPMoviePlay

    2024年02月14日
    浏览(12)
  • WebRTC音视频采集和播放示例及MediaStream媒体流解析

    WebRTC音视频采集和播放示例及MediaStream媒体流解析

    示例代码——同时打开摄像头和麦克风,并在页面显示画面和播放捕获的声音 API解析 mediaDevices MediaStream媒体流 代码 效果 1. mediaDevices mediaDevices 是 Navigator 只读属性,返回一个 MediaDevices 对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享。 语法

    2023年04月08日
    浏览(6)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包