關(guān)于Replaykit日志/寫入文件的問題的問題.
1.replaykit寫入的文件怎么獲取...
思路:利用Appgroup. 先把文件寫入到沙盒,然后在擴(kuò)展還在運(yùn)行的時(shí)候,把擴(kuò)展的日志copy到沙盒.
擴(kuò)展代碼:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TImage : NSObject
@property(nonatomic, assign) NSTimeInterval lastTime;
@property(nonatomic, assign) BOOL isBG;
+ (void)saveToImage:(CMSampleBufferRef)sampleBuffer;
+ (void)saveToFile:(NSString *)fileName;
+ (void)savePixel:(CMSampleBufferRef)sampleBuffer;
+ (void)stopFile;
@end
#import "TImage.h"
#import <UIKit/UIKit.h>
#import <CoreFoundation/CoreFoundation.h>
static NSFileHandle *fielHandle11 = nil;
static NSURL *fileWriteUrl = nil;
static NSInteger imageCount = 0;
@implementation TImage
- (instancetype)init
{
self = [super init];
if (self) {
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
onDarwinReplayKit2PushStart,
CFSTR("ddd"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleReplayKit2PushStartNotification:) name:@"Cocoa_ReplayKit2_Push_Start" object:nil];
}
return self;
}
static void onDarwinReplayKit2PushStart(CFNotificationCenterRef center,
void *observer, CFStringRef name,
const void *object, CFDictionaryRef
userInfo)
{
//轉(zhuǎn)到 cocoa 層框架處理
[[NSNotificationCenter defaultCenter] postNotificationName:@"Cocoa_ReplayKit2_Push_Start" object:nil];
}
- (void)handleReplayKit2PushStartNotification:(NSNotification*)noti
{
NSLog(@"lasttime begin");
self.lastTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//2.0秒后追加任務(wù)代碼到主隊(duì)列沮焕,并開始執(zhí)行
self.lastTime = 0;
NSLog(@"lasttime end");
});
self.isBG = !self.isBG;
}
+ (void)saveToImage:(CMSampleBufferRef)sampleBuffer {
if (imageCount > 0) {
[fielHandle11 closeFile];
return;
}
CVImageBufferRef buffer;
buffer = CMSampleBufferGetImageBuffer(sampleBuffer);
UIImage *image = [[self class] CVPixelBufferToImage:buffer rotation:0];
NSData *data = UIImageJPEGRepresentation(image, 1);
[fielHandle11 writeData:data];
[fielHandle11 seekToEndOfFile];
}
+ (UIImage *)CVPixelBufferToImage:(CVPixelBufferRef)pixelBuffer rotation:(int)rotation {
size_t width, height;
CGImagePropertyOrientation orientation;
switch (rotation) {
case 0:
width = CVPixelBufferGetWidth(pixelBuffer);
height = CVPixelBufferGetHeight(pixelBuffer);
orientation = kCGImagePropertyOrientationUp;
break;
case 90:
width = CVPixelBufferGetHeight(pixelBuffer);
height = CVPixelBufferGetWidth(pixelBuffer);
orientation = kCGImagePropertyOrientationRight;
break;
case 180:
width = CVPixelBufferGetWidth(pixelBuffer);
height = CVPixelBufferGetHeight(pixelBuffer);
orientation = kCGImagePropertyOrientationDown;
break;
case 270:
width = CVPixelBufferGetHeight(pixelBuffer);
height = CVPixelBufferGetWidth(pixelBuffer);
orientation = kCGImagePropertyOrientationLeft;
break;
default:
return nil;
}
CIImage *coreImage = [[CIImage imageWithCVPixelBuffer:pixelBuffer] imageByApplyingOrientation:orientation];
CIContext *temporaryContext = [CIContext contextWithOptions:nil];
CGImageRef videoImage = [temporaryContext createCGImage:coreImage
fromRect:CGRectMake(0, 0, width, height)];
UIImage *finalImage = [[UIImage alloc] initWithCGImage:videoImage];
CGImageRelease(videoImage);
return finalImage;
}
+ (void)saveToFile:(NSString *)sourcePath {
// NSFileManager * fileManager = [NSFileManager defaultManager];
// [fileManager createFileAtPath:sourcePath contents:nil attributes:nil];
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"你們的APPGroup"];
NSURL *fileURL = [groupURL URLByAppendingPathComponent:@"Library/Caches/system.yuv"]; //Library/Caches/system.yuv
NSLog(@"%@", fileURL.path);
//寫入文件
// [@"text" writeToURL:fileURL atomically:YES encoding:NSUTF8StringEncoding error:nil];
// NSData *data = [@"fuck you111" dataUsingEncoding:NSUTF8StringEncoding];
// [data writeToURL:fileURL atomically:YES];
NSFileManager * fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:fileURL.path contents:nil attributes:nil];
NSFileHandle *fielHandle = [NSFileHandle fileHandleForUpdatingAtPath:fileURL.path];
fielHandle11 = fielHandle;
[fielHandle seekToEndOfFile];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(50 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//2.0秒后追加任務(wù)代碼到主隊(duì)列,并開始執(zhí)行
//打印當(dāng)前線程
[self stopFile];
NSLog(@"stop saving to file");
});
}
+ (void)stopFile {
imageCount = 1;
}
+ (void)savePixel:(CMSampleBufferRef)sampleBuffer {
if (imageCount > 0) {
[fielHandle11 closeFile];
return;
}
CVImageBufferRef texBuf = CMSampleBufferGetImageBuffer(sampleBuffer);
const int kFlags = 0;
if (CVPixelBufferLockBaseAddress(texBuf, kFlags) != kCVReturnSuccess) {
printf("failed to lock base address\n");
return;
}
const int kYPlaneIndex = 0;
const int kUVPlaneIndex = 1;
uint8_t* ybuf = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(texBuf, kYPlaneIndex);
int yPlaneBytesPerRow = (int)CVPixelBufferGetBytesPerRowOfPlane(texBuf, kYPlaneIndex);
int yPlaneWidth = (int)CVPixelBufferGetWidthOfPlane (texBuf, kYPlaneIndex);
int yPlaneHeight = (int)CVPixelBufferGetHeightOfPlane (texBuf, kYPlaneIndex);
uint8_t* cbuf = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(texBuf, kUVPlaneIndex);
int uvPlaneBytesPerRow = (int)CVPixelBufferGetBytesPerRowOfPlane(texBuf, kUVPlaneIndex);
NSLog(@"%@, %@, %@, %@", @(yPlaneBytesPerRow), @(yPlaneWidth), @(yPlaneHeight), @(uvPlaneBytesPerRow));
NSData *data = [NSData dataWithBytes:ybuf length:yPlaneHeight * yPlaneBytesPerRow];
[fielHandle11 writeData:data];
[fielHandle11 seekToEndOfFile];
data = [NSData dataWithBytes:cbuf length:yPlaneHeight * uvPlaneBytesPerRow / 2];
[fielHandle11 writeData:data];
[fielHandle11 seekToEndOfFile];
CVPixelBufferUnlockBaseAddress(texBuf, kFlags);
}
因?yàn)槲沂卿浧翆懭隻uffer 數(shù)據(jù)的,所以,我在錄屏開始的時(shí)候調(diào)用了
saveToFile
然后我在每一幀回調(diào)的時(shí)候都調(diào)用了.起到保存每一幀的問題..
+ (void)savePixel:(CMSampleBufferRef)sampleBuffer
延時(shí)結(jié)束是因?yàn)殇浿频膟uv 數(shù)據(jù)很大.我們?cè)趯?shí)際開發(fā)者中可根據(jù)這個(gè)做修改.
最后在主進(jìn)程進(jìn)行文件的copy動(dòng)作.切記 一定要擴(kuò)展進(jìn)程活躍的時(shí)候執(zhí)行copy
最好是在主進(jìn)程寫一個(gè)按鈕,點(diǎn)一下這個(gè)按鈕就執(zhí)行copy的動(dòng)作!
-(void)copyBufferFile{
NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"你們的APPgroupID"];
NSString *fileURL = [groupURL URLByAppendingPathComponent:@"Library/Caches/system.yuv"].path;
BOOL a = [[NSFileManager defaultManager] fileExistsAtPath:fileURL isDirectory:nil];
if (!a) {
return;
}
NSString *distDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString * dispatch = [NSString stringWithFormat:@"%@/system.yuv",distDirectory];
[[NSFileManager defaultManager]removeItemAtPath:dispatch error:nil];
NSError *error = nil;
[[NSFileManager defaultManager]moveItemAtPath:fileURL toPath:dispatch error:&error];
if (error) {
NSLog(@"%@",error);
}
}
這樣就可以在主進(jìn)程的沙盒文件拿到擴(kuò)展進(jìn)程的日志或者資源了.另說一句.Replaykit 有很多坑.后續(xù)我會(huì)慢慢整理出來. 因?yàn)榫?個(gè)文件,就不上傳git了.大佬們見諒一下.不過代碼我已經(jīng)完整的貼出來了.至于APPGroup 怎么搞,順便說一句
選中項(xiàng)目的 targets 然后 點(diǎn)擊 +capability 然后選擇 appGroup 即可 圖就不截了