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