最近有个需求:把屏幕内容录制下来保持到本地
这里ReplayKit不做介绍,想了解请看下面的链接
iOS端使用replaykit录制屏幕的技术细节
核心代码(最后附demo)
请求同意使用摄像头和麦克风权限,如果用户拒绝了,将无法进行录制。
不支持模拟器
{
RPScreenRecorder *_recorder;
NSURL *_movieUrl;
}
// 开始录制
[_recorder startRecordingWithHandler:^(NSError * _Nullable error) {
NSLog(@"视频录制开启产生问题=%@",error);
}];
// 结束录制
[_recorder stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
self->_movieUrl = [previewViewController valueForKey:@"movieURL"];
[self export:[_movieUrl path] complete:^(ScreenRecError error, NSString *filePath) {
[self writeVideoToAlbum:filePath];
}];
}];
//导出视频 mp4
- (void)export:(NSString *)filePathUrl complete:(void(^)(ScreenRecError error,NSString* filePath))complete {
if (!filePathUrl) {
NSLog(@"filePathUrl为空");
return;
}
NSDate *date = [NSDate date];
NSString *exportPath = [NSString stringWithFormat:@"%@%d.mp4",[self getCacheDir],(int)[date timeIntervalSince1970]*1000 ];
NSURL *fileUrl = [NSURL fileURLWithPath:filePathUrl];
AVAsset *fileAsset = [AVURLAsset assetWithURL:fileUrl];
AVMutableComposition *mixComposition = [AVMutableComposition composition];
if (!([fileAsset tracksWithMediaType:AVMediaTypeVideo].count>0 && [fileAsset tracksWithMediaType:AVMediaTypeAudio].count>0)) {
complete(exportError,filePathUrl);
return;
}
for (AVAssetTrack *track in fileAsset.tracks) {
if ([track.mediaType isEqual:AVMediaTypeVideo]) {
AVMutableCompositionTrack *compositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error;
[compositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, fileAsset.duration) ofTrack:track atTime:kCMTimeZero error:&error];
}
else if([track.mediaType isEqual:AVMediaTypeAudio]){
AVMutableCompositionTrack *compositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error;
[compositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, fileAsset.duration) ofTrack:track atTime:kCMTimeZero error:&error];
}
}
AVAssetExportSession *assetExport = [AVAssetExportSession exportSessionWithAsset:mixComposition presetName:AVAssetExportPreset1280x720];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:exportPath]) {
NSError *error = nil;
[fileManager removeItemAtPath:exportPath error:&error];
if (error) {
NSLog(@"移除文件出错=%@",error);
}
}
assetExport.outputFileType = AVFileTypeMPEG4;
assetExport.outputURL = [NSURL fileURLWithPath:exportPath];
assetExport.shouldOptimizeForNetworkUse = false;
[assetExport exportAsynchronouslyWithCompletionHandler:^{
if (assetExport.status == AVAssetExportSessionStatusCompleted) {
NSLog(@"Record SaveTmpVideo Success");
complete(nil,exportPath);
}
else {
complete(exportError,filePathUrl);
}
}];
}
//保存图片到相册
- (void)writeVideoToAlbum:(NSString *)exportFilePath{
UISaveVideoAtPathToSavedPhotosAlbum(exportFilePath, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
}
//保存视频完成之后的回调
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (error) {
NSLog(@"保存视频失败%@", error.localizedDescription);
}
else {
NSLog(@"保存视频成功");
}
}