2014 snapchat source code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
7.9 KiB

  1. //
  2. // SCMetalTextureResource.m
  3. // Snapchat
  4. //
  5. // Created by Brian Ng on 11/7/17.
  6. //
  7. #import "SCMetalTextureResource.h"
  8. #import "SCCameraSettingUtils.h"
  9. #import "SCCameraTweaks.h"
  10. #import "SCMetalUtils.h"
  11. @import CoreImage;
  12. #if !TARGET_IPHONE_SIMULATOR
  13. static NSInteger const kSCFocusRectSize = 4;
  14. #endif
  15. @interface SCMetalTextureResource ()
  16. #if !TARGET_IPHONE_SIMULATOR
  17. @property (nonatomic, readonly) CVMetalTextureCacheRef textureCache;
  18. #endif
  19. @end
  20. @implementation SCMetalTextureResource {
  21. RenderData _renderData;
  22. CVImageBufferRef _imageBuffer;
  23. CIContext *_context;
  24. }
  25. #if !TARGET_IPHONE_SIMULATOR
  26. @synthesize sourceYTexture = _sourceYTexture;
  27. @synthesize sourceUVTexture = _sourceUVTexture;
  28. @synthesize destinationYTexture = _destinationYTexture;
  29. @synthesize destinationUVTexture = _destinationUVTexture;
  30. @synthesize sourceBlurredYTexture = _sourceBlurredYTexture;
  31. @synthesize sourceDepthTexture = _sourceDepthTexture;
  32. @synthesize depthRange = _depthRange;
  33. @synthesize depthOffset = _depthOffset;
  34. @synthesize depthBlurForegroundThreshold = _depthBlurForegroundThreshold;
  35. @synthesize device = _device;
  36. @synthesize sampleBufferMetadata = _sampleBufferMetadata;
  37. - (instancetype)initWithRenderData:(RenderData)renderData
  38. textureCache:(CVMetalTextureCacheRef)textureCache
  39. device:(id<MTLDevice>)device
  40. {
  41. self = [super init];
  42. if (self) {
  43. _imageBuffer = CMSampleBufferGetImageBuffer(renderData.sampleBuffer);
  44. _renderData = renderData;
  45. _textureCache = textureCache;
  46. _device = device;
  47. _context = [CIContext contextWithOptions:@{ kCIContextWorkingFormat : @(kCIFormatRGBAh) }];
  48. }
  49. return self;
  50. }
  51. #endif
  52. #if !TARGET_IPHONE_SIMULATOR
  53. - (id<MTLTexture>)sourceYTexture
  54. {
  55. if (!_sourceYTexture) {
  56. CVPixelBufferLockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  57. _sourceYTexture = SCMetalTextureFromPixelBuffer(_imageBuffer, 0, MTLPixelFormatR8Unorm, _textureCache);
  58. CVPixelBufferUnlockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  59. }
  60. return _sourceYTexture;
  61. }
  62. - (id<MTLTexture>)sourceUVTexture
  63. {
  64. if (!_sourceUVTexture) {
  65. CVPixelBufferLockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  66. _sourceUVTexture = SCMetalTextureFromPixelBuffer(_imageBuffer, 1, MTLPixelFormatRG8Unorm, _textureCache);
  67. CVPixelBufferUnlockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  68. }
  69. return _sourceUVTexture;
  70. }
  71. - (id<MTLTexture>)destinationYTexture
  72. {
  73. if (!_destinationYTexture) {
  74. MTLTextureDescriptor *textureDescriptor =
  75. [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
  76. width:CVPixelBufferGetWidthOfPlane(_imageBuffer, 0)
  77. height:CVPixelBufferGetHeightOfPlane(_imageBuffer, 0)
  78. mipmapped:NO];
  79. textureDescriptor.usage |= MTLTextureUsageShaderWrite;
  80. _destinationYTexture = [_device newTextureWithDescriptor:textureDescriptor];
  81. }
  82. return _destinationYTexture;
  83. }
  84. - (id<MTLTexture>)destinationUVTexture
  85. {
  86. if (!_destinationUVTexture) {
  87. MTLTextureDescriptor *textureDescriptor =
  88. [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRG8Unorm
  89. width:CVPixelBufferGetWidthOfPlane(_imageBuffer, 1)
  90. height:CVPixelBufferGetHeightOfPlane(_imageBuffer, 1)
  91. mipmapped:NO];
  92. textureDescriptor.usage |= MTLTextureUsageShaderWrite;
  93. _destinationUVTexture = [_device newTextureWithDescriptor:textureDescriptor];
  94. }
  95. return _destinationUVTexture;
  96. }
  97. - (id<MTLTexture>)sourceBlurredYTexture
  98. {
  99. if (!_sourceBlurredYTexture) {
  100. MTLTextureDescriptor *textureDescriptor =
  101. [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR8Unorm
  102. width:CVPixelBufferGetWidthOfPlane(_imageBuffer, 0)
  103. height:CVPixelBufferGetHeightOfPlane(_imageBuffer, 0)
  104. mipmapped:NO];
  105. textureDescriptor.usage |= MTLTextureUsageShaderWrite;
  106. _sourceBlurredYTexture = [_device newTextureWithDescriptor:textureDescriptor];
  107. }
  108. return _sourceBlurredYTexture;
  109. }
  110. - (id<MTLTexture>)sourceDepthTexture
  111. {
  112. if (!_sourceDepthTexture) {
  113. CVPixelBufferLockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  114. _sourceDepthTexture =
  115. SCMetalTextureFromPixelBuffer(_renderData.depthDataMap, 0, MTLPixelFormatR16Float, _textureCache);
  116. CVPixelBufferUnlockBaseAddress(_imageBuffer, kCVPixelBufferLock_ReadOnly);
  117. }
  118. return _sourceDepthTexture;
  119. }
  120. - (float)depthRange
  121. {
  122. if (_depthRange == 0) {
  123. // Get min/max values of depth image to normalize
  124. size_t bufferWidth = CVPixelBufferGetWidth(_renderData.depthDataMap);
  125. size_t bufferHeight = CVPixelBufferGetHeight(_renderData.depthDataMap);
  126. size_t bufferBytesPerRow = CVPixelBufferGetBytesPerRow(_renderData.depthDataMap);
  127. CVPixelBufferLockBaseAddress(_renderData.depthDataMap, kCVPixelBufferLock_ReadOnly);
  128. unsigned char *pixelBufferPointer = CVPixelBufferGetBaseAddress(_renderData.depthDataMap);
  129. __fp16 *bufferPtr = (__fp16 *)pixelBufferPointer;
  130. uint32_t ptrInc = (int)bufferBytesPerRow / sizeof(__fp16);
  131. float depthMin = MAXFLOAT;
  132. float depthMax = -MAXFLOAT;
  133. for (int j = 0; j < bufferHeight; j++) {
  134. for (int i = 0; i < bufferWidth; i++) {
  135. float value = bufferPtr[i];
  136. if (!isnan(value)) {
  137. depthMax = MAX(depthMax, value);
  138. depthMin = MIN(depthMin, value);
  139. }
  140. }
  141. bufferPtr += ptrInc;
  142. }
  143. CVPixelBufferUnlockBaseAddress(_renderData.depthDataMap, kCVPixelBufferLock_ReadOnly);
  144. _depthRange = depthMax - depthMin;
  145. _depthOffset = depthMin;
  146. }
  147. return _depthRange;
  148. }
  149. - (float)depthOffset
  150. {
  151. if (_depthRange == 0) {
  152. [self depthRange];
  153. }
  154. return _depthOffset;
  155. }
  156. - (CGFloat)depthBlurForegroundThreshold
  157. {
  158. if (_renderData.depthBlurPointOfInterest) {
  159. CGPoint point = *_renderData.depthBlurPointOfInterest;
  160. CIImage *disparityImage = [CIImage imageWithCVPixelBuffer:_renderData.depthDataMap];
  161. CIVector *vector =
  162. [CIVector vectorWithX:point.x * CVPixelBufferGetWidth(_renderData.depthDataMap) - kSCFocusRectSize / 2
  163. Y:point.y * CVPixelBufferGetHeight(_renderData.depthDataMap) - kSCFocusRectSize / 2
  164. Z:kSCFocusRectSize
  165. W:kSCFocusRectSize];
  166. CIImage *minMaxImage =
  167. [[disparityImage imageByClampingToExtent] imageByApplyingFilter:@"CIAreaMinMaxRed"
  168. withInputParameters:@{kCIInputExtentKey : vector}];
  169. UInt8 pixel[4] = {0, 0, 0, 0};
  170. [_context render:minMaxImage
  171. toBitmap:&pixel
  172. rowBytes:4
  173. bounds:CGRectMake(0, 0, 1, 1)
  174. format:kCIFormatRGBA8
  175. colorSpace:nil];
  176. CGFloat disparity = pixel[1] / 255.0;
  177. CGFloat normalizedDisparity = (disparity - self.depthOffset) / self.depthRange;
  178. return normalizedDisparity;
  179. } else {
  180. return SCCameraTweaksDepthBlurForegroundThreshold();
  181. }
  182. }
  183. - (SampleBufferMetadata)sampleBufferMetadata
  184. {
  185. SampleBufferMetadata sampleMetadata = {
  186. .isoSpeedRating = 0, .exposureTime = 0.033, .brightness = 0,
  187. };
  188. retrieveSampleBufferMetadata(_renderData.sampleBuffer, &sampleMetadata);
  189. return sampleMetadata;
  190. }
  191. #endif
  192. @end