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