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