1 /*
2 * Copyright (C) 2021 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 "gst_shmem_allocator.h"
17 #include "media_log.h"
18 #include "media_errors.h"
19 #include "securec.h"
20 using namespace OHOS;
21
22 #define gst_shmem_allocator_parent_class parent_class
23 G_DEFINE_TYPE(GstShMemAllocator, gst_shmem_allocator, GST_TYPE_ALLOCATOR);
24
25 GST_DEBUG_CATEGORY_STATIC(gst_shmem_allocator_debug_category);
26 #define GST_CAT_DEFAULT gst_shmem_allocator_debug_category
27
28 static constexpr uint32_t ALIGN_BYTES = 4;
29
gst_shmem_allocator_new()30 GstShMemAllocator *gst_shmem_allocator_new()
31 {
32 GstShMemAllocator *alloc = GST_SHMEM_ALLOCATOR_CAST(g_object_new(
33 GST_TYPE_SHMEM_ALLOCATOR, "name", "ShMemAllocator", nullptr));
34 (void)gst_object_ref_sink(alloc);
35
36 return alloc;
37 }
38
gst_shmem_allocator_set_pool(GstShMemAllocator * allocator,std::shared_ptr<OHOS::Media::AVSharedMemoryPool> pool)39 void gst_shmem_allocator_set_pool(GstShMemAllocator *allocator,
40 std::shared_ptr<OHOS::Media::AVSharedMemoryPool> pool)
41 {
42 g_return_if_fail(allocator != nullptr && pool != nullptr);
43 allocator->avShmemPool = pool;
44 }
45
gst_shmem_allocator_alloc(GstAllocator * allocator,gsize size,GstAllocationParams * params)46 GstMemory *gst_shmem_allocator_alloc(GstAllocator *allocator, gsize size, GstAllocationParams *params)
47 {
48 g_return_val_if_fail(allocator != nullptr && params != nullptr, nullptr);
49 GstShMemAllocator *sAlloctor = GST_SHMEM_ALLOCATOR_CAST(allocator);
50 g_return_val_if_fail(sAlloctor != nullptr && sAlloctor->avShmemPool != nullptr, nullptr);
51 g_return_val_if_fail((params->prefix & (ALIGN_BYTES - 1)) == 0, nullptr);
52 g_return_val_if_fail((UINT64_MAX - params->prefix) >= size, nullptr);
53
54 uint64_t allocSize = size + params->prefix;
55 g_return_val_if_fail(allocSize < INT32_MAX, nullptr);
56
57 std::shared_ptr<OHOS::Media::AVSharedMemory> shmem = sAlloctor->avShmemPool->AcquireMemory(allocSize);
58 if (shmem == nullptr) {
59 GST_LOG("no memory");
60 return nullptr;
61 }
62
63 GstShMemMemory *memory = reinterpret_cast<GstShMemMemory *>(g_slice_alloc0(sizeof(GstShMemMemory)));
64 g_return_val_if_fail(memory != nullptr, nullptr);
65
66 gst_memory_init(GST_MEMORY_CAST(memory), (GstMemoryFlags)0, allocator,
67 nullptr, allocSize, 0, params->prefix, size);
68
69 memory->mem = shmem;
70 GST_LOG("alloc memory from %s for size: %" PRIu64 ", gstmemory: 0x%06" PRIXPTR "",
71 sAlloctor->avShmemPool->GetName().c_str(), allocSize, FAKE_POINTER(memory));
72
73 return GST_MEMORY_CAST(memory);
74 }
75
gst_shmem_allocator_free(GstAllocator * allocator,GstMemory * memory)76 void gst_shmem_allocator_free(GstAllocator *allocator, GstMemory *memory)
77 {
78 g_return_if_fail(memory != nullptr && allocator != nullptr);
79 g_return_if_fail(gst_is_shmem_memory(memory));
80
81 GstShMemAllocator *sAlloctor = GST_SHMEM_ALLOCATOR_CAST(allocator);
82 g_return_if_fail(sAlloctor->avShmemPool != nullptr);
83
84 GstShMemMemory *avSharedMem = reinterpret_cast<GstShMemMemory *>(memory);
85 GST_LOG("free memory to %s for size: %" G_GSIZE_FORMAT ", gstmemory: 0x%06" PRIXPTR ", recount: %ld",
86 sAlloctor->avShmemPool->GetName().c_str(), memory->size, FAKE_POINTER(avSharedMem),
87 avSharedMem->mem.use_count());
88
89 // assign the nullptr will decrease the refcount, if the refcount is zero,
90 // the memory will be released back to pool.
91 avSharedMem->mem = nullptr;
92 g_slice_free(GstShMemMemory, avSharedMem);
93 }
94
gst_shmem_allocator_mem_map(GstMemory * mem,gsize maxsize,GstMapFlags flags)95 static gpointer gst_shmem_allocator_mem_map(GstMemory *mem, gsize maxsize, GstMapFlags flags)
96 {
97 (void)maxsize;
98 (void)flags;
99 g_return_val_if_fail(mem != nullptr, nullptr);
100 g_return_val_if_fail(gst_is_shmem_memory(mem), nullptr);
101
102 GstShMemMemory *avSharedMem = reinterpret_cast<GstShMemMemory *>(mem);
103 g_return_val_if_fail(avSharedMem->mem != nullptr, nullptr);
104
105 return avSharedMem->mem->GetBase();
106 }
107
gst_shmem_allocator_mem_unmap(GstMemory * mem)108 static void gst_shmem_allocator_mem_unmap(GstMemory *mem)
109 {
110 (void)mem;
111 }
112
gst_shmem_allocator_mem_copy(GstShMemMemory * mem,gssize offset,gssize size)113 static GstMemory *gst_shmem_allocator_mem_copy(GstShMemMemory *mem, gssize offset, gssize size)
114 {
115 g_return_val_if_fail(mem != nullptr && mem->mem != nullptr, nullptr);
116 g_return_val_if_fail(mem->mem->GetBase() != nullptr, nullptr);
117
118 gssize realOffset = 0;
119 if (((gint64)mem->parent.offset + offset) > INT32_MAX) {
120 GST_ERROR("invalid offset");
121 return nullptr;
122 } else {
123 realOffset = static_cast<gssize>(mem->parent.offset) + offset;
124 }
125 g_return_val_if_fail(realOffset >= 0, nullptr);
126
127 if (size == -1) {
128 if (((gint64)mem->parent.size - offset) > INT32_MAX) {
129 GST_ERROR("invalid size");
130 return nullptr;
131 } else {
132 size = static_cast<gssize>(mem->parent.size) - offset;
133 }
134 }
135 g_return_val_if_fail(size > 0, nullptr);
136
137 if ((size < INT32_MAX) && ((INT32_MAX - size) <= realOffset)) {
138 GST_ERROR("invalid limit");
139 return nullptr;
140 }
141 gsize realLimit = static_cast<gsize>(size) + static_cast<gsize>(realOffset);
142 g_return_val_if_fail(realLimit <= static_cast<gsize>(mem->mem->GetSize()), nullptr);
143
144 GstMemory *copy = gst_allocator_alloc(nullptr, static_cast<gsize>(size), nullptr);
145 g_return_val_if_fail(copy != nullptr, nullptr);
146
147 GstMapInfo info = GST_MAP_INFO_INIT;
148 if (!gst_memory_map(copy, &info, GST_MAP_READ)) {
149 gst_memory_unref(copy);
150 GST_ERROR("map failed");
151 return nullptr;
152 }
153
154 uint8_t *src = mem->mem->GetBase() + realOffset;
155 errno_t rc = memcpy_s(info.data, info.size, src, static_cast<size_t>(size));
156 if (rc != EOK) {
157 GST_ERROR("memcpy failed");
158 gst_memory_unmap(copy, &info);
159 gst_memory_unref(copy);
160 return nullptr;
161 }
162
163 gst_memory_unmap(copy, &info);
164 GST_LOG("copy memory: 0x%06" PRIXPTR " for size: %" G_GSSIZE_FORMAT ", offset: %" G_GSSIZE_FORMAT
165 ", gstmemory: 0x%06" PRIXPTR, FAKE_POINTER(mem), size, offset, FAKE_POINTER(copy));
166
167 return copy;
168 }
169
gst_shmem_allocator_mem_share(GstMemory * mem,gssize offset,gssize size)170 static GstShMemMemory *gst_shmem_allocator_mem_share(GstMemory *mem, gssize offset, gssize size)
171 {
172 g_return_val_if_fail(mem != nullptr, nullptr);
173 g_return_val_if_fail(offset >= 0 && static_cast<gsize>(offset) < mem->size, nullptr);
174 GstShMemMemory *shmem = reinterpret_cast<GstShMemMemory *>(mem);
175 g_return_val_if_fail(shmem->mem != nullptr, nullptr);
176
177 GstMemory *parent = mem->parent;
178 if (parent == nullptr) {
179 parent = GST_MEMORY_CAST(mem);
180 }
181 size = size == -1 ? static_cast<gssize>(mem->size) - offset : size;
182
183 GstShMemMemory *sub = reinterpret_cast<GstShMemMemory *>(g_slice_alloc0(sizeof(GstShMemMemory)));
184 g_return_val_if_fail(sub != nullptr, nullptr);
185
186 GstMemoryFlags flags = static_cast<GstMemoryFlags>(GST_MEMORY_FLAGS(parent) | GST_MEMORY_FLAG_READONLY);
187 gst_memory_init(GST_MEMORY_CAST(sub), flags, mem->allocator, parent, mem->maxsize,
188 mem->align, mem->offset + offset, size);
189 sub->mem = shmem->mem;
190
191 GST_LOG("share memory 0x%06" PRIXPTR " for size: %" G_GSSIZE_FORMAT ", offset: %" G_GSSIZE_FORMAT
192 ", addr: 0x%06" PRIXPTR ", refcount: %ld",
193 FAKE_POINTER(mem), size, offset, FAKE_POINTER(sub), sub->mem.use_count());
194
195 return sub;
196 }
197
gst_shmem_allocator_is_span(GstShMemMemory * mem1,GstShMemMemory * mem2,gsize * offset)198 static gboolean gst_shmem_allocator_is_span(GstShMemMemory *mem1, GstShMemMemory *mem2, gsize *offset)
199 {
200 g_return_val_if_fail(mem1 != nullptr && mem1->mem != nullptr, FALSE);
201 g_return_val_if_fail(mem2 != nullptr && mem2->mem != nullptr, FALSE);
202
203 if (mem1->mem != mem2->mem) {
204 return FALSE;
205 }
206
207 if (offset != nullptr) {
208 GstShMemMemory *parent = reinterpret_cast<GstShMemMemory *>(mem1->parent.parent);
209 if (parent != nullptr) {
210 *offset = mem1->parent.offset - parent->parent.offset;
211 }
212 }
213
214 return mem1->mem->GetBase() + mem1->parent.offset + mem1->parent.size ==
215 mem2->mem->GetBase() + mem2->parent.offset;
216 }
217
gst_shmem_allocator_init(GstShMemAllocator * allocator)218 static void gst_shmem_allocator_init(GstShMemAllocator *allocator)
219 {
220 GstAllocator *bAllocator = GST_ALLOCATOR_CAST(allocator);
221 g_return_if_fail(bAllocator != nullptr);
222
223 GST_DEBUG_OBJECT(allocator, "init allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
224
225 bAllocator->mem_type = GST_SHMEM_MEMORY_TYPE;
226 bAllocator->mem_map = (GstMemoryMapFunction)gst_shmem_allocator_mem_map;
227 bAllocator->mem_unmap = (GstMemoryUnmapFunction)gst_shmem_allocator_mem_unmap;
228 bAllocator->mem_copy = (GstMemoryCopyFunction)gst_shmem_allocator_mem_copy;
229 bAllocator->mem_share = (GstMemoryShareFunction)gst_shmem_allocator_mem_share;
230 bAllocator->mem_is_span = (GstMemoryIsSpanFunction)gst_shmem_allocator_is_span;
231 }
232
gst_shmem_allocator_finalize(GObject * obj)233 static void gst_shmem_allocator_finalize(GObject *obj)
234 {
235 GstShMemAllocator *allocator = GST_SHMEM_ALLOCATOR_CAST(obj);
236 g_return_if_fail(allocator != nullptr);
237
238 GST_DEBUG_OBJECT(allocator, "finalize allocator 0x%06" PRIXPTR "", FAKE_POINTER(allocator));
239 allocator->avShmemPool = nullptr;
240 G_OBJECT_CLASS(parent_class)->finalize(obj);
241 }
242
gst_shmem_allocator_class_init(GstShMemAllocatorClass * klass)243 static void gst_shmem_allocator_class_init(GstShMemAllocatorClass *klass)
244 {
245 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
246 g_return_if_fail(gobjectClass != nullptr);
247
248 gobjectClass->finalize = gst_shmem_allocator_finalize;
249
250 GstAllocatorClass *allocatorClass = GST_ALLOCATOR_CLASS(klass);
251 g_return_if_fail(allocatorClass != nullptr);
252
253 allocatorClass->alloc = gst_shmem_allocator_alloc;
254 allocatorClass->free = gst_shmem_allocator_free;
255
256 GST_DEBUG_CATEGORY_INIT(gst_shmem_allocator_debug_category, "shmemalloc", 0, "shmemalloc class");
257 }
258