【问题标题】:Play video downloaded through CloudKit as CKAsset - iOS播放通过 CloudKit 作为 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()函数的完整代码

标签: ios swift icloud avplayer cloudkit


【解决方案1】:

根本问题是 AVPlayer 需要一个文件扩展名,例如 .mov,但 CKAssetfileURL 属性指向一个缺少扩展名的文件。最干净的解决方案是创建一个硬链接,这样可以避免移动兆字节的数据并且不需要磁盘空间:

- (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)")
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-24
        • 1970-01-01
        相关资源
        最近更新 更多