如何将 AVMutableComposition 传递给 AVAssetWriter

How to pass AVMutableComposition to AVAssetWriter

现在我使用 AVExportSession 从 AVMixComposition 中得到一个 url。 HighestQuality 看起来不错,但文件太大,15 秒的视频是 27 MB。 MediumQuality 看起来很糟糕,但文件大小只有 1 MB。我知道我必须使用 AVAssetWriter 并调整比特率来找到中间立场。

问题是我想不出一种方法来从 AVMixComposition 获取 url 而不使用 使用 AVExportSession 传递给 AVAssetWriter。

我要做的是使用 exportSession 保存视频,获取 url,将其传递给 assetWriter,设置比特率,然后从那里进行压缩。生成的 .mp4(必须为 .mp4)assetWriter 视频不会压缩原始的 exportSession videoURL。它实际上更大,这违背了目的。

let mixComposition = AVMutableComposition()
// ...

guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else { return }

exporter.outputURL = outputFileURL
exporter.outputFileType = AVFileType.mp4
exporter.shouldOptimizeForNetworkUse = true

exporter.exportAsynchronously {
    // ...
    let data = try! Data(contentsOf: outputFileURL)
    print("compression size: \(Double(data.count / 1048576)) mb") // 27 mb

    DispatchQueue.main.async { ...
        guard let videoURL = exporter.outputURL else { return }

        self.passUrlToAssetWriter(urlToCompress: videoURL)
}

func passUrlToAssetWriter(urlToCompress: URL) {

    let asset = AVAsset(url: urlToCompress)
    guard let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first else { return }
    guard let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first else return }

    // dropping the bit rate made no difference
    let videoSettings:[String:Any] = [AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey: 250000], AVVideoCodecKey: AVVideoCodecType.h264, AVVideoHeightKey: videoTrack.naturalSize.height, AVVideoWidthKey: videoTrack.naturalSize.width]
    let audioSettings: [String:Any] = [AVFormatIDKey : kAudioFormatMPEG4AAC, AVNumberOfChannelsKey : 2, AVSampleRateKey : 44100.0, AVEncoderBitRateKey: 128000]

    assetWriter = try! AVAssetWriter(outputURL: myOutputURL, fileType: AVFileType.mp4)
    // everything else to configure assetWriter ...

    assetWriter?.finishWriting(completionHandler: {

        let data = try! Data(contentsOf: self.assetWriter!.outputURL)!)
        print("compression size: \(Double(data.count / 1048576)) mb") // 27.5 mb, it's actually bigger than the exporter file size         
    })
}

不需要使用url,你可以将mixComposition传递给AVPlayerItem > AVPlayer > player.currentItem.asset:

let mixComposition = AVMutableComposition()
// ...
passMixToAssetWriter(mixComposition)

func passMixToAssetWriter(_ mixComposition: AVMutableComposition) {

    let item = AVPlayerItem(asset: composition)
    let player = AVPlayer()
    player.replaceCurrentItem(with: item)
    guard let currentItem = player.currentItem else { return }

    let asset = currentItem.asset

    guard let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first else { return }
    guard let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first else return }

    // raise the bit rate to 11000000
    let videoSettings:[String:Any] = [AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey: 1100000], AVVideoCodecKey: AVVideoCodecType.h264, AVVideoHeightKey: videoTrack.naturalSize.height, AVVideoWidthKey: videoTrack.naturalSize.width]
    let audioSettings: [String:Any] = [AVFormatIDKey : kAudioFormatMPEG4AAC, AVNumberOfChannelsKey : 2, AVSampleRateKey : 44100.0, AVEncoderBitRateKey: 128000]

    assetWriter = try! AVAssetWriter(outputURL: myOutputURL, fileType: AVFileType.mp4)
    // everything else to configure assetWriter ...

    assetWriter?.finishWriting(completionHandler: {

        let data = try! Data(contentsOf: self.assetWriter!.outputURL)!)
        print("compression size: \(Double(data.count / 1048576)) mb") // 27.5 mb, it's actually bigger than the exporter file size         
    })
}