AVMutableComposition旋转视频文件

时间:2018-06-30 07:44:33

标签: ios swift avassetexportsession avmutablecomposition trim

我正在使用PryntTrimmerView修剪视频文件。我的代码用于导出修整视频文件并生成视频缩略图:

func prepareAssetComposition() throws {

    guard let asset = trimmerView.asset, let videoTrack = asset.tracks(withMediaType: AVMediaTypeVideo).last else {
      return
    }
    let size = videoTrack.naturalSize.applying(videoTrack.preferredTransform)
    print(CGSize(width: fabs(size.width), height: fabs(size.height)))

    let assetComposition = AVMutableComposition()
    let start = trimmerView.startTime?.seconds
    let end = trimmerView.endTime?.seconds
    let startTime = CMTime(seconds: Double(start ?? 0), preferredTimescale: 1000)
    let endTime = CMTime(seconds: Double(end ?? 0), preferredTimescale: 1000)
    let trackTimeRange = CMTimeRange(start: startTime, end: endTime)


    let compositionTrack = assetComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
    try compositionTrack.insertTimeRange(trackTimeRange, of: videoTrack, at: kCMTimeZero)

    var url: URL!
    if self.state == .Left {
     url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie1.mp4")
    }else if state == .Right {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie3.mp4")

    }else if state == .Center {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie2.mp4")
    }

    try? FileManager.default.removeItem(at: url)

    let exportSession = AVAssetExportSession(asset: assetComposition, presetName: AVAssetExportPresetHighestQuality)
    if UIDevice.current.userInterfaceIdiom == .phone {
    exportSession?.outputFileType = AVFileTypeQuickTimeMovie
    }else {
      exportSession?.outputFileType = AVFileTypeQuickTimeMovie
    }
    exportSession?.shouldOptimizeForNetworkUse = true
    exportSession?.outputURL = url
    exportSession?.exportAsynchronously(completionHandler: {

      DispatchQueue.main.async {

        if let url = exportSession?.outputURL, exportSession?.status == .completed {
          var thump: UIImage?
          var vData: Data?
          if let asset = self.trimmerView.asset {
          if let img = asset.videoThumbnail {
            thump = img
          }
          }
          if  let  videoData = NSData(contentsOf: url) {
            vData = videoData as Data
          }
          if let delegate = self.delegate {
            delegate.setVideoFromPath(path: url.path, thump: thump, videoData: vData)
            self.dismiss(animated: true, completion: nil)
          }
        } else {
          let error = exportSession?.error
          print("error exporting video \(String(describing: error))")
        }
      }
    })
  }

extension AVAsset{
  var videoThumbnail:UIImage?{
    let assetImageGenerator = AVAssetImageGenerator(asset: self)
    var time = self.duration
    time.value = min(time.value, 2)
    do {
      let imageRef = try assetImageGenerator.copyCGImage(at: time, actualTime: nil)
      let thumbNail = UIImage.init(cgImage: imageRef)
      print("Video Thumbnail genertated successfuly")
      return thumbNail

    } catch {
      print("error getting thumbnail video")
      return nil
    }

  }
}

