Error Domain=NSCocoaErrorDomain Code=-1 "(null)" when moving .mov to camera roll
Asked Answered
G

2

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.

Godesberg answered 11/7, 2017 at 8:20 Comment(6)
Did you figure this out ?Aniseed
Nope, still have this issue. Nothing that I've tried has worked. I was suspecting it might be some sort of an issue with the aspect ratio, but it works fine with the same aspect ratio in HD size, just not full sensor size.Godesberg
Any solution? I meet same problem with all video filesCaterwaul
Nope, never did get this to work. In the end, I decided not to support the 4K larger than 16:9 aspect ratioGodesberg
Same problem here. Still no solution? My video is 256x256.Strawser
No, I have no idea what is causing this. I can get many sizes to save OK, but not 4032x3024. I can get 3880x2160 to save just fine. It's not the 4:3 aspect ratio doing it because I get smaller 4:3 to save OK.Godesberg
S
-1

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)
            }
        }
}
Spartacus answered 31/10, 2018 at 8:19 Comment(0)
P
-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);
      }
    }];
  });
}
Paulapauldron answered 12/11, 2018 at 14:30 Comment(1)
Please add some explanation.Katinka

© 2022 - 2024 — McMap. All rights reserved.