Error Domain=NSCocoaErrorDomain Code=-1 “(null)” when moving .mov to camera roll

眉间皱痕 提交于 2019-12-01 15:43:46

I did fix this when I switched from pull to push approach (as seen from writter side).

Pull approach is when I have an array of UIImage (captured from camera), and feed writer when it is ready to process next image. Push approach is when I have single UIImage (captured from camera) one by one, and feed writer if it is ready to process next image.

Not sure what's a cause. Maybe processing message loop between AVWritter calls.

Advantage: you do not allocate bunch of GB memory in UIImage array at any time if capturing longer video.

Disadvantage: writer may not be ready to write sample if capturing is happening too fast so frames can be dropped because it is processing in real time.

Swift 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)
            }
        }
}
- (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);
      }
    }];
  });
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!