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