• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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