0

I am using AVAssetWriter for compressing video but it taking 20 to 25 seconds to compress a video of size 160 in 12 mb. i want fix bitrate of 1600 kbps and natural frame of video. Is there any way to compress quickly?

 func compressFile(urlToCompress: URL, outputURL: URL, completion:@escaping (URL)->Void) {
            //video file to make the asset

            var audioFinished = false
            var videoFinished = false

            let asset = AVAsset(url: urlToCompress);

            //create asset reader
            do{
                assetReader = try AVAssetReader(asset: asset)
            } catch{
                assetReader = nil
            }

            guard let reader = assetReader else{
                fatalError("Could not initalize asset reader probably failed its try catch")
            }

            let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first!
            let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!

            let videoReaderSettings: [String:Any] =  [(kCVPixelBufferPixelFormatTypeKey as String?)!:kCVPixelFormatType_32ARGB ]

            // MARK: ADJUST BIT RATE OF VIDEO HERE

            let videoSettings:[String:Any] = [
                AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey: self.bitrate] as Any,
                AVVideoCodecKey: AVVideoCodecType.h264,
                AVVideoHeightKey: videoTrack.naturalSize.height,//352,
                AVVideoWidthKey: videoTrack.naturalSize.width //640//
            ]


            let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
            let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)


            if reader.canAdd(assetReaderVideoOutput){
                reader.add(assetReaderVideoOutput)
            }else{
                fatalError("Couldn't add video output reader")
            }

            if reader.canAdd(assetReaderAudioOutput){
                reader.add(assetReaderAudioOutput)
            }else{
                fatalError("Couldn't add audio output reader")
            }

            let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
            let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
            videoInput.transform = videoTrack.preferredTransform
            //we need to add samples to the video input

            let videoInputQueue = DispatchQueue(label: "videoQueue")
            let audioInputQueue = DispatchQueue(label: "audioQueue")

            do{
                assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
            }catch{
                assetWriter = nil
            }
            guard let writer = assetWriter else{
                fatalError("assetWriter was nil")
            }

            writer.shouldOptimizeForNetworkUse = true
            writer.add(videoInput)
            writer.add(audioInput)


            writer.startWriting()
            reader.startReading()
            writer.startSession(atSourceTime: CMTime.zero)


            let closeWriter:()->Void = {
                if (audioFinished && videoFinished){
                    self.assetWriter?.finishWriting(completionHandler: {

                        self.checkFileSize(sizeUrl: (self.assetWriter?.outputURL)!, message: "The file size of the compressed file is: ")

                        completion((self.assetWriter?.outputURL)!)

                    })

                    self.assetReader?.cancelReading()

                }
            }


            audioInput.requestMediaDataWhenReady(on: audioInputQueue) {
                while(audioInput.isReadyForMoreMediaData){
                    let sample = assetReaderAudioOutput.copyNextSampleBuffer()
                    if (sample != nil){
                        audioInput.append(sample!)
                    }else{
                        audioInput.markAsFinished()
                        DispatchQueue.main.async {
                            audioFinished = true
                            closeWriter()
                        }
                        break;
                    }
                }
            }

            videoInput.requestMediaDataWhenReady(on: videoInputQueue) {
                //request data here

                while(videoInput.isReadyForMoreMediaData){
                    let sample = assetReaderVideoOutput.copyNextSampleBuffer()
                    if (sample != nil){
                        videoInput.append(sample!)
                    }else{
                        videoInput.markAsFinished()
                        DispatchQueue.main.async {
                            videoFinished = true
                            closeWriter()
                        }
                        break;
                    }
                }
            }
        }

Edit:- Using above method it converts video on different bitrate not on defined bit rate why?

Any Direction will appreciate.

Thanks in advance

dinesh sharma
  • 577
  • 10
  • 20

1 Answers1

1

This is a non-trivial problem. There is no "simple" answer to how to encode faster. If you are unfamiliar with this, you are better off picking another codec bit-rates and codecs that encode faster. You have to assume the library is doing it's job. So, there a few things you can do:

  1. Make the source file smaller -- or chunk it
  2. Run it on a cloud service which has beefier hardware
  3. You can choose another codec and a lower set of bit-rate + width and height. (https://developer.apple.com/documentation/avfoundation/avvideocodectype)
  4. You can potentially spin up multiple threads and encode faster this way but I doubt it would gain you much
Vaughan Hilts
  • 2,839
  • 1
  • 20
  • 39