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_producer_surface_pool.h"
17 #include <unordered_map>
18 #include <sys/time.h>
19 #include "media_log.h"
20 #include "display_type.h"
21 #include "surface_buffer.h"
22 #include "buffer_type_meta.h"
23 #include "gst_surface_allocator.h"
24 #include "gst/video/gstvideometa.h"
25 #include "media_dfx.h"
26 #include "securec.h"
27
28 namespace {
29 const std::unordered_map<GstVideoFormat, PixelFormat> FORMAT_MAPPING = {
30 { GST_VIDEO_FORMAT_RGBA, PIXEL_FMT_RGBA_8888 },
31 { GST_VIDEO_FORMAT_NV21, PIXEL_FMT_YCRCB_420_SP },
32 { GST_VIDEO_FORMAT_NV12, PIXEL_FMT_YCBCR_420_SP },
33 { GST_VIDEO_FORMAT_I420, PIXEL_FMT_YCBCR_420_P },
34 };
35 constexpr int32_t TIME_VAL_US = 1000000;
36 constexpr guint32 DEFAULT_PROP_DYNAMIC_BUFFER_NUM = 10;
37 }
38
39 enum {
40 PROP_0,
41 PROP_DYNAMIC_BUFFER_NUM,
42 PROP_CACHE_BUFFERS_NUM,
43 PROP_VIDEO_SCALE_TYPE,
44 };
45
46 #define GST_BUFFER_POOL_LOCK(pool) (g_mutex_lock(&(pool)->lock))
47 #define GST_BUFFER_POOL_UNLOCK(pool) (g_mutex_unlock(&(pool)->lock))
48 #define GST_BUFFER_POOL_WAIT(pool) (g_cond_wait(&(pool)->cond, &(pool)->lock))
49 #define GST_BUFFER_POOL_NOTIFY(pool) (g_cond_signal(&(pool)->cond))
50
51 #define gst_producer_surface_pool_parent_class parent_class
52 G_DEFINE_TYPE(GstProducerSurfacePool, gst_producer_surface_pool, GST_TYPE_BUFFER_POOL);
53
54 GST_DEBUG_CATEGORY_STATIC(gst_producer_surface_pool_debug_category);
55 #define GST_CAT_DEFAULT gst_producer_surface_pool_debug_category
56
57 static void gst_producer_surface_pool_finalize(GObject *obj);
58 static const gchar **gst_producer_surface_pool_get_options (GstBufferPool *pool);
59 static gboolean gst_producer_surface_pool_set_config(GstBufferPool *pool, GstStructure *config);
60 static gboolean gst_producer_surface_pool_start(GstBufferPool *pool);
61 static gboolean gst_producer_surface_pool_stop(GstBufferPool *pool);
62 static GstFlowReturn gst_producer_surface_pool_alloc_buffer(GstBufferPool *pool,
63 GstBuffer **buffer, GstBufferPoolAcquireParams *params);
64 static void gst_producer_surface_pool_free_buffer(GstBufferPool *pool, GstBuffer *buffer);
65 static GstFlowReturn gst_producer_surface_pool_acquire_buffer(GstBufferPool *pool,
66 GstBuffer **buffer, GstBufferPoolAcquireParams *params);
67 static void gst_producer_surface_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer);
68 static void gst_producer_surface_pool_flush_start(GstBufferPool *pool);
69 static void gst_producer_surface_pool_set_property(GObject *object, guint prop_id,
70 const GValue *value, GParamSpec *pspec);
71 static void gst_producer_surface_pool_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
72
clear_preallocated_buffer(GstProducerSurfacePool * spool)73 static void clear_preallocated_buffer(GstProducerSurfacePool *spool)
74 {
75 g_return_if_fail(spool != nullptr);
76 for (GList *node = g_list_first(spool->preAllocated); node != nullptr; node = g_list_next(node)) {
77 GstBuffer *buffer = GST_BUFFER_CAST(node->data);
78 if (buffer == nullptr) {
79 continue;
80 }
81 gst_producer_surface_pool_free_buffer(GST_BUFFER_POOL_CAST(spool), buffer);
82 }
83 g_list_free(spool->preAllocated);
84 spool->preAllocated = nullptr;
85 }
86
gst_producer_surface_pool_class_init(GstProducerSurfacePoolClass * klass)87 static void gst_producer_surface_pool_class_init(GstProducerSurfacePoolClass *klass)
88 {
89 g_return_if_fail(klass != nullptr);
90 GstBufferPoolClass *poolClass = GST_BUFFER_POOL_CLASS (klass);
91 GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
92 gobjectClass->set_property = gst_producer_surface_pool_set_property;
93 gobjectClass->get_property = gst_producer_surface_pool_get_property;
94 gobjectClass->finalize = gst_producer_surface_pool_finalize;
95
96 g_object_class_install_property(gobjectClass, PROP_DYNAMIC_BUFFER_NUM,
97 g_param_spec_uint("dynamic-buffer-num", "Dynamic Buffer Num",
98 "Dynamic set buffer num when pool is active",
99 0, G_MAXUINT, DEFAULT_PROP_DYNAMIC_BUFFER_NUM,
100 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
101
102 g_object_class_install_property(gobjectClass, PROP_CACHE_BUFFERS_NUM,
103 g_param_spec_uint("cache-buffers-num", "Cached Buffer Num",
104 "Set cached buffer nums for pool thread loop",
105 0, G_MAXUINT, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
106
107 g_object_class_install_property(gobjectClass, PROP_VIDEO_SCALE_TYPE,
108 g_param_spec_uint("video-scale-type", "Video Scale Type",
109 "Set video scale type for graphic",
110 0, G_MAXUINT, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
111
112 poolClass->get_options = gst_producer_surface_pool_get_options;
113 poolClass->set_config = gst_producer_surface_pool_set_config;
114 poolClass->start = gst_producer_surface_pool_start;
115 poolClass->stop = gst_producer_surface_pool_stop;
116 poolClass->acquire_buffer = gst_producer_surface_pool_acquire_buffer;
117 poolClass->alloc_buffer = gst_producer_surface_pool_alloc_buffer;
118 poolClass->release_buffer = gst_producer_surface_pool_release_buffer;
119 poolClass->free_buffer = gst_producer_surface_pool_free_buffer;
120 poolClass->flush_start = gst_producer_surface_pool_flush_start;
121 }
122
gst_producer_surface_pool_init(GstProducerSurfacePool * pool)123 static void gst_producer_surface_pool_init(GstProducerSurfacePool *pool)
124 {
125 g_return_if_fail(pool != nullptr);
126
127 GST_DEBUG_CATEGORY_INIT(gst_producer_surface_pool_debug_category, "surfacepool", 0, "gst surface pool for sink");
128
129 pool->surface = nullptr;
130 pool->started = FALSE;
131 g_mutex_init(&pool->lock);
132 g_cond_init(&pool->cond);
133 pool->allocator = nullptr;
134 pool->preAllocated = nullptr;
135 pool->minBuffers = 0;
136 pool->maxBuffers = 0;
137 pool->format = PixelFormat::PIXEL_FMT_BUTT;
138 pool->usage = 0;
139 gst_video_info_init(&pool->info);
140 gst_allocation_params_init(&pool->params);
141 pool->task = nullptr;
142 g_rec_mutex_init(&pool->taskLock);
143 (void)memset_s(&pool->beginTime, sizeof(timeval), 0, sizeof(timeval));
144 (void)memset_s(&pool->endTime, sizeof(timeval), 0, sizeof(timeval));
145 pool->callCnt = 0;
146 pool->isDynamicCached = FALSE;
147 pool->cachedBuffers = 0;
148 pool->scale_type = 1; // VIDEO_SCALE_TYPE_FIT_CROP
149 }
150
gst_producer_surface_pool_finalize(GObject * obj)151 static void gst_producer_surface_pool_finalize(GObject *obj)
152 {
153 g_return_if_fail(obj != nullptr);
154 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(obj);
155 GstBufferPool *pool = GST_BUFFER_POOL(obj);
156 g_return_if_fail(spool != nullptr);
157
158 clear_preallocated_buffer(spool);
159 (void)gst_buffer_pool_set_active(pool, FALSE);
160
161 spool->surface = nullptr;
162 gst_object_unref(spool->allocator);
163 spool->allocator = nullptr;
164 g_mutex_clear(&spool->lock);
165 g_cond_clear(&spool->cond);
166 g_rec_mutex_clear(&spool->taskLock);
167 if (spool->task != nullptr) {
168 gst_object_unref(spool->task);
169 spool->task = nullptr;
170 }
171
172 G_OBJECT_CLASS(parent_class)->finalize(obj);
173 }
174
gst_producer_surface_pool_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)175 static void gst_producer_surface_pool_set_property(GObject *object, guint prop_id,
176 const GValue *value, GParamSpec *pspec)
177 {
178 g_return_if_fail(object != nullptr);
179 g_return_if_fail(value != nullptr);
180 g_return_if_fail(pspec != nullptr);
181 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL(object);
182
183 switch (prop_id) {
184 case PROP_DYNAMIC_BUFFER_NUM: {
185 g_return_if_fail(spool->surface != nullptr);
186 guint dynamicBuffers = g_value_get_uint(value);
187 g_return_if_fail(dynamicBuffers != 0);
188 GST_BUFFER_POOL_LOCK(spool);
189 if (spool->freeBufCnt + dynamicBuffers < spool->maxBuffers) {
190 GST_BUFFER_POOL_UNLOCK(spool);
191 GST_ERROR_OBJECT(spool, "set queue size failed for free buffers %u", spool->freeBufCnt);
192 return;
193 }
194 spool->freeBufCnt += (dynamicBuffers - spool->maxBuffers);
195 spool->maxBuffers = dynamicBuffers;
196 OHOS::SurfaceError err = spool->surface->SetQueueSize(spool->maxBuffers);
197 if (err != OHOS::SurfaceError::SURFACE_ERROR_OK) {
198 GST_BUFFER_POOL_UNLOCK(spool);
199 GST_ERROR_OBJECT(spool, "set queue size to %u failed", spool->maxBuffers);
200 return;
201 }
202 GST_DEBUG_OBJECT(spool, "set max buffer count: %u", spool->maxBuffers);
203 GST_BUFFER_POOL_UNLOCK(spool);
204 break;
205 }
206 case PROP_CACHE_BUFFERS_NUM: {
207 GST_BUFFER_POOL_LOCK(spool);
208 guint cache_num = g_value_get_uint(value);
209 GST_DEBUG_OBJECT(spool, "set cache_num to: %u", cache_num);
210 if (cache_num == 0) {
211 spool->isDynamicCached = FALSE;
212 } else {
213 spool->isDynamicCached = TRUE;
214 spool->cachedBuffers = cache_num;
215 }
216 GST_BUFFER_POOL_UNLOCK(spool);
217 break;
218 }
219 case PROP_VIDEO_SCALE_TYPE: {
220 GST_BUFFER_POOL_LOCK(spool);
221 spool->scale_type = g_value_get_uint(value);
222 GST_BUFFER_POOL_UNLOCK(spool);
223 break;
224 }
225 default:
226 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
227 break;
228 }
229 }
230
gst_producer_surface_pool_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)231 static void gst_producer_surface_pool_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
232 {
233 g_return_if_fail(object != nullptr);
234 g_return_if_fail(value != nullptr);
235 g_return_if_fail(pspec != nullptr);
236 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL(object);
237
238 switch (prop_id) {
239 case PROP_DYNAMIC_BUFFER_NUM: {
240 GST_BUFFER_POOL_LOCK(spool);
241 g_value_set_uint(value, spool->maxBuffers);
242 GST_BUFFER_POOL_UNLOCK(spool);
243 break;
244 }
245 default:
246 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
247 break;
248 }
249 }
250
gst_producer_surface_pool_new(void)251 GstProducerSurfacePool *gst_producer_surface_pool_new(void)
252 {
253 GstProducerSurfacePool *pool = GST_PRODUCER_SURFACE_POOL_CAST(g_object_new(
254 GST_TYPE_PRODUCER_SURFACE_POOL, "name", "SurfacePool", nullptr));
255 (void)gst_object_ref_sink(pool);
256
257 return pool;
258 }
259
gst_producer_surface_pool_get_options(GstBufferPool * pool)260 static const gchar **gst_producer_surface_pool_get_options (GstBufferPool *pool)
261 {
262 // add buffer type meta option at here
263 (void)pool;
264 static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, nullptr };
265 return options;
266 }
267
parse_caps_info(GstCaps * caps,GstVideoInfo * info,PixelFormat * format)268 static gboolean parse_caps_info(GstCaps *caps, GstVideoInfo *info, PixelFormat *format)
269 {
270 if (caps == nullptr) {
271 GST_INFO("caps is nullptr");
272 return FALSE;
273 }
274
275 if (!gst_video_info_from_caps(info, caps)) {
276 GST_ERROR("wrong caps");
277 return FALSE;
278 }
279
280 if (FORMAT_MAPPING.count(GST_VIDEO_INFO_FORMAT(info)) == 0) {
281 GST_ERROR("unsupported format, %s", GST_VIDEO_INFO_NAME(info));
282 return FALSE;
283 }
284
285 *format = FORMAT_MAPPING.at(GST_VIDEO_INFO_FORMAT(info));
286 return TRUE;
287 }
288
parse_config_usage(GstProducerSurfacePool * spool,GstStructure * config)289 static gboolean parse_config_usage(GstProducerSurfacePool *spool, GstStructure *config)
290 {
291 g_return_val_if_fail(spool != nullptr, FALSE);
292 g_return_val_if_fail(config != nullptr, FALSE);
293 if (!gst_structure_get_uint64(config, "usage", &spool->usage)) {
294 GST_INFO_OBJECT(spool, "no usage available");
295 spool->usage = 0;
296 }
297 return TRUE;
298 }
299
gst_producer_surface_pool_set_config(GstBufferPool * pool,GstStructure * config)300 static gboolean gst_producer_surface_pool_set_config(GstBufferPool *pool, GstStructure *config)
301 {
302 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
303 g_return_val_if_fail(spool != nullptr, FALSE);
304 g_return_val_if_fail(config != nullptr, FALSE);
305
306 GstCaps *caps = nullptr;
307 guint size; // ignore the size
308 guint min_buffers;
309 guint max_buffers;
310 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers)) {
311 GST_ERROR_OBJECT(spool, "wrong config");
312 return FALSE;
313 }
314 g_return_val_if_fail(min_buffers <= max_buffers, FALSE);
315
316 GstVideoInfo info;
317 PixelFormat format;
318 if (!parse_caps_info(caps, &info, &format)) {
319 return FALSE;
320 }
321 g_return_val_if_fail(parse_config_usage(spool, config), FALSE);
322 GST_INFO_OBJECT(pool, "get usage %" G_GUINT64_FORMAT " ", spool->usage);
323
324 GST_BUFFER_POOL_LOCK(spool);
325
326 spool->info = info;
327 spool->format = format;
328 spool->minBuffers = min_buffers;
329 spool->maxBuffers = max_buffers;
330
331 GST_INFO_OBJECT(spool, "set config, width: %d, height: %d, format: %d, min_bufs: %u, max_bufs: %u",
332 GST_VIDEO_INFO_WIDTH(&info), GST_VIDEO_INFO_HEIGHT(&info), format, min_buffers, max_buffers);
333
334 GstAllocator *allocator = nullptr;
335 GstAllocationParams params;
336 (void)gst_buffer_pool_config_get_allocator(config, &allocator, ¶ms);
337 if (!(allocator && GST_IS_SURFACE_ALLOCATOR(allocator))) {
338 GST_BUFFER_POOL_UNLOCK(spool);
339 GST_WARNING_OBJECT(pool, "no valid allocator in pool");
340 return TRUE;
341 }
342 spool->allocator = GST_SURFACE_ALLOCATOR_CAST(allocator);
343 spool->params = params;
344
345 GST_INFO_OBJECT(spool, "update allocator and params");
346
347 GST_BUFFER_POOL_UNLOCK(spool);
348 return TRUE;
349 }
350
gst_producer_surface_pool_set_surface(GstProducerSurfacePool * pool,OHOS::sptr<OHOS::Surface> surface)351 gboolean gst_producer_surface_pool_set_surface(GstProducerSurfacePool *pool, OHOS::sptr<OHOS::Surface> surface)
352 {
353 g_return_val_if_fail(surface != nullptr, FALSE);
354 g_return_val_if_fail(pool != nullptr, FALSE);
355
356 GST_BUFFER_POOL_LOCK(pool);
357
358 if (pool->started) {
359 GST_INFO_OBJECT(pool, "started already, reject to set surface");
360 GST_BUFFER_POOL_UNLOCK(pool);
361 return FALSE;
362 }
363
364 if (pool->surface != nullptr) {
365 GST_INFO_OBJECT(pool, "surface has already been set");
366 GST_BUFFER_POOL_UNLOCK(pool);
367 return FALSE;
368 }
369
370 pool->surface = surface;
371
372 GST_BUFFER_POOL_UNLOCK(pool);
373 return TRUE;
374 }
375
gst_producer_surface_pool_statistics(GstProducerSurfacePool * spool)376 static void gst_producer_surface_pool_statistics(GstProducerSurfacePool *spool)
377 {
378 g_return_if_fail(spool != nullptr);
379 if (spool->callCnt == 0) {
380 gettimeofday(&(spool->beginTime), nullptr);
381 }
382 spool->callCnt++;
383 gettimeofday(&(spool->endTime), nullptr);
384 if ((spool->endTime.tv_sec * TIME_VAL_US + spool->endTime.tv_usec) -
385 (spool->beginTime.tv_sec * TIME_VAL_US + spool->beginTime.tv_usec) > TIME_VAL_US) {
386 OHOS::Media::MediaEvent event;
387 if (event.CreateMsg("The gst_producer_surface_pool_request_loop function is called in a second: %d",
388 spool->callCnt)) {
389 event.EventWrite("PLAYER_STATISTICS", OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "PLAYER");
390 spool->callCnt = 0;
391 } else {
392 GST_ERROR_OBJECT(spool, "Failed to call CreateMsg");
393 }
394 }
395 }
396
gst_producer_surface_pool_request_loop(GstProducerSurfacePool * spool)397 static void gst_producer_surface_pool_request_loop(GstProducerSurfacePool *spool)
398 {
399 g_return_if_fail(spool != nullptr);
400 GstBufferPool *pool = GST_BUFFER_POOL_CAST(spool);
401 GST_DEBUG_OBJECT(spool, "Loop In");
402
403 GST_BUFFER_POOL_LOCK(spool);
404 gst_producer_surface_pool_statistics(spool);
405
406 while (spool->isDynamicCached && g_list_length(spool->preAllocated) >= spool->cachedBuffers && spool->started) {
407 GST_BUFFER_POOL_WAIT(spool);
408 }
409
410 if (!spool->started) {
411 GST_BUFFER_POOL_UNLOCK(spool);
412 GST_WARNING_OBJECT(spool, "task is paused, exit");
413 gst_task_pause(spool->task);
414 return;
415 }
416 GST_BUFFER_POOL_UNLOCK(spool);
417
418 GstBuffer *buffer = nullptr;
419 GstFlowReturn ret = gst_producer_surface_pool_alloc_buffer(pool, &buffer, nullptr);
420 if (ret != GST_FLOW_OK) {
421 GST_WARNING_OBJECT(spool, "alloc buffer failed, exit");
422 gst_task_pause(spool->task);
423 GST_BUFFER_POOL_LOCK(spool);
424 spool->started = FALSE;
425 GST_BUFFER_POOL_NOTIFY(spool);
426 GST_BUFFER_POOL_UNLOCK(spool);
427 return;
428 }
429
430 GST_BUFFER_POOL_LOCK(spool);
431 if (!spool->started) {
432 gst_producer_surface_pool_free_buffer(pool, buffer);
433 } else {
434 spool->preAllocated = g_list_append(spool->preAllocated, buffer);
435 GST_BUFFER_POOL_NOTIFY(spool);
436 }
437 GST_BUFFER_POOL_UNLOCK(spool);
438 }
439
gst_producer_surface_pool_start(GstBufferPool * pool)440 static gboolean gst_producer_surface_pool_start(GstBufferPool *pool)
441 {
442 g_return_val_if_fail(pool != nullptr, FALSE);
443 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
444 g_return_val_if_fail(spool != nullptr, FALSE);
445
446 GST_DEBUG_OBJECT(spool, "pool start");
447
448 GST_BUFFER_POOL_LOCK(spool);
449 if (spool->surface == nullptr) {
450 GST_BUFFER_POOL_UNLOCK(spool);
451 GST_ERROR_OBJECT(spool, "not set surface");
452 return FALSE;
453 }
454
455 OHOS::SurfaceError err = spool->surface->SetQueueSize(spool->maxBuffers);
456 if (err != OHOS::SurfaceError::SURFACE_ERROR_OK) {
457 GST_BUFFER_POOL_UNLOCK(spool);
458 GST_ERROR_OBJECT(spool, "set queue size to %u failed", spool->maxBuffers);
459 return FALSE;
460 }
461
462 gst_surface_allocator_set_surface(spool->allocator, spool->surface);
463 GST_INFO_OBJECT(spool, "Set pool minbuf %u maxbuf %u", spool->minBuffers, spool->maxBuffers);
464
465 spool->freeBufCnt = spool->maxBuffers;
466 GST_BUFFER_POOL_UNLOCK(spool);
467
468 if (spool->task == nullptr) {
469 spool->task = gst_task_new((GstTaskFunction)gst_producer_surface_pool_request_loop, spool, nullptr);
470 g_return_val_if_fail(spool->task != nullptr, FALSE);
471 gst_task_set_lock(spool->task, &spool->taskLock);
472 gst_object_set_name(GST_OBJECT_CAST(spool->task), "surface_pool_req");
473 }
474
475 GST_BUFFER_POOL_LOCK(spool);
476 spool->started = TRUE;
477 if (!gst_task_set_state(spool->task, GST_TASK_STARTED)) {
478 spool->started = FALSE;
479 GST_BUFFER_POOL_UNLOCK(spool);
480 return FALSE;
481 }
482 GST_BUFFER_POOL_UNLOCK(spool);
483 return TRUE;
484 }
485
gst_producer_surface_pool_stop(GstBufferPool * pool)486 static gboolean gst_producer_surface_pool_stop(GstBufferPool *pool)
487 {
488 g_return_val_if_fail(pool != nullptr, FALSE);
489 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
490 g_return_val_if_fail(spool != nullptr, FALSE);
491
492 GST_DEBUG_OBJECT(spool, "pool stop");
493
494 GST_BUFFER_POOL_LOCK(spool);
495 spool->started = FALSE;
496 GST_BUFFER_POOL_NOTIFY(spool); // wakeup immediately
497 if (spool->surface != nullptr) {
498 spool->surface->CleanCache();
499 }
500 GST_BUFFER_POOL_UNLOCK(spool);
501 (void)gst_task_stop(spool->task);
502 GST_BUFFER_POOL_LOCK(spool);
503 clear_preallocated_buffer(spool);
504
505 // leave all configuration unchanged.
506 gboolean ret = (spool->freeBufCnt == spool->maxBuffers);
507 GST_BUFFER_POOL_UNLOCK(spool);
508
509 g_rec_mutex_lock(&spool->taskLock);
510 GST_INFO_OBJECT(spool, "surface pool req task lock got");
511 g_rec_mutex_unlock(&spool->taskLock);
512 (void)gst_task_join(spool->task);
513 gst_object_unref(spool->task);
514 spool->task = nullptr;
515
516 return ret;
517 }
518
do_alloc_memory_locked(GstProducerSurfacePool * spool,GstBufferPoolAcquireParams * params,GstSurfaceMemory ** memory)519 static GstFlowReturn do_alloc_memory_locked(GstProducerSurfacePool *spool,
520 GstBufferPoolAcquireParams *params, GstSurfaceMemory **memory)
521 {
522 g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
523 GstVideoInfo *info = &spool->info;
524 GstSurfaceAllocParam allocParam = {
525 GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info), spool->format, spool->usage,
526 (params != nullptr ? ((params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT) != 0) : FALSE),
527 spool->scale_type
528 };
529
530 GST_DEBUG_OBJECT(spool, "do_alloc_memory_locked");
531 *memory = gst_surface_allocator_alloc(spool->allocator, allocParam);
532 if (*memory == nullptr) {
533 return GST_FLOW_EOS;
534 }
535 return GST_FLOW_OK;
536 }
537
gst_producer_surface_pool_alloc_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)538 static GstFlowReturn gst_producer_surface_pool_alloc_buffer(GstBufferPool *pool,
539 GstBuffer **buffer, GstBufferPoolAcquireParams *params)
540 {
541 g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
542 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
543 g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
544
545 GST_DEBUG_OBJECT(spool, "alloc surface buffer");
546
547 GstSurfaceMemory *memory = nullptr;
548 GstFlowReturn ret = do_alloc_memory_locked(spool, params, &memory);
549 if (memory == nullptr) {
550 GST_WARNING_OBJECT(spool, "allocator mem fail");
551 return ret;
552 }
553
554 *buffer = gst_buffer_new();
555 if (*buffer == nullptr) {
556 GST_ERROR_OBJECT(spool, "alloc gst buffer failed");
557 gst_allocator_free(reinterpret_cast<GstAllocator*>(spool->allocator), reinterpret_cast<GstMemory*>(memory));
558 return GST_FLOW_ERROR;
559 }
560
561 gst_buffer_append_memory(*buffer, reinterpret_cast<GstMemory *>(memory));
562
563 // add buffer type meta at here.
564 OHOS::sptr<OHOS::SurfaceBuffer> buf = memory->buf;
565 auto buffer_handle = buf->GetBufferHandle();
566 int32_t stride = buffer_handle->stride;
567 GstVideoInfo *info = &spool->info;
568
569 if (buf->GetFormat() == PIXEL_FMT_RGBA_8888) {
570 for (guint plane = 0; plane < info->finfo->n_planes; ++plane) {
571 info->stride[plane] = stride;
572 GST_DEBUG_OBJECT(spool, "new stride %d", stride);
573 }
574 gst_buffer_add_video_meta_full(*buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT(info),
575 GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info), info->finfo->n_planes, info->offset, info->stride);
576 } else {
577 gst_buffer_add_video_meta(*buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT(info),
578 GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info));
579 }
580 GstBufferHandleConfig config = { sizeof(buffer_handle), memory->fence, 0, 0, 0, 0, 0 };
581 gst_buffer_add_buffer_handle_meta(*buffer, reinterpret_cast<intptr_t>(buffer_handle), config);
582 return GST_FLOW_OK;
583 }
584
gst_producer_surface_pool_free_buffer(GstBufferPool * pool,GstBuffer * buffer)585 static void gst_producer_surface_pool_free_buffer(GstBufferPool *pool, GstBuffer *buffer)
586 {
587 (void)pool;
588 g_return_if_fail(buffer != nullptr);
589 gst_buffer_unref(buffer);
590 }
591
gst_producer_surface_pool_acquire_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)592 static GstFlowReturn gst_producer_surface_pool_acquire_buffer(GstBufferPool *pool,
593 GstBuffer **buffer, GstBufferPoolAcquireParams *params)
594 {
595 g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
596 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
597 g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
598 GstFlowReturn ret = GST_FLOW_OK;
599
600 GST_DEBUG_OBJECT(spool, "acquire buffer");
601 GST_BUFFER_POOL_LOCK(spool);
602
603 while (TRUE) {
604 // when pool is set flushing or set inactive, the flushing state is true, refer to GstBufferPool
605 if (GST_BUFFER_POOL_IS_FLUSHING(pool)) {
606 ret = GST_FLOW_FLUSHING;
607 GST_INFO_OBJECT(spool, "pool is flushing");
608 break;
609 }
610 if (spool->started == FALSE) {
611 ret = GST_FLOW_ERROR;
612 GST_ERROR_OBJECT(spool, "surface pool is not started");
613 break;
614 }
615 GList *node = g_list_first(spool->preAllocated);
616 if (node != nullptr) {
617 *buffer = GST_BUFFER_CAST(node->data);
618 if (*buffer == nullptr) {
619 ret = GST_FLOW_ERROR;
620 GST_ERROR_OBJECT(spool, "buffer is nullptr");
621 break;
622 }
623 spool->preAllocated = g_list_delete_link(spool->preAllocated, node);
624 GST_DEBUG_OBJECT(spool, "acquire buffer from preallocated buffers");
625 spool->freeBufCnt -= 1;
626 GST_BUFFER_POOL_NOTIFY(spool);
627 ret = GST_FLOW_OK;
628 break;
629 }
630
631 if ((params != nullptr) && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT)) {
632 ret = GST_FLOW_EOS;
633 break;
634 }
635
636 GST_BUFFER_POOL_WAIT(spool);
637 }
638
639 if (ret == GST_FLOW_EOS) {
640 GST_DEBUG_OBJECT(spool, "no more buffers");
641 }
642
643 // The GstBufferPool will add the GstBuffer's pool ref to this pool.
644 GST_BUFFER_POOL_UNLOCK(spool);
645 return ret;
646 }
647
gst_producer_surface_pool_release_buffer(GstBufferPool * pool,GstBuffer * buffer)648 static void gst_producer_surface_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer)
649 {
650 // The GstBufferPool has already cleared the GstBuffer's pool ref to this pool.
651
652 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
653 g_return_if_fail(spool != nullptr);
654 GST_DEBUG_OBJECT(spool, "release buffer 0x%06" PRIXPTR "", FAKE_POINTER(buffer));
655
656 if (G_UNLIKELY(!gst_buffer_is_all_memory_writable(buffer))) {
657 GST_WARNING_OBJECT(spool, "buffer is not writable, 0x%06" PRIXPTR, FAKE_POINTER(buffer));
658 }
659
660 // we dont queue the buffer to the idlelist. the memory rotation reuse feature
661 // provided by the Surface itself.
662 gst_producer_surface_pool_free_buffer(pool, buffer);
663
664 GST_BUFFER_POOL_LOCK(spool);
665 spool->freeBufCnt += 1;
666 GST_BUFFER_POOL_UNLOCK(spool);
667 }
668
gst_producer_surface_pool_flush_start(GstBufferPool * pool)669 static void gst_producer_surface_pool_flush_start(GstBufferPool *pool)
670 {
671 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
672 g_return_if_fail(spool != nullptr);
673
674 GST_BUFFER_POOL_LOCK(spool);
675 GST_BUFFER_POOL_NOTIFY(spool);
676 GST_BUFFER_POOL_UNLOCK(spool);
677 }
678