• 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_surface_pool_src.h"
17 #include <gst/video/video.h>
18 #include <sync_fence.h>
19 #include "gst_consumer_surface_pool.h"
20 #include "gst_consumer_surface_allocator.h"
21 #include "media_errors.h"
22 #include "surface_buffer.h"
23 #include "buffer_type_meta.h"
24 #include "scope_guard.h"
25 #include "display_type.h"
26 
27 #define gst_surface_pool_src_parent_class parent_class
28 using namespace OHOS;
29 namespace {
30     constexpr guint MAX_SURFACE_QUEUE_SIZE = 12;
31     constexpr guint DEFAULT_SURFACE_QUEUE_SIZE = 8;
32     constexpr int32_t DEFAULT_SURFACE_SIZE = 1024 * 1024;
33     constexpr int32_t DEFAULT_VIDEO_WIDTH = 1920;
34     constexpr int32_t DEFAULT_VIDEO_HEIGHT = 1080;
35     constexpr uint32_t STRIDE_ALIGN = 8;
36 }
37 
38 GST_DEBUG_CATEGORY_STATIC(gst_surface_pool_src_debug_category);
39 #define GST_CAT_DEFAULT gst_surface_pool_src_debug_category
40 
41 static GstStaticPadTemplate gst_src_template =
42 GST_STATIC_PAD_TEMPLATE("src",
43     GST_PAD_SRC,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL)));
46 
47 enum {
48     PROP_0,
49     PROP_SURFACE,
50     PROP_SURFACE_STRIDE,
51     PROP_SUSPEND,
52     PROP_REPEAT,
53     PROP_MAX_FRAME_RATE,
54 };
55 
56 G_DEFINE_TYPE(GstSurfacePoolSrc, gst_surface_pool_src, GST_TYPE_MEM_POOL_SRC);
57 
58 static void gst_surface_pool_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
59 static void gst_surface_pool_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
60 static GstStateChangeReturn gst_surface_pool_src_change_state(GstElement *element, GstStateChange transition);
61 static gboolean gst_surface_pool_src_create_surface(GstSurfacePoolSrc *src);
62 static gboolean gst_surface_pool_src_create_pool(GstSurfacePoolSrc *src);
63 static void gst_surface_pool_src_destroy_surface(GstSurfacePoolSrc *src);
64 static void gst_surface_pool_src_destroy_pool(GstSurfacePoolSrc *src);
65 static gboolean gst_surface_pool_src_decide_allocation(GstBaseSrc *basesrc, GstQuery *query);
66 static GstFlowReturn gst_surface_pool_src_fill(GstBaseSrc *src, guint64 offset, guint size, GstBuffer *buf);
67 static void gst_surface_pool_src_init_surface(GstSurfacePoolSrc *src);
68 static gboolean gst_surface_pool_src_send_event(GstElement *element, GstEvent *event);
69 
gst_surface_pool_src_class_init(GstSurfacePoolSrcClass * klass)70 static void gst_surface_pool_src_class_init(GstSurfacePoolSrcClass *klass)
71 {
72     g_return_if_fail(klass != nullptr);
73     GObjectClass *gobject_class = reinterpret_cast<GObjectClass*>(klass);
74     GstElementClass *gstelement_class = reinterpret_cast<GstElementClass*>(klass);
75     GstBaseSrcClass *gstbasesrc_class = reinterpret_cast<GstBaseSrcClass*>(klass);
76     GST_DEBUG_CATEGORY_INIT(gst_surface_pool_src_debug_category, "surfacepoolsrc", 0, "surface pool src base class");
77     gobject_class->get_property = gst_surface_pool_src_get_property;
78     gobject_class->set_property = gst_surface_pool_src_set_property;
79 
80     g_object_class_install_property(gobject_class, PROP_SURFACE,
81         g_param_spec_pointer("surface", "Surface", "Surface for buffer",
82             (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
83 
84     g_object_class_install_property(gobject_class, PROP_SURFACE_STRIDE,
85         g_param_spec_uint("surface-stride", "surface stride",
86             "surface buffer stride", 0, G_MAXINT32, STRIDE_ALIGN,
87             (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
88 
89     g_object_class_install_property(gobject_class, PROP_SUSPEND,
90         g_param_spec_boolean("suspend", "Suspend surface", "Suspend surface",
91             FALSE, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
92 
93     g_object_class_install_property(gobject_class, PROP_REPEAT,
94         g_param_spec_uint("repeat", "Repeat frame", "Repeat previous frame after given milliseconds",
95             0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
96 
97     g_object_class_install_property(gobject_class, PROP_MAX_FRAME_RATE,
98         g_param_spec_uint("max-framerate", "Max frame rate", "Max frame rate",
99             0, G_MAXUINT32, 0, (GParamFlags)(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)));
100 
101     gstelement_class->change_state = gst_surface_pool_src_change_state;
102     gstelement_class->send_event = gst_surface_pool_src_send_event;
103     gstbasesrc_class->fill = gst_surface_pool_src_fill;
104     gstbasesrc_class->decide_allocation = gst_surface_pool_src_decide_allocation;
105     gst_element_class_set_static_metadata(gstelement_class,
106         "surface mem source", "Source/Surface/Pool",
107         "Retrieve frame from surface buffer queue with raw data", "OpenHarmony");
108 
109     gst_element_class_add_static_pad_template(gstelement_class, &gst_src_template);
110 }
111 
gst_surface_pool_src_init(GstSurfacePoolSrc * surfacesrc)112 static void gst_surface_pool_src_init(GstSurfacePoolSrc *surfacesrc)
113 {
114     g_return_if_fail(surfacesrc != nullptr);
115     surfacesrc->pool = nullptr;
116     surfacesrc->stride = STRIDE_ALIGN;
117     surfacesrc->need_flush = FALSE;
118     surfacesrc->flushing = FALSE;
119 }
120 
gst_surface_pool_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)121 static void gst_surface_pool_src_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
122 {
123     GstSurfacePoolSrc *src = GST_SURFACE_POOL_SRC(object);
124     g_return_if_fail(src != nullptr);
125     g_return_if_fail(value != nullptr);
126     (void)pspec;
127     switch (prop_id) {
128         case PROP_SURFACE:
129             g_value_set_pointer(value, src->producerSurface.GetRefPtr());
130             break;
131         case PROP_SURFACE_STRIDE:
132             g_value_set_uint(value, src->stride);
133             break;
134         default:
135             break;
136     }
137 }
138 
gst_surface_pool_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)139 static void gst_surface_pool_src_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
140 {
141     GstSurfacePoolSrc *src = GST_SURFACE_POOL_SRC(object);
142     g_return_if_fail(src != nullptr && value != nullptr);
143     (void)pspec;
144     switch (prop_id) {
145         case PROP_SURFACE_STRIDE:
146             src->stride = g_value_get_uint(value);
147             if (src->stride > INT32_MAX) {
148                 src->stride = STRIDE_ALIGN;
149             }
150             break;
151         case PROP_SUSPEND:
152             g_return_if_fail(src->pool != nullptr);
153             g_object_set(src->pool, "suspend", g_value_get_boolean(value), nullptr);
154             break;
155         case PROP_REPEAT:
156             g_return_if_fail(src->pool != nullptr);
157             g_object_set(src->pool, "repeat", g_value_get_uint(value), nullptr);
158             break;
159         case PROP_MAX_FRAME_RATE:
160             g_return_if_fail(src->pool != nullptr);
161             g_object_set(src->pool, "max-framerate", g_value_get_uint(value), nullptr);
162             break;
163         default:
164             break;
165     }
166 }
167 
gst_surface_pool_src_fill(GstBaseSrc * src,guint64 offset,guint size,GstBuffer * buf)168 static GstFlowReturn gst_surface_pool_src_fill(GstBaseSrc *src, guint64 offset, guint size, GstBuffer *buf)
169 {
170     (void)src;
171     (void)offset;
172     (void)size;
173     GstBufferTypeMeta *meta = gst_buffer_get_buffer_type_meta(buf);
174     if (meta != nullptr && (meta->bufferFlag & BUFFER_FLAG_EOS)) {
175         return GST_FLOW_EOS;
176     }
177     return GST_FLOW_OK;
178 }
179 
gst_surface_pool_src_change_state(GstElement * element,GstStateChange transition)180 static GstStateChangeReturn gst_surface_pool_src_change_state(GstElement *element, GstStateChange transition)
181 {
182     GstSurfacePoolSrc *surfacesrc = GST_SURFACE_POOL_SRC(element);
183     g_return_val_if_fail(surfacesrc != nullptr, GST_STATE_CHANGE_FAILURE);
184     switch (transition) {
185         case GST_STATE_CHANGE_NULL_TO_READY:
186             g_return_val_if_fail(gst_surface_pool_src_create_surface(surfacesrc) == TRUE, GST_STATE_CHANGE_FAILURE);
187             g_return_val_if_fail(gst_surface_pool_src_create_pool(surfacesrc) == TRUE, GST_STATE_CHANGE_FAILURE);
188             break;
189         case GST_STATE_CHANGE_READY_TO_PAUSED:
190             gst_surface_pool_src_init_surface(surfacesrc);
191             break;
192         default:
193             break;
194     }
195     GstStateChangeReturn ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
196 
197     switch (transition) {
198         case GST_STATE_CHANGE_READY_TO_NULL:
199             gst_surface_pool_src_destroy_pool(surfacesrc);
200             gst_surface_pool_src_destroy_surface(surfacesrc);
201             GST_OBJECT_LOCK(surfacesrc);
202             surfacesrc->need_flush = FALSE;
203             GST_OBJECT_UNLOCK(surfacesrc);
204             break;
205         default:
206             break;
207     }
208 
209     return ret;
210 }
211 
gst_surface_pool_src_create_surface(GstSurfacePoolSrc * surfacesrc)212 static gboolean gst_surface_pool_src_create_surface(GstSurfacePoolSrc *surfacesrc)
213 {
214     g_return_val_if_fail(surfacesrc != nullptr, FALSE);
215     sptr<Surface> consumerSurface = Surface::CreateSurfaceAsConsumer();
216     g_return_val_if_fail(consumerSurface != nullptr, FALSE);
217     sptr<IBufferProducer> producer = consumerSurface->GetProducer();
218     g_return_val_if_fail(producer != nullptr, FALSE);
219     sptr<Surface> producerSurface = Surface::CreateSurfaceAsProducer(producer);
220     g_return_val_if_fail(producerSurface != nullptr, FALSE);
221     surfacesrc->consumerSurface = consumerSurface;
222     surfacesrc->producerSurface = producerSurface;
223 
224     GST_DEBUG_OBJECT(surfacesrc, "create surface");
225     return TRUE;
226 }
227 
gst_surface_pool_src_send_event(GstElement * element,GstEvent * event)228 static gboolean gst_surface_pool_src_send_event(GstElement *element, GstEvent *event)
229 {
230     GstSurfacePoolSrc *surfacesrc = GST_SURFACE_POOL_SRC(element);
231     g_return_val_if_fail(surfacesrc != nullptr, FALSE);
232     g_return_val_if_fail(event != nullptr, FALSE);
233     GST_DEBUG_OBJECT(surfacesrc, "New event %s", GST_EVENT_TYPE_NAME(event));
234 
235     switch (GST_EVENT_TYPE(event)) {
236         case GST_EVENT_FLUSH_START:
237             if (surfacesrc->need_flush == FALSE) {
238                 GST_DEBUG_OBJECT(surfacesrc, "No need flushing");
239                 surfacesrc->flushing = FALSE;
240                 return TRUE;
241             }
242             surfacesrc->flushing = TRUE;
243             break;
244         case GST_EVENT_FLUSH_STOP:
245             if (surfacesrc->flushing == FALSE) {
246                 GST_DEBUG_OBJECT(surfacesrc, "No flush start");
247                 return TRUE;
248             }
249             surfacesrc->flushing = FALSE;
250             break;
251         default:
252             break;
253     }
254 
255     return GST_ELEMENT_CLASS(parent_class)->send_event(element, event);
256 }
257 
gst_surface_pool_src_create_pool(GstSurfacePoolSrc * surfacesrc)258 static gboolean gst_surface_pool_src_create_pool(GstSurfacePoolSrc *surfacesrc)
259 {
260     GstAllocationParams params;
261     gst_allocation_params_init(&params);
262     GstBufferPool *pool = gst_consumer_surface_pool_new();
263     g_return_val_if_fail(pool != nullptr, FALSE);
264     ON_SCOPE_EXIT(0) { gst_object_unref(pool); };
265     GstAllocator *allocator = gst_consumer_surface_allocator_new();
266     g_return_val_if_fail(allocator != nullptr, FALSE);
267     gst_consumer_surface_pool_set_surface(pool, surfacesrc->consumerSurface);
268     gst_consumer_surface_allocator_set_surface(allocator, surfacesrc->consumerSurface);
269     // init pool config
270     GstStructure *config = gst_buffer_pool_get_config(pool);
271     gst_buffer_pool_config_set_allocator(config, allocator, &params);
272     g_return_val_if_fail(gst_buffer_pool_set_config(pool, config) != TRUE, FALSE);
273     surfacesrc->pool = pool;
274     CANCEL_SCOPE_EXIT_GUARD(0);
275     GST_DEBUG_OBJECT(surfacesrc, "create surface pool");
276     return TRUE;
277 }
278 
gst_surface_pool_src_destroy_pool(GstSurfacePoolSrc * src)279 static void gst_surface_pool_src_destroy_pool(GstSurfacePoolSrc *src)
280 {
281     gst_object_unref(src->pool);
282     src->pool = nullptr;
283 }
284 
gst_surface_pool_src_destroy_surface(GstSurfacePoolSrc * src)285 static void gst_surface_pool_src_destroy_surface(GstSurfacePoolSrc *src)
286 {
287     src->consumerSurface = nullptr;
288     src->producerSurface = nullptr;
289 }
290 
gst_surface_pool_src_init_surface(GstSurfacePoolSrc * src)291 static void gst_surface_pool_src_init_surface(GstSurfacePoolSrc *src)
292 {
293     // The internal function do not need judge whether it is empty
294     GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(src);
295     sptr<Surface> surface = src->consumerSurface;
296     guint width = DEFAULT_VIDEO_WIDTH;
297     guint height = DEFAULT_VIDEO_HEIGHT;
298     GST_OBJECT_LOCK(memsrc);
299     if (memsrc->caps != nullptr) {
300         GstVideoInfo info;
301         gst_video_info_init(&info);
302         gst_video_info_from_caps(&info, memsrc->caps);
303         width = static_cast<guint>(info.width);
304         height = static_cast<guint>(info.height);
305     }
306     GST_OBJECT_UNLOCK(memsrc);
307     SurfaceError ret = surface->SetUserData("video_width", std::to_string(width));
308     if (ret != SURFACE_ERROR_OK) {
309         GST_WARNING_OBJECT(src, "Set video width fail");
310     }
311     ret = surface->SetUserData("video_height", std::to_string(height));
312     if (ret != SURFACE_ERROR_OK) {
313         GST_WARNING_OBJECT(src, "Set video height fail");
314     }
315     ret = surface->SetUserData("surface_size", std::to_string(DEFAULT_SURFACE_SIZE));
316     if (ret != SURFACE_ERROR_OK) {
317         GST_WARNING_OBJECT(src, "Set surface size fail");
318     }
319     ret = surface->SetDefaultWidthAndHeight(width, height);
320     if (ret != SURFACE_ERROR_OK) {
321         GST_WARNING_OBJECT(src, "Set surface width and height fail");
322     }
323 }
324 
gst_surface_pool_src_gstformat_to_surfaceformat(GstSurfacePoolSrc * surfacesrc,GstVideoInfo * format)325 static int32_t gst_surface_pool_src_gstformat_to_surfaceformat(GstSurfacePoolSrc *surfacesrc, GstVideoInfo *format)
326 {
327     g_return_val_if_fail(surfacesrc != nullptr, -1);
328     g_return_val_if_fail(format != nullptr, -1);
329     g_return_val_if_fail(format->finfo != nullptr, -1);
330     switch (format->finfo->format) {
331         case GST_VIDEO_FORMAT_NV21:
332             return PIXEL_FMT_YCRCB_420_SP;
333         case GST_VIDEO_FORMAT_NV12:
334             return PIXEL_FMT_YCBCR_420_SP;
335         default:
336             GST_ERROR_OBJECT(surfacesrc, "Unknow format");
337             break;
338     }
339     return -1;
340 }
341 
342 // The buffer of the graphics is dynamically expanded.
343 // In order to make the number of buffers used by the graphics correspond to the number of encoders one-to-one.
344 // it is necessary to apply for the buffers first.
gst_surface_pool_src_init_surface_buffer(GstSurfacePoolSrc * surfacesrc)345 static void gst_surface_pool_src_init_surface_buffer(GstSurfacePoolSrc *surfacesrc)
346 {
347     GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(surfacesrc);
348     gint width = DEFAULT_VIDEO_WIDTH;
349     gint height = DEFAULT_VIDEO_HEIGHT;
350     int32_t format = -1;
351     if (memsrc->caps != nullptr) {
352         GstVideoInfo info;
353         gst_video_info_init(&info);
354         gst_video_info_from_caps(&info, memsrc->caps);
355         width = info.width;
356         height = info.height;
357         format = gst_surface_pool_src_gstformat_to_surfaceformat(surfacesrc, &info);
358     }
359     std::vector<OHOS::sptr<OHOS::SurfaceBuffer>> buffers;
360     OHOS::BufferRequestConfig g_requestConfig;
361     g_requestConfig.width = width;
362     g_requestConfig.height = height;
363     g_requestConfig.strideAlignment = static_cast<gint>(surfacesrc->stride);
364     g_requestConfig.format = format;
365     g_requestConfig.usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA;
366     g_requestConfig.timeout = 0;
367     for (uint32_t i = 0; i < surfacesrc->producerSurface->GetQueueSize(); ++i) {
368         OHOS::sptr<OHOS::SurfaceBuffer> buffer;
369         int32_t releaseFence;
370         (void)surfacesrc->producerSurface->RequestBuffer(buffer, releaseFence, g_requestConfig);
371         sptr<OHOS::SyncFence> autoFence = new(std::nothrow) OHOS::SyncFence(releaseFence);
372         if (autoFence != nullptr) {
373             autoFence->Wait(100); // 100ms
374         }
375         if (buffer != nullptr) {
376             buffers.push_back(buffer);
377         }
378     }
379     for (uint32_t i = 0; i < buffers.size(); ++i) {
380         if (buffers[i] != nullptr) {
381             surfacesrc->producerSurface->CancelBuffer(buffers[i]);
382         }
383     }
384 }
385 
gst_surface_pool_src_get_pool(GstSurfacePoolSrc * surfacesrc,GstQuery * query,GstCaps * outcaps,guint min_buf,guint max_buf)386 static gboolean gst_surface_pool_src_get_pool(GstSurfacePoolSrc *surfacesrc, GstQuery *query, GstCaps *outcaps,
387     guint min_buf, guint max_buf)
388 {
389     g_return_val_if_fail(surfacesrc != nullptr && query != nullptr && surfacesrc->consumerSurface != nullptr, FALSE);
390     if (surfacesrc->pool == nullptr) {
391         return FALSE;
392     }
393     GstMemPoolSrc *memsrc = GST_MEM_POOL_SRC(surfacesrc);
394     memsrc->buffer_num = max_buf;
395     gboolean is_video = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
396     if (is_video) {
397         // when video need update size
398         GstVideoInfo info;
399         gst_video_info_init(&info);
400         gst_video_info_from_caps(&info, outcaps);
401         memsrc->buffer_size = info.size;
402     }
403     GST_INFO_OBJECT(surfacesrc, "update buffer num %u", memsrc->buffer_num);
404     SurfaceError ret = surfacesrc->consumerSurface->SetQueueSize(memsrc->buffer_num);
405     if (ret != SURFACE_ERROR_OK) {
406         GST_WARNING_OBJECT(surfacesrc, "set queue size fail");
407     }
408     gst_surface_pool_src_init_surface_buffer(surfacesrc);
409     GstStructure *config = gst_buffer_pool_get_config(surfacesrc->pool);
410     if (is_video) {
411         gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META);
412     }
413     gst_buffer_pool_config_set_params(config, outcaps, memsrc->buffer_size, min_buf, max_buf);
414     if (gst_buffer_pool_set_config(surfacesrc->pool, config) != TRUE) {
415         GST_WARNING_OBJECT(surfacesrc, "set config failed");
416     }
417     gst_query_set_nth_allocation_pool(query, 0, surfacesrc->pool, memsrc->buffer_num, min_buf, max_buf);
418     GST_DEBUG_OBJECT(surfacesrc, "set surface pool success");
419     return TRUE;
420 }
421 
gst_surface_pool_src_decide_allocation(GstBaseSrc * basesrc,GstQuery * query)422 static gboolean gst_surface_pool_src_decide_allocation(GstBaseSrc *basesrc, GstQuery *query)
423 {
424     GstSurfacePoolSrc *surfacesrc = GST_SURFACE_POOL_SRC(basesrc);
425     g_return_val_if_fail(basesrc != nullptr && query != nullptr, FALSE);
426     GST_OBJECT_LOCK(surfacesrc);
427     surfacesrc->need_flush = TRUE;
428     GST_OBJECT_UNLOCK(surfacesrc);
429     GstCaps *outcaps = nullptr;
430     GstBufferPool *pool = nullptr;
431     guint size = 0;
432     guint min_buf = DEFAULT_SURFACE_QUEUE_SIZE;
433     guint max_buf = DEFAULT_SURFACE_QUEUE_SIZE;
434 
435     // get caps and save to video info
436     gst_query_parse_allocation(query, &outcaps, nullptr);
437     // get pool and pool info from down stream
438     if (gst_query_get_n_allocation_pools(query) > 0) {
439         gst_query_parse_nth_allocation_pool(query, 0, &pool, &size, &min_buf, &max_buf);
440     }
441     auto caps_struct = gst_caps_get_structure(outcaps, 0);
442     auto mediaType = gst_structure_get_name(caps_struct);
443     gboolean isVideo = g_str_has_prefix(mediaType, "video/");
444     if (isVideo) {
445         gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
446     }
447     GstVideoInfo info;
448     gst_video_info_init(&info);
449     gst_video_info_from_caps(&info, outcaps);
450     size = info.size;
451 
452     // we use our own pool
453     if (pool != nullptr) {
454         gst_query_set_nth_allocation_pool(query, 0, nullptr, 0, 0, 0);
455         gst_object_unref(pool);
456         pool = nullptr;
457     }
458     if (min_buf > MAX_SURFACE_QUEUE_SIZE || max_buf > MAX_SURFACE_QUEUE_SIZE) {
459         min_buf = MAX_SURFACE_QUEUE_SIZE;
460         max_buf = MAX_SURFACE_QUEUE_SIZE;
461     } else if (min_buf > max_buf) {
462         max_buf = min_buf;
463     } else {
464         max_buf = max_buf == 0 ? DEFAULT_SURFACE_QUEUE_SIZE : max_buf;
465     }
466     if (gst_surface_pool_src_get_pool(surfacesrc, query, outcaps, min_buf, max_buf)) {
467         return TRUE;
468     }
469     return FALSE;
470 }
471