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 GST_INFO("pool finalize in");
173 G_OBJECT_CLASS(parent_class)->finalize(obj);
174 GST_INFO("pool finalize out");
175 }
176
gst_producer_surface_pool_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)177 static void gst_producer_surface_pool_set_property(GObject *object, guint prop_id,
178 const GValue *value, GParamSpec *pspec)
179 {
180 g_return_if_fail(object != nullptr);
181 g_return_if_fail(value != nullptr);
182 g_return_if_fail(pspec != nullptr);
183 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL(object);
184
185 switch (prop_id) {
186 case PROP_DYNAMIC_BUFFER_NUM: {
187 g_return_if_fail(spool->surface != nullptr);
188 guint dynamicBuffers = g_value_get_uint(value);
189 g_return_if_fail(dynamicBuffers != 0);
190 GST_BUFFER_POOL_LOCK(spool);
191 if (spool->freeBufCnt + dynamicBuffers < spool->maxBuffers) {
192 GST_BUFFER_POOL_UNLOCK(spool);
193 GST_ERROR_OBJECT(spool, "set queue size failed for free buffers %u", spool->freeBufCnt);
194 return;
195 }
196 spool->freeBufCnt += (dynamicBuffers - spool->maxBuffers);
197 spool->maxBuffers = dynamicBuffers;
198 OHOS::SurfaceError err = spool->surface->SetQueueSize(spool->maxBuffers);
199 if (err != OHOS::SurfaceError::SURFACE_ERROR_OK) {
200 GST_BUFFER_POOL_UNLOCK(spool);
201 GST_ERROR_OBJECT(spool, "set queue size to %u failed", spool->maxBuffers);
202 return;
203 }
204 GST_DEBUG_OBJECT(spool, "set max buffer count: %u", spool->maxBuffers);
205 GST_BUFFER_POOL_UNLOCK(spool);
206 break;
207 }
208 case PROP_CACHE_BUFFERS_NUM: {
209 GST_BUFFER_POOL_LOCK(spool);
210 guint cache_num = g_value_get_uint(value);
211 GST_DEBUG_OBJECT(spool, "set cache_num to: %u", cache_num);
212 if (cache_num == 0) {
213 spool->isDynamicCached = FALSE;
214 } else {
215 spool->isDynamicCached = TRUE;
216 spool->cachedBuffers = cache_num;
217 }
218 GST_BUFFER_POOL_UNLOCK(spool);
219 break;
220 }
221 case PROP_VIDEO_SCALE_TYPE: {
222 GST_BUFFER_POOL_LOCK(spool);
223 spool->scale_type = g_value_get_uint(value);
224 GST_BUFFER_POOL_UNLOCK(spool);
225 break;
226 }
227 default:
228 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
229 break;
230 }
231 }
232
gst_producer_surface_pool_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)233 static void gst_producer_surface_pool_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
234 {
235 g_return_if_fail(object != nullptr);
236 g_return_if_fail(value != nullptr);
237 g_return_if_fail(pspec != nullptr);
238 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL(object);
239
240 switch (prop_id) {
241 case PROP_DYNAMIC_BUFFER_NUM: {
242 GST_BUFFER_POOL_LOCK(spool);
243 g_value_set_uint(value, spool->maxBuffers);
244 GST_BUFFER_POOL_UNLOCK(spool);
245 break;
246 }
247 default:
248 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
249 break;
250 }
251 }
252
gst_producer_surface_pool_new(void)253 GstProducerSurfacePool *gst_producer_surface_pool_new(void)
254 {
255 GstProducerSurfacePool *pool = GST_PRODUCER_SURFACE_POOL_CAST(g_object_new(
256 GST_TYPE_PRODUCER_SURFACE_POOL, "name", "SurfacePool", nullptr));
257 (void)gst_object_ref_sink(pool);
258
259 return pool;
260 }
261
gst_producer_surface_pool_get_options(GstBufferPool * pool)262 static const gchar **gst_producer_surface_pool_get_options(GstBufferPool *pool)
263 {
264 // add buffer type meta option at here
265 (void)pool;
266 static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT,
267 nullptr };
268 return options;
269 }
270
parse_caps_info(GstCaps * caps,GstVideoInfo * info,PixelFormat * format)271 static gboolean parse_caps_info(GstCaps *caps, GstVideoInfo *info, PixelFormat *format)
272 {
273 if (caps == nullptr) {
274 GST_INFO("caps is nullptr");
275 return FALSE;
276 }
277
278 if (!gst_video_info_from_caps(info, caps)) {
279 GST_ERROR("wrong caps");
280 return FALSE;
281 }
282
283 if (FORMAT_MAPPING.count(GST_VIDEO_INFO_FORMAT(info)) == 0) {
284 GST_ERROR("unsupported format, %s", GST_VIDEO_INFO_NAME(info));
285 return FALSE;
286 }
287
288 *format = FORMAT_MAPPING.at(GST_VIDEO_INFO_FORMAT(info));
289 return TRUE;
290 }
291
parse_config_usage(GstProducerSurfacePool * spool,GstStructure * config)292 static gboolean parse_config_usage(GstProducerSurfacePool *spool, GstStructure *config)
293 {
294 g_return_val_if_fail(spool != nullptr, FALSE);
295 g_return_val_if_fail(config != nullptr, FALSE);
296 if (!gst_structure_get_uint64(config, "usage", &spool->usage)) {
297 GST_INFO_OBJECT(spool, "no usage available");
298 spool->usage = 0;
299 }
300 return TRUE;
301 }
302
gst_producer_surface_pool_set_config(GstBufferPool * pool,GstStructure * config)303 static gboolean gst_producer_surface_pool_set_config(GstBufferPool *pool, GstStructure *config)
304 {
305 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
306 g_return_val_if_fail(spool != nullptr, FALSE);
307 g_return_val_if_fail(config != nullptr, FALSE);
308
309 GstCaps *caps = nullptr;
310 guint size; // ignore the size
311 guint min_buffers;
312 guint max_buffers;
313 if (!gst_buffer_pool_config_get_params(config, &caps, &size, &min_buffers, &max_buffers)) {
314 GST_ERROR_OBJECT(spool, "wrong config");
315 return FALSE;
316 }
317 g_return_val_if_fail(min_buffers <= max_buffers, FALSE);
318
319 GstVideoInfo info;
320 PixelFormat format;
321 if (!parse_caps_info(caps, &info, &format)) {
322 return FALSE;
323 }
324 g_return_val_if_fail(parse_config_usage(spool, config), FALSE);
325 GST_INFO_OBJECT(pool, "get usage %" G_GUINT64_FORMAT " ", spool->usage);
326
327 GST_BUFFER_POOL_LOCK(spool);
328
329 spool->info = info;
330 spool->format = format;
331 spool->minBuffers = min_buffers;
332 spool->maxBuffers = max_buffers;
333
334 GST_INFO_OBJECT(spool, "set config, width: %d, height: %d, format: %d, min_bufs: %u, max_bufs: %u",
335 GST_VIDEO_INFO_WIDTH(&info), GST_VIDEO_INFO_HEIGHT(&info), format, min_buffers, max_buffers);
336
337 GstAllocator *allocator = nullptr;
338 GstAllocationParams params;
339 (void)gst_buffer_pool_config_get_allocator(config, &allocator, ¶ms);
340 if (!(allocator && GST_IS_SURFACE_ALLOCATOR(allocator))) {
341 GST_BUFFER_POOL_UNLOCK(spool);
342 GST_WARNING_OBJECT(pool, "no valid allocator in pool");
343 return TRUE;
344 }
345 spool->allocator = GST_SURFACE_ALLOCATOR_CAST(allocator);
346 spool->params = params;
347
348 GST_INFO_OBJECT(spool, "update allocator and params");
349
350 GST_BUFFER_POOL_UNLOCK(spool);
351 return TRUE;
352 }
353
gst_producer_surface_pool_set_surface(GstProducerSurfacePool * pool,OHOS::sptr<OHOS::Surface> surface)354 gboolean gst_producer_surface_pool_set_surface(GstProducerSurfacePool *pool, OHOS::sptr<OHOS::Surface> surface)
355 {
356 g_return_val_if_fail(surface != nullptr, FALSE);
357 g_return_val_if_fail(pool != nullptr, FALSE);
358
359 GST_BUFFER_POOL_LOCK(pool);
360
361 if (pool->started) {
362 GST_INFO_OBJECT(pool, "started already, reject to set surface");
363 GST_BUFFER_POOL_UNLOCK(pool);
364 return FALSE;
365 }
366
367 if (pool->surface != nullptr) {
368 GST_INFO_OBJECT(pool, "surface has already been set");
369 GST_BUFFER_POOL_UNLOCK(pool);
370 return FALSE;
371 }
372
373 pool->surface = surface;
374
375 GST_BUFFER_POOL_UNLOCK(pool);
376 return TRUE;
377 }
378
gst_producer_surface_pool_statistics(GstProducerSurfacePool * spool)379 static void gst_producer_surface_pool_statistics(GstProducerSurfacePool *spool)
380 {
381 if (spool->callCnt == 0) {
382 gettimeofday(&(spool->beginTime), nullptr);
383 }
384 spool->callCnt++;
385 gettimeofday(&(spool->endTime), nullptr);
386 if ((spool->endTime.tv_sec * TIME_VAL_US + spool->endTime.tv_usec) -
387 (spool->beginTime.tv_sec * TIME_VAL_US + spool->beginTime.tv_usec) > TIME_VAL_US) {
388 OHOS::Media::MediaEvent event;
389 if (event.CreateMsg("The gst_producer_surface_pool_request_loop function is called in a second: %d",
390 spool->callCnt)) {
391 event.EventWrite("PLAYER_STATISTICS", OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "PLAYER");
392 spool->callCnt = 0;
393 } else {
394 GST_ERROR_OBJECT(spool, "Failed to call CreateMsg");
395 }
396 }
397 }
398
gst_producer_surface_pool_request_loop(GstProducerSurfacePool * spool)399 static void gst_producer_surface_pool_request_loop(GstProducerSurfacePool *spool)
400 {
401 g_return_if_fail(spool != nullptr);
402 GstBufferPool *pool = GST_BUFFER_POOL_CAST(spool);
403 GST_DEBUG_OBJECT(spool, "Loop In");
404
405 GST_BUFFER_POOL_LOCK(spool);
406 gst_producer_surface_pool_statistics(spool);
407
408 while (spool->isDynamicCached && g_list_length(spool->preAllocated) >= spool->cachedBuffers && spool->started) {
409 GST_BUFFER_POOL_WAIT(spool);
410 }
411
412 if (!spool->started) {
413 GST_BUFFER_POOL_UNLOCK(spool);
414 GST_WARNING_OBJECT(spool, "task is paused, exit");
415 gst_task_pause(spool->task);
416 return;
417 }
418 GST_BUFFER_POOL_UNLOCK(spool);
419
420 GstBuffer *buffer = nullptr;
421 GstFlowReturn ret = gst_producer_surface_pool_alloc_buffer(pool, &buffer, nullptr);
422 if (ret != GST_FLOW_OK) {
423 GST_WARNING_OBJECT(spool, "alloc buffer failed, exit");
424 gst_task_pause(spool->task);
425 GST_BUFFER_POOL_LOCK(spool);
426 spool->started = FALSE;
427 GST_BUFFER_POOL_NOTIFY(spool);
428 GST_BUFFER_POOL_UNLOCK(spool);
429 return;
430 }
431
432 GST_BUFFER_POOL_LOCK(spool);
433 if (!spool->started) {
434 gst_producer_surface_pool_free_buffer(pool, buffer);
435 } else {
436 spool->preAllocated = g_list_append(spool->preAllocated, buffer);
437 GST_BUFFER_POOL_NOTIFY(spool);
438 }
439 GST_BUFFER_POOL_UNLOCK(spool);
440 }
441
gst_producer_surface_pool_start(GstBufferPool * pool)442 static gboolean gst_producer_surface_pool_start(GstBufferPool *pool)
443 {
444 g_return_val_if_fail(pool != nullptr, FALSE);
445 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
446 g_return_val_if_fail(spool != nullptr, FALSE);
447
448 GST_DEBUG_OBJECT(spool, "pool start");
449
450 GST_BUFFER_POOL_LOCK(spool);
451 if (spool->surface == nullptr) {
452 GST_BUFFER_POOL_UNLOCK(spool);
453 GST_ERROR_OBJECT(spool, "not set surface");
454 return FALSE;
455 }
456
457 OHOS::SurfaceError err = spool->surface->SetQueueSize(spool->maxBuffers);
458 if (err != OHOS::SurfaceError::SURFACE_ERROR_OK) {
459 GST_BUFFER_POOL_UNLOCK(spool);
460 GST_ERROR_OBJECT(spool, "set queue size to %u failed", spool->maxBuffers);
461 return FALSE;
462 }
463
464 gst_surface_allocator_set_surface(spool->allocator, spool->surface);
465 GST_INFO_OBJECT(spool, "Set pool minbuf %u maxbuf %u", spool->minBuffers, spool->maxBuffers);
466
467 spool->freeBufCnt = spool->maxBuffers;
468 GST_BUFFER_POOL_UNLOCK(spool);
469
470 if (spool->task == nullptr) {
471 spool->task = gst_task_new((GstTaskFunction)gst_producer_surface_pool_request_loop, spool, nullptr);
472 g_return_val_if_fail(spool->task != nullptr, FALSE);
473 gst_task_set_lock(spool->task, &spool->taskLock);
474 gst_object_set_name(GST_OBJECT_CAST(spool->task), "surface_pool_req");
475 }
476
477 GST_BUFFER_POOL_LOCK(spool);
478 spool->started = TRUE;
479 if (!gst_task_set_state(spool->task, GST_TASK_STARTED)) {
480 spool->started = FALSE;
481 GST_BUFFER_POOL_UNLOCK(spool);
482 return FALSE;
483 }
484 GST_BUFFER_POOL_UNLOCK(spool);
485 return TRUE;
486 }
487
gst_producer_surface_pool_stop(GstBufferPool * pool)488 static gboolean gst_producer_surface_pool_stop(GstBufferPool *pool)
489 {
490 g_return_val_if_fail(pool != nullptr, FALSE);
491 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
492 g_return_val_if_fail(spool != nullptr, FALSE);
493
494 GST_DEBUG_OBJECT(spool, "pool stop");
495
496 GST_BUFFER_POOL_LOCK(spool);
497 spool->started = FALSE;
498 GST_BUFFER_POOL_NOTIFY(spool); // wakeup immediately
499 if (spool->surface != nullptr) {
500 spool->surface->CleanCache();
501 }
502 GST_BUFFER_POOL_UNLOCK(spool);
503 (void)gst_task_stop(spool->task);
504 GST_BUFFER_POOL_LOCK(spool);
505 clear_preallocated_buffer(spool);
506
507 // leave all configuration unchanged.
508 gboolean ret = (spool->freeBufCnt == spool->maxBuffers);
509 GST_BUFFER_POOL_UNLOCK(spool);
510
511 g_rec_mutex_lock(&spool->taskLock);
512 GST_INFO_OBJECT(spool, "surface pool req task lock got");
513 g_rec_mutex_unlock(&spool->taskLock);
514 (void)gst_task_join(spool->task);
515 gst_object_unref(spool->task);
516 spool->task = nullptr;
517
518 return ret;
519 }
520
do_alloc_memory_locked(GstProducerSurfacePool * spool,GstBufferPoolAcquireParams * params,GstSurfaceMemory ** memory)521 static GstFlowReturn do_alloc_memory_locked(GstProducerSurfacePool *spool,
522 GstBufferPoolAcquireParams *params, GstSurfaceMemory **memory)
523 {
524 GstVideoInfo *info = &spool->info;
525 GstSurfaceAllocParam allocParam = {
526 GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info), spool->format, spool->usage,
527 (params != nullptr ? ((params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT) != 0) : FALSE),
528 spool->scale_type
529 };
530
531 GST_DEBUG_OBJECT(spool, "do_alloc_memory_locked");
532 *memory = gst_surface_allocator_alloc(spool->allocator, allocParam);
533 if (*memory == nullptr) {
534 return GST_FLOW_EOS;
535 }
536 return GST_FLOW_OK;
537 }
538
gst_producer_surface_pool_alloc_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)539 static GstFlowReturn gst_producer_surface_pool_alloc_buffer(GstBufferPool *pool,
540 GstBuffer **buffer, GstBufferPoolAcquireParams *params)
541 {
542 g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
543 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
544 g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
545
546 GST_DEBUG_OBJECT(spool, "alloc surface buffer");
547
548 GstSurfaceMemory *memory = nullptr;
549 GstFlowReturn ret = do_alloc_memory_locked(spool, params, &memory);
550 if (memory == nullptr) {
551 GST_WARNING_OBJECT(spool, "allocator mem fail");
552 return ret;
553 }
554
555 *buffer = gst_buffer_new();
556 if (*buffer == nullptr) {
557 GST_ERROR_OBJECT(spool, "alloc gst buffer failed");
558 gst_allocator_free(reinterpret_cast<GstAllocator*>(spool->allocator), reinterpret_cast<GstMemory*>(memory));
559 return GST_FLOW_ERROR;
560 }
561
562 gst_buffer_append_memory(*buffer, reinterpret_cast<GstMemory *>(memory));
563
564 // add buffer type meta at here.
565 OHOS::sptr<OHOS::SurfaceBuffer> buf = memory->buf;
566 auto buffer_handle = buf->GetBufferHandle();
567 g_return_val_if_fail(buffer_handle != nullptr, GST_FLOW_ERROR);
568 int32_t stride = buffer_handle->stride;
569 GstBufferHandleConfig config = { sizeof(buffer_handle), memory->fence, 0, 0, 0, 0, 0 };
570 gst_buffer_add_buffer_handle_meta(*buffer, reinterpret_cast<intptr_t>(buffer_handle), config);
571
572 GstVideoInfo *info = &spool->info;
573 g_return_val_if_fail(info != nullptr && info->finfo != nullptr, GST_FLOW_ERROR);
574 for (guint plane = 0; plane < info->finfo->n_planes; ++plane) {
575 info->stride[plane] = stride;
576 GST_DEBUG_OBJECT(spool, "new stride %d", stride);
577 }
578 gst_buffer_add_video_meta_full(*buffer, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT(info),
579 GST_VIDEO_INFO_WIDTH(info), GST_VIDEO_INFO_HEIGHT(info), info->finfo->n_planes, info->offset, info->stride);
580 return GST_FLOW_OK;
581 }
582
gst_producer_surface_pool_free_buffer(GstBufferPool * pool,GstBuffer * buffer)583 static void gst_producer_surface_pool_free_buffer(GstBufferPool *pool, GstBuffer *buffer)
584 {
585 (void)pool;
586 g_return_if_fail(buffer != nullptr);
587 gst_buffer_unref(buffer);
588 }
589
gst_producer_surface_pool_acquire_buffer(GstBufferPool * pool,GstBuffer ** buffer,GstBufferPoolAcquireParams * params)590 static GstFlowReturn gst_producer_surface_pool_acquire_buffer(GstBufferPool *pool,
591 GstBuffer **buffer, GstBufferPoolAcquireParams *params)
592 {
593 g_return_val_if_fail(pool != nullptr && buffer != nullptr, GST_FLOW_ERROR);
594 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
595 g_return_val_if_fail(spool != nullptr, GST_FLOW_ERROR);
596 GstFlowReturn ret = GST_FLOW_OK;
597
598 GST_DEBUG_OBJECT(spool, "acquire buffer");
599 GST_BUFFER_POOL_LOCK(spool);
600
601 while (TRUE) {
602 // when pool is set flushing or set inactive, the flushing state is true, refer to GstBufferPool
603 if (GST_BUFFER_POOL_IS_FLUSHING(pool)) {
604 ret = GST_FLOW_FLUSHING;
605 GST_INFO_OBJECT(spool, "pool is flushing");
606 break;
607 }
608 if (spool->started == FALSE) {
609 ret = GST_FLOW_ERROR;
610 GST_ERROR_OBJECT(spool, "surface pool is not started");
611 break;
612 }
613 GList *node = g_list_first(spool->preAllocated);
614 if (node != nullptr) {
615 *buffer = GST_BUFFER_CAST(node->data);
616 if (*buffer == nullptr) {
617 ret = GST_FLOW_ERROR;
618 GST_ERROR_OBJECT(spool, "buffer is nullptr");
619 break;
620 }
621 spool->preAllocated = g_list_delete_link(spool->preAllocated, node);
622 GST_DEBUG_OBJECT(spool, "acquire buffer from preallocated buffers");
623 spool->freeBufCnt -= 1;
624 GST_BUFFER_POOL_NOTIFY(spool);
625 ret = GST_FLOW_OK;
626 break;
627 }
628
629 if ((params != nullptr) && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT)) {
630 ret = GST_FLOW_EOS;
631 break;
632 }
633
634 GST_BUFFER_POOL_WAIT(spool);
635 }
636
637 if (ret == GST_FLOW_EOS) {
638 GST_DEBUG_OBJECT(spool, "no more buffers");
639 }
640
641 // The GstBufferPool will add the GstBuffer's pool ref to this pool.
642 GST_BUFFER_POOL_UNLOCK(spool);
643 return ret;
644 }
645
gst_producer_surface_pool_release_buffer(GstBufferPool * pool,GstBuffer * buffer)646 static void gst_producer_surface_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer)
647 {
648 // The GstBufferPool has already cleared the GstBuffer's pool ref to this pool.
649
650 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
651 g_return_if_fail(spool != nullptr);
652 GST_DEBUG_OBJECT(spool, "release buffer 0x%06" PRIXPTR "", FAKE_POINTER(buffer));
653
654 if (G_UNLIKELY(!gst_buffer_is_all_memory_writable(buffer))) {
655 GST_WARNING_OBJECT(spool, "buffer is not writable, 0x%06" PRIXPTR, FAKE_POINTER(buffer));
656 }
657
658 // we dont queue the buffer to the idlelist. the memory rotation reuse feature
659 // provided by the Surface itself.
660 gst_producer_surface_pool_free_buffer(pool, buffer);
661
662 GST_BUFFER_POOL_LOCK(spool);
663 spool->freeBufCnt += 1;
664 GST_BUFFER_POOL_UNLOCK(spool);
665 }
666
gst_producer_surface_pool_flush_start(GstBufferPool * pool)667 static void gst_producer_surface_pool_flush_start(GstBufferPool *pool)
668 {
669 GstProducerSurfacePool *spool = GST_PRODUCER_SURFACE_POOL_CAST(pool);
670 g_return_if_fail(spool != nullptr);
671
672 GST_BUFFER_POOL_LOCK(spool);
673 GST_BUFFER_POOL_NOTIFY(spool);
674 GST_BUFFER_POOL_UNLOCK(spool);
675 }
676