ReplayKit
Record or stream video from the screen, and audio from the app and microphone.
Overview
Using the ReplayKit
framework, users can record video from the screen, and audio from the app and microphone. They can then share their recordings with other users through email, messages, and social media. You can build app extensions for live broadcasting your content to sharing services. ReplayKit is incompatible with AVPlayer
content.
概述
使用 ReplayKit 框架,用戶可以從屏幕上錄制視頻,并從應(yīng)用程序內(nèi)和麥克風(fēng)錄制音頻干跛。 然后他們也可以通過電子郵件、消息和社交媒體與其他用戶共享他們的錄音烂叔。 您還可以構(gòu)建應(yīng)用擴展程序,共享服務(wù)嵌牺。 注意:ReplayKit 與 AVPlayer 內(nèi)容不兼容蒙保。
ReplayKit 優(yōu)點:
1、內(nèi)存奴曙、CPU占用極小可以忽略不計
2别凹、錄制清晰度和流暢度非常高
3、不需要導(dǎo)入一些SDK包洽糟,對APP的負(fù)擔(dān)幾乎為0
4番川、錄制代碼實現(xiàn)簡單
ReplayKit 缺點:
1、不支持AVPlayer播放的視頻錄制
2脊框、不支持模擬器
3、無法自定義RPPreviewViewController預(yù)覽視圖
4践啄、無法修改錄制視頻保存路徑
5浇雹、錄制的原始視頻清晰度非常高,導(dǎo)致整個視頻文件非常大
6屿讽、部分機型部分系統(tǒng)錄制會有失敗的情況昭灵,穩(wěn)定性有待商榷
7、只支持 iOS9.0+ 版本
錄屏過程:
1伐谈、檢測是否有相冊權(quán)限(后期不需要本地操作錄屏可省略)
2烂完、檢測是否支持錄屏(iOS9.0+)
3、開始錄屏
4诵棵、結(jié)束錄屏
5抠蚣、將錄屏保存到相冊
6、拿出相冊里當(dāng)前錄屏進行壓縮處理(壓縮規(guī)格可修改)
7履澳、壓縮后的錄屏保存至沙盒后可進行任意操作
部分代碼:
1嘶窄、獲取相冊權(quán)限
- (void)startRecord {
[MXReplayManager mx_getPHAuthorizationStatusBlock:^(BOOL success) {
if (success) {
[self mx_recorderAvailable];
}
}];
}
2怀跛、錄屏是否可用
// 錄屏是否可用
- (void)mx_recorderAvailable {
if ([_recorder isAvailable]) {
[self mx_startCapture];
} else {
NSLog(@"請允許App錄制屏幕且使用麥克風(fēng)(選擇第一項),否則無法進行錄屏");
}
}
3柄冲、開始錄屏
// 開始錄屏(分系統(tǒng))
- (void)mx_startCapture {
//是否錄麥克風(fēng)的聲音(如果只想要App內(nèi)的聲音吻谋,設(shè)置為NO即可)
_recorder.microphoneEnabled = NO;
if ([_recorder isRecording]) {
NSLog(@"正在錄制...");
} else {
if (@available(iOS 11.0, *)) {
[_recorder startCaptureWithHandler:^(CMSampleBufferRef _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) {
//CMSampleBufferRef 視頻+音頻原始幀數(shù)據(jù) (幀數(shù)據(jù)處理可參考部分開源直播SDk)
switch (bufferType) {
case RPSampleBufferTypeVideo: //視頻
break;
case RPSampleBufferTypeAudioApp: //App內(nèi)音頻
break;
case RPSampleBufferTypeAudioMic: //麥克風(fēng)音頻
break;
default:
break;
}
} completionHandler:^(NSError * _Nullable error) {
}];
} else if (@available(iOS 10.0, *)) {
[_recorder startRecordingWithHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"啟動錄屏成功...");
}
}];
} else if (@available(iOS 9.0, *)) {
[_recorder startRecordingWithMicrophoneEnabled:NO handler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"啟動錄屏成功...");
}
}];
}
}
}
4、結(jié)束錄屏
//停止錄屏
- (void)stopRecord {
if (@available(iOS 11.0, *)) {
[_recorder stopCaptureWithHandler:^(NSError * _Nullable error) {
}];
} else {
[_recorder stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) {
NSURL * videoURL = [previewViewController valueForKey:@"movieURL"];
if (!videoURL) {
NSLog(@"錄屏失敗...");
} else {
//是否需要展示預(yù)覽界面給用戶现横,自行決定
[self mx_saveVideoToPhoto:videoURL];
}
}];
}
}
5漓拾、保存視頻至相冊
//保存視頻至相冊
- (void)mx_saveVideoToPhoto:(NSURL *)videoURL {
NSString * videoPath = [videoURL path];
BOOL compatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoPath);
if (compatible) {
UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, @selector(savedPhotoImage:didFinishSavingWithError:contextInfo:), nil);
}
}
6、保存視頻完成之后的回調(diào)
//保存視頻完成之后的回調(diào)
- (void)savedPhotoImage:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (error) {
NSLog(@"保存視頻失敗 == %@", error.description);
} else {
//取出這個視頻并按創(chuàng)建日期排序
PHFetchOptions * options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult * assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
PHAsset * phasset = [assetsFetchResults lastObject];
if (phasset) {
//視頻文件
if (phasset.mediaType == PHAssetMediaTypeVideo) {
PHImageManager * manager = [PHImageManager defaultManager];
[manager requestAVAssetForVideo:phasset options:nil resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
AVURLAsset * urlAsset = (AVURLAsset *)asset;
[self mx_saveVideoToDocument:urlAsset.URL];
}];
} else {
NSLog(@"未成功保存視頻...");
}
} else {
NSLog(@"未成功保存視頻...");
}
}
}
7戒祠、保存視頻至沙盒
//保存視頻至沙盒
- (void)mx_saveVideoToDocument:(NSURL *)videoURL {
NSString * outPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[@"mx_test_replay" stringByAppendingString:@".mp4"]];
[MXReplayManager mx_compressQuailtyWithInputURL:videoURL outputURL:[NSURL fileURLWithPath:outPath] blockHandler:^(AVAssetExportSession * _Nonnull session) {
if (session.status == AVAssetExportSessionStatusCompleted) {
NSLog(@"視頻已處理好可以對其進行操作");
//處理完的視頻是否需要刪除骇两?自行決定
} else {
NSLog(@"視頻壓縮出錯...");
}
}];
}
8、壓縮視頻
+ (void)mx_compressQuailtyWithInputURL:(NSURL *)inputURL
outputURL:(NSURL *)outputURL
blockHandler:(void (^)(AVAssetExportSession * _Nonnull))handler {
AVURLAsset * asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
session.outputURL = outputURL;
session.outputFileType = AVFileTypeMPEG4;
[session exportAsynchronouslyWithCompletionHandler:^(void) {
if (handler) {
handler(session);
}
}];
}
GitHub地址
原創(chuàng)文章得哆,轉(zhuǎn)載請注明出處脯颜。