3 * Copyright (C) 2016 Vivia Nikolaidou <vivia@toolsonair.com>
5 * Based on gstvideoframe-audiolevel.c:
6 * Copyright (C) 2015 Vivia Nikolaidou <vivia@toolsonair.com>
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.
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.
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.
25 * SECTION:element-avwait
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
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.
42 * ## Example launch line
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
52 #include "gstavwait.h"
54 #define GST_CAT_DEFAULT gst_avwait_debug
55 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
57 static GstStaticPadTemplate audio_sink_template =
58 GST_STATIC_PAD_TEMPLATE ("asink",
61 GST_STATIC_CAPS ("audio/x-raw")
64 static GstStaticPadTemplate audio_src_template =
65 GST_STATIC_PAD_TEMPLATE ("asrc",
68 GST_STATIC_CAPS ("audio/x-raw")
71 static GstStaticPadTemplate video_sink_template =
72 GST_STATIC_PAD_TEMPLATE ("vsink",
75 GST_STATIC_CAPS ("video/x-raw")
78 static GstStaticPadTemplate video_src_template =
79 GST_STATIC_PAD_TEMPLATE ("vsrc",
82 GST_STATIC_CAPS ("video/x-raw")
85 #define parent_class gst_avwait_parent_class
86 G_DEFINE_TYPE (GstAvWait, gst_avwait, GST_TYPE_ELEMENT);
87 GST_ELEMENT_REGISTER_DEFINE (avwait, "avwait", GST_RANK_NONE, GST_TYPE_AVWAIT);
92 PROP_TARGET_TIME_CODE,
93 PROP_TARGET_TIME_CODE_STRING,
94 PROP_TARGET_RUNNING_TIME,
96 PROP_END_RUNNING_TIME,
101 #define DEFAULT_TARGET_TIMECODE_STR "00:00:00:00"
102 #define DEFAULT_TARGET_RUNNING_TIME GST_CLOCK_TIME_NONE
103 #define DEFAULT_END_RUNNING_TIME GST_CLOCK_TIME_NONE
104 #define DEFAULT_MODE MODE_TIMECODE
106 /* flags for self->must_send_end_message */
109 END_MESSAGE_NORMAL = 0,
110 END_MESSAGE_STREAM_ENDED = 1,
111 END_MESSAGE_VIDEO_PUSHED = 2,
112 END_MESSAGE_AUDIO_PUSHED = 4
115 static void gst_avwait_set_property (GObject * object,
116 guint prop_id, const GValue * value, GParamSpec * pspec);
117 static void gst_avwait_get_property (GObject * object,
118 guint prop_id, GValue * value, GParamSpec * pspec);
120 static GstFlowReturn gst_avwait_asink_chain (GstPad * pad,
121 GstObject * parent, GstBuffer * inbuf);
122 static GstFlowReturn gst_avwait_vsink_chain (GstPad * pad,
123 GstObject * parent, GstBuffer * inbuf);
124 static gboolean gst_avwait_asink_event (GstPad * pad,
125 GstObject * parent, GstEvent * event);
126 static gboolean gst_avwait_vsink_event (GstPad * pad,
127 GstObject * parent, GstEvent * event);
128 static GstIterator *gst_avwait_iterate_internal_links (GstPad *
129 pad, GstObject * parent);
131 static void gst_avwait_finalize (GObject * gobject);
133 static GstStateChangeReturn gst_avwait_change_state (GstElement *
134 element, GstStateChange transition);
137 gst_avwait_mode_get_type (void)
139 static GType gtype = 0;
142 static const GEnumValue values[] = {
143 {MODE_TIMECODE, "time code (default)", "timecode"},
144 {MODE_RUNNING_TIME, "running time", "running-time"},
145 {MODE_VIDEO_FIRST, "video first", "video-first"},
149 gtype = g_enum_register_static ("GstAvWaitMode", values);
155 gst_avwait_class_init (GstAvWaitClass * klass)
157 GstElementClass *gstelement_class;
158 GObjectClass *gobject_class = (GObjectClass *) klass;
160 GST_DEBUG_CATEGORY_INIT (gst_avwait_debug, "avwait", 0, "avwait");
162 gstelement_class = (GstElementClass *) klass;
164 gst_element_class_set_static_metadata (gstelement_class,
165 "Timecode Wait", "Filter/Audio/Video",
166 "Drops all audio/video until a specific timecode or running time has been reached",
167 "Vivia Nikolaidou <vivia@toolsonair.com>");
169 gobject_class->set_property = gst_avwait_set_property;
170 gobject_class->get_property = gst_avwait_get_property;
172 g_object_class_install_property (gobject_class, PROP_TARGET_TIME_CODE_STRING,
173 g_param_spec_string ("target-timecode-string", "Target timecode (string)",
174 "Timecode to wait for in timecode mode (string). Must take the form 00:00:00:00",
175 DEFAULT_TARGET_TIMECODE_STR,
176 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178 g_object_class_install_property (gobject_class, PROP_TARGET_TIME_CODE,
179 g_param_spec_boxed ("target-timecode", "Target timecode (object)",
180 "Timecode to wait for in timecode mode (object)",
181 GST_TYPE_VIDEO_TIME_CODE,
182 GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
183 G_PARAM_STATIC_STRINGS));
185 g_object_class_install_property (gobject_class, PROP_TARGET_RUNNING_TIME,
186 g_param_spec_uint64 ("target-running-time", "Target running time",
187 "Running time to wait for in running-time mode",
189 DEFAULT_TARGET_RUNNING_TIME,
190 GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
191 G_PARAM_STATIC_STRINGS));
193 g_object_class_install_property (gobject_class, PROP_MODE,
194 g_param_spec_enum ("mode", "Mode",
195 "Operation mode: What to wait for",
196 GST_TYPE_AVWAIT_MODE,
198 GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
199 G_PARAM_STATIC_STRINGS));
201 g_object_class_install_property (gobject_class, PROP_END_TIME_CODE,
202 g_param_spec_boxed ("end-timecode", "End timecode (object)",
203 "Timecode to end at in timecode mode (object)",
204 GST_TYPE_VIDEO_TIME_CODE,
205 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207 g_object_class_install_property (gobject_class, PROP_END_RUNNING_TIME,
208 g_param_spec_uint64 ("end-running-time", "End running time",
209 "Running time to end at in running-time mode",
211 DEFAULT_END_RUNNING_TIME,
212 GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
213 G_PARAM_STATIC_STRINGS));
215 g_object_class_install_property (gobject_class, PROP_RECORDING,
216 g_param_spec_boolean ("recording",
218 "Whether the element is stopped or recording. "
219 "If set to FALSE, all buffers will be dropped regardless of settings.",
220 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
222 gobject_class->finalize = gst_avwait_finalize;
223 gstelement_class->change_state = gst_avwait_change_state;
225 gst_element_class_add_static_pad_template (gstelement_class,
226 &audio_src_template);
227 gst_element_class_add_static_pad_template (gstelement_class,
228 &audio_sink_template);
230 gst_element_class_add_static_pad_template (gstelement_class,
231 &video_src_template);
232 gst_element_class_add_static_pad_template (gstelement_class,
233 &video_sink_template);
235 gst_type_mark_as_plugin_api (GST_TYPE_AVWAIT_MODE, 0);
239 gst_avwait_init (GstAvWait * self)
242 gst_pad_new_from_static_template (&audio_sink_template, "asink");
243 gst_pad_set_chain_function (self->asinkpad,
244 GST_DEBUG_FUNCPTR (gst_avwait_asink_chain));
245 gst_pad_set_event_function (self->asinkpad,
246 GST_DEBUG_FUNCPTR (gst_avwait_asink_event));
247 gst_pad_set_iterate_internal_links_function (self->asinkpad,
248 GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
249 gst_element_add_pad (GST_ELEMENT (self), self->asinkpad);
252 gst_pad_new_from_static_template (&video_sink_template, "vsink");
253 gst_pad_set_chain_function (self->vsinkpad,
254 GST_DEBUG_FUNCPTR (gst_avwait_vsink_chain));
255 gst_pad_set_event_function (self->vsinkpad,
256 GST_DEBUG_FUNCPTR (gst_avwait_vsink_event));
257 gst_pad_set_iterate_internal_links_function (self->vsinkpad,
258 GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
259 gst_element_add_pad (GST_ELEMENT (self), self->vsinkpad);
262 gst_pad_new_from_static_template (&audio_src_template, "asrc");
263 gst_pad_set_iterate_internal_links_function (self->asrcpad,
264 GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
265 gst_element_add_pad (GST_ELEMENT (self), self->asrcpad);
268 gst_pad_new_from_static_template (&video_src_template, "vsrc");
269 gst_pad_set_iterate_internal_links_function (self->vsrcpad,
270 GST_DEBUG_FUNCPTR (gst_avwait_iterate_internal_links));
271 gst_element_add_pad (GST_ELEMENT (self), self->vsrcpad);
273 GST_PAD_SET_PROXY_CAPS (self->asinkpad);
274 GST_PAD_SET_PROXY_ALLOCATION (self->asinkpad);
276 GST_PAD_SET_PROXY_CAPS (self->asrcpad);
277 GST_PAD_SET_PROXY_SCHEDULING (self->asrcpad);
279 GST_PAD_SET_PROXY_CAPS (self->vsinkpad);
280 GST_PAD_SET_PROXY_ALLOCATION (self->vsinkpad);
282 GST_PAD_SET_PROXY_CAPS (self->vsrcpad);
283 GST_PAD_SET_PROXY_SCHEDULING (self->vsrcpad);
285 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
286 self->last_seen_video_running_time = GST_CLOCK_TIME_NONE;
287 self->first_audio_running_time = GST_CLOCK_TIME_NONE;
288 self->last_seen_tc = NULL;
290 self->video_eos_flag = FALSE;
291 self->audio_eos_flag = FALSE;
292 self->video_flush_flag = FALSE;
293 self->audio_flush_flag = FALSE;
294 self->shutdown_flag = FALSE;
295 self->dropping = TRUE;
296 self->tc = gst_video_time_code_new_empty ();
298 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
299 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
300 self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
301 self->recording = TRUE;
303 self->target_running_time = DEFAULT_TARGET_RUNNING_TIME;
304 self->end_running_time = DEFAULT_TARGET_RUNNING_TIME;
305 self->mode = DEFAULT_MODE;
307 gst_video_info_init (&self->vinfo);
308 g_mutex_init (&self->mutex);
309 g_cond_init (&self->cond);
310 g_cond_init (&self->audio_cond);
314 gst_avwait_send_element_message (GstAvWait * self, gboolean dropping,
315 GstClockTime running_time)
317 if (!gst_element_post_message (GST_ELEMENT (self),
318 gst_message_new_element (GST_OBJECT (self),
319 gst_structure_new ("avwait-status",
320 "dropping", G_TYPE_BOOLEAN, dropping,
321 "running-time", GST_TYPE_CLOCK_TIME, running_time, NULL)))) {
322 GST_ERROR_OBJECT (self, "Unable to send element message!");
323 g_assert_not_reached ();
327 static GstStateChangeReturn
328 gst_avwait_change_state (GstElement * element, GstStateChange transition)
330 GstStateChangeReturn ret;
331 GstAvWait *self = GST_AVWAIT (element);
333 switch (transition) {
334 case GST_STATE_CHANGE_PAUSED_TO_READY:
335 g_mutex_lock (&self->mutex);
336 self->shutdown_flag = TRUE;
337 g_cond_signal (&self->cond);
338 g_cond_signal (&self->audio_cond);
339 g_mutex_unlock (&self->mutex);
341 case GST_STATE_CHANGE_READY_TO_PAUSED:
342 g_mutex_lock (&self->mutex);
343 self->shutdown_flag = FALSE;
344 self->video_eos_flag = FALSE;
345 self->audio_eos_flag = FALSE;
346 self->video_flush_flag = FALSE;
347 self->audio_flush_flag = FALSE;
348 self->must_send_end_message = END_MESSAGE_NORMAL;
349 g_mutex_unlock (&self->mutex);
354 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
356 switch (transition) {
357 case GST_STATE_CHANGE_PAUSED_TO_READY:{
358 gboolean send_message = FALSE;
360 g_mutex_lock (&self->mutex);
361 if (self->mode != MODE_RUNNING_TIME) {
362 GST_DEBUG_OBJECT (self, "First time reset in paused to ready");
363 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
364 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
365 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
366 self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
368 if (!self->dropping) {
369 self->dropping = TRUE;
372 gst_segment_init (&self->asegment, GST_FORMAT_UNDEFINED);
373 self->asegment.position = GST_CLOCK_TIME_NONE;
374 gst_segment_init (&self->vsegment, GST_FORMAT_UNDEFINED);
375 self->vsegment.position = GST_CLOCK_TIME_NONE;
376 gst_video_info_init (&self->vinfo);
377 self->last_seen_video_running_time = GST_CLOCK_TIME_NONE;
378 self->first_audio_running_time = GST_CLOCK_TIME_NONE;
379 if (self->last_seen_tc)
380 gst_video_time_code_free (self->last_seen_tc);
381 self->last_seen_tc = NULL;
382 g_mutex_unlock (&self->mutex);
385 gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
396 gst_avwait_finalize (GObject * object)
398 GstAvWait *self = GST_AVWAIT (object);
401 gst_video_time_code_free (self->tc);
406 gst_video_time_code_free (self->end_tc);
410 g_mutex_clear (&self->mutex);
411 g_cond_clear (&self->cond);
412 g_cond_clear (&self->audio_cond);
414 G_OBJECT_CLASS (parent_class)->finalize (object);
418 gst_avwait_get_property (GObject * object, guint prop_id,
419 GValue * value, GParamSpec * pspec)
421 GstAvWait *self = GST_AVWAIT (object);
424 case PROP_TARGET_TIME_CODE_STRING:{
425 g_mutex_lock (&self->mutex);
427 g_value_take_string (value, gst_video_time_code_to_string (self->tc));
429 g_value_set_string (value, DEFAULT_TARGET_TIMECODE_STR);
430 g_mutex_unlock (&self->mutex);
433 case PROP_TARGET_TIME_CODE:{
434 g_mutex_lock (&self->mutex);
435 g_value_set_boxed (value, self->tc);
436 g_mutex_unlock (&self->mutex);
439 case PROP_END_TIME_CODE:{
440 g_mutex_lock (&self->mutex);
441 g_value_set_boxed (value, self->end_tc);
442 g_mutex_unlock (&self->mutex);
445 case PROP_TARGET_RUNNING_TIME:{
446 g_mutex_lock (&self->mutex);
447 g_value_set_uint64 (value, self->target_running_time);
448 g_mutex_unlock (&self->mutex);
451 case PROP_END_RUNNING_TIME:{
452 g_mutex_lock (&self->mutex);
453 g_value_set_uint64 (value, self->end_running_time);
454 g_mutex_unlock (&self->mutex);
457 case PROP_RECORDING:{
458 g_mutex_lock (&self->mutex);
459 g_value_set_boolean (value, self->recording);
460 g_mutex_unlock (&self->mutex);
464 g_mutex_lock (&self->mutex);
465 g_value_set_enum (value, self->mode);
466 g_mutex_unlock (&self->mutex);
470 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
476 gst_avwait_set_property (GObject * object, guint prop_id,
477 const GValue * value, GParamSpec * pspec)
479 GstAvWait *self = GST_AVWAIT (object);
482 case PROP_TARGET_TIME_CODE_STRING:{
485 guint hours, minutes, seconds, frames;
487 tc_str = g_value_get_string (value);
488 parts = g_strsplit (tc_str, ":", 4);
489 if (!parts || parts[3] == NULL) {
490 GST_ERROR_OBJECT (self,
491 "Error: Could not parse timecode %s. Please input a timecode in the form 00:00:00:00",
496 hours = g_ascii_strtoll (parts[0], NULL, 10);
497 minutes = g_ascii_strtoll (parts[1], NULL, 10);
498 seconds = g_ascii_strtoll (parts[2], NULL, 10);
499 frames = g_ascii_strtoll (parts[3], NULL, 10);
500 g_mutex_lock (&self->mutex);
502 gst_video_time_code_free (self->tc);
503 self->tc = gst_video_time_code_new (0, 1, NULL, 0, hours, minutes,
505 if (GST_VIDEO_INFO_FORMAT (&self->vinfo) != GST_VIDEO_FORMAT_UNKNOWN
506 && self->vinfo.fps_n != 0) {
507 self->tc->config.fps_n = self->vinfo.fps_n;
508 self->tc->config.fps_d = self->vinfo.fps_d;
510 g_mutex_unlock (&self->mutex);
514 case PROP_TARGET_TIME_CODE:{
515 g_mutex_lock (&self->mutex);
517 gst_video_time_code_free (self->tc);
518 self->tc = g_value_dup_boxed (value);
519 if (self->tc && self->tc->config.fps_n == 0
520 && GST_VIDEO_INFO_FORMAT (&self->vinfo) !=
521 GST_VIDEO_FORMAT_UNKNOWN && self->vinfo.fps_n != 0) {
522 self->tc->config.fps_n = self->vinfo.fps_n;
523 self->tc->config.fps_d = self->vinfo.fps_d;
525 g_mutex_unlock (&self->mutex);
528 case PROP_END_TIME_CODE:{
529 g_mutex_lock (&self->mutex);
531 gst_video_time_code_free (self->end_tc);
532 self->end_tc = g_value_dup_boxed (value);
533 if (self->end_tc && self->end_tc->config.fps_n == 0
534 && GST_VIDEO_INFO_FORMAT (&self->vinfo) !=
535 GST_VIDEO_FORMAT_UNKNOWN && self->vinfo.fps_n != 0) {
536 self->end_tc->config.fps_n = self->vinfo.fps_n;
537 self->end_tc->config.fps_d = self->vinfo.fps_d;
539 g_mutex_unlock (&self->mutex);
542 case PROP_TARGET_RUNNING_TIME:{
543 g_mutex_lock (&self->mutex);
544 self->target_running_time = g_value_get_uint64 (value);
545 if (self->mode == MODE_RUNNING_TIME) {
546 if (self->target_running_time > self->last_seen_video_running_time) {
547 self->dropping = TRUE;
550 g_mutex_unlock (&self->mutex);
553 case PROP_END_RUNNING_TIME:{
554 g_mutex_lock (&self->mutex);
555 self->end_running_time = g_value_get_uint64 (value);
556 if (self->mode == MODE_RUNNING_TIME) {
557 if (self->end_running_time >= self->last_seen_video_running_time) {
558 self->dropping = TRUE;
561 g_mutex_unlock (&self->mutex);
565 GstAvWaitMode old_mode;
567 g_mutex_lock (&self->mutex);
568 old_mode = self->mode;
569 self->mode = g_value_get_enum (value);
570 if (self->mode != old_mode) {
571 switch (self->mode) {
573 if (self->last_seen_tc && self->tc &&
574 gst_video_time_code_compare (self->last_seen_tc,
576 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
577 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
578 self->dropping = TRUE;
581 case MODE_RUNNING_TIME:
582 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
583 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
584 if (self->target_running_time > self->last_seen_video_running_time
585 || self->end_running_time >=
586 self->last_seen_video_running_time) {
587 self->dropping = TRUE;
590 /* Let the chain functions handle the rest */
591 case MODE_VIDEO_FIRST:
597 g_mutex_unlock (&self->mutex);
600 case PROP_RECORDING:{
601 g_mutex_lock (&self->mutex);
602 self->recording = g_value_get_boolean (value);
603 g_mutex_unlock (&self->mutex);
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
613 gst_avwait_vsink_event (GstPad * pad, GstObject * parent, GstEvent * event)
615 GstAvWait *self = GST_AVWAIT (parent);
616 GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
618 switch (GST_EVENT_TYPE (event)) {
619 case GST_EVENT_SEGMENT:{
621 gboolean send_message = FALSE;
622 gboolean segment_changed;
624 g_mutex_lock (&self->mutex);
625 gst_event_copy_segment (event, &segment);
626 segment.position = self->vsegment.position;
627 segment_changed = !gst_segment_is_equal (&segment, &self->vsegment);
628 self->vsegment = segment;
629 if (self->vsegment.format != GST_FORMAT_TIME) {
630 GST_ERROR_OBJECT (self, "Invalid segment format");
631 g_mutex_unlock (&self->mutex);
632 gst_event_unref (event);
635 if (segment_changed) {
636 GST_DEBUG_OBJECT (self, "First time reset in video segment");
637 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
638 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
639 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
640 self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
641 if (!self->dropping) {
642 self->dropping = TRUE;
645 self->vsegment.position = GST_CLOCK_TIME_NONE;
647 g_mutex_unlock (&self->mutex);
650 gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
654 gst_event_unref (event);
657 GstClockTime running_time;
658 gboolean send_message = FALSE;
659 GstClockTime audio_running_time_to_end_at;
661 g_mutex_lock (&self->mutex);
662 self->video_eos_flag = TRUE;
664 /* If we were recording then we'd be done with it at EOS of the video
665 * pad once the audio has caught up, if it has to */
666 running_time = self->last_seen_video_running_time;
667 if (self->was_recording) {
668 GST_INFO_OBJECT (self, "Recording stopped at EOS at %" GST_TIME_FORMAT,
669 GST_TIME_ARGS (running_time));
671 if (running_time > self->running_time_to_wait_for
672 && running_time <= self->running_time_to_end_at) {
673 /* We just stopped recording: synchronise the audio */
674 self->audio_running_time_to_end_at = running_time;
675 self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
676 } else if (running_time < self->running_time_to_wait_for
677 && self->running_time_to_wait_for != GST_CLOCK_TIME_NONE) {
678 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
682 g_cond_signal (&self->cond);
684 if (self->must_send_end_message & END_MESSAGE_AUDIO_PUSHED) {
685 self->must_send_end_message = END_MESSAGE_NORMAL;
687 audio_running_time_to_end_at = self->audio_running_time_to_end_at;
688 } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
689 self->must_send_end_message |= END_MESSAGE_VIDEO_PUSHED;
691 g_mutex_unlock (&self->mutex);
694 gst_avwait_send_element_message (self, TRUE,
695 audio_running_time_to_end_at);
698 case GST_EVENT_FLUSH_START:
699 g_mutex_lock (&self->mutex);
700 self->video_flush_flag = TRUE;
701 g_cond_signal (&self->audio_cond);
702 g_mutex_unlock (&self->mutex);
704 case GST_EVENT_FLUSH_STOP:{
705 gboolean send_message = FALSE;
707 g_mutex_lock (&self->mutex);
708 self->video_flush_flag = FALSE;
709 GST_DEBUG_OBJECT (self, "First time reset in video flush");
710 self->running_time_to_wait_for = GST_CLOCK_TIME_NONE;
711 self->running_time_to_end_at = GST_CLOCK_TIME_NONE;
712 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
713 self->audio_running_time_to_end_at = GST_CLOCK_TIME_NONE;
714 if (!self->dropping) {
715 self->dropping = TRUE;
718 gst_segment_init (&self->vsegment, GST_FORMAT_UNDEFINED);
719 self->vsegment.position = GST_CLOCK_TIME_NONE;
720 g_mutex_unlock (&self->mutex);
723 gst_avwait_send_element_message (self, TRUE, GST_CLOCK_TIME_NONE);
726 case GST_EVENT_CAPS:{
728 gst_event_parse_caps (event, &caps);
729 GST_DEBUG_OBJECT (self, "Got caps %" GST_PTR_FORMAT, caps);
730 g_mutex_lock (&self->mutex);
731 if (!gst_video_info_from_caps (&self->vinfo, caps)) {
732 gst_event_unref (event);
733 g_mutex_unlock (&self->mutex);
736 if (self->tc && self->tc->config.fps_n == 0 && self->vinfo.fps_n != 0) {
737 self->tc->config.fps_n = self->vinfo.fps_n;
738 self->tc->config.fps_d = self->vinfo.fps_d;
740 if (self->end_tc && self->end_tc->config.fps_n == 0
741 && self->vinfo.fps_n != 0) {
742 self->end_tc->config.fps_n = self->vinfo.fps_n;
743 self->end_tc->config.fps_d = self->vinfo.fps_d;
745 g_mutex_unlock (&self->mutex);
751 return gst_pad_event_default (pad, parent, event);
755 gst_avwait_asink_event (GstPad * pad, GstObject * parent, GstEvent * event)
757 GstAvWait *self = GST_AVWAIT (parent);
758 GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
760 switch (GST_EVENT_TYPE (event)) {
761 case GST_EVENT_SEGMENT:{
763 gboolean segment_changed;
765 g_mutex_lock (&self->mutex);
766 gst_event_copy_segment (event, &segment);
767 segment.position = self->asegment.position;
768 segment_changed = !gst_segment_is_equal (&segment, &self->asegment);
769 self->asegment = segment;
771 if (self->asegment.format != GST_FORMAT_TIME) {
772 GST_ERROR_OBJECT (self, "Invalid segment format");
773 g_mutex_unlock (&self->mutex);
774 gst_event_unref (event);
778 if (segment_changed) {
779 self->asegment.position = GST_CLOCK_TIME_NONE;
781 g_mutex_unlock (&self->mutex);
784 case GST_EVENT_FLUSH_START:
785 g_mutex_lock (&self->mutex);
786 self->audio_flush_flag = TRUE;
787 g_cond_signal (&self->cond);
788 g_mutex_unlock (&self->mutex);
791 gboolean send_message = FALSE;
792 GstClockTime audio_running_time_to_end_at;
794 g_mutex_lock (&self->mutex);
795 self->audio_eos_flag = TRUE;
796 g_cond_signal (&self->audio_cond);
798 if ((self->must_send_end_message & END_MESSAGE_VIDEO_PUSHED)) {
799 self->must_send_end_message = END_MESSAGE_NORMAL;
800 audio_running_time_to_end_at = self->audio_running_time_to_end_at;
802 } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
803 self->must_send_end_message |= END_MESSAGE_AUDIO_PUSHED;
805 self->must_send_end_message = END_MESSAGE_NORMAL;
807 g_mutex_unlock (&self->mutex);
810 gst_avwait_send_element_message (self, TRUE,
811 audio_running_time_to_end_at);
814 case GST_EVENT_FLUSH_STOP:
815 g_mutex_lock (&self->mutex);
816 self->audio_flush_flag = FALSE;
817 gst_segment_init (&self->asegment, GST_FORMAT_UNDEFINED);
818 self->asegment.position = GST_CLOCK_TIME_NONE;
819 g_mutex_unlock (&self->mutex);
821 case GST_EVENT_CAPS:{
823 gst_event_parse_caps (event, &caps);
824 GST_DEBUG_OBJECT (self, "Got caps %" GST_PTR_FORMAT, caps);
825 g_mutex_lock (&self->mutex);
826 if (!gst_audio_info_from_caps (&self->ainfo, caps)) {
827 g_mutex_unlock (&self->mutex);
828 gst_event_unref (event);
831 g_mutex_unlock (&self->mutex);
838 return gst_pad_event_default (pad, parent, event);
842 gst_avwait_vsink_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
844 GstClockTime timestamp;
845 GstAvWait *self = GST_AVWAIT (parent);
846 GstClockTime running_time;
847 GstVideoTimeCode *tc = NULL;
848 GstVideoTimeCodeMeta *tc_meta;
849 gboolean retry = FALSE;
850 gboolean ret = GST_FLOW_OK;
851 gboolean send_message = FALSE;
852 GstClockTime message_running_time;
853 gboolean message_dropping;
855 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
856 if (timestamp == GST_CLOCK_TIME_NONE) {
857 gst_buffer_unref (inbuf);
858 return GST_FLOW_ERROR;
861 g_mutex_lock (&self->mutex);
862 self->vsegment.position = timestamp;
864 gst_segment_to_running_time (&self->vsegment, GST_FORMAT_TIME,
865 self->vsegment.position);
866 self->last_seen_video_running_time = running_time;
868 tc_meta = gst_buffer_get_video_time_code_meta (inbuf);
870 tc = gst_video_time_code_copy (&tc_meta->tc);
871 if (self->last_seen_tc) {
872 gst_video_time_code_free (self->last_seen_tc);
874 self->last_seen_tc = tc;
877 while (self->mode == MODE_VIDEO_FIRST
878 && self->first_audio_running_time == GST_CLOCK_TIME_NONE
879 && !self->audio_eos_flag
880 && !self->shutdown_flag && !self->video_flush_flag) {
881 GST_DEBUG_OBJECT (self, "Waiting for first audio buffer");
882 g_cond_wait (&self->audio_cond, &self->mutex);
885 if (self->video_flush_flag || self->shutdown_flag) {
886 GST_DEBUG_OBJECT (self, "Shutting down, ignoring buffer");
887 gst_buffer_unref (inbuf);
888 g_mutex_unlock (&self->mutex);
889 return GST_FLOW_FLUSHING;
892 switch (self->mode) {
894 if (self->tc && self->end_tc
895 && gst_video_time_code_compare (self->tc, self->end_tc) != -1) {
896 gchar *tc_str, *end_tc;
898 tc_str = gst_video_time_code_to_string (self->tc);
899 end_tc = gst_video_time_code_to_string (self->end_tc);
900 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
901 ("End timecode %s must be after start timecode %s. Start timecode rejected",
905 gst_buffer_unref (inbuf);
906 g_mutex_unlock (&self->mutex);
907 return GST_FLOW_ERROR;
910 if (self->tc != NULL && tc != NULL) {
911 gboolean emit_passthrough_signal = FALSE;
913 if (gst_video_time_code_compare (tc, self->tc) < 0
914 && self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
915 GST_DEBUG_OBJECT (self, "Timecode not yet reached, ignoring frame");
916 gst_buffer_unref (inbuf);
918 } else if (self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
919 GST_INFO_OBJECT (self, "Target timecode reached at %" GST_TIME_FORMAT,
920 GST_TIME_ARGS (self->vsegment.position));
921 /* Don't emit a signal if we weren't dropping (e.g. settings changed
923 emit_passthrough_signal = self->dropping;
924 self->dropping = FALSE;
925 self->running_time_to_wait_for = running_time;
926 if (self->recording) {
927 self->audio_running_time_to_wait_for =
928 self->running_time_to_wait_for;
932 if (self->end_tc && gst_video_time_code_compare (tc, self->end_tc) >= 0) {
933 if (self->running_time_to_end_at == GST_CLOCK_TIME_NONE) {
934 GST_INFO_OBJECT (self, "End timecode reached at %" GST_TIME_FORMAT,
935 GST_TIME_ARGS (self->vsegment.position));
936 self->dropping = TRUE;
937 self->running_time_to_end_at = running_time;
938 if (self->recording) {
939 self->audio_running_time_to_end_at = self->running_time_to_end_at;
940 self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
945 gst_buffer_unref (inbuf);
948 } else if (emit_passthrough_signal && self->recording) {
950 message_running_time = self->running_time_to_wait_for;
951 message_dropping = FALSE;
956 case MODE_RUNNING_TIME:{
957 gboolean emit_passthrough_signal = FALSE;
959 if (self->target_running_time != GST_CLOCK_TIME_NONE
960 && running_time < self->target_running_time) {
961 GST_DEBUG_OBJECT (self,
962 "Have %" GST_TIME_FORMAT ", waiting for %" GST_TIME_FORMAT,
963 GST_TIME_ARGS (running_time),
964 GST_TIME_ARGS (self->target_running_time));
965 gst_buffer_unref (inbuf);
967 } else if (self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
968 /* Don't emit a signal if we weren't dropping (e.g. settings changed
970 emit_passthrough_signal = self->dropping;
971 self->dropping = FALSE;
972 self->running_time_to_wait_for = running_time;
973 if (self->recording) {
974 self->audio_running_time_to_wait_for = running_time;
976 if (self->recording) {
978 message_running_time = running_time;
979 message_dropping = FALSE;
983 if (GST_CLOCK_TIME_IS_VALID (self->end_running_time)
984 && running_time >= self->end_running_time) {
985 if (self->running_time_to_end_at == GST_CLOCK_TIME_NONE) {
986 GST_INFO_OBJECT (self,
987 "End running time %" GST_TIME_FORMAT " reached at %"
988 GST_TIME_FORMAT, GST_TIME_ARGS (self->end_running_time),
989 GST_TIME_ARGS (self->vsegment.position));
990 self->dropping = TRUE;
991 self->running_time_to_end_at = running_time;
992 if (self->recording) {
993 self->audio_running_time_to_end_at = running_time;
994 self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
999 gst_buffer_unref (inbuf);
1002 } else if (emit_passthrough_signal && self->recording) {
1003 send_message = TRUE;
1004 message_running_time = self->running_time_to_wait_for;
1005 message_dropping = FALSE;
1010 case MODE_VIDEO_FIRST:{
1011 if (self->running_time_to_wait_for == GST_CLOCK_TIME_NONE) {
1012 self->running_time_to_wait_for = running_time;
1013 GST_DEBUG_OBJECT (self, "First video running time is %" GST_TIME_FORMAT,
1014 GST_TIME_ARGS (self->running_time_to_wait_for));
1015 if (self->recording) {
1016 self->audio_running_time_to_wait_for = self->running_time_to_wait_for;
1018 if (self->dropping) {
1019 self->dropping = FALSE;
1020 if (self->recording) {
1021 send_message = TRUE;
1022 message_running_time = self->running_time_to_wait_for;
1023 message_dropping = FALSE;
1031 if (!self->recording) {
1032 if (self->was_recording) {
1033 GST_INFO_OBJECT (self, "Recording stopped at %" GST_TIME_FORMAT,
1034 GST_TIME_ARGS (running_time));
1036 if (running_time > self->running_time_to_wait_for
1037 && (running_time <= self->running_time_to_end_at
1038 || self->running_time_to_end_at == GST_CLOCK_TIME_NONE)) {
1039 /* We just stopped recording: synchronise the audio */
1040 if (self->running_time_to_end_at == GST_CLOCK_TIME_NONE)
1041 self->running_time_to_end_at = running_time;
1042 self->audio_running_time_to_end_at = running_time;
1043 self->must_send_end_message |= END_MESSAGE_STREAM_ENDED;
1044 } else if (running_time < self->running_time_to_wait_for
1045 && self->running_time_to_wait_for != GST_CLOCK_TIME_NONE) {
1046 self->audio_running_time_to_wait_for = GST_CLOCK_TIME_NONE;
1050 /* Recording is FALSE: we drop all buffers */
1052 gst_buffer_unref (inbuf);
1056 if (!self->was_recording) {
1057 GST_INFO_OBJECT (self,
1058 "Recording started at %" GST_TIME_FORMAT " waiting for %"
1059 GST_TIME_FORMAT " inbuf %p", GST_TIME_ARGS (running_time),
1060 GST_TIME_ARGS (self->running_time_to_wait_for), inbuf);
1062 if (self->mode != MODE_VIDEO_FIRST ||
1063 self->first_audio_running_time <= running_time ||
1064 self->audio_eos_flag) {
1065 if (running_time < self->running_time_to_end_at ||
1066 self->running_time_to_end_at == GST_CLOCK_TIME_NONE) {
1067 /* We are before the end of the recording. Check if we just actually
1069 if (self->running_time_to_wait_for != GST_CLOCK_TIME_NONE
1070 && running_time > self->running_time_to_wait_for) {
1071 /* We just started recording: synchronise the audio */
1072 self->audio_running_time_to_wait_for = running_time;
1073 send_message = TRUE;
1074 message_running_time = running_time;
1075 message_dropping = FALSE;
1077 /* We will start in the future when running_time_to_wait_for is
1079 self->audio_running_time_to_wait_for =
1080 self->running_time_to_wait_for;
1082 self->audio_running_time_to_end_at = self->running_time_to_end_at;
1085 /* We are in video-first mode and behind the first audio timestamp. We
1086 * should drop all video buffers until the first audio timestamp, so
1087 * we can catch up with it. (In timecode mode and running-time mode, we
1088 * don't care about when the audio starts, we start as soon as the
1089 * target timecode or running time has been reached) */
1091 gst_buffer_unref (inbuf);
1100 self->was_recording = self->recording;
1101 g_cond_signal (&self->cond);
1102 g_mutex_unlock (&self->mutex);
1105 gst_avwait_send_element_message (self, message_dropping,
1106 message_running_time);
1107 send_message = FALSE;
1110 GST_DEBUG_OBJECT (self,
1111 "Pass video buffer %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1112 GST_TIME_ARGS (gst_segment_to_running_time (&self->vsegment,
1113 GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (inbuf))),
1114 GST_TIME_ARGS (gst_segment_to_running_time (&self->vsegment,
1116 GST_BUFFER_TIMESTAMP (inbuf) + GST_BUFFER_DURATION (inbuf))));
1117 ret = gst_pad_push (self->vsrcpad, inbuf);
1120 g_mutex_lock (&self->mutex);
1121 if (self->must_send_end_message & END_MESSAGE_AUDIO_PUSHED) {
1122 self->must_send_end_message = END_MESSAGE_NORMAL;
1123 send_message = TRUE;
1124 message_dropping = TRUE;
1125 message_running_time = self->audio_running_time_to_end_at;
1126 } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
1127 if (self->audio_eos_flag) {
1128 self->must_send_end_message = END_MESSAGE_NORMAL;
1129 send_message = TRUE;
1130 message_dropping = TRUE;
1131 message_running_time = self->audio_running_time_to_end_at;
1133 self->must_send_end_message |= END_MESSAGE_VIDEO_PUSHED;
1136 g_mutex_unlock (&self->mutex);
1139 gst_avwait_send_element_message (self, message_dropping,
1140 message_running_time);
1146 * assumes sign1 and sign2 are either 1 or -1
1147 * returns 0 if sign1*num1 == sign2*num2
1148 * -1 if sign1*num1 < sign2*num2
1149 * 1 if sign1*num1 > sign2*num2
1152 gst_avwait_compare_guint64_with_signs (gint sign1,
1153 guint64 num1, gint sign2, guint64 num2)
1157 else if (num1 == num2)
1160 return num1 > num2 ? sign1 : -sign1;
1163 static GstFlowReturn
1164 gst_avwait_asink_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf)
1166 GstClockTime timestamp;
1167 GstAvWait *self = GST_AVWAIT (parent);
1168 GstClockTime current_running_time;
1169 GstClockTime video_running_time = GST_CLOCK_TIME_NONE;
1170 GstClockTime duration;
1171 GstClockTime running_time_at_end = GST_CLOCK_TIME_NONE;
1172 gint asign, vsign = 1, esign = 1;
1173 GstFlowReturn ret = GST_FLOW_OK;
1174 /* Make sure the video thread doesn't send the element message before we
1175 * actually call gst_pad_push */
1176 gboolean send_element_message = FALSE;
1178 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
1179 if (timestamp == GST_CLOCK_TIME_NONE) {
1180 gst_buffer_unref (inbuf);
1181 return GST_FLOW_ERROR;
1184 g_mutex_lock (&self->mutex);
1185 self->asegment.position = timestamp;
1187 gst_segment_to_running_time_full (&self->asegment, GST_FORMAT_TIME,
1188 self->asegment.position, ¤t_running_time);
1190 g_mutex_unlock (&self->mutex);
1191 gst_buffer_unref (inbuf);
1192 GST_ERROR_OBJECT (self, "Could not get current running time");
1193 return GST_FLOW_ERROR;
1196 if (self->first_audio_running_time == GST_CLOCK_TIME_NONE) {
1197 self->first_audio_running_time = current_running_time;
1200 g_cond_signal (&self->audio_cond);
1201 if (self->vsegment.format == GST_FORMAT_TIME) {
1203 gst_segment_to_running_time_full (&self->vsegment, GST_FORMAT_TIME,
1204 self->vsegment.position, &video_running_time);
1206 video_running_time = GST_CLOCK_TIME_NONE;
1211 gst_util_uint64_scale (gst_buffer_get_size (inbuf) / self->ainfo.bpf,
1212 GST_SECOND, self->ainfo.rate);
1213 if (duration != GST_CLOCK_TIME_NONE) {
1215 gst_segment_to_running_time_full (&self->asegment, GST_FORMAT_TIME,
1216 self->asegment.position + duration, &running_time_at_end);
1218 g_mutex_unlock (&self->mutex);
1219 GST_ERROR_OBJECT (self, "Could not get running time at end");
1220 gst_buffer_unref (inbuf);
1221 return GST_FLOW_ERROR;
1225 while (!(self->video_eos_flag || self->audio_flush_flag
1226 || self->shutdown_flag) &&
1227 /* Start at timecode */
1228 /* Wait if we haven't received video yet */
1229 (video_running_time == GST_CLOCK_TIME_NONE
1230 /* Wait if audio is after the video: dunno what to do */
1231 || gst_avwait_compare_guint64_with_signs (asign,
1232 running_time_at_end, vsign, video_running_time) == 1)) {
1233 GST_DEBUG_OBJECT (self,
1234 "Waiting for video: audio at %s%" GST_TIME_FORMAT ", video at %s%"
1235 GST_TIME_FORMAT, asign < 0 ? "-" : "+",
1236 GST_TIME_ARGS (running_time_at_end), vsign < 0 ? "-" : "+",
1237 GST_TIME_ARGS (video_running_time));
1238 g_cond_wait (&self->cond, &self->mutex);
1240 gst_segment_to_running_time_full (&self->vsegment, GST_FORMAT_TIME,
1241 self->vsegment.position, &video_running_time);
1243 video_running_time = GST_CLOCK_TIME_NONE;
1247 if (self->audio_flush_flag || self->shutdown_flag) {
1248 GST_DEBUG_OBJECT (self, "Shutting down, ignoring frame");
1249 gst_buffer_unref (inbuf);
1250 g_mutex_unlock (&self->mutex);
1251 return GST_FLOW_FLUSHING;
1254 if (self->audio_running_time_to_wait_for == GST_CLOCK_TIME_NONE
1255 /* Audio ends before start : drop */
1256 || gst_avwait_compare_guint64_with_signs (esign,
1257 running_time_at_end, 1, self->audio_running_time_to_wait_for) == -1
1258 /* Audio starts after end: drop */
1259 || current_running_time >= self->audio_running_time_to_end_at) {
1260 GST_DEBUG_OBJECT (self,
1261 "Dropped an audio buf at %" GST_TIME_FORMAT " waiting for %"
1262 GST_TIME_FORMAT " video time %" GST_TIME_FORMAT,
1263 GST_TIME_ARGS (current_running_time),
1264 GST_TIME_ARGS (self->audio_running_time_to_wait_for),
1265 GST_TIME_ARGS (video_running_time));
1266 GST_DEBUG_OBJECT (self, "Would have ended at %i %" GST_TIME_FORMAT,
1267 esign, GST_TIME_ARGS (running_time_at_end));
1268 gst_buffer_unref (inbuf);
1270 if (current_running_time >= self->audio_running_time_to_end_at &&
1271 (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) &&
1272 !(self->must_send_end_message & END_MESSAGE_AUDIO_PUSHED)) {
1273 send_element_message = TRUE;
1275 } else if (gst_avwait_compare_guint64_with_signs (esign, running_time_at_end,
1276 1, self->audio_running_time_to_wait_for) >= 0
1277 && gst_avwait_compare_guint64_with_signs (esign, running_time_at_end, 1,
1278 self->audio_running_time_to_end_at) == -1) {
1279 /* Audio ends after start, but before end: clip */
1280 GstSegment asegment2 = self->asegment;
1284 ssign = gst_segment_position_from_running_time_full (&asegment2,
1285 GST_FORMAT_TIME, self->audio_running_time_to_wait_for, &start);
1287 asegment2.start = start;
1289 /* Starting before the start of the audio segment?! */
1290 /* This shouldn't happen: we already know that the current audio is
1291 * inside the segment, and that the end is after the current audio
1293 GST_ELEMENT_ERROR (self, CORE, FAILED,
1294 ("Failed to clip audio: it should have started before the current segment"),
1299 gst_audio_buffer_clip (inbuf, &asegment2, self->ainfo.rate,
1301 } else if (gst_avwait_compare_guint64_with_signs (esign, running_time_at_end,
1302 1, self->audio_running_time_to_end_at) >= 0) {
1303 /* Audio starts after start, but before end: clip from the other side */
1304 GstSegment asegment2 = self->asegment;
1309 gst_segment_position_from_running_time_full (&asegment2,
1310 GST_FORMAT_TIME, self->audio_running_time_to_end_at, &stop);
1312 asegment2.stop = stop;
1314 /* Stopping before the start of the audio segment?! */
1315 /* This shouldn't happen: we already know that the current audio is
1316 * inside the segment, and that the end is after the current audio
1318 GST_ELEMENT_ERROR (self, CORE, FAILED,
1319 ("Failed to clip audio: it should have ended before the current segment"),
1323 gst_audio_buffer_clip (inbuf, &asegment2, self->ainfo.rate,
1325 if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
1326 send_element_message = TRUE;
1329 /* Programming error? Shouldn't happen */
1330 g_assert_not_reached ();
1332 g_mutex_unlock (&self->mutex);
1335 GstClockTime new_duration =
1336 gst_util_uint64_scale (gst_buffer_get_size (inbuf) / self->ainfo.bpf,
1337 GST_SECOND, self->ainfo.rate);
1338 GstClockTime new_running_time_at_end =
1339 gst_segment_to_running_time (&self->asegment, GST_FORMAT_TIME,
1340 GST_BUFFER_TIMESTAMP (inbuf) + new_duration);
1342 GST_DEBUG_OBJECT (self,
1343 "Pass audio buffer %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1344 GST_TIME_ARGS (gst_segment_to_running_time (&self->asegment,
1345 GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (inbuf))),
1346 GST_TIME_ARGS (new_running_time_at_end));
1347 ret = gst_pad_push (self->asrcpad, inbuf);
1350 if (send_element_message) {
1351 gboolean send_message = FALSE;
1352 GstClockTime audio_running_time_to_end_at;
1354 g_mutex_lock (&self->mutex);
1355 if ((self->must_send_end_message & END_MESSAGE_VIDEO_PUSHED) ||
1356 self->video_eos_flag) {
1357 self->must_send_end_message = END_MESSAGE_NORMAL;
1358 send_message = TRUE;
1359 audio_running_time_to_end_at = self->audio_running_time_to_end_at;
1360 } else if (self->must_send_end_message & END_MESSAGE_STREAM_ENDED) {
1361 self->must_send_end_message |= END_MESSAGE_AUDIO_PUSHED;
1363 g_assert_not_reached ();
1364 g_mutex_unlock (&self->mutex);
1366 g_mutex_unlock (&self->mutex);
1369 gst_avwait_send_element_message (self, TRUE,
1370 audio_running_time_to_end_at);
1372 send_element_message = FALSE;
1376 static GstIterator *
1377 gst_avwait_iterate_internal_links (GstPad * pad, GstObject * parent)
1379 GstIterator *it = NULL;
1381 GValue val = G_VALUE_INIT;
1382 GstAvWait *self = GST_AVWAIT (parent);
1384 if (self->asinkpad == pad)
1385 opad = gst_object_ref (self->asrcpad);
1386 else if (self->asrcpad == pad)
1387 opad = gst_object_ref (self->asinkpad);
1388 else if (self->vsinkpad == pad)
1389 opad = gst_object_ref (self->vsrcpad);
1390 else if (self->vsrcpad == pad)
1391 opad = gst_object_ref (self->vsinkpad);
1395 g_value_init (&val, GST_TYPE_PAD);
1396 g_value_set_object (&val, opad);
1397 it = gst_iterator_new_single (GST_TYPE_PAD, &val);
1398 g_value_unset (&val);
1400 gst_object_unref (opad);