Swift - Compressing video files

20,338

Solution 1

This extension focuses on exporting it to a lower quality setting (in this case Medium) and uses an mp4 container, over the mov container favored by iOS. This can result in a loss of quality, but you can experiment with higher output settings and different formats as you work to fine tune your output.

extension PreviewVideoViewController: AVCaptureFileOutputRecordingDelegate {
    func fileOutput(_ output: AVCaptureFileOutput,
                    didFinishRecordingTo outputFileURL: URL,
                    from connections: [AVCaptureConnection],
                    error: Error?) {
        guard let data = try? Data(contentsOf: outputFileURL) else {
            return
        }

        print("File size before compression: \(Double(data.count / 1048576)) mb")

        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + UUID().uuidString + ".mp4")
        compressVideo(inputURL: outputFileURL as URL,
                      outputURL: compressedURL) { exportSession in
            guard let session = exportSession else {
                return
            }

            switch session.status {
            case .unknown:
                break
            case .waiting:
                break
            case .exporting:
                break
            case .completed:
                guard let compressedData = try? Data(contentsOf: compressedURL) else {
                    return
                }

                print("File size after compression: \(Double(compressedData.count / 1048576)) mb")
            case .failed:
                break
            case .cancelled:
                break
            }
        }
    }


    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 = .mp4
        exportSession.exportAsynchronously {
            handler(exportSession)
        }
    }
}

Solution 2

   func convertVideo(phAsset : PHAsset){

    PHImageManager.default().requestAVAsset(forVideo: phAsset, options: PHVideoRequestOptions(), resultHandler: { (asset, audioMix, info) -> Void in
        if let asset = asset as? AVURLAsset {
            do {
                let videoData = try  Data.init(contentsOf: asset.url)
                print(asset.url)
                self.orginalVideo = asset.url
                print("File size before compression: \(Double(videoData.count / 1048576)) mb")
            let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".MP4")
                print(compressedURL)
                self.compressVideo(inputURL: asset.url , outputURL: compressedURL) { (exportSession) in
                    guard let session = exportSession else {
                        return
                    }
                    switch session.status {
                    case .unknown:
                        print("unknown")
                        break
                    case .waiting:
                        print("waiting")
                        break
                    case .exporting:
                        print("exporting")
                        break
                    case .completed:
                        do {
                        let compressedData = try  Data.init(contentsOf: compressedURL)
                            self.compressVideo = compressedURL
                            print(compressedData)
                             print("File size AFTER compression: \(Double(compressedData.count / 1048576)) mb")
                        }
                        catch{
                           print(error)
                        }


                    case .failed:
                        print("failed")
                        break
                    case .cancelled:
                        print("cancelled")
                        break
                    }
                }
            } catch {
                print(error)
                //return
            }
        }
    })


}

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)
    }
}
Share:
20,338
Roduck Nickes
Author by

Roduck Nickes

Updated on July 09, 2022

Comments

  • Roduck Nickes
    Roduck Nickes almost 2 years

    So, at the moment I am using this to compress video:

    func compressVideo(inputURL: NSURL, outputURL: NSURL, handler:(session: AVAssetExportSession)-> Void)
        {
            let urlAsset = AVURLAsset(URL: inputURL, options: nil)
    
            let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality)
    
            exportSession!.outputURL = outputURL
    
            exportSession!.outputFileType = AVFileTypeQuickTimeMovie
    
            exportSession!.shouldOptimizeForNetworkUse = true
    
            exportSession!.exportAsynchronouslyWithCompletionHandler { () -> Void in
    
                handler(session: exportSession!)
            }
    
        }
    

    When I recorded a video in 2 seconds, the size was 4,3 MB and when I recorded a video in 6 seconds the file size was 9,3 MB.

    Any tips to reduce the size?

  • Roduck Nickes
    Roduck Nickes over 7 years
    I guess since my class name is class PreviewVideoViewController: UIViewController { I should replace your MyViewController with PreviewVideoViewController? But I do get 3 error messages: s22.postimg.org/p8ps48lm9/…
  • CodeBender
    CodeBender over 7 years
    @RoduckNickes Is your app in Swift 2.2?
  • Roduck Nickes
    Roduck Nickes over 7 years
    It says Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1) Target: x86_64-apple-macosx10.9 when I run xcrun swift -version in Terminal.
  • CodeBender
    CodeBender over 7 years
    @RoduckNickes Updated with a 2.2 answer, since your errors are indicating that you are not writing for 3.0. Let me know if that does not work for you.
  • vaibhav
    vaibhav almost 7 years
    no sound in video i found when i compress video using this code..?
  • Martin
    Martin over 6 years
    @vaibhav: is there sound in your video before the compression? Did you record it properly with an audio input source set?
  • vaibhav
    vaibhav over 6 years
    its done by adding single line in code session.sessionPreset = AVCaptureSessionPresetMedium and the sound turns off when the video recorded time is greater then 10 sec, its corrected by adding self.movieOutput.movieFragmentInterval = kCMTimeInvalid line of code.
  • Sachin Kishore
    Sachin Kishore over 5 years
    Error: Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_0102.MP4” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/var/mobile/Media/DCIM/100APPLE/IMG_010‌​2.MP4, NSUnderlyingError=0x1030b70f0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}} file:///private/var/mobile/Containers/Data/Application/B38F4‌​E96-43B1-449C-A3F1-A‌​99960E52BC3/tmp/FEBC‌​7046-D7B8-4A86-B889-‌​92D2CDFA8879.mp4 File size after compression: 0.0 mb
  • Mahesh Joya
    Mahesh Joya over 3 years
    Check if anyone have issue with tranfom or any other issue in SDK: github.com/YaoSu/SDAVAssetExportSession
  • ScripterKiddo
    ScripterKiddo almost 2 years
    I used this code but after the video length passed a certain unknown amount sound from the video is removed