• 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_pool.h"
17 #include "gst/video/gstvideometa.h"
18 #include "gst_shmem_allocator.h"
19 #include "media_log.h"
20 #include "media_errors.h"
21 #include "buffer_type_meta.h"
22 #include "avsharedmemorybase.h"
23 #include "scope_guard.h"
24 using namespace OHOS;
25 
26 #define GST_BUFFER_POOL_LOCK(pool) (g_mutex_lock(&pool->lock))
27 #define GST_BUFFER_POOL_UNLOCK(pool) (g_mutex_unlock(&pool->lock))
28 
29 #define gst_shmem_pool_parent_class parent_class
30 G_DEFINE_TYPE(GstShMemPool, gst_shmem_pool, GST_TYPE_BUFFER_POOL);
31 
32 static void gst_shmem_pool_finalize(GObject *obj);
33 static const gchar **gst_shmem_pool_get_options(GstBufferPool *pool);
34 static gboolean gst_shmem_pool_set_config(GstBufferPool *pool, GstStructure *config);
35 static gboolean gst_shmem_pool_start(GstBufferPool *pool);
36 static gboolean gst_shmem_pool_stop(GstBufferPool *pool);
37 static GstFlowReturn gst_shmem_pool_alloc_buffer(GstBufferPool *pool,
38     GstBuffer **buffer, GstBufferPoolAcquireParams *params);
39 static void gst_shmem_pool_free_buffer(GstBufferPool *pool, GstBuffer *buffer);
40 static GstFlowReturn gst_shmem_pool_acquire_buffer(GstBufferPool *pool,
41     GstBuffer **buffer, GstBufferPoolAcquireParams *params);
42 static void gst_shmem_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer);
43 static void gst_shmem_pool_memory_available(GstBufferPool *pool);
44 
45 GST_DEBUG_CATEGORY_STATIC(gst_shmem_pool_debug_category);
46 #define GST_CAT_DEFAULT gst_shmem_pool_debug_category
47 
gst_shmem_pool_class_init(GstShMemPoolClass * klass)48 static void gst_shmem_pool_class_init(GstShMemPoolClass *klass)
49 {
50     g_return_if_fail(klass != nullptr);
51     GstBufferPoolClass *poolClass = GST_BUFFER_POOL_CLASS(klass);
52     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
53 
54     gobjectClass->finalize = gst_shmem_pool_finalize;
55     poolClass->get_options = gst_shmem_pool_get_options;
56     poolClass->set_config = gst_shmem_pool_set_config;
57     poolClass->start = gst_shmem_pool_start;
58     poolClass->stop = gst_shmem_pool_stop;
59     poolClass->acquire_buffer = gst_shmem_pool_acquire_buffer;
60     poolClass->alloc_buffer = gst_shmem_pool_alloc_buffer;
61     poolClass->release_buffer = gst_shmem_pool_release_buffer;
62     poolClass->free_buffer = gst_shmem_pool_free_buffer;
63 
64     GST_DEBUG_CATEGORY_INIT(gst_shmem_pool_debug_category, "shmempool", 0, "shmempool class");
65 }
66 
gst_shmem_pool_init(GstShMemPool * pool)67 static void gst_shmem_pool_init(GstShMemPool *pool)
68 {
69     g_return_if_fail(pool != nullptr);
70 
71     pool->started = FALSE;
72     g_mutex_init(&pool->lock);
73     g_cond_init(&pool->cond);
74     pool->allocator = nullptr;
75     pool->minBuffers = 0;
76     pool->maxBuffers = 0;
77     pool->avshmempool = nullptr;
78     pool->addVideoMeta = FALSE;
79     gst_video_info_init(&pool->info);
80     pool->size = 0;
81     pool->curBuffers = 0;
82     pool->end = FALSE;
83     pool->debugName = g_strdup("");
84     gst_allocation_params_init(&pool->params);
85 
86     GST_DEBUG_OBJECT(pool, "init pool");
87 }
88 
gst_shmem_pool_finalize(GObject * obj)89 static void gst_shmem_pool_finalize(GObject *obj)
90 {
91     g_return_if_fail(obj != nullptr);
92     GstShMemPool *spool = GST_SHMEM_POOL_CAST(obj);
93     g_return_if_fail(spool != nullptr);
94 
95     if (spool->allocator != nullptr) {
96         gst_object_unref(spool->allocator);
97         spool->allocator = nullptr;
98     }
99 
100     g_mutex_clear(&spool->lock);
101     g_cond_clear(&spool->cond);
102     if (spool->avshmempool != nullptr) {
103         spool->avshmempool->Reset();
104         spool->avshmempool = nullptr;
105     }
106     spool->end = TRUE;
107     if (spool->debugName != nullptr) {
108         g_free(spool->debugName);
109         spool->debugName = nullptr;
110     }
111 
112     GST_DEBUG_OBJECT(spool, "finalize pool");
113     G_OBJECT_CLASS(parent_class)->finalize(obj);
114 }
115 
gst_shmem_pool_new()116 GstShMemPool *gst_shmem_pool_new()
117 {
118     GstShMemPool *pool = GST_SHMEM_POOL_CAST(g_object_new(
119         GST_TYPE_SHMEM_POOL, "name", "ShMemPool", nullptr));
120     (void)gst_object_ref_sink(pool);
121 
122     return pool;
123 }
124 
gst_shmem_pool_get_options(GstBufferPool * pool)125 static const gchar **gst_shmem_pool_get_options(GstBufferPool *pool)
126 {
127     // add buffer type meta option at here
128     (void)pool;
129     static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, nullptr };
130     return options;
131 }
132 
gst_shmem_pool_set_avshmempool(GstShMemPool * pool,const std::shared_ptr<OHOS::Media::AVSharedMemoryPool> & avshmempool)133 gboolean gst_shmem_pool_set_avshmempool(GstShMemPool *pool,
134                                         const std::shared_ptr<OHOS::Media::AVSharedMemoryPool> &avshmempool)
135 {
136     g_return_val_if_fail(pool != nullptr && avshmempool != nullptr, FALSE);
137 
138     GST_BUFFER_POOL_LOCK(pool);
139     ON_SCOPE_EXIT(0) { GST_BUFFER_POOL_UNLOCK(pool); };
140     g_return_val_if_fail(!pool->started, FALSE);
141 
142     g_return_val_if_fail(pool->avshmempool == nullptr, FALSE);
143     pool->avshmempool = avshmempool;
144 
145     if (pool->debugName != nullptr) {
146         g_free(pool->debugName);
147         pool->debugName = g_strdup(avshmempool->GetName().c_str());
148     }
149 
150     return TRUE;
151 }
152 
parse_caps_for_raw_video(GstShMemPool * spool,GstCaps * caps,guint * size)153 static gboolean parse_caps_for_raw_video(GstShMemPool *spool, GstCaps *caps, guint *size)
154 {
155     GstStructure *structure = gst_caps_get_structure(caps, 0);
156     g_return_val_if_fail(structure != nullptr, FALSE);
157     if (gst_structure_has_name(structure, "video/x-raw")) {
158         GstVideoInfo info;
159         gboolean ret = gst_video_info_from_caps(&info, caps);
160         g_return_val_if_fail(ret, FALSE);
161         *size = info.size > *size ? info.size : *size;
162         GST_INFO("this is video raw scene");
163         spool->info = info;
164         spool->addVideoMeta = TRUE;
165         return TRUE;
166     }
167 
168     return FALSE;
169 }
170 
gst_shmem_pool_set_config(GstBufferPool * pool,GstStructure * config)171 static gboolean gst_shmem_pool_set_config(GstBufferPool *pool, GstStructure *config)
172 {
173     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
174     g_return_val_if_fail(spool != nullptr, FALSE);
175     g_return_val_if_fail(config != nullptr, FALSE);
176 
177     GstCaps *caps = nullptr;
178     guint size;
179     guint minBuffers;
180     guint maxBuffers;
181     static constexpr guint defaultMaxBuffers = 10;
182     g_return_val_if_fail(gst_buffer_pool_config_get_params(config, &caps, &size, &minBuffers, &maxBuffers),
183         FALSE);
184     g_return_val_if_fail(minBuffers <= maxBuffers, FALSE);
185 
186     GST_BUFFER_POOL_LOCK(spool);
187 
188     spool->minBuffers = minBuffers;
189     spool->maxBuffers = maxBuffers > 0 ? maxBuffers : defaultMaxBuffers;
190     parse_caps_for_raw_video(spool, caps, &size);
191     spool->size = size;
192 
193     GstAllocator *allocator = nullptr;
194     GstAllocationParams params;
195     (void)gst_buffer_pool_config_get_allocator(config, &allocator, &params);
196     ON_SCOPE_EXIT(0) { GST_BUFFER_POOL_UNLOCK(spool); };
197     g_return_val_if_fail(allocator != nullptr && GST_IS_SHMEM_ALLOCATOR(allocator), FALSE);
198     GST_INFO("set config, size: %u, min_bufs: %u, max_bufs: %u", size, minBuffers, maxBuffers);
199 
200     if (spool->allocator != nullptr) {
201         gst_object_unref(spool->allocator);
202     }
203     spool->allocator = GST_SHMEM_ALLOCATOR_CAST(gst_object_ref(allocator));
204     spool->params = params;
205     CANCEL_SCOPE_EXIT_GUARD(0);
206     GST_BUFFER_POOL_UNLOCK(spool);
207 
208     // modify the minBuffers to zero, we preallocate buffer by the avshmempool's memory available notifier.
209     gst_buffer_pool_config_set_params(config, caps, size, 0, maxBuffers);
210     GST_BUFFER_POOL_CLASS(parent_class)->set_config(pool, config);
211     return TRUE;
212 }
213 
gst_shmem_pool_start(GstBufferPool * pool)214 static gboolean gst_shmem_pool_start(GstBufferPool *pool)
215 {
216     g_return_val_if_fail(pool != nullptr, FALSE);
217     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
218     g_return_val_if_fail(spool != nullptr, FALSE);
219 
220     GST_DEBUG("pool start");
221 
222     GST_BUFFER_POOL_LOCK(spool);
223     ON_SCOPE_EXIT(0) { GST_BUFFER_POOL_UNLOCK(spool); };
224     g_return_val_if_fail(spool->avshmempool != nullptr, FALSE);
225 
226     // clear the configuration carried in the avshmempool
227     spool->avshmempool->Reset();
228     auto notifier = [pool]() {
229         gst_shmem_pool_memory_available(pool);
230     };
231 
232     static constexpr uint32_t alignBytes = 4;
233     gsize alignedPrefix = (spool->params.prefix + alignBytes - 1) & ~(alignBytes - 1);
234     OHOS::Media::AVSharedMemoryPool::InitializeOption option = {
235         .preAllocMemCnt = spool->minBuffers,
236         .memSize = spool->size + alignedPrefix,
237         .maxMemCnt = spool->maxBuffers,
238         .notifier = notifier,
239     };
240 
241     int32_t ret = spool->avshmempool->Init(option);
242     g_return_val_if_fail(ret == OHOS::Media::MSERR_OK, FALSE);
243 
244     // Always force to non-blocking way to alloc shared memory if we use the gstbuferpool's memory manage.
245     spool->avshmempool->SetNonBlocking(true);
246     gst_shmem_allocator_set_pool(spool->allocator, spool->avshmempool);
247 
248     gboolean rc = GST_BUFFER_POOL_CLASS(parent_class)->start(pool);
249     g_return_val_if_fail(rc, rc);
250 
251     spool->started = TRUE;
252     return TRUE;
253 }
254 
gst_shmem_pool_stop(GstBufferPool * pool)255 static gboolean gst_shmem_pool_stop(GstBufferPool *pool)
256 {
257     g_return_val_if_fail(pool != nullptr, FALSE);
258     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
259     g_return_val_if_fail(spool != nullptr, FALSE);
260     if (spool->end) {
261         return GST_BUFFER_POOL_CLASS(parent_class)->stop(pool);
262     }
263 
264     GST_DEBUG("pool stop");
265     GST_BUFFER_POOL_LOCK(spool);
266     spool->started = FALSE;
267     if (spool->avshmempool != nullptr) {
268         spool->avshmempool->Reset();
269     }
270 
271     gboolean ret = GST_BUFFER_POOL_CLASS(parent_class)->stop(pool);
272     GST_DEBUG("parent class stop ret: %d, ret", ret);
273     ret = ret && (g_atomic_int_get(&spool->curBuffers) == 0);
274     GST_DEBUG("stop pool, curBuffers: %d, maxBuffers: %u", spool->curBuffers, spool->maxBuffers);
275 
276     // leave all configuration unchanged.
277     GST_BUFFER_POOL_UNLOCK(spool);
278     return ret;
279 }
280 
add_meta_to_buffer(GstShMemPool * spool,GstBuffer * buffer,GstShMemMemory * memory)281 static GstFlowReturn add_meta_to_buffer(GstShMemPool *spool, GstBuffer *buffer, GstShMemMemory *memory)
282 {
283     if (spool->addVideoMeta) {
284         GstVideoInfo *info = &spool->info;
285         gst_buffer_add_video_meta(buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT(info),
286             GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info));
287     }
288 
289     auto mem = std::static_pointer_cast<OHOS::Media::AVSharedMemoryBase>(memory->mem);
290     g_return_val_if_fail(mem != nullptr, GST_FLOW_ERROR);
291 
292     AVShmemFlags flag = FLAGS_READ_WRITE;
293     flag = mem->GetFlags() == OHOS::Media::AVSharedMemory::FLAGS_READ_ONLY ? FLAGS_READ_ONLY : flag;
294 
295     GstBufferFdConfig config = { sizeof(mem->GetFd()), 0, mem->GetSize(), mem->GetSize(), flag, 0 };
296     gst_buffer_add_buffer_fd_meta(buffer, mem->GetFd(), config);
297 
298     return GST_FLOW_OK;
299 }
300 
gst_shmem_pool_alloc_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)301 static GstFlowReturn gst_shmem_pool_alloc_buffer(GstBufferPool *pool,
302     GstBuffer **buffer, GstBufferPoolAcquireParams *params)
303 {
304     (void)params;
305     g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
306     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
307     g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
308     GstFlowReturn ret = GST_FLOW_OK;
309 
310     GstShMemMemory *memory = reinterpret_cast<GstShMemMemory *>(
311         gst_allocator_alloc(GST_ALLOCATOR_CAST(spool->allocator), spool->size, &spool->params));
312     g_return_val_if_fail(memory != nullptr, GST_FLOW_EOS);
313 
314     *buffer = gst_buffer_new();
315     if (*buffer == nullptr) {
316         GST_ERROR("alloc gst buffer failed");
317         gst_allocator_free(GST_ALLOCATOR_CAST(spool->allocator), reinterpret_cast<GstMemory *>(memory));
318         return GST_FLOW_ERROR;
319     }
320 
321     gst_buffer_append_memory(*buffer, reinterpret_cast<GstMemory *>(memory));
322 
323     ret = add_meta_to_buffer(spool, *buffer, memory);
324     if (ret != GST_FLOW_OK) {
325         gst_buffer_unref(*buffer);
326         return ret;
327     }
328 
329     GST_LOG("alloc buffer ok, 0x%06" PRIXPTR " from pool %s", FAKE_POINTER(*buffer), spool->debugName);
330     g_atomic_int_add(&spool->curBuffers, 1);
331     return GST_FLOW_OK;
332 }
333 
gst_shmem_pool_free_buffer(GstBufferPool * pool,GstBuffer * buffer)334 static void gst_shmem_pool_free_buffer(GstBufferPool *pool, GstBuffer *buffer)
335 {
336     g_return_if_fail(pool != nullptr);
337     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
338     g_return_if_fail(buffer != nullptr);
339 
340     gst_buffer_unref(buffer);
341     g_atomic_int_add(&spool->curBuffers, -1);
342     GST_LOG("free buffer ok, 0x%06" PRIXPTR ", from pool %s", FAKE_POINTER(buffer), spool->debugName);
343 }
344 
gst_shmem_pool_acquire_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)345 static GstFlowReturn gst_shmem_pool_acquire_buffer(GstBufferPool *pool,
346     GstBuffer **buffer, GstBufferPoolAcquireParams *params)
347 {
348     g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
349     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
350     g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
351 
352     GST_LOG("acquire buffer from pool 0x%06" PRIXPTR " %s before", FAKE_POINTER(pool), spool->debugName);
353     GstFlowReturn ret = GST_BUFFER_POOL_CLASS(parent_class)->acquire_buffer(pool, buffer, params);
354 
355     // The GstBufferPool will add the GstBuffer's pool ref to this pool.
356     GST_LOG("acquire buffer from pool 0x%06" PRIXPTR " %s after", FAKE_POINTER(pool), spool->debugName);
357     return ret;
358 }
359 
gst_shmem_pool_release_buffer(GstBufferPool * pool,GstBuffer * buffer)360 static void gst_shmem_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer)
361 {
362     // The GstBufferPool has already cleared the GstBuffer's pool ref to this pool.
363     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
364     g_return_if_fail(spool != nullptr);
365     GST_LOG("release buffer 0x%06" PRIXPTR " to pool 0x%06" PRIXPTR " %s",
366         FAKE_POINTER(buffer), FAKE_POINTER(pool), spool->debugName);
367 
368     GST_BUFFER_POOL_CLASS(parent_class)->release_buffer(pool, buffer);
369 }
370 
gst_shmem_pool_memory_available(GstBufferPool * pool)371 static void gst_shmem_pool_memory_available(GstBufferPool *pool)
372 {
373     g_return_if_fail(pool != nullptr);
374 
375     GstShMemPool *spool = GST_SHMEM_POOL_CAST(pool);
376     GST_DEBUG("pool memory available, currBuffers: %d", g_atomic_int_get(&spool->curBuffers));
377 
378     GstBuffer *buffer = nullptr;
379     GstBufferPoolAcquireParams params = { GST_FORMAT_DEFAULT, 0, 0, GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT, {} };
380     GstFlowReturn ret = gst_shmem_pool_acquire_buffer(pool, &buffer, &params);
381 
382     GST_DEBUG("memory available, fake acquire ret: %s", gst_flow_get_name(ret));
383     // Get buffer maybe fail f there ary any others getting buffer concurringly.
384     g_return_if_fail(ret == GST_FLOW_OK);
385 
386     gst_shmem_pool_release_buffer(pool, buffer);
387 }
388