• 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     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, &params);
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