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.AppSrc;
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.BaseSrc;
32 private import gstreamer.Buffer;
33 private import gstreamer.Caps;
34 private import gstreamer.Sample;
35 private import gstreamer.URIHandlerIF;
36 private import gstreamer.URIHandlerT;
37 private import std.algorithm;
38 
39 
40 /**
41  * The appsrc element can be used by applications to insert data into a
42  * GStreamer pipeline. Unlike most GStreamer elements, appsrc provides
43  * external API functions.
44  * 
45  * appsrc can be used by linking with the libgstapp library to access the
46  * methods directly or by using the appsrc action signals.
47  * 
48  * Before operating appsrc, the caps property must be set to fixed caps
49  * describing the format of the data that will be pushed with appsrc. An
50  * exception to this is when pushing buffers with unknown caps, in which case no
51  * caps should be set. This is typically true of file-like sources that push raw
52  * byte buffers. If you don't want to explicitly set the caps, you can use
53  * gst_app_src_push_sample. This method gets the caps associated with the
54  * sample and sets them on the appsrc replacing any previously set caps (if
55  * different from sample's caps).
56  * 
57  * The main way of handing data to the appsrc element is by calling the
58  * gst_app_src_push_buffer() method or by emitting the push-buffer action signal.
59  * This will put the buffer onto a queue from which appsrc will read from in its
60  * streaming thread. It is important to note that data transport will not happen
61  * from the thread that performed the push-buffer call.
62  * 
63  * The "max-bytes" property controls how much data can be queued in appsrc
64  * before appsrc considers the queue full. A filled internal queue will always
65  * signal the "enough-data" signal, which signals the application that it should
66  * stop pushing data into appsrc. The "block" property will cause appsrc to
67  * block the push-buffer method until free data becomes available again.
68  * 
69  * When the internal queue is running out of data, the "need-data" signal is
70  * emitted, which signals the application that it should start pushing more data
71  * into appsrc.
72  * 
73  * In addition to the "need-data" and "enough-data" signals, appsrc can emit the
74  * "seek-data" signal when the "stream-mode" property is set to "seekable" or
75  * "random-access". The signal argument will contain the new desired position in
76  * the stream expressed in the unit set with the "format" property. After
77  * receiving the seek-data signal, the application should push-buffers from the
78  * new position.
79  * 
80  * These signals allow the application to operate the appsrc in two different
81  * ways:
82  * 
83  * The push mode, in which the application repeatedly calls the push-buffer/push-sample
84  * method with a new buffer/sample. Optionally, the queue size in the appsrc
85  * can be controlled with the enough-data and need-data signals by respectively
86  * stopping/starting the push-buffer/push-sample calls. This is a typical
87  * mode of operation for the stream-type "stream" and "seekable". Use this
88  * mode when implementing various network protocols or hardware devices.
89  * 
90  * The pull mode, in which the need-data signal triggers the next push-buffer call.
91  * This mode is typically used in the "random-access" stream-type. Use this
92  * mode for file access or other randomly accessable sources. In this mode, a
93  * buffer of exactly the amount of bytes given by the need-data signal should be
94  * pushed into appsrc.
95  * 
96  * In all modes, the size property on appsrc should contain the total stream
97  * size in bytes. Setting this property is mandatory in the random-access mode.
98  * For the stream and seekable modes, setting this property is optional but
99  * recommended.
100  * 
101  * When the application has finished pushing data into appsrc, it should call
102  * gst_app_src_end_of_stream() or emit the end-of-stream action signal. After
103  * this call, no more buffers can be pushed into appsrc until a flushing seek
104  * occurs or the state of the appsrc has gone through READY.
105  */
106 public class AppSrc : BaseSrc, URIHandlerIF
107 {
108 	/** the main Gtk struct */
109 	protected GstAppSrc* gstAppSrc;
110 
111 	/** Get the main Gtk struct */
112 	public GstAppSrc* getAppSrcStruct(bool transferOwnership = false)
113 	{
114 		if (transferOwnership)
115 			ownedRef = false;
116 		return gstAppSrc;
117 	}
118 
119 	/** the main Gtk struct as a void* */
120 	protected override void* getStruct()
121 	{
122 		return cast(void*)gstAppSrc;
123 	}
124 
125 	protected override void setStruct(GObject* obj)
126 	{
127 		gstAppSrc = cast(GstAppSrc*)obj;
128 		super.setStruct(obj);
129 	}
130 
131 	/**
132 	 * Sets our main struct and passes it to the parent class.
133 	 */
134 	public this (GstAppSrc* gstAppSrc, bool ownedRef = false)
135 	{
136 		this.gstAppSrc = gstAppSrc;
137 		super(cast(GstBaseSrc*)gstAppSrc, ownedRef);
138 	}
139 
140 	// add the URIHandler capabilities
141 	mixin URIHandlerT!(GstAppSrc);
142 
143 
144 	/** */
145 	public static GType getType()
146 	{
147 		return gst_app_src_get_type();
148 	}
149 
150 	/**
151 	 * Indicates to the appsrc element that the last buffer queued in the
152 	 * element is the last buffer of the stream.
153 	 *
154 	 * Returns: #GST_FLOW_OK when the EOS was successfuly queued.
155 	 *     #GST_FLOW_FLUSHING when @appsrc is not PAUSED or PLAYING.
156 	 */
157 	public GstFlowReturn endOfStream()
158 	{
159 		return gst_app_src_end_of_stream(gstAppSrc);
160 	}
161 
162 	/**
163 	 * Get the configured caps on @appsrc.
164 	 *
165 	 * Returns: the #GstCaps produced by the source. gst_caps_unref() after usage.
166 	 */
167 	public Caps getCaps()
168 	{
169 		auto p = gst_app_src_get_caps(gstAppSrc);
170 
171 		if(p is null)
172 		{
173 			return null;
174 		}
175 
176 		return ObjectG.getDObject!(Caps)(cast(GstCaps*) p, true);
177 	}
178 
179 	/**
180 	 * Get the number of currently queued bytes inside @appsrc.
181 	 *
182 	 * Returns: The number of currently queued bytes.
183 	 *
184 	 * Since: 1.2
185 	 */
186 	public ulong getCurrentLevelBytes()
187 	{
188 		return gst_app_src_get_current_level_bytes(gstAppSrc);
189 	}
190 
191 	/**
192 	 * Get the duration of the stream in nanoseconds. A value of GST_CLOCK_TIME_NONE means that the duration is
193 	 * not known.
194 	 *
195 	 * Returns: the duration of the stream previously set with gst_app_src_set_duration();
196 	 *
197 	 * Since: 1.10
198 	 */
199 	public GstClockTime getDuration()
200 	{
201 		return gst_app_src_get_duration(gstAppSrc);
202 	}
203 
204 	/**
205 	 * Check if appsrc will emit the "new-preroll" and "new-buffer" signals.
206 	 *
207 	 * Returns: %TRUE if @appsrc is emitting the "new-preroll" and "new-buffer"
208 	 *     signals.
209 	 */
210 	public bool getEmitSignals()
211 	{
212 		return gst_app_src_get_emit_signals(gstAppSrc) != 0;
213 	}
214 
215 	/**
216 	 * Retrieve the min and max latencies in @min and @max respectively.
217 	 *
218 	 * Params:
219 	 *     min = the min latency
220 	 *     max = the min latency
221 	 */
222 	public void getLatency(ulong* min, ulong* max)
223 	{
224 		gst_app_src_get_latency(gstAppSrc, min, max);
225 	}
226 
227 	/**
228 	 * Get the maximum amount of bytes that can be queued in @appsrc.
229 	 *
230 	 * Returns: The maximum amount of bytes that can be queued.
231 	 */
232 	public ulong getMaxBytes()
233 	{
234 		return gst_app_src_get_max_bytes(gstAppSrc);
235 	}
236 
237 	/**
238 	 * Get the size of the stream in bytes. A value of -1 means that the size is
239 	 * not known.
240 	 *
241 	 * Returns: the size of the stream previously set with gst_app_src_set_size();
242 	 */
243 	public long getSize()
244 	{
245 		return gst_app_src_get_size(gstAppSrc);
246 	}
247 
248 	/**
249 	 * Get the stream type. Control the stream type of @appsrc
250 	 * with gst_app_src_set_stream_type().
251 	 *
252 	 * Returns: the stream type.
253 	 */
254 	public GstAppStreamType getStreamType()
255 	{
256 		return gst_app_src_get_stream_type(gstAppSrc);
257 	}
258 
259 	/**
260 	 * Adds a buffer to the queue of buffers that the appsrc element will
261 	 * push to its source pad.  This function takes ownership of the buffer.
262 	 *
263 	 * When the block property is TRUE, this function can block until free
264 	 * space becomes available in the queue.
265 	 *
266 	 * Params:
267 	 *     buffer = a #GstBuffer to push
268 	 *
269 	 * Returns: #GST_FLOW_OK when the buffer was successfuly queued.
270 	 *     #GST_FLOW_FLUSHING when @appsrc is not PAUSED or PLAYING.
271 	 *     #GST_FLOW_EOS when EOS occured.
272 	 */
273 	public GstFlowReturn pushBuffer(Buffer buffer)
274 	{
275 		return gst_app_src_push_buffer(gstAppSrc, (buffer is null) ? null : buffer.getBufferStruct());
276 	}
277 
278 	/**
279 	 * Extract a buffer from the provided sample and adds it to the queue of
280 	 * buffers that the appsrc element will push to its source pad. Any
281 	 * previous caps that were set on appsrc will be replaced by the caps
282 	 * associated with the sample if not equal.
283 	 *
284 	 * When the block property is TRUE, this function can block until free
285 	 * space becomes available in the queue.
286 	 *
287 	 * Params:
288 	 *     sample = a #GstSample from which buffer and caps may be
289 	 *         extracted
290 	 *
291 	 * Returns: #GST_FLOW_OK when the buffer was successfuly queued.
292 	 *     #GST_FLOW_FLUSHING when @appsrc is not PAUSED or PLAYING.
293 	 *     #GST_FLOW_EOS when EOS occured.
294 	 *
295 	 * Since: 1.6
296 	 */
297 	public GstFlowReturn pushSample(Sample sample)
298 	{
299 		return gst_app_src_push_sample(gstAppSrc, (sample is null) ? null : sample.getSampleStruct());
300 	}
301 
302 	/**
303 	 * Set callbacks which will be executed when data is needed, enough data has
304 	 * been collected or when a seek should be performed.
305 	 * This is an alternative to using the signals, it has lower overhead and is thus
306 	 * less expensive, but also less flexible.
307 	 *
308 	 * If callbacks are installed, no signals will be emitted for performance
309 	 * reasons.
310 	 *
311 	 * Params:
312 	 *     callbacks = the callbacks
313 	 *     userData = a user_data argument for the callbacks
314 	 *     notify = a destroy notify function
315 	 */
316 	public void setCallbacks(GstAppSrcCallbacks* callbacks, void* userData, GDestroyNotify notify)
317 	{
318 		gst_app_src_set_callbacks(gstAppSrc, callbacks, userData, notify);
319 	}
320 
321 	/**
322 	 * Set the duration of the stream in nanoseconds. A value of GST_CLOCK_TIME_NONE means that the duration is
323 	 * not known.
324 	 *
325 	 * Params:
326 	 *     duration = the duration to set
327 	 *
328 	 * Since: 1.10
329 	 */
330 	public void setDuration(GstClockTime duration)
331 	{
332 		gst_app_src_set_duration(gstAppSrc, duration);
333 	}
334 
335 	/**
336 	 * Make appsrc emit the "new-preroll" and "new-buffer" signals. This option is
337 	 * by default disabled because signal emission is expensive and unneeded when
338 	 * the application prefers to operate in pull mode.
339 	 *
340 	 * Params:
341 	 *     emit = the new state
342 	 */
343 	public void setEmitSignals(bool emit)
344 	{
345 		gst_app_src_set_emit_signals(gstAppSrc, emit);
346 	}
347 
348 	/**
349 	 * Configure the @min and @max latency in @src. If @min is set to -1, the
350 	 * default latency calculations for pseudo-live sources will be used.
351 	 *
352 	 * Params:
353 	 *     min = the min latency
354 	 *     max = the min latency
355 	 */
356 	public void setLatency(ulong min, ulong max)
357 	{
358 		gst_app_src_set_latency(gstAppSrc, min, max);
359 	}
360 
361 	/**
362 	 * Set the maximum amount of bytes that can be queued in @appsrc.
363 	 * After the maximum amount of bytes are queued, @appsrc will emit the
364 	 * "enough-data" signal.
365 	 *
366 	 * Params:
367 	 *     max = the maximum number of bytes to queue
368 	 */
369 	public void setMaxBytes(ulong max)
370 	{
371 		gst_app_src_set_max_bytes(gstAppSrc, max);
372 	}
373 
374 	/**
375 	 * Set the size of the stream in bytes. A value of -1 means that the size is
376 	 * not known.
377 	 *
378 	 * Params:
379 	 *     size = the size to set
380 	 */
381 	public void setSize(long size)
382 	{
383 		gst_app_src_set_size(gstAppSrc, size);
384 	}
385 
386 	/**
387 	 * Set the stream type on @appsrc. For seekable streams, the "seek" signal must
388 	 * be connected to.
389 	 *
390 	 * A stream_type stream
391 	 *
392 	 * Params:
393 	 *     type = the new state
394 	 */
395 	public void setStreamType(GstAppStreamType type)
396 	{
397 		gst_app_src_set_stream_type(gstAppSrc, type);
398 	}
399 
400 	protected class OnEndOfStreamDelegateWrapper
401 	{
402 		GstFlowReturn delegate(AppSrc) dlg;
403 		gulong handlerId;
404 
405 		this(GstFlowReturn delegate(AppSrc) dlg)
406 		{
407 			this.dlg = dlg;
408 			onEndOfStreamListeners ~= this;
409 		}
410 
411 		void remove(OnEndOfStreamDelegateWrapper source)
412 		{
413 			foreach(index, wrapper; onEndOfStreamListeners)
414 			{
415 				if (wrapper.handlerId == source.handlerId)
416 				{
417 					onEndOfStreamListeners[index] = null;
418 					onEndOfStreamListeners = std.algorithm.remove(onEndOfStreamListeners, index);
419 					break;
420 				}
421 			}
422 		}
423 	}
424 	OnEndOfStreamDelegateWrapper[] onEndOfStreamListeners;
425 
426 	/**
427 	 * Notify @appsrc that no more buffer are available.
428 	 */
429 	gulong addOnEndOfStream(GstFlowReturn delegate(AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
430 	{
431 		auto wrapper = new OnEndOfStreamDelegateWrapper(dlg);
432 		wrapper.handlerId = Signals.connectData(
433 			this,
434 			"end-of-stream",
435 			cast(GCallback)&callBackEndOfStream,
436 			cast(void*)wrapper,
437 			cast(GClosureNotify)&callBackEndOfStreamDestroy,
438 			connectFlags);
439 		return wrapper.handlerId;
440 	}
441 
442 	extern(C) static GstFlowReturn callBackEndOfStream(GstAppSrc* appsrcStruct, OnEndOfStreamDelegateWrapper wrapper)
443 	{
444 		return wrapper.dlg(wrapper.outer);
445 	}
446 
447 	extern(C) static void callBackEndOfStreamDestroy(OnEndOfStreamDelegateWrapper wrapper, GClosure* closure)
448 	{
449 		wrapper.remove(wrapper);
450 	}
451 
452 	protected class OnEnoughDataDelegateWrapper
453 	{
454 		void delegate(AppSrc) dlg;
455 		gulong handlerId;
456 
457 		this(void delegate(AppSrc) dlg)
458 		{
459 			this.dlg = dlg;
460 			onEnoughDataListeners ~= this;
461 		}
462 
463 		void remove(OnEnoughDataDelegateWrapper source)
464 		{
465 			foreach(index, wrapper; onEnoughDataListeners)
466 			{
467 				if (wrapper.handlerId == source.handlerId)
468 				{
469 					onEnoughDataListeners[index] = null;
470 					onEnoughDataListeners = std.algorithm.remove(onEnoughDataListeners, index);
471 					break;
472 				}
473 			}
474 		}
475 	}
476 	OnEnoughDataDelegateWrapper[] onEnoughDataListeners;
477 
478 	/**
479 	 * Signal that the source has enough data. It is recommended that the
480 	 * application stops calling push-buffer until the need-data signal is
481 	 * emitted again to avoid excessive buffer queueing.
482 	 */
483 	gulong addOnEnoughData(void delegate(AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
484 	{
485 		auto wrapper = new OnEnoughDataDelegateWrapper(dlg);
486 		wrapper.handlerId = Signals.connectData(
487 			this,
488 			"enough-data",
489 			cast(GCallback)&callBackEnoughData,
490 			cast(void*)wrapper,
491 			cast(GClosureNotify)&callBackEnoughDataDestroy,
492 			connectFlags);
493 		return wrapper.handlerId;
494 	}
495 
496 	extern(C) static void callBackEnoughData(GstAppSrc* appsrcStruct, OnEnoughDataDelegateWrapper wrapper)
497 	{
498 		wrapper.dlg(wrapper.outer);
499 	}
500 
501 	extern(C) static void callBackEnoughDataDestroy(OnEnoughDataDelegateWrapper wrapper, GClosure* closure)
502 	{
503 		wrapper.remove(wrapper);
504 	}
505 
506 	protected class OnNeedDataDelegateWrapper
507 	{
508 		void delegate(uint, AppSrc) dlg;
509 		gulong handlerId;
510 
511 		this(void delegate(uint, AppSrc) dlg)
512 		{
513 			this.dlg = dlg;
514 			onNeedDataListeners ~= this;
515 		}
516 
517 		void remove(OnNeedDataDelegateWrapper source)
518 		{
519 			foreach(index, wrapper; onNeedDataListeners)
520 			{
521 				if (wrapper.handlerId == source.handlerId)
522 				{
523 					onNeedDataListeners[index] = null;
524 					onNeedDataListeners = std.algorithm.remove(onNeedDataListeners, index);
525 					break;
526 				}
527 			}
528 		}
529 	}
530 	OnNeedDataDelegateWrapper[] onNeedDataListeners;
531 
532 	/**
533 	 * Signal that the source needs more data. In the callback or from another
534 	 * thread you should call push-buffer or end-of-stream.
535 	 *
536 	 * @length is just a hint and when it is set to -1, any number of bytes can be
537 	 * pushed into @appsrc.
538 	 *
539 	 * You can call push-buffer multiple times until the enough-data signal is
540 	 * fired.
541 	 *
542 	 * Params:
543 	 *     length = the amount of bytes needed.
544 	 */
545 	gulong addOnNeedData(void delegate(uint, AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
546 	{
547 		auto wrapper = new OnNeedDataDelegateWrapper(dlg);
548 		wrapper.handlerId = Signals.connectData(
549 			this,
550 			"need-data",
551 			cast(GCallback)&callBackNeedData,
552 			cast(void*)wrapper,
553 			cast(GClosureNotify)&callBackNeedDataDestroy,
554 			connectFlags);
555 		return wrapper.handlerId;
556 	}
557 
558 	extern(C) static void callBackNeedData(GstAppSrc* appsrcStruct, uint length, OnNeedDataDelegateWrapper wrapper)
559 	{
560 		wrapper.dlg(length, wrapper.outer);
561 	}
562 
563 	extern(C) static void callBackNeedDataDestroy(OnNeedDataDelegateWrapper wrapper, GClosure* closure)
564 	{
565 		wrapper.remove(wrapper);
566 	}
567 
568 	protected class OnPushBufferDelegateWrapper
569 	{
570 		GstFlowReturn delegate(Buffer, AppSrc) dlg;
571 		gulong handlerId;
572 
573 		this(GstFlowReturn delegate(Buffer, AppSrc) dlg)
574 		{
575 			this.dlg = dlg;
576 			onPushBufferListeners ~= this;
577 		}
578 
579 		void remove(OnPushBufferDelegateWrapper source)
580 		{
581 			foreach(index, wrapper; onPushBufferListeners)
582 			{
583 				if (wrapper.handlerId == source.handlerId)
584 				{
585 					onPushBufferListeners[index] = null;
586 					onPushBufferListeners = std.algorithm.remove(onPushBufferListeners, index);
587 					break;
588 				}
589 			}
590 		}
591 	}
592 	OnPushBufferDelegateWrapper[] onPushBufferListeners;
593 
594 	/**
595 	 * Adds a buffer to the queue of buffers that the appsrc element will
596 	 * push to its source pad. This function does not take ownership of the
597 	 * buffer so the buffer needs to be unreffed after calling this function.
598 	 *
599 	 * When the block property is TRUE, this function can block until free space
600 	 * becomes available in the queue.
601 	 *
602 	 * Params:
603 	 *     buffer = a buffer to push
604 	 */
605 	gulong addOnPushBuffer(GstFlowReturn delegate(Buffer, AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
606 	{
607 		auto wrapper = new OnPushBufferDelegateWrapper(dlg);
608 		wrapper.handlerId = Signals.connectData(
609 			this,
610 			"push-buffer",
611 			cast(GCallback)&callBackPushBuffer,
612 			cast(void*)wrapper,
613 			cast(GClosureNotify)&callBackPushBufferDestroy,
614 			connectFlags);
615 		return wrapper.handlerId;
616 	}
617 
618 	extern(C) static GstFlowReturn callBackPushBuffer(GstAppSrc* appsrcStruct, GstBuffer* buffer, OnPushBufferDelegateWrapper wrapper)
619 	{
620 		return wrapper.dlg(ObjectG.getDObject!(Buffer)(buffer), wrapper.outer);
621 	}
622 
623 	extern(C) static void callBackPushBufferDestroy(OnPushBufferDelegateWrapper wrapper, GClosure* closure)
624 	{
625 		wrapper.remove(wrapper);
626 	}
627 
628 	protected class OnPushSampleDelegateWrapper
629 	{
630 		GstFlowReturn delegate(Sample, AppSrc) dlg;
631 		gulong handlerId;
632 
633 		this(GstFlowReturn delegate(Sample, AppSrc) dlg)
634 		{
635 			this.dlg = dlg;
636 			onPushSampleListeners ~= this;
637 		}
638 
639 		void remove(OnPushSampleDelegateWrapper source)
640 		{
641 			foreach(index, wrapper; onPushSampleListeners)
642 			{
643 				if (wrapper.handlerId == source.handlerId)
644 				{
645 					onPushSampleListeners[index] = null;
646 					onPushSampleListeners = std.algorithm.remove(onPushSampleListeners, index);
647 					break;
648 				}
649 			}
650 		}
651 	}
652 	OnPushSampleDelegateWrapper[] onPushSampleListeners;
653 
654 	/**
655 	 * Extract a buffer from the provided sample and adds the extracted buffer
656 	 * to the queue of buffers that the appsrc element will
657 	 * push to its source pad. This function set the appsrc caps based on the caps
658 	 * in the sample and reset the caps if they change.
659 	 * Only the caps and the buffer of the provided sample are used and not
660 	 * for example the segment in the sample.
661 	 * This function does not take ownership of the
662 	 * sample so the sample needs to be unreffed after calling this function.
663 	 *
664 	 * When the block property is TRUE, this function can block until free space
665 	 * becomes available in the queue.
666 	 *
667 	 * Params:
668 	 *     sample = a sample from which extract buffer to push
669 	 *
670 	 * Since: 1.6
671 	 */
672 	gulong addOnPushSample(GstFlowReturn delegate(Sample, AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
673 	{
674 		auto wrapper = new OnPushSampleDelegateWrapper(dlg);
675 		wrapper.handlerId = Signals.connectData(
676 			this,
677 			"push-sample",
678 			cast(GCallback)&callBackPushSample,
679 			cast(void*)wrapper,
680 			cast(GClosureNotify)&callBackPushSampleDestroy,
681 			connectFlags);
682 		return wrapper.handlerId;
683 	}
684 
685 	extern(C) static GstFlowReturn callBackPushSample(GstAppSrc* appsrcStruct, GstSample* sample, OnPushSampleDelegateWrapper wrapper)
686 	{
687 		return wrapper.dlg(ObjectG.getDObject!(Sample)(sample), wrapper.outer);
688 	}
689 
690 	extern(C) static void callBackPushSampleDestroy(OnPushSampleDelegateWrapper wrapper, GClosure* closure)
691 	{
692 		wrapper.remove(wrapper);
693 	}
694 
695 	protected class OnSeekDataDelegateWrapper
696 	{
697 		bool delegate(ulong, AppSrc) dlg;
698 		gulong handlerId;
699 
700 		this(bool delegate(ulong, AppSrc) dlg)
701 		{
702 			this.dlg = dlg;
703 			onSeekDataListeners ~= this;
704 		}
705 
706 		void remove(OnSeekDataDelegateWrapper source)
707 		{
708 			foreach(index, wrapper; onSeekDataListeners)
709 			{
710 				if (wrapper.handlerId == source.handlerId)
711 				{
712 					onSeekDataListeners[index] = null;
713 					onSeekDataListeners = std.algorithm.remove(onSeekDataListeners, index);
714 					break;
715 				}
716 			}
717 		}
718 	}
719 	OnSeekDataDelegateWrapper[] onSeekDataListeners;
720 
721 	/**
722 	 * Seek to the given offset. The next push-buffer should produce buffers from
723 	 * the new @offset.
724 	 * This callback is only called for seekable stream types.
725 	 *
726 	 * Params:
727 	 *     offset = the offset to seek to
728 	 *
729 	 * Returns: %TRUE if the seek succeeded.
730 	 */
731 	gulong addOnSeekData(bool delegate(ulong, AppSrc) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
732 	{
733 		auto wrapper = new OnSeekDataDelegateWrapper(dlg);
734 		wrapper.handlerId = Signals.connectData(
735 			this,
736 			"seek-data",
737 			cast(GCallback)&callBackSeekData,
738 			cast(void*)wrapper,
739 			cast(GClosureNotify)&callBackSeekDataDestroy,
740 			connectFlags);
741 		return wrapper.handlerId;
742 	}
743 
744 	extern(C) static int callBackSeekData(GstAppSrc* appsrcStruct, ulong offset, OnSeekDataDelegateWrapper wrapper)
745 	{
746 		return wrapper.dlg(offset, wrapper.outer);
747 	}
748 
749 	extern(C) static void callBackSeekDataDestroy(OnSeekDataDelegateWrapper wrapper, GClosure* closure)
750 	{
751 		wrapper.remove(wrapper);
752 	}
753 
754 	/**
755 	 * Set the capabilities on the appsrc element.  This function takes
756 	 * a copy of the caps structure. After calling this method, the source will
757 	 * only produce caps that match @caps. @caps must be fixed and the caps on the
758 	 * buffers must match the caps or left NULL.
759 	 *
760 	 * Params:
761 	 *     caps = caps to set
762 	 */
763 	public void appSrcSetCaps(Caps caps)
764 	{
765 		gst_app_src_set_caps(gstAppSrc, (caps is null) ? null : caps.getCapsStruct());
766 	}
767 }