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 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 <sys/mman.h>
17 #include <securec.h>
18 #include "ashmem.h"
19 #include "encode_buffer_helper.h"
20 
21 namespace OHOS::VDI::HEIF {
22 using namespace OHOS::HDI::Codec::Image::V2_0;
23 using namespace OHOS::HDI::Display::Buffer::V1_2;
24 using namespace OHOS::HDI::Display::Composer::V1_2;
25 using namespace std;
26 
ToUint32(const uint8_t * ptr)27 uint32_t ToUint32(const uint8_t* ptr)
28 {
29     if (ptr == nullptr) {
30         return 0;
31     }
32     return (ptr[0] << 24) | (ptr[1] << 16) |  // 24:bit offset, 16: bit offset, 1:byte offset
33            (ptr[2] << 8) | (ptr[3]);          // 8:bit offset, 2: byte offset, 3:byte offset
34 }
35 
EncodeBufferHelper()36 EncodeBufferHelper::EncodeBufferHelper()
37 {
38     bufferMgr_ = OHOS::HDI::Display::Buffer::V1_2::IDisplayBuffer::Get();
39 }
40 
~EncodeBufferHelper()41 EncodeBufferHelper::~EncodeBufferHelper()
42 {
43     bufferMgr_ = nullptr;
44     for (auto iter = allocatedFd_.begin(); iter != allocatedFd_.end(); ++iter) {
45         close(*iter);
46     }
47     allocatedFd_.clear();
48 }
49 
50 
InitialRgbaData(BufferHandle * handle,PixelFileInfo & pixelInfo,uint8_t * data,size_t size)51 bool EncodeBufferHelper::InitialRgbaData(BufferHandle* handle, PixelFileInfo& pixelInfo, uint8_t* data, size_t size)
52 {
53     char* dst = reinterpret_cast<char*>(handle->virAddr);
54     static constexpr uint32_t BYTES_PER_PIXEL_RBGA = 4;
55     errno_t ret = EOK;
56     uint8_t* dataEnd = data + size -1;
57     if (dataEnd < data + pixelInfo.alignedWidth * BYTES_PER_PIXEL_RBGA * pixelInfo.displayHeight) {
58         return false;
59         HDF_LOGI("Input Data length Not Enough");
60     }
61     for (uint32_t i = 0; i < pixelInfo.displayHeight; i++) {
62         ret = memcpy_s(dst, pixelInfo.alignedWidth * BYTES_PER_PIXEL_RBGA, data,
63                        pixelInfo.alignedWidth * BYTES_PER_PIXEL_RBGA);
64         dst += handle->stride;
65     }
66     data += pixelInfo.alignedWidth * BYTES_PER_PIXEL_RBGA * pixelInfo.displayHeight;
67     return (ret == EOK);
68 }
69 
CreateImgBuffer(uint8_t * data,size_t size)70 sptr<NativeBuffer> EncodeBufferHelper::CreateImgBuffer(uint8_t* data, size_t size)
71 {
72     PixelFileInfo pixelInfo;
73     uint8_t* dataEnd = data + size -1;
74     if (dataEnd < data + sizeof(pixelInfo.displayWidth)) {
75         return nullptr;
76     }
77     static constexpr int SHIFT_CNT = 22;
78     pixelInfo.displayWidth = (ToUint32(data) >> SHIFT_CNT); //Max 1024
79     pixelInfo.alignedWidth = pixelInfo.displayWidth;
80     data += sizeof(pixelInfo.displayWidth);
81 
82     if (dataEnd < data + sizeof(pixelInfo.displayHeight)) {
83         return nullptr;
84     }
85     pixelInfo.displayHeight = (ToUint32(data) >> SHIFT_CNT);
86     pixelInfo.alignedHeight = pixelInfo.displayHeight;
87     data += sizeof(pixelInfo.displayHeight);
88 
89     pixelInfo.pixFmt = OHOS::HDI::Display::Composer::V1_2::PIXEL_FMT_RGBA_8888;
90     uint64_t usage = OHOS::HDI::Display::Composer::V1_2::HBM_USE_CPU_READ |
91                      OHOS::HDI::Display::Composer::V1_2::HBM_USE_CPU_WRITE |
92                      OHOS::HDI::Display::Composer::V1_2::HBM_USE_MEM_DMA;
93     AllocInfo alloc = {
94         .width = pixelInfo.displayWidth,
95         .height = pixelInfo.displayHeight,
96         .usage =  usage,
97         .format = pixelInfo.pixFmt
98     };
99 
100     BufferHandle *handle = nullptr;
101     int32_t ret = bufferMgr_->AllocMem(alloc, handle);
102     IF_TRUE_RETURN_VAL_WITH_MSG(ret != HDF_SUCCESS, nullptr,
103                                 "failed to alloc output buffer, err [%{public}d] !", ret);
104     bufferMgr_->Mmap(*handle);
105 
106     HDF_LOGI("Fill Image RGB Data");
107     bool flag = InitialRgbaData(handle, pixelInfo, data, size);
108 
109     (void)bufferMgr_->Unmap(*handle);
110     if (!flag) {
111         bufferMgr_->FreeMem(*handle);
112         return nullptr;
113     }
114     HDF_LOGI("Fill Image RGB Data Succesfully");
115     sptr<NativeBuffer> imgBuffer = new NativeBuffer(handle);
116     return imgBuffer;
117 }
118 
CreateSharedBuffer(uint8_t * data,size_t size)119 SharedBuffer EncodeBufferHelper::CreateSharedBuffer(uint8_t* data, size_t size)
120 {
121     SharedBuffer buffer = {
122         .fd = -1,
123         .filledLen = 0,
124         .capacity = 0
125     };
126 
127     uint8_t* dataEnd = data + size - 1;
128     if (dataEnd < data + sizeof(uint8_t)) {
129         return buffer;
130     }
131     uint8_t totalSize = *data;
132     data += sizeof(totalSize);
133     int fd = AshmemCreate("ForMetaData", (size_t)totalSize);
134     IF_TRUE_RETURN_VAL_WITH_MSG(fd < 0, buffer, "cannot create ashmem for meta data");
135     void *addr = mmap(nullptr, (size_t)totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
136     if (addr == nullptr) {
137         HDF_LOGE("failed to map addr for meta buffer");
138         close(fd);
139         return buffer;
140     }
141     if (dataEnd < data + totalSize) {
142         return buffer;
143     }
144     errno_t ret = EOK;
145     ret = memcpy_s(reinterpret_cast<char*>(addr), totalSize, data, totalSize);
146     if (ret != EOK) {
147         return buffer;
148     }
149     data += totalSize;
150     if (munmap(addr, totalSize) != 0) {
151         HDF_LOGW("failed to unmap addr for meta buffer");
152     }
153     buffer.fd = fd;
154     buffer.filledLen = static_cast<uint32_t>(totalSize);
155     buffer.capacity = static_cast<uint32_t>(AshmemGetSize(fd));
156     allocatedFd_.insert(fd);
157     return buffer;
158 }
159 }