我对iOS开发和Swift相对较新,但我有一个我正在研究的应用程序应该在屏幕上记录活动并将生成的视频保存到相机胶卷。我正在使用ReplayKit。
现在正在做什么:
这是我开始录制和结束录制的代码
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)
}
}
函数由一个显示“start”的按钮运行,RPPreviewViewController?
函数由一个显示“stop”的按钮调用。
UISaveVideoAtPathToSavedPhotosAlbum(_ videoPath: String, _ completionTarget: AnyObject?, _ completionSelector: Selector, _ contextInfo: UnsafeMutablePointer<Void>)
屏幕记录正常。我有一个按钮,上面写着“完成”,它会调用stopRecording()函数。单击该按钮时,将显示预览,播放录制的视频并允许用户手动编辑和保存视频。
我正在尝试做什么:
我需要将按钮简单地保存为相机胶卷。我想绕过预览屏幕,允许用户编辑和手动保存。这可能吗?如果是这样,你会如何处理这个问题呢?
预览的类型为root = tk.Tk()
tk.IntVar(value='1')
sv = tk.StringVar()
sv.set('clicks = ' + str(iv.get()))
>>> sv.get()
'clicks = 1'
,请尽可能尝试,我似乎无法访问该视频进行保存。由于ReplayKit是UIKit的扩展,我尝试使用
catch (SQLException e) {
LOG.error(
"Sql Exception: "
+ e.getStackTrace()[1].getClassName() + "."
+ e.getStackTrace()[1].getMethodName(), e);
throw e;
方法,但这些属性都不存在!
如果您需要更多信息,请告诉我们。如果我是白痴,请告诉我!这是我在这里的第一篇文章,所以要好!谢谢。
答案 0 :(得分:3)
我也想做你所问的问题,但截至目前RPScreenRecorder
并没有提供任何这些功能。
答案 1 :(得分:2)
正如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");
}
}
}
答案 2 :(得分: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)
}
}
}
答案 3 :(得分:1)
我遇到了一个错误,当它命中时:
self.videoWriterInput.markAsFinished();
它给了我:
-[AVAssetWriterInput markAsFinished] 状态为 0 时无法调用方法