1 /*
2 * Copyright (C) 2022 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 <cinttypes>
17 #include "image_log.h"
18 #include "media_errors.h"
19 #include "native_image.h"
20
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23
24 #undef LOG_TAG
25 #define LOG_TAG "NativeImage"
26
27 namespace {
28 constexpr int32_t NUMI_0 = 0;
29 constexpr uint32_t NUM_0 = 0;
30 constexpr uint32_t NUM_1 = 1;
31 constexpr uint32_t NUM_2 = 2;
32 const std::string DATA_SIZE_TAG = "dataSize";
33 }
34
35 namespace OHOS {
36 namespace Media {
NativeImage(sptr<SurfaceBuffer> buffer,std::shared_ptr<IBufferProcessor> releaser)37 NativeImage::NativeImage(sptr<SurfaceBuffer> buffer,
38 std::shared_ptr<IBufferProcessor> releaser) : buffer_(buffer), releaser_(releaser)
39 {}
40
41 struct YUVData {
42 std::vector<uint8_t> y;
43 std::vector<uint8_t> u;
44 std::vector<uint8_t> v;
45 uint64_t ySize;
46 uint64_t uvSize;
47 };
48
DataSwap(uint8_t * a,uint8_t * b,bool flip)49 static inline void DataSwap(uint8_t* a, uint8_t* b, bool flip)
50 {
51 if (flip) {
52 *a = *b;
53 } else {
54 *b = *a;
55 }
56 }
57
IsYUV422SPFormat(int32_t format)58 static inline bool IsYUV422SPFormat(int32_t format)
59 {
60 if (format == int32_t(ImageFormat::YCBCR_422_SP) ||
61 format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)) {
62 return true;
63 }
64 return false;
65 }
66
YUV422SPDataCopy(uint8_t * buffer,uint64_t size,YUVData & data,bool flip)67 static void YUV422SPDataCopy(uint8_t* buffer, uint64_t size, YUVData &data, bool flip)
68 {
69 uint64_t ui = NUM_0;
70 uint64_t vi = NUM_0;
71 for (uint64_t i = NUM_0; i < size; i++) {
72 if (i < data.ySize) {
73 DataSwap(&(buffer[i]), &(data.y[i]), flip);
74 continue;
75 }
76 if (vi >= data.uvSize || ui >= data.uvSize) {
77 // Over write buffer size.
78 continue;
79 }
80 if (i % NUM_2 == NUM_1) {
81 DataSwap(&(buffer[i]), &(data.v[vi]), flip);
82 vi++;
83 } else {
84 DataSwap(&(buffer[i]), &(data.u[ui]), flip);
85 ui++;
86 }
87 }
88 }
GetSurfaceBufferAddr()89 uint8_t* NativeImage::GetSurfaceBufferAddr()
90 {
91 if (buffer_ != nullptr) {
92 return static_cast<uint8_t*>(buffer_->GetVirAddr());
93 }
94 return nullptr;
95 }
SplitYUV422SPComponent()96 int32_t NativeImage::SplitYUV422SPComponent()
97 {
98 auto rawBuffer = GetSurfaceBufferAddr();
99 if (rawBuffer == nullptr) {
100 IMAGE_LOGE("SurfaceBuffer viraddr is nullptr");
101 return ERR_MEDIA_NULL_POINTER;
102 }
103
104 uint64_t surfaceSize = NUM_0;
105 auto res = GetDataSize(surfaceSize);
106 if (res != SUCCESS || surfaceSize == NUM_0) {
107 IMAGE_LOGE("S size is 0");
108 return ERR_MEDIA_DATA_UNSUPPORT;
109 }
110
111 int32_t width = NUM_0;
112 int32_t height = NUM_0;
113 res = GetSize(width, height);
114 if (res != SUCCESS || width <= NUMI_0 || height <= NUMI_0) {
115 IMAGE_LOGE("Invaild width %{public}" PRId32 " height %{public}" PRId32, width, height);
116 return ERR_MEDIA_DATA_UNSUPPORT;
117 }
118
119 struct YUVData yuv;
120 uint64_t uvStride = static_cast<uint64_t>((width + NUM_1) / NUM_2);
121 yuv.ySize = static_cast<uint64_t>(width * height);
122 yuv.uvSize = static_cast<uint64_t>(height * uvStride);
123 if (surfaceSize < (yuv.ySize + yuv.uvSize * NUM_2)) {
124 IMAGE_LOGE("S size %{public}" PRIu64 " < y plane %{public}" PRIu64
125 " + uv plane %{public}" PRIu64, surfaceSize, yuv.ySize, yuv.uvSize * NUM_2);
126 return ERR_MEDIA_DATA_UNSUPPORT;
127 }
128
129 NativeComponent* y = CreateComponent(int32_t(ComponentType::YUV_Y), yuv.ySize, width, NUM_1, nullptr);
130 NativeComponent* u = CreateComponent(int32_t(ComponentType::YUV_U), yuv.uvSize, uvStride, NUM_2, nullptr);
131 NativeComponent* v = CreateComponent(int32_t(ComponentType::YUV_V), yuv.uvSize, uvStride, NUM_2, nullptr);
132 if ((y == nullptr) || (u == nullptr) || (v == nullptr)) {
133 IMAGE_LOGE("Create Component failed");
134 return ERR_MEDIA_DATA_UNSUPPORT;
135 }
136 yuv.y = y->raw;
137 yuv.u = u->raw;
138 yuv.v = v->raw;
139 YUV422SPDataCopy(rawBuffer, surfaceSize, yuv, false);
140 return SUCCESS;
141 }
142
SplitSurfaceToComponent()143 int32_t NativeImage::SplitSurfaceToComponent()
144 {
145 int32_t format = NUM_0;
146 auto res = GetFormat(format);
147 if (res != SUCCESS) {
148 return res;
149 }
150 switch (format) {
151 case int32_t(ImageFormat::YCBCR_422_SP):
152 case int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP):
153 return SplitYUV422SPComponent();
154 case int32_t(ImageFormat::JPEG):
155 if (CreateCombineComponent(int32_t(ComponentType::JPEG)) != nullptr) {
156 return SUCCESS;
157 }
158 }
159 // Unsupport split component
160 return ERR_MEDIA_DATA_UNSUPPORT;
161 }
162
CombineYUVComponents()163 int32_t NativeImage::CombineYUVComponents()
164 {
165 int32_t format = NUM_0;
166 auto res = GetFormat(format);
167 if (res != SUCCESS) {
168 return res;
169 }
170 if (!IsYUV422SPFormat(format)) {
171 IMAGE_LOGI("No need to combine components for NO YUV format now");
172 return SUCCESS;
173 }
174
175 auto y = GetComponent(int32_t(ComponentType::YUV_Y));
176 auto u = GetComponent(int32_t(ComponentType::YUV_U));
177 auto v = GetComponent(int32_t(ComponentType::YUV_V));
178 if ((y == nullptr) || (u == nullptr) || (v == nullptr)) {
179 IMAGE_LOGE("No component need to combine");
180 return ERR_MEDIA_DATA_UNSUPPORT;
181 }
182 YUVData data;
183 data.ySize = y->raw.size();
184 data.uvSize = u->raw.size();
185 data.y = y->raw;
186 data.u = u->raw;
187 data.v = v->raw;
188
189 uint64_t bufferSize = NUM_0;
190 GetDataSize(bufferSize);
191
192 YUV422SPDataCopy(GetSurfaceBufferAddr(), bufferSize, data, true);
193 return SUCCESS;
194 }
195
BuildComponent(size_t size,int32_t row,int32_t pixel,uint8_t * vir)196 static std::unique_ptr<NativeComponent> BuildComponent(size_t size, int32_t row, int32_t pixel, uint8_t* vir)
197 {
198 if (size == NUM_0 && vir == nullptr) {
199 IMAGE_LOGE("Could't create 0 size component data");
200 return nullptr;
201 }
202 std::unique_ptr<NativeComponent> component = std::make_unique<NativeComponent>();
203 component->pixelStride = pixel;
204 component->rowStride = row;
205 component->size = size;
206 if (vir != nullptr) {
207 component->virAddr = vir;
208 } else {
209 component->raw.resize(size);
210 }
211 return component;
212 }
213
GetCachedComponent(int32_t type)214 NativeComponent* NativeImage::GetCachedComponent(int32_t type)
215 {
216 auto iter = components_.find(type);
217 if (iter != components_.end()) {
218 return iter->second.get();
219 }
220 return nullptr;
221 }
222
CreateComponent(int32_t type,size_t size,int32_t row,int32_t pixel,uint8_t * vir)223 NativeComponent* NativeImage::CreateComponent(int32_t type, size_t size, int32_t row,
224 int32_t pixel, uint8_t* vir)
225 {
226 NativeComponent* res = GetCachedComponent(type);
227 if (res != nullptr) {
228 IMAGE_LOGI("Component %{public}d already exist. No need create", type);
229 return res;
230 }
231
232 std::unique_ptr<NativeComponent> component = BuildComponent(size, row, pixel, vir);
233 if (component == nullptr) {
234 return nullptr;
235 }
236 components_.insert(std::map<int32_t, std::unique_ptr<NativeComponent>>::value_type(type,
237 std::move(component)));
238
239 return GetCachedComponent(type);
240 }
241
CreateCombineComponent(int32_t type)242 NativeComponent* NativeImage::CreateCombineComponent(int32_t type)
243 {
244 uint64_t size = NUM_0;
245 GetDataSize(size);
246 return CreateComponent(type, static_cast<size_t>(size), buffer_->GetWidth(), NUM_1, GetSurfaceBufferAddr());
247 }
GetSize(int32_t & width,int32_t & height)248 int32_t NativeImage::GetSize(int32_t &width, int32_t &height)
249 {
250 if (buffer_ == nullptr) {
251 return ERR_MEDIA_DEAD_OBJECT;
252 }
253 width = buffer_->GetWidth();
254 height = buffer_->GetHeight();
255 return SUCCESS;
256 }
257
GetDataSize(uint64_t & size)258 int32_t NativeImage::GetDataSize(uint64_t &size)
259 {
260 if (buffer_ == nullptr) {
261 return ERR_MEDIA_DEAD_OBJECT;
262 }
263
264 size = static_cast<uint64_t>(buffer_->GetSize());
265 auto extraData = buffer_->GetExtraData();
266 if (extraData == nullptr) {
267 IMAGE_LOGI("Nullptr s extra data. return buffer size %{public}" PRIu64, size);
268 return SUCCESS;
269 }
270
271 int32_t extraDataSize = NUMI_0;
272 auto res = extraData->ExtraGet(DATA_SIZE_TAG, extraDataSize);
273 if (res != NUM_0) {
274 IMAGE_LOGI("S ExtraGet dataSize error %{public}d", res);
275 } else if (extraDataSize <= NUMI_0) {
276 IMAGE_LOGI("S ExtraGet dataSize Ok, but size <= 0");
277 } else if (static_cast<uint64_t>(extraDataSize) > size) {
278 IMAGE_LOGI("S ExtraGet dataSize Ok,but dataSize %{public}d is bigger than bufferSize %{public}" PRIu64,
279 extraDataSize, size);
280 } else {
281 IMAGE_LOGI("S ExtraGet dataSize %{public}d", extraDataSize);
282 size = extraDataSize;
283 }
284 return SUCCESS;
285 }
286
GetFormat(int32_t & format)287 int32_t NativeImage::GetFormat(int32_t &format)
288 {
289 if (buffer_ == nullptr) {
290 return ERR_MEDIA_DEAD_OBJECT;
291 }
292 format = buffer_->GetFormat();
293 return SUCCESS;
294 }
295
GetComponent(int32_t type)296 NativeComponent* NativeImage::GetComponent(int32_t type)
297 {
298 if (buffer_ == nullptr) {
299 return nullptr;
300 }
301
302 // Find type if it has exist.
303 auto component = GetCachedComponent(type);
304 if (component != nullptr) {
305 return component;
306 }
307
308 int32_t format = NUM_0;
309 if (GetFormat(format) == SUCCESS && type == format) {
310 return CreateCombineComponent(type);
311 }
312 SplitSurfaceToComponent();
313 // Try again
314 component = GetCachedComponent(type);
315
316 #ifdef COMPONENT_STRICT_CHECK
317 return component;
318 #else // We don't check the input type anymore, return raw format component!!
319 if (component == nullptr && GetFormat(format) == SUCCESS) {
320 return CreateCombineComponent(format);
321 }
322 return nullptr;
323 #endif
324 }
325
release()326 void NativeImage::release()
327 {
328 if (buffer_ == nullptr) {
329 return;
330 }
331 IMAGE_LOGI("NativeImage release");
332 if (components_.size() > 0) {
333 components_.clear();
334 }
335 if (releaser_ != nullptr && buffer_ != nullptr) {
336 releaser_->BufferRelease(buffer_);
337 }
338 releaser_ = nullptr;
339 buffer_ = nullptr;
340 }
341 } // namespace Media
342 } // namespace OHOS
343