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