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 "native_buffer_inner.h"
17
18#include <cinttypes>
19#include "surface_type.h"
20#include "buffer_log.h"
21#include "native_window.h"
22#include "surface_buffer_impl.h"
23#include "metadata_helper.h"
24
25using namespace OHOS;
26using namespace HDI::Display::Graphic::Common::V1_0;
27static std::unordered_map<OH_NativeBuffer_ColorSpace, CM_ColorSpaceType> NATIVE_COLORSPACE_TO_HDI_MAP = {
28    {OH_COLORSPACE_NONE, CM_COLORSPACE_NONE},
29    {OH_COLORSPACE_BT601_EBU_FULL, CM_BT601_EBU_FULL},
30    {OH_COLORSPACE_BT601_SMPTE_C_FULL, CM_BT601_SMPTE_C_FULL},
31    {OH_COLORSPACE_BT709_FULL, CM_BT709_FULL},
32    {OH_COLORSPACE_BT2020_HLG_FULL, CM_BT2020_HLG_FULL},
33    {OH_COLORSPACE_BT2020_PQ_FULL, CM_BT2020_PQ_FULL},
34    {OH_COLORSPACE_BT601_EBU_LIMIT, CM_BT601_EBU_LIMIT},
35    {OH_COLORSPACE_BT601_SMPTE_C_LIMIT, CM_BT601_SMPTE_C_LIMIT},
36    {OH_COLORSPACE_BT709_LIMIT, CM_BT709_LIMIT},
37    {OH_COLORSPACE_BT2020_HLG_LIMIT, CM_BT2020_HLG_LIMIT},
38    {OH_COLORSPACE_BT2020_PQ_LIMIT, CM_BT2020_PQ_LIMIT},
39    {OH_COLORSPACE_SRGB_FULL, CM_SRGB_FULL},
40    {OH_COLORSPACE_P3_FULL, CM_P3_FULL},
41    {OH_COLORSPACE_P3_HLG_FULL, CM_P3_HLG_FULL},
42    {OH_COLORSPACE_P3_PQ_FULL, CM_P3_PQ_FULL},
43    {OH_COLORSPACE_ADOBERGB_FULL, CM_ADOBERGB_FULL},
44    {OH_COLORSPACE_SRGB_LIMIT, CM_SRGB_LIMIT},
45    {OH_COLORSPACE_P3_LIMIT, CM_P3_LIMIT},
46    {OH_COLORSPACE_P3_HLG_LIMIT, CM_P3_HLG_LIMIT},
47    {OH_COLORSPACE_P3_PQ_LIMIT, CM_P3_PQ_LIMIT},
48    {OH_COLORSPACE_ADOBERGB_LIMIT, CM_ADOBERGB_LIMIT},
49    {OH_COLORSPACE_LINEAR_SRGB, CM_LINEAR_SRGB},
50    {OH_COLORSPACE_LINEAR_BT709, CM_LINEAR_BT709},
51    {OH_COLORSPACE_LINEAR_P3, CM_LINEAR_P3},
52    {OH_COLORSPACE_LINEAR_BT2020, CM_LINEAR_BT2020},
53    {OH_COLORSPACE_DISPLAY_SRGB, CM_DISPLAY_SRGB},
54    {OH_COLORSPACE_DISPLAY_P3_SRGB, CM_DISPLAY_P3_SRGB},
55    {OH_COLORSPACE_DISPLAY_P3_HLG, CM_DISPLAY_P3_HLG},
56    {OH_COLORSPACE_DISPLAY_P3_PQ, CM_DISPLAY_P3_PQ},
57    {OH_COLORSPACE_DISPLAY_BT2020_SRGB, CM_DISPLAY_BT2020_SRGB},
58    {OH_COLORSPACE_DISPLAY_BT2020_HLG, CM_DISPLAY_BT2020_HLG},
59    {OH_COLORSPACE_DISPLAY_BT2020_PQ, CM_DISPLAY_BT2020_PQ}
60};
61
62static std::unordered_map<OH_NativeBuffer_MetadataType, CM_HDR_Metadata_Type> NATIVE_METADATATYPE_TO_HDI_MAP = {
63    {OH_VIDEO_HDR_HLG, CM_VIDEO_HLG},
64    {OH_VIDEO_HDR_HDR10, CM_VIDEO_HDR10},
65    {OH_VIDEO_HDR_VIVID, CM_VIDEO_HDR_VIVID},
66};
67
68static OH_NativeBuffer* OH_NativeBufferFromSurfaceBuffer(SurfaceBuffer* buffer)
69{
70    if (buffer == nullptr) {
71        return nullptr;
72    }
73    return buffer->SurfaceBufferToNativeBuffer();
74}
75
76static SurfaceBuffer* OH_NativeBufferToSurfaceBuffer(OH_NativeBuffer *buffer)
77{
78    return SurfaceBuffer::NativeBufferToSurfaceBuffer(buffer);
79}
80
81static const SurfaceBuffer* OH_NativeBufferToSurfaceBuffer(const OH_NativeBuffer *buffer)
82{
83    return SurfaceBuffer::NativeBufferToSurfaceBuffer(buffer);
84}
85
86OH_NativeBuffer* OH_NativeBuffer_Alloc(const OH_NativeBuffer_Config* config)
87{
88    if (config == nullptr) {
89        return nullptr;
90    }
91    BufferRequestConfig bfConfig = {};
92    bfConfig.width = config->width;
93    bfConfig.height = config->height;
94    bfConfig.strideAlignment = 0x8; // set 0x8 as default value to alloc SurfaceBufferImpl
95    bfConfig.format = config->format; // PixelFormat
96    bfConfig.usage = config->usage;
97    bfConfig.timeout = 0;
98    bfConfig.colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB;
99    bfConfig.transform = GraphicTransformType::GRAPHIC_ROTATE_NONE;
100    sptr<SurfaceBuffer> bufferImpl = new SurfaceBufferImpl();
101    GSError ret = bufferImpl->Alloc(bfConfig);
102    if (ret != OHOS::SURFACE_ERROR_OK) {
103        BLOGE("Alloc failed ret: %{public}d, config info: width[%{public}d, height[%{public}d,"
104            "format[%{public}d], usage[%{public}d]", ret, config->width, config->height,
105            config->format, config->usage);
106        return nullptr;
107    }
108
109    OH_NativeBuffer* buffer = OH_NativeBufferFromSurfaceBuffer(bufferImpl);
110    int32_t err = OH_NativeBuffer_Reference(buffer);
111    if (err != OHOS::SURFACE_ERROR_OK) {
112        BLOGE("NativeBufferReference failed, err: %{public}d.", err);
113        return nullptr;
114    }
115    return buffer;
116}
117
118int32_t OH_NativeBuffer_Reference(OH_NativeBuffer *buffer)
119{
120    if (buffer == nullptr) {
121        return OHOS::GSERROR_INVALID_ARGUMENTS;
122    }
123    OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
124    ref->IncStrongRef(ref);
125    return OHOS::SURFACE_ERROR_OK;
126}
127
128int32_t OH_NativeBuffer_Unreference(OH_NativeBuffer *buffer)
129{
130    if (buffer == nullptr) {
131        return OHOS::GSERROR_INVALID_ARGUMENTS;
132    }
133    OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(buffer);
134    ref->DecStrongRef(ref);
135    return OHOS::SURFACE_ERROR_OK;
136}
137
138void OH_NativeBuffer_GetConfig(OH_NativeBuffer *buffer, OH_NativeBuffer_Config* config)
139{
140    if (buffer == nullptr || config == nullptr) {
141        return;
142    }
143    const SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
144    config->width = sbuffer->GetWidth();
145    config->height = sbuffer->GetHeight();
146    config->format = sbuffer->GetFormat();
147    config->usage = sbuffer->GetUsage();
148    config->stride = sbuffer->GetStride();
149}
150
151int32_t OH_NativeBuffer_Map(OH_NativeBuffer *buffer, void **virAddr)
152{
153    if (buffer == nullptr || virAddr == nullptr) {
154        return OHOS::SURFACE_ERROR_INVALID_PARAM;
155    }
156    SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
157    int32_t ret = sbuffer->Map();
158    if (ret == OHOS::SURFACE_ERROR_OK) {
159        *virAddr = sbuffer->GetVirAddr();
160    } else {
161        BLOGE("Map failed, ret:%{public}d", ret);
162        ret = OHOS::SURFACE_ERROR_UNKOWN;
163    }
164    return ret;
165}
166
167int32_t OH_NativeBuffer_Unmap(OH_NativeBuffer *buffer)
168{
169    if (buffer == nullptr) {
170        return OHOS::SURFACE_ERROR_INVALID_PARAM;
171    }
172    SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
173    int32_t ret = sbuffer->Unmap();
174    if (ret != OHOS::SURFACE_ERROR_OK) {
175        BLOGE("Unmap failed, ret:%{public}d", ret);
176        ret = OHOS::SURFACE_ERROR_UNKOWN;
177    }
178    return ret;
179}
180
181uint32_t OH_NativeBuffer_GetSeqNum(OH_NativeBuffer *buffer)
182{
183    if (buffer == nullptr) {
184        return UINT_MAX;
185    }
186    const SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
187    return sbuffer->GetSeqNum();
188}
189
190const BufferHandle* OH_NativeBuffer_GetBufferHandle(const OH_NativeBuffer *buffer)
191{
192    if (buffer == nullptr) {
193        return nullptr;
194    }
195    const SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
196    return sbuffer->GetBufferHandle();
197}
198
199void OH_NativeBuffer_GetNativeBufferConfig(const OH_NativeBuffer *buffer, OH_NativeBuffer_Config* config)
200{
201    if (buffer == nullptr || config == nullptr) {
202        return;
203    }
204    const SurfaceBuffer* sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
205    config->width = sbuffer->GetWidth();
206    config->height = sbuffer->GetHeight();
207    config->format = sbuffer->GetFormat();
208    config->usage = sbuffer->GetUsage();
209    config->stride = sbuffer->GetStride();
210}
211
212OH_NativeBuffer* OH_NativeBufferFromNativeWindowBuffer(OHNativeWindowBuffer* nativeWindowBuffer)
213{
214    if (nativeWindowBuffer == nullptr) {
215        return nullptr;
216    }
217    OH_NativeBuffer* buffer = OH_NativeBufferFromSurfaceBuffer(nativeWindowBuffer->sfbuffer);
218    return buffer;
219}
220
221int32_t OH_NativeBuffer_SetColorSpace(OH_NativeBuffer *buffer, OH_NativeBuffer_ColorSpace colorSpace)
222{
223    if (buffer == nullptr || NATIVE_COLORSPACE_TO_HDI_MAP.find(colorSpace) == NATIVE_COLORSPACE_TO_HDI_MAP.end()) {
224        return OHOS::SURFACE_ERROR_INVALID_PARAM;
225    }
226    sptr<SurfaceBuffer> sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
227    GSError ret = MetadataHelper::SetColorSpaceType(sbuffer, NATIVE_COLORSPACE_TO_HDI_MAP[colorSpace]);
228    if (ret == OHOS::GSERROR_HDI_ERROR) {
229        return OHOS::SURFACE_ERROR_NOT_SUPPORT;
230    } else if (ret != OHOS::SURFACE_ERROR_OK) {
231        return OHOS::SURFACE_ERROR_UNKOWN;
232    }
233    return OHOS::SURFACE_ERROR_OK;
234}
235
236int32_t OH_NativeBuffer_MapPlanes(OH_NativeBuffer *buffer, void **virAddr, OH_NativeBuffer_Planes *outPlanes)
237{
238    if (buffer == nullptr || virAddr == nullptr || outPlanes == nullptr) {
239        return OHOS::SURFACE_ERROR_INVALID_PARAM;
240    }
241    sptr<SurfaceBuffer> sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
242    int32_t ret = sbuffer->Map();
243    if (ret == OHOS::SURFACE_ERROR_OK) {
244        *virAddr = sbuffer->GetVirAddr();
245    } else {
246        BLOGE("Map failed, %{public}d", ret);
247        return ret;
248    }
249    OH_NativeBuffer_Planes *planes = nullptr;
250    GSError retVal = sbuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
251    if (retVal != OHOS::SURFACE_ERROR_OK) {
252        BLOGE("GetPlanesInfo failed, retVal:%{public}d", retVal);
253        return retVal;
254    }
255    outPlanes->planeCount = planes->planeCount;
256    for (uint32_t i = 0; i < planes->planeCount && i < 4; i++) { // 4: max plane count
257        outPlanes->planes[i].offset = planes->planes[i].offset;
258        outPlanes->planes[i].rowStride = planes->planes[i].rowStride;
259        outPlanes->planes[i].columnStride = planes->planes[i].columnStride;
260    }
261    return OHOS::SURFACE_ERROR_OK;
262}
263
264int32_t OH_NativeBuffer_FromNativeWindowBuffer(OHNativeWindowBuffer *nativeWindowBuffer, OH_NativeBuffer **buffer)
265{
266    if (nativeWindowBuffer == nullptr || buffer == nullptr) {
267        return OHOS::SURFACE_ERROR_INVALID_PARAM;
268    }
269    *buffer = OH_NativeBufferFromSurfaceBuffer(nativeWindowBuffer->sfbuffer);
270    if (*buffer == nullptr) {
271        BLOGE("get sfbuffer is nullptr");
272        return OHOS::GSERROR_INVALID_OPERATING;
273    }
274    return OHOS::SURFACE_ERROR_OK;
275}
276
277int32_t OH_NativeBuffer_GetColorSpace(OH_NativeBuffer *buffer, OH_NativeBuffer_ColorSpace *colorSpace)
278{
279    if (buffer == nullptr || colorSpace == nullptr) {
280        return OHOS::SURFACE_ERROR_INVALID_PARAM;
281    }
282    sptr<SurfaceBuffer> sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
283    OHOS::HDI::Display::Graphic::Common::V1_0::CM_ColorSpaceType colorSpaceType;
284    GSError ret = MetadataHelper::GetColorSpaceType(sbuffer, colorSpaceType);
285    if (ret == OHOS::GSERROR_HDI_ERROR) {
286        return OHOS::SURFACE_ERROR_NOT_SUPPORT;
287    } else if (ret != OHOS::SURFACE_ERROR_OK) {
288        BLOGE("GetColorSpaceType failed!, retVal:%{public}d", ret);
289        return OHOS::SURFACE_ERROR_UNKOWN;
290    }
291    auto it = std::find_if(NATIVE_COLORSPACE_TO_HDI_MAP.begin(), NATIVE_COLORSPACE_TO_HDI_MAP.end(),
292        [colorSpaceType](const std::pair<OH_NativeBuffer_ColorSpace, CM_ColorSpaceType>& element) {
293            return element.second == colorSpaceType;
294        });
295    if (it != NATIVE_COLORSPACE_TO_HDI_MAP.end()) {
296        *colorSpace = it->first;
297        return OHOS::SURFACE_ERROR_OK;
298    }
299    BLOGE("the colorSpace does not support it.");
300    return OHOS::SURFACE_ERROR_UNKOWN;
301}
302
303int32_t OH_NativeBuffer_SetMetadataValue(OH_NativeBuffer *buffer, OH_NativeBuffer_MetadataKey metadataKey,
304    int32_t size, uint8_t *metadata)
305{
306    if (buffer == nullptr || metadata == nullptr || size <= 0) {
307        return OHOS::SURFACE_ERROR_INVALID_PARAM;
308    }
309    sptr<SurfaceBuffer> sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
310    GSError ret = GSERROR_OK;
311    std::vector<uint8_t> mD(metadata, metadata + size);
312    if (metadataKey == OH_HDR_DYNAMIC_METADATA) {
313        ret = MetadataHelper::SetHDRDynamicMetadata(sbuffer, mD);
314    } else if (metadataKey == OH_HDR_STATIC_METADATA) {
315        ret = MetadataHelper::SetHDRStaticMetadata(sbuffer, mD);
316    } else if (metadataKey == OH_HDR_METADATA_TYPE) {
317        OH_NativeBuffer_MetadataType hdrMetadataType = static_cast<OH_NativeBuffer_MetadataType>(*metadata);
318        ret = MetadataHelper::SetHDRMetadataType(sbuffer, NATIVE_METADATATYPE_TO_HDI_MAP[hdrMetadataType]);
319    } else {
320        BLOGE("the metadataKey does not support it.");
321        return OHOS::SURFACE_ERROR_UNKOWN;
322    }
323    if (ret == OHOS::GSERROR_HDI_ERROR) {
324        return OHOS::SURFACE_ERROR_NOT_SUPPORT;
325    } else if (ret != OHOS::SURFACE_ERROR_OK) {
326        BLOGE("SetHDRMetadata failed!, retVal:%{public}d", ret);
327        return OHOS::SURFACE_ERROR_UNKOWN;
328    }
329    return OHOS::SURFACE_ERROR_OK;
330}
331
332static GSError OH_NativeBuffer_GetMatedataValueType(sptr<SurfaceBuffer> sbuffer, int32_t *size, uint8_t **metadata)
333{
334    CM_HDR_Metadata_Type hdrMetadataType = CM_METADATA_NONE;
335    GSError ret = MetadataHelper::GetHDRMetadataType(sbuffer, hdrMetadataType);
336    if (ret == OHOS::GSERROR_HDI_ERROR) {
337        return OHOS::SURFACE_ERROR_NOT_SUPPORT;
338    } else if (ret != OHOS::SURFACE_ERROR_OK) {
339        BLOGE("GetHDRMetadataType failed!, ret: %{public}d", ret);
340        return OHOS::SURFACE_ERROR_UNKOWN;
341    }
342    auto it = std::find_if(NATIVE_METADATATYPE_TO_HDI_MAP.begin(), NATIVE_METADATATYPE_TO_HDI_MAP.end(),
343    [hdrMetadataType](const std::pair<OH_NativeBuffer_MetadataType, CM_HDR_Metadata_Type>& element) {
344        return element.second == hdrMetadataType;
345    });
346    if (it != NATIVE_METADATATYPE_TO_HDI_MAP.end()) {
347        *size = sizeof(OH_NativeBuffer_MetadataType);
348        *metadata = new uint8_t[*size];
349        errno_t err = memcpy_s(*metadata, *size, &(it->first), *size);
350        if (err != 0) {
351            delete[] *metadata;
352            *metadata = nullptr;
353            BLOGE("memcpy_s failed!, ret: %{public}d", err);
354            return OHOS::SURFACE_ERROR_UNKOWN;
355        }
356        return OHOS::SURFACE_ERROR_OK;
357    }
358    BLOGE("the hdrMetadataType does not support it.");
359    return OHOS::SURFACE_ERROR_NOT_SUPPORT;
360}
361
362int32_t OH_NativeBuffer_GetMetadataValue(OH_NativeBuffer *buffer, OH_NativeBuffer_MetadataKey metadataKey,
363    int32_t *size, uint8_t **metadata)
364{
365    if (buffer == nullptr || metadata == nullptr || size == nullptr) {
366        return OHOS::SURFACE_ERROR_INVALID_PARAM;
367    }
368    sptr<SurfaceBuffer> sbuffer = OH_NativeBufferToSurfaceBuffer(buffer);
369    GSError ret = GSERROR_OK;
370    std::vector<uint8_t> mD;
371    if (metadataKey == OH_HDR_DYNAMIC_METADATA) {
372        ret = MetadataHelper::GetHDRDynamicMetadata(sbuffer, mD);
373    } else if (metadataKey == OH_HDR_STATIC_METADATA) {
374        ret = MetadataHelper::GetHDRStaticMetadata(sbuffer, mD);
375    } else if (metadataKey == OH_HDR_METADATA_TYPE) {
376        ret = OH_NativeBuffer_GetMatedataValueType(sbuffer, size, metadata);
377        return ret;
378    } else {
379        BLOGE("the metadataKey does not support it.");
380        return OHOS::SURFACE_ERROR_UNKOWN;
381    }
382    if (ret == OHOS::GSERROR_HDI_ERROR) {
383        return OHOS::SURFACE_ERROR_NOT_SUPPORT;
384    } else if (ret != OHOS::SURFACE_ERROR_OK) {
385        BLOGE("SetHDRSMetadata failed!, ret: %{public}d", ret);
386        return OHOS::SURFACE_ERROR_UNKOWN;
387    }
388    *size = mD.size();
389    if (mD.empty()) {
390        BLOGE("Metadata is empty!");
391        return OHOS::SURFACE_ERROR_UNKOWN;
392    }
393    *metadata = new uint8_t[mD.size()];
394    errno_t err = memcpy_s(*metadata, mD.size(), &mD[0], mD.size());
395    if (err != 0) {
396        delete[] *metadata;
397        *metadata = nullptr;
398        BLOGE("memcpy_s failed!, ret: %{public}d", err);
399        return OHOS::SURFACE_ERROR_UNKOWN;
400    }
401    return OHOS::SURFACE_ERROR_OK;
402}