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