0

My app is crashing when I select multiple videos(1+ min each) from photo library because of memory warning. I'm trying to compress videos but still the same issue although compression code is working properly. I want my app to select 5 videos at once and send them in chat. Whatsapp is allowing the user to select 30 videos and send them in chat but my app is crashing because of memory issues after 3 videos only. I am using "AssetsPickerViewController" lib for multiple pic/video selection.

func assetsPicker(controller: AssetsPickerViewController, selected assets: [PHAsset]) {
    self.dismiss(animated: true, completion: nil)
    
    var isImages = false
    var mediaData: [Data] = []
    let imageManager = PHCachingImageManager.default()
    DispatchQueue.main.async {
        self.appDelegate.helper.showHUD(withMessage: "Preparing media", withObject: self)
    }
    autoreleasepool {
        for selectedAsset in assets {
            if selectedAsset.mediaType == .image {
                isImages = true
                let option = PHImageRequestOptions()
                option.isSynchronous = true
                option.isNetworkAccessAllowed = true
                
                imageManager.requestImageData(for: selectedAsset, options: option) { (assetData, assetDataUTI, assetOrientation, assetInfo) in
                    if let data = assetData {
                        if let image = UIImage(data: data)?.upOrientation(), let finalData = image.jpegData(compressionQuality: 0.5) {
                            if let newData = ImageHelper.removeExifData(data: finalData as NSData) {
                                mediaData.append(newData as Data)
                                self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                            } else {
                                mediaData.append(finalData)
                                self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                            }
                        } else {
                            mediaData.append(data)
                            self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                        }
                    }
                }
            } else if selectedAsset.mediaType == .video {
                let options: PHVideoRequestOptions = PHVideoRequestOptions()
                options.isNetworkAccessAllowed = true
                options.deliveryMode = .fastFormat
                self.convertVideo(phAsset: selectedAsset) { (data) in
                    if let finalData = data {
                        mediaData.append(finalData)
                        self.checkFileStatus(mediaCount: mediaData.count, assetsCount: assets.count, data: mediaData, isImages: isImages)
                    } else {
                        
                    }
                    
                }
            }
        }
    }
}

func compressVideo(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
   let urlAsset = AVURLAsset(url: inputURL, options: nil)
   guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
       handler(nil)

       return
   }
   exportSession.outputURL = outputURL
   exportSession.outputFileType = AVFileType.mp4
   exportSession.shouldOptimizeForNetworkUse = true
   exportSession.exportAsynchronously { () -> Void in
       handler(exportSession)
   }

}

Priyanka
  • 1
  • 2
  • edit your question and post your code – Leo Dabus Dec 21 '20 at 06:41
  • @LeoDabus Edited quesion – Priyanka Dec 21 '20 at 06:56
  • move your `autoreleasepool {` inside your loop. So change `autoreleasepool {` `for selectedAsset in assets {` to `for selectedAsset in assets {` `autoreleasepool {` – Leo Dabus Dec 21 '20 at 07:00
  • @LeoDabus I tried but still same issue. I want my app to select max 5 videos. I can select 5 video only if they are less than 1min duration. Otherwise my app crash because of memory issue. – Priyanka Dec 21 '20 at 07:20
  • does it happen if you select a single video? – Leo Dabus Dec 21 '20 at 07:22
  • @LeoDabus No, even if I select 5 videos, it doesn't crash if videos are of 30-45 sec each. It crashes if I select 5 videos of 1+ min each. For 1+ min videos, it doesn't crash till 3 videos. – Priyanka Dec 21 '20 at 07:24
  • Note that you should only perform synchronous requests from a background thread. – Leo Dabus Dec 21 '20 at 07:25
  • Btw IMO your issue is here `mediaData.append(finalData)`. Instead of loading all your video data to memory you should create temporary files for them. – Leo Dabus Dec 21 '20 at 07:29
  • @LeoDabus Please suggest, How should I do it. Can you please post a code or edit my code. – Priyanka Dec 21 '20 at 07:37
  • Don't you know how to write your data to disk? – Leo Dabus Dec 21 '20 at 07:38
  • @LeoDabus When I'm compressing the video, its already saving to temp storage after it. – Priyanka Dec 21 '20 at 07:47
  • Why do you need an array of Data? As I have already mentioned you should not load all your videos to memory. – Leo Dabus Dec 21 '20 at 07:50
  • @LeoDabus I need to send them to another view controller where user write some caption to videos and send to the server. – Priyanka Dec 21 '20 at 07:54
  • Just create a directory at your application support directory or use the cache directory, write your data there and pass the URLs – Leo Dabus Dec 21 '20 at 07:58
  • You can also simply load the contents of the directory at the other view controller – Leo Dabus Dec 21 '20 at 08:01
  • @LeoDabus I tried to comment this line `mediaData.append(finalData)` to check if just video selection is working but still same crash of memory issue. – Priyanka Dec 21 '20 at 08:05
  • Ensure your completion handler accesses the array `mediaData` in a synchronised manner. Since it's not guaranteed, that the completion handlers will be called on the same queue, you might have _also_ data race issues. The way you are doing it, i.e. getting the videos as a Data object, and saving them into an array, is not recommended as it requires to allocate huge amount of memory. You better use file streams, and thus a much more elaborated approach. – CouchDeveloper Dec 21 '20 at 12:28

0 Answers0