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