1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong DID 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_share_buffer.h"
17#include <hdf_base.h>
18#include <securec.h>
19#include <unistd.h>
20#include "codec_log_wrapper.h"
21using namespace OHOS::HDI::Codec::V3_0;
22namespace OHOS {
23namespace Codec {
24namespace Omx {
25CodecShareBuffer::CodecShareBuffer(struct OmxCodecBuffer &codecBuffer) : ICodecBuffer(codecBuffer)
26{}
27
28CodecShareBuffer::~CodecShareBuffer()
29{
30    shMem_ = nullptr;
31}
32
33void CodecShareBuffer::SetAshMem(std::shared_ptr<OHOS::Ashmem> shMem)
34{
35    shMem_ = shMem;
36}
37
38OHOS::sptr<ICodecBuffer> CodecShareBuffer::Create(struct OmxCodecBuffer &codecBuffer)
39{
40    if (codecBuffer.fd < 0) {
41        CODEC_LOGE("codecBuffer.fd is invalid");
42        return OHOS::sptr<ICodecBuffer>();
43    }
44    int size = OHOS::AshmemGetSize(codecBuffer.fd);
45    std::shared_ptr<OHOS::Ashmem> sharedMem = std::make_shared<OHOS::Ashmem>(codecBuffer.fd, size);
46    if (sharedMem == nullptr) {
47        CODEC_LOGE("Failed to init sharedMem");
48        return OHOS::sptr<ICodecBuffer>();
49    }
50    bool mapd = false;
51    if (codecBuffer.type == READ_WRITE_TYPE) {
52        mapd = sharedMem->MapReadAndWriteAshmem();
53    } else {
54        mapd = sharedMem->MapReadOnlyAshmem();
55    }
56    if (!mapd) {
57        CODEC_LOGE("MapReadAndWriteAshmem or MapReadOnlyAshmem return false");
58        return OHOS::sptr<ICodecBuffer>();
59    }
60    codecBuffer.fd = -1;
61    CodecShareBuffer *buffer = new CodecShareBuffer(codecBuffer);
62    buffer->SetAshMem(sharedMem);
63    return OHOS::sptr<ICodecBuffer>(buffer);
64}
65
66OHOS::sptr<ICodecBuffer> CodecShareBuffer::Allocate(struct OmxCodecBuffer &codecBuffer)
67{
68    codecBuffer.bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
69    // create shared memory
70    int sharedFD = AshmemCreate(nullptr, codecBuffer.allocLen);
71
72    std::shared_ptr<Ashmem> sharedMemory = std::make_shared<Ashmem>(sharedFD, codecBuffer.allocLen);
73    if (sharedMemory == nullptr) {
74        CODEC_LOGE("Failed to init sharedMemory");
75        return OHOS::sptr<ICodecBuffer>();
76    }
77    bool mapd = false;
78    if (codecBuffer.type == READ_WRITE_TYPE) {
79        mapd = sharedMemory->MapReadAndWriteAshmem();
80    } else {
81        mapd = sharedMemory->MapReadOnlyAshmem();
82    }
83    if (!mapd) {
84        CODEC_LOGE("MapReadAndWriteAshmem or MapReadOnlyAshmem return false");
85        return OHOS::sptr<ICodecBuffer>();
86    }
87    codecBuffer.offset = 0;
88    codecBuffer.filledLen = 0;
89    CodecShareBuffer *buffer = new CodecShareBuffer(codecBuffer);
90    codecBuffer.fd = sharedFD;
91    buffer->SetAshMem(sharedMemory);
92    return OHOS::sptr<ICodecBuffer>(buffer);
93}
94
95int32_t CodecShareBuffer::FillOmxBuffer(struct OmxCodecBuffer &codecBuffer, OMX_BUFFERHEADERTYPE &omxBuffer)
96{
97    if (!CheckInvalid(codecBuffer) || codecBuffer_.type != READ_WRITE_TYPE) {
98        CODEC_LOGE("CheckInvalid return false or mem has no right to write ");
99        return HDF_ERR_INVALID_PARAM;
100    }
101
102    return ICodecBuffer::FillOmxBuffer(codecBuffer, omxBuffer);
103}
104
105int32_t CodecShareBuffer::EmptyOmxBuffer(struct OmxCodecBuffer &codecBuffer, OMX_BUFFERHEADERTYPE &omxBuffer)
106{
107    if (!CheckInvalid(codecBuffer)) {
108        CODEC_LOGE("shMem_ is null or CheckInvalid return false");
109        return HDF_ERR_INVALID_PARAM;
110    }
111
112    void *sharedPtr = const_cast<void *>(shMem_->ReadFromAshmem(codecBuffer.filledLen, codecBuffer.offset));
113    if (!sharedPtr) {
114        CODEC_LOGE("omxBuffer.length [%{public}d omxBuffer.offset[%{public}d]", codecBuffer.filledLen,
115                   codecBuffer.offset);
116        return HDF_ERR_INVALID_PARAM;
117    }
118    auto ret = memcpy_s(omxBuffer.pBuffer + codecBuffer.offset, codecBuffer.allocLen - codecBuffer.offset, sharedPtr,
119                        codecBuffer.filledLen);
120    if (ret != EOK) {
121        CODEC_LOGE("memcpy_s ret [%{public}d]", ret);
122        return HDF_ERR_INVALID_PARAM;
123    }
124    return ICodecBuffer::EmptyOmxBuffer(codecBuffer, omxBuffer);
125}
126
127int32_t CodecShareBuffer::FreeBuffer(struct OmxCodecBuffer &codecBuffer)
128{
129    if (!CheckInvalid(codecBuffer)) {
130        CODEC_LOGE("shMem_ is null or CheckInvalid return false");
131        return HDF_ERR_INVALID_PARAM;
132    }
133
134    shMem_ = nullptr;
135    return HDF_SUCCESS;
136}
137
138uint8_t *CodecShareBuffer::GetBuffer()
139{
140    return nullptr;
141}
142
143int32_t CodecShareBuffer::EmptyOmxBufferDone(OMX_BUFFERHEADERTYPE &omxBuffer)
144{
145    return ICodecBuffer::EmptyOmxBufferDone(omxBuffer);
146}
147
148int32_t CodecShareBuffer::FillOmxBufferDone(OMX_BUFFERHEADERTYPE &omxBuffer)
149{
150    if (shMem_ == nullptr || !shMem_->WriteToAshmem(omxBuffer.pBuffer, omxBuffer.nFilledLen, omxBuffer.nOffset)) {
151        CODEC_LOGE("write to ashmem fail");
152        return HDF_ERR_INVALID_PARAM;
153    }
154
155    return ICodecBuffer::FillOmxBufferDone(omxBuffer);
156}
157
158bool CodecShareBuffer::CheckInvalid(struct OmxCodecBuffer &codecBuffer)
159{
160    if (!ICodecBuffer::CheckInvalid(codecBuffer) || shMem_ == nullptr) {
161        CODEC_LOGE("shMem_ is null or CheckInvalid return false");
162        return false;
163    }
164    return true;
165}
166}  // namespace Omx
167}  // namespace Codec
168}  // namespace OHOS