美文网首页
iOS 视频压缩(自定义压缩参数)

iOS 视频压缩(自定义压缩参数)

作者: KevinDengSir | 来源:发表于2021-02-26 18:28 被阅读0次

    最近一个新需求需要将选择的视频进行压缩后上传,且要求按照压缩参数进行压缩。因此写上这文章记录下,我总结过后写出的关于自定义压缩参数压缩视频。

    - (void)compressVideo:(NSURL *)videoUrl
        withVideoSettings:(NSDictionary *)videoSettings
            AudioSettings:(NSDictionary *)audioSettings
                 fileType:(AVFileType)fileType
                 complete:(void (^)(NSURL * _Nullable, NSError * _Nullable))complete {
      NSURL *outputUrl = [NSURL fileURLWithPath:[self buildFilePath]];
      
      AVAsset *asset = [AVAsset assetWithURL:videoUrl];
      AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:asset error:nil];
      AVAssetWriter *writer = [AVAssetWriter assetWriterWithURL:outputUrl fileType:fileType error:nil];
      
      // video part
      AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject];
      AVAssetReaderTrackOutput *videoOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:[self configVideoOutput]];
      AVAssetWriterInput *videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
      if ([reader canAddOutput:videoOutput]) {
        [reader addOutput:videoOutput];
      }
      if ([writer canAddInput:videoInput]) {
        [writer addInput:videoInput];
      }
      
      // audio part
      AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
      AVAssetReaderTrackOutput *audioOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:[self configAudioOutput]];
      AVAssetWriterInput *audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
      if ([reader canAddOutput:audioOutput]) {
        [reader addOutput:audioOutput];
      }
      if ([writer canAddInput:audioInput]) {
        [writer addInput:audioInput];
      }
      
      // 开始读写
      [reader startReading];
      [writer startWriting];
      [writer startSessionAtSourceTime:kCMTimeZero];
      
      //创建视频写入队列
      dispatch_queue_t videoQueue = dispatch_queue_create("Video Queue", DISPATCH_QUEUE_SERIAL);
      //创建音频写入队列
      dispatch_queue_t audioQueue = dispatch_queue_create("Audio Queue", DISPATCH_QUEUE_SERIAL);
      //创建一个线程组
      dispatch_group_t group = dispatch_group_create();
      //进入线程组
      dispatch_group_enter(group);
      //队列准备好后 usingBlock
      [videoInput requestMediaDataWhenReadyOnQueue:videoQueue usingBlock:^{
        BOOL completedOrFailed = NO;
        while ([videoInput isReadyForMoreMediaData] && !completedOrFailed) {
              CMSampleBufferRef sampleBuffer = [videoOutput copyNextSampleBuffer];
          if (sampleBuffer != NULL) {
            [videoInput appendSampleBuffer:sampleBuffer];
            DLog(@"===%@===", sampleBuffer);
            CFRelease(sampleBuffer);
          }
          else {
            completedOrFailed = YES;
            [videoInput markAsFinished];
            dispatch_group_leave(group);
          }
        }
      }];
      
      dispatch_group_enter(group);
      //队列准备好后 usingBlock
      [audioInput requestMediaDataWhenReadyOnQueue:audioQueue usingBlock:^{
        BOOL completedOrFailed = NO;
        while ([audioInput isReadyForMoreMediaData] && !completedOrFailed) {
          CMSampleBufferRef sampleBuffer = [audioOutput copyNextSampleBuffer];
          if (sampleBuffer != NULL) {
            BOOL success = [audioInput appendSampleBuffer:sampleBuffer];
            DLog(@"===%@===", sampleBuffer);
            CFRelease(sampleBuffer);
            completedOrFailed = !success;
          }
          else {
            completedOrFailed = YES;
          }
        }
        
        if (completedOrFailed) {
          [audioInput markAsFinished];
          dispatch_group_leave(group);
        }
      }];
      
      //完成压缩
      dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        if ([reader status] == AVAssetReaderStatusReading) {
          [reader cancelReading];
        }
        
        switch (writer.status) {
          case AVAssetWriterStatusWriting: {
            DLog(@"视频压缩完成");
            [writer finishWritingWithCompletionHandler:^{
              
              // 可以尝试异步回至主线程回调
              if (complete) {
                complete(outputUrl,nil);
              }
              
            }];
          }
            break;
              
          case AVAssetWriterStatusCancelled:
            DLog(@"取消压缩");
            break;
              
          case AVAssetWriterStatusFailed:
            DLog(@"===error:%@===", writer.error);
            if (complete) {
              complete(nil,writer.error);
            }
            break;
              
          case AVAssetWriterStatusCompleted: {
            DLog(@"视频压缩完成");
            [writer finishWritingWithCompletionHandler:^{
              
              // 可以尝试异步回至主线程回调
              if (complete) {
                complete(outputUrl,nil);
              }
            }];
          }
            break;
              
          default:
            break;
        }
      });
    }
    
    /** 视频解码 */
    - (NSDictionary *)configVideoOutput {
    
      NSDictionary *videoOutputSetting = @{
        (__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_422YpCbCr8],
        (__bridge NSString *)kCVPixelBufferIOSurfacePropertiesKey:[NSDictionary dictionary]
      };
        
      return videoOutputSetting;
    }
    
    
    /** 音频解码 */
    - (NSDictionary *)configAudioOutput {
      NSDictionary *audioOutputSetting = @{
        AVFormatIDKey: @(kAudioFormatLinearPCM)
      };
      return audioOutputSetting;
    }
    
    /// 指定音视频的压缩码率,profile,帧率等关键参数信息,这些参数可以根据要求自行更改
    - (NSDictionary *)performanceVideoSettings {
      NSDictionary *compressionProperties = @{
        AVVideoAverageBitRateKey          : @(409600), // 码率 400K
        AVVideoExpectedSourceFrameRateKey : @24, // 帧率
        AVVideoProfileLevelKey            : AVVideoProfileLevelH264HighAutoLevel
      };
      
      NSString *videoCodeec;
      if (@available(iOS 11.0, *)) {
          videoCodeec = AVVideoCodecTypeH264;
      } else {
          videoCodeec = AVVideoCodecH264;
      }
      NSDictionary *videoCompressSettings = @{
        AVVideoCodecKey                 : videoCodeec,
        AVVideoWidthKey                 : @640,
        AVVideoHeightKey                : @360,
        AVVideoCompressionPropertiesKey : compressionProperties,
        AVVideoScalingModeKey           : AVVideoScalingModeResizeAspectFill
      };
      
      return videoCompressSettings;
    }
    
    - (NSDictionary *)performanceAudioSettings {
      AudioChannelLayout stereoChannelLayout = {
        .mChannelLayoutTag = kAudioChannelLayoutTag_Stereo, 
        .mChannelBitmap = kAudioChannelBit_Left,
        .mNumberChannelDescriptions = 0
      };
      NSData *channelLayoutAsData = [NSData dataWithBytes:&stereoChannelLayout length:offsetof(AudioChannelLayout, mChannelDescriptions)];
      NSDictionary *audioCompressSettings = @{
        AVFormatIDKey         : @(kAudioFormatMPEG4AAC),
        AVEncoderBitRateKey   : @(49152), // 码率 48K
        AVSampleRateKey       : @44100, // 采样率
        AVChannelLayoutKey    : channelLayoutAsData,
        AVNumberOfChannelsKey : @(2)  // 声道
      };
      
      return audioCompressSettings;
    }
    

    相关文章

      网友评论

          本文标题:iOS 视频压缩(自定义压缩参数)

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