1 /*
2 * Copyright (C) 2024 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 "buffer_converter.h"
17 #include <cmath>
18 #include "avcodec_errors.h"
19 #include "avcodec_log.h"
20 #include "meta/meta_key.h"
21 #include "native_buffer.h"
22 #include "surface_buffer.h"
23 #include "surface_type.h"
24
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "BufferConverter"};
27 using AVCodecRect = OHOS::MediaAVCodec::BufferConverter::AVCodecRect;
28 using GraphicPixelFormat = OHOS::GraphicPixelFormat;
29 using VideoPixelFormat = OHOS::MediaAVCodec::VideoPixelFormat;
30 constexpr int32_t OFFSET_2 = 0x02;
31 constexpr int32_t OFFSET_3 = 0x03;
32 constexpr int32_t OFFSET_4 = 0x04;
33 constexpr int32_t OFFSET_15 = 0x0F;
34 constexpr int32_t OFFSET_16 = 0x10;
TranslateSurfaceFormat(GraphicPixelFormat surfaceFormat)35 VideoPixelFormat TranslateSurfaceFormat(GraphicPixelFormat surfaceFormat)
36 {
37 switch (surfaceFormat) {
38 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_P: {
39 return VideoPixelFormat::YUVI420;
40 }
41 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888: {
42 return VideoPixelFormat::RGBA;
43 }
44 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_P010:
45 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_SP: {
46 return VideoPixelFormat::NV12;
47 }
48 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_P010:
49 case GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_420_SP: {
50 return VideoPixelFormat::NV21;
51 }
52 default:
53 AVCODEC_LOGE("Invalid graphic pixel format:%{public}d", static_cast<int32_t>(surfaceFormat));
54 return VideoPixelFormat::UNKNOWN;
55 }
56 }
57
ConvertYUV420SP(uint8_t * dst,uint8_t * src,AVCodecRect * rects,int32_t capacity)58 int32_t ConvertYUV420SP(uint8_t *dst, uint8_t *src, AVCodecRect *rects, int32_t capacity)
59 {
60 AVCodecRect &dstRect = rects[0];
61 AVCodecRect &srcRect = rects[1];
62 AVCodecRect &rect = rects[2]; // 2: index
63 int32_t dstSize = (OFFSET_3 * dstRect.wStride * dstRect.hStride) / OFFSET_2;
64 int32_t ret;
65 CHECK_AND_RETURN_RET_LOG(dstSize <= capacity, 0, "No memory. dstSize:%{public}d, capacity:%{public}d", dstSize,
66 capacity);
67 // Y
68 for (int32_t i = 0; i < rect.hStride; ++i) {
69 ret = memcpy_s(dst, dstRect.wStride, src, rect.wStride);
70 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
71 dst += dstRect.wStride;
72 src += srcRect.wStride;
73 }
74 // padding
75 dst += (dstRect.hStride - rect.hStride) * dstRect.wStride;
76 src += (srcRect.hStride - rect.hStride) * srcRect.wStride;
77 rect.hStride /= OFFSET_2;
78 // UV
79 for (int32_t i = 0; i < rect.hStride; ++i) {
80 ret = memcpy_s(dst, dstRect.wStride, src, rect.wStride);
81 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
82 dst += dstRect.wStride;
83 src += srcRect.wStride;
84 }
85 return dstSize;
86 }
87
ConvertYUV420P(uint8_t * dst,uint8_t * src,AVCodecRect * rects,int32_t capacity)88 int32_t ConvertYUV420P(uint8_t *dst, uint8_t *src, AVCodecRect *rects, int32_t capacity)
89 {
90 AVCodecRect &dstRect = rects[0];
91 AVCodecRect &srcRect = rects[1];
92 AVCodecRect &rect = rects[2]; // 2: index
93 int32_t dstSize = (OFFSET_3 * dstRect.wStride * dstRect.hStride) / OFFSET_2;
94 int32_t ret;
95 CHECK_AND_RETURN_RET_LOG(dstSize <= capacity, 0, "No memory. dstSize:%{public}d, capacity:%{public}d", dstSize,
96 capacity);
97 // Y
98 for (int32_t i = 0; i < rect.hStride; ++i) {
99 ret = memcpy_s(dst, dstRect.wStride, src, rect.wStride);
100 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
101 dst += dstRect.wStride;
102 src += srcRect.wStride;
103 }
104 // padding
105 const int32_t dstWidth = dstRect.wStride / OFFSET_2;
106 const int32_t srcWidth = srcRect.wStride / OFFSET_2;
107 const int32_t dstPadding = (dstRect.hStride - rect.hStride) * dstRect.wStride;
108 const int32_t srcPadding = (srcRect.hStride - rect.hStride) * srcRect.wStride;
109 rect.hStride /= OFFSET_2;
110 rect.wStride /= OFFSET_2;
111 dst += dstPadding;
112 src += srcPadding;
113 // U
114 for (int32_t i = 0; i < rect.hStride; ++i) {
115 ret = memcpy_s(dst, dstWidth, src, rect.wStride);
116 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
117 dst += dstWidth;
118 src += srcWidth;
119 }
120 // padding
121 dst += (dstPadding / OFFSET_4);
122 src += (srcPadding / OFFSET_4);
123 // V
124 for (int32_t i = 0; i < rect.hStride; ++i) {
125 ret = memcpy_s(dst, dstWidth, src, rect.wStride);
126 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
127 dst += dstWidth;
128 src += srcWidth;
129 }
130 return dstSize;
131 }
132
ConvertRGBA8888(uint8_t * dst,uint8_t * src,AVCodecRect * rects,int32_t capacity)133 int32_t ConvertRGBA8888(uint8_t *dst, uint8_t *src, AVCodecRect *rects, int32_t capacity)
134 {
135 AVCodecRect &dstRect = rects[0];
136 AVCodecRect &srcRect = rects[1];
137 AVCodecRect &rect = rects[2]; // 2: index
138 int32_t dstSize = dstRect.wStride * dstRect.hStride;
139 int32_t ret;
140 CHECK_AND_RETURN_RET_LOG(dstSize <= capacity, 0, "No memory. dstSize:%{public}d, capacity:%{public}d", dstSize,
141 capacity);
142 for (int32_t i = 0; i < rect.hStride; ++i) {
143 ret = memcpy_s(dst, dstRect.wStride, src, rect.wStride);
144 EXPECT_AND_LOGW(ret != 0, "memcpy failed");
145 dst += dstRect.wStride;
146 src += srcRect.wStride;
147 }
148 return dstSize;
149 }
150 } // namespace
151
152 namespace OHOS {
153 namespace MediaAVCodec {
154 using AVBuffer = Media::AVBuffer;
155 using AVSharedMemory = Media::AVSharedMemory;
156 using Format = Media::Format;
157 using MemoryType = Media::MemoryType;
158 using Tag = Media::Tag;
Create(AVCodecType type)159 std::shared_ptr<BufferConverter> BufferConverter::Create(AVCodecType type)
160 {
161 auto converter = std::make_shared<BufferConverter>();
162 if (converter->Init(type)) {
163 return converter;
164 }
165 return nullptr;
166 }
167
BufferConverter()168 BufferConverter::BufferConverter() : func_(ConvertYUV420SP), isSharedMemory_(false), needResetFormat_(true) {}
169
Init(AVCodecType type)170 bool BufferConverter::Init(AVCodecType type)
171 {
172 if (type == AVCODEC_TYPE_VIDEO_ENCODER) {
173 isEncoder_ = true;
174 } else if (type == AVCODEC_TYPE_VIDEO_DECODER) {
175 isEncoder_ = false;
176 } else {
177 return false;
178 }
179 return true;
180 }
181
ReadFromBuffer(std::shared_ptr<AVBuffer> & buffer,std::shared_ptr<AVSharedMemory> & memory)182 int32_t BufferConverter::ReadFromBuffer(std::shared_ptr<AVBuffer> &buffer, std::shared_ptr<AVSharedMemory> &memory)
183 {
184 std::shared_lock<std::shared_mutex> lock(mutex_);
185 if (isSharedMemory_) {
186 return AVCS_ERR_OK;
187 }
188 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer != nullptr, AVCS_ERR_INVALID_VAL, "buffer is nullptr");
189 if (buffer->memory_ == nullptr) {
190 return AVCS_ERR_OK;
191 }
192 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer->memory_->GetAddr() != nullptr, AVCS_ERR_INVALID_VAL,
193 "buffer addr is nullptr");
194 CHECK_AND_RETURN_RET_LOG_WITH_TAG(memory != nullptr && memory->GetBase() != nullptr, AVCS_ERR_INVALID_VAL,
195 "shared memory is nullptr");
196 int32_t size = buffer->memory_->GetSize();
197 if (size <= 0) {
198 return AVCS_ERR_OK;
199 }
200 if (isEncoder_) {
201 int32_t ret = buffer->memory_->Read(memory->GetBase(), size, 0);
202 CHECK_AND_RETURN_RET_LOG_WITH_TAG(ret == size, AVCS_ERR_INVALID_VAL, "Read avbuffer's data failed");
203 return AVCS_ERR_OK;
204 }
205 AVCodecRect rects[3] = {usrRect_, hwRect_, rect_}; // 1:dstRect, 2:srcRect, 3:rect
206 int32_t usrSize = func_(memory->GetBase(), buffer->memory_->GetAddr(), rects, memory->GetSize());
207 buffer->memory_->SetSize(usrSize);
208 return AVCS_ERR_OK;
209 }
210
WriteToBuffer(std::shared_ptr<AVBuffer> & buffer,std::shared_ptr<AVSharedMemory> & memory)211 int32_t BufferConverter::WriteToBuffer(std::shared_ptr<AVBuffer> &buffer, std::shared_ptr<AVSharedMemory> &memory)
212 {
213 std::shared_lock<std::shared_mutex> lock(mutex_);
214 if (isSharedMemory_) {
215 return AVCS_ERR_OK;
216 }
217 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer != nullptr && buffer->memory_ != nullptr &&
218 buffer->memory_->GetAddr() != nullptr,
219 AVCS_ERR_INVALID_VAL, "buffer is nullptr");
220 CHECK_AND_RETURN_RET_LOG_WITH_TAG(memory != nullptr && memory->GetBase() != nullptr, AVCS_ERR_INVALID_VAL,
221 "shared memory is nullptr");
222 int32_t size = buffer->memory_->GetSize();
223 if (size <= 0) {
224 return AVCS_ERR_OK;
225 }
226 if (!isEncoder_) {
227 (void)buffer->memory_->Write(memory->GetBase(), size, 0);
228 return AVCS_ERR_OK;
229 }
230 AVCodecRect rects[3] = {hwRect_, usrRect_, rect_}; // 1:dstRect, 2:srcRect, 3:rect
231 int32_t hwSize = func_(buffer->memory_->GetAddr(), memory->GetBase(), rects, buffer->memory_->GetCapacity());
232 buffer->memory_->SetSize(hwSize);
233 return AVCS_ERR_OK;
234 }
235
NeedToResetFormatOnce()236 void BufferConverter::NeedToResetFormatOnce()
237 {
238 std::lock_guard<std::shared_mutex> lock(mutex_);
239 needResetFormat_ = true;
240 }
241
GetFormat(Format & format)242 void BufferConverter::GetFormat(Format &format)
243 {
244 std::shared_lock<std::shared_mutex> lock(mutex_);
245 if (isSharedMemory_ || needResetFormat_) {
246 return;
247 }
248 if (!isEncoder_ && format.ContainKey(Tag::VIDEO_WIDTH)) {
249 format.PutIntValue(Tag::VIDEO_WIDTH, usrRect_.wStride);
250 }
251 if (!isEncoder_ && format.ContainKey(Tag::VIDEO_HEIGHT)) {
252 format.PutIntValue(Tag::VIDEO_HEIGHT, usrRect_.hStride);
253 }
254 if (format.ContainKey(Tag::VIDEO_STRIDE) || format.ContainKey(Tag::VIDEO_SLICE_HEIGHT)) {
255 format.PutIntValue(Tag::VIDEO_STRIDE, usrRect_.wStride);
256 format.PutIntValue(Tag::VIDEO_SLICE_HEIGHT, usrRect_.hStride);
257 }
258 }
259
SetFormat(const Format & format)260 void BufferConverter::SetFormat(const Format &format)
261 {
262 std::lock_guard<std::shared_mutex> lock(mutex_);
263 if (isSharedMemory_) {
264 return;
265 }
266 int32_t width = 0;
267 int32_t height = 0;
268 int32_t wStride = 0;
269 int32_t hStride = 0;
270 int32_t pixelFormat = static_cast<int32_t>(VideoPixelFormat::UNKNOWN);
271 if (format.GetIntValue(Tag::VIDEO_PIXEL_FORMAT, pixelFormat)) {
272 SetPixFormat(static_cast<VideoPixelFormat>(pixelFormat));
273 }
274 if (format.GetIntValue(Tag::VIDEO_PIC_WIDTH, width) || format.GetIntValue(Tag::VIDEO_WIDTH, width)) {
275 SetWidth(width);
276 }
277 if (format.GetIntValue(Tag::VIDEO_PIC_HEIGHT, height) || format.GetIntValue(Tag::VIDEO_HEIGHT, height)) {
278 SetHeight(height);
279 }
280 if (!format.GetIntValue(Tag::VIDEO_STRIDE, wStride)) {
281 SetWidthStride(rect_.wStride);
282 } else {
283 hwRect_.wStride = wStride;
284 }
285 if (!format.GetIntValue(Tag::VIDEO_SLICE_HEIGHT, hStride)) {
286 SetHeightStride(rect_.hStride);
287 } else {
288 hwRect_.hStride = hStride;
289 }
290 // check if the converter needs to reset the format.
291 needResetFormat_ = !SetRectValue(width, height, wStride, hStride) ||
292 pixelFormat == static_cast<int32_t>(VideoPixelFormat::UNKNOWN);
293 if (needResetFormat_) {
294 AVCODEC_LOGW_WITH_TAG("Invalid format:%{public}s", format.Stringify().c_str());
295 return;
296 }
297 AVCODEC_LOGD_WITH_TAG(
298 "Actual:(%{public}dx%{public}d),Converter:(%{public}dx%{public}d),Hardware:(%{public}dx%{public}d)", width,
299 rect_.hStride, usrRect_.wStride, usrRect_.hStride, hwRect_.wStride, hwRect_.hStride);
300 }
301
SetInputBufferFormat(std::shared_ptr<AVBuffer> & buffer)302 void BufferConverter::SetInputBufferFormat(std::shared_ptr<AVBuffer> &buffer)
303 {
304 if (!isEncoder_) {
305 return;
306 }
307 std::lock_guard<std::shared_mutex> lock(mutex_);
308 if (!needResetFormat_) {
309 return;
310 }
311 needResetFormat_ = !SetBufferFormat(buffer);
312 }
313
SetOutputBufferFormat(std::shared_ptr<AVBuffer> & buffer)314 void BufferConverter::SetOutputBufferFormat(std::shared_ptr<AVBuffer> &buffer)
315 {
316 if (isEncoder_) {
317 return;
318 }
319 std::lock_guard<std::shared_mutex> lock(mutex_);
320 if (!needResetFormat_) {
321 return;
322 }
323 needResetFormat_ = !SetBufferFormat(buffer);
324 }
325
SetPixFormat(const VideoPixelFormat pixelFormat)326 void BufferConverter::SetPixFormat(const VideoPixelFormat pixelFormat)
327 {
328 switch (pixelFormat) {
329 case VideoPixelFormat::YUV420P:
330 case VideoPixelFormat::YUVI420:
331 func_ = ConvertYUV420P;
332 break;
333 case VideoPixelFormat::NV12:
334 case VideoPixelFormat::NV21:
335 func_ = ConvertYUV420SP;
336 break;
337 case VideoPixelFormat::RGBA:
338 func_ = ConvertRGBA8888;
339 break;
340 default:
341 AVCODEC_LOGE_WITH_TAG("Invalid video pix format:%{public}d", static_cast<int32_t>(pixelFormat));
342 break;
343 };
344 }
345
SetWidth(const int32_t width)346 inline void BufferConverter::SetWidth(const int32_t width)
347 {
348 rect_.wStride = ((width + OFFSET_15) / OFFSET_16) * OFFSET_16;
349 }
350
SetHeight(const int32_t height)351 inline void BufferConverter::SetHeight(const int32_t height)
352 {
353 rect_.hStride = ((height + OFFSET_15) / OFFSET_16) * OFFSET_16;
354 }
355
SetWidthStride(const int32_t wStride)356 inline void BufferConverter::SetWidthStride(const int32_t wStride)
357 {
358 hwRect_.wStride = wStride;
359 }
360
SetHeightStride(const int32_t hStride)361 inline void BufferConverter::SetHeightStride(const int32_t hStride)
362 {
363 hwRect_.hStride = hStride;
364 }
365
SetBufferFormat(std::shared_ptr<AVBuffer> & buffer)366 bool BufferConverter::SetBufferFormat(std::shared_ptr<AVBuffer> &buffer)
367 {
368 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer != nullptr, false, "buffer is nullptr");
369 if (buffer->memory_ == nullptr) {
370 isSharedMemory_ = true;
371 AVCODEC_LOGW_WITH_TAG("memory is nullptr");
372 return true;
373 }
374 isSharedMemory_ = buffer->memory_->GetMemoryType() == MemoryType::SHARED_MEMORY;
375 if (isSharedMemory_) {
376 AVCODEC_LOGW_WITH_TAG("AVBuffer is shared memory");
377 return true;
378 }
379
380 auto surfaceBuffer = buffer->memory_->GetSurfaceBuffer();
381 CHECK_AND_RETURN_RET_LOG_WITH_TAG(surfaceBuffer != nullptr, false, "surface buffer is nullptr");
382 // pixelFormat
383 VideoPixelFormat pixelFormat = TranslateSurfaceFormat(static_cast<GraphicPixelFormat>(surfaceBuffer->GetFormat()));
384 SetPixFormat(pixelFormat);
385 int32_t width = surfaceBuffer->GetWidth();
386 int32_t height = surfaceBuffer->GetHeight();
387 int32_t wStride = surfaceBuffer->GetStride();
388 int32_t hStride = GetSliceHeightFromSurfaceBuffer(surfaceBuffer);
389 bool ret = SetRectValue(width, height, wStride, hStride);
390 CHECK_AND_RETURN_RET_LOG_WITH_TAG(ret, false, "width is 0");
391 AVCODEC_LOGI_WITH_TAG(
392 "Actual:(%{public}dx%{public}d),Converter:(%{public}dx%{public}d),Hardware:(%{public}dx%{public}d)",
393 rect_.wStride, rect_.hStride, usrRect_.wStride, usrRect_.hStride, hwRect_.wStride, hwRect_.hStride);
394 return true;
395 }
396
SetRectValue(const int32_t width,const int32_t height,const int32_t wStride,const int32_t hStride)397 bool BufferConverter::SetRectValue(const int32_t width, const int32_t height, const int32_t wStride,
398 const int32_t hStride)
399 {
400 CHECK_AND_RETURN_RET_LOG_WITH_TAG(wStride > 0, false, "stride <= 0");
401 CHECK_AND_RETURN_RET_LOG_WITH_TAG(width > 0 && height > 0, false, "width/height <= 0");
402 int32_t tempPixelSize = wStride / width;
403 tempPixelSize = (tempPixelSize <= 0) ? 1 : tempPixelSize;
404
405 // width or height <= calculated stride <= hardware stride
406 // rect <= usrRect <= hwRect
407 rect_.wStride = width * tempPixelSize;
408 rect_.hStride = height;
409 hwRect_.wStride = std::max(rect_.wStride, wStride);
410 hwRect_.hStride = std::max(rect_.hStride, hStride);
411 usrRect_.wStride = std::min(hwRect_.wStride, CalculateUserStride(width) * tempPixelSize);
412 usrRect_.hStride = std::min(hwRect_.hStride, CalculateUserStride(height));
413 return true;
414 }
415
CalculateUserStride(const int32_t widthHeight)416 inline int32_t BufferConverter::CalculateUserStride(const int32_t widthHeight)
417 {
418 return ((widthHeight + OFFSET_15) / OFFSET_16) * OFFSET_16;
419 }
420
GetSliceHeightFromSurfaceBuffer(sptr<SurfaceBuffer> & surfaceBuffer) const421 int32_t BufferConverter::GetSliceHeightFromSurfaceBuffer(sptr<SurfaceBuffer> &surfaceBuffer) const
422 {
423 int32_t height = surfaceBuffer->GetHeight();
424 if (isEncoder_) {
425 return height;
426 }
427 OH_NativeBuffer_Planes *planes = nullptr;
428 GSError err = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void **>(&planes));
429 if (err != GSERROR_OK || planes == nullptr) {
430 AVCODEC_LOGW("get plane info failed, GSError=%{public}d", err);
431 return height;
432 }
433 uint32_t count = planes->planeCount;
434 if (count <= 1) {
435 AVCODEC_LOGW("planes count is %{public}u", count);
436 return height;
437 }
438 return static_cast<int32_t>(static_cast<int64_t>(planes->planes[1].offset) / surfaceBuffer->GetStride());
439 }
440 } // namespace MediaAVCodec
441 } // namespace OHOS
442