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(¶ms);
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, ¶ms);
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