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 "av_hardware_memory.h"
17#include "av_shared_memory_ext.h"
18#include "av_surface_memory.h"
19#include "av_virtual_memory.h"
20#include "buffer/avallocator.h"
21#include "buffer/avbuffer.h"
22#include "common/log.h"
23#include "common/status.h"
24#include "message_parcel.h"
25#include "securec.h"
26#include "surface_buffer.h"
27
28namespace {
29constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_FOUNDATION, "AVMemory" };
30}
31
32namespace {
33uint64_t GetUniqueId()
34{
35#ifdef MEDIA_OHOS
36    using namespace std::chrono;
37    static const uint64_t startTime =
38        static_cast<uint64_t>(time_point_cast<seconds>(system_clock::now()).time_since_epoch().count());
39    static const uint16_t processId = static_cast<uint16_t>(getpid());
40#else
41    static const uint64_t startTime = 0;
42    static const uint16_t processId = 0;
43#endif
44    static std::atomic<uint32_t> bufferId = 0;
45    if (bufferId == UINT32_MAX) {
46        bufferId = 0;
47    }
48    union UniqueId {
49        uint64_t startTime;    //  1--16, 16: time
50        uint16_t processId[4]; // 17--32, 16: process id
51        uint32_t bufferId[2];  // 33--64, 32: atomic val
52    } uid = {.startTime = startTime};
53    ++bufferId;
54    uid.processId[1] = processId;
55    uid.bufferId[1] = bufferId;
56    return uid.startTime;
57}
58} // namespace
59namespace OHOS {
60namespace Media {
61std::shared_ptr<AVMemory> AVMemory::CreateAVMemory(std::shared_ptr<AVAllocator> allocator, int32_t capacity,
62                                                   int32_t align)
63{
64    MemoryType type = allocator->GetMemoryType();
65    std::shared_ptr<AVMemory> mem = nullptr;
66    switch (type) {
67        case MemoryType::VIRTUAL_MEMORY: {
68            mem = std::shared_ptr<AVMemory>(new AVVirtualMemory());
69            break;
70        }
71        case MemoryType::SURFACE_MEMORY: {
72            mem = std::shared_ptr<AVMemory>(new AVSurfaceMemory());
73            break;
74        }
75        case MemoryType::SHARED_MEMORY: {
76            mem = std::shared_ptr<AVMemory>(new AVSharedMemoryExt());
77            break;
78        }
79        case MemoryType::HARDWARE_MEMORY: {
80            mem = std::shared_ptr<AVMemory>(new AVHardwareMemory());
81            break;
82        }
83        default:
84            break;
85    }
86    FALSE_RETURN_V_MSG_E(mem != nullptr, nullptr, "Create AVMemory failed, no memory");
87
88    mem->allocator_ = allocator;
89    mem->capacity_ = capacity;
90    mem->align_ = align;
91    Status ret = mem->Init();
92    FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "Init AVMemory failed, uid:" PUBLIC_LOG_U64, mem->uid_);
93    return mem;
94}
95
96std::shared_ptr<AVMemory> AVMemory::CreateAVMemory(uint8_t *ptr, int32_t capacity, int32_t size)
97{
98    std::shared_ptr<AVMemory> mem = std::shared_ptr<AVMemory>(new AVVirtualMemory());
99    FALSE_RETURN_V_MSG_E(mem != nullptr, nullptr, "Create AVVirtualMemory failed, no memory");
100    mem->allocator_ = nullptr;
101    mem->capacity_ = capacity;
102    mem->size_ = size;
103    mem->base_ = ptr;
104    return mem;
105}
106
107std::shared_ptr<AVMemory> AVMemory::CreateAVMemory(MessageParcel &parcel, bool isSurfaceBuffer)
108{
109#ifdef MEDIA_OHOS
110    if (isSurfaceBuffer) {
111        auto mem = std::shared_ptr<AVMemory>(new AVSurfaceMemory());
112        Status ret = mem->InitSurfaceBuffer(parcel);
113        FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "Init AVSurfaceMemory failed");
114        return mem;
115    }
116    MemoryType type = static_cast<MemoryType>(parcel.ReadUint8());
117    std::shared_ptr<AVMemory> mem = nullptr;
118    switch (type) {
119        case MemoryType::VIRTUAL_MEMORY: {
120            return nullptr;
121        }
122        case MemoryType::SURFACE_MEMORY: {
123            mem = std::shared_ptr<AVMemory>(new AVSurfaceMemory());
124            break;
125        }
126        case MemoryType::SHARED_MEMORY: {
127            mem = std::shared_ptr<AVMemory>(new AVSharedMemoryExt());
128            break;
129        }
130        case MemoryType::HARDWARE_MEMORY: {
131            mem = std::shared_ptr<AVMemory>(new AVHardwareMemory());
132            break;
133        }
134        default:
135            break;
136    }
137
138    FALSE_RETURN_V_MSG_E(mem != nullptr, nullptr, "Create AVMemory failed, no memory");
139    bool isReadParcel = mem->ReadCommonFromMessageParcel(parcel);
140    FALSE_RETURN_V_MSG_E(isReadParcel == true, nullptr, "Read common memory info from parcel failed");
141
142    Status ret = mem->Init(parcel);
143    FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "Init AVMemory failed, uid:" PUBLIC_LOG_U64, mem->uid_);
144    return mem;
145#else
146    return nullptr;
147#endif
148}
149
150std::shared_ptr<AVMemory> AVMemory::CreateAVMemory(sptr<SurfaceBuffer> surfaceBuffer)
151{
152    auto mem = std::shared_ptr<AVMemory>(new AVSurfaceMemory());
153    Status ret = mem->InitSurfaceBuffer(surfaceBuffer);
154    FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "Init AVSurfaceMemory failed");
155    return mem;
156}
157
158AVMemory::AVMemory() : align_(0), offset_(0), size_(0), base_(nullptr), uid_(GetUniqueId()), allocator_(nullptr)
159{
160    MEDIA_LOG_DD("enter ctor, instance:0x%{public}06" PRIXPTR ", uid:" PUBLIC_LOG_U64, FAKE_POINTER(this), uid_);
161}
162
163AVMemory::~AVMemory()
164{
165    MEDIA_LOG_DD("enter dtor, instance:0x%{public}06" PRIXPTR ", uid:" PUBLIC_LOG_U64, FAKE_POINTER(this), uid_);
166}
167
168Status AVMemory::Init()
169{
170    return Status::ERROR_UNIMPLEMENTED;
171}
172
173Status AVMemory::Init(MessageParcel &parcel)
174{
175    (void)parcel;
176    return Status::ERROR_UNIMPLEMENTED;
177}
178
179Status AVMemory::InitSurfaceBuffer(MessageParcel &parcel)
180{
181    (void)parcel;
182    return Status::ERROR_UNIMPLEMENTED;
183}
184
185Status AVMemory::InitSurfaceBuffer(sptr<SurfaceBuffer> surfaceBuffer)
186{
187    (void)surfaceBuffer;
188    return Status::ERROR_UNIMPLEMENTED;
189}
190
191bool AVMemory::ReadFromMessageParcel(MessageParcel &parcel)
192{
193    (void)parcel;
194    return false;
195}
196
197bool AVMemory::WriteToMessageParcel(MessageParcel &parcel)
198{
199    (void)parcel;
200    return false;
201}
202
203bool AVMemory::ReadCommonFromMessageParcel(MessageParcel &parcel)
204{
205#ifdef MEDIA_OHOS
206    (void)parcel.ReadUint64();
207    int32_t capacity = -1;
208    int32_t align = -1;
209    int32_t offset = -1;
210    int32_t size = -1;
211
212    bool ret = parcel.ReadInt32(capacity);
213    FALSE_RETURN_V_MSG_E(ret && (capacity >= 0), false, "capacity is invalid");
214
215    ret = parcel.ReadInt32(align);
216    FALSE_RETURN_V_MSG_E(ret && (capacity >= align) && (align >= 0), false, "align is invalid");
217
218    ret = parcel.ReadInt32(offset);
219    FALSE_RETURN_V_MSG_E(ret && (capacity >= offset) && (offset >= 0), false, "offset is invalid");
220
221    ret = parcel.ReadInt32(size);
222    FALSE_RETURN_V_MSG_E(ret && (capacity >= size) && (size >= 0), false, "size is invalid");
223
224    capacity_ = capacity;
225    align_ = align;
226    offset_ = offset;
227    size_ = size;
228    return true;
229#else
230    return true;
231#endif
232}
233
234bool AVMemory::SkipCommonFromMessageParcel(MessageParcel &parcel)
235{
236#ifdef MEDIA_OHOS
237    uint64_t skipSize = 0;
238    bool ret = parcel.ReadUint64(skipSize);
239    FALSE_RETURN_V_MSG_E(ret, false, "unknown parcel");
240    parcel.SkipBytes(static_cast<size_t>(skipSize) - 2 * sizeof(int32_t)); // 2: the size of size_ and offset_
241
242    int32_t size = -1;
243    int32_t offset = -1;
244
245    ret = parcel.ReadInt32(offset);
246    FALSE_RETURN_V_MSG_E(ret && (capacity_ >= offset) && (offset >= 0), false, "offset is invalid");
247
248    ret = parcel.ReadInt32(size);
249    FALSE_RETURN_V_MSG_E(ret && (capacity_ >= size) && (size >= 0), false, "size is invalid");
250
251    size_ = size;
252    offset_ = offset;
253    return true;
254#else
255    return true;
256#endif
257}
258
259bool AVMemory::WriteCommonToMessageParcel(MessageParcel &parcel)
260{
261#ifdef MEDIA_OHOS
262    bool ret = true;
263    MessageParcel bufferParcel;
264    ret = bufferParcel.WriteInt32(capacity_) && bufferParcel.WriteInt32(align_) && bufferParcel.WriteInt32(offset_) &&
265          bufferParcel.WriteInt32(size_);
266
267    size_t size = bufferParcel.GetDataSize();
268    return ret && parcel.WriteUint64(static_cast<uint64_t>(size)) && parcel.Append(bufferParcel);
269#endif
270    return true;
271}
272
273MemoryType AVMemory::GetMemoryType()
274{
275    return MemoryType::VIRTUAL_MEMORY;
276}
277
278MemoryFlag AVMemory::GetMemoryFlag()
279{
280    return MemoryFlag::MEMORY_READ_WRITE;
281}
282
283int32_t AVMemory::GetCapacity()
284{
285    return capacity_;
286}
287
288int32_t AVMemory::GetSize()
289{
290    return size_;
291}
292
293Status AVMemory::SetSize(int32_t size)
294{
295    FALSE_RETURN_V_MSG_E((capacity_ >= size) && (size >= 0), Status::ERROR_INVALID_PARAMETER,
296                         "size out of range, "
297                         "current size:%{public}d , capacity:%{public}d",
298                         size_, capacity_);
299    size_ = size;
300    return Status::OK;
301}
302
303int32_t AVMemory::GetOffset()
304{
305    return offset_;
306}
307
308Status AVMemory::SetOffset(int32_t offset)
309{
310    FALSE_RETURN_V_MSG_E((capacity_ >= offset) && (offset >= 0), Status::ERROR_INVALID_PARAMETER,
311                         "offset out of range, "
312                         "current offset:%{public}d , capacity:%{public}d",
313                         offset_, capacity_);
314    offset_ = offset;
315    return Status::OK;
316}
317
318uint8_t *AVMemory::GetAddr()
319{
320    return base_;
321}
322
323int32_t AVMemory::GetFileDescriptor()
324{
325    return -1;
326}
327
328int32_t AVMemory::Write(const uint8_t *in, int32_t writeSize, int32_t position)
329{
330    FALSE_RETURN_V_MSG_E(in != nullptr, 0, "Input buffer is nullptr");
331    FALSE_RETURN_V_MSG_E(writeSize > 0, 0, "Input writeSize:%{public}d is invalid", writeSize);
332    FALSE_RETURN_V_MSG_E((GetMemoryFlag() & MemoryFlag::MEMORY_WRITE_ONLY) != 0, 0, "Lack write permission");
333    uint8_t *addr = GetAddr();
334    FALSE_RETURN_V_MSG_E(addr != nullptr, 0, "Base buffer is nullptr");
335    int32_t start = 0;
336    if (position <= INVALID_POSITION) {
337        start = size_;
338    } else {
339        start = std::min(position, capacity_);
340    }
341    int32_t unusedSize = capacity_ - start;
342    int32_t length = std::min(writeSize, unusedSize);
343    FALSE_RETURN_V_MSG_E((length + start) <= capacity_, 0,
344                         "Write out of bounds, length:%{public}d , start:%{public}d , capacity:%{public}d", length,
345                         start, capacity_);
346    uint8_t *dstPtr = addr + start;
347    FALSE_RETURN_V_MSG_E(dstPtr != nullptr, 0, "Inner dstPtr is nullptr");
348    auto error = memcpy_s(dstPtr, length, in, length);
349    FALSE_RETURN_V_MSG_E(error == EOK, 0, "Inner memcpy_s failed, uid:" PUBLIC_LOG_U64 ", %{public}s", uid_,
350                         strerror(error));
351    size_ = start + length;
352    return length;
353}
354
355int32_t AVMemory::Read(uint8_t *out, int32_t readSize, int32_t position)
356{
357    FALSE_RETURN_V_MSG_E(out != nullptr, 0, "Output buffer is nullptr");
358    FALSE_RETURN_V_MSG_E(readSize > 0, 0, "Output readSize:%{public}d is invalid", readSize);
359    FALSE_RETURN_V_MSG_E((GetMemoryFlag() & MemoryFlag::MEMORY_READ_ONLY) != 0, 0, "Lack read permission");
360    uint8_t *addr = GetAddr();
361    FALSE_RETURN_V_MSG_E(addr != nullptr, 0, "Base buffer is nullptr");
362    int32_t start = 0;
363    int32_t maxLength = size_;
364    if (position > INVALID_POSITION) {
365        start = std::min(position, size_);
366        maxLength = size_ - start;
367    }
368    int32_t length = std::min(readSize, maxLength);
369    FALSE_RETURN_V_MSG_E((length + start) <= capacity_, 0,
370                         "Read out of bounds, length:%{public}d, start:%{public}d, capacity:%{public}d", length, start,
371                         capacity_);
372    uint8_t *srcPtr = addr + start;
373    FALSE_RETURN_V_MSG_E(srcPtr != nullptr, 0, "Inner srcPtr is nullptr");
374    auto error = memcpy_s(out, length, srcPtr, length);
375    FALSE_RETURN_V_MSG_E(error == EOK, 0, "Inner memcpy_s failed, uid:%" PUBLIC_LOG_U64 ", %{public}s", uid_,
376                         strerror(error));
377    return length;
378}
379
380void AVMemory::Reset()
381{
382    size_ = 0;
383}
384
385sptr<SurfaceBuffer> AVMemory::GetSurfaceBuffer()
386{
387    return nullptr;
388}
389} // namespace Media
390} // namespace OHOS