Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVMutableComposition rotate video file

I'm using PryntTrimmerView for trimming video file. there is my code for exportation trimming video file, and generating video thumbnail:

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
    }

  }
}

sometimes video and thumbnail that export rotate to landscape rotation, This is most likely to happen when the video is recorded on a mobile camera. How can solve this issue. and force asset Orientation to portrait? thanks for all reply.

like image 308
ava Avatar asked Oct 23 '25 14:10

ava


1 Answers

I found the solution. there is my code for 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))")
        }
      }
    })

  }
like image 155
ava Avatar answered Oct 26 '25 03:10

ava



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!