音频文件播放正常,但无法添加到 AVMutableVideoComposition 中
我正在尝试将使用 MPMediaPickerController 选择的音频文件添加到使用 AVMutableVideoComposition 的视频中,但它出现错误并且不起作用。
像这样选择音频:
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
if let musicUrl: NSURL = mediaItemCollection.items.first?.assetURL as NSURL? {
musicURL = musicUrl as URL
print("Music URL in did select \(musicUrl) !!!")
}
}
并像这样混合音频和视频:
func testMerge(url: URL) {
let firstVideo = AVAsset(url: url)
var audioAsset = AVAsset(url: musicURL!)
print("Music URL\(musicURL)")
let firstVideoTrack = firstVideo.tracks(withMediaType: AVMediaType.video).first
let mixComposition = AVMutableComposition()
let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
let firstTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
try firstTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: firstVideoTrack!, at: .zero)
if musicURL.isFileURL {
try audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: audioAsset.tracks(withMediaType: AVMediaType.audio).first, at: .zero)
}
} catch {
debugPrint("Can't get track from the Video URL!")
}
let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: firstVideo.duration)
let firstLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
let scale = CGAffineTransform(scaleX: 1, y: 1)
firstLayerInstruction.setTransform(scale, at: .zero)
mainInstruction.layerInstructions = [firstLayerInstruction]
let mainCompositionInstruction = AVMutableVideoComposition()
mainCompositionInstruction.instructions = [mainInstruction]
mainCompositionInstruction.frameDuration = CMTimeMake(value: 1, timescale: 30)
mainCompositionInstruction.renderSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
guard let documentDirectory = FileManager.default.urls (
for: .documentDirectory,
in: .userDomainMask).first else { print("ERROR"); return }
let url = documentDirectory.appendingPathComponent("mergeVideo-\(arc4random() % 10000).mp4")
guard let assetExport = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else {print("ERROR"); return }
assetExport.videoComposition = mainCompositionInstruction
assetExport.outputFileType = .mp4
assetExport.shouldOptimizeForNetworkUse = true
assetExport.outputURL = url
assetExport.exportAsynchronously {
switch assetExport.status {
case AVAssetExportSessionStatus.failed:
print("failed \(String(describing: assetExport.error))")
case AVAssetExportSessionStatus.cancelled:
print("cancelled \(String(describing: assetExport.error))")
case AVAssetExportSessionStatus.completed:
print("Completed")
print(url)
default:
print("unknown")
}
DispatchQueue.main.async {
self.exportDidFinish(assetExport)
}
}
}
如果我用 AVAudioPlayer 播放该音频,那么它正在播放,但如果我在视频中添加它会给出错误 {Error Domain=NSOSStatusErrorDomain Code=-12109 "(null)" }, NSLocalizedFailureReason=此媒体不支持该操作。, NSLocalizedDescription=操作已停止}
任何帮助或提示将非常感激,谢谢。
i'm trying to add audio file selected with MPMediaPickerController to video with AVMutableVideoComposition, but it gives error and doesn't work.
picking audio like this :
func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
if let musicUrl: NSURL = mediaItemCollection.items.first?.assetURL as NSURL? {
musicURL = musicUrl as URL
print("Music URL in did select \(musicUrl) !!!")
}
}
and mixing audio and video like this :
func testMerge(url: URL) {
let firstVideo = AVAsset(url: url)
var audioAsset = AVAsset(url: musicURL!)
print("Music URL\(musicURL)")
let firstVideoTrack = firstVideo.tracks(withMediaType: AVMediaType.video).first
let mixComposition = AVMutableComposition()
let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
let firstTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
try firstTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: firstVideoTrack!, at: .zero)
if musicURL.isFileURL {
try audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: audioAsset.tracks(withMediaType: AVMediaType.audio).first, at: .zero)
}
} catch {
debugPrint("Can't get track from the Video URL!")
}
let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: firstVideo.duration)
let firstLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
let scale = CGAffineTransform(scaleX: 1, y: 1)
firstLayerInstruction.setTransform(scale, at: .zero)
mainInstruction.layerInstructions = [firstLayerInstruction]
let mainCompositionInstruction = AVMutableVideoComposition()
mainCompositionInstruction.instructions = [mainInstruction]
mainCompositionInstruction.frameDuration = CMTimeMake(value: 1, timescale: 30)
mainCompositionInstruction.renderSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
guard let documentDirectory = FileManager.default.urls (
for: .documentDirectory,
in: .userDomainMask).first else { print("ERROR"); return }
let url = documentDirectory.appendingPathComponent("mergeVideo-\(arc4random() % 10000).mp4")
guard let assetExport = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else {print("ERROR"); return }
assetExport.videoComposition = mainCompositionInstruction
assetExport.outputFileType = .mp4
assetExport.shouldOptimizeForNetworkUse = true
assetExport.outputURL = url
assetExport.exportAsynchronously {
switch assetExport.status {
case AVAssetExportSessionStatus.failed:
print("failed \(String(describing: assetExport.error))")
case AVAssetExportSessionStatus.cancelled:
print("cancelled \(String(describing: assetExport.error))")
case AVAssetExportSessionStatus.completed:
print("Completed")
print(url)
default:
print("unknown")
}
DispatchQueue.main.async {
self.exportDidFinish(assetExport)
}
}
}
if i play that audio with AVAudioPlayer then it is playing but if i add in video it gives error {Error Domain=NSOSStatusErrorDomain Code=-12109 "(null)"}, NSLocalizedFailureReason=The operation is not supported for this media., NSLocalizedDescription=Operation Stopped}
any help or tip would be really appreciated, thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果我将音频文件添加到项目目录,然后使用捆绑包 url 访问它,那么它工作正常,只是不适用于通过 MPMediaPicker 选取的音频。
这就是我能够使其工作的方式:
将其作为 AVPlayerItem 存储在这样的变量中
,然后在 mergeVideo 函数中访问它的轨道,如下所示
If i add audio file to project directory and then access it with bundle url then it works fine it just doesn't work with audio picked through MPMediaPicker.
This is how i was able to make it work :
stored it as AVPlayerItem in variable like this
then in mergeVideo function accessed it's track like this