• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "pixel_map_from_surface.h"
17 
18 #include "image_log.h"
19 #include "sync_fence.h"
20 
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23 
24 #undef LOG_TAG
25 #define LOG_TAG "PixelMap"
26 
27 namespace OHOS {
28 namespace Media {
29 
PixelMapFromSurface()30 PixelMapFromSurface::PixelMapFromSurface()
31 {}
32 
~PixelMapFromSurface()33 PixelMapFromSurface::~PixelMapFromSurface() noexcept
34 {
35     Clear();
36 }
37 
Clear()38 void PixelMapFromSurface::Clear() noexcept
39 {
40     if (eglImage_ != EGL_NO_IMAGE_KHR) {
41         if (renderContext_ != nullptr) {
42             eglDestroyImageKHR(renderContext_->GetEGLDisplay(), eglImage_);
43         } else {
44             auto disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
45             eglDestroyImageKHR(disp, eglImage_);
46         }
47         eglImage_ = EGL_NO_IMAGE_KHR;
48     }
49 
50     if (texId_ != 0U) {
51         glDeleteTextures(1, &texId_);
52         texId_ = 0U;
53     }
54 
55     surfaceBuffer_ = nullptr;
56     if (nativeWindowBuffer_ != nullptr) {
57         DestroyNativeWindowBuffer(nativeWindowBuffer_);
58         nativeWindowBuffer_ = nullptr;
59     }
60 }
61 
GetNativeWindowBufferFromSurface(const sptr<Surface> & surface,const Rect & srcRect)62 bool PixelMapFromSurface::GetNativeWindowBufferFromSurface(const sptr<Surface> &surface, const Rect &srcRect)
63 {
64     // private func, surface is not nullptr.
65     sptr<SyncFence> fence;
66     // a 4 * 4 idetity matrix
67     float matrix[16] = {
68         1, 0, 0, 0,
69         0, 1, 0, 0,
70         0, 0, 1, 0,
71         0, 0, 0, 1
72     };
73     int ret = surface->GetLastFlushedBuffer(surfaceBuffer_, fence, matrix);
74     if (ret != OHOS::GSERROR_OK || surfaceBuffer_ == nullptr) {
75         Clear();
76         IMAGE_LOGE(
77             "CreatePixelMapFromSurface: GetLastFlushedBuffer from nativeWindow failed, err: %{public}d",
78             ret);
79         return false;
80     }
81 
82     int bufferWidth = surfaceBuffer_->GetWidth();
83     int bufferHeight = surfaceBuffer_->GetHeight();
84     if (srcRect.width > bufferWidth || srcRect.height > bufferHeight ||
85         srcRect.left >= bufferWidth || srcRect.top >= bufferHeight ||
86         srcRect.left + srcRect.width > bufferWidth || srcRect.top + srcRect.height > bufferHeight) {
87         IMAGE_LOGE(
88             "CreatePixelMapFromSurface: invalid argument: srcRect[%{public}d, %{public}d, %{public}d, %{public}d],"
89             "bufferSize:[%{public}d, %{public}d]",
90             srcRect.left, srcRect.top, srcRect.width, srcRect.height,
91             surfaceBuffer_->GetWidth(), surfaceBuffer_->GetHeight());
92         return false;
93     }
94 
95     if (fence != nullptr) {
96         fence->Wait(3000); // wait at most 3000ms
97     }
98     nativeWindowBuffer_ = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer_);
99     return nativeWindowBuffer_ != nullptr;
100 }
101 
CreateEGLImage()102 bool PixelMapFromSurface::CreateEGLImage()
103 {
104     EGLint attrs[] = {
105         EGL_IMAGE_PRESERVED,
106         EGL_TRUE,
107         EGL_NONE,
108     };
109     eglImage_ = eglCreateImageKHR(
110         renderContext_->GetEGLDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS,
111         nativeWindowBuffer_, attrs);
112     if (eglImage_ == EGL_NO_IMAGE_KHR) {
113         Clear();
114         IMAGE_LOGE("%{public}s create egl image fail %{public}d", __func__, eglGetError());
115         return false;
116     }
117     glGenTextures(1, &texId_);
118     glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId_);
119     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
120     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
121     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
122     glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
123     static auto glEGLImageTargetTexture2DOESFunc = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
124         eglGetProcAddress("glEGLImageTargetTexture2DOES"));
125     if (glEGLImageTargetTexture2DOESFunc == nullptr) {
126         Clear();
127         IMAGE_LOGE("%{public}s glEGLImageTargetTexture2DOES func not found: %{public}d",
128             __func__, eglGetError());
129         return false;
130     }
131     glEGLImageTargetTexture2DOESFunc(GL_TEXTURE_EXTERNAL_OES, static_cast<GLeglImageOES>(eglImage_));
132     return true;
133 }
134 
DrawImage(const Rect & srcRect)135 bool PixelMapFromSurface::DrawImage(const Rect &srcRect)
136 {
137     GraphicPixelFormat pixelFormat = static_cast<GraphicPixelFormat>(surfaceBuffer_->GetFormat());
138     SkColorType colorType = kRGBA_8888_SkColorType;
139     GLuint glType = GL_RGBA8;
140     int bufferWidth = surfaceBuffer_->GetWidth();
141     int bufferHeight = surfaceBuffer_->GetHeight();
142     if (pixelFormat == GRAPHIC_PIXEL_FMT_BGRA_8888) {
143         colorType = kBGRA_8888_SkColorType;
144     } else if (pixelFormat == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFormat == GRAPHIC_PIXEL_FMT_YCRCB_P010) {
145         colorType = kRGBA_1010102_SkColorType;
146         glType = GL_RGB10_A2;
147     }
148     GrGLTextureInfo grExternalTextureInfo = { GL_TEXTURE_EXTERNAL_OES, texId_, static_cast<GrGLenum>(glType) };
149     auto backendTexturePtr =
150         std::make_shared<GrBackendTexture>(bufferWidth, bufferHeight, GrMipMapped::kNo, grExternalTextureInfo);
151     auto image = SkImage::MakeFromTexture(renderContext_->GetGrContext().get(), *backendTexturePtr,
152         kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType, nullptr);
153     if (image == nullptr) {
154         Clear();
155         IMAGE_LOGE("%{public}s create SkImage failed.", __func__);
156         return false;
157     }
158 
159     auto imageInfo = SkImageInfo::Make(srcRect.width, srcRect.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
160     targetSurface_ = SkSurface::MakeRenderTarget(renderContext_->GetGrContext().get(), SkBudgeted::kYes,
161         imageInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
162     if (targetSurface_ == nullptr) {
163         Clear();
164         IMAGE_LOGE("%{public}s SkSurface::MakeRenderTarget failed.", __func__);
165         return false;
166     }
167 
168     SkCanvas* canvas = targetSurface_->getCanvas();
169     SkPaint paint;
170     paint.setStyle(SkPaint::kFill_Style);
171     SkSamplingOptions sampling(SkFilterMode::kNearest);
172     canvas->drawImageRect(image,
173         SkRect::MakeXYWH(srcRect.left, srcRect.top, srcRect.width, srcRect.height),
174         SkRect::MakeWH(srcRect.width, srcRect.height),
175         sampling, &paint, SkCanvas::kStrict_SrcRectConstraint);
176     canvas->flush();
177     return true;
178 }
179 
Create(uint64_t surfaceId,const Rect & srcRect)180 std::unique_ptr<PixelMap> PixelMapFromSurface::Create(uint64_t surfaceId, const Rect &srcRect)
181 {
182     if (srcRect.left < 0 || srcRect.top < 0 || srcRect.width <= 0 || srcRect.height <= 0) {
183         IMAGE_LOGE(
184             "CreatePixelMapFromSurface: invalid argument: srcRect[%{public}d, %{public}d, %{public}d, %{public}d]",
185             srcRect.left, srcRect.top, srcRect.width, srcRect.height);
186         return nullptr;
187     }
188 
189     Clear();
190     sptr<Surface> surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
191     if (surface == nullptr) {
192         IMAGE_LOGE(
193             "CreatePixelMapFromSurface: can't find surface for surfaceId: %{public}" PRIu64 ".", surfaceId);
194         return nullptr;
195     }
196 
197     if (!GetNativeWindowBufferFromSurface(surface, srcRect)) {
198         return nullptr;
199     }
200 
201     // init renderContext to do some format convertion if necessary.
202     renderContext_ = std::make_unique<RenderContext>();
203     if (!renderContext_->Init()) {
204         Clear();
205         IMAGE_LOGE("CreatePixelMapFromSurface: init renderContext failed.");
206         return nullptr;
207     }
208 
209     if (!CreateEGLImage()) {
210         return nullptr;
211     }
212 
213     if (!DrawImage(srcRect)) {
214         return nullptr;
215     }
216 
217     InitializationOptions options;
218     options.size.width = srcRect.width;
219     options.size.height = srcRect.height;
220     options.srcPixelFormat = PixelFormat::RGBA_8888;
221     options.pixelFormat = PixelFormat::RGBA_8888;
222     auto pixelMap = PixelMap::Create(options);
223     auto imageInfo = SkImageInfo::Make(srcRect.width, srcRect.height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
224     SkPixmap skPixmap(imageInfo, pixelMap->GetPixel(0, 0), pixelMap->GetRowBytes());
225     targetSurface_->readPixels(skPixmap, 0, 0);
226     return pixelMap;
227 }
228 
CreatePixelMapFromSurfaceId(uint64_t surfaceId,const Rect & srcRect)229 std::unique_ptr<PixelMap> CreatePixelMapFromSurfaceId(uint64_t surfaceId, const Rect &srcRect)
230 {
231     auto helper = std::make_unique<PixelMapFromSurface>();
232     return helper->Create(surfaceId, srcRect);
233 }
234 } // namespace Media
235 } // namespace OHOS
236