iOS音视频处理

iOS音视频录音、播放、剪辑、合成

2017-10-30  本文已影响244人  一誠

一、录制

1、检测AVAudioSessionRecordPermission,用户是否有权限使用录音器

    [AVAudioSession sharedInstance].recordPermission == AVAudioSessionRecordPermissionGranted //授权
    // AVAudioSessionRecordPermissionUndetermined 没有决定
    // AVAudioSessionRecordPermissionDenied 用户禁止

2、请求授权

    AVAudioSession *session = [AVAudioSession sharedInstance];
    if ([session respondsToSelector:@selector(requestRecordPermission:)]) {
        [session performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
            if (granted) {
                // 用户授权
                [self safeRecorder];
            } else {
                [self userDeniedRecordRequest];
            }
        }];
    }

3、开始录音
创建音频会话

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *sessionError;
    //录音会话的几种模式
     AVAudioSessionCategoryPlayAndRecord :边录音边播放
     AVAudioSessionCategoryAmbient       :混音播放,可以与其他音频应用同时播放
     AVAudioSessionCategorySoloAmbient   :独占播放
     AVAudioSessionCategoryPlayback      :后台播放,也是独占的
     AVAudioSessionCategoryRecord        :用于需要录音的应用,除了来电铃声,闹钟或日历提醒之外的其它系统声音都不会被播放,只提供单纯录音功能.
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
    if (audioSession != nil) {
        NSLog(@"Error creating sessing:%@", [sessionError description]);
    } else {
        //关闭其他音频播放,把自己设为活跃状态
        [audioSession setActive:YES error:&sessionError];
        NSLog(@"Error creating sessing:%@", [sessionError description]);
    }

录音设置

    //编码格式
    NSMutableDictionary*settings = [[NSMutableDictionary alloc]init];
    //设置录音格式
    // 1、kAudioFormatMPEG4AAC压缩格式能在显著减小文件的同时,保证音频的质量。同时Android也支持aac音频格式。
    [settings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC]forKey:AVFormatIDKey];
    //设置录音采样率(Hz)如:AVSampleRateKey==8000/44100/96000(影响音频的质量)
    [settings setValue:[NSNumber numberWithFloat:44100.0f]forKey:AVSampleRateKey];
    //录音通道数1或2 单声道 立体声
    [settings setValue:[NSNumber numberWithInt:1]forKey:AVNumberOfChannelsKey];
    //线性采样位数8、16、24、32
    //[settings setValue:[NSNumber numberWithInt:16]forKey:AVEncoderBitRateKey];
    
    // 创建录音器
    NSURL * recorderUrl = [NSURL fileURLWithPath:self.audioRecordPath];
    NSError * error = nil;
    self.audioRecorder = [[AVAudioRecorder alloc] initWithURL:recorderUrl settings:settings error:&error];
    if (error) {
        //Error Domain=NSOSStatusErrorDomain Code=1718449215 --- 录音格式错误
        NSLog(@"创建录音器 - %@",error.description);
    }
    //设置代理
    self.audioRecorder.delegate = self;
    //开启音频测量
    self.audioRecorder.meteringEnabled = YES;
    //准备记录录音
    [_audioRecorder prepareToRecord];
    //开启仪表计数功能,必须开启这个功能,才能检测音频值
    [_audioRecorder setMeteringEnabled:YES];
    //启动或者恢复记录的录音文件
    [_audioRecorder record];
    // 检测音频频率
    kWeakSelf
    [self.timer startWithEventHandler:^{//定时器每秒调用一次
        [weakSelf meterAudio];
    }];
    
    // 注册通知 检测录音过程是否被打断
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(audioSessionDidInterrupte:) name:AVAudioSessionInterruptionNotification object:nil];

这里通过计时器检测音频强度

- (void)meterAudio{
    [self.audioRecorder updateMeters];
    if (self.audioRecorder.recording) {
        //float num = [self.audioRecorder peakPowerForChannel:0];
        float power = [self.audioRecorder averagePowerForChannel:0];//音频强度范围时-160到0
        //customLog(@"获取频率--- %f - %f",num,power);
        CGFloat value = 1 - fabs(power / 160.0);
        customLog(@"强度值 --- %f",value);
    }
}

当录音过程被打断时调用

///录音被打断了
- (void)audioSessionDidInterrupte:(NSNotification *)notification{
    customLog(@"录音被中断了");
    NSArray *allKeys = notification.userInfo.allKeys;
    // 判断事件类型
    if([allKeys containsObject:AVAudioSessionInterruptionTypeKey]){
        AVAudioSessionInterruptionType audioInterruptionType = [[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] integerValue];
        switch (audioInterruptionType) {
            case AVAudioSessionInterruptionTypeBegan:
                break;
            case AVAudioSessionInterruptionTypeEnded:
                break;
        }
    }
    // 判断中断的音频录制是否可恢复录制
    if([allKeys containsObject:AVAudioSessionInterruptionOptionKey]){
        AVAudioSessionInterruptionOptions shouldResume = [[notification.userInfo valueForKey:AVAudioSessionInterruptionOptionKey] integerValue];
        if(shouldResume){
        }
    }
}

AVAudioRecorderDelegate

#pragma mark AVAudioRecorderDelegate
// AVAudioRecorder INTERRUPTION NOTIFICATIONS ARE DEPRECATED - Use AVAudioSession instead. 注册通知
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag{
    customLog(@"录制完成");
}

- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error{
    customLog(@"录制出错 %@",error);
}

二、播放

    // 播放器
    NSURL * audioUrl = [NSURL fileURLWithPath:url];
    NSError * error = nil;
    _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:audioUrl error:&error];
    if (error) {
        customLog(@"播放错误 --- %@",error.description);
    }
    [_audioPlayer prepareToPlay];
    _audioPlayer.delegate = self;
    [_audioPlayer prepareToPlay];
    [_audioPlayer play];

三、剪辑

    //AVURLAsset是AVAsset的子类,AVAsset类专门用于获取多媒体的相关信息,包括获取多媒体的画面、声音等信息.而AVURLAsset子类的作用则是根据NSURL来初始化AVAsset对象.
    AVURLAsset *videoAsset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:self.recordUrl]];
    //音频输出会话
    //AVAssetExportPresetAppleM4A: This export option will produce an audio-only .m4a file with appropriate iTunes gapless playback data(输出音频,并且是.m4a格式)
    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:videoAsset presetName:AVAssetExportPresetAppleM4A];
    self.exportSession = exportSession;
    //设置输出路径 / 文件类型 / 截取时间段
    exportSession.outputURL = [NSURL fileURLWithPath:self.outputUrl];
    exportSession.outputFileType = AVFileTypeAppleM4A;
    CMTime time = videoAsset.duration;
    exportSession.timeRange = CMTimeRangeFromTimeToTime(CMTimeMake(1 * time.timescale, time.timescale), CMTimeMake(5 * time.timescale, time.timescale));
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
      /**
        AVContentKeyRequestStatusRequestingResponse,
        AVContentKeyRequestStatusReceivedResponse,
       AVContentKeyRequestStatusRenewed,
       AVContentKeyRequestStatusRetried,
       AVContentKeyRequestStatusCancelled,
       AVContentKeyRequestStatusFailed
       */
      customLog(@"%ld",(long)exportSession.status);
      if (exportSession.status == AVAssetExportSessionStatusCompleted) {
          customLog(@"导出完成");
      }
    }];
        
// 通过CADisplayLink检测导出进度 过程一般很快
[self.timer startDisplayLinkWithTarget:self selector:@selector(updateProgress)];
- (void)updateProgress{
    customLog(@"%f",self.exportSession.progress);
    if (self.exportSession.progress >= 1) {
        [self.timer stopDisplayLink];
        // 播放
        [self.play playWithUrl:self.outputUrl];
    }
}

四、合成

  //AVURLAsset子类的作用则是根据NSURL来初始化AVAsset对象.
    AVURLAsset *audioAsset1 = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:self.recordUrl] options:nil];
    AVURLAsset *audioAsset2 = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:self.outputUrl] options:nil];
    //音频轨迹(一般视频至少有2个轨道,一个播放声音,一个播放画面.音频有一个)
    NSArray * audioAssets1 = [audioAsset1 tracksWithMediaType:AVMediaTypeAudio];//AVMediaTypeVideo视频
    AVAssetTrack *assetTrack1 = [audioAssets1 objectAtIndex:0];
    NSArray * audioAssets2 = [audioAsset2 tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *assetTrack2 = [audioAssets2 objectAtIndex:0];
    // 音频合成
    AVMutableComposition *composition = [AVMutableComposition composition];
    //AVMutableComposition用来合成视频或音频
    AVMutableCompositionTrack *compositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    // 把第二段录音添加到第一段后面
    [compositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset1.duration) ofTrack:assetTrack1 atTime:kCMTimeZero error:nil];
    [compositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset2.duration) ofTrack:assetTrack2 atTime:audioAsset2.duration error:nil];
    //输出
    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
    self.compositionSession = exportSession;
    exportSession.outputFileType = AVFileTypeAppleM4A;
    exportSession.outputURL = [NSURL fileURLWithPath:self.compositionUrl];
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        //exporeSession.status
        customLog(@"%ld",(long)exportSession.status);
        if (exportSession.status == AVAssetExportSessionStatusCompleted) {
            customLog(@"合成完成");
        }
    }];
    // 检测进度
    [self.timer startDisplayLinkWithTarget:self selector:@selector(updateCompositionProgress)];

参考:
什么是音频比特率、视频比特率、音频采样率?
音频剪辑、合成

上一篇下一篇

猜你喜欢

热点阅读