0

I want to first trimming video that choose from photoLibrary, and then compress video file for custom size and bitrate. I'm using PryntTrimmerView for Trimming video, and then use trimmed video for compress video file. there is my code for trimming and compressing video file. I successfully export trimming asset, and then get compressed file successfully. when I choose short video from gallery there is no problem, but when choose video big size after compressing I have this error in console: Message from debugger: Terminated due to memory issue there is my code for trimming and compressing video file.

func prepareAssetComposition() throws {
    topActivity.isHidden = false
    topActivity.startAnimating()
    confirmButton.isUserInteractionEnabled = false
    //get asset and track
    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)
    }
    //set video oriention to portrati
    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
    }
    //start exporting video
    var name = ""
    var url: URL!
    if self.state == .Left {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie1.mp4")
      name = "TrimmedMovie1.mp4"
    }else if state == .Right {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie3.mp4")
      name = "TrimmedMovie3.mp4"
    }else if state == .Center {
      url = URL(fileURLWithPath: "\(NSTemporaryDirectory())TrimmedMovie2.mp4")
      name = "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)
          print(asset.duration)
          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 {
            self.playbackTimeCheckerTimer?.invalidate()
            self.playButton.setImage(#imageLiteral(resourceName: "play"), for: .normal)
            self.playbackTimeCheckerTimer = nil
            let size = CGSize(width: 1280, height: 720)

            if  let  videoData = NSData(contentsOf: url) {
              vData = videoData as Data
            }
            let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let folderPath: URL = directoryURL.appendingPathComponent(name, isDirectory: true)
            do {
              try vData?.write(to: folderPath, options: [])
            }
            catch {
              print(error.localizedDescription)
            }

            self.compress(fileName:name,videoPath: folderPath.path, exportVideoPath: folderPath.path, renderSize: size, completion: {res in
              if res {
                OperationQueue.main.addOperation {
                self.topActivity.isHidden = true
                self.topActivity.stopAnimating()
                self.confirmButton.isUserInteractionEnabled = true
                delegate.setVideoFromPath(path: folderPath.path, thump: thump, videoData: vData)
                self.dismiss(animated: true, completion: nil)
                  return
                }
              }else {
                print("can not compress")
              }
            })
          }
        } else {
          self.topActivity.isHidden = true
          self.topActivity.stopAnimating()
          self.confirmButton.isUserInteractionEnabled = true
          let error = exportSession?.error
          print("error exporting video \(String(describing: error))")
        }
      }
    })
  }
  private func existsFileAtUrl(url:String,name:String) -> Bool {

    let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
    let url = URL(fileURLWithPath: path)
    let filePath = url.appendingPathComponent(name).path
    let fileManager = FileManager.default
    if fileManager.fileExists(atPath: filePath) {
      return true
    } else {
      return false
    }
  }
  //MARK: Compress
  func compress(fileName:String,videoPath : String, exportVideoPath : String, renderSize : CGSize, completion : @escaping (Bool) -> ()) {

    let videoUrl = URL(fileURLWithPath: videoPath)
    if (!existsFileAtUrl(url: videoUrl.absoluteString,name:fileName)) {
      completion(false)
      return
    }

    let videoAssetUrl = AVURLAsset(url: videoUrl)
    let videoTrackArray = videoAssetUrl.tracks(withMediaType: AVMediaTypeVideo)

    if videoTrackArray.count < 1 {
      completion(false)
      return
    }
    let videoAssetTrack = videoTrackArray[0]
    let audioTrackArray = videoAssetUrl.tracks(withMediaType: AVMediaTypeAudio)

    if audioTrackArray.count < 1 {
      completion(false)
      return
    }
    let audioAssetTrack = audioTrackArray[0]
    let outputUrl = URL(fileURLWithPath: exportVideoPath)
    var videoWriter = try? AVAssetWriter(url: outputUrl, fileType: AVFileTypeQuickTimeMovie)
    videoWriter?.shouldOptimizeForNetworkUse = true

    let vSetting = videoSettings(size: renderSize)
    let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: vSetting)
    videoWriterInput.expectsMediaDataInRealTime = false
    videoWriterInput.transform = videoAssetTrack.preferredTransform
    videoWriter?.add(videoWriterInput)

    // output readers

    let videoReaderSettings : [String : Int] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)]
    let videoReaderOutput = AVAssetReaderTrackOutput(track: videoAssetTrack, outputSettings: videoReaderSettings)
    let videoReader = try! AVAssetReader(asset: videoAssetUrl)
    videoReader.add(videoReaderOutput)
    videoWriter?.startWriting()
    videoReader.startReading()
    videoWriter?.startSession(atSourceTime: kCMTimeZero)

    let processingVideoQueue = DispatchQueue(label: "processingVideoCompressionQueue")
    videoWriterInput.requestMediaDataWhenReady(on: processingVideoQueue, using: {
      while(videoWriterInput.isReadyForMoreMediaData){
        let sampleVideoBuffer = videoReaderOutput.copyNextSampleBuffer()
        if (videoReader.status == .reading && sampleVideoBuffer != nil) {
          videoWriterInput.append(sampleVideoBuffer!)
        }else {
          videoWriterInput.markAsFinished()
          if (videoReader.status == .completed) {
                    videoWriter?.finishWriting(completionHandler: {
                      videoWriter = nil
                      completion(true)
                    })
          }
        }
      }
    })
  }

  //MARK: Setting
  func videoSettings(size : CGSize) -> [String : AnyObject] {

    var compressionSettings = [String : AnyObject]()
    compressionSettings[AVVideoAverageBitRateKey] = 5 as AnyObject

    var settings = [String : AnyObject]()
    settings[AVVideoCompressionPropertiesKey] = compressionSettings as AnyObject
    settings[AVVideoCodecKey] = AVVideoCodecH264 as AnyObject?
    settings[AVVideoHeightKey] = size.height as AnyObject?
    settings[AVVideoWidthKey] = size.width as AnyObject?

    return settings
  }
ava
  • 1,148
  • 5
  • 15
  • 44

1 Answers1

0

I found issue, the problem is while statement. when I dismiss view controller this statement repeatedly call and I get this error. now when I want to dismiss view controller stop while loop with break and everything is working fine.

ava
  • 1,148
  • 5
  • 15
  • 44