avwait: Fix sending of dropping=true messages
[platform/upstream/gstreamer.git] / gst / timecode / gstavwait.c
1 /*
2  * GStreamer
3  * Copyright (C) 2016 Vivia Nikolaidou <vivia@toolsonair.com>
4  *
5  * Based on gstvideoframe-audiolevel.c:
6  * Copyright (C) 2015 Vivia Nikolaidou <vivia@toolsonair.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:element-avwait
26  * @title: avwait
27  *
28  * This element will drop all buffers until a specific timecode or running
29  * time has been reached. It will then pass-through both audio and video,
30  * starting from that specific timecode or running time, making sure that
31  * audio starts as early as possible after the video (or at the same time as
32  * the video). In the "video-first" mode, it only drops audio buffers until
33  * video has started.
34  *
35  * The "recording" property acts essentially like a valve connected before
36  * everything else. If recording is FALSE, all buffers are dropped regardless
37  * of settings. If recording is TRUE, the other settings (mode,
38  * target-timecode, target-running-time, etc) are taken into account. Audio
39  * will always start and end together with the video, as long as the stream
40  * itself doesn't start too late or end too early.
41  *
42  * ## Example launch line
43  * |[
44  * gst-launch-1.0 filesrc location="my_file" ! decodebin name=d ! "audio/x-raw" ! avwait name=l target-timecode-str="00:00:04:00" ! autoaudiosink d. ! "video/x-raw" ! timecodestamper ! l. l. ! queue ! timeoverlay time-mode=time-code ! autovideosink
45  *
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include "gstavwait.h"
53
54 #define GST_CAT_DEFAULT gst_avwait_debug
55 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
56
57 static GstStaticPadTemplate audio_sink_template =
58 GST_STATIC_PAD_TEMPLATE ("asink",
59     GST_PAD_SINK,
60     GST_PAD_ALWAYS,
61     GST_STATIC_CAPS ("audio/x-raw")
62     );
63
64 static GstStaticPadTemplate audio_src_template =
65 GST_STATIC_PAD_TEMPLATE ("asrc",
66     GST_PAD_SRC,
67     GST_PAD_ALWAYS,
68     GST_STATIC_CAPS ("audio/x-raw")
69     );
70
71 static GstStaticPadTemplate video_sink_template =
72 GST_STATIC_PAD_TEMPLATE ("vsink",
73     GST_PAD_SINK,
74     GST_PAD_ALWAYS,
75     GST_STATIC_CAPS ("video/x-raw")
76     );
77
78 static GstStaticPadTemplate video_src_template =
79 GST_STATIC_PAD_TEMPLATE ("vsrc",
80     GST_PAD_SRC,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS ("video/x-raw")
83     );
84
85 #define parent_class gst_avwait_parent_class
86 G_DEFINE_TYPE (GstAvWait, gst_avwait, GST_TYPE_ELEMENT);
87
88 enum
89 {
90   PROP_0,
91   PROP_TARGET_TIME_CODE,
92   PROP_TARGET_TIME_CODE_STRING,
93   PROP_TARGET_RUNNING_TIME,
94   PROP_END_TIME_CODE,
95   PROP_RECORDING,
96   PROP_MODE
97 };
98
99 #define DEFAULT_TARGET_TIMECODE_STR "00:00:00:00"
100 #define DEFAULT_TARGET_RUNNING_TIME GST_CLOCK_TIME_NONE
101 #define DEFAULT_MODE MODE_TIMECODE
102
103 /* flags for self->must_send_end_message */
104 enum
105 {
106   END_MESSAGE_NORMAL = 0,
107   END_MESSAGE_STREAM_ENDED = 1,
108   END_MESSAGE_VIDEO_PUSHED = 2,
109   END_MESSAGE_AUDIO_PUSHED = 4
110 };
111
112 static void gst_avwait_set_property (GObject * object,
113     guint prop_id, const GValue * value, GParamSpec * pspec);
114 static void gst_avwait_get_property (GObject * object,
115     guint prop_id, GValue * value, GParamSpec * pspec);
116
117 static GstFlowReturn gst_avwait_asink_chain (GstPad * pad,
118     GstObject * parent, GstBuffer * inbuf);
119 static GstFlowReturn gst_avwait_vsink_chain (GstPad * pad,
120     GstObject * parent, GstBuffer * inbuf);
121 static gboolean gst_avwait_asink_event (GstPad * pad,
122     GstObject * parent, GstEvent * event);
123 static gboolean gst_avwait_vsink_event (GstPad * pad,
124     GstObject * parent, GstEvent * event);
125 static GstIterator *gst_avwait_iterate_internal_links (GstPad *
126     pad, GstObject * parent);
127
128 static void gst_avwait_finalize (GObject * gobject);
129
130 static GstStateChangeReturn gst_avwait_change_state (GstElement *
131     element, GstStateChange transition);
132
133 static GType
134 gst_avwait_mode_get_type (void)
135 {
136   static GType gtype = 0;
137
138   if (gtype == 0) {
139     static const GEnumValue values[] = {
140       {MODE_TIMECODE, "time code (default)", "timecode"},
141       {MODE_RUNNING_TIME, "running time", "running-time"},
142       {MODE_VIDEO_FIRST, "video first", "video-first"},
143       {0, NULL, NULL}
144     };
145
146     gtype = g_enum_register_static ("GstAvWaitMode", values);
147   }
148   return gtype;
149 }
150
151 static void
152 gst_avwait_class_init (GstAvWaitClass * klass)
153 {
154   GstElementClass *gstelement_class;
155   GObjectClass *gobject_class = (GObjectClass *) klass;
156
157   GST_DEBUG_CATEGORY_INIT (gst_avwait_debug, "avwait", 0, "avwait");
158
159   gstelement_class = (GstElementClass *) klass;
160
161   gst_element_class_set_static_metadata (gstelement_class,
162       "Timecode Wait", "Filter/Audio/Video",
163       "Drops all audio/video until a specific timecode or running time has been reached",
164       "Vivia Nikolaidou <vivia@toolsonair.com>");
165
166   gobject_class->set_property = gst_avwait_set_property;
167   gobject_class->get_property = gst_avwait_get_property;
168
169   g_object_class_install_property (gobject_class, PROP_TARGET_TIME_CODE_STRING,
170       g_param_spec_string ("target-timecode-string", "Target timecode (string)",
171           "Timecode to wait for in timecode mode (string). Must take the form 00:00:00:00",
172           DEFAULT_TARGET_TIMECODE_STR,
173           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174
175   g_object_class_install_property (gobject_class, PROP_TARGET_TIME_CODE,
176       g_param_spec_boxed ("target-timecode", "Target timecode (object)",
177           "Timecode to wait for in timecode mode (object)",
178           GST_TYPE_VIDEO_TIME_CODE,
179           GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
180           G_PARAM_STATIC_STRINGS));
181
182   g_object_class_install_property (gobject_class, PROP_TARGET_RUNNING_TIME,
183       g_param_spec_uint64 ("target-running-time", "Target running time",
184           "Running time to wait for in running-time mode",
185           0, G_MAXUINT64,
186           DEFAULT_TARGET_RUNNING_TIME,
187           GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
188           G_PARAM_STATIC_STRINGS));
189
190   g_object_class_install_property (gobject_class, PROP_MODE,
191       g_param_spec_enum ("mode", "Mode",
192           "Operation mode: What to wait for",
193           GST_TYPE_AVWAIT_MODE,
194           DEFAULT_MODE,
195           GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
196           G_PARAM_STATIC_STRINGS));
197
198   g_object_class_install_property (gobject_class, PROP_END_TIME_CODE,
199       g_param_spec_boxed ("end-timecode", "End timecode (object)",
200           "Timecode to end at in timecode mode (object)",
201           GST_TYPE_VIDEO_TIME_CODE,
202           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
203
204   g_object_class_install_property (gobject_class, PROP_RECORDING,
205       g_param_spec_boolean ("recording",
206           "Recording state",
207           "Whether the element is stopped or recording. "
208           "If set to FALSE, all buffers will be dropped regardless of settings.",
209           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
210
211   gobject_class->finalize = gst_avwait_finalize;
212   gstelement_class->change_state = gst_avwait_change_state;
213
214   gst_element_class_add_static_pad_template (gstelement_class,
215       &audio_src_template);
216   gst_element_class_add_static_pad_template (gstelement_class,
217       &audio_sink_template);
218
219   gst_element_class_add_static_pad_template (gstelement_class,
220       &video_src_template);
221   gst_element_class_add_static_pad_template (gstelement_class,
222       &video_sink_template);
223 }
224
225 static void
226 gst_avwait_init (GstAvWait * self)
227 {
228   self->asinkpad =
229       gst_pad_new_from_static_template (&audio_sink_template, "asink");
230   gst_pad_set_chain_function (self->asinkpad,
231       GST_DEBUG_FUNCPTR (gst_avwait_asink_chain));
232   gst_pad_set_event_function (self->asinkpad,
233       GST_DEBUG_FUNCPTR (gst_avwait_asink_event));
234   gst_pad_set_iterate_internal_links_function (self->asinkpad,
235       GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
236   gst_element_add_pad (GST_ELEMENT (self), self->asinkpad);
237
238   self->vsinkpad =
239       gst_pad_new_from_static_template (&video_sink_template, "vsink");
240   gst_pad_set_chain_function (self->vsinkpad,
241       GST_DEBUG_FUNCPTR (gst_avwait_vsink_chain));
242   gst_pad_set_event_function (self->vsinkpad,
243       GST_DEBUG_FUNCPTR (gst_avwait_vsink_event));
244   gst_pad_set_iterate_internal_links_function (self->vsinkpad,
245       GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
246   gst_element_add_pad (GST_ELEMENT (self), self->vsinkpad);
247
248   self->asrcpad =
249       gst_pad_new_from_static_template (&audio_src_template, "asrc");
250   gst_pad_set_iterate_internal_links_function (self->asrcpad,
251       GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
252   gst_element_add_pad (GST_ELEMENT (self), self->asrcpad);
253
254   self->vsrcpad =
255       gst_pad_new_from_static_template (&video_src_template, "vsrc");
256   gst_pad_set_iterate_internal_links_function (self->vsrcpad,
257       GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
258   gst_element_add_pad (GST_ELEMENT (self), self->vsrcpad);
259
260   GST_PAD_SET_PROXY_CAPS (self->asinkpad);
261   GST_PAD_SET_PROXY_ALLOCATION (self->asinkpad);
262
263   GST_PAD_SET_PROXY_CAPS (self->asrcpad);
264   GST_PAD_SET_PROXY_SCHEDULING (self->asrcpad);
265
266   GST_PAD_SET_PROXY_CAPS (self->vsinkpad);
267   GST_PAD_SET_PROXY_ALLOCATION (self->vsinkpad);
268
269   GST_PAD_SET_PROXY_CAPS (self->vsrcpad);
270   GST_PAD_SET_PROXY_SCHEDULING (self->vsrcpad);
271
272   self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
273   self->last_seen_video_running_time = GST_CLOCK_TIME_NONE;
274   self->first_audio_running_time = GST_CLOCK_TIME_NONE;
275   self->last_seen_tc = NULL;
276
277   self->video_eos_flag = FALSE;
278   self->audio_eos_flag = FALSE;
279   self->video_flush_flag = FALSE;
280   self->audio_flush_flag = FALSE;
281   self->shutdown_flag = FALSE;
282   self->dropping = TRUE;
283   self->tc = gst_video_time_code_new_empty ();
284   self->end_tc = NULL;
285   self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
286   self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
287   self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
288   self->recording = TRUE;
289
290   self->target_running_time = DEFAULT_TARGET_RUNNING_TIME;
291   self->mode = DEFAULT_MODE;
292
293   gst_video_info_init (&self->vinfo);
294   g_mutex_init (&self->mutex);
295   g_cond_init (&self->cond);
296   g_cond_init (&self->audio_cond);
297 }
298
299 static void
300 gst_avwait_send_element_message (GstAvWait * self, gboolean dropping,
301     GstClockTime running_time)
302 {
303   if (!gst_element_post_message (GST_ELEMENT (self),
304           gst_message_new_element (GST_OBJECT (self),
305               gst_structure_new ("avwait-status",
306                   "dropping", G_TYPE_BOOLEAN, dropping,
307                   "running-time", GST_TYPE_CLOCK_TIME, running_time, NULL)))) {
308     GST_ERROR_OBJECT (self, "Unable to send element message!");
309     g_assert_not_reached ();
310   }
311 }
312
313 static GstStateChangeReturn
314 gst_avwait_change_state (GstElement * element, GstStateChange transition)
315 {
316   GstStateChangeReturn ret;
317   GstAvWait *self = GST_AVWAIT (element);
318
319   switch (transition) {
320     case GST_STATE_CHANGE_PAUSED_TO_READY:
321       g_mutex_lock (&self->mutex);
322       self->shutdown_flag = TRUE;
323       g_cond_signal (&self->cond);
324       g_cond_signal (&self->audio_cond);
325       g_mutex_unlock (&self->mutex);
326       break;
327     case GST_STATE_CHANGE_READY_TO_PAUSED:
328       g_mutex_lock (&self->mutex);
329       self->shutdown_flag = FALSE;
330       self->video_eos_flag = FALSE;
331       self->audio_eos_flag = FALSE;
332       self->video_flush_flag = FALSE;
333       self->audio_flush_flag = FALSE;
334       self->must_send_end_message = END_MESSAGE_NORMAL;
335       g_mutex_unlock (&self->mutex);
336     default:
337       break;
338   }
339
340   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
341
342   switch (transition) {
343     case GST_STATE_CHANGE_PAUSED_TO_READY:
344       g_mutex_lock (&self->mutex);
345       if (self->mode != MODE_RUNNING_TIME) {
346         GST_DEBUG_OBJECT (self, "First time reset in paused to ready");
347         self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
348         self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
349         self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
350         self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
351       }
352       if (!self->dropping) {
353         self->dropping = TRUE;
354         gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
355       }
356       gst_segment_init (&self->asegment, GST_FORMAT_UNDEFINED);
357       self->asegment.position = GST_CLOCK_TIME_NONE;
358       gst_segment_init (&self->vsegment, GST_FORMAT_UNDEFINED);
359       self->vsegment.position = GST_CLOCK_TIME_NONE;
360       gst_video_info_init (&self->vinfo);
361       self->last_seen_video_running_time = GST_CLOCK_TIME_NONE;
362       self->first_audio_running_time = GST_CLOCK_TIME_NONE;
363       if (self->last_seen_tc)
364         gst_video_time_code_free (self->last_seen_tc);
365       self->last_seen_tc = NULL;
366       g_mutex_unlock (&self->mutex);
367       break;
368     default:
369       break;
370   }
371
372   return ret;
373 }
374
375 static void
376 gst_avwait_finalize (GObject * object)
377 {
378   GstAvWait *self = GST_AVWAIT (object);
379
380   if (self->tc) {
381     gst_video_time_code_free (self->tc);
382     self->tc = NULL;
383   }
384
385   if (self->end_tc) {
386     gst_video_time_code_free (self->end_tc);
387     self->end_tc = NULL;
388   }
389
390   g_mutex_clear (&self->mutex);
391   g_cond_clear (&self->cond);
392   g_cond_clear (&self->audio_cond);
393
394   G_OBJECT_CLASS (parent_class)->finalize (object);
395 }
396
397 static void
398 gst_avwait_get_property (GObject * object, guint prop_id,
399     GValue * value, GParamSpec * pspec)
400 {
401   GstAvWait *self = GST_AVWAIT (object);
402
403   switch (prop_id) {
404     case PROP_TARGET_TIME_CODE_STRING:{
405       if (self->tc)
406         g_value_take_string (value, gst_video_time_code_to_string (self->tc));
407       else
408         g_value_set_string (value, DEFAULT_TARGET_TIMECODE_STR);
409       break;
410     }
411     case PROP_TARGET_TIME_CODE:{
412       g_value_set_boxed (value, self->tc);
413       break;
414     }
415     case PROP_END_TIME_CODE:{
416       g_value_set_boxed (value, self->end_tc);
417       break;
418     }
419     case PROP_TARGET_RUNNING_TIME:{
420       g_value_set_uint64 (value, self->target_running_time);
421       break;
422     }
423     case PROP_RECORDING:{
424       g_value_set_boolean (value, self->recording);
425       break;
426     }
427     case PROP_MODE:{
428       g_value_set_enum (value, self->mode);
429       break;
430     }
431     default:
432       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433       break;
434   }
435 }
436
437 static void
438 gst_avwait_set_property (GObject * object, guint prop_id,
439     const GValue * value, GParamSpec * pspec)
440 {
441   GstAvWait *self = GST_AVWAIT (object);
442
443   switch (prop_id) {
444     case PROP_TARGET_TIME_CODE_STRING:{
445       gchar **parts;
446       const gchar *tc_str;
447       guint hours, minutes, seconds, frames;
448
449       tc_str = g_value_get_string (value);
450       parts = g_strsplit (tc_str, ":", 4);
451       if (!parts || parts[3] == NULL) {
452         GST_ERROR_OBJECT (self,
453             "Error: Could not parse timecode %s. Please input a timecode in the form 00:00:00:00",
454             tc_str);
455         g_strfreev (parts);
456         return;
457       }
458       hours = g_ascii_strtoll (parts[0], NULL, 10);
459       minutes = g_ascii_strtoll (parts[1], NULL, 10);
460       seconds = g_ascii_strtoll (parts[2], NULL, 10);
461       frames = g_ascii_strtoll (parts[3], NULL, 10);
462       gst_video_time_code_init (self->tc, 0, 1, NULL, 0, hours, minutes,
463           seconds, frames, 0);
464       if (self->end_tc
465           && gst_video_time_code_compare (self->tc, self->end_tc) != -1) {
466         gchar *end_tc;
467
468         end_tc = gst_video_time_code_to_string (self->end_tc);
469         g_warning
470             ("ERROR: End timecode %s must be after start timecode %s. Start timecode rejected",
471             end_tc, tc_str);
472         gst_video_time_code_free (self->tc);
473         g_free (end_tc);
474         self->tc = gst_video_time_code_new_empty ();
475       } else {
476         if (GST_VIDEO_INFO_FORMAT (&self->vinfo) != GST_VIDEO_FORMAT_UNKNOWN
477             && self->vinfo.fps_n != 0) {
478           self->tc->config.fps_n = self->vinfo.fps_n;
479           self->tc->config.fps_d = self->vinfo.fps_d;
480         }
481       }
482       g_strfreev (parts);
483       break;
484     }
485     case PROP_TARGET_TIME_CODE:{
486       if (self->tc)
487         gst_video_time_code_free (self->tc);
488       self->tc = g_value_dup_boxed (value);
489       if (self->end_tc
490           && gst_video_time_code_compare (self->tc, self->end_tc) != -1) {
491         gchar *start_tc, *end_tc;
492
493         start_tc = gst_video_time_code_to_string (self->tc);
494         end_tc = gst_video_time_code_to_string (self->end_tc);
495         g_warning
496             ("ERROR: End timecode %s must be after start timecode %s. Start timecode rejected",
497             end_tc, start_tc);
498         gst_video_time_code_free (self->tc);
499         g_free (start_tc);
500         g_free (end_tc);
501         self->tc = gst_video_time_code_new_empty ();
502       } else {
503         if (self->tc->config.fps_n == 0
504             && GST_VIDEO_INFO_FORMAT (&self->vinfo) !=
505             GST_VIDEO_FORMAT_UNKNOWN && self->vinfo.fps_n != 0) {
506           self->tc->config.fps_n = self->vinfo.fps_n;
507           self->tc->config.fps_d = self->vinfo.fps_d;
508         }
509       }
510       break;
511     }
512     case PROP_END_TIME_CODE:{
513       if (self->end_tc)
514         gst_video_time_code_free (self->end_tc);
515       self->end_tc = g_value_dup_boxed (value);
516       if (self->tc && self->end_tc
517           && gst_video_time_code_compare (self->tc, self->end_tc) != -1) {
518         gchar *start_tc, *end_tc;
519
520         start_tc = gst_video_time_code_to_string (self->tc);
521         end_tc = gst_video_time_code_to_string (self->end_tc);
522         g_warning
523             ("ERROR: End timecode %s must be after start timecode %s. End timecode rejected",
524             end_tc, start_tc);
525         gst_video_time_code_free (self->end_tc);
526         self->end_tc = NULL;
527         g_free (start_tc);
528         g_free (end_tc);
529       } else if (self->end_tc) {
530         if (self->end_tc->config.fps_n == 0
531             && GST_VIDEO_INFO_FORMAT (&self->vinfo) !=
532             GST_VIDEO_FORMAT_UNKNOWN && self->vinfo.fps_n != 0) {
533           self->end_tc->config.fps_n = self->vinfo.fps_n;
534           self->end_tc->config.fps_d = self->vinfo.fps_d;
535         }
536       }
537       break;
538     }
539     case PROP_TARGET_RUNNING_TIME:{
540       self->target_running_time = g_value_get_uint64 (value);
541       if (self->mode == MODE_RUNNING_TIME) {
542         self->running_time_to_wait_for = self->target_running_time;
543         if (self->recording) {
544           self->audio_running_time_to_wait_for = self->running_time_to_wait_for;
545         }
546         if (self->target_running_time < self->last_seen_video_running_time) {
547           self->dropping = TRUE;
548         }
549       }
550       break;
551     }
552     case PROP_MODE:{
553       GstAvWaitMode old_mode = self->mode;
554       self->mode = g_value_get_enum (value);
555       if (self->mode != old_mode) {
556         switch (self->mode) {
557           case MODE_TIMECODE:
558             if (self->last_seen_tc && self->tc &&
559                 gst_video_time_code_compare (self->last_seen_tc,
560                     self->tc) < 0) {
561               self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
562               self->dropping = TRUE;
563             }
564             break;
565           case MODE_RUNNING_TIME:
566             self->running_time_to_wait_for = self->target_running_time;
567             if (self->recording) {
568               self->audio_running_time_to_wait_for =
569                   self->running_time_to_wait_for;
570             }
571             if (self->target_running_time < self->last_seen_video_running_time) {
572               self->dropping = TRUE;
573             }
574             break;
575             /* Let the chain functions handle the rest */
576           case MODE_VIDEO_FIRST:
577             /* pass-through */
578           default:
579             break;
580         }
581       }
582       break;
583     }
584     case PROP_RECORDING:{
585       g_mutex_lock (&self->mutex);
586       self->recording = g_value_get_boolean (value);
587       g_mutex_unlock (&self->mutex);
588       break;
589     }
590     default:
591       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
592       break;
593   }
594 }
595
596 static gboolean
597 gst_avwait_vsink_event (GstPad * pad, GstObject * parent, GstEvent * event)
598 {
599   GstAvWait *self = GST_AVWAIT (parent);
600   GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
601
602   switch (GST_EVENT_TYPE (event)) {
603     case GST_EVENT_SEGMENT:
604       g_mutex_lock (&self->mutex);
605       gst_event_copy_segment (event, &self->vsegment);
606       if (self->vsegment.format != GST_FORMAT_TIME) {
607         GST_ERROR_OBJECT (self, "Invalid segment format");
608         g_mutex_unlock (&self->mutex);
609         gst_event_unref (event);
610         return FALSE;
611       }
612       if (self->mode != MODE_RUNNING_TIME) {
613         GST_DEBUG_OBJECT (self, "First time reset in video segment");
614         self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
615         self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
616         self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
617         self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
618         if (!self->dropping) {
619           self->dropping = TRUE;
620           gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
621         }
622       }
623       self->vsegment.position = GST_CLOCK_TIME_NONE;
624       g_mutex_unlock (&self->mutex);
625       break;
626     case GST_EVENT_GAP:
627       gst_event_unref (event);
628       return TRUE;
629     case GST_EVENT_EOS:
630       g_mutex_lock (&self->mutex);
631       self->video_eos_flag = TRUE;
632       g_cond_signal (&self->cond);
633       g_mutex_unlock (&self->mutex);
634       break;
635     case GST_EVENT_FLUSH_START:
636       g_mutex_lock (&self->mutex);
637       self->video_flush_flag = TRUE;
638       g_cond_signal (&self->audio_cond);
639       g_mutex_unlock (&self->mutex);
640       break;
641     case GST_EVENT_FLUSH_STOP:
642       g_mutex_lock (&self->mutex);
643       self->video_flush_flag = FALSE;
644       if (self->mode != MODE_RUNNING_TIME) {
645         GST_DEBUG_OBJECT (self, "First time reset in video flush");
646         self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
647         self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
648         self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
649         self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
650         if (!self->dropping) {
651           self->dropping = TRUE;
652           gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
653         }
654       }
655       gst_segment_init (&self->vsegment, GST_FORMAT_UNDEFINED);
656       self->vsegment.position = GST_CLOCK_TIME_NONE;
657       g_mutex_unlock (&self->mutex);
658       break;
659     case GST_EVENT_CAPS:{
660       GstCaps *caps;
661       gst_event_parse_caps (event, &caps);
662       GST_DEBUG_OBJECT (self, "Got caps %" GST_PTR_FORMAT, caps);
663       if (!gst_video_info_from_caps (&self->vinfo, caps)) {
664         gst_event_unref (event);
665         return FALSE;
666       }
667       g_mutex_lock (&self->mutex);
668       if (self->tc && self->tc->config.fps_n == 0 && self->vinfo.fps_n != 0) {
669         self->tc->config.fps_n = self->vinfo.fps_n;
670         self->tc->config.fps_d = self->vinfo.fps_d;
671       }
672       if (self->end_tc && self->end_tc->config.fps_n == 0
673           && self->vinfo.fps_n != 0) {
674         self->end_tc->config.fps_n = self->vinfo.fps_n;
675         self->end_tc->config.fps_d = self->vinfo.fps_d;
676       }
677       g_mutex_unlock (&self->mutex);
678       break;
679     }
680     default:
681       break;
682   }
683   return gst_pad_event_default (pad, parent, event);
684 }
685
686 static gboolean
687 gst_avwait_asink_event (GstPad * pad, GstObject * parent, GstEvent * event)
688 {
689   GstAvWait *self = GST_AVWAIT (parent);
690   GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
691
692   switch (GST_EVENT_TYPE (event)) {
693     case GST_EVENT_SEGMENT:
694       g_mutex_lock (&self->mutex);
695       gst_event_copy_segment (event, &self->asegment);
696       if (self->asegment.format != GST_FORMAT_TIME) {
697         GST_ERROR_OBJECT (self, "Invalid segment format");
698         g_mutex_unlock (&self->mutex);
699         return FALSE;
700       }
701       self->asegment.position = GST_CLOCK_TIME_NONE;
702       g_mutex_unlock (&self->mutex);
703       break;
704     case GST_EVENT_FLUSH_START:
705       g_mutex_lock (&self->mutex);
706       self->audio_flush_flag = TRUE;
707       g_cond_signal (&self->cond);
708       g_mutex_unlock (&self->mutex);
709       break;
710     case GST_EVENT_EOS:
711       g_mutex_lock (&self->mutex);
712       self->audio_eos_flag = TRUE;
713       self->must_send_end_message = END_MESSAGE_NORMAL;
714       g_cond_signal (&self->audio_cond);
715       g_mutex_unlock (&self->mutex);
716       break;
717     case GST_EVENT_FLUSH_STOP:
718       g_mutex_lock (&self->mutex);
719       self->audio_flush_flag = FALSE;
720       gst_segment_init (&self->asegment, GST_FORMAT_UNDEFINED);
721       self->asegment.position = GST_CLOCK_TIME_NONE;
722       g_mutex_unlock (&self->mutex);
723       break;
724     case GST_EVENT_CAPS:{
725       GstCaps *caps;
726       gst_event_parse_caps (event, &caps);
727       GST_DEBUG_OBJECT (self, "Got caps %" GST_PTR_FORMAT, caps);
728       g_mutex_lock (&self->mutex);
729       if (!gst_audio_info_from_caps (&self->ainfo, caps)) {
730         g_mutex_unlock (&self->mutex);
731         return FALSE;
732       }
733       g_mutex_unlock (&self->mutex);
734       break;
735     }
736     default:
737       break;
738   }
739
740   return gst_pad_event_default (pad, parent, event);
741 }
742
743 static GstFlowReturn
744 gst_avwait_vsink_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
745 {
746   GstClockTime timestamp;
747   GstAvWait *self = GST_AVWAIT (parent);
748   GstClockTime running_time;
749   GstVideoTimeCode *tc = NULL;
750   GstVideoTimeCodeMeta *tc_meta;
751   gboolean retry = FALSE;
752   gboolean ret = GST_FLOW_OK;
753
754   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
755   if (timestamp == GST_CLOCK_TIME_NONE) {
756     gst_buffer_unref (inbuf);
757     return GST_FLOW_ERROR;
758   }
759   g_mutex_lock (&self->mutex);
760   self->vsegment.position = timestamp;
761   running_time =
762       gst_segment_to_running_time (&self->vsegment, GST_FORMAT_TIME,
763       self->vsegment.position);
764   self->last_seen_video_running_time = running_time;
765
766   tc_meta = gst_buffer_get_video_time_code_meta (inbuf);
767   if (tc_meta) {
768     tc = gst_video_time_code_copy (&tc_meta->tc);
769     if (self->last_seen_tc) {
770       gst_video_time_code_free (self->last_seen_tc);
771     }
772     self->last_seen_tc = tc;
773   }
774   while (self->mode == MODE_VIDEO_FIRST
775       && self->first_audio_running_time == GST_CLOCK_TIME_NONE
776       && !self->audio_eos_flag
777       && !self->shutdown_flag && !self->video_flush_flag) {
778     g_cond_wait (&self->audio_cond, &self->mutex);
779   }
780   if (self->video_flush_flag || self->shutdown_flag) {
781     GST_DEBUG_OBJECT (self, "Shutting down, ignoring buffer");
782     gst_buffer_unref (inbuf);
783     g_mutex_unlock (&self->mutex);
784     return GST_FLOW_FLUSHING;
785   }
786   switch (self->mode) {
787     case MODE_TIMECODE:{
788       if (self->tc != NULL && tc != NULL) {
789         gboolean emit_passthrough_signal = FALSE;
790         if (gst_video_time_code_compare (tc, self->tc) < 0
791             && self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
792           GST_DEBUG_OBJECT (self, "Timecode not yet reached, ignoring frame");
793           gst_buffer_unref (inbuf);
794           inbuf = NULL;
795         } else if (self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
796           GST_INFO_OBJECT (self, "Target timecode reached at %" GST_TIME_FORMAT,
797               GST_TIME_ARGS (self->vsegment.position));
798           /* Don't emit a signal if we weren't dropping (e.g. settings changed
799            * mid-flight) */
800           emit_passthrough_signal = self->dropping;
801           self->dropping = FALSE;
802           self->running_time_to_wait_for =
803               gst_segment_to_running_time (&self->vsegment, GST_FORMAT_TIME,
804               self->vsegment.position);
805           if (self->recording) {
806             self->audio_running_time_to_wait_for =
807                 self->running_time_to_wait_for;
808           }
809         }
810         if (self->end_tc && gst_video_time_code_compare (tc, self->end_tc) >= 0) {
811           if (self->running_time_to_end_at == GST_CLOCK_TIME_NONE) {
812             GST_INFO_OBJECT (self, "End timecode reached at %" GST_TIME_FORMAT,
813                 GST_TIME_ARGS (self->vsegment.position));
814             self->dropping = TRUE;
815             self->running_time_to_end_at =
816                 gst_segment_to_running_time (&self->vsegment, GST_FORMAT_TIME,
817                 self->vsegment.position);
818             if (self->recording) {
819               self->audio_running_time_to_end_at = self->running_time_to_end_at;
820               self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
821             }
822           }
823           gst_buffer_unref (inbuf);
824           inbuf = NULL;
825         } else if (emit_passthrough_signal && self->recording) {
826           gst_avwait_send_element_message (self, FALSE,
827               self->running_time_to_wait_for);
828         }
829       }
830       break;
831     }
832     case MODE_RUNNING_TIME:{
833       if (running_time < self->running_time_to_wait_for) {
834         GST_DEBUG_OBJECT (self,
835             "Have %" GST_TIME_FORMAT ", waiting for %" GST_TIME_FORMAT,
836             GST_TIME_ARGS (running_time),
837             GST_TIME_ARGS (self->running_time_to_wait_for));
838         gst_buffer_unref (inbuf);
839         inbuf = NULL;
840       } else {
841         if (self->dropping) {
842           self->dropping = FALSE;
843           if (self->recording)
844             gst_avwait_send_element_message (self, FALSE, running_time);
845         }
846         GST_INFO_OBJECT (self,
847             "Have %" GST_TIME_FORMAT ", waiting for %" GST_TIME_FORMAT,
848             GST_TIME_ARGS (running_time),
849             GST_TIME_ARGS (self->running_time_to_wait_for));
850       }
851       break;
852     }
853     case MODE_VIDEO_FIRST:{
854       if (self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
855         self->running_time_to_wait_for =
856             gst_segment_to_running_time (&self->vsegment, GST_FORMAT_TIME,
857             self->vsegment.position);
858         GST_DEBUG_OBJECT (self, "First video running time is %" GST_TIME_FORMAT,
859             GST_TIME_ARGS (self->running_time_to_wait_for));
860         if (self->recording) {
861           self->audio_running_time_to_wait_for = self->running_time_to_wait_for;
862         }
863         if (self->dropping) {
864           self->dropping = FALSE;
865           if (self->recording)
866             gst_avwait_send_element_message (self, FALSE,
867                 self->running_time_to_wait_for);
868         }
869       }
870       break;
871     }
872   }
873
874   if (!self->recording) {
875     if (self->was_recording) {
876       GST_INFO_OBJECT (self, "Recording stopped at %" GST_TIME_FORMAT,
877           GST_TIME_ARGS (running_time));
878       if (running_time > self->running_time_to_wait_for
879           && running_time <= self->running_time_to_end_at) {
880         /* We just stopped recording: synchronise the audio */
881         self->audio_running_time_to_end_at = running_time;
882         self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
883       } else if (running_time < self->running_time_to_wait_for
884           && self->running_time_to_wait_for != GST_CLOCK_TIME_NONE) {
885         self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
886       }
887     }
888     /* Recording is FALSE: we drop all buffers */
889     if (inbuf) {
890       gst_buffer_unref (inbuf);
891       inbuf = NULL;
892     }
893   } else {
894     if (!self->was_recording) {
895       GST_INFO_OBJECT (self,
896           "Recording started at %" GST_TIME_FORMAT " waiting for %"
897           GST_TIME_FORMAT " inbuf %p", GST_TIME_ARGS (running_time),
898           GST_TIME_ARGS (self->running_time_to_wait_for), inbuf);
899       if (self->mode != MODE_VIDEO_FIRST ||
900           self->first_audio_running_time <= running_time ||
901           self->audio_eos_flag) {
902         if (running_time < self->running_time_to_end_at ||
903             self->running_time_to_end_at == GST_CLOCK_TIME_NONE) {
904           /* We are before the end of the recording. Check if we just actually
905            * started */
906           if (running_time > self->running_time_to_wait_for) {
907             /* We just started recording: synchronise the audio */
908             self->audio_running_time_to_wait_for = running_time;
909             gst_avwait_send_element_message (self, FALSE, running_time);
910           } else {
911             /* We will start in the future when running_time_to_wait_for is
912              * reached */
913             self->audio_running_time_to_wait_for =
914                 self->running_time_to_wait_for;
915           }
916           self->audio_running_time_to_end_at = self->running_time_to_end_at;
917         }
918       } else {
919         /* We are in video-first mode and behind the first audio timestamp. We
920          * should drop all video buffers until the first audio timestamp, so
921          * we can catch up with it. (In timecode mode and running-time mode, we
922          * don't care about when the audio starts, we start as soon as the
923          * target timecode or running time has been reached) */
924         gst_buffer_unref (inbuf);
925         inbuf = NULL;
926         retry = TRUE;
927       }
928     }
929   }
930
931   if (!retry)
932     self->was_recording = self->recording;
933   g_cond_signal (&self->cond);
934   g_mutex_unlock (&self->mutex);
935   if (inbuf) {
936     GST_WARNING_OBJECT (self, "Pass video buffer ending at %" GST_TIME_FORMAT,
937         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf) +
938             GST_BUFFER_DURATION (inbuf)));
939     ret = gst_pad_push (self->vsrcpad, inbuf);
940   }
941   g_mutex_lock (&self->mutex);
942   if (self->must_send_end_message & END_MESSAGE_AUDIO_PUSHED) {
943     self->must_send_end_message = END_MESSAGE_NORMAL;
944     g_mutex_unlock (&self->mutex);
945     gst_avwait_send_element_message (self, TRUE,
946         self->audio_running_time_to_end_at);
947   } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
948     if (self->audio_eos_flag) {
949       self->must_send_end_message = END_MESSAGE_NORMAL;
950       g_mutex_unlock (&self->mutex);
951       gst_avwait_send_element_message (self, TRUE,
952           self->audio_running_time_to_end_at);
953     } else {
954       self->must_send_end_message |= END_MESSAGE_VIDEO_PUSHED;
955       g_mutex_unlock (&self->mutex);
956     }
957   } else {
958     g_mutex_unlock (&self->mutex);
959   }
960
961   return ret;
962 }
963
964 /*
965  * assumes sign1 and sign2 are either 1 or -1
966  * returns 0 if sign1*num1 == sign2*num2
967  * -1 if sign1*num1 < sign2*num2
968  *  1 if sign1*num1 > sign2*num2
969  */
970 static gint
971 gst_avwait_compare_guint64_with_signs (gint sign1,
972     guint64 num1, gint sign2, guint64 num2)
973 {
974   if (sign1 != sign2)
975     return sign1;
976   else if (num1 == num2)
977     return 0;
978   else
979     return num1 > num2 ? sign1 : -sign1;
980 }
981
982 static GstFlowReturn
983 gst_avwait_asink_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
984 {
985   GstClockTime timestamp;
986   GstAvWait *self = GST_AVWAIT (parent);
987   GstClockTime current_running_time;
988   GstClockTime video_running_time = GST_CLOCK_TIME_NONE;
989   GstClockTime duration;
990   GstClockTime running_time_at_end = GST_CLOCK_TIME_NONE;
991   gint asign, vsign = 1, esign = 1;
992   GstFlowReturn ret = GST_FLOW_OK;
993   /* Make sure the video thread doesn't send the element message before we
994    * actually call gst_pad_push */
995   gboolean send_element_message = FALSE;
996
997   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
998   if (timestamp == GST_CLOCK_TIME_NONE) {
999     gst_buffer_unref (inbuf);
1000     return GST_FLOW_ERROR;
1001   }
1002   g_mutex_lock (&self->mutex);
1003   self->asegment.position = timestamp;
1004   asign =
1005       gst_segment_to_running_time_full (&self->asegment, GST_FORMAT_TIME,
1006       self->asegment.position, &current_running_time);
1007   if (asign == 0) {
1008     g_mutex_unlock (&self->mutex);
1009     gst_buffer_unref (inbuf);
1010     GST_ERROR_OBJECT (self, "Could not get current running time");
1011     return GST_FLOW_ERROR;
1012   }
1013   if (self->first_audio_running_time == GST_CLOCK_TIME_NONE) {
1014     self->first_audio_running_time = current_running_time;
1015   }
1016   g_cond_signal (&self->audio_cond);
1017   if (self->vsegment.format == GST_FORMAT_TIME) {
1018     vsign =
1019         gst_segment_to_running_time_full (&self->vsegment, GST_FORMAT_TIME,
1020         self->vsegment.position, &video_running_time);
1021     if (vsign == 0) {
1022       video_running_time = GST_CLOCK_TIME_NONE;
1023     }
1024   }
1025   duration =
1026       gst_util_uint64_scale (gst_buffer_get_size (inbuf) / self->ainfo.bpf,
1027       GST_SECOND, self->ainfo.rate);
1028   if (duration != GST_CLOCK_TIME_NONE) {
1029     esign =
1030         gst_segment_to_running_time_full (&self->asegment, GST_FORMAT_TIME,
1031         self->asegment.position + duration, &running_time_at_end);
1032     if (esign == 0) {
1033       g_mutex_unlock (&self->mutex);
1034       GST_ERROR_OBJECT (self, "Could not get running time at end");
1035       gst_buffer_unref (inbuf);
1036       return GST_FLOW_ERROR;
1037     }
1038   }
1039   while (!(self->video_eos_flag || self->audio_flush_flag
1040           || self->shutdown_flag) &&
1041       /* Start at timecode */
1042       /* Wait if we haven't received video yet */
1043       (video_running_time == GST_CLOCK_TIME_NONE
1044           /* Wait if audio is after the video: dunno what to do */
1045           || gst_avwait_compare_guint64_with_signs (asign,
1046               running_time_at_end, vsign, video_running_time) == 1)) {
1047     g_cond_wait (&self->cond, &self->mutex);
1048     vsign =
1049         gst_segment_to_running_time_full (&self->vsegment, GST_FORMAT_TIME,
1050         self->vsegment.position, &video_running_time);
1051     if (vsign == 0) {
1052       video_running_time = GST_CLOCK_TIME_NONE;
1053     }
1054   }
1055   if (self->audio_flush_flag || self->shutdown_flag) {
1056     GST_DEBUG_OBJECT (self, "Shutting down, ignoring frame");
1057     gst_buffer_unref (inbuf);
1058     g_mutex_unlock (&self->mutex);
1059     return GST_FLOW_FLUSHING;
1060   }
1061   if (self->audio_running_time_to_wait_for == GST_CLOCK_TIME_NONE
1062       /* Audio ends before start : drop */
1063       || gst_avwait_compare_guint64_with_signs (esign,
1064           running_time_at_end, 1, self->audio_running_time_to_wait_for) == -1
1065       /* Audio starts after end: drop */
1066       || current_running_time >= self->audio_running_time_to_end_at) {
1067     GST_DEBUG_OBJECT (self,
1068         "Dropped an audio buf at %" GST_TIME_FORMAT " waiting for %"
1069         GST_TIME_FORMAT " video time %" GST_TIME_FORMAT,
1070         GST_TIME_ARGS (current_running_time),
1071         GST_TIME_ARGS (self->audio_running_time_to_wait_for),
1072         GST_TIME_ARGS (video_running_time));
1073     GST_DEBUG_OBJECT (self, "Would have ended at %i %" GST_TIME_FORMAT,
1074         esign, GST_TIME_ARGS (running_time_at_end));
1075     gst_buffer_unref (inbuf);
1076     inbuf = NULL;
1077     if (current_running_time >= self->audio_running_time_to_end_at &&
1078         (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) &&
1079         !(self->must_send_end_message & END_MESSAGE_AUDIO_PUSHED)) {
1080       send_element_message = TRUE;
1081     }
1082
1083   } else if (gst_avwait_compare_guint64_with_signs (esign, running_time_at_end,
1084           1, self->audio_running_time_to_wait_for) >= 0
1085       && gst_avwait_compare_guint64_with_signs (esign, running_time_at_end, 1,
1086           self->audio_running_time_to_end_at) == -1) {
1087     /* Audio ends after start, but before end: clip */
1088     GstSegment asegment2 = self->asegment;
1089
1090     gst_segment_set_running_time (&asegment2, GST_FORMAT_TIME,
1091         self->audio_running_time_to_wait_for);
1092     inbuf =
1093         gst_audio_buffer_clip (inbuf, &asegment2, self->ainfo.rate,
1094         self->ainfo.bpf);
1095   } else if (gst_avwait_compare_guint64_with_signs (esign, running_time_at_end,
1096           1, self->audio_running_time_to_end_at) >= 0) {
1097     /* Audio starts after start, but before end: clip from the other side */
1098     GstSegment asegment2 = self->asegment;
1099     guint64 stop;
1100     gint ssign;
1101
1102     ssign =
1103         gst_segment_position_from_running_time_full (&asegment2,
1104         GST_FORMAT_TIME, self->audio_running_time_to_end_at, &stop);
1105     if (ssign > 0) {
1106       asegment2.stop = stop;
1107     } else {
1108       /* Stopping before the start of the audio segment?! */
1109       /* This shouldn't happen: we already know that the current audio is
1110        * inside the segment, and that the end is after the current audio
1111        * position */
1112       GST_ELEMENT_ERROR (self, CORE, FAILED,
1113           ("Failed to clip audio: it should have ended before the current segment"),
1114           NULL);
1115     }
1116     inbuf =
1117         gst_audio_buffer_clip (inbuf, &asegment2, self->ainfo.rate,
1118         self->ainfo.bpf);
1119     if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
1120       send_element_message = TRUE;
1121     }
1122   } else {
1123     /* Programming error? Shouldn't happen */
1124     g_assert_not_reached ();
1125   }
1126   g_mutex_unlock (&self->mutex);
1127   if (inbuf) {
1128     GstClockTime new_duration =
1129         gst_util_uint64_scale (gst_buffer_get_size (inbuf) / self->ainfo.bpf,
1130         GST_SECOND, self->ainfo.rate);
1131     GstClockTime new_running_time_at_end =
1132         gst_segment_to_running_time (&self->asegment, GST_FORMAT_TIME,
1133         self->asegment.position + new_duration);
1134     GST_WARNING_OBJECT (self, "Pass audio buffer ending at %" GST_TIME_FORMAT,
1135         GST_TIME_ARGS (new_running_time_at_end));
1136     ret = gst_pad_push (self->asrcpad, inbuf);
1137   }
1138   if (send_element_message) {
1139     g_mutex_lock (&self->mutex);
1140     if ((self->must_send_end_message & END_MESSAGE_VIDEO_PUSHED) ||
1141         self->video_eos_flag) {
1142       self->must_send_end_message = END_MESSAGE_NORMAL;
1143       g_mutex_unlock (&self->mutex);
1144       gst_avwait_send_element_message (self, TRUE,
1145           self->audio_running_time_to_end_at);
1146     } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
1147       self->must_send_end_message |= END_MESSAGE_AUDIO_PUSHED;
1148       g_mutex_unlock (&self->mutex);
1149     } else {
1150       g_assert_not_reached ();
1151     }
1152   }
1153   send_element_message = FALSE;
1154   return ret;
1155 }
1156
1157 static GstIterator *
1158 gst_avwait_iterate_internal_links (GstPad * pad, GstObject * parent)
1159 {
1160   GstIterator *it = NULL;
1161   GstPad *opad;
1162   GValue val = G_VALUE_INIT;
1163   GstAvWait *self = GST_AVWAIT (parent);
1164
1165   if (self->asinkpad == pad)
1166     opad = gst_object_ref (self->asrcpad);
1167   else if (self->asrcpad == pad)
1168     opad = gst_object_ref (self->asinkpad);
1169   else if (self->vsinkpad == pad)
1170     opad = gst_object_ref (self->vsrcpad);
1171   else if (self->vsrcpad == pad)
1172     opad = gst_object_ref (self->vsinkpad);
1173   else
1174     goto out;
1175
1176   g_value_init (&val, GST_TYPE_PAD);
1177   g_value_set_object (&val, opad);
1178   it = gst_iterator_new_single (GST_TYPE_PAD, &val);
1179   g_value_unset (&val);
1180
1181   gst_object_unref (opad);
1182
1183 out:
1184   return it;
1185 }