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