ios - 视频调整大小不符合要求的大小

时间:2016-12-24 05:43:22

标签: ios video avfoundation video-processing

我试图在我的ios应用中调整视频大小。我的代码如下:

fileprivate func resize(url: URL, height: CGFloat, completion: @escaping ((URL) -> Void)) {
  let video = AVAsset(url: url)
  guard let track = video.tracks(withMediaType: AVMediaTypeVideo).first
    else { return }
  let size = track.naturalSize

  // detect video rotation
  let txf = track.preferredTransform
  let videoAngle = atan2(txf.b, txf.a)
  let isRotated = videoAngle == CGFloat(M_PI_2) || videoAngle == CGFloat(M_PI_2 * 3)
  let videoW = isRotated ? size.height : size.width
  let videoH = isRotated ? size.width : size.height
  // get output width that keeps aspect ratio
  let width = height / videoH * videoW

  print("desired width \(width) height \(height)")
  print("original width \(size.width) height \(size.height)")

  // resize the video
  let videoComposition = AVMutableVideoComposition()
  videoComposition.renderSize = CGSize(width: width, height: height)
  videoComposition.frameDuration = CMTimeMake(1, 30)
  let instruction = AVMutableVideoCompositionInstruction()
  instruction.timeRange = CMTimeRangeMake(kCMTimeZero, video.duration)
  videoComposition.instructions = [instruction]
  let outputURL = Constants.cacheDirectory.appendingPathComponent(
    "\(String.random(ofLength: 10)).mp4")

  guard let exporter = AVAssetExportSession(
    asset: video,
    presetName: AVAssetExportPresetMediumQuality
  ) else { return }
  exporter.videoComposition = videoComposition
  exporter.outputURL = outputURL
  exporter.outputFileType = AVFileTypeQuickTimeMovie

  exporter.exportAsynchronously(completionHandler: { () -> Void in
    DispatchQueue.main.async {
      let asset = AVAsset(url: outputURL)
      let track = asset.tracks(withMediaType: AVMediaTypeVideo).first!
      print("result size \(track.naturalSize)")
      completion(outputURL)
    }
  })
}

当我在resize视频720上调1280.0 x 720.0并且旋转90度时,我得到320.0 x 568.0的结果和我的日志是:

desired width 405.0 height 720.0
original width 1280.0 height 720.0
result size (320.0, 568.0)

我甚至无法找到这些数字来自哪里的关系。唯一的问题是宽高比保持不变。

1 个答案:

答案 0 :(得分:1)

我最后采取了另一种方式,因为视频调整大小似乎要复杂得多,它应该在ios上。 SDAVAssetExportSession在处理所有这些方面做得很好,如果你看一下code那就有很多工作要做。

无论如何,我的最终代码如下:

import SDAVAssetExportSession

fileprivate func resize(url: URL, height: CGFloat, completion: @escaping ((Error?) -> Void)) {
  let video = AVAsset(url: url)

  guard let track = video.tracks(withMediaType: AVMediaTypeVideo).first
    else { return }
  let size = track.naturalSize

  let txf = track.preferredTransform
  let videoAngle = atan2(txf.b, txf.a)
  let isRotated = videoAngle == CGFloat(M_PI_2) || videoAngle == CGFloat(M_PI_2 * 3)
  let videoW = isRotated ? size.height : size.width
  let videoH = isRotated ? size.width : size.height
  let width = height / videoH * videoW

  let outputURL = Constants.cacheDirectory.appendingPathComponent(
    "\(String.random(ofLength: 10)).mp4")

  if let encoder = SDAVAssetExportSession(asset: AVAsset(url: url)) {
    encoder.outputFileType = AVFileTypeMPEG4
    encoder.outputURL = outputURL
    encoder.videoSettings = [
      AVVideoCodecKey: AVVideoCodecH264,
      AVVideoWidthKey: width,
      AVVideoHeightKey: height,
      AVVideoCompressionPropertiesKey: [
        AVVideoAverageBitRateKey: 1000000,
        AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
        AVVideoMaxKeyFrameIntervalKey: 60,
      ],
    ]

    encoder.exportAsynchronously(completionHandler: {
      if encoder.status == AVAssetExportSessionStatus.completed {
        DispatchQueue.main.async {
          self.url = outputURL
          let asset = AVAsset(url: outputURL)
          let track = asset.tracks(withMediaType: AVMediaTypeVideo).first!
          completion(nil)
        }
      } else if encoder.status == AVAssetExportSessionStatus.cancelled {
        completion(nil)
      } else {
        completion(encoder.error)
      }
    })
  }
}