j. doe j. doe - 10 months ago 58
iOS Question

Value of type DictionaryLiteral<_,_> does not conform to 'Any' in coersion

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)
//setup video reader
var videoReaderSettings = [ (kCVPixelBufferPixelFormatTypeKey as String) : Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) ]
var videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
var videoReader = try! AVAssetReader(asset: videoAsset)
//setup audio writer
var audioWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: nil)
audioWriterInput.expectsMediaDataInRealTime = false
//setup audio reader
var audioTrack = videoAsset.tracks(withMediaType: AVMediaTypeAudio)[0]
var audioReaderOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
var audioReader = try! AVAssetReader(asset: videoAsset)
//start writing from video reader
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()!) {

else {
if videoReader.status == .completed {
//start writing from audio reader
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()!)) {
else {
if audioReader.status == .completed {
videoWriter.finishWriting(completionHandler: {() -> Void in
self.sendMovieFile(at: outputURL)


Answer Source

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...)