美文网首页
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自定义视频压缩

    一、前言 随着抖音,快手等APP的迅猛发展,短视频在移动端的地位越来越突出。而视频压缩是视频传输中很关键的一步。 ...

  • springboot服务端视频压缩和图片压缩

    视频压缩:参考:(61条消息) JAVA,实现视频压缩(最全)seniorShen的博客-CSDN博客压缩视频实现...

  • iOS 视频压缩

    iPhone默认录制视频为高质量视频,视频体积很大,对流量,网速都是很大的考验。测试发现从高质量( AVAsset...

  • iOS视频压缩

    JJVideoManagerKit https://github.com/ljj756640646/JJVideo...

  • iOS 视频压缩

    1.获取本地视频,fromUrl为本地视频链接 AVAsset*asset = [AVAsset assetWit...

  • iOS视频压缩

    项目中涉及视频上传需求的, 为了上传和拉取速度体验, 节省存储费用, 都会在上传前进行视频压缩. 下面提供两种视频...

  • iOS AVFoundation自定义视频压缩 自定义视频 比特

    最近做视频压缩上传功能 刚开始用的苹果已经简单封装好的 AVAssetExportSession 框架 视频压缩上...

  • iOS视频压缩AVAssetExportSession

    AVAssetExportSession是系统自带的压缩

  • iOS的视频压缩

    之前公司在做一个聊天的项目,里面用到了发送视频的功能,由于一些视频是从苹果的相册里读取的,所以拿到的文件比较大,服...

  • 【iOS】 视频压缩上传

    之前写过图片上传PHP服务器,今天把接口稍微改了一下,把视频上传的代码贴出来,目前上传功能已经调通,视频的压缩代码...

网友评论

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

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