混编的时候可以用swift调用
#import <AVFoundation/AVFoundation.h>
#import <MetalKit/MetalKit.h>
#import <MetalPerformanceShaders/MetalPerformanceShaders.h>
NS_ASSUME_NONNULL_BEGIN
@interface MetalTextureManager : NSObject
+ (instancetype)shareManager;
- (void)setCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer tag:(NSInteger)tag complete:(nullable void(^)(id <MTLTexture> tex,CMSampleBufferRef buffer))complete;
@end
NS_ASSUME_NONNULL_END
#import "MetalTextureManager.h"
@interface MetalTextureManager ()
@property (nonatomic, strong) id <MTLDevice> device;
@property (nonatomic, strong) dispatch_queue_t processQueue;// 处理队列
@property (nonatomic, assign) CVMetalTextureCacheRef textureCache;// 纹理缓存区
@property (nonatomic, strong) id<MTLCommandQueue> commandQueue;// 命令队列
@property (nonatomic, strong) id<MTLTexture> texture;// 纹理
@end
@implementation MetalTextureManager
+ (instancetype)shareManager {
static MetalTextureManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[MetalTextureManager alloc] init];
[manager setup];
});
return manager;
}
- (void)setup {
[self setupMetal];
}
- (void)setCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer tag:(NSInteger)tag complete:(nullable void (^)(id<MTLTexture> _Nonnull, CMSampleBufferRef))complete {
//metal渲染
[self metalRenderWithSampleBuffer:sampleBuffer complete:^(id<MTLTexture> tex, CMSampleBufferRef buffer) {
if (complete != nil) {
complete(tex,buffer);
}
}];
}
- (void)setupMetal {
// 1.获取MTKView
self.device = MTLCreateSystemDefaultDevice();
// 3.创建命令队列
self.commandQueue = [self.device newCommandQueue];
// 4.创建Core Video的Metal纹理缓存区
CVMetalTextureCacheCreate(NULL, NULL, self.device, NULL, &_textureCache);
}
- (void)metalRenderWithSampleBuffer:(CMSampleBufferRef)sampleBuffer complete:(nullable void(^)(id<MTLTexture> tex, CMSampleBufferRef buffer))complete {
// NSLog(@"----线程3333----%@----",[NSThread currentThread]);
// 1.从sampleBuffer获取视频像素缓存区对象
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (pixelBuffer == nil) {
return;
}
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
// 2.获取捕捉视频的宽和高
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);
// 4.从现有图像缓冲区创建核心视频Metal纹理缓冲区
CVMetalTextureRef tmpTexture = NULL;
CVReturn status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, self.textureCache, pixelBuffer, NULL, MTLPixelFormatBGRA8Unorm, width, height, 0, &tmpTexture);
// 判断纹理缓冲区是否创建成功
if(status == kCVReturnSuccess) {
// 6.返回纹理缓冲区的Metal纹理对象
self.texture = CVMetalTextureGetTexture(tmpTexture);
if (complete != nil && self.texture != nil) {
complete(self.texture,sampleBuffer);
}
// 7.使用完毕,则释放纹理缓冲区
CFRelease(tmpTexture);
tmpTexture = NULL;
self.texture = NULL;
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
}
@end
使用示例
可以传递给unity去渲染(用callback将texture纹理传递给unity让其去渲染)
typedef void (*dp_updateTextureCallback_t)(void *texture, int screenId, int width, int height);
//在USBServiceOC.h里面声明
@property (nonatomic, copy, nullable) void (^screenRecordSampleBufferBlock1)(int screenId,CMSampleBufferRef sampleBuffer);
void drawRenderWithTextureIDFromUnity(dp_updateTextureCallback_t callback) {
__weak service *service = [USBServiceOC shareManager];
//这里是个获取SampleBuffer的回调block,可以在获取SampleBuffer的调用【self.screenRecordSampleBufferBlock1(0, sampleBuffer)】
service.screenRecordSampleBufferBlock1 = ^(int screenId, CMSampleBufferRef sampleBuffer) {
if (service.isNOCallBack == NO && service.isStopRecording == NO) {
[service.metalTextureManager setCMSampleBufferRef:sampleBuffer tag:0 complete:^(id<MTLTexture> _Nonnull texture, CMSampleBufferRef _Nonnull buffer) {
id<MTLTexture> tmpTexture = texture;
if (callback != nil) {
callback((__bridge void *)texture,0,int(texture.width),int(texture.height));
}
tmpTexture = nil;
}];
}
};
}
[service.metalTextureManager setCMSampleBufferRef:sampleBuffer tag:0 complete:^(id<MTLTexture> _Nonnull texture, CMSampleBufferRef _Nonnull buffer) {
id<MTLTexture> tmpTexture = texture;
if (callback != nil) {
callback((__bridge void *)texture,0,int(texture.width),int(texture.height));
}
tmpTexture = nil;
}];