0

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

    ```
Community
  • 1
  • 1
Zack Shapiro
  • 6,648
  • 17
  • 83
  • 151
  • can you clarify where this error is occurring, you have several error prints – gadu Aug 01 '19 at 20:27
  • Sure, it's the very bottom, "video did not save for some reason" will add to my original post too – Zack Shapiro Aug 01 '19 at 20:28
  • recorder.stopCapture actually seems to have some sort of async callback, its fair to assume that it doesn't happen instantly. you may be trying to access the `atFileURL` too early, maybe try separate the save out to a separate function thats called in the callback of the stopRecording? (you might be able to check if theres anything at the URL also just before you try creating the asset) – gadu Aug 01 '19 at 20:29
  • @gadu good catch. I moved the save functionality to a different function which is called inside of the `stopCapture` callback but I'm still getting the same error – Zack Shapiro Aug 01 '19 at 20:57

1 Answers1

1

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)
        }
    }        
}
Pavel Kozlov
  • 993
  • 6
  • 16