iosswiftreplaykit

Saving a video to my camera roll returns error: The operation couldn’t be completed. (Cocoa error -1.)


I'm attempting to use ReplayKit and save the video of the screen capture to my camera roll.

However I'm getting an error when I try to save it at the very bottom of my code, that last error check: "Video did not save for some reason"

Optional(Error Domain=NSCocoaErrorDomain Code=-1 “(null)“)

“The operation couldn’t be completed. (Cocoa error -1.)”

I've looked around at a number of other questions similar to this but most of them have a trail of unanswered comments similar to "I'm getting this too, did you ever get an answer to this"

Would love some help on this. Thanks!

    private func startRecording() {
        //Create the file path to write to
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
        self.videoOutputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent(UUID.init().description + ".mp4"))
​
        //Check the file does not already exist by deleting it if it does
        do {
            try FileManager.default.removeItem(at: videoOutputURL!)
        } catch {}
​
        do {
            try videoWriter = AVAssetWriter(outputURL: videoOutputURL!, fileType: .mp4)
        } catch let writerError as NSError {
            print("Error opening video file", writerError);
            videoWriter = nil;
            return;
        }
​
        //Create the video settings
        let videoSettings: [String : Any] = [
            AVVideoCodecKey: AVVideoCodecType.h264,
            AVVideoWidthKey: view.bounds.width,
            AVVideoHeightKey: view.bounds.height
        ]
​
        //Create the asset writer input object whihc is actually used to write out the video
        //with the video settings we have created
        videoWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings);
        videoWriterInput!.expectsMediaDataInRealTime = true
        videoWriter?.add(videoWriterInput!);
​
        let recorder = RPScreenRecorder.shared()
        guard recorder.isAvailable else { return } // or throw error
​
        recorder.startCapture(handler: { (buffer, sampleType, error) in
            guard error == nil else {
                return DispatchQueue.main.async { self.presentError(error!) }
            }
​
            switch sampleType {
            case .video:
                print("writing sample....")
​
                switch self.videoWriter!.status {
                case .unknown:
                    if self.videoWriter?.startWriting != nil {
                        print("Starting writing")
​
                        self.videoWriter!.startWriting()
                        self.videoWriter!.startSession(atSourceTime:  CMSampleBufferGetPresentationTimeStamp(buffer))
                    }
​
                case .writing:
                    if self.videoWriterInput!.isReadyForMoreMediaData {
                        print("Writing a sample")
​
                        if  self.videoWriterInput!.append(buffer) == false {
                            print(" we have a problem writing video")
                        }
                    }
                default: break
                }
​
            default:
                print("not a video sample, so ignore");
            }
        })
    }
​
    private func stopRecording() {
        let recorder = RPScreenRecorder.shared()

        recorder.stopCapture { [unowned self] error in
            guard error == nil else {
                return DispatchQueue.main.async { self.presentError(error!) }
            }

            self.saveVideoToCameraRoll(completion: completion)
        }

    }

    func saveVideoToCameraRoll(completion: (() -> Void)?) {
        //Now save the video
        PHPhotoLibrary.shared().performChanges({
            print(self.videoOutputURL!)
            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: self.videoOutputURL!)
        }) { saved, error in
            if saved {
                let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert)
                let defaultAction = UIAlertAction(title: "OK", style: .default) { _ in
                    completion?()
                }
                alertController.addAction(defaultAction)
                self.present(alertController, animated: true, completion: nil)
            }

            if error != nil {
                print("Video did not save for some reason", error.debugDescription)
                debugPrint(error?.localizedDescription ?? "error is nil")
            }
        }
    }

    ```

Solution

  • Seems like you forgot to finish writing to the file when you stop recording:

    private func stopRecording() {
        let recorder = RPScreenRecorder.shared()
        recorder.stopCapture { [unowned self] error in
            ...
            self.videoWriter?.finishWriting {
                self.saveVideoToCameraRoll(completion: completion)
            }
        }        
    }