• 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_shared_mem_sink.h"
17 #include <cinttypes>
18 #include "gst_shmem_pool.h"
19 #include "avsharedmemorypool.h"
20 #include "media_log.h"
21 #include "media_errors.h"
22 #include "buffer_type_meta.h"
23 
24 namespace {
25     constexpr guint32 DEFAULT_PROP_MEM_SIZE = 0; // 0 is meanless
26     constexpr guint32 DEFAULT_PROP_MEM_PREFIX_SIZE = 0;
27 }
28 
29 struct _GstSharedMemSinkPrivate {
30     guint mem_size;
31     guint mem_prefix_size;
32     GstShMemPool *pool;
33     GstShMemAllocator *allocator;
34     GstAllocationParams alloc_params;
35     std::shared_ptr<OHOS::Media::AVSharedMemoryPool> av_shmem_pool;
36     gboolean set_pool_for_allocator;
37     GMutex mutex;
38     GCond cond;
39     gboolean unlock;
40     gboolean flushing;
41     GstCaps *caps;
42 };
43 
44 enum {
45     PROP_0,
46     PROP_MEM_SIZE,
47     PROP_MEM_PREFIX_SIZE,
48 };
49 
50 static void gst_shared_mem_sink_dispose(GObject *obj);
51 static void gst_shared_mem_sink_finalize(GObject *obj);
52 static void gst_shared_mem_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec);
53 static void gst_shared_mem_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec);
54 static gboolean gst_shared_mem_sink_do_propose_allocation(GstMemSink *memsink, GstQuery *query);
55 static GstFlowReturn gst_shared_mem_sink_do_stream_render(GstMemSink *memsink, GstBuffer **buffer);
56 static gboolean gst_shared_mem_sink_unlock_start(GstBaseSink *bsink);
57 static gboolean gst_shared_mem_sink_unlock_stop(GstBaseSink *bsink);
58 static gboolean gst_shared_mem_sink_start(GstBaseSink *bsink);
59 static gboolean gst_shared_mem_sink_stop(GstBaseSink *bsink);
60 static guint caculate_mem_size_from_caps(GstSharedMemSink *memsink, GstCaps *caps);
61 static gboolean gst_shared_mem_sink_event(GstBaseSink *bsink, GstEvent *event);
62 
63 #define gst_shared_mem_sink_parent_class parent_class
64 G_DEFINE_TYPE_WITH_CODE(GstSharedMemSink, gst_shared_mem_sink,
65                         GST_TYPE_MEM_SINK, G_ADD_PRIVATE(GstSharedMemSink));
66 
67 GST_DEBUG_CATEGORY_STATIC(gst_shmem_sink_debug_category);
68 #define GST_CAT_DEFAULT gst_shmem_sink_debug_category
69 
gst_shared_mem_sink_class_init(GstSharedMemSinkClass * klass)70 static void gst_shared_mem_sink_class_init(GstSharedMemSinkClass *klass)
71 {
72     g_return_if_fail(klass != nullptr);
73 
74     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
75     GstMemSinkClass *mem_sink_class = GST_MEM_SINK_CLASS(klass);
76     GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
77     GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS(klass);
78 
79     gobject_class->dispose = gst_shared_mem_sink_dispose;
80     gobject_class->finalize = gst_shared_mem_sink_finalize;
81     gobject_class->set_property = gst_shared_mem_sink_set_property;
82     gobject_class->get_property = gst_shared_mem_sink_get_property;
83 
84     g_object_class_install_property(gobject_class, PROP_MEM_SIZE,
85         g_param_spec_uint("mem-size", "Memory Size",
86             "Allocate the memory with required length (in bytes)",
87             0, G_MAXUINT, DEFAULT_PROP_MEM_SIZE,
88             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
89 
90     g_object_class_install_property(gobject_class, PROP_MEM_PREFIX_SIZE,
91         g_param_spec_uint("mem-prefix-size", "Memory Prefix Size",
92             "Allocate the memory with required length's prefix (in bytes)",
93             0, G_MAXUINT, DEFAULT_PROP_MEM_PREFIX_SIZE,
94             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
95 
96     gst_element_class_set_static_metadata(element_class,
97         "ShMemSink", "Sink/Generic",
98         "Output to multi-process shared memory and allow the application to get access to the shared memory",
99         "OpenHarmony");
100 
101     base_sink_class->unlock = gst_shared_mem_sink_unlock_start;
102     base_sink_class->unlock_stop = gst_shared_mem_sink_unlock_stop;
103     base_sink_class->start = gst_shared_mem_sink_start;
104     base_sink_class->stop = gst_shared_mem_sink_stop;
105     base_sink_class->event = gst_shared_mem_sink_event;
106 
107     mem_sink_class->do_propose_allocation = gst_shared_mem_sink_do_propose_allocation;
108     mem_sink_class->do_stream_render = gst_shared_mem_sink_do_stream_render;
109 
110     GST_DEBUG_CATEGORY_INIT(gst_shmem_sink_debug_category, "shmemsink", 0, "shmemsink class");
111 }
112 
gst_shared_mem_sink_init(GstSharedMemSink * sink)113 static void gst_shared_mem_sink_init(GstSharedMemSink *sink)
114 {
115     g_return_if_fail(sink != nullptr);
116 
117     auto priv = reinterpret_cast<GstSharedMemSinkPrivate *>(gst_shared_mem_sink_get_instance_private(sink));
118     g_return_if_fail(priv != nullptr);
119     sink->priv = priv;
120     priv->mem_size = DEFAULT_PROP_MEM_SIZE;
121     priv->mem_prefix_size = DEFAULT_PROP_MEM_PREFIX_SIZE;
122     gst_allocation_params_init(&priv->alloc_params);
123     priv->allocator = gst_shmem_allocator_new();
124     priv->set_pool_for_allocator = FALSE;
125     g_mutex_init(&priv->mutex);
126     g_cond_init(&priv->cond);
127     priv->unlock = FALSE;
128     priv->flushing = FALSE;
129     priv->caps = nullptr;
130 }
131 
gst_shared_mem_sink_dispose(GObject * obj)132 static void gst_shared_mem_sink_dispose(GObject *obj)
133 {
134     g_return_if_fail(obj != nullptr);
135 
136     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(obj);
137     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
138     g_return_if_fail(priv != nullptr);
139 
140     GST_OBJECT_LOCK(shmem_sink);
141     if (priv->allocator != nullptr) {
142         gst_object_unref(priv->allocator);
143         priv->allocator = nullptr;
144     }
145     if (priv->pool != nullptr) {
146         gst_object_unref(priv->pool);
147         priv->pool = nullptr;
148     }
149     if (priv->caps != nullptr) {
150         gst_caps_unref(priv->caps);
151         priv->caps = nullptr;
152     }
153     priv->av_shmem_pool = nullptr;
154     GST_OBJECT_UNLOCK(shmem_sink);
155 
156     G_OBJECT_CLASS(parent_class)->dispose(obj);
157 }
158 
gst_shared_mem_sink_finalize(GObject * obj)159 static void gst_shared_mem_sink_finalize(GObject *obj)
160 {
161     g_return_if_fail(obj != nullptr);
162     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(obj);
163     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
164     g_return_if_fail(priv != nullptr);
165 
166     g_mutex_clear(&priv->mutex);
167     g_cond_clear(&priv->cond);
168 
169     G_OBJECT_CLASS(parent_class)->finalize(obj);
170 }
171 
gst_shared_mem_sink_set_property(GObject * object,guint propId,const GValue * value,GParamSpec * pspec)172 static void gst_shared_mem_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
173 {
174     g_return_if_fail(object != nullptr && value != nullptr);
175 
176     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(object);
177     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
178     g_return_if_fail(priv != nullptr);
179 
180     switch (propId) {
181         case PROP_MEM_SIZE: {
182             GST_OBJECT_LOCK(shmem_sink);
183             priv->mem_size = g_value_get_uint(value);
184             GST_DEBUG_OBJECT(shmem_sink, "memory size: %u", priv->mem_size);
185             GST_OBJECT_UNLOCK(shmem_sink);
186             break;
187         }
188         case PROP_MEM_PREFIX_SIZE: {
189             GST_OBJECT_LOCK(shmem_sink);
190             priv->mem_prefix_size = g_value_get_uint(value);
191             priv->alloc_params.prefix = priv->mem_prefix_size;
192             GST_DEBUG_OBJECT(shmem_sink, "memory prefix size: %u", priv->mem_prefix_size);
193             GST_OBJECT_UNLOCK(shmem_sink);
194             break;
195         }
196         default:
197             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
198             break;
199     }
200 }
201 
gst_shared_mem_sink_get_property(GObject * object,guint propId,GValue * value,GParamSpec * pspec)202 static void gst_shared_mem_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
203 {
204     g_return_if_fail(object != nullptr);
205 
206     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(object);
207     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
208     g_return_if_fail(priv != nullptr);
209 
210     switch (propId) {
211         case PROP_MEM_SIZE: {
212             GST_OBJECT_LOCK(shmem_sink);
213             g_value_set_uint(value, priv->mem_size);
214             GST_OBJECT_UNLOCK(shmem_sink);
215             break;
216         }
217         case PROP_MEM_PREFIX_SIZE: {
218             GST_OBJECT_LOCK(shmem_sink);
219             g_value_set_uint(value, priv->mem_prefix_size);
220             GST_OBJECT_UNLOCK(shmem_sink);
221             break;
222         }
223         default:
224             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
225             break;
226     }
227 }
228 
gst_shared_mem_sink_unlock_start(GstBaseSink * bsink)229 static gboolean gst_shared_mem_sink_unlock_start(GstBaseSink *bsink)
230 {
231     g_return_val_if_fail(bsink != nullptr, FALSE);
232     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(bsink);
233     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
234     g_return_val_if_fail(priv != nullptr, FALSE);
235 
236     GST_INFO_OBJECT(shmem_sink, "we are unlock start");
237 
238     g_mutex_lock(&priv->mutex);
239     priv->unlock = TRUE;
240     g_cond_signal(&priv->cond);
241     g_mutex_unlock(&priv->mutex);
242 
243     return TRUE;
244 }
245 
gst_shared_mem_sink_unlock_stop(GstBaseSink * bsink)246 static gboolean gst_shared_mem_sink_unlock_stop(GstBaseSink *bsink)
247 {
248     g_return_val_if_fail(bsink != nullptr, FALSE);
249     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(bsink);
250     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
251     g_return_val_if_fail(priv != nullptr, FALSE);
252 
253     GST_INFO_OBJECT(shmem_sink, "we are unlock stop");
254 
255     g_mutex_lock(&priv->mutex);
256     priv->unlock = FALSE;
257     g_cond_signal(&priv->cond);
258     g_mutex_unlock(&priv->mutex);
259 
260     return TRUE;
261 }
262 
gst_shared_mem_sink_start(GstBaseSink * bsink)263 static gboolean gst_shared_mem_sink_start(GstBaseSink *bsink)
264 {
265     g_return_val_if_fail(bsink != nullptr, FALSE);
266     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(bsink);
267     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
268     g_return_val_if_fail(priv != nullptr, FALSE);
269 
270     GST_INFO_OBJECT(shmem_sink, "we are start");
271 
272     g_mutex_lock(&priv->mutex);
273     priv->flushing = FALSE;
274     g_mutex_unlock(&priv->mutex);
275 
276     return GST_BASE_SINK_CLASS(parent_class)->start(bsink);
277 }
278 
gst_shared_mem_sink_stop(GstBaseSink * bsink)279 static gboolean gst_shared_mem_sink_stop(GstBaseSink *bsink)
280 {
281     g_return_val_if_fail(bsink != nullptr, FALSE);
282     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(bsink);
283     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
284     g_return_val_if_fail(priv != nullptr, FALSE);
285 
286     GST_INFO_OBJECT(shmem_sink, "we are stop");
287 
288     g_mutex_lock(&priv->mutex);
289     priv->flushing = TRUE;
290     g_cond_signal(&priv->cond);
291     g_mutex_unlock(&priv->mutex);
292 
293     return GST_BASE_SINK_CLASS(parent_class)->stop(bsink);
294 }
295 
gst_shared_mem_sink_event(GstBaseSink * bsink,GstEvent * event)296 static gboolean gst_shared_mem_sink_event(GstBaseSink *bsink, GstEvent *event)
297 {
298     g_return_val_if_fail(bsink != nullptr, FALSE);
299     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(bsink);
300     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
301     g_return_val_if_fail(priv != nullptr, FALSE);
302 
303     switch (event->type) {
304         case GST_EVENT_CAPS : {
305             GstCaps *caps = nullptr;
306             gst_event_parse_caps(event, &caps);
307             g_return_val_if_fail(caps != nullptr, FALSE);
308             if (shmem_sink->priv->caps != nullptr) {
309                 gst_caps_unref(shmem_sink->priv->caps);
310             }
311             shmem_sink->priv->caps = gst_caps_ref(caps);
312             break;
313         }
314         default :
315             break;
316     }
317     return GST_BASE_SINK_CLASS(parent_class)->event(bsink, event);
318 }
319 
notify_memory_available(GstSharedMemSink * shmem_sink)320 static void notify_memory_available(GstSharedMemSink *shmem_sink)
321 {
322     g_return_if_fail(shmem_sink != nullptr);
323     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
324     g_return_if_fail(priv != nullptr);
325 
326     g_mutex_lock(&priv->mutex);
327     g_cond_signal(&priv->cond);
328     g_mutex_unlock(&priv->mutex);
329 }
330 
set_pool_for_allocator(GstSharedMemSink * shmem_sink,guint min_bufs,guint max_bufs,guint size)331 static gboolean set_pool_for_allocator(GstSharedMemSink *shmem_sink, guint min_bufs, guint max_bufs, guint size)
332 {
333     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
334 
335     if (priv->allocator == nullptr) {
336         return FALSE;
337     }
338 
339     if (priv->set_pool_for_allocator) {
340         return TRUE;
341     }
342 
343     if (size == 0) {
344         size = caculate_mem_size_from_caps(shmem_sink, nullptr);
345     }
346 
347     if (size == 0 || max_bufs == 0) {
348         GST_ERROR_OBJECT(shmem_sink, "need copy buffer, but the dest buf's size or pool capacity is not provided");
349         return FALSE;
350     }
351 
352     GST_DEBUG_OBJECT(shmem_sink, "min_bufs: %u, max_bufs: %u, size: %u", min_bufs, max_bufs, size);
353 
354     auto notifier = [shmem_sink]() {
355         notify_memory_available(shmem_sink);
356     };
357 
358     priv->av_shmem_pool = std::make_shared<OHOS::Media::AVSharedMemoryPool>("shmemsink");
359     OHOS::Media::AVSharedMemoryPool::InitializeOption option = {
360         .preAllocMemCnt = min_bufs,
361         .memSize = size,
362         .maxMemCnt = max_bufs,
363         .notifier = notifier,
364     };
365     int32_t ret = priv->av_shmem_pool->Init(option);
366     g_return_val_if_fail(ret == OHOS::Media::MSERR_OK, GST_FLOW_ERROR);
367 
368     priv->av_shmem_pool->SetNonBlocking(true);
369     gst_shmem_allocator_set_pool(priv->allocator, priv->av_shmem_pool);
370     priv->set_pool_for_allocator = TRUE;
371     return TRUE;
372 }
373 
do_allocate_buffer(GstSharedMemSink * shmem_sink,GstBuffer ** buffer)374 static GstFlowReturn do_allocate_buffer(GstSharedMemSink *shmem_sink, GstBuffer **buffer)
375 {
376     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
377     g_mutex_lock(&priv->mutex);
378 
379     while (!priv->flushing) {
380         GstMemory *memory = gst_allocator_alloc(GST_ALLOCATOR_CAST(priv->allocator),
381             priv->mem_size, &priv->alloc_params);
382         if (memory != nullptr) {
383             g_mutex_unlock(&priv->mutex);
384             *buffer = gst_buffer_new();
385             if (*buffer == nullptr) {
386                 GST_ERROR_OBJECT(shmem_sink, "buffer new failed");
387                 gst_allocator_free(GST_ALLOCATOR_CAST(priv->allocator), memory);
388                 return GST_FLOW_ERROR;
389             }
390             gst_buffer_append_memory(*buffer, memory);
391             return GST_FLOW_OK;
392         }
393 
394         if (priv->unlock) {
395             g_mutex_unlock(&priv->mutex);
396             GstFlowReturn ret = gst_base_sink_wait_preroll(GST_BASE_SINK(shmem_sink));
397             if (ret != GST_FLOW_OK) {
398                 GST_INFO_OBJECT(shmem_sink, "we are stopping");
399                 return ret;
400             }
401             g_mutex_lock(&priv->mutex);
402             continue;
403         }
404 
405         g_cond_wait(&priv->cond, &priv->mutex);
406     };
407 
408     g_mutex_unlock(&priv->mutex);
409     GST_INFO_OBJECT(shmem_sink, "we are flushing");
410     return GST_FLOW_FLUSHING;
411 }
412 
do_copy_buffer(GstSharedMemSink * shmem_sink,GstBuffer * in_buf,GstBuffer ** out_buf)413 static GstFlowReturn do_copy_buffer(GstSharedMemSink *shmem_sink, GstBuffer *in_buf, GstBuffer **out_buf)
414 {
415     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
416     GstMemSink *memsink = GST_MEM_SINK_CAST(shmem_sink);
417 
418     gboolean ret = set_pool_for_allocator(shmem_sink, 1, memsink->max_pool_capacity, priv->mem_size);
419     g_return_val_if_fail(ret, GST_FLOW_ERROR);
420 
421     GstFlowReturn flow_ret = do_allocate_buffer(shmem_sink, out_buf);
422     g_return_val_if_fail(flow_ret == GST_FLOW_OK, flow_ret);
423     g_return_val_if_fail(*out_buf != nullptr, GST_FLOW_ERROR);
424 
425     do {
426         ret = gst_buffer_copy_into(*out_buf, in_buf, GST_BUFFER_COPY_METADATA, 0, -1);
427         if (!ret) {
428             GST_ERROR_OBJECT(shmem_sink, "copy metadata from in_buf failed");
429             break;
430         }
431 
432         GstMapInfo info;
433         if (!gst_buffer_map(*out_buf, &info, GST_MAP_WRITE)) {
434             GST_ERROR_OBJECT(shmem_sink, "map buffer failed");
435             ret = FALSE;
436             break;
437         }
438 
439         gsize size = gst_buffer_get_size(in_buf);
440         if (info.size < size) {
441             gst_buffer_unmap(*out_buf, &info);
442             ret = FALSE;
443             break;
444         }
445         gsize writesize = gst_buffer_extract(in_buf, 0, info.data, size);
446         gst_buffer_unmap(*out_buf, &info);
447         if (writesize != size) {
448             GST_ERROR_OBJECT(shmem_sink, "extract buffer failed");
449             ret = FALSE;
450             break;
451         }
452         gst_buffer_resize(*out_buf, 0, size);
453     } while (0);
454 
455     if (!ret) {
456         gst_buffer_unref(*out_buf);
457         *out_buf = nullptr;
458         return GST_FLOW_ERROR;
459     }
460 
461     return GST_FLOW_OK;
462 }
463 
check_need_copy(GstSharedMemSink * shmem_sink,GstBuffer * buffer)464 static gboolean check_need_copy(GstSharedMemSink *shmem_sink, GstBuffer *buffer)
465 {
466     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
467 
468     if (buffer->pool != nullptr) {
469         if (buffer->pool != GST_BUFFER_POOL_CAST(priv->pool)) {
470             return TRUE;
471         }
472         return FALSE;
473     }
474 
475     if (priv->allocator != nullptr) {
476         GstMemory *memory = gst_buffer_peek_memory(buffer, 0);
477         if (memory == nullptr) {
478             return FALSE;
479         }
480         if (memory->allocator == GST_ALLOCATOR_CAST(priv->allocator)) {
481             return FALSE;
482         }
483     }
484 
485     return TRUE;
486 }
487 
gst_shared_mem_sink_do_stream_render(GstMemSink * memsink,GstBuffer ** buffer)488 static GstFlowReturn gst_shared_mem_sink_do_stream_render(GstMemSink *memsink, GstBuffer **buffer)
489 {
490     g_return_val_if_fail(memsink != nullptr && buffer != nullptr, GST_FLOW_ERROR);
491     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(memsink);
492     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
493     g_return_val_if_fail(priv != nullptr, GST_FLOW_ERROR);
494     GstBuffer *orig_buf = *buffer;
495     GstBuffer *out_buf = nullptr;
496 
497     if (gst_buffer_n_memory(orig_buf) != 1) {
498         GST_ERROR_OBJECT(shmem_sink, "buffer's memory chunks is not 1 !");
499         return GST_FLOW_ERROR;
500     }
501 
502     if (gst_buffer_peek_memory(orig_buf, 0) == nullptr) {
503         GST_ERROR_OBJECT(shmem_sink, "buffer's memory is nullptr !");
504         return GST_FLOW_ERROR;
505     }
506 
507     if (!check_need_copy(shmem_sink, orig_buf)) {
508         // To keep the user interface consistent with the scenario where the output
509         // buffer needs to be copied, reference counting needs to be added.
510         gst_buffer_ref(orig_buf);
511         return GST_FLOW_OK;
512     }
513 
514     GstFlowReturn ret = do_copy_buffer(shmem_sink, orig_buf, &out_buf);
515     g_return_val_if_fail(ret == GST_FLOW_OK, ret);
516 
517     *buffer = out_buf;
518     return GST_FLOW_OK;
519 }
520 
set_pool_for_propose_allocation(GstSharedMemSink * shmem_sink,GstQuery * query,GstCaps * caps)521 static gboolean set_pool_for_propose_allocation(GstSharedMemSink *shmem_sink, GstQuery *query, GstCaps *caps)
522 {
523     GstMemSink *memsink = GST_MEM_SINK_CAST(shmem_sink);
524     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
525 
526     guint size = 0;
527     guint min_buffers = 0;
528     guint max_buffers = 0;
529     gst_query_parse_nth_allocation_pool(query, 0, nullptr, &size, &min_buffers, &max_buffers);
530     if (max_buffers == 0) {
531         GST_INFO_OBJECT(shmem_sink, "correct the maxbuffer from %u to %u", max_buffers, memsink->max_pool_capacity);
532         max_buffers = memsink->max_pool_capacity;
533     }
534     if (size == 0) {
535         size = caculate_mem_size_from_caps(shmem_sink, caps);
536         GST_INFO_OBJECT(shmem_sink, "correct the size from 0 to %u", size);
537     }
538 
539     if (priv->pool != nullptr)  {
540         gst_object_unref(priv->pool);
541     }
542     priv->pool = gst_shmem_pool_new();
543     g_return_val_if_fail(priv->pool != nullptr, FALSE);
544     GstShMemPool *pool = priv->pool;
545     GstStructure *params = gst_structure_new("mem", "memtype", G_TYPE_STRING, "avshmem", nullptr);
546     gst_query_add_allocation_pool(query, GST_BUFFER_POOL_CAST(pool), size, min_buffers, max_buffers);
547     gst_query_add_allocation_meta(query, GST_BUFFER_TYPE_META_API_TYPE, params);
548     gst_structure_free(params);
549 
550     // the gstbufferpool will reconfig the av_shmem_pool when the gstbufferpool is activated.
551     (void)gst_shmem_pool_set_avshmempool(priv->pool, priv->av_shmem_pool);
552 
553     GstStructure *config = gst_buffer_pool_get_config(GST_BUFFER_POOL_CAST(pool));
554     g_return_val_if_fail(config != nullptr, FALSE);
555 
556     gst_buffer_pool_config_set_params(config, caps, size, min_buffers, max_buffers);
557     gst_buffer_pool_config_set_allocator(config, GST_ALLOCATOR_CAST(priv->allocator), &priv->alloc_params);
558 
559     return gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(pool), config);
560 }
561 
gst_shared_mem_sink_do_propose_allocation(GstMemSink * memsink,GstQuery * query)562 static gboolean gst_shared_mem_sink_do_propose_allocation(GstMemSink *memsink, GstQuery *query)
563 {
564     g_return_val_if_fail(memsink != nullptr && query != nullptr, FALSE);
565     GstSharedMemSink *shmem_sink = GST_SHARED_MEM_SINK_CAST(memsink);
566     GstSharedMemSinkPrivate *priv = shmem_sink->priv;
567     g_return_val_if_fail(priv != nullptr, FALSE);
568     g_return_val_if_fail(priv->allocator != nullptr, FALSE);
569 
570     GstCaps *caps = nullptr;
571     gboolean need_pool = FALSE;
572     priv->set_pool_for_allocator = FALSE;
573     gst_query_parse_allocation(query, &caps, &need_pool);
574 
575     GST_OBJECT_LOCK(shmem_sink);
576     gst_query_add_allocation_param(query, GST_ALLOCATOR_CAST(priv->allocator), &priv->alloc_params);
577 
578     // always set av_shmem_pool for allocator, in case that the upstream only use the
579     // gstallocator while the needpool is set.
580     gboolean ret = set_pool_for_allocator(shmem_sink, 1, memsink->max_pool_capacity, priv->mem_size);
581     if (!ret) {
582         GST_ERROR_OBJECT(shmem_sink, "set pool for allocator failed");
583         GST_OBJECT_UNLOCK(shmem_sink);
584         return ret;
585     }
586 
587     if (need_pool) {
588         ret = set_pool_for_propose_allocation(shmem_sink, query, caps);
589         if (!ret) {
590             GST_ERROR_OBJECT(shmem_sink, "config pool failed");
591         }
592     }
593 
594     GST_OBJECT_UNLOCK(shmem_sink);
595     return ret;
596 }
597 
caculate_mem_size_from_caps(GstSharedMemSink * memsink,GstCaps * caps)598 static guint caculate_mem_size_from_caps(GstSharedMemSink *memsink, GstCaps *caps)
599 {
600     if (memsink->priv->mem_size != 0) {
601         return memsink->priv->mem_size;
602     }
603 
604     if (caps == nullptr) {
605         caps = memsink->priv->caps;
606     }
607 
608     if (caps == nullptr) {
609         GST_WARNING_OBJECT(memsink, "caps is nullptr");
610         return 0;
611     }
612 
613     // currently, only video/x-raw mimetype supported
614     GstStructure *structure = gst_caps_get_structure(caps, 0);
615     if (!gst_structure_has_name(structure, "video/x-raw")) {
616         return 0;
617     }
618 
619     GstVideoInfo info;
620     if (!gst_video_info_from_caps(&info, caps)) {
621         return 0;
622     }
623 
624     guint size = static_cast<guint>(info.size);
625     GST_INFO_OBJECT(memsink, "caculate mem size: %u", size);
626 
627     return size;
628 }
629