Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c330ca8

Browse files
authored
[darwin] Update pixel format handling in FlutterTexture (#52326)
CVPixelBuffers from the application can have arbitrary pixel formats. However, current implementation doesn't support all pixel formats. To address this, add a comment to the FlutterTexture class to clarify which pixel formats are supported. Also, reject unsupported pixel formats so that the application can handle them properly. Fixes [#147242](flutter/flutter#147242). [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent d3fd919 commit c330ca8

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

shell/platform/darwin/common/framework/Headers/FlutterTexture.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ FLUTTER_DARWIN_EXPORT
1919
* See also: https://github.com/flutter/plugins/tree/master/packages/camera
2020
*/
2121
@protocol FlutterTexture <NSObject>
22-
/** Copy the contents of the texture into a `CVPixelBuffer`. */
22+
/**
23+
* Copy the contents of the texture into a `CVPixelBuffer`.
24+
*
25+
* The type of the pixel buffer is one of the following:
26+
* - `kCVPixelFormatType_32BGRA`
27+
* - `kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange`
28+
* - `kCVPixelFormatType_420YpCbCr8BiPlanarFullRange`
29+
*/
2330
- (CVPixelBufferRef _Nullable)copyPixelBuffer;
2431

2532
/**

shell/platform/darwin/graphics/FlutterDarwinExternalTextureMetal.mm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ - (void)onTextureUnregistered {
133133
if (_pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
134134
_pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
135135
image = [self wrapNV12ExternalPixelBuffer:pixelBuffer context:context];
136+
} else if (_pixelFormat == kCVPixelFormatType_32BGRA) {
137+
image = [self wrapBGRAExternalPixelBuffer:pixelBuffer context:context];
136138
} else {
137-
image = [self wrapRGBAExternalPixelBuffer:pixelBuffer context:context];
139+
FML_LOG(ERROR) << "Unsupported pixel format: " << _pixelFormat;
140+
return nullptr;
138141
}
139142

140143
if (!image) {
@@ -235,7 +238,7 @@ - (void)onTextureUnregistered {
235238
return flutter::DlImage::Make(skImage);
236239
}
237240

238-
- (sk_sp<flutter::DlImage>)wrapRGBAExternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
241+
- (sk_sp<flutter::DlImage>)wrapBGRAExternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
239242
context:(flutter::Texture::PaintContext&)context {
240243
SkISize textureSize =
241244
SkISize::Make(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));

shell/platform/darwin/macos/framework/Source/FlutterEmbedderExternalTextureTest.mm

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,4 +288,50 @@ - (CVPixelBufferRef)pixelBuffer {
288288
gpuSurface->makeImageSnapshot();
289289
}
290290

291+
TEST_F(FlutterEmbedderExternalTextureTest, TestPopulateUnsupportedExternalTexture) {
292+
// Constants.
293+
const size_t width = 100;
294+
const size_t height = 100;
295+
const int64_t texture_id = 1;
296+
297+
// Set up the surface.
298+
FlutterDarwinContextMetalSkia* darwinContextMetal =
299+
[[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice];
300+
SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
301+
GrDirectContext* grContext = darwinContextMetal.mainContext.get();
302+
sk_sp<SkSurface> gpuSurface(SkSurfaces::RenderTarget(grContext, skgpu::Budgeted::kNo, info));
303+
304+
// Create a texture.
305+
TestExternalTexture* testExternalTexture =
306+
[[TestExternalTexture alloc] initWidth:width
307+
height:height
308+
pixelFormatType:kCVPixelFormatType_420YpCbCr8PlanarFullRange];
309+
FlutterExternalTexture* textureHolder =
310+
[[FlutterExternalTexture alloc] initWithFlutterTexture:testExternalTexture
311+
darwinMetalContext:darwinContextMetal];
312+
313+
// Callback to resolve the texture.
314+
EmbedderExternalTextureMetal::ExternalTextureCallback callback = [&](int64_t texture_id, size_t w,
315+
size_t h) {
316+
EXPECT_TRUE(w == width);
317+
EXPECT_TRUE(h == height);
318+
319+
auto texture = std::make_unique<FlutterMetalExternalTexture>();
320+
EXPECT_FALSE([textureHolder populateTexture:texture.get()]);
321+
return nullptr;
322+
};
323+
324+
// Render the texture.
325+
std::unique_ptr<flutter::Texture> texture =
326+
std::make_unique<EmbedderExternalTextureMetal>(texture_id, callback);
327+
SkRect bounds = SkRect::MakeWH(info.width(), info.height());
328+
DlImageSampling sampling = DlImageSampling::kNearestNeighbor;
329+
DlSkCanvasAdapter canvas(gpuSurface->getCanvas());
330+
flutter::Texture::PaintContext context{
331+
.canvas = &canvas,
332+
.gr_context = grContext,
333+
};
334+
texture->Paint(context, bounds, /*freeze=*/false, sampling);
335+
}
336+
291337
} // namespace flutter::testing

shell/platform/darwin/macos/framework/Source/FlutterExternalTexture.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ - (BOOL)populateTexture:(FlutterMetalExternalTexture*)textureOut {
4343
if (pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
4444
pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
4545
return [self populateTextureFromYUVAPixelBuffer:pixelBuffer textureOut:textureOut];
46-
} else {
46+
} else if (pixel_format == kCVPixelFormatType_32BGRA) {
4747
return [self populateTextureFromRGBAPixelBuffer:pixelBuffer textureOut:textureOut];
48+
} else {
49+
NSLog(@"Unsupported pixel format: %d", pixel_format);
50+
return NO;
4851
}
4952
}
5053

0 commit comments

Comments
 (0)