1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gst.app.AppSink;
26 
27 private import gobject.ObjectG;
28 private import gobject.Signals;
29 private import gst.app.c.functions;
30 public  import gst.app.c.types;
31 private import gst.base.BaseSink;
32 private import gstreamer.Caps;
33 private import gstreamer.Sample;
34 private import gstreamer.URIHandlerIF;
35 private import gstreamer.URIHandlerT;
36 private import std.algorithm;
37 
38 
39 /**
40  * Appsink is a sink plugin that supports many different methods for making
41  * the application get a handle on the GStreamer data in a pipeline. Unlike
42  * most GStreamer elements, Appsink provides external API functions.
43  * 
44  * appsink can be used by linking to the gstappsink.h header file to access the
45  * methods or by using the appsink action signals and properties.
46  * 
47  * The normal way of retrieving samples from appsink is by using the
48  * gst_app_sink_pull_sample() and gst_app_sink_pull_preroll() methods.
49  * These methods block until a sample becomes available in the sink or when the
50  * sink is shut down or reaches EOS. There are also timed variants of these
51  * methods, gst_app_sink_try_pull_sample() and gst_app_sink_try_pull_preroll(),
52  * which accept a timeout parameter to limit the amount of time to wait.
53  * 
54  * Appsink will internally use a queue to collect buffers from the streaming
55  * thread. If the application is not pulling samples fast enough, this queue
56  * will consume a lot of memory over time. The "max-buffers" property can be
57  * used to limit the queue size. The "drop" property controls whether the
58  * streaming thread blocks or if older buffers are dropped when the maximum
59  * queue size is reached. Note that blocking the streaming thread can negatively
60  * affect real-time performance and should be avoided.
61  * 
62  * If a blocking behaviour is not desirable, setting the "emit-signals" property
63  * to %TRUE will make appsink emit the "new-sample" and "new-preroll" signals
64  * when a sample can be pulled without blocking.
65  * 
66  * The "caps" property on appsink can be used to control the formats that
67  * appsink can receive. This property can contain non-fixed caps, the format of
68  * the pulled samples can be obtained by getting the sample caps.
69  * 
70  * If one of the pull-preroll or pull-sample methods return %NULL, the appsink
71  * is stopped or in the EOS state. You can check for the EOS state with the
72  * "eos" property or with the gst_app_sink_is_eos() method.
73  * 
74  * The eos signal can also be used to be informed when the EOS state is reached
75  * to avoid polling.
76  */
77 public class AppSink : BaseSink, URIHandlerIF
78 {
79 	/** the main Gtk struct */
80 	protected GstAppSink* gstAppSink;
81 
82 	/** Get the main Gtk struct */
83 	public GstAppSink* getAppSinkStruct(bool transferOwnership = false)
84 	{
85 		if (transferOwnership)
86 			ownedRef = false;
87 		return gstAppSink;
88 	}
89 
90 	/** the main Gtk struct as a void* */
91 	protected override void* getStruct()
92 	{
93 		return cast(void*)gstAppSink;
94 	}
95 
96 	/**
97 	 * Sets our main struct and passes it to the parent class.
98 	 */
99 	public this (GstAppSink* gstAppSink, bool ownedRef = false)
100 	{
101 		this.gstAppSink = gstAppSink;
102 		super(cast(GstBaseSink*)gstAppSink, ownedRef);
103 	}
104 
105 	// add the URIHandler capabilities
106 	mixin URIHandlerT!(GstAppSink);
107 
108 
109 	/** */
110 	public static GType getType()
111 	{
112 		return gst_app_sink_get_type();
113 	}
114 
115 	/**
116 	 * Check if @appsink supports buffer lists.
117 	 *
118 	 * Returns: %TRUE if @appsink supports buffer lists.
119 	 *
120 	 * Since: 1.12
121 	 */
122 	public bool getBufferListSupport()
123 	{
124 		return gst_app_sink_get_buffer_list_support(gstAppSink) != 0;
125 	}
126 
127 	/**
128 	 * Get the configured caps on @appsink.
129 	 *
130 	 * Returns: the #GstCaps accepted by the sink. gst_caps_unref() after usage.
131 	 */
132 	public Caps getCaps()
133 	{
134 		auto p = gst_app_sink_get_caps(gstAppSink);
135 
136 		if(p is null)
137 		{
138 			return null;
139 		}
140 
141 		return ObjectG.getDObject!(Caps)(cast(GstCaps*) p, true);
142 	}
143 
144 	/**
145 	 * Check if @appsink will drop old buffers when the maximum amount of queued
146 	 * buffers is reached.
147 	 *
148 	 * Returns: %TRUE if @appsink is dropping old buffers when the queue is
149 	 *     filled.
150 	 */
151 	public bool getDrop()
152 	{
153 		return gst_app_sink_get_drop(gstAppSink) != 0;
154 	}
155 
156 	/**
157 	 * Check if appsink will emit the "new-preroll" and "new-sample" signals.
158 	 *
159 	 * Returns: %TRUE if @appsink is emiting the "new-preroll" and "new-sample"
160 	 *     signals.
161 	 */
162 	public bool getEmitSignals()
163 	{
164 		return gst_app_sink_get_emit_signals(gstAppSink) != 0;
165 	}
166 
167 	/**
168 	 * Get the maximum amount of buffers that can be queued in @appsink.
169 	 *
170 	 * Returns: The maximum amount of buffers that can be queued.
171 	 */
172 	public uint getMaxBuffers()
173 	{
174 		return gst_app_sink_get_max_buffers(gstAppSink);
175 	}
176 
177 	/**
178 	 * Check if @appsink will wait for all buffers to be consumed when an EOS is
179 	 * received.
180 	 *
181 	 * Returns: %TRUE if @appsink will wait for all buffers to be consumed when an
182 	 *     EOS is received.
183 	 */
184 	public bool getWaitOnEos()
185 	{
186 		return gst_app_sink_get_wait_on_eos(gstAppSink) != 0;
187 	}
188 
189 	/**
190 	 * Check if @appsink is EOS, which is when no more samples can be pulled because
191 	 * an EOS event was received.
192 	 *
193 	 * This function also returns %TRUE when the appsink is not in the PAUSED or
194 	 * PLAYING state.
195 	 *
196 	 * Returns: %TRUE if no more samples can be pulled and the appsink is EOS.
197 	 */
198 	public bool isEos()
199 	{
200 		return gst_app_sink_is_eos(gstAppSink) != 0;
201 	}
202 
203 	/**
204 	 * Get the last preroll sample in @appsink. This was the sample that caused the
205 	 * appsink to preroll in the PAUSED state. This sample can be pulled many times
206 	 * and remains available to the application even after EOS.
207 	 *
208 	 * This function is typically used when dealing with a pipeline in the PAUSED
209 	 * state. Calling this function after doing a seek will give the sample right
210 	 * after the seek position.
211 	 *
212 	 * Note that the preroll sample will also be returned as the first sample
213 	 * when calling gst_app_sink_pull_sample().
214 	 *
215 	 * If an EOS event was received before any buffers, this function returns
216 	 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
217 	 *
218 	 * This function blocks until a preroll sample or EOS is received or the appsink
219 	 * element is set to the READY/NULL state.
220 	 *
221 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
222 	 *     Call gst_sample_unref() after usage.
223 	 */
224 	public Sample pullPreroll()
225 	{
226 		auto p = gst_app_sink_pull_preroll(gstAppSink);
227 
228 		if(p is null)
229 		{
230 			return null;
231 		}
232 
233 		return ObjectG.getDObject!(Sample)(cast(GstSample*) p, true);
234 	}
235 
236 	/**
237 	 * This function blocks until a sample or EOS becomes available or the appsink
238 	 * element is set to the READY/NULL state.
239 	 *
240 	 * This function will only return samples when the appsink is in the PLAYING
241 	 * state. All rendered buffers will be put in a queue so that the application
242 	 * can pull samples at its own rate. Note that when the application does not
243 	 * pull samples fast enough, the queued buffers could consume a lot of memory,
244 	 * especially when dealing with raw video frames.
245 	 *
246 	 * If an EOS event was received before any buffers, this function returns
247 	 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
248 	 *
249 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
250 	 *     Call gst_sample_unref() after usage.
251 	 */
252 	public Sample pullSample()
253 	{
254 		auto p = gst_app_sink_pull_sample(gstAppSink);
255 
256 		if(p is null)
257 		{
258 			return null;
259 		}
260 
261 		return ObjectG.getDObject!(Sample)(cast(GstSample*) p, true);
262 	}
263 
264 	/**
265 	 * Instruct @appsink to enable or disable buffer list support.
266 	 *
267 	 * For backwards-compatibility reasons applications need to opt in
268 	 * to indicate that they will be able to handle buffer lists.
269 	 *
270 	 * Params:
271 	 *     enableLists = enable or disable buffer list support
272 	 *
273 	 * Since: 1.12
274 	 */
275 	public void setBufferListSupport(bool enableLists)
276 	{
277 		gst_app_sink_set_buffer_list_support(gstAppSink, enableLists);
278 	}
279 
280 	/**
281 	 * Set callbacks which will be executed for each new preroll, new sample and eos.
282 	 * This is an alternative to using the signals, it has lower overhead and is thus
283 	 * less expensive, but also less flexible.
284 	 *
285 	 * If callbacks are installed, no signals will be emitted for performance
286 	 * reasons.
287 	 *
288 	 * Params:
289 	 *     callbacks = the callbacks
290 	 *     userData = a user_data argument for the callbacks
291 	 *     notify = a destroy notify function
292 	 */
293 	public void setCallbacks(GstAppSinkCallbacks* callbacks, void* userData, GDestroyNotify notify)
294 	{
295 		gst_app_sink_set_callbacks(gstAppSink, callbacks, userData, notify);
296 	}
297 
298 	/**
299 	 * Set the capabilities on the appsink element.  This function takes
300 	 * a copy of the caps structure. After calling this method, the sink will only
301 	 * accept caps that match @caps. If @caps is non-fixed, or incomplete,
302 	 * you must check the caps on the samples to get the actual used caps.
303 	 *
304 	 * Params:
305 	 *     caps = caps to set
306 	 */
307 	public void setCaps(Caps caps)
308 	{
309 		gst_app_sink_set_caps(gstAppSink, (caps is null) ? null : caps.getCapsStruct());
310 	}
311 
312 	/**
313 	 * Instruct @appsink to drop old buffers when the maximum amount of queued
314 	 * buffers is reached.
315 	 *
316 	 * Params:
317 	 *     drop = the new state
318 	 */
319 	public void setDrop(bool drop)
320 	{
321 		gst_app_sink_set_drop(gstAppSink, drop);
322 	}
323 
324 	/**
325 	 * Make appsink emit the "new-preroll" and "new-sample" signals. This option is
326 	 * by default disabled because signal emission is expensive and unneeded when
327 	 * the application prefers to operate in pull mode.
328 	 *
329 	 * Params:
330 	 *     emit = the new state
331 	 */
332 	public void setEmitSignals(bool emit)
333 	{
334 		gst_app_sink_set_emit_signals(gstAppSink, emit);
335 	}
336 
337 	/**
338 	 * Set the maximum amount of buffers that can be queued in @appsink. After this
339 	 * amount of buffers are queued in appsink, any more buffers will block upstream
340 	 * elements until a sample is pulled from @appsink.
341 	 *
342 	 * Params:
343 	 *     max = the maximum number of buffers to queue
344 	 */
345 	public void setMaxBuffers(uint max)
346 	{
347 		gst_app_sink_set_max_buffers(gstAppSink, max);
348 	}
349 
350 	/**
351 	 * Instruct @appsink to wait for all buffers to be consumed when an EOS is received.
352 	 *
353 	 * Params:
354 	 *     wait = the new state
355 	 */
356 	public void setWaitOnEos(bool wait)
357 	{
358 		gst_app_sink_set_wait_on_eos(gstAppSink, wait);
359 	}
360 
361 	/**
362 	 * Get the last preroll sample in @appsink. This was the sample that caused the
363 	 * appsink to preroll in the PAUSED state. This sample can be pulled many times
364 	 * and remains available to the application even after EOS.
365 	 *
366 	 * This function is typically used when dealing with a pipeline in the PAUSED
367 	 * state. Calling this function after doing a seek will give the sample right
368 	 * after the seek position.
369 	 *
370 	 * Note that the preroll sample will also be returned as the first sample
371 	 * when calling gst_app_sink_pull_sample().
372 	 *
373 	 * If an EOS event was received before any buffers or the timeout expires,
374 	 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
375 	 * condition.
376 	 *
377 	 * This function blocks until a preroll sample or EOS is received, the appsink
378 	 * element is set to the READY/NULL state, or the timeout expires.
379 	 *
380 	 * Params:
381 	 *     timeout = the maximum amount of time to wait for the preroll sample
382 	 *
383 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
384 	 *     Call gst_sample_unref() after usage.
385 	 *
386 	 * Since: 1.10
387 	 */
388 	public Sample tryPullPreroll(GstClockTime timeout)
389 	{
390 		auto p = gst_app_sink_try_pull_preroll(gstAppSink, timeout);
391 
392 		if(p is null)
393 		{
394 			return null;
395 		}
396 
397 		return ObjectG.getDObject!(Sample)(cast(GstSample*) p, true);
398 	}
399 
400 	/**
401 	 * This function blocks until a sample or EOS becomes available or the appsink
402 	 * element is set to the READY/NULL state or the timeout expires.
403 	 *
404 	 * This function will only return samples when the appsink is in the PLAYING
405 	 * state. All rendered buffers will be put in a queue so that the application
406 	 * can pull samples at its own rate. Note that when the application does not
407 	 * pull samples fast enough, the queued buffers could consume a lot of memory,
408 	 * especially when dealing with raw video frames.
409 	 *
410 	 * If an EOS event was received before any buffers or the timeout expires,
411 	 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
412 	 * condition.
413 	 *
414 	 * Params:
415 	 *     timeout = the maximum amount of time to wait for a sample
416 	 *
417 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
418 	 *     Call gst_sample_unref() after usage.
419 	 *
420 	 * Since: 1.10
421 	 */
422 	public Sample tryPullSample(GstClockTime timeout)
423 	{
424 		auto p = gst_app_sink_try_pull_sample(gstAppSink, timeout);
425 
426 		if(p is null)
427 		{
428 			return null;
429 		}
430 
431 		return ObjectG.getDObject!(Sample)(cast(GstSample*) p, true);
432 	}
433 
434 	protected class OnEosDelegateWrapper
435 	{
436 		void delegate(AppSink) dlg;
437 		gulong handlerId;
438 
439 		this(void delegate(AppSink) dlg)
440 		{
441 			this.dlg = dlg;
442 			onEosListeners ~= this;
443 		}
444 
445 		void remove(OnEosDelegateWrapper source)
446 		{
447 			foreach(index, wrapper; onEosListeners)
448 			{
449 				if (wrapper.handlerId == source.handlerId)
450 				{
451 					onEosListeners[index] = null;
452 					onEosListeners = std.algorithm.remove(onEosListeners, index);
453 					break;
454 				}
455 			}
456 		}
457 	}
458 	OnEosDelegateWrapper[] onEosListeners;
459 
460 	/**
461 	 * Signal that the end-of-stream has been reached. This signal is emitted from
462 	 * the streaming thread.
463 	 */
464 	gulong addOnEos(void delegate(AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
465 	{
466 		auto wrapper = new OnEosDelegateWrapper(dlg);
467 		wrapper.handlerId = Signals.connectData(
468 			this,
469 			"eos",
470 			cast(GCallback)&callBackEos,
471 			cast(void*)wrapper,
472 			cast(GClosureNotify)&callBackEosDestroy,
473 			connectFlags);
474 		return wrapper.handlerId;
475 	}
476 
477 	extern(C) static void callBackEos(GstAppSink* appsinkStruct, OnEosDelegateWrapper wrapper)
478 	{
479 		wrapper.dlg(wrapper.outer);
480 	}
481 
482 	extern(C) static void callBackEosDestroy(OnEosDelegateWrapper wrapper, GClosure* closure)
483 	{
484 		wrapper.remove(wrapper);
485 	}
486 
487 	protected class OnNewPrerollDelegateWrapper
488 	{
489 		GstFlowReturn delegate(AppSink) dlg;
490 		gulong handlerId;
491 
492 		this(GstFlowReturn delegate(AppSink) dlg)
493 		{
494 			this.dlg = dlg;
495 			onNewPrerollListeners ~= this;
496 		}
497 
498 		void remove(OnNewPrerollDelegateWrapper source)
499 		{
500 			foreach(index, wrapper; onNewPrerollListeners)
501 			{
502 				if (wrapper.handlerId == source.handlerId)
503 				{
504 					onNewPrerollListeners[index] = null;
505 					onNewPrerollListeners = std.algorithm.remove(onNewPrerollListeners, index);
506 					break;
507 				}
508 			}
509 		}
510 	}
511 	OnNewPrerollDelegateWrapper[] onNewPrerollListeners;
512 
513 	/**
514 	 * Signal that a new preroll sample is available.
515 	 *
516 	 * This signal is emitted from the streaming thread and only when the
517 	 * "emit-signals" property is %TRUE.
518 	 *
519 	 * The new preroll sample can be retrieved with the "pull-preroll" action
520 	 * signal or gst_app_sink_pull_preroll() either from this signal callback
521 	 * or from any other thread.
522 	 *
523 	 * Note that this signal is only emitted when the "emit-signals" property is
524 	 * set to %TRUE, which it is not by default for performance reasons.
525 	 */
526 	gulong addOnNewPreroll(GstFlowReturn delegate(AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
527 	{
528 		auto wrapper = new OnNewPrerollDelegateWrapper(dlg);
529 		wrapper.handlerId = Signals.connectData(
530 			this,
531 			"new-preroll",
532 			cast(GCallback)&callBackNewPreroll,
533 			cast(void*)wrapper,
534 			cast(GClosureNotify)&callBackNewPrerollDestroy,
535 			connectFlags);
536 		return wrapper.handlerId;
537 	}
538 
539 	extern(C) static GstFlowReturn callBackNewPreroll(GstAppSink* appsinkStruct, OnNewPrerollDelegateWrapper wrapper)
540 	{
541 		return wrapper.dlg(wrapper.outer);
542 	}
543 
544 	extern(C) static void callBackNewPrerollDestroy(OnNewPrerollDelegateWrapper wrapper, GClosure* closure)
545 	{
546 		wrapper.remove(wrapper);
547 	}
548 
549 	protected class OnNewSampleDelegateWrapper
550 	{
551 		GstFlowReturn delegate(AppSink) dlg;
552 		gulong handlerId;
553 
554 		this(GstFlowReturn delegate(AppSink) dlg)
555 		{
556 			this.dlg = dlg;
557 			onNewSampleListeners ~= this;
558 		}
559 
560 		void remove(OnNewSampleDelegateWrapper source)
561 		{
562 			foreach(index, wrapper; onNewSampleListeners)
563 			{
564 				if (wrapper.handlerId == source.handlerId)
565 				{
566 					onNewSampleListeners[index] = null;
567 					onNewSampleListeners = std.algorithm.remove(onNewSampleListeners, index);
568 					break;
569 				}
570 			}
571 		}
572 	}
573 	OnNewSampleDelegateWrapper[] onNewSampleListeners;
574 
575 	/**
576 	 * Signal that a new sample is available.
577 	 *
578 	 * This signal is emitted from the streaming thread and only when the
579 	 * "emit-signals" property is %TRUE.
580 	 *
581 	 * The new sample can be retrieved with the "pull-sample" action
582 	 * signal or gst_app_sink_pull_sample() either from this signal callback
583 	 * or from any other thread.
584 	 *
585 	 * Note that this signal is only emitted when the "emit-signals" property is
586 	 * set to %TRUE, which it is not by default for performance reasons.
587 	 */
588 	gulong addOnNewSample(GstFlowReturn delegate(AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
589 	{
590 		auto wrapper = new OnNewSampleDelegateWrapper(dlg);
591 		wrapper.handlerId = Signals.connectData(
592 			this,
593 			"new-sample",
594 			cast(GCallback)&callBackNewSample,
595 			cast(void*)wrapper,
596 			cast(GClosureNotify)&callBackNewSampleDestroy,
597 			connectFlags);
598 		return wrapper.handlerId;
599 	}
600 
601 	extern(C) static GstFlowReturn callBackNewSample(GstAppSink* appsinkStruct, OnNewSampleDelegateWrapper wrapper)
602 	{
603 		return wrapper.dlg(wrapper.outer);
604 	}
605 
606 	extern(C) static void callBackNewSampleDestroy(OnNewSampleDelegateWrapper wrapper, GClosure* closure)
607 	{
608 		wrapper.remove(wrapper);
609 	}
610 
611 	protected class OnPullPrerollDelegateWrapper
612 	{
613 		Sample delegate(AppSink) dlg;
614 		gulong handlerId;
615 
616 		this(Sample delegate(AppSink) dlg)
617 		{
618 			this.dlg = dlg;
619 			onPullPrerollListeners ~= this;
620 		}
621 
622 		void remove(OnPullPrerollDelegateWrapper source)
623 		{
624 			foreach(index, wrapper; onPullPrerollListeners)
625 			{
626 				if (wrapper.handlerId == source.handlerId)
627 				{
628 					onPullPrerollListeners[index] = null;
629 					onPullPrerollListeners = std.algorithm.remove(onPullPrerollListeners, index);
630 					break;
631 				}
632 			}
633 		}
634 	}
635 	OnPullPrerollDelegateWrapper[] onPullPrerollListeners;
636 
637 	/**
638 	 * Get the last preroll sample in @appsink. This was the sample that caused the
639 	 * appsink to preroll in the PAUSED state. This sample can be pulled many times
640 	 * and remains available to the application even after EOS.
641 	 *
642 	 * This function is typically used when dealing with a pipeline in the PAUSED
643 	 * state. Calling this function after doing a seek will give the sample right
644 	 * after the seek position.
645 	 *
646 	 * Note that the preroll sample will also be returned as the first sample
647 	 * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal.
648 	 *
649 	 * If an EOS event was received before any buffers, this function returns
650 	 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
651 	 *
652 	 * This function blocks until a preroll sample or EOS is received or the appsink
653 	 * element is set to the READY/NULL state.
654 	 *
655 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
656 	 */
657 	gulong addOnPullPreroll(Sample delegate(AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
658 	{
659 		auto wrapper = new OnPullPrerollDelegateWrapper(dlg);
660 		wrapper.handlerId = Signals.connectData(
661 			this,
662 			"pull-preroll",
663 			cast(GCallback)&callBackPullPreroll,
664 			cast(void*)wrapper,
665 			cast(GClosureNotify)&callBackPullPrerollDestroy,
666 			connectFlags);
667 		return wrapper.handlerId;
668 	}
669 
670 	extern(C) static GstSample* callBackPullPreroll(GstAppSink* appsinkStruct, OnPullPrerollDelegateWrapper wrapper)
671 	{
672 		auto r = wrapper.dlg(wrapper.outer);
673 		return r.getSampleStruct();
674 	}
675 
676 	extern(C) static void callBackPullPrerollDestroy(OnPullPrerollDelegateWrapper wrapper, GClosure* closure)
677 	{
678 		wrapper.remove(wrapper);
679 	}
680 
681 	protected class OnPullSampleDelegateWrapper
682 	{
683 		Sample delegate(AppSink) dlg;
684 		gulong handlerId;
685 
686 		this(Sample delegate(AppSink) dlg)
687 		{
688 			this.dlg = dlg;
689 			onPullSampleListeners ~= this;
690 		}
691 
692 		void remove(OnPullSampleDelegateWrapper source)
693 		{
694 			foreach(index, wrapper; onPullSampleListeners)
695 			{
696 				if (wrapper.handlerId == source.handlerId)
697 				{
698 					onPullSampleListeners[index] = null;
699 					onPullSampleListeners = std.algorithm.remove(onPullSampleListeners, index);
700 					break;
701 				}
702 			}
703 		}
704 	}
705 	OnPullSampleDelegateWrapper[] onPullSampleListeners;
706 
707 	/**
708 	 * This function blocks until a sample or EOS becomes available or the appsink
709 	 * element is set to the READY/NULL state.
710 	 *
711 	 * This function will only return samples when the appsink is in the PLAYING
712 	 * state. All rendered samples will be put in a queue so that the application
713 	 * can pull samples at its own rate.
714 	 *
715 	 * Note that when the application does not pull samples fast enough, the
716 	 * queued samples could consume a lot of memory, especially when dealing with
717 	 * raw video frames. It's possible to control the behaviour of the queue with
718 	 * the "drop" and "max-buffers" properties.
719 	 *
720 	 * If an EOS event was received before any buffers, this function returns
721 	 * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
722 	 *
723 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
724 	 */
725 	gulong addOnPullSample(Sample delegate(AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
726 	{
727 		auto wrapper = new OnPullSampleDelegateWrapper(dlg);
728 		wrapper.handlerId = Signals.connectData(
729 			this,
730 			"pull-sample",
731 			cast(GCallback)&callBackPullSample,
732 			cast(void*)wrapper,
733 			cast(GClosureNotify)&callBackPullSampleDestroy,
734 			connectFlags);
735 		return wrapper.handlerId;
736 	}
737 
738 	extern(C) static GstSample* callBackPullSample(GstAppSink* appsinkStruct, OnPullSampleDelegateWrapper wrapper)
739 	{
740 		auto r = wrapper.dlg(wrapper.outer);
741 		return r.getSampleStruct();
742 	}
743 
744 	extern(C) static void callBackPullSampleDestroy(OnPullSampleDelegateWrapper wrapper, GClosure* closure)
745 	{
746 		wrapper.remove(wrapper);
747 	}
748 
749 	protected class OnTryPullPrerollDelegateWrapper
750 	{
751 		Sample delegate(ulong, AppSink) dlg;
752 		gulong handlerId;
753 
754 		this(Sample delegate(ulong, AppSink) dlg)
755 		{
756 			this.dlg = dlg;
757 			onTryPullPrerollListeners ~= this;
758 		}
759 
760 		void remove(OnTryPullPrerollDelegateWrapper source)
761 		{
762 			foreach(index, wrapper; onTryPullPrerollListeners)
763 			{
764 				if (wrapper.handlerId == source.handlerId)
765 				{
766 					onTryPullPrerollListeners[index] = null;
767 					onTryPullPrerollListeners = std.algorithm.remove(onTryPullPrerollListeners, index);
768 					break;
769 				}
770 			}
771 		}
772 	}
773 	OnTryPullPrerollDelegateWrapper[] onTryPullPrerollListeners;
774 
775 	/**
776 	 * Get the last preroll sample in @appsink. This was the sample that caused the
777 	 * appsink to preroll in the PAUSED state. This sample can be pulled many times
778 	 * and remains available to the application even after EOS.
779 	 *
780 	 * This function is typically used when dealing with a pipeline in the PAUSED
781 	 * state. Calling this function after doing a seek will give the sample right
782 	 * after the seek position.
783 	 *
784 	 * Note that the preroll sample will also be returned as the first sample
785 	 * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal.
786 	 *
787 	 * If an EOS event was received before any buffers or the timeout expires,
788 	 * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS
789 	 * condition.
790 	 *
791 	 * This function blocks until a preroll sample or EOS is received, the appsink
792 	 * element is set to the READY/NULL state, or the timeout expires.
793 	 *
794 	 * Params:
795 	 *     timeout = the maximum amount of time to wait for the preroll sample
796 	 *
797 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
798 	 *
799 	 * Since: 1.10
800 	 */
801 	gulong addOnTryPullPreroll(Sample delegate(ulong, AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
802 	{
803 		auto wrapper = new OnTryPullPrerollDelegateWrapper(dlg);
804 		wrapper.handlerId = Signals.connectData(
805 			this,
806 			"try-pull-preroll",
807 			cast(GCallback)&callBackTryPullPreroll,
808 			cast(void*)wrapper,
809 			cast(GClosureNotify)&callBackTryPullPrerollDestroy,
810 			connectFlags);
811 		return wrapper.handlerId;
812 	}
813 
814 	extern(C) static GstSample* callBackTryPullPreroll(GstAppSink* appsinkStruct, ulong timeout, OnTryPullPrerollDelegateWrapper wrapper)
815 	{
816 		auto r = wrapper.dlg(timeout, wrapper.outer);
817 		return r.getSampleStruct();
818 	}
819 
820 	extern(C) static void callBackTryPullPrerollDestroy(OnTryPullPrerollDelegateWrapper wrapper, GClosure* closure)
821 	{
822 		wrapper.remove(wrapper);
823 	}
824 
825 	protected class OnTryPullSampleDelegateWrapper
826 	{
827 		Sample delegate(ulong, AppSink) dlg;
828 		gulong handlerId;
829 
830 		this(Sample delegate(ulong, AppSink) dlg)
831 		{
832 			this.dlg = dlg;
833 			onTryPullSampleListeners ~= this;
834 		}
835 
836 		void remove(OnTryPullSampleDelegateWrapper source)
837 		{
838 			foreach(index, wrapper; onTryPullSampleListeners)
839 			{
840 				if (wrapper.handlerId == source.handlerId)
841 				{
842 					onTryPullSampleListeners[index] = null;
843 					onTryPullSampleListeners = std.algorithm.remove(onTryPullSampleListeners, index);
844 					break;
845 				}
846 			}
847 		}
848 	}
849 	OnTryPullSampleDelegateWrapper[] onTryPullSampleListeners;
850 
851 	/**
852 	 * This function blocks until a sample or EOS becomes available or the appsink
853 	 * element is set to the READY/NULL state or the timeout expires.
854 	 *
855 	 * This function will only return samples when the appsink is in the PLAYING
856 	 * state. All rendered samples will be put in a queue so that the application
857 	 * can pull samples at its own rate.
858 	 *
859 	 * Note that when the application does not pull samples fast enough, the
860 	 * queued samples could consume a lot of memory, especially when dealing with
861 	 * raw video frames. It's possible to control the behaviour of the queue with
862 	 * the "drop" and "max-buffers" properties.
863 	 *
864 	 * If an EOS event was received before any buffers or the timeout expires,
865 	 * this function returns %NULL. Use gst_app_sink_is_eos () to check
866 	 * for the EOS condition.
867 	 *
868 	 * Params:
869 	 *     timeout = the maximum amount of time to wait for a sample
870 	 *
871 	 * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires.
872 	 *
873 	 * Since: 1.10
874 	 */
875 	gulong addOnTryPullSample(Sample delegate(ulong, AppSink) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
876 	{
877 		auto wrapper = new OnTryPullSampleDelegateWrapper(dlg);
878 		wrapper.handlerId = Signals.connectData(
879 			this,
880 			"try-pull-sample",
881 			cast(GCallback)&callBackTryPullSample,
882 			cast(void*)wrapper,
883 			cast(GClosureNotify)&callBackTryPullSampleDestroy,
884 			connectFlags);
885 		return wrapper.handlerId;
886 	}
887 
888 	extern(C) static GstSample* callBackTryPullSample(GstAppSink* appsinkStruct, ulong timeout, OnTryPullSampleDelegateWrapper wrapper)
889 	{
890 		auto r = wrapper.dlg(timeout, wrapper.outer);
891 		return r.getSampleStruct();
892 	}
893 
894 	extern(C) static void callBackTryPullSampleDestroy(OnTryPullSampleDelegateWrapper wrapper, GClosure* closure)
895 	{
896 		wrapper.remove(wrapper);
897 	}
898 }