2

我有以下函数,它获取现有视频文件的 url 并将其压缩到输出文件中。我正在使用 Avasset 读写器。

var assetReader:AVAssetReader?
var assetWriter:AVAssetWriter?

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 ]

       // ADJUST BIT RATE OF VIDEO HERE

    let width = UIScreen.main.bounds.width - 20
    let scale = width / videoTrack.naturalSize.width
    let height = Int(videoTrack.naturalSize.height * scale)
       let videoSettings:[String:Any] = [
           AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:4000000],
           AVVideoCodecKey: AVVideoCodecH264,
           AVVideoHeightKey: height,
           AVVideoWidthKey: Int(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: 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;
               }
           }

       }


   }

   func checkFileSize(sizeUrl: URL, message:String){
       let data = NSData(contentsOf: sizeUrl)!
       print(message, (Double(data.length) / 1048576.0), " mb")
   }

出于某种原因,我收到以下错误。我的问题是如何设置这个键,更重要的是我为什么要设置它以及设置什么值。什么是编码器延迟?谢谢你

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetWriterInput appendSampleBuffer:] Cannot append sample buffer: First input buffer must have an appropriate kCMSampleBufferAttachmentKey_TrimDurationAtStart since the codec has encoder delay'
4

0 回答 0