我想在iPhone相册中对视频执行操作,由于我将在我的应用程序内部使用本地的ffmpeg,因此需要绝对URI。
是否可以直接对视频进行操作?还是需要将视频复制到临时目录中,进行操作,然后再写回到相册?
是否可以直接对视频进行操作?还是需要将视频复制到临时目录中,进行操作,然后再写回到相册?
我阅读了一些文档和教程,基于这些研究回答以下问题。
能否直接操作视频文件?
是的(将其复制到临时目录中),不可以(不能在视频实际存储位置上进行操作)
看一下下面的图片和官方文档的引用:
使用 PhotoKit,您可以获取和缓存资产以进行显示和播放,编辑图像和视频内容,或管理包含大量资产的集合,例如相册、时刻和共享相册。
我们没有直接访问图像/视频实际存储位置的权限,而是使用PHAsset获得原始数据或表示形式。Asset对象是不可变的,因此我们无法直接对其执行操作。我们需要PHAssetChangeRequest来创建、删除、更改元数据或编辑照片资产的内容。
我需要将视频复制到临时目录中,进行操作,然后再写回相册吗?
是的,这就是正确的方式。
如果您已经获取了资产,并且有PHFetchResult对象,请尝试:
var video = PHAsset() // the video to be edited
…
if video.canPerform(.content) { // check if the selected PHAsset can be edited
video.requestContentEditingInput(with: nil, completionHandler: { editingInput, _ in
let videoAsset = editingInput?.audiovisualAsset // get tracks and metadata of the video and start editing
let videoURL = (videoAsset as? AVURLAsset)?.url // This might be nil so better use videoAsset
/*
Start editing your video here
*/
guard let input = editingInput else { return }
let output = PHContentEditingOutput(contentEditingInput: input)
let outputURL = output.renderedContentURL // URL at which you write/export the edited video, it must be a .mov file
let editedVideo = NSData() // suppose your video fileName is editedVideo.mov, I used NSData since I don't know what final edited object will be.
editedVideo.write(to: outputURL, atomically: false)
PHPhotoLibrary.shared().performChanges({
let changeRequest = PHAssetChangeRequest(for: video)
changeRequest.contentEditingOutput = output
})
})
}
如果您正在使用默认图像选择器,则可以使用以下代码获取临时视频 URL:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let videoURL = info[UIImagePickerController.InfoKey.mediaURL] as! NSURL
print(videoURL) // file is already in tmp folder
let video = info[UIImagePickerController.InfoKey.phAsset] as! PHAsset
// implement the above code using this PHAsset
// your will still need to request photo library changes, and save the edited video and/or delete the older one
}
我在我的项目中实现了类似这样的功能,希望能对你有所帮助。
我会展示所有集合视图中的项目并在选择时执行动作,你也可以获取所选视频的URL。
func getVideoFromCameraRoll() {
let options = PHFetchOptions()
options.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ]
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.video.rawValue)
videos = PHAsset.fetchAssets(with: options)
videoLibraryCV.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return videos.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
let asset = videos!.object(at: indexPath.row)
let width: CGFloat = 150
let height: CGFloat = 150
let size = CGSize(width:width, height:height)
cell.layer.borderWidth = 0.5
cell.layer.borderColor = UIColor.lightGray.cgColor
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: PHImageContentMode.aspectFit, options: nil)
{ (image, userInfo) -> Void in
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = image
let labelView = cell.viewWithTag(2) as! UILabel
labelView.text = String(format: "%02d:%02d",Int((asset.duration / 60)),Int(asset.duration) % 60)
}
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let asset = photos!.object(at: indexPath.row)
guard(asset.mediaType == PHAssetMediaType.Video)
else {
print("Not a valid video media type")
return
}
PHCachingImageManager().requestAVAssetForVideo(asset, options: nil, resultHandler: {
(asset: AVAsset ? , audioMix : AVAudioMix ? , info : [NSObject: AnyObject] ? ) in
let asset = asset as!AVURLAsset
print(asset.URL) // Here is video URL
})
}
希望它能对你有用...:)