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  *     http://www.apache.org/licenses/LICENSE-2.0
7  * Unless required by applicable law or agreed to in writing, software
8  * distributed under the License is distributed on an "AS IS" BASIS,
9  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  * See the License for the specific language governing permissions and
11  * limitations under the License.
12  */
13 
14 #include "node_utils.h"
15 #include "map"
16 #include "camera.h"
17 extern "C" {
18 #ifdef DEVICE_USAGE_FFMPEG_ENABLE
19 #include "libavutil/frame.h"
20 #include "libavcodec/avcodec.h"
21 #include "libswscale/swscale.h"
22 #include "libavutil/imgutils.h"
23 #endif // DEVICE_USAGE_FFMPEG_ENABLE
24 }
25 
26 namespace OHOS::Camera {
27 using namespace std;
28 
29 const int32_t INVALID_ARGUMENT = -1;
30 
ConvertOhosFormat2AVPixelFormat(uint32_t format)31 static enum AVPixelFormat ConvertOhosFormat2AVPixelFormat(uint32_t format)
32 {
33     static map<uint32_t, enum AVPixelFormat> ohosFormat2AVPixelFormatMap = {
34         {CAMERA_FORMAT_RGBA_8888,    AV_PIX_FMT_RGBA},
35         {CAMERA_FORMAT_RGB_888,      AV_PIX_FMT_RGB24},
36         {CAMERA_FORMAT_YCRCB_420_SP, AV_PIX_FMT_NV21},
37         {CAMERA_FORMAT_YCRCB_422_P,  AV_PIX_FMT_YUYV422},
38     };
39     auto it = ohosFormat2AVPixelFormatMap.find(format);
40     if (it != ohosFormat2AVPixelFormatMap.end()) {
41         return it->second;
42     }
43     return AV_PIX_FMT_NONE;
44 }
45 
ImageFormatConvert(ImageBufferInfo & srcBufferInfo,ImageBufferInfo & dstBufferInfo)46 int32_t NodeUtils::ImageFormatConvert(ImageBufferInfo &srcBufferInfo, ImageBufferInfo &dstBufferInfo)
47 {
48     static uint32_t convertCount = 0;
49     uint32_t id = convertCount++;
50     auto srcAVFmt = ConvertOhosFormat2AVPixelFormat(srcBufferInfo.format);
51     auto dstAVFmt = ConvertOhosFormat2AVPixelFormat(dstBufferInfo.format);
52     if (srcAVFmt == AV_PIX_FMT_NONE || dstAVFmt == AV_PIX_FMT_NONE) {
53         CAMERA_LOGE("NodeUtils::ImageFormatConvert err, id = %{public}d, unsupport format: %{public}d -> %{public}d",
54             id, srcBufferInfo.format, dstBufferInfo.format);
55         return INVALID_ARGUMENT;
56     }
57     CAMERA_LOGI("NodeUtils::ImageFormatConvert Start ====== id = %{public}d", id);
58     CAMERA_LOGI("====imageSize: %{public}d * %{public}d -> %{public}d * %{public}d, format: %{public}d -> %{public}d",
59         srcBufferInfo.width, srcBufferInfo.height, dstBufferInfo.width, dstBufferInfo.height,
60         srcBufferInfo.format, dstBufferInfo.format);
61     CAMERA_LOGI("====buffer: %{public}p [%{public}d] -> %{public}p [%{public}d]",
62         srcBufferInfo.bufferAddr, srcBufferInfo.bufferSize,
63         dstBufferInfo.bufferAddr, dstBufferInfo.bufferSize);
64 
65     AVFrame *pFrameSrc = av_frame_alloc();
66     if (pFrameSrc == nullptr) {
67         CAMERA_LOGE("ImageFormatConvert Error pFrameSrc == nullptr");
68         return INVALID_ARGUMENT;
69     }
70     AVFrame *pFrameDst = av_frame_alloc();
71     if (pFrameDst == nullptr) {
72         CAMERA_LOGE("ImageFormatConvert Error pFrameDst == nullptr");
73         av_frame_free(&pFrameSrc);
74         return INVALID_ARGUMENT;
75     }
76 
77     av_image_fill_arrays(pFrameSrc->data, pFrameSrc->linesize, static_cast<uint8_t *>(srcBufferInfo.bufferAddr),
78         srcAVFmt, srcBufferInfo.width, srcBufferInfo.height, 1);
79     av_image_fill_arrays(pFrameDst->data, pFrameDst->linesize, static_cast<uint8_t *>(dstBufferInfo.bufferAddr),
80         dstAVFmt, dstBufferInfo.width, dstBufferInfo.height, 1);
81 
82     struct SwsContext* imgCtx = sws_getContext(
83         srcBufferInfo.width, srcBufferInfo.height, srcAVFmt,
84         dstBufferInfo.width, dstBufferInfo.height, dstAVFmt,
85         SWS_BILINEAR, 0, 0, 0);
86 
87     auto ret = sws_scale(imgCtx, pFrameSrc->data, pFrameSrc->linesize, 0, srcBufferInfo.height,
88         pFrameDst->data, pFrameDst->linesize);
89 
90     sws_freeContext(imgCtx);
91     av_frame_free(&pFrameSrc);
92     av_frame_free(&pFrameDst);
93     CAMERA_LOGD("NodeUtils::ImageFormatConvert End [%{public}d] ====== %{public}d", ret, id);
94 
95     return 0;
96 }
97 
BufferScaleFormatTransform(std::shared_ptr<IBuffer> & buffer,void * dstBuffer,uint32_t dstBufferSize)98 void NodeUtils::BufferScaleFormatTransform(std::shared_ptr<IBuffer>& buffer, void *dstBuffer, uint32_t dstBufferSize)
99 {
100     if (buffer == nullptr) {
101         CAMERA_LOGI("BufferScaleFormatTransform Error buffer == nullptr");
102         return;
103     }
104 
105     if (buffer->GetCurWidth() == buffer->GetWidth()
106         && buffer->GetCurHeight() == buffer->GetHeight()
107         && buffer->GetCurFormat() == buffer->GetFormat()) {
108             CAMERA_LOGE("no need ImageFormatConvert, nothing to do");
109             return;
110     }
111     if (buffer->GetIsValidDataInSurfaceBuffer()) {
112         CAMERA_LOGD("IsValidDataInSurfaceBuffer ture");
113         if (memcpy_s(buffer->GetVirAddress(), buffer->GetSize(),
114             buffer->GetSuffaceBufferAddr(), buffer->GetSuffaceBufferSize()) != 0) {
115             CAMERA_LOGE("BufferScaleFormatTransform Fail,  memcpy_s error");
116             return;
117         }
118     }
119 
120     NodeUtils::ImageBufferInfo srcInfo = {
121         .width = buffer->GetCurWidth(),
122         .height = buffer->GetCurHeight(),
123         .format = buffer->GetCurFormat(),
124         .bufferAddr = buffer->GetVirAddress(),
125         .bufferSize = buffer->GetSize(),
126     };
127 
128     NodeUtils::ImageBufferInfo dstInfo = {
129         .width = buffer->GetWidth(),
130         .height = buffer->GetHeight(),
131         .format = buffer->GetFormat(),
132         .bufferAddr = buffer->GetSuffaceBufferAddr(),
133         .bufferSize = buffer->GetSuffaceBufferSize()
134     };
135 
136     if (dstBuffer != nullptr && dstBufferSize != 0) {
137         dstInfo.bufferAddr = dstBuffer;
138         dstInfo.bufferSize = dstBufferSize;
139     }
140 
141     if (NodeUtils::ImageFormatConvert(srcInfo, dstInfo) == 0) {
142         buffer->SetCurFormat(buffer->GetFormat());
143         buffer->SetCurWidth(buffer->GetWidth());
144         buffer->SetCurHeight(buffer->GetHeight());
145         buffer->SetIsValidDataInSurfaceBuffer(true);
146     }
147 }
148 };