0

I am attempting to set up custom video compression in swift based off of this SO post that used Obj-C instead (How can I reduce the file size of a video created with UIImagePickerController?). However, I am having a few issues converting the syntax, specifically the error above which is highlighted over the dictionary. The compression function is below:

func convertVideoToLowQuailty(withInputURL inputURL: URL, outputURL: URL) {
    //setup video writer
    var videoAsset = AVURLAsset(url: inputURL, options: nil)
    var videoTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
    var videoSize = videoTrack.naturalSize
    var videoWriterCompressionSettings = [
        AVVideoAverageBitRateKey : Int(1250000)
    ]

    var videoWriterSettings : NSDictionary = [
        DictionaryLiteral : (Key: AVVideoCodecKey, Object: AVVideoCodecH264),
        AVVideoCompressionPropertiesKey : videoWriterCompressionSettings,
        AVVideoWidthKey : Int(videoSize.width),
        AVVideoHeightKey : Int(videoSize.height)
    ]

    var videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoWriterSettings as! [String : Any?])
    videoWriterInput.expectsMediaDataInRealTime = true
    videoWriterInput.transform = videoTrack.preferredTransform
    var videoWriter = try! AVAssetWriter(outputURL: outputURL, fileType: AVFileTypeMPEG4)
    videoWriter.add(videoWriterInput)
    //setup video reader
    var videoReaderSettings = [ (kCVPixelBufferPixelFormatTypeKey as String) : Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) ]
    var videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
    var videoReader = try! AVAssetReader(asset: videoAsset)
    videoReader.add(videoReaderOutput)
    //setup audio writer
    var audioWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: nil)
    audioWriterInput.expectsMediaDataInRealTime = false
    videoWriter.add(audioWriterInput)
    //setup audio reader
    var audioTrack = videoAsset.tracks(withMediaType: AVMediaTypeAudio)[0]
    var audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
    var audioReader = try! AVAssetReader(asset: videoAsset)
    audioReader.add(audioReaderOutput)
    videoWriter.startWriting()
    //start writing from video reader
    videoReader.startReading()
    videoWriter.startSession(atSourceTime: kCMTimeZero)
    var processingQueue = DispatchQueue(label: "processingQueue1")
    videoWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in
        while videoWriterInput.isReadyForMoreMediaData {
            var sampleBuffer: CMSampleBuffer
            if videoReader.status == .reading && (sampleBuffer == videoReaderOutput.copyNextSampleBuffer()!) {
                videoWriterInput.append(sampleBuffer)

            }
            else {
                videoWriterInput.markAsFinished()
                if videoReader.status == .completed {
                    //start writing from audio reader
                    audioReader.startReading()
                    videoWriter.startSession(atSourceTime: kCMTimeZero)
                    var processingQueue = DispatchQueue(label: "processingQueue2")
                    audioWriterInput.requestMediaDataWhenReady(on: processingQueue, using: {() -> Void in
                        while audioWriterInput.isReadyForMoreMediaData {
                            var sampleBuffer: CMSampleBuffer
                            if audioReader.status == .reading && (sampleBuffer == (audioReaderOutput.copyNextSampleBuffer()!)) {
                                audioWriterInput.append(sampleBuffer)
                            }
                            else {
                                audioWriterInput.markAsFinished()
                                if audioReader.status == .completed {
                                    videoWriter.finishWriting(completionHandler: {() -> Void in
                                        self.sendMovieFile(at: outputURL)
                                    })
                                }
                            }
                        }
                    })
                }
            }

        }
    })
}
Community
  • 1
  • 1
j. doe
  • 27
  • 4
  • change your videoWriterSettings declaration to `var videoWriterSettings: [String: Any]` – Leo Dabus Sep 22 '16 at 21:35
  • @LeoDabus same error still present – j. doe Sep 22 '16 at 21:45
  • `var videoWriterSettings: [String: Any] = [AVVideoCodecKey: AVVideoCodecH264, AVVideoCompressionPropertiesKey : [AVVideoAverageBitRateKey: NSNumber(value: 1250000)], AVVideoWidthKey: videoSize.width as NSNumber, AVVideoHeightKey: videoSize.height as NSNumber]` – Leo Dabus Sep 22 '16 at 21:55

1 Answers1

0

I do not understand why you need this line:

    DictionaryLiteral : (Key: AVVideoCodecKey, Object: AVVideoCodecH264),

Seeing the linked thread, you can write something like this:

    var videoWriterCompressionSettings: [String: AnyObject] = [
        AVVideoAverageBitRateKey : 1250000 as NSNumber
    ]

    var videoWriterSettings : [String: AnyObject] = [
        AVVideoCodecKey: AVVideoCodecH264 as NSString,
        AVVideoCompressionPropertiesKey : videoWriterCompressionSettings as NSDictionary,
        AVVideoWidthKey : videoSize.width as NSNumber,
        AVVideoHeightKey : videoSize.height as NSNumber
    ]

    var videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoWriterSettings)

(Someone prefers [String: Any] than [String: AnyObject], saying it's more Swifty in Swift 3. With using Any, you can remove some castings, but may mistakingly contain some bad things which would be revealed only in runtime.)

And another very bad part of your code is as! [String : Any?]. You need to pass [String: Any]? to AVAssetWriterInput.init(mediaType:outputSettings:), not [String: Any?].

(There may be some other bad parts, which I have not checked...)

OOPer
  • 47,149
  • 6
  • 107
  • 142
  • Okay, thank you very much, I will check this and hopefully it all fixes, I used an Obj-C converter to do this as I do not understand Obj-C – j. doe Sep 22 '16 at 21:47
  • @j.doe, I see. Sometimes such tools (including Swift migrator) generate weird outputs. Hope you can fix all your issues soon. – OOPer Sep 22 '16 at 21:53