13

I'm having a weird problem moving a .mov file created by my app from the documents folder to the camera roll. A bit of background:

The app makes time lapse movies. It works specifically with the devices that have a 12 megapixel 4032x3024 sensor. It created the movies in the app's documents folder. The movies can be saved as either 4k or HD. They can also be saved as a 4:3 aspect ratio movie of the entire sensor, or a 16:9 crop of the sensor. If the user wants the movie to be stored in the Camera Roll of the device, they can set that option. My problem exists when trying to move a full size movie (4032x3024) from the app's documents folder to the Camera Roll. I get this error:

Error Domain=NSCocoaErrorDomain Code=-1 "(null)"

The movie is fine, it's still sitting in the document's folder. It just can't be copied to the Camera Roll. If I do this same operation through the same code with any of the other sizes, no problem. A 4:3 HD (1440x1080) works fine, a 16:9 HD (1920x1080) works fine, a 16:9 4k (3880x2160) works fine. It's just the 4:3 4k (4032x3024) that generates this error when I try to move it.

This is the code that does the move:

PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: cameraRollURL!)

The URL is OK because it works with the other sizes just fine.

4

2 回答 2

-1

当我从拉动方法切换到推动方法时,我确实解决了这个问题(从作者的角度来看)。

拉式方法是当我有一个 UIImage 数组(从相机捕获),并在它准备好处理下一个图像时提供写入器。推送方法是当我一个一个 UIImage (从相机捕获)时,如果它准备好处理下一个图像,则提供作者。

不确定是什么原因。也许处理 AVWritter 调用之间的消息循环。

优点:如果捕获更长的视频,您不会随时在 UIImage 数组中分配大量 GB 内存。

缺点:如果捕获发生得太快,写入器可能还没有准备好写入样本,因此可能会丢弃帧,因为它是实时处理的。

斯威夫特 4:

func initVideo(videoSettings: [String: Any]) -> (assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput, bufferAdapter:AVAssetWriterInputPixelBufferAdaptor)? {

    if(FileManager.default.fileExists(atPath: ImagesToVideoUtils.tempPath)){
        guard (try? FileManager.default.removeItem(atPath: ImagesToVideoUtils.tempPath)) != nil else {
            print("remove path failed")
            return nil
        }
    }

    let assetWriter = try! AVAssetWriter(url: ImagesToVideoUtils.fileURL, fileType: AVFileType.mov)

    let writeInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
    assert(assetWriter.canAdd(writeInput), "add failed")

    assetWriter.add(writeInput)
    let bufferAttributes:[String: Any] = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32ARGB)]
    let bufferAdapter = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: writeInput, sourcePixelBufferAttributes: bufferAttributes)

    return (assetWriter, writeInput, bufferAdapter)

}

func exportVideo_start(assetWriter: AVAssetWriter) -> (DispatchQueue) {

    assetWriter.startWriting()
    assetWriter.startSession(atSourceTime: CMTime.zero)

    let mediaInputQueue = DispatchQueue(label: "mediaInputQueue")

    return (mediaInputQueue)
}

func exportVideo_write(videoSettings: [String: Any], img: UIImage, assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput, bufferAdapter:AVAssetWriterInputPixelBufferAdaptor, mediaInputQueue: DispatchQueue, timestamp: CMTime) {

    if (writeInput.isReadyForMoreMediaData){
        var sampleBuffer:CVPixelBuffer?
        autoreleasepool{
            sampleBuffer = self.newPixelBufferFrom(cgImage: img.cgImage!, videoSettings: videoSettings)
        }

        bufferAdapter.append(sampleBuffer!, withPresentationTime: timestamp)
        print("Adding frame at \(timestamp)")
    }
}

func exportVideo_end( assetWriter: AVAssetWriter, writeInput: AVAssetWriterInput) {

    writeInput.markAsFinished()
        assetWriter.finishWriting {
            DispatchQueue.main.sync {
                print("Finished writting")
                ImagesToVideoUtils.saveToCameraRoll(videoURL: ImagesToVideoUtils.fileURL)
            }
        }
}
于 2018-10-31T08:19:16.907 回答
-3
- (void)saveVideoPath:(NSString *)videoPath {
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), 
  dispatch_get_main_queue(), ^{
    NSURL *url = [NSURL fileURLWithPath:videoPath];
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
      [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
      if (success) {
        NSLog(@"succ");
      }
      if (error) {
        NSLog(@"%@",error);
      }
    }];
  });
}
于 2018-11-12T14:30:22.343 回答