有时,导出的视频和缩略图会旋转为横向旋转,这很可能在将视频记录在移动相机上时发生。 如何解决这个问题。并迫使资产导向走向纵向? 感谢所有答复。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。有我的Swift 3.2代码

 func prepareAssetComposition() throws {


    guard let asset = trimmerView.asset, let videoTrack = asset.tracks(withMediaType: AVMediaTypeVideo).first else {
      return
    }

    let assetComposition = AVMutableComposition()
    let start = trimmerView.startTime?.seconds
    let end = trimmerView.endTime?.seconds
    let startTime = CMTime(seconds: Double(start ?? 0), preferredTimescale: 1000)
    let endTime = CMTime(seconds: Double(end ?? 0), preferredTimescale: 1000)
    let trackTimeRange = CMTimeRange(start: startTime, end: endTime)

    let videoCompositionTrack = assetComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)

    try videoCompositionTrack.insertTimeRange(trackTimeRange, of: videoTrack, at: kCMTimeZero)

    if let audioTrack = asset.tracks(withMediaType: AVMediaTypeAudio).first {
      let audioCompositionTrack = assetComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)

      try audioCompositionTrack.insertTimeRange(trackTimeRange, of: audioTrack, at: kCMTimeZero)
    }

    let size = videoTrack.naturalSize
    let txf = videoTrack.preferredTransform

    var recordType = ""
    if (size.width == txf.tx && size.height == txf.ty){
     recordType = "UIInterfaceOrientationLandscapeRight"
    }else if (txf.tx == 0 && txf.ty == 0){
     recordType = "UIInterfaceOrientationLandscapeLeft"
    }else if (txf.tx == 0 && txf.ty == size.width){
     recordType = "UIInterfaceOrientationPortraitUpsideDown"
    }else{
    recordType = "UIInterfaceOrientationPortrait"
  }

    if recordType == "UIInterfaceOrientationPortrait" {
      let t1: CGAffineTransform = CGAffineTransform(translationX: videoTrack.naturalSize.height, y: -(videoTrack.naturalSize.width - videoTrack.naturalSize.height)/2)
      let t2: CGAffineTransform = t1.rotated(by: CGFloat(Double.pi / 2))
      let finalTransform: CGAffineTransform = t2
      videoCompositionTrack.preferredTransform = finalTransform
    }else if recordType == "UIInterfaceOrientationLandscapeRight" {
      let t1: CGAffineTransform = CGAffineTransform(translationX: videoTrack.naturalSize.height, y: -(videoTrack.naturalSize.width - videoTrack.naturalSize.height)/2)
      let t2: CGAffineTransform = t1.rotated(by: -CGFloat(Double.pi))
      let finalTransform: CGAffineTransform = t2
      videoCompositionTrack.preferredTransform = finalTransform
    }else if recordType == "UIInterfaceOrientationPortraitUpsideDown" {
      let t1: CGAffineTransform = CGAffineTransform(translationX: videoTrack.naturalSize.height, y: -(videoTrack.naturalSize.width - videoTrack.naturalSize.height)/2)
      let t2: CGAffineTransform = t1.rotated(by: -CGFloat(Double.pi/2))
      let finalTransform: CGAffineTransform = t2
      videoCompositionTrack.preferredTransform = finalTransform
    }

    var url: URL!
    if self.state == .Left {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie1.mp4")
    }else if state == .Right {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie3.mp4")

    }else if state == .Center {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie2.mp4")
    }

    try? FileManager.default.removeItem(at: url)

    let exportSession = AVAssetExportSession(asset: assetComposition, presetName: AVAssetExportPresetHighestQuality)
    if UIDevice.current.userInterfaceIdiom == .phone {
      exportSession?.outputFileType = AVFileTypeQuickTimeMovie
    }else {
      exportSession?.outputFileType = AVFileTypeQuickTimeMovie
    }
    exportSession?.shouldOptimizeForNetworkUse = true
    exportSession?.outputURL = url
    exportSession?.exportAsynchronously(completionHandler: {

      DispatchQueue.main.async {

        if let url = exportSession?.outputURL, exportSession?.status == .completed {
          let asset = AVAsset(url: url)
          var thump: UIImage?
          var vData: Data?
          if let img = asset.videoThumbnail {
            thump = img
            if recordType == "UIInterfaceOrientationPortrait" {
              if  thump != nil {
                let img = UIImage(cgImage: thump!.cgImage!, scale: CGFloat(1.0), orientation: .right)
                thump = img
                thump = thump?.fixedOrientation()
              }
            }else if recordType == "UIInterfaceOrientationLandscapeRight" {
              if  thump != nil {
                let img = UIImage(cgImage: thump!.cgImage!, scale: CGFloat(1.0), orientation: .down)
                thump = img
                thump = thump?.fixedOrientation()
              }

            }else if recordType == "UIInterfaceOrientationPortraitUpsideDown" {
              if  thump != nil {
                let img = UIImage(cgImage: thump!.cgImage!, scale: CGFloat(1.0), orientation: .left)
                thump = img
                thump = thump?.fixedOrientation()
              }
            }
          }
          if  let  videoData = NSData(contentsOf: url) {
            vData = videoData as Data
          }
          if let delegate = self.delegate {
            delegate.setVideoFromPath(path: url.path, thump: thump, videoData: vData)
            self.dismiss(animated: true, completion: nil)
          }
        } else {
          let error = exportSession?.error
          print("error exporting video \(String(describing: error))")
        }
      }
    })

  }