Mac OS 使用Metal渲染NV12、YUV420、CMSampleBufferRef视频
Mac OS 使用Metal渲染NV12、YUV420、CMSampleBufferRef视频
- 需求
- MTKView初始化
- 摄像头采集CMSampleBufferRef
- 渲染CMSampleBufferRef
- yuv420转NV12
- 渲染NV12
- END
资料较少,整合后仅作为记录学习使用。
需求
yuv420原始视频数据使用metal渲染。
MTKView初始化
vector_uint2 viewportSize;
MTKView *mMtkview;
id <MTLDevice> mDevice;
id <MTLCommandQueue> mCmdQueue;
id <MTLRenderPipelineState> mPipeline;
id <MTLBuffer> mBuffer;
id <MTLTexture> mTexture;
CVMetalTextureCacheRef mTextureCache;
NSUInteger vertexCount;id<MTLTexture> mTextureY;
id<MTLTexture> mTextureUV;id <MTLBuffer> mConvertMatrix;
setMetal
mMtkview = [[MTKView alloc] initWithFrame:self.view.frame device:MTLCreateSystemDefaultDevice()];
mDevice = mMtkview.device;
self.view = mMtkview;
mMtkview.delegate = self;
mCmdQueue = [mDevice newCommandQueue];CVMetalTextureCacheCreate(NULL, NULL, mDevice, NULL, &mTextureCache);
setPipeline
id <MTLLibrary> library = [mDevice newDefaultLibrary];
id <MTLFunction> vertexfunc = [library newFunctionWithName:@"verfunc"];
id <MTLFunction> fragfunc = [library newFunctionWithName:@"fragfunc"];
MTLRenderPipelineDescriptor *renderdes = [MTLRenderPipelineDescriptor new];
renderdes.vertexFunction = vertexfunc;
renderdes.fragmentFunction = fragfunc;
renderdes.colorAttachments[0].pixelFormat = mMtkview.colorPixelFormat;
mPipeline = [mDevice newRenderPipelineStateWithDescriptor:renderdes error:nil];
setupMatrix
matrix_float3x3 kColorConversion601FullRangeMatrix = (matrix_float3x3){(simd_float3){1.0, 1.0, 1.0},(simd_float3){0.0, -0.343, 1.765},(simd_float3){1.4, -0.711, 0.0},
};
vector_float3 kColorConversion601FullRangeOffset = (vector_float3){ -(16.0/255.0), -0.5, -0.5}; // 这个是偏移HQHConvertMatrix converMatrix;
converMatrix.matrix = kColorConversion601FullRangeMatrix;
converMatrix.offset = kColorConversion601FullRangeOffset;
mConvertMatrix = [mDevice newBufferWithBytes:&converMatrix length:sizeof(HQHConvertMatrix) options:MTLResourceStorageModeShared];
MTKViewDelegate
- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size {viewportSize = (vector_uint2){size.width, size.height};
}- (void)drawInMTKView:(MTKView *)view {if (mTextureY && mTextureUV) {id <MTLCommandBuffer> cmdBuffer = [mCmdQueue commandBuffer];MTLRenderPassDescriptor *passdes = view.currentRenderPassDescriptor;if (passdes != nil) {id <MTLRenderCommandEncoder> cmdEncoder = [cmdBuffer renderCommandEncoderWithDescriptor:passdes];[cmdEncoder setViewport:(MTLViewport){0.0,0.0,viewportSize.x,viewportSize.y, -1.0,1.0}];[cmdEncoder setRenderPipelineState:mPipeline];[cmdEncoder setVertexBuffer:mBuffer offset:0 atIndex:0];[cmdEncoder setFragmentTexture:mTextureY atIndex:0];[cmdEncoder setFragmentTexture:mTextureUV atIndex:1];[cmdEncoder setFragmentBuffer:mConvertMatrix offset:0 atIndex:HQHFragmentInputindexMatrix];[cmdEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCount];/**rgb 数据[cmdEncoder setFragmentTexture:mTexture atIndex:0];[cmdEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:vertexCount];*/[cmdEncoder endEncoding];[cmdBuffer presentDrawable:view.currentDrawable];[cmdBuffer commit];}}
}
摄像头采集CMSampleBufferRef
AVCaptureSession *mCaptureSession;
AVCaptureDeviceInput *mCaptureInput;
AVCaptureVideoDataOutput *mCaptureOutput;
setupSession
mCaptureSession = [[AVCaptureSession alloc] init];
mCaptureSession.sessionPreset = AVCaptureSessionPreset1280x720;
if (@available(macOS 10.15, *)) {AVCaptureDevice *cameraDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionBack];mCaptureInput = [[AVCaptureDeviceInput alloc] initWithDevice:cameraDevice error:nil];
} else {AVCaptureDevice *cameraDevice = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo].firstObject;mCaptureInput = [[AVCaptureDeviceInput alloc] initWithDevice:cameraDevice error:nil];
}
if ([mCaptureSession canAddInput:mCaptureInput]) {[mCaptureSession addInput:mCaptureInput];
}mCaptureOutput = [[AVCaptureVideoDataOutput alloc] init];
[mCaptureOutput setAlwaysDiscardsLateVideoFrames:NO];
[mCaptureOutput setSampleBufferDelegate:self queue:dispatch_queue_create("bd", DISPATCH_QUEUE_SERIAL)];if ([mCaptureSession canAddOutput:mCaptureOutput]) {[mCaptureSession addOutput:mCaptureOutput];
}
NSLog(@"out = %@ ary = %@",mCaptureOutput,[mCaptureOutput availableVideoCodecTypes]);
[mCaptureOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
AVCaptureConnection *connection = [mCaptureOutput connectionWithMediaType:AVMediaTypeVideo];
[connection setVideoOrientation:AVCaptureVideoOrientationPortrait];
[mCaptureSession startRunning];
AVCaptureVideoDataOutputSampleBufferDelegate
- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{NSLog(@"data");
// [self setTexture:sampleBuffer];
}
渲染CMSampleBufferRef
- (void)setTexture:(CMSampleBufferRef)samplebuffer {CVPixelBufferRef pixelbuffer = CMSampleBufferGetImageBuffer(samplebuffer);// textureY{size_t width = CVPixelBufferGetWidthOfPlane(pixelbuffer, 0);size_t height = CVPixelBufferGetHeightOfPlane(pixelbuffer, 0);CVMetalTextureRef texture = NULL;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelbuffer, NULL, MTLPixelFormatR8Unorm, width, height, 0, &texture);if (status == kCVReturnSuccess) {mTextureY = CVMetalTextureGetTexture(texture);CFRelease(texture);}}// textureUV{size_t width = CVPixelBufferGetWidthOfPlane(pixelbuffer, 1);size_t height = CVPixelBufferGetHeightOfPlane(pixelbuffer, 1);CVMetalTextureRef texture = NULL;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelbuffer, NULL, MTLPixelFormatRG8Unorm, width, height, 1, &texture);if (status == kCVReturnSuccess) {mTextureUV = CVMetalTextureGetTexture(texture);CFRelease(texture);}}size_t width = CVPixelBufferGetWidth(pixelbuffer);size_t heigth = CVPixelBufferGetHeight(pixelbuffer);CVMetalTextureRef temTexture = nil;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelbuffer, NULL, MTLPixelFormatBGRA8Unorm, width, heigth, 0, &temTexture);if (status == kCVReturnSuccess) {mMtkview.drawableSize = CGSizeMake(width, heigth);mTexture = CVMetalTextureGetTexture(temTexture);CFRelease(temTexture);}
}
yuv420转NV12
void YUV420PtoNV12(unsigned char *Src, unsigned char* Dst,int Width,int Height){unsigned char* SrcU = Src + Width * Height;unsigned char* SrcV = SrcU + Width * Height / 4 ;memcpy(Dst, Src, Width * Height);unsigned char* DstU = Dst + Width * Height;for(int i = 0 ; i < Width * Height / 4 ; i++ ){( *DstU++) = ( *SrcU++);( *DstU++) = ( *SrcV++);}
}
渲染NV12
- (void)renderYUV420P:(EVFrame *)frame {int w = frame.vsize.width;int h = frame.vsize.height;unsigned char *i420 = frame.data;unsigned char *buffer = malloc(w*h*10);YUV420PtoNV12(i420, buffer, w, h);NSDictionary *pixelAttributes = @{(NSString*)kCVPixelBufferIOSurfacePropertiesKey:@{}};CVPixelBufferRef pixelBuffer = NULL;CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault, w, h, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, (__bridge CFDictionaryRef)(pixelAttributes), &pixelBuffer);CVPixelBufferLockBaseAddress(pixelBuffer,0);void *yDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);unsigned char *y_ch0 = buffer;unsigned char *y_ch1 = buffer + w * h;memcpy(yDestPlane, y_ch0, w * h);void *uvDestPlane = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);// NV12memcpy(uvDestPlane, y_ch1, w * h * 0.5);CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);if (result != kCVReturnSuccess) {NSLog(@"Unable to create cvpixelbuffer %d", result);}{size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);size_t height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);CVMetalTextureRef texture = NULL;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelBuffer, NULL, MTLPixelFormatR8Unorm, width, height, 0, &texture);if (status == kCVReturnSuccess) {mTextureY = CVMetalTextureGetTexture(texture);CFRelease(texture);}}// textureUV{size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);size_t height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);CVMetalTextureRef texture = NULL;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelBuffer, NULL, MTLPixelFormatRG8Unorm, width, height, 1, &texture);if (status == kCVReturnSuccess) {mTextureUV = CVMetalTextureGetTexture(texture);CFRelease(texture);}}size_t width = CVPixelBufferGetWidth(pixelBuffer);size_t heigth = CVPixelBufferGetHeight(pixelBuffer);CVMetalTextureRef temTexture = nil;CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, mTextureCache, pixelBuffer, NULL, MTLPixelFormatBGRA8Unorm, width, heigth, 0, &temTexture);if (status == kCVReturnSuccess) {mMtkview.drawableSize = CGSizeMake(width, heigth);mTexture = CVMetalTextureGetTexture(temTexture);CFRelease(temTexture);}CVPixelBufferRelease(pixelBuffer);free(buffer);buffer = NULL;
}
END
metal确实比OpenGL简单好用很多
Mac OS 使用Metal渲染NV12、YUV420、CMSampleBufferRef视频相关推荐
- 让Unraid 也装上黑苹果MAC OS系统
Hi,大家好,我是热爱开源黑科技的郭大侠. 受到人生观.阿文菌等各位Unraid大神的恩惠,在疫情期间自己在家弄了一套Unraid,并做了直通,但是对于一个极客CTO来讲,虚拟机只弄个群晖和软路由岂不 ...
- Mac OS X 背后的故事(九)半导体的丰收(下)
文 / 王越 随着CPU与GPU合并成技术发展的趋势,苹果开发出了OpenCL框架,能够进行高速并行处理的能力使OpenCL成为了业界标准,被广泛应用. 最近几年,GPU的发展吸引了很多来自科学计算界 ...
- Mac OS X 背后的故事(八)半导体的丰收
原文地址: http://www.programmer.com.cn/10071/ 文/王越 在美国宾夕法尼亚州的东部,有一个风景秀美的城市叫费城.在这个城市诞生了一系列改变世界的奇迹:第一个三权分立 ...
- 图像渲染测试软件,检测你的电脑是否支持Metal渲染技术的小工具
本帖最后由 bizongyi 于 2015-6-20 20:09 编辑 在刚召开的苹果WWDC大会上,与全新操作系统OS X El Capitan一同亮相的还有原来iOS平台上的图形渲染技术Metal ...
- Mac os x 系统的发展史
·Mac OS 9:发布时间:1999年 于1999年发布的Mac OS 9操作系统(图片来自互联网) 在OS X之前,1999年发布的Mac OS 9看起来就是一个普通的桌面操作系统.并且现在已经被 ...
- 什么是mac os?它有哪些好的特点?有哪些应用小技巧
基本信息 Mac系统是苹果机专用系统,是基于Unix内核的图形化操作系统,一般情况下在普通pc上无法安装的操作系统. 苹果公司不但生产MAC的大部分硬件,连MAC所用的操作系统都是它自行开发的,接下来 ...
- mac 10.11 brew php71,MAC OS X 10.11.4下载-OS X 10.11正式版下载 V10.11.6-PC6苹果网
苹果WWDC 2015全球开发者大会在美国旧金山如期举行,苹果在本次大会上推出了全新的OS X 10.11系统,代号El Capitan,MAC OS X10.11系统并没有带来太多全新的技术和功能, ...
- 《MAC OS X 技术内幕》读书笔记第一章:MAC OS X的起源
<MAC OS X 技术内幕>读书笔记第一章:MAC OS X的起源 前言 1 System x.x系列 1.1System 1.0(1984年1月24日) 1.2System 2.x(1 ...
- 通向KDE4之路(三):完全的Mac OS X撑持
Troy Unrau 当然KDE的打算在Linux,FreeBSD以及其它UNIX/X11平台上均可乐成移植,但这并不透露表现它在其它平台上就没有冲破.奇趣公司在GPL协议之下颁布了面向Mac,Wi ...
最新文章
- SpringDataJpa根据多个id物品清单id查询房源编号
- loj #143. 质数判定
- oracle-关于时间的sql
- linux sh文件case,Shell脚本case语句简明教程
- centos ping不通局域网_新手小白初次安装虚拟机,网络不通怎么办,踩过的坑都告诉你...
- 北京 || Java 技术、生活、工作交流社区
- python判断安全密码_python 字符串实例:检查并判断密码字符串的安全强度
- day9 集合基础命令
- SmartDrv的前世今生——PrimoCache_2.2.0汉化
- 工业通讯 | Profinet协议基础知识(一)
- 软文广告的写作技巧分析!
- lunix上silk转mp3 和 mp3转silk
- SnnGrow快讯:Apple Books上线AI读书功能、有声书市场将迎来颠覆时刻、刚过7岁生日的OpenAI估值达到290亿美元、跻身全球独角兽排行榜前20、中国航天2023全年发射将再破60次
- NAND flash基本概念整理
- bat 格式化年月日时分秒
- win7 计算机不显示收藏夹,win7系统下收藏夹无法使用的原因及解决方法
- 关于github上一个关于lytro的代码
- cogs184搭建篱笆
- streamFile
- Android专项测试性能篇整理