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