播放通过 CloudKit 作为 CKAsset 下载的视频 - iOS
Posted
技术标签:
【中文标题】播放通过 CloudKit 作为 CKAsset 下载的视频 - iOS【英文标题】:Play video downloaded through CloudKit as CKAsset - iOS 【发布时间】:2015-10-01 02:03:56 【问题描述】:我正在制作一个录制视频的应用程序,使用带有 CKAsset 的 CloudKit 将其上传到 iCloud,然后下载文件并在 AVPlayer 中播放。这都是用 Swift 2.0 编写的
我已经下载了数据,我想我可以参考它,但我不确定。当我将 URL 转换为 NSData 对象并将其打印到控制台时,会打印数据/垃圾。然而,视频文件作为二进制文件下载。我能够去 CloudKit 仪表板并下载文件并将“.mov”附加到它,它在 Quicktime 中打开没问题。
所以我认为我的主要问题是我无法弄清楚如何让视频文件真正播放,因为该文件没有扩展名。我尝试使用 URLByAppendingPathExtension() 将“.mov”附加到末尾,但无济于事。让我知道任何想法!
上传视频
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
let tempURL = info[UIImagePickerControllerMediaURL] as! NSURL
dismissViewControllerAnimated(true) () -> Void in
self.uploadVideoToiCloud(tempURL)
print("\n Before Upload: \(tempURL)\n")
func uploadVideoToiCloud(url: NSURL)
let videoRecord = CKRecord(recordType: "video", recordID: id)
videoRecord["title"] = "This is the title"
let videoAsset = CKAsset(fileURL: url)
videoRecord["video"] = videoAsset
CKContainer.defaultContainer().privateCloudDatabase.saveRecord(videoRecord) (record, error) -> Void in
dispatch_async(dispatch_get_main_queue(), () -> Void in
if error == nil
print("upload successful")
else
print(error!)
)
下载视频
func downloadVideo(id: CKRecordID)
privateDatabase.fetchRecordWithID(id) (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) () -> Void in
if error != nil
print(" Error Fetching Record " + error!.localizedDescription)
else
if results != nil
print("pulled record")
let record = results!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL
print(" After Download: \(self.videoURL!)")
self.videoAsset = AVAsset(URL: self.videoURL!)
self.playVideo()
else
print("results Empty")
【问题讨论】:
在上传之前移动文件并重命名 您需要为每个视频生成一个新的文件名,而不是capturedVideo 能否请您添加代码中提到的Self.playVideo()函数的完整代码 【参考方案1】:根本问题是 AVPlayer 需要一个文件扩展名,例如 .mov
,但 CKAsset
的 fileURL
属性指向一个缺少扩展名的文件。最干净的解决方案是创建一个硬链接,这样可以避免移动兆字节的数据并且不需要磁盘空间:
- (NSURL *)videoURL
return [self createHardLinkToVideoFile];
- (NSURL *)createHardLinkToVideoFile
NSError *err;
if (![self.hardURL checkResourceIsReachableAndReturnError:nil])
if (![[NSFileManager defaultManager] linkItemAtURL:self.asset.fileURL toURL:self.hardURL error:&err])
// if creating hard link failed it is still possible to create a copy of self.asset.fileURL and return the URL of the copy
return self.hardURL;
- (void)removeHardLinkToVideoFile
NSError *err;
if ([self.hardURL checkResourceIsReachableAndReturnError:nil])
if (![[NSFileManager defaultManager] removeItemAtURL:self.hardURL error:&err])
- (NSURL *)hardURL
return [self.asset.fileURL URLByAppendingPathExtension:@"mov"];
然后在视图控制器中,将AVPlayer
指向videoURL
而不是asset.fileURL
。
【讨论】:
【参考方案2】:解决方案是我在写入数据之前忘记指定文件名。我正在使用 URLByAppendingPathExtension 并且它弄乱了 URL,最终使用 URLByAppendingPathComponent 并在那里添加了一个文件名。这是对我有用的解决方案!感谢 cmets 伙计们。
func downloadVideo(id: CKRecordID)
privateDatabase.fetchRecordWithID(id) (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) () -> Void in
if error != nil
print(" Error Fetching Record " + error!.localizedDescription)
else
if results != nil
print("pulled record")
let record = results as CKRecord!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL as NSURL!
let videoData = NSData(contentsOfURL: self.videoURL!)
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).URLByAppendingPathComponent("filename.mov", isDirectory: false) //This is where I messed up.
NSFileManager.defaultManager().createFileAtPath(destinationPath.path!, contents:videoData, attributes:nil)
self.videoURL = destinationPath
self.videoAsset = AVURLAsset(URL: self.videoURL!)
self.playVideo()
else
print("results Empty")
【讨论】:
【参考方案3】:这是从 CloudKit 下载多个视频的解决方案。使用它,您可以将视频存储在多个目的地并轻松获取文件路径
import AVKit
import CloudKit
var assetForVideo = [CKAsset]()
var videoURLForGetVideo = NSURL()
database.perform(queryForVideo, inZoneWith: nil) [weak self] record, Error in
guard let records = record, Error == nil else
return
DispatchQueue.main.async [self] in
self?.assetForVideo = records.compactMap( $0.value(forKey: "video") as? CKAsset )
for (i,dt) in self!.assetForVideo.enumerated()
self!.videoURLForGetVideo = (dt.fileURL as NSURL?)!
let videoData = NSData(contentsOf: self!.videoURLForGetVideo as URL)
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).appendingPathComponent(self!.assetForVideo.count == i ? "filename\(self!.assetForVideo.count).mov" : "filename\(i+1).mov", isDirectory: false)! as NSURL
FileManager.default.createFile(atPath: destinationPath.path!, contents: videoData as Data?, attributes: nil)
self?.videoURLForGetVideo = destinationPath
self!.videoAssett = AVURLAsset(url: self!.videoURLForGetVideo as URL)
let abc = self!.videoAssett.url
let videoURL = URL(string: "\(abc)")
【讨论】:
以上是关于播放通过 CloudKit 作为 CKAsset 下载的视频 - iOS的主要内容,如果未能解决你的问题,请参考以下文章
在 CloudKit 中将图像存储为 CKAsset,图像倒置
将 CloudKit 记录保存到本地文件保存除 CKAsset 之外的所有字段