美文网首页IOS理论知识音视频iOS 视频图像相关
iOS AVFoundation 视频暂停 多视频合成 流程

iOS AVFoundation 视频暂停 多视频合成 流程

作者: 苏永茂 | 来源:发表于2016-08-05 17:46 被阅读2302次

    iOS AVFoundation 视频暂停 多视频合成 流程

    AVCaptureSession 只有开始和结束 编码的方法 。他并没有暂停的接口 。

    所以我们要做暂停就有两种思路 。

    • 点击暂停,就执行 stopRunning 方法 。恢复录制的时候重新录制下一个 。这样就录制了多个小视频 。然后手动把他们拼接起来 。
    • 点击暂停的时候,CMSampleBufferRef 不写入 。恢复录制的时候,再继续写入 。

    两种方法对应的功能点:

    • 多段视频的拼接
    • 时间偏移量(就是暂停的时候)的计算

    音视频中的时间 CMTime

    一个c结构体 ,包括:

    • typedef int64_t CMTimeValue : 分子

    • typedef int32_t CMTimeScale : 分母 (必须为正,vidio文件的推荐范围是movie files range from 600 to 90000)

    • typedef int64_t CMTimeEpoch : 类似循环次数(eg, loop number)加减法必须在同一个 epoch内

    • uint32_t, CMTimeFlags :标记位 (一个枚举值)

            kCMTimeFlags_Valid = 1UL<<0,(必须设置 ,否则CMTime无效)
            kCMTimeFlags_HasBeenRounded = 1UL<<1,
            kCMTimeFlags_PositiveInfinity = 1UL<<2,(正无穷)
            kCMTimeFlags_NegativeInfinity = 1UL<<3,(负无穷)
            kCMTimeFlags_Indefinite = 1UL<<4,(时间未定的时候,如实况直播的时候)
            kCMTimeFlags_ImpliedValueFlagsMask = 
            kCMTimeFlags_PositiveInfinity |     
            kCMTimeFlags_NegativeInfinity |     
            kCMTimeFlags_Indefinite
      

    second=value/timescale

    • 加法
      CMTime t3 = CMTimeAdd(t1, t2);

    • 减法
      CMTime t4 = CMTimeSubtract(t3, t1);

    • 获取second

    Float64 CMTimeGetSeconds(CMTime time)

    • CMTimeRange
      表示时间范围的一个数据类型 结构体:

      • CMTime : start起始时间
      • CMTime : duration 持续时间
    创建
    • CMTimeRange timeRange1 = CMTimeRangeMake(start, duration);
    • CMTimeRange timeRange2 = CMTimeRangeFromTimeToTime(t4, t3);

    计算连个时间段的交集并集

    • 交叉时间范围
      CMTimeRange intersectionRange = CMTimeRangeGetIntersection(timeRange2, timeRange1);
    • 总和时间范围
      CMTimeRange unionRange = CMTimeRangeGetUnion(timeRange1, timeRange2);

    --

    (一)时间偏移量(就是暂停的时候)的计算

    首先暂停的时候设置标志 discont = YES .

    然后我们的操作都是在 CMSampleBufferRef 的编码回调中进行

    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;
    
    
    • 第一种,如果是暂停的时候,进来的buffer 全部丢弃

      if (self.discont) 
      {
          if (isVideo) 
              return;
      }
      
    • 如果暂停结束,恢复录制 ,就要把buffer 传输给AVAssetWriter

      // 得到当前buffer 的时间
              CMTime pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
              CMTime last = isVideo ? _lastVideo : _lastAudio;
              if (last.flags & kCMTimeFlags_Valid) {
                  
                  // 一开始录制的时候  _timeOffset = CMTimeMake(0, 0);
      
                  // kCMTimeFlags_Valid 是否有效
                  if (_timeOffset.flags & kCMTimeFlags_Valid) {
                      // CMTime 减法
                      pts = CMTimeSubtract(pts, _timeOffset);
                  }
                  // 取得现在的时间 和 上一次时间 的时间差
                  CMTime offset = CMTimeSubtract(pts, last);
                  // 赋值给 _timeOfSet
                  if (_timeOffset.value == 0) {
                      _timeOffset = offset;
                  }else {
                      _timeOffset = CMTimeAdd(_timeOffset, offset);
                  }
              }
              // 清空记录
              _lastVideo.flags = 0;
              _lastAudio.flags = 0;
          }
          
              sampleBuffer = [self adjustTime:sampleBuffer by:_timeOffset];
          
      
      //调整媒体数据的时间
      - (CMSampleBufferRef)adjustTime:(CMSampleBufferRef)sample by:(CMTime)offset {
      CMItemCount count;
      CMSampleBufferGetSampleTimingInfoArray(sample, 0, nil, &count);
      CMSampleTimingInfo* pInfo = malloc(sizeof(CMSampleTimingInfo) * count);
      CMSampleBufferGetSampleTimingInfoArray(sample, count, pInfo, &count);
      for (CMItemCount i = 0; i < count; i++) {
          pInfo[i].decodeTimeStamp = CMTimeSubtract(pInfo[i].decodeTimeStamp, offset);
          pInfo[i].presentationTimeStamp = CMTimeSubtract(pInfo[i].presentationTimeStamp, offset);
      }
      CMSampleBufferRef sout;
      CMSampleBufferCreateCopyWithNewTiming(nil, sample, count, pInfo, &sout);
      free(pInfo);
      return sout;
      

    }

    ```
    
    //记录住这次buffer 的时间       
    
    ```
    //sampleBuffer的起点时间
        CMTime pts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
        //sampleBuffer 的持续时间
        CMTime dur = CMSampleBufferGetDuration(sampleBuffer);
        if (dur.value > 0) {
            // 得到这个buffer 的结束时间,记录下来
            pts = CMTimeAdd(pts, dur);
        }
        if (isVideo) {
            _lastVideo = pts;
        }else {
            _lastAudio = pts;
        }
    
    ```     
    
    最后就可以存储了。       
    

    (二)多段视频的拼接

    • 获取 录制好的一组 媒体资源 AVAsset

      for (NSURL *fileURL in fileURLArray) {
              AVAsset *asset = [AVAsset assetWithURL:fileURL];
              
              if (!asset) {
                  continue;
              }
              
              [assetArray addObject:asset];
       }
      
      
    • 对多个资源的操作需要用到 AVMutableComposition

      // 组成
          AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
      
    • AVMutableComposition给每一段资源生成对应的 音频轨道和视频轨道 ,把资源添加进轨道

      for (int i = 0; i < [assetArray count] ; i++) {
              
              AVAsset *asset = [assetArray objectAtIndex:i];
              AVAssetTrack *assetTrack = [assetTrackArray objectAtIndex:i];
              
              //一个 audio 轨道
              //AVMutableCompositionTrack provides a convenient interface for insertion, removals, and scaling of track
              //合成音频轨道    进行插入、缩放、删除
              AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
              //把第一段录制的 audio 插入到 AVMutableCompositionTrack
              [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                  ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
                                   atTime:totalDuration
                                    error:nil];
              //合成视频轨道
              AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
              //把录制的第一段 视频轨道插入到 AVMutableCompositionTrack
              [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                  ofTrack:assetTrack
                                   atTime:totalDuration
                                    error:&error];
                                    
      }                                  
      
    • 合成 需要使用AVAssetExportSession

      
          AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
          exporter.outputURL = mergeFileURL;
          exporter.outputFileType = AVFileTypeMPEG4;
          exporter.shouldOptimizeForNetworkUse = YES;
          [exporter exportAsynchronouslyWithCompletionHandler:^{
              dispatch_async(dispatch_get_main_queue(), ^{
                  //如果转换成功
                  if ( exporter.status == AVAssetExportSessionStatusCompleted)
                  {
                      if ([_delegate respondsToSelector:@selector(videoRecorder:didFinishMergingVideosToOutPutFileAtURL:)]) {
                          [_delegate videoRecorder:self didFinishMergingVideosToOutPutFileAtURL:mergeFileURL];
                      }
      
                  }
              });
          }];
      
      

    相关文章

      网友评论

      • 字母B一路向北:大神方便的话,求第二种拼接的demo 1096562298@qq.com
      • New_卡迪熊:大神视频合成的demo有吗 799610809@qq.com
      • sooon77:大神能 把两种实现方式的demo给一份么 904208686@qq.com
      • SunnyLeong:楼主多段视频拼接的Demo 95013297@qq.com 谢谢
      • 勤奋的张神:你好,大神,能发我你的demo吗,我想学习这方面的技术,两种都可以,谢谢了 1138113194@qq.com
      • smile丶淡然:第二种合成视频,中间会有黑屏闪过吗!
        757e213229b4:中间黑屏是因为使用的insertTimeRange的时间不正确导致的。
        Howie_54b9:哈喽,您好 合成视频的时候 会出现有方向不一致的问题。就是 我在本地录制了一个视频 方向是朝上的,但是用这个视频和网络上的一个视频合成之后,刚刚拍摄的视频方向就变了不是朝上的了。
        苏永茂:没有的 。
      • 不懂后悔:楼主能发个第二种方式的demo么?369485229@qq.com
      • 狗蛋的春天:求两种demo谢谢大神了916176426@qq.com
        不懂后悔:你好。你有这个合成的demo吗?发我一份。谢谢。369485229@qq.com
      • 博麗毛玉:求大神可以給我兩種的demo嗎? 感恩!!

        yahoo信箱 :z11x22c330011000@kimo.com
      • _弥勒:求第一种的demo
        谢谢大神
      • 来宝:楼主,有没有第二种的demo麻烦发一下,谢谢!460876003@qq.com
      • 爱恨如梦:请问有第二种多段录制合成的demo吗?麻烦你了
      • efd0507a0501:你好,同问一下有没有第二种多段录制合成的demo
      • 清水_yuxin:你好,请问你这个例子有demo吗?
        清水_yuxin:@苏永茂 又遇到个问题。合成裁剪多段的时候会合成失败。但是没有报错。求指导
        清水_yuxin:@苏永茂 第二种。合成我做了。多段的话手机很烫,也可能会闪退。谢谢😜
        苏永茂:@john_2016哪一种的?

      本文标题:iOS AVFoundation 视频暂停 多视频合成 流程

      本文链接:https://www.haomeiwen.com/subject/vjzhsttx.html