@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; ._cmsamplebufferref">
当前位置:   article > 正文

常用知识之CMSampleBufferRef系

cmsamplebufferref
  1. //
  2. // ViewController.m
  3. // Demo
  4. //
  5. // Created by on 2021/9/28.
  6. //
  7. #import "ViewController.h"
  8. #import <CoreMedia/CoreMedia.h>
  9. @interface ViewController ()
  10. @end
  11. @implementation ViewController
  12. - (void)viewDidLoad {
  13. [super viewDidLoad];
  14. // Do any additional setup after loading the view.
  15. /**
  16. CMSampleBufferRef的数据结构是一个包含0个或多个解码后(未解码)特定
  17. 媒体类型的样本(音频、视频、多路复用等);
  18. A reference to a CMSampleBuffer, a CF object containing
  19. zero or more compressed (or uncompressed) samples of a
  20. particular media type (audio, video, muxed, etc).
  21. CMSampleBufferRef的使用场景:
  22. 比如:摄像头、麦克风采集的音视频数据
  23. - (void)captureOutput:(AVCaptureOutput *)output
  24. didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
  25. fromConnection:(AVCaptureConnection *)connection;
  26. 比如:屏幕共享ReplayKit,音视频流输出
  27. - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer
  28. withType:(RPSampleBufferType)sampleBufferType
  29. 比如:读取视频文件的输出流AVAssetWriterInput
  30. - (nullable CMSampleBufferRef)copyNextSampleBuffer
  31. CF_RETURNS_RETAINED;
  32. 比如:ARKit ARSessionObserver输出捕获的audioSampleBuffer
  33. - (void)session:(ARSession *)session
  34. didOutputAudioSampleBuffer:(CMSampleBufferRef)audioSampleBuffer;
  35. 最近开发的WebRTC音视频的项目,就涉及到此类数据的处理和使用。
  36. 下面有两个常用的数据转换,仅供参考:
  37. CMSampleBufferRef转换为UIImage;
  38. CMSampleBufferRef转换为NSData;
  39. //获取一个Core Video图像缓存对象
  40. //CVImageBufferRef:Base type for all CoreVideo image buffers
  41. CVImageBufferRef imgBuffer = CMSampleBufferGetImageBuffer(buffer);
  42. CVPixelBufferRef:Based on the image buffer type. The pixel
  43. buffer implements the memory storage for an image buffer.
  44. CVPixelBufferRef是以CVImageBufferRef为基础的类型。这是一种像素图片
  45. 类型,属于Core Video模块.
  46. CVPixelBufferRef是一个C对象,不是OC对象,也不是一个类。
  47. CVPixelBufferRef是用CVBufferRef typedef 定义出来的,
  48. 而CVBufferRef本质上就是一个void *,所以从下面的方法中可以看到这一点。
  49. 因为CVPixelBufferRef属于C对象,所以定义了很多C函数,比如:
  50. CVPixelBufferRelease()
  51. CVPixelBufferCreate()
  52. CVPixelBufferLockBaseAddress()
  53. CVPixelBufferUnlockBaseAddress()
  54. CVPixelBufferGetWidth()
  55. CVPixelBufferGetHeight()
  56. 等等。
  57. 由于是C对象,它是不受ARC管理的,所以需要手动管理引用计数,控制对象的
  58. 生命周期,可以用CVPixelBufferRetain,CVPixelBufferRelease函数
  59. 用来加减引用计数,其实和CFRetain和CFRelease是等效的,所以可以用 CFGetRetainCount来查看当前引用计数。
  60. CVPixelBufferRef是iOS视频采集处理编码流程的重要中间数据媒介和纽带,
  61. 理解CVPixelBufferRef有助于写出高性能可靠的视频处理。
  62. 其实可以下载一个集美颜、滤镜、水印等功能的GPUImage源码看看,里面有很多
  63. 关于CMSampleBufferRef、CVImageBufferRef、CVPixelBufferRef的
  64. 处理,有助于更好的了解和使用。
  65. 最近的项目中,需要适配手机屏幕共享时的视频方向,即获取视频帧方向,
  66. 所以使用以下方法:
  67. CGImagePropertyOrientation oritation = (CGImagePropertyOrientation)((__bridge NSNumber *)CMGetAttachment(sampleBuffer, (__bridge CFStringRef)RPVideoSampleOrientationKey, NULL)).unsignedIntValue;
  68. 方向枚举:
  69. typedef CF_CLOSED_ENUM(uint32_t, CGImagePropertyOrientation) {
  70. // 0th row at top, 0th column on left - default orientation
  71. kCGImagePropertyOrientationUp = 1,
  72. // 0th row at top, 0th column on right - horizontal flip
  73. kCGImagePropertyOrientationUpMirrored,
  74. // 0th row at bottom, 0th column on right - 180 deg rotation
  75. kCGImagePropertyOrientationDown,
  76. // 0th row at bottom, 0th column on left - vertical flip
  77. kCGImagePropertyOrientationDownMirrored,
  78. // 0th row on left, 0th column at top
  79. kCGImagePropertyOrientationLeftMirrored,
  80. // 0th row on right, 0th column at top - 90 deg CW
  81. kCGImagePropertyOrientationRight,
  82. // 0th row on right, 0th column on bottom
  83. kCGImagePropertyOrientationRightMirrored,
  84. // 0th row on left, 0th column at bottom - 90 deg CCW
  85. kCGImagePropertyOrientationLeft
  86. };
  87. */
  88. }
  89. #pragma mark - CMSampleBufferRef转换为UIImage
  90. -(UIImage *)bufferToImage:(CMSampleBufferRef)buffer{
  91. //获取一个Core Video图像缓存对象
  92. //CVImageBufferRef:Base type for all CoreVideo image buffers
  93. CVImageBufferRef imgBuffer = CMSampleBufferGetImageBuffer(buffer);
  94. //锁定基地址
  95. //参数一:CVPixelBufferRef
  96. /**
  97. CVPixelBufferRef:Based on the image buffer type. The pixel
  98. buffer implements the memory storage for an image buffer.
  99. CVPixelBufferRef是以CVImageBufferRef为基础的类型
  100. */
  101. //参数二:CVPixelBufferLockFlags
  102. /**
  103. If you are not going to modify the data while you hold the
  104. lock, you should set this flag to avoid potentially
  105. invalidating any existing caches of the buffer contents.
  106. This flag should be passed both to the lock and unlock
  107. functions. Non-symmetrical usage of this flag will result in
  108. undefined behavior.
  109. 如果在持有锁时不打算修改数据,则应设置此标志以避免可能使缓冲区内容的任何现有缓存失效。此标志应同时传递给锁定和解锁功能。非对称使用此标志将导致未定义的行为。
  110. */
  111. CVReturn result = CVPixelBufferLockBaseAddress(imgBuffer, 0);
  112. NSLog(@"success or error result:%d", result);
  113. //获得基地址
  114. void *baseAddr = CVPixelBufferGetBaseAddress(imgBuffer);
  115. //获得行字节数
  116. size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imgBuffer);
  117. //获得宽、高
  118. size_t width = CVPixelBufferGetWidth(imgBuffer);
  119. size_t height = CVPixelBufferGetHeight(imgBuffer);
  120. NSLog(@"width:%zu, height:%zu", width, height);
  121. //创建RGB颜色空间
  122. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  123. //创建一个图形上下文
  124. CGContextRef context = CGBitmapContextCreate(baseAddr, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
  125. //根据上下文创建CGImage
  126. CGImageRef cgImg = CGBitmapContextCreateImage(context);
  127. //处理完成后,解锁(加锁、解锁要配套使用)
  128. CVPixelBufferUnlockBaseAddress(imgBuffer, 0);
  129. //这些资源不会自动释放,需要手动释放
  130. CGContextRelease(context);
  131. CGColorSpaceRelease(colorSpace);
  132. //创建UIImage
  133. //UIImage *img = [UIImage imageWithCGImage:cgImg];
  134. UIImage *img = [UIImage imageWithCGImage:cgImg scale:1.0f orientation:UIImageOrientationUp];
  135. //释放
  136. CGImageRelease(cgImg);
  137. return img;
  138. }
  139. #pragma mark - CMSampleBufferRef转换为NSData
  140. -(NSData *)bufferToData:(CMSampleBufferRef)buffer{
  141. CVImageBufferRef imgBuffer = CMSampleBufferGetImageBuffer(buffer);
  142. CVPixelBufferLockBaseAddress(imgBuffer, 0);
  143. size_t bytePerRow = CVPixelBufferGetBytesPerRow(imgBuffer);
  144. size_t height = CVPixelBufferGetHeight(imgBuffer);
  145. void *baseAddr = CVPixelBufferGetBaseAddress(imgBuffer);
  146. NSData *data = [NSData dataWithBytes:baseAddr length:bytePerRow * height];
  147. CVPixelBufferUnlockBaseAddress(imgBuffer, 0);
  148. return data;
  149. }
  150. @end

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号