• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "gst_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, &params);
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