Reputation: 369
I m validating one thing: The composition's duration is the same as it has been exported.
This is ok when no scaleTimeRange
.. I don't know why the exported file duration is not the same as AVMutableComposition
after using scaleTimeRange
API
Here is demo code
class ViewController2 : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let asset: AVURLAsset = {
let url = Bundle.main.url(forResource: "test", withExtension: "caf", subdirectory: nil)
return AVURLAsset(url: url!, options: [AVURLAssetPreferPreciseDurationAndTimingKey : true])
}()
let composition = AVMutableComposition()
let mix = AVAudioMix()
try! composition.insertTimeRange(CMTimeRange(start: .zero, end: asset.duration), of: asset, at: .zero)
// scale time range of whole resource, make it 2x speed
// After using this, the assert will fail.
// Comment this line the assert can be true.
composition.scaleTimeRange(CMTimeRange(start: .zero, end: composition.duration), toDuration: CMTime(value: composition.duration.value / 2, timescale: composition.duration.timescale))
Task {
let outputURL = URL(fileURLWithPath: NSTemporaryDirectory() + UUID().uuidString + ".caf")
await TestAudioDemo.export(asset: composition, mix: mix, outputURL: outputURL)
let exportAsset = AVURLAsset(url: outputURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey : true])
print("export ok \(composition.duration) \(exportAsset.duration)")
assert(composition.duration == exportAsset.duration)
}
}
}
func export(asset: AVAsset,
mix: AVAudioMix,
outputURL: URL) async {
return await withCheckedContinuation { continuation in
let reader = try! AVAssetReader(asset: asset)
let readerOutput = AVAssetReaderAudioMixOutput(audioTracks: asset.tracks(withMediaType: .audio), audioSettings: nil)
readerOutput.audioMix = mix
reader.add(readerOutput)
let writer = try! AVAssetWriter(outputURL: outputURL, fileType: .caf)
let cafOutputSettings:[String:Any] = [
AVFormatIDKey : kAudioFormatLinearPCM,
AVSampleRateKey : 44100,
AVNumberOfChannelsKey : 2,
AVLinearPCMBitDepthKey : 32,
AVLinearPCMIsNonInterleaved : false,
AVLinearPCMIsFloatKey : true,
AVLinearPCMIsBigEndianKey : true,
]
let writerInput = AVAssetWriterInput(mediaType: .audio,
outputSettings: cafOutputSettings)
writer.add(writerInput)
reader.startReading()
writer.startWriting()
writer.startSession(atSourceTime: .zero)
let workQueue = DispatchQueue(label: "Exporter.simpleExportQueue")
writerInput.requestMediaDataWhenReady(on: workQueue) {
while writerInput.isReadyForMoreMediaData {
if let buffer = readerOutput.copyNextSampleBuffer() {
writerInput.append(buffer)
} else {
writerInput.markAsFinished()
reader.cancelReading()
writer.finishWriting {
continuation.resume()
}
break
}
}
}
}
}
Upvotes: 0
Views: 41