• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "basic_transformer.h"
17 #include <iostream>
18 #include <new>
19 #include <unistd.h>
20 #include "image_utils.h"
21 #include "pixel_convert.h"
22 #include "pixel_map.h"
23 #ifndef _WIN32
24 #include "securec.h"
25 #else
26 #include "memory.h"
27 #endif
28 
29 #if !defined(_WIN32) && !defined(_APPLE)
30 #include "ashmem.h"
31 #include <sys/mman.h>
32 #endif
33 
34 namespace OHOS {
35 namespace Media {
36 using namespace std;
ResetParam()37 void BasicTransformer::ResetParam()
38 {
39     matrix_ = Matrix();
40     minX_ = 0.0f;
41     minY_ = 0.0f;
42 }
43 
SetScaleParam(const float sx,const float sy)44 void BasicTransformer::SetScaleParam(const float sx, const float sy)
45 {
46     Matrix m;
47     m.SetScale(sx, sy);
48     matrix_.SetConcat(m);
49 }
50 
SetTranslateParam(const float tx,const float ty)51 void BasicTransformer::SetTranslateParam(const float tx, const float ty)
52 {
53     Matrix m;
54     m.SetTranslate(tx, ty);
55     matrix_.SetConcat(m);
56 }
57 
SetRotateParam(const float degrees,const float px,const float py)58 void BasicTransformer::SetRotateParam(const float degrees, const float px, const float py)
59 {
60     Matrix m;
61     m.SetRotate(degrees, px, py);
62     matrix_.SetConcat(m);
63 }
64 
GetDstDimension(const Size & srcSize,Size & dstSize)65 void BasicTransformer::GetDstDimension(const Size &srcSize, Size &dstSize)
66 {
67     Matrix::OperType operType = matrix_.GetOperType();
68     if ((static_cast<uint8_t>(operType) & Matrix::SCALE) == Matrix::SCALE) {
69         dstSize.width = static_cast<int32_t>(srcSize.width * matrix_.GetScaleX() + FHALF);
70         dstSize.height = static_cast<int32_t>(srcSize.height * matrix_.GetScaleY() + FHALF);
71     }
72 
73     if ((static_cast<uint8_t>(operType) & Matrix::ROTATEORSKEW) == Matrix::ROTATEORSKEW) {
74         Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType);
75         GetRotateDimension(fInvProc, srcSize, dstSize);
76     }
77 }
78 
CheckAllocateBuffer(PixmapInfo & outPixmap,AllocateMem allocate,int & fd,uint64_t & bufferSize,Size & dstSize)79 bool BasicTransformer::CheckAllocateBuffer(PixmapInfo &outPixmap, AllocateMem allocate,
80                                            int &fd, uint64_t &bufferSize, Size &dstSize)
81 {
82     if (bufferSize == 0 || bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
83         IMAGE_LOGE("[BasicTransformer]Invalid value of bufferSize");
84         return false;
85     }
86     if (allocate == nullptr) {
87         outPixmap.data = static_cast<uint8_t *>(malloc(bufferSize));
88     } else {
89         outPixmap.data = allocate(dstSize, bufferSize, fd);
90     }
91     if (outPixmap.data == nullptr) {
92         IMAGE_LOGE("[BasicTransformer]apply heap memory failed");
93         return false;
94     }
95     return true;
96 }
97 
ReleaseBuffer(AllocatorType allocatorType,int fd,int dataSize,uint8_t * buffer)98 void BasicTransformer::ReleaseBuffer(AllocatorType allocatorType, int fd, int dataSize, uint8_t *buffer)
99 {
100 #if !defined(_WIN32) && !defined(_APPLE)
101     if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
102         if (buffer != nullptr) {
103             ::munmap(buffer, dataSize);
104             ::close(fd);
105         }
106         return;
107     }
108 #endif
109 
110     if (allocatorType == AllocatorType::HEAP_ALLOC) {
111         if (buffer != nullptr) {
112             free(buffer);
113         }
114         return;
115     }
116 }
TransformPixmap(const PixmapInfo & inPixmap,PixmapInfo & outPixmap,AllocateMem allocate)117 uint32_t BasicTransformer::TransformPixmap(const PixmapInfo &inPixmap, PixmapInfo &outPixmap, AllocateMem allocate)
118 {
119     if (inPixmap.data == nullptr) {
120         IMAGE_LOGE("[BasicTransformer]input data is null.");
121         return ERR_IMAGE_GENERAL_ERROR;
122     }
123     int32_t pixelBytes = ImageUtils::GetPixelBytes(inPixmap.imageInfo.pixelFormat);
124     if (pixelBytes == 0) {
125         IMAGE_LOGE("[BasicTransformer]input pixel is invalid.");
126         return ERR_IMAGE_INVALID_PIXEL;
127     }
128 
129     Size dstSize = inPixmap.imageInfo.size;
130     GetDstDimension(inPixmap.imageInfo.size, dstSize);
131     outPixmap.imageInfo.size = dstSize;
132     if (dstSize.width <= 0 || dstSize.height <= 0) {
133         IMAGE_LOGE("[BasicTransformer]buffer size is invalid.");
134         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
135     }
136 
137     uint64_t bufferSize = static_cast<uint64_t>(dstSize.width) * dstSize.height * pixelBytes;
138     if (bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
139         IMAGE_LOGE("[BasicTransformer] buffer size:%{public}llu out of range.",
140                    static_cast<unsigned long long>(bufferSize));
141         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
142     }
143     int fd = 0;
144     if (CheckAllocateBuffer(outPixmap, allocate, fd, bufferSize, dstSize) != true) {
145         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
146     }
147     outPixmap.bufferSize = bufferSize;
148     outPixmap.imageInfo.pixelFormat = inPixmap.imageInfo.pixelFormat;
149     outPixmap.imageInfo.colorSpace = inPixmap.imageInfo.colorSpace;
150     outPixmap.imageInfo.alphaType = inPixmap.imageInfo.alphaType;
151     outPixmap.imageInfo.baseDensity = inPixmap.imageInfo.baseDensity;
152 
153 #ifdef _WIN32
154     memset(outPixmap.data, COLOR_DEFAULT, bufferSize * sizeof(uint8_t));
155 #else
156     if (memset_s(outPixmap.data, bufferSize * sizeof(uint8_t), COLOR_DEFAULT, bufferSize * sizeof(uint8_t)) != EOK) {
157         IMAGE_LOGE("[BasicTransformer]apply heap memory failed.");
158         ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC,
159             fd, bufferSize, outPixmap.data);
160         return ERR_IMAGE_GENERAL_ERROR;
161     }
162 #endif
163 
164     if (!DrawPixelmap(inPixmap, pixelBytes, dstSize, outPixmap.data)) {
165         IMAGE_LOGE("[BasicTransformer] the matrix can not invert.");
166         ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC,
167             fd, bufferSize, outPixmap.data);
168         return ERR_IMAGE_MATRIX_NOT_INVERT;
169     }
170     return IMAGE_SUCCESS;
171 }
172 
DrawPixelmap(const PixmapInfo & pixmapInfo,const int32_t pixelBytes,const Size & size,uint8_t * data)173 bool BasicTransformer::DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t pixelBytes, const Size &size,
174                                     uint8_t *data)
175 {
176     Matrix invertMatrix;
177     bool isInvert = matrix_.Invert(invertMatrix);
178     if (!isInvert) {
179         return false;
180     }
181 
182     uint32_t rb = pixmapInfo.imageInfo.size.width * pixelBytes;
183     Matrix::OperType operType = matrix_.GetOperType();
184     Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType);
185 
186     for (int32_t y = 0; y < size.height; ++y) {
187         for (int32_t x = 0; x < size.width; ++x) {
188             Point srcPoint;
189             // Center coordinate alignment, need to add 0.5, so the boundary can also be considered
190             fInvProc(invertMatrix, static_cast<float>(x) + minX_ + FHALF, static_cast<float>(y) + minY_ + FHALF,
191                      srcPoint);
192             if (CheckOutOfRange(srcPoint, pixmapInfo.imageInfo.size)) {
193                 continue;
194             }
195             uint32_t shiftBytes = (y * size.width + x) * pixelBytes;
196             BilinearProc(srcPoint, pixmapInfo, rb, shiftBytes, data);
197         }
198     }
199 
200     return true;
201 }
202 
GetRotateDimension(Matrix::CalcXYProc fInvProc,const Size & srcSize,Size & dstSize)203 void BasicTransformer::GetRotateDimension(Matrix::CalcXYProc fInvProc, const Size &srcSize, Size &dstSize)
204 {
205     Point dstP1;
206     Point dstP2;
207     Point dstP3;
208     Point dstP4;
209 
210     float fx = static_cast<float>(srcSize.width);
211     float fy = static_cast<float>(srcSize.height);
212     fInvProc(matrix_, 0.0f, 0.0f, dstP1);
213     fInvProc(matrix_, fx, 0.0f, dstP2);
214     fInvProc(matrix_, 0.0f, fy, dstP3);
215     fInvProc(matrix_, fx, fy, dstP4);
216 
217     // For rotation, the width and height will change, so you need to take the maximum of the two diagonals.
218     dstSize.width = static_cast<int32_t>(fmaxf(fabsf(dstP4.x - dstP1.x), fabsf(dstP3.x - dstP2.x)) + FHALF);
219     dstSize.height = static_cast<int32_t>(fmaxf(fabsf(dstP4.y - dstP1.y), fabsf(dstP3.y - dstP2.y)) + FHALF);
220 
221     float min14X = std::min(dstP1.x, dstP4.x);
222     float min23X = std::min(dstP2.x, dstP3.x);
223     minX_ = std::min(min14X, min23X);
224 
225     float min14Y = std::min(dstP1.y, dstP4.y);
226     float min23Y = std::min(dstP2.y, dstP3.y);
227     minY_ = std::min(min14Y, min23Y);
228 }
229 
BilinearProc(const Point & pt,const PixmapInfo & pixmapInfo,const uint32_t rb,const int32_t shiftBytes,uint8_t * data)230 void BasicTransformer::BilinearProc(const Point &pt, const PixmapInfo &pixmapInfo, const uint32_t rb,
231                                     const int32_t shiftBytes, uint8_t *data)
232 {
233     uint32_t srcX = (pt.x * MULTI_65536) - HALF_BASIC;
234     uint32_t srcY = (pt.y * MULTI_65536) - HALF_BASIC;
235 
236     AroundPos aroundPos;
237     aroundPos.x0 = RightShift16Bit(srcX, pixmapInfo.imageInfo.size.width - 1);
238     aroundPos.x1 = RightShift16Bit(srcX + BASIC, pixmapInfo.imageInfo.size.width - 1);
239     uint32_t subx = GetSubValue(srcX);
240 
241     aroundPos.y0 = RightShift16Bit(srcY, pixmapInfo.imageInfo.size.height - 1);
242     aroundPos.y1 = RightShift16Bit(srcY + BASIC, pixmapInfo.imageInfo.size.height - 1);
243     uint32_t suby = GetSubValue(srcY);
244 
245     AroundPixels aroundPixels;
246     switch (pixmapInfo.imageInfo.pixelFormat) {
247         case PixelFormat::RGBA_8888:
248         case PixelFormat::ARGB_8888:
249         case PixelFormat::BGRA_8888:
250             GetAroundPixelRGBA(aroundPos, pixmapInfo.data, rb, aroundPixels);
251             break;
252         case PixelFormat::RGB_565:
253             GetAroundPixelRGB565(aroundPos, pixmapInfo.data, rb, aroundPixels);
254             break;
255         case PixelFormat::RGB_888:
256             GetAroundPixelRGB888(aroundPos, pixmapInfo.data, rb, aroundPixels);
257             break;
258         case PixelFormat::ALPHA_8:
259             GetAroundPixelALPHA8(aroundPos, pixmapInfo.data, rb, aroundPixels);
260             break;
261         default:
262             IMAGE_LOGE("[BasicTransformer] pixel format not supported, format:%d", pixmapInfo.imageInfo.pixelFormat);
263             return;
264     }
265 
266     uint32_t *tmp = reinterpret_cast<uint32_t *>(data + shiftBytes);
267     *tmp = FilterProc(subx, suby, aroundPixels);
268 }
269 
GetAroundPixelRGB565(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)270 void BasicTransformer::GetAroundPixelRGB565(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
271                                             AroundPixels &aroundPixels)
272 {
273     const uint16_t *row0 = reinterpret_cast<uint16_t *>(data + aroundPos.y0 * rb);
274     const uint16_t *row1 = reinterpret_cast<uint16_t *>(data + aroundPos.y1 * rb);
275     aroundPixels.color00 = row0[aroundPos.x0];
276     aroundPixels.color01 = row0[aroundPos.x1];
277     aroundPixels.color10 = row1[aroundPos.x0];
278     aroundPixels.color11 = row1[aroundPos.x1];
279 }
280 
GetAroundPixelRGB888(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)281 void BasicTransformer::GetAroundPixelRGB888(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
282                                             AroundPixels &aroundPixels)
283 {
284     const uint8_t *row0 = data + aroundPos.y0 * rb;
285     const uint8_t *row1 = data + aroundPos.y1 * rb;
286     uint32_t current0 = aroundPos.x0 * RGB888_BYTE;
287     uint32_t current1 = aroundPos.x1 * RGB888_BYTE;
288     // The RGB888 format occupies 3 bytes, and an int integer is formed by OR operation.
289     aroundPixels.color00 =
290         (row0[current0] << SHIFT_16_BIT) | (row0[current0 + 1] << SHIFT_8_BIT) | (row0[current0 + 2]);
291     aroundPixels.color01 =
292         (row0[current1] << SHIFT_16_BIT) | (row0[current1 + 1] << SHIFT_8_BIT) | (row0[current1 + 2]);
293     aroundPixels.color10 =
294         (row1[current0] << SHIFT_16_BIT) | (row1[current0 + 1] << SHIFT_8_BIT) | (row1[current0 + 2]);
295     aroundPixels.color11 =
296         (row1[current1] << SHIFT_16_BIT) | (row1[current1 + 1] << SHIFT_8_BIT) | (row1[current1 + 2]);
297 }
298 
GetAroundPixelRGBA(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)299 void BasicTransformer::GetAroundPixelRGBA(const AroundPos aroundPos, uint8_t *data,
300                                           uint32_t rb, AroundPixels &aroundPixels)
301 {
302     const uint32_t *row0 = reinterpret_cast<uint32_t *>(data + aroundPos.y0 * rb);
303     const uint32_t *row1 = reinterpret_cast<uint32_t *>(data + aroundPos.y1 * rb);
304     aroundPixels.color00 = row0[aroundPos.x0];
305     aroundPixels.color01 = row0[aroundPos.x1];
306     aroundPixels.color10 = row1[aroundPos.x0];
307     aroundPixels.color11 = row1[aroundPos.x1];
308 }
309 
GetAroundPixelALPHA8(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)310 void BasicTransformer::GetAroundPixelALPHA8(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
311                                             AroundPixels &aroundPixels)
312 {
313     const uint8_t *row0 = data + aroundPos.y0 * rb;
314     const uint8_t *row1 = data + aroundPos.y1 * rb;
315     aroundPixels.color00 = row0[aroundPos.x0];
316     aroundPixels.color01 = row0[aroundPos.x1];
317     aroundPixels.color10 = row1[aroundPos.x0];
318     aroundPixels.color11 = row1[aroundPos.x1];
319 }
320 
RightShift16Bit(uint32_t num,int32_t maxNum)321 uint32_t BasicTransformer::RightShift16Bit(uint32_t num, int32_t maxNum)
322 {
323     /*
324      * When the original image coordinates are obtained,
325      * the first 16 bits are shifted to the left, so the right shift is 16 bits here.
326      */
327     return ClampMax(num >> 16, maxNum);
328 }
329 
FilterProc(const uint32_t subx,const uint32_t suby,const AroundPixels & aroundPixels)330 uint32_t BasicTransformer::FilterProc(const uint32_t subx, const uint32_t suby, const AroundPixels &aroundPixels)
331 {
332     int32_t xy = subx * suby;
333     // Mask 0xFF00FF ensures that high and low 16 bits can be calculated simultaneously
334     const uint32_t mask = 0xFF00FF;
335 
336     /* All values are first magnified 16 times (left shift 4bit) and then divide 256 (right shift 8bit).
337      * Reference formula f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1),
338      * The subx is u, the suby is y,
339      * color00 is f(i,j), color 01 is f(i,j+1), color 10 is f(i+1,j), color11 is f(i+1,j+1).
340      */
341     int32_t scale = 256 - 16 * suby - 16 * subx + xy;
342     uint32_t lo = (aroundPixels.color00 & mask) * scale;
343     uint32_t hi = ((aroundPixels.color00 >> 8) & mask) * scale;
344 
345     scale = 16 * subx - xy;
346     lo += (aroundPixels.color01 & mask) * scale;
347     hi += ((aroundPixels.color01 >> 8) & mask) * scale;
348 
349     scale = 16 * suby - xy;
350     lo += (aroundPixels.color10 & mask) * scale;
351     hi += ((aroundPixels.color10 >> 8) & mask) * scale;
352 
353     lo += (aroundPixels.color11 & mask) * xy;
354     hi += ((aroundPixels.color11 >> 8) & mask) * xy;
355 
356     return ((lo >> 8) & mask) | (hi & ~mask);
357 }
358 } // namespace Media
359 } // namespace OHOS