【问题标题】:Issue with AVAssetWriter Input: MPEG4AVAssetWriter 输入问题:MPEG4
【发布时间】:2021-06-18 01:13:33
【问题描述】:

我正在使用 AVAssetWriter 压缩视频。如果我将视频压缩文件设置为 Quicktime 电影,它可以正常工作,但是我想将其导出为 MPEG4,但它在运行时给了我这个错误:

为了对文件类型 public.mpeg-4 执行直通,请在 AVAssetWriterInput 初始化程序中提供格式提示'

这是我声明文件类型的具体代码:

 let videoInputQueue = DispatchQueue(label: "videoQueue")
    let audioInputQueue = DispatchQueue(label: "audioQueue")
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
    let date = Date()
    let documentsPath = NSTemporaryDirectory()
    let outputPath = "\(documentsPath)/\(formatter.string(from: date)).mp4"
    let newOutputUrl = URL(fileURLWithPath: outputPath)

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

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

这是我的压缩的完整代码:

func compressFile(urlToCompress: 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: AVMediaTypeVideo).first!
    let audioTrack = asset.tracks(withMediaType: AVMediaTypeAudio).first!

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

    // ADJUST BIT RATE OF VIDEO HERE

    let videoSettings:[String:Any] = [
        AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:self.bitrate],
        AVVideoCodecKey: AVVideoCodecH264,
        AVVideoHeightKey: videoTrack.naturalSize.height,
        AVVideoWidthKey: videoTrack.naturalSize.width
    ]


    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: AVMediaTypeAudio, outputSettings: nil)
    let videoInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, 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")
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
    let date = Date()
    let documentsPath = NSTemporaryDirectory()
    let outputPath = "\(documentsPath)/\(formatter.string(from: date)).mp4"
    let newOutputUrl = URL(fileURLWithPath: outputPath)

    do{
        assetWriter = try AVAssetWriter(outputURL: newOutputUrl, fileType: AVFileTypeMPEG4)
    }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: kCMTimeZero)


    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)!)
                print("Completed 1")

            })

            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()
                    print("Completed 2")
                }
                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
                    print("Completed 3")
                    closeWriter()
                }
                break;
            }
        }

    }


}

【问题讨论】:

    标签: ios swift xcode avassetwriter


    【解决方案1】:

    通过使用nil outputSettings 创建您的音频AVAssetWriterInput,您表明您想要传递您的音频数据。 assetWriterInputWithMediaType:outputSettings: 头文件注释说:

    AVAssetWriter 仅支持通过一组受限的媒体类型和子类型。为了将媒体数据传递给 AVFileTypeQuickTimeMovie 以外的文件,必须使用 +assetWriterInputWithMediaType:outputSettings:sourceFormatHint: 来提供非 NULL 格式提示,而不是此方法。

    需要格式说明,幸运的是,您可以从遇到的示例缓冲区中获得:

    let formatDesc = CMSampleBufferGetFormatDescription(anAudioSampleBuffer)!   
    let audioInput = AVAssetWriterInput(mediaType: AVMediaTypeAudio, outputSettings: nil, sourceFormatHint: formatDesc)
    

    既然这么容易做到,为什么AVAssetWriter 不为我们做呢?我猜是因为它会笨拙地推动AVAssetWriter 的通常初始化,直到您附加一些CMSampleBuffers 之后的某个时间点,或者(也许?)因为并非所有CMSampleBuffers 都有格式描述。

    【讨论】:

    • 嗨,我遇到了这个问题 let formatDesc = CMSampleBufferGetFormatDescription(let formatDesc = CMSampleBufferGetFormatDescription(anAudioSampleBuffer)! )! 如何获得这个 anAudioSampleBuffer进入我的代码。
    • 您可以从AVCaptureSession 或ReplayKit 广播扩展中获取CMSampleBuffers,您可以从带有AVAssetReader 的文件中读取它们,并且可以使用CoreMedia 框架创建它们。跨度>
    • 我对这方面的领域完全陌生,任何进一步的 sugeustions。 ?
    • 请使用您拥有的代码和问题描述开始一个新问题,或者如果您没有代码,请询问如何实现您想要的问题。
    • stackoverflow.com/q/61434041/9250384你好,我创建了一个新问题请看一下,看看你是否能理解并解决我的问题。
    【解决方案2】:

    我在尝试将.mp4 传递给AVAssetWriter 时遇到了这个问题。

    具体来说:

    AVAssetReaderTrackOutput(track:,outputSettings:) outputSettings 参数为nil

    AVAssetWriterInput(mediaType:,outputSettings:) outputSettings 参数为nil

    使用此code from samkirkiles 或更多detailed look

    问题在第 38 行和第 53 行:

    // outputSettings: nil is the problem
    let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
    let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
    

    使用.mov 该行工作正常,但在outputSettings 参数中使用.mp4 nil 值会导致崩溃:outputSettings: nil

    要修复它,请将带有一些 audioSettings 的字典添加到 outputSettings 参数中:

    这是第 38 行:

    let audioOutputSettingsDict: [String : Any] = [
                AVFormatIDKey: kAudioFormatLinearPCM,
                AVSampleRateKey: 44100
    ]
    
    let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: audioOutputSettingsDict)
    

    这是第 53 行:

    let audioInputSettingsDict: [String:Any] = [AVFormatIDKey : kAudioFormatMPEG4AAC,
                                       AVNumberOfChannelsKey : 2,
                                       AVSampleRateKey : 44100.0,
                                       AVEncoderBitRateKey: 128000 // he uses 250000 in his code via self.bitRate
    ]
    
    let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: audioInputSettingsDict)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2020-06-27
      • 1970-01-01
      • 2012-06-15
      • 2011-11-11
      • 2015-04-22
      相关资源
      最近更新 更多