我正在创建一个简单的音频编辑工具来修剪和删除音频。我实现了修剪功能,并且工作正常。但是我搜索并尝试实现删除功能,这是我的代码:
func deleteExportAsset(_ asset: AVAsset, fileName: String, completeAudioTime: CGFloat) -> URL { print("\(#function)") let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let trimmedSoundFileURL = documentsDirectory.appendingPathComponent(fileName) print("saving to \(trimmedSoundFileURL.absoluteString)") if FileManager.default.fileExists(atPath: trimmedSoundFileURL.absoluteString) { print("sound exists, removing \(trimmedSoundFileURL.absoluteString)") do { if try trimmedSoundFileURL.checkResourceIsReachable() { print("is reachable") } try FileManager.default.removeItem(atPath: trimmedSoundFileURL.absoluteString) } catch { print("could not remove \(trimmedSoundFileURL)") print(error.localizedDescription) } } print("creating export session for \(asset)") if let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) { exporter.outputFileType = AVFileType.m4a exporter.outputURL = trimmedSoundFileURL let timeRange1 = CMTimeRangeFromTimeToTime(CMTime(seconds: 0, preferredTimescale: 100), CMTime(seconds: endTimeOfRange1, preferredTimescale: 100)) let timeRange2 = CMTimeRangeFromTimeToTime(CMTime(seconds: startTimeOfRange2)), preferredTimescale: 100), CMTime(seconds: Double(completeAudioTime), preferredTimescale: 100)) exporter.timeRange = CMTimeRangeGetUnion(timeRange1, timeRange2) // do it exporter.exportAsynchronously(completionHandler: { print("export complete \(exporter.status)") switch exporter.status { case AVAssetExportSessionStatus.failed: if let e = exporter.error { print("export failed \(e)") } case AVAssetExportSessionStatus.cancelled: print("export cancelled \(String(describing: exporter.error))") default: print("export complete") } }) } else { print("cannot create AVAssetExportSession for asset \(asset)") } return trimmedSoundFileURL }
我在这里正在创建2个范围。从0-> time1的Range1和从time2-> endOfAudio的Range2。(我想从时间1->时间2中删除)
然后我在2个范围之间创建并集。但是,音频没有任何反应。它的保存与该功能之前的保存完全相同。
CMTimeRangeGetUnion返回another CMTimeRange,它只是一个(开始)时间和一个持续时间。因此,没有什么可以容纳完成您期望的两个时间范围。扩展而言,AVASsetExportSession没有API需要导出时间范围 列表 。
CMTimeRangeGetUnion
CMTimeRange
但是有一种方法可以实现它。这个想法是创建资产的可编辑副本,删除时间范围,然后导出可编辑副本。AVMutableComposition做这个:
AVMutableComposition
// assuming 'asset', 'endTimeOfRange1' and 'startTimeOfRange2' from the question: // create empty mutable composition let composition: AVMutableComposition = AVMutableComposition() // copy all of original asset into the mutable composition, effectively creating an editable copy try composition.insertTimeRange( CMTimeRangeMake( kCMTimeZero, asset.duration), of: asset, at: kCMTimeZero) // now edit as required, e.g. delete a time range let startTime = CMTime(seconds: endTimeOfRange1, preferredTimescale: 100) let endTime = CMTime(seconds: startTimeOfRange2, preferredTimescale: 100) composition.removeTimeRange( CMTimeRangeFromTimeToTime( startTime, endTime)) // since AVMutableComposition is an AVAsset subclass, it can be exported with AVAssetExportSession (or played with an AVPlayer(Item)) if let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) { // configure session and exportAsynchronously as above. // You don't have to set the timeRange of the exportSession }
请注意,从资产复制到合成仅会修改某些内存结构,这些结构定义了哪些样本在时间轴上到达何处,但实际上并没有移动任何媒体样本。直到导出才完成。结果,编辑(相对)很快,并且您必须至少保留源文件,直到导出完成。