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