|
10 | 10 |
|
11 | 11 | #include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" |
12 | 12 | #include "third_party/skia/include/core/SkSurface.h" |
| 13 | +#include "third_party/skia/include/core/SkYUVAIndex.h" |
13 | 14 | #include "third_party/skia/include/gpu/GrBackendSurface.h" |
| 15 | +#include "third_party/skia/src/gpu/gl/GrGLDefines.h" |
14 | 16 |
|
15 | 17 | namespace flutter { |
16 | 18 |
|
|
41 | 43 | if (buffer_ref_ == nullptr) { |
42 | 44 | return; |
43 | 45 | } |
| 46 | + if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || |
| 47 | + pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| 48 | + CreateYUVTexturesFromPixelBuffer(); |
| 49 | + } else { |
| 50 | + CreateRGBATextureFromPixelBuffer(); |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +void IOSExternalTextureGL::CreateRGBATextureFromPixelBuffer() { |
44 | 55 | CVOpenGLESTextureRef texture; |
45 | 56 | CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage( |
46 | 57 | kCFAllocatorDefault, cache_ref_, buffer_ref_, nullptr, GL_TEXTURE_2D, GL_RGBA, |
|
54 | 65 | } |
55 | 66 | } |
56 | 67 |
|
| 68 | +void IOSExternalTextureGL::CreateYUVTexturesFromPixelBuffer() { |
| 69 | + size_t width = CVPixelBufferGetWidth(buffer_ref_); |
| 70 | + size_t height = CVPixelBufferGetHeight(buffer_ref_); |
| 71 | + { |
| 72 | + CVOpenGLESTextureRef yTexture; |
| 73 | + CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage( |
| 74 | + kCFAllocatorDefault, cache_ref_, buffer_ref_, nullptr, GL_TEXTURE_2D, GL_LUMINANCE, width, |
| 75 | + height, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0, &yTexture); |
| 76 | + if (err != noErr) { |
| 77 | + FML_DCHECK(yTexture) << "Could not create texture from pixel buffer: " << err; |
| 78 | + } else { |
| 79 | + y_texture_ref_.Reset(yTexture); |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + { |
| 84 | + CVOpenGLESTextureRef uvTexture; |
| 85 | + CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage( |
| 86 | + kCFAllocatorDefault, cache_ref_, buffer_ref_, nullptr, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, |
| 87 | + width / 2, height / 2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &uvTexture); |
| 88 | + if (err != noErr) { |
| 89 | + FML_DCHECK(uvTexture) << "Could not create texture from pixel buffer: " << err; |
| 90 | + } else { |
| 91 | + uv_texture_ref_.Reset(uvTexture); |
| 92 | + } |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +sk_sp<SkImage> IOSExternalTextureGL::CreateImageFromRGBATexture(GrContext* context, |
| 97 | + const SkRect& bounds) { |
| 98 | + GrGLTextureInfo textureInfo = {CVOpenGLESTextureGetTarget(texture_ref_), |
| 99 | + CVOpenGLESTextureGetName(texture_ref_), GL_RGBA8_OES}; |
| 100 | + GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, textureInfo); |
| 101 | + sk_sp<SkImage> image = |
| 102 | + SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin, |
| 103 | + kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); |
| 104 | + return image; |
| 105 | +} |
| 106 | + |
| 107 | +sk_sp<SkImage> IOSExternalTextureGL::CreateImageFromYUVTextures(GrContext* context, |
| 108 | + const SkRect& bounds) { |
| 109 | + GrGLTextureInfo yTextureInfo = {CVOpenGLESTextureGetTarget(y_texture_ref_), |
| 110 | + CVOpenGLESTextureGetName(y_texture_ref_), GR_GL_LUMINANCE8}; |
| 111 | + GrBackendTexture yBackendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, yTextureInfo); |
| 112 | + GrGLTextureInfo uvTextureInfo = {CVOpenGLESTextureGetTarget(uv_texture_ref_), |
| 113 | + CVOpenGLESTextureGetName(uv_texture_ref_), GR_GL_RGBA8}; |
| 114 | + GrBackendTexture uvBackendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, |
| 115 | + uvTextureInfo); |
| 116 | + GrBackendTexture nv12TextureHandles[] = {yBackendTexture, uvBackendTexture}; |
| 117 | + SkYUVAIndex yuvaIndices[4] = { |
| 118 | + SkYUVAIndex{0, SkColorChannel::kR}, // Read Y data from the red channel of the first texture |
| 119 | + SkYUVAIndex{1, SkColorChannel::kR}, // Read U data from the red channel of the second texture |
| 120 | + SkYUVAIndex{ |
| 121 | + 1, SkColorChannel::kA}, // Read V data from the alpha channel of the second texture, |
| 122 | + // normal NV12 data V should be taken from the green channel, but |
| 123 | + // currently only the uv texture created by GL_LUMINANCE_ALPHA |
| 124 | + // can be used, so the V value is taken from the alpha channel |
| 125 | + SkYUVAIndex{-1, SkColorChannel::kA}}; //-1 means to omit the alpha data of YUVA |
| 126 | + SkISize size{yBackendTexture.width(), yBackendTexture.height()}; |
| 127 | + sk_sp<SkImage> image = |
| 128 | + SkImage::MakeFromYUVATextures(context, kRec601_SkYUVColorSpace, nv12TextureHandles, |
| 129 | + yuvaIndices, size, kTopLeft_GrSurfaceOrigin, nullptr); |
| 130 | + return image; |
| 131 | +} |
| 132 | + |
| 133 | +bool IOSExternalTextureGL::IsTexturesAvailable() { |
| 134 | + return ((pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || |
| 135 | + pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) && |
| 136 | + (y_texture_ref_ && uv_texture_ref_)) || |
| 137 | + (pixelFormat == kCVPixelFormatType_32BGRA && texture_ref_); |
| 138 | +} |
| 139 | + |
57 | 140 | bool IOSExternalTextureGL::NeedUpdateTexture(bool freeze) { |
58 | 141 | // Update texture if `texture_ref_` is reset to `nullptr` when GrContext |
59 | 142 | // is destroyed or new frame is ready. |
60 | | - return (!freeze && new_frame_ready_) || !texture_ref_; |
| 143 | + return (!freeze && new_frame_ready_) || !IsTexturesAvailable(); |
61 | 144 | } |
62 | 145 |
|
63 | 146 | void IOSExternalTextureGL::Paint(SkCanvas& canvas, |
|
70 | 153 | auto pixelBuffer = [external_texture_.get() copyPixelBuffer]; |
71 | 154 | if (pixelBuffer) { |
72 | 155 | buffer_ref_.Reset(pixelBuffer); |
| 156 | + pixelFormat = CVPixelBufferGetPixelFormatType(buffer_ref_); |
73 | 157 | } |
74 | 158 | CreateTextureFromPixelBuffer(); |
75 | 159 | new_frame_ready_ = false; |
76 | 160 | } |
77 | | - if (!texture_ref_) { |
| 161 | + if (!IsTexturesAvailable()) { |
78 | 162 | return; |
79 | 163 | } |
80 | | - GrGLTextureInfo textureInfo = {CVOpenGLESTextureGetTarget(texture_ref_), |
81 | | - CVOpenGLESTextureGetName(texture_ref_), GL_RGBA8_OES}; |
82 | | - GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, textureInfo); |
83 | | - sk_sp<SkImage> image = |
84 | | - SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin, |
85 | | - kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); |
| 164 | + |
| 165 | + sk_sp<SkImage> image = nullptr; |
| 166 | + if (pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || |
| 167 | + pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) { |
| 168 | + image = CreateImageFromYUVTextures(context, bounds); |
| 169 | + } else { |
| 170 | + image = CreateImageFromRGBATexture(context, bounds); |
| 171 | + } |
| 172 | + |
86 | 173 | FML_DCHECK(image) << "Failed to create SkImage from Texture."; |
87 | 174 | if (image) { |
88 | 175 | SkPaint paint; |
|
0 commit comments