问题描述
- 场景:视频上传
在使用 PHImageManager 中的如下方法获取视频路径的时候,如果选择的是慢动作视频就会引起如下崩溃:
-[AVComposition URL]: unrecognized selector sent to instance 0x2821c8f40
- (PHImageRequestID)requestAVAssetForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVAsset *__nullable asset, AVAudioMix *__nullable audioMix, NSDictionary *__nullable info))resultHandler
这是因为 asset 对象是 AVComposition 的对象,AVComposition 继承自 AVAsset ,在该类中没有 URL 属性,就会造成 unrecognized selector sent to instance 0x2821c8f40 的错误
一般的视频返回的都是 AVURLAsset 对象,在使用 asset 的时候需要强制转换下 ((AVURLAsset *)asset).URL 就可以获取 URL。
如果选择的是手机拍摄的慢动作视频,就会造成崩溃,也就是 asset 对象变成了 AVComposition 的实例,而不是 AVURLAsset 的实例。
有关 AVComposition 的介绍 https://www.jianshu.com/p/6ecae3de4344
解决办法
将 AVComposition 对象导出成AVURLAsset视频保存在手机里就可以获取 URL
- ObjC
+ (void)convertAvcompositionToAvasset:(AVComposition *)composition completion:(void (^)(AVAsset *asset))completion {
// 导出视频
AVAssetExportSession *exporter = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetHighestQuality];
// 生成一个文件路径
NSInteger randNumber = arc4random();
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingString:[NSString stringWithFormat:@"%ldvideo.mov", randNumber]];
NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
// 导出
if (exporter) {
exporter.outputURL = exportURL; // 设置路径
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (AVAssetExportSessionStatusCompleted == exporter.status) { // 导出完成
NSURL *URL = exporter.outputURL;
AVAsset *avAsset = [AVAsset assetWithURL:URL];
if (completion) {
completion(avAsset);
}
} else {
if (completion) {
completion(nil);
}
}
});
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(nil);
}
});
}
}
- Swift
func ConvertAvcompositionToAvasset(avComp: AVComposition, completion:@escaping (_ avasset: AVAsset) -> Void){
let exporter = AVAssetExportSession(asset: avComp, presetName: AVAssetExportPresetHighestQuality)
let randNum:Int = Int(arc4random())
//Generating Export Path
let exportPath: NSString = NSTemporaryDirectory().appendingFormat("\(randNum)"+"video.mov") as NSString
let exportUrl: NSURL = NSURL.fileURL(withPath: exportPath as String) as NSURL
//SettingUp Export Path as URL
exporter?.outputURL = exportUrl as URL
exporter?.outputFileType = AVFileTypeQuickTimeMovie
exporter?.shouldOptimizeForNetworkUse = true
exporter?.exportAsynchronously(completionHandler: {() -> Void in
DispatchQueue.main.async(execute: {() -> Void in
if exporter?.status == .completed {
let URL: URL? = exporter?.outputURL
let Avasset:AVAsset = AVAsset(url: URL!)
completion(Avasset)
}
else if exporter?.status == .failed{
print("Failed")
}
})
}) }