关于Replaykit日志/写入文件的问题的问题.
1.replaykit写入的文件怎么获取...
思路:利用Appgroup. 先把文件写入到沙盒,然后在扩展还在运行的时候,把扩展的日志copy到沙盒.
扩展代码:
#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)
{
//转到 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秒后追加任务代码到主队列,并开始执行
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秒后追加任务代码到主队列,并开始执行
//打印当前线程
[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);
}
因为我是录屏写入buffer 数据的,所以,我在录屏开始的时候调用了
saveToFile
然后我在每一帧回调的时候都调用了.起到保存每一帧的问题..
+ (void)savePixel:(CMSampleBufferRef)sampleBuffer
延时结束是因为录制的yuv 数据很大.我们在实际开发者中可根据这个做修改.
最后在主进程进行文件的copy动作.切记 一定要扩展进程活跃的时候执行copy
最好是在主进程写一个按钮,点一下这个按钮就执行copy的动作!
-(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);
}
}
这样就可以在主进程的沙盒文件拿到扩展进程的日志或者资源了.另说一句.Replaykit 有很多坑.后续我会慢慢整理出来. 因为就2个文件,就不上传git了.大佬们见谅一下.不过代码我已经完整的贴出来了.至于APPGroup 怎么搞,顺便说一句
选中项目的 targets 然后 点击 +capability 然后选择 appGroup 即可 图就不截了