1/*
2 * Copyright (C) 2023 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 "codec_utils.h"
17#include "avcodec_log.h"
18#include "media_description.h"
19namespace OHOS {
20namespace MediaAVCodec {
21namespace Codec {
22namespace {
23constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "FCodec"};
24constexpr uint32_t INDEX_ARRAY = 2;
25std::map<VideoPixelFormat, AVPixelFormat> g_pixelFormatMap = {
26    {VideoPixelFormat::YUVI420, AV_PIX_FMT_YUV420P},
27    {VideoPixelFormat::NV12, AV_PIX_FMT_NV12},
28    {VideoPixelFormat::NV21, AV_PIX_FMT_NV21},
29    {VideoPixelFormat::RGBA, AV_PIX_FMT_RGBA},
30};
31} // namespace
32
33using namespace OHOS::Media;
34int32_t ConvertVideoFrame(std::shared_ptr<Scale> *scale, std::shared_ptr<AVFrame> frame, uint8_t **dstData,
35                          int32_t *dstLineSize, AVPixelFormat dstPixFmt)
36{
37    if (*scale == nullptr) {
38        *scale = std::make_shared<Scale>();
39        ScalePara scalePara{static_cast<int32_t>(frame->width),        static_cast<int32_t>(frame->height),
40                            static_cast<AVPixelFormat>(frame->format), static_cast<int32_t>(frame->width),
41                            static_cast<int32_t>(frame->height),       dstPixFmt};
42        CHECK_AND_RETURN_RET_LOG((*scale)->Init(scalePara, dstData, dstLineSize) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN,
43                                 "Scale init error");
44    }
45    return (*scale)->Convert(frame->data, frame->linesize, dstData, dstLineSize);
46}
47
48int32_t WriteYuvDataStride(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
49                           int32_t stride, const Format &format)
50{
51    int32_t height;
52    int32_t fmt;
53    format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
54    format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt);
55    VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
56    CHECK_AND_RETURN_RET_LOG(pixFmt == VideoPixelFormat::YUVI420 || pixFmt == VideoPixelFormat::NV12 ||
57                                 pixFmt == VideoPixelFormat::NV21,
58                             AVCS_ERR_UNSUPPORT, "pixFmt: %{public}d do not support", pixFmt);
59    int32_t srcPos = 0;
60    int32_t dstPos = 0;
61    int32_t dataSize = scaleLineSize[0];
62    int32_t writeSize = dataSize > stride ? stride : dataSize;
63    for (int32_t colNum = 0; colNum < height; colNum++) {
64        memory->Write(scaleData[0] + srcPos, writeSize, dstPos);
65        dstPos += stride;
66        srcPos += dataSize;
67    }
68    srcPos = 0;
69    if (pixFmt == VideoPixelFormat::YUVI420) {
70        dataSize = scaleLineSize[1];
71        writeSize = dataSize > (stride / UV_SCALE_FACTOR) ? (stride / UV_SCALE_FACTOR) : dataSize;
72        for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
73            memory->Write(scaleData[1] + srcPos, writeSize, dstPos);
74            dstPos += (stride / UV_SCALE_FACTOR);
75            srcPos += dataSize;
76        }
77        srcPos = 0;
78        for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
79            memory->Write(scaleData[INDEX_ARRAY] + srcPos, writeSize, dstPos);
80            dstPos += (stride / UV_SCALE_FACTOR);
81            srcPos += dataSize;
82        }
83    } else if ((pixFmt == VideoPixelFormat::NV12) || (pixFmt == VideoPixelFormat::NV21)) {
84        dataSize = scaleLineSize[1];
85        writeSize = dataSize > stride ? stride : dataSize;
86        for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
87            memory->Write(scaleData[1] + srcPos, writeSize, dstPos);
88            dstPos += stride;
89            srcPos += dataSize;
90        }
91    }
92    AVCODEC_LOGD("WriteYuvDataStride success");
93    return AVCS_ERR_OK;
94}
95
96int32_t WriteRgbDataStride(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
97                           int32_t stride, const Format &format)
98{
99    int32_t height;
100    format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
101    int32_t srcPos = 0;
102    int32_t dstPos = 0;
103    int32_t dataSize = scaleLineSize[0];
104    int32_t writeSize = dataSize > stride ? stride : dataSize;
105    for (int32_t colNum = 0; colNum < height; colNum++) {
106        memory->Write(scaleData[0] + srcPos, writeSize, dstPos);
107        dstPos += stride;
108        srcPos += dataSize;
109    }
110
111    AVCODEC_LOGD("WriteRgbDataStride success");
112    return AVCS_ERR_OK;
113}
114
115int32_t WriteYuvData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
116                     int32_t &height, VideoPixelFormat &pixFmt)
117{
118    int32_t ySize = static_cast<int32_t>(scaleLineSize[0] * height);      // yuv420: 411 nv21
119    int32_t uvSize = static_cast<int32_t>(scaleLineSize[1] * height / 2); // 2
120    int32_t frameSize = 0;
121    if (pixFmt == VideoPixelFormat::YUVI420) {
122        frameSize = ySize + (uvSize * 2); // 2
123    } else if (pixFmt == VideoPixelFormat::NV21 || pixFmt == VideoPixelFormat::NV12) {
124        frameSize = ySize + uvSize;
125    }
126    CHECK_AND_RETURN_RET_LOG(memory->GetCapacity() >= frameSize, AVCS_ERR_NO_MEMORY,
127                             "output buffer size is not enough: real[%{public}d], need[%{public}u]",
128                             memory->GetCapacity(), frameSize);
129    if (pixFmt == VideoPixelFormat::YUVI420) {
130        memory->Write(scaleData[0], ySize);
131        memory->Write(scaleData[1], uvSize);
132        memory->Write(scaleData[2], uvSize); // 2
133    } else if ((pixFmt == VideoPixelFormat::NV12) || (pixFmt == VideoPixelFormat::NV21)) {
134        memory->Write(scaleData[0], ySize);
135        memory->Write(scaleData[1], uvSize);
136    } else {
137        return AVCS_ERR_UNSUPPORT;
138    }
139    return AVCS_ERR_OK;
140}
141
142int32_t WriteRgbData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
143                     int32_t &height)
144{
145    int32_t frameSize = static_cast<int32_t>(scaleLineSize[0] * height);
146    CHECK_AND_RETURN_RET_LOG(memory->GetCapacity() >= frameSize, AVCS_ERR_NO_MEMORY,
147                             "output buffer size is not enough: real[%{public}d], need[%{public}u]",
148                             memory->GetCapacity(), frameSize);
149    memory->Write(scaleData[0], frameSize);
150    return AVCS_ERR_OK;
151}
152
153int32_t WriteSurfaceData(const std::shared_ptr<AVMemory> &memory, struct SurfaceInfo &surfaceInfo, const Format &format)
154{
155    int32_t height;
156    int32_t fmt;
157    format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
158    format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt);
159    VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
160    if (surfaceInfo.surfaceFence != nullptr) {
161        surfaceInfo.surfaceFence->Wait(100); // 100ms
162    }
163    uint32_t yScaleLineSize = static_cast<uint32_t>(surfaceInfo.scaleLineSize[0]);
164    if (IsYuvFormat(pixFmt)) {
165        if (surfaceInfo.surfaceStride % yScaleLineSize) {
166            return WriteYuvDataStride(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize,
167                                      surfaceInfo.surfaceStride, format);
168        }
169        WriteYuvData(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize, height, pixFmt);
170    } else if (IsRgbFormat(pixFmt)) {
171        if (surfaceInfo.surfaceStride % yScaleLineSize) {
172            return WriteRgbDataStride(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize,
173                                      surfaceInfo.surfaceStride, format);
174        }
175        WriteRgbData(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize, height);
176    } else {
177        AVCODEC_LOGE("Fill frame buffer failed : unsupported pixel format: %{public}d", pixFmt);
178        return AVCS_ERR_UNSUPPORT;
179    }
180    return AVCS_ERR_OK;
181}
182
183int32_t WriteBufferData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, int32_t *scaleLineSize,
184                        const Format &format)
185{
186    int32_t height;
187    int32_t width;
188    int32_t fmt;
189    format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
190    format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width);
191    format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt);
192    VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
193
194    if (IsYuvFormat(pixFmt)) {
195        if (scaleLineSize[0] % width) {
196            return WriteYuvDataStride(memory, scaleData, scaleLineSize, width, format);
197        }
198        WriteYuvData(memory, scaleData, scaleLineSize, height, pixFmt);
199    } else if (IsRgbFormat(pixFmt)) {
200        if (scaleLineSize[0] % width) {
201            return WriteRgbDataStride(memory, scaleData, scaleLineSize, width * VIDEO_PIX_DEPTH_RGBA, format);
202        }
203        WriteRgbData(memory, scaleData, scaleLineSize, height);
204    } else {
205        AVCODEC_LOGE("Fill frame buffer failed : unsupported pixel format: %{public}d", pixFmt);
206        return AVCS_ERR_UNSUPPORT;
207    }
208    return AVCS_ERR_OK;
209}
210
211std::string AVStrError(int errnum)
212{
213    char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};
214    av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
215    return std::string(errbuf);
216}
217
218GraphicTransformType TranslateSurfaceRotation(const VideoRotation &rotation)
219{
220    switch (rotation) {
221        case VideoRotation::VIDEO_ROTATION_90: {
222            return GRAPHIC_ROTATE_270;
223        }
224        case VideoRotation::VIDEO_ROTATION_180: {
225            return GRAPHIC_ROTATE_180;
226        }
227        case VideoRotation::VIDEO_ROTATION_270: {
228            return GRAPHIC_ROTATE_90;
229        }
230        default:
231            return GRAPHIC_ROTATE_NONE;
232    }
233}
234
235GraphicPixelFormat TranslateSurfaceFormat(const VideoPixelFormat &surfaceFormat)
236{
237    switch (surfaceFormat) {
238        case VideoPixelFormat::YUVI420: {
239            return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_P;
240        }
241        case VideoPixelFormat::RGBA: {
242            return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888;
243        }
244        case VideoPixelFormat::NV12: {
245            return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_SP;
246        }
247        case VideoPixelFormat::NV21: {
248            return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_420_SP;
249        }
250        default:
251            return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_BUTT;
252    }
253}
254
255VideoPixelFormat ConvertPixelFormatFromFFmpeg(int32_t ffmpegPixelFormat)
256{
257    auto iter = std::find_if(
258        g_pixelFormatMap.begin(), g_pixelFormatMap.end(),
259        [&](const std::pair<VideoPixelFormat, AVPixelFormat> &tmp) -> bool { return tmp.second == ffmpegPixelFormat; });
260    return iter == g_pixelFormatMap.end() ? VideoPixelFormat::UNKNOWN : iter->first;
261}
262
263AVPixelFormat ConvertPixelFormatToFFmpeg(VideoPixelFormat pixelFormat)
264{
265    auto iter = std::find_if(
266        g_pixelFormatMap.begin(), g_pixelFormatMap.end(),
267        [&](const std::pair<VideoPixelFormat, AVPixelFormat> &tmp) -> bool { return tmp.first == pixelFormat; });
268    return iter == g_pixelFormatMap.end() ? AV_PIX_FMT_NONE : iter->second;
269}
270
271bool IsYuvFormat(VideoPixelFormat &format)
272{
273    return (format == VideoPixelFormat::YUVI420 || format == VideoPixelFormat::NV12 ||
274            format == VideoPixelFormat::NV21);
275}
276
277bool IsRgbFormat(VideoPixelFormat &format)
278{
279    return (format == VideoPixelFormat::RGBA);
280}
281
282int32_t Scale::Init(const ScalePara &scalePara, uint8_t **dstData, int32_t *dstLineSize)
283{
284    scalePara_ = scalePara;
285    if (swsCtx_ != nullptr) {
286        return AVCS_ERR_OK;
287    }
288    auto swsContext =
289        sws_getContext(scalePara_.srcWidth, scalePara_.srcHeight, scalePara_.srcFfFmt, scalePara_.dstWidth,
290                       scalePara_.dstHeight, scalePara_.dstFfFmt, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
291    if (swsContext == nullptr) {
292        return AVCS_ERR_UNKNOWN;
293    }
294    swsCtx_ = std::shared_ptr<SwsContext>(swsContext, [](struct SwsContext *ptr) {
295        if (ptr != nullptr) {
296            sws_freeContext(ptr);
297        }
298    });
299    auto ret = av_image_alloc(dstData, dstLineSize, scalePara_.dstWidth, scalePara_.dstHeight, scalePara_.dstFfFmt,
300                              scalePara_.align);
301    if (ret < 0) {
302        return AVCS_ERR_UNKNOWN;
303    }
304    for (int32_t i = 0; dstLineSize[i] > 0; i++) {
305        if (dstData[i] && !dstLineSize[i]) {
306            return AVCS_ERR_UNKNOWN;
307        }
308    }
309    return AVCS_ERR_OK;
310}
311
312int32_t Scale::Convert(uint8_t **srcData, const int32_t *srcLineSize, uint8_t **dstData, int32_t *dstLineSize)
313{
314    auto res = sws_scale(swsCtx_.get(), srcData, srcLineSize, 0, scalePara_.srcHeight, dstData, dstLineSize);
315    if (res < 0) {
316        return AVCS_ERR_UNKNOWN;
317    }
318    return AVCS_ERR_OK;
319}
320} // namespace Codec
321} // namespace MediaAVCodec
322} // namespace OHOS