Flutter macOS Embedder
FlutterExternalTexture.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include "flutter/fml/platform/darwin/cf_utils.h"
8 
9 @implementation FlutterExternalTexture {
10  FlutterDarwinContextMetalSkia* _darwinMetalContext;
11 
12  int64_t _textureID;
13 
14  id<FlutterTexture> _texture;
15 
16  std::vector<FlutterMetalTextureHandle> _textures;
17 }
18 
19 - (instancetype)initWithFlutterTexture:(id<FlutterTexture>)texture
20  darwinMetalContext:(FlutterDarwinContextMetalSkia*)context {
21  self = [super init];
22  if (self) {
23  _texture = texture;
24  _textureID = reinterpret_cast<int64_t>(_texture);
25  _darwinMetalContext = context;
26  }
27  return self;
28 }
29 
30 - (int64_t)textureID {
31  return _textureID;
32 }
33 
34 - (BOOL)populateTexture:(FlutterMetalExternalTexture*)textureOut {
35  // Copy the pixel buffer from the FlutterTexture instance implemented on the user side.
36  fml::CFRef<CVPixelBufferRef> pixelBuffer([_texture copyPixelBuffer]);
37 
38  if (!pixelBuffer) {
39  return NO;
40  }
41 
42  OSType pixel_format = CVPixelBufferGetPixelFormatType(pixelBuffer);
43  if (pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
44  pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
45  return [self populateTextureFromYUVAPixelBuffer:pixelBuffer textureOut:textureOut];
46  } else if (pixel_format == kCVPixelFormatType_32BGRA) {
47  return [self populateTextureFromRGBAPixelBuffer:pixelBuffer textureOut:textureOut];
48  } else {
49  NSLog(@"Unsupported pixel format: %d", pixel_format);
50  return NO;
51  }
52 }
53 
54 - (BOOL)populateTextureFromYUVAPixelBuffer:(nonnull CVPixelBufferRef)pixelBuffer
55  textureOut:(nonnull FlutterMetalExternalTexture*)textureOut {
56  CVMetalTextureRef yCVMetalTexture = nullptr;
57  CVMetalTextureRef uvCVMetalTextureRef = nullptr;
58  SkISize textureSize =
59  SkISize::Make(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));
60 
61  CVReturn yCVReturn = CVMetalTextureCacheCreateTextureFromImage(
62  /*allocator=*/kCFAllocatorDefault,
63  /*textureCache=*/_darwinMetalContext.textureCache,
64  /*sourceImage=*/pixelBuffer,
65  /*textureAttributes=*/nullptr,
66  /*pixelFormat=*/MTLPixelFormatR8Unorm,
67  /*width=*/CVPixelBufferGetWidthOfPlane(pixelBuffer, 0u),
68  /*height=*/CVPixelBufferGetHeightOfPlane(pixelBuffer, 0u),
69  /*planeIndex=*/0u,
70  /*texture=*/&yCVMetalTexture);
71 
72  if (yCVReturn != kCVReturnSuccess) {
73  NSLog(@"Could not create Metal texture from pixel buffer: CVReturn %d", yCVReturn);
74  return NO;
75  }
76 
77  CVReturn uvCVReturn = CVMetalTextureCacheCreateTextureFromImage(
78  /*allocator=*/kCFAllocatorDefault,
79  /*textureCache=*/_darwinMetalContext.textureCache,
80  /*sourceImage=*/pixelBuffer,
81  /*textureAttributes=*/nullptr,
82  /*pixelFormat=*/MTLPixelFormatRG8Unorm,
83  /*width=*/CVPixelBufferGetWidthOfPlane(pixelBuffer, 1u),
84  /*height=*/CVPixelBufferGetHeightOfPlane(pixelBuffer, 1u),
85  /*planeIndex=*/1u,
86  /*texture=*/&uvCVMetalTextureRef);
87 
88  if (uvCVReturn != kCVReturnSuccess) {
89  CVBufferRelease(yCVMetalTexture);
90  NSLog(@"Could not create Metal texture from pixel buffer: CVReturn %d", uvCVReturn);
91  return NO;
92  }
93 
94  _textures = {(__bridge FlutterMetalTextureHandle)CVMetalTextureGetTexture(yCVMetalTexture),
95  (__bridge FlutterMetalTextureHandle)CVMetalTextureGetTexture(uvCVMetalTextureRef)};
96  CVBufferRelease(yCVMetalTexture);
97  CVBufferRelease(uvCVMetalTextureRef);
98 
99  textureOut->num_textures = 2;
100  textureOut->height = textureSize.height();
101  textureOut->width = textureSize.width();
102  textureOut->pixel_format = FlutterMetalExternalTexturePixelFormat::kYUVA;
103  textureOut->textures = _textures.data();
104  OSType pixel_format = CVPixelBufferGetPixelFormatType(pixelBuffer);
105  textureOut->yuv_color_space = pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
106  ? FlutterMetalExternalTextureYUVColorSpace::kBT601LimitedRange
107  : FlutterMetalExternalTextureYUVColorSpace::kBT601FullRange;
108 
109  return YES;
110 }
111 
112 - (BOOL)populateTextureFromRGBAPixelBuffer:(nonnull CVPixelBufferRef)pixelBuffer
113  textureOut:(nonnull FlutterMetalExternalTexture*)textureOut {
114  SkISize textureSize =
115  SkISize::Make(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));
116 
117  CVMetalTextureRef cvMetalTexture = nullptr;
118  CVReturn cvReturn =
119  CVMetalTextureCacheCreateTextureFromImage(/*allocator=*/kCFAllocatorDefault,
120  /*textureCache=*/_darwinMetalContext.textureCache,
121  /*sourceImage=*/pixelBuffer,
122  /*textureAttributes=*/nullptr,
123  /*pixelFormat=*/MTLPixelFormatBGRA8Unorm,
124  /*width=*/textureSize.width(),
125  /*height=*/textureSize.height(),
126  /*planeIndex=*/0u,
127  /*texture=*/&cvMetalTexture);
128 
129  if (cvReturn != kCVReturnSuccess) {
130  NSLog(@"Could not create Metal texture from pixel buffer: CVReturn %d", cvReturn);
131  return NO;
132  }
133 
134  _textures = {(__bridge FlutterMetalTextureHandle)CVMetalTextureGetTexture(cvMetalTexture)};
135  CVBufferRelease(cvMetalTexture);
136 
137  textureOut->num_textures = 1;
138  textureOut->height = textureSize.height();
139  textureOut->width = textureSize.width();
140  textureOut->pixel_format = FlutterMetalExternalTexturePixelFormat::kRGBA;
141  textureOut->textures = _textures.data();
142 
143  return YES;
144 }
145 
146 @end
_textureID
int64_t _textureID
Definition: FlutterExternalTexture.mm:9
FlutterExternalTexture.h
FlutterExternalTexture
Definition: FlutterExternalTexture.h:18
_textures
std::vector< FlutterMetalTextureHandle > _textures
Definition: FlutterExternalTexture.mm:16
_texture
id< FlutterTexture > _texture
Definition: FlutterExternalTexture.mm:14
FlutterTexture-p
Definition: FlutterTexture.h:21