如何使用应用程序按钮将ReplayKit视频保存到相机胶卷

问题描述 投票:14回答:3

我对iOS开发和Swift相对较新,但我有一个我正在研究的应用程序应该在屏幕上记录活动并将生成的视频保存到相机胶卷。我正在使用ReplayKit。

什么在现在:

这是我开始录制和结束录制的代码,startRecording()函数由一个显示“start”的按钮运行,stopRecording()函数由一个显示“stop”的按钮调用。

var preview : RPPreviewViewController?

    func startRecording() {
        let recorder = RPScreenRecorder.sharedRecorder()
        recorder.startRecordingWithMicrophoneEnabled(true) { 
            [unowned self] (error) in
            print(recorder)
            if let unwrappedError = error {
                print(unwrappedError.localizedDescription)
            }
        }
    }

    func stopRecording() {
        let recorder = RPScreenRecorder.sharedRecorder()
        recorder.stopRecordingWithHandler {
            [unowned self] (preview, error) in
                if let unwrappedError = error {
                    print(unwrappedError.localizedDescription)
                }

        if let unwrappedPreview = preview {
            print("end")
            unwrappedPreview.previewControllerDelegate = self
    unwrappedPreview.modalPresentationStyle=UIModalPresentationStyle.FullScreen
            self.presentViewController(unwrappedPreview, animated: true, completion: nil)
        }
    }

屏幕记录正常。我有一个按钮,上面写着“完成”,它会调用stopRecording()函数。单击该按钮时,将显示预览,播放录制的视频并允许用户手动编辑和保存视频。

我正在尝试做什么:

我需要将按钮简单地保存为相机胶卷。我想绕过预览屏幕,允许用户编辑和手动保存。这可能吗?如果是这样,你会如何处理这个问题?

预览是RPPreviewViewController?类型,尽我所能,我似乎无法访问视频进行保存。由于ReplayKit是UIKit的扩展,我尝试使用

UISaveVideoAtPathToSavedPhotosAlbum(_ videoPath: String, _ completionTarget: AnyObject?, _ completionSelector: Selector, _ contextInfo: UnsafeMutablePointer<Void>)

方法,但这些属性都不存在!

如果您需要更多信息,请告诉我。如果我是白痴,请告诉我!这是我在这里的第一篇文章,所以要好!谢谢。

ios swift swift2
3个回答
3
投票

我也想做你所问的问题,但截至目前,RPScreenRecorder没有提供任何这些功能。


3
投票

正如Geoff H所提到的,Replay Kit 2现在允许您录制屏幕并将其保存在您的应用程序或图库中,而无需使用预览。

文档很稀疏但经过一些试验和实验后,下面的代码可以在iOS 12中使用。

请注意,这只会捕获视频而不是音频,虽然这应该很容易添加,如果使用它,您可能需要添加更多错误检查。例如,下面的功能可以通过UI按钮触发。

 @objc func startRecording() {
        //Use ReplayKit to record the screen

        //Create the file path to write to
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
        self.videoOutputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent("MyVideo.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: AVFileType.mp4)
        } catch let writerError as NSError {
            os_log("Error opening video file", writerError);
            videoWriter = nil;
            return;
        }

        //Create the video settings
        let videoSettings: [String : Any] = [
            AVVideoCodecKey  : AVVideoCodecType.h264,
            AVVideoWidthKey  : 1920,  //Replace as you need
            AVVideoHeightKey : 1080   //Replace as you need
        ]

        //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: AVMediaType.video, outputSettings: videoSettings);
        videoWriter.add(videoWriterInput);

        //Tell the screen recorder to start capturing and to call the handler when it has a
        //sample 
        RPScreenRecorder.shared().startCapture(handler: { (cmSampleBuffer, rpSampleType, error) in

            guard error == nil else {
                //Handle error
                os_log("Error starting capture");
                return;
            }

            switch rpSampleType {
                case RPSampleBufferType.video:
                    os_log("writing sample....");
                    if self.videoWriter.status == AVAssetWriter.Status.unknown {

                        if (( self.videoWriter?.startWriting ) != nil) {
                            os_log("Starting writing");
                            self.videoWriter.startWriting()
                            self.videoWriter.startSession(atSourceTime:  CMSampleBufferGetPresentationTimeStamp(cmSampleBuffer))
                        }
                    }

                    if self.videoWriter.status == AVAssetWriter.Status.writing {
                        if (self.videoWriterInput.isReadyForMoreMediaData == true) {
                            os_log("Writting a sample");
                            if  self.videoWriterInput.append(cmSampleBuffer) == false {
                                print(" we have a problem writing video")
                            }
                        }
                }

                default:
                    os_log("not a video sample, so ignore");
            }
        } )
    }

    @objc func stoprecording() {
        //Stop Recording the screen
        RPScreenRecorder.shared().stopCapture( handler: { (error) in
            os_log("stopping recording");
        })

        self.videoWriterInput.markAsFinished();
        self.videoWriter.finishWriting {
            os_log("finished writing video");

            //Now save the video
            PHPhotoLibrary.shared().performChanges({
                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, handler: nil)
                    alertController.addAction(defaultAction)
                    self.present(alertController, animated: true, completion: nil)
                }
                if error != nil {
                    os_log("Video did not save for some reason", error.debugDescription);
                    debugPrint(error?.localizedDescription ?? "error is nil");
                }
            }
        }

1
投票

是的你可以。检查这个ReplayKit2 Swift 4:

https://medium.com/@giridharvc7/replaykit-screen-recording-8ee9a61dd762

一旦你有了这个文件,把它保存到相机胶卷上应该不会太麻烦:

static func saveVideo(url: URL, returnCompletion: @escaping (String?) -> () ) {

        DispatchQueue.global(qos: .userInitiated).async { 

            guard let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

            if !FileManager.default.fileExists(atPath: documentsDirectoryURL.appendingPathComponent(url.lastPathComponent).path) {

                URLSession.shared.downloadTask(with: url) { (location, response, error) -> Void in

                    guard let location = location else { return }

                    let destinationURL = documentsDirectoryURL.appendingPathComponent(response?.suggestedFilename ?? url.lastPathComponent)

                    do {
                        try FileManager.default.moveItem(at: location, to: destinationURL)
                        PHPhotoLibrary.requestAuthorization({ (authorizationStatus: PHAuthorizationStatus) -> Void in
                            if authorizationStatus == .authorized {
                                PHPhotoLibrary.shared().performChanges({
                                    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: destinationURL)}) { completed, error in
                                        DispatchQueue.main.async {
                                            if completed {                                                    returnCompletion(url.lastPathComponent)
                                            } else {
                                                returnCompletion(nil)
                                            }
                                        }
                                }
                            }
                        })
                        returnCompletion(url.lastPathComponent)
                    } catch {
                        returnCompletion(nil)
                    }

                }.resume()

            } else {
                returnCompletion(nil)
            }
        }

    }
© www.soinside.com 2019 - 2024. All rights reserved.