static gboolean gst_cdxa_parse_do_seek (GstCDXAParse * cdxa, GstEvent * event) { GstSeekFlags flags; GstSeekType start_type; GstFormat format; gint64 start, off, upstream_size; gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start, NULL, NULL); if (format != GST_FORMAT_BYTES) { GST_DEBUG_OBJECT (cdxa, "Can only handle seek in BYTES format"); return FALSE; } if (start_type != GST_SEEK_TYPE_SET) { GST_DEBUG_OBJECT (cdxa, "Can only handle seek from start (SEEK_TYPE_SET)"); return FALSE; } GST_OBJECT_LOCK (cdxa); off = gst_cdxa_parse_convert_src_to_sink_offset (cdxa, start); upstream_size = cdxa->datasize; GST_OBJECT_UNLOCK (cdxa); if (off >= upstream_size) { GST_DEBUG_OBJECT (cdxa, "Invalid target offset %" G_GINT64_FORMAT ", file " "is only %" G_GINT64_FORMAT " bytes in size", off, upstream_size); return FALSE; } /* unlock upstream pull_range */ gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_start ()); /* make sure our loop function exits */ gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_start ()); /* wait for streaming to finish */ GST_PAD_STREAM_LOCK (cdxa->sinkpad); /* prepare for streaming again */ gst_pad_push_event (cdxa->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (cdxa->srcpad, gst_event_new_flush_stop ()); gst_pad_push_event (cdxa->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, start, GST_CLOCK_TIME_NONE, 0)); GST_OBJECT_LOCK (cdxa); cdxa->offset = off; GST_OBJECT_UNLOCK (cdxa); /* and restart */ gst_pad_start_task (cdxa->sinkpad, (GstTaskFunction) gst_cdxa_parse_loop, cdxa->sinkpad, NULL); GST_PAD_STREAM_UNLOCK (cdxa->sinkpad); return TRUE; }
static gboolean gst_rnd_buffer_size_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstRndBufferSize *self; GstSeekType start_type; GstSeekFlags flags; GstFormat format; gint64 start; if (GST_EVENT_TYPE (event) != GST_EVENT_SEEK) { GST_WARNING_OBJECT (pad, "dropping %s event", GST_EVENT_TYPE_NAME (event)); return FALSE; } self = GST_RND_BUFFER_SIZE (parent); gst_event_parse_seek (event, NULL, &format, &flags, &start_type, &start, NULL, NULL); if (format != GST_FORMAT_BYTES) { GST_WARNING_OBJECT (pad, "only BYTE format supported"); return FALSE; } if (start_type != GST_SEEK_TYPE_SET) { GST_WARNING_OBJECT (pad, "only SEEK_TYPE_SET supported"); return FALSE; } if ((flags & GST_SEEK_FLAG_FLUSH)) { gst_pad_push_event (self->srcpad, gst_event_new_flush_start ()); gst_pad_push_event (self->sinkpad, gst_event_new_flush_start ()); } else { gst_pad_pause_task (self->sinkpad); } GST_PAD_STREAM_LOCK (self->sinkpad); if ((flags & GST_SEEK_FLAG_FLUSH)) { gst_pad_push_event (self->srcpad, gst_event_new_flush_stop (TRUE)); gst_pad_push_event (self->sinkpad, gst_event_new_flush_stop (TRUE)); } GST_INFO_OBJECT (pad, "seeking to offset %" G_GINT64_FORMAT, start); self->offset = start; self->need_newsegment = TRUE; gst_pad_start_task (self->sinkpad, (GstTaskFunction) gst_rnd_buffer_size_loop, self); GST_PAD_STREAM_UNLOCK (self->sinkpad); return TRUE; }
static HRESULT WINAPI Gstreamer_transform_EndFlush(TransformFilter *iface) { GstTfImpl *This = (GstTfImpl*)iface; TRACE("%p\n", This); gst_pad_push_event(This->my_src, gst_event_new_flush_stop()); return S_OK; }
static gboolean forward_event_func (const GValue * val, GValue * ret, EventData * data) { GstPad *pad = g_value_get_object (val); GstEvent *event = data->event; GstPad *peer; gst_event_ref (event); GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event)); peer = gst_pad_get_peer (pad); /* collect pad might have been set flushing, * so bypass core checking that and send directly to peer */ if (!peer || !gst_pad_send_event (peer, event)) { if (!peer) gst_event_unref (event); GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", event, GST_EVENT_TYPE_NAME (event)); /* quick hack to unflush the pads, ideally we need a way to just unflush * this single collect pad */ if (data->flush) gst_pad_send_event (pad, gst_event_new_flush_stop (TRUE)); } else { g_value_set_boolean (ret, TRUE); GST_LOG_OBJECT (pad, "Sent event %p (%s).", event, GST_EVENT_TYPE_NAME (event)); } if (peer) gst_object_unref (peer); /* continue on other pads, even if one failed */ return TRUE; }
static GstFlowReturn gst_smart_encoder_reencode_gop (GstSmartEncoder * smart_encoder) { GstFlowReturn res = GST_FLOW_OK; GList *tmp; if (smart_encoder->encoder == NULL) { if (!setup_recoder_pipeline (smart_encoder)) return GST_FLOW_ERROR; } /* Activate elements */ /* Set elements to PAUSED */ gst_element_set_state (smart_encoder->encoder, GST_STATE_PAUSED); gst_element_set_state (smart_encoder->decoder, GST_STATE_PAUSED); GST_INFO ("Pushing Flush start/stop to clean decoder/encoder"); gst_pad_push_event (smart_encoder->internal_srcpad, gst_event_new_flush_start ()); gst_pad_push_event (smart_encoder->internal_srcpad, gst_event_new_flush_stop (TRUE)); /* push newsegment */ GST_INFO ("Pushing newsegment %" GST_PTR_FORMAT, smart_encoder->newsegment); gst_pad_push_event (smart_encoder->internal_srcpad, gst_event_ref (smart_encoder->newsegment)); /* Push buffers through our pads */ GST_DEBUG ("Pushing pending buffers"); for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) { GstBuffer *buf = (GstBuffer *) tmp->data; res = gst_pad_push (smart_encoder->internal_srcpad, buf); if (G_UNLIKELY (res != GST_FLOW_OK)) break; } if (G_UNLIKELY (res != GST_FLOW_OK)) { GST_WARNING ("Error pushing pending buffers : %s", gst_flow_get_name (res)); /* Remove pending bfufers */ for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) { gst_buffer_unref ((GstBuffer *) tmp->data); } } else { GST_INFO ("Pushing out EOS to flush out decoder/encoder"); gst_pad_push_event (smart_encoder->internal_srcpad, gst_event_new_eos ()); } /* Activate elements */ /* Set elements to PAUSED */ gst_element_set_state (smart_encoder->encoder, GST_STATE_NULL); gst_element_set_state (smart_encoder->decoder, GST_STATE_NULL); g_list_free (smart_encoder->pending_gop); smart_encoder->pending_gop = NULL; return res; }
static void send_flush_on_unlink (GstPad * pad, GstPad * peer, gpointer user_data) { if (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_EOS)) { gst_pad_send_event (pad, gst_event_new_flush_start ()); gst_pad_send_event (pad, gst_event_new_flush_stop (FALSE)); } }
KUIRecord::~KUIRecord() { gst_element_send_event (screenEnc, gst_event_new_eos ()); gst_element_send_event (camEnc, gst_event_new_eos ()); gst_element_send_event (audioEnc, gst_event_new_eos()); gst_element_send_event(pipeline, gst_event_new_flush_stop()); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); }
/* element navigation */ static void _send_eos (GstElement * element) { GstPad *sinkpad = gst_element_get_static_pad (element, "sink"); if (sinkpad) gst_pad_send_event (sinkpad, gst_event_new_eos ()); else { GstPad *srcpad = gst_element_get_static_pad (element, "src"); gst_pad_send_event (srcpad, gst_event_new_flush_stop (FALSE)); } }
static void distribute_running_time (GstElement * element, const GstSegment * segment) { GstEvent *event; GstPad *pad; pad = gst_element_get_static_pad (element, "sink"); gst_pad_send_event (pad, gst_event_new_flush_start ()); gst_pad_send_event (pad, gst_event_new_flush_stop (FALSE)); if (segment->format != GST_FORMAT_UNDEFINED) { event = gst_event_new_segment (segment); gst_pad_send_event (pad, event); } gst_object_unref (pad); }
static void kms_element_release_pad (GstElement * element, GstPad * pad) { GstElement *agnosticbin; GstPad *target; GstPad *peer; if (g_str_has_prefix (GST_OBJECT_NAME (pad), "audio_src")) { agnosticbin = KMS_ELEMENT (element)->priv->audio_agnosticbin; } else if (g_str_has_prefix (GST_OBJECT_NAME (pad), "video_src")) { agnosticbin = KMS_ELEMENT (element)->priv->video_agnosticbin; } else { return; } // TODO: Remove pad if is a sinkpad target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); if (target != NULL) { if (agnosticbin != NULL) { gst_element_release_request_pad (agnosticbin, target); } g_object_unref (target); } peer = gst_pad_get_peer (pad); gst_pad_push_event (pad, gst_event_new_flush_start ()); if (GST_STATE (element) >= GST_STATE_PAUSED || GST_STATE_PENDING (element) >= GST_STATE_PAUSED) { gst_pad_set_active (pad, FALSE); } if (peer) { gst_pad_send_event (peer, gst_event_new_flush_stop (FALSE)); g_object_unref (peer); } gst_element_remove_pad (element, pad); }
static void kms_element_set_target_on_linked (GstPad * pad, GstPad * peer, GstElement * element) { GstPad *target; target = gst_element_get_request_pad (element, "src_%u"); if (GST_PAD_IS_FLUSHING (peer)) { gst_pad_send_event (peer, gst_event_new_flush_start ()); gst_pad_send_event (peer, gst_event_new_flush_stop (FALSE)); } GST_DEBUG_OBJECT (pad, "Setting target %" GST_PTR_FORMAT, target); if (!gst_ghost_pad_set_target (GST_GHOST_PAD (pad), target)) { GST_ERROR_OBJECT (pad, "Can not set target pad"); } g_object_unref (target); }
static void switch_pads (GstHLSDemux * demux, GstCaps * newcaps) { GstPad *oldpad = demux->srcpad; GST_DEBUG ("Switching pads (oldpad:%p)", oldpad); /* FIXME: This is a workaround for a bug in playsink. * If we're switching from an audio-only or video-only fragment * to an audio-video segment, the new sink doesn't know about * the current running time and audio/video will go out of sync. * * This should be fixed in playsink by distributing the * current running time to newly created sinks and is * fixed in 0.11 with the new segments. */ if (demux->srcpad) gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ()); /* First create and activate new pad */ demux->srcpad = gst_pad_new_from_static_template (&srctemplate, NULL); gst_pad_set_event_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_hls_demux_src_event)); gst_pad_set_query_function (demux->srcpad, GST_DEBUG_FUNCPTR (gst_hls_demux_src_query)); gst_pad_set_element_private (demux->srcpad, demux); gst_pad_set_active (demux->srcpad, TRUE); gst_pad_set_caps (demux->srcpad, newcaps); gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad); gst_element_no_more_pads (GST_ELEMENT (demux)); if (oldpad) { /* Push out EOS */ gst_pad_push_event (oldpad, gst_event_new_eos ()); gst_pad_set_active (oldpad, FALSE); gst_element_remove_pad (GST_ELEMENT (demux), oldpad); } }
static gboolean forward_event_func (GstPad * pad, GValue * ret, EventData * data) { GstEvent *event = data->event; gst_event_ref (event); GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event)); if (!gst_pad_push_event (pad, event)) { GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", event, GST_EVENT_TYPE_NAME (event)); /* quick hack to unflush the pads, ideally we need a way to just unflush * this single collect pad */ if (data->flush) gst_pad_send_event (pad, gst_event_new_flush_stop ()); } else { g_value_set_boolean (ret, TRUE); GST_LOG_OBJECT (pad, "Sent event %p (%s).", event, GST_EVENT_TYPE_NAME (event)); } gst_object_unref (pad); /* continue on other pads, even if one failed */ return TRUE; }
/*********************************************************************************** * Seek implementation ***********************************************************************************/ static gboolean progress_buffer_perform_push_seek(ProgressBuffer *element, GstPad *pad, GstEvent *event) { GstFormat format; gdouble rate; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 position; GstSegment segment; gst_event_parse_seek(event, &rate, &format, &flags, &start_type, &position, &stop_type, NULL); if (format != GST_FORMAT_BYTES || start_type != GST_SEEK_TYPE_SET) return FALSE; if (stop_type != GST_SEEK_TYPE_NONE) { gst_element_message_full(GST_ELEMENT(element), GST_MESSAGE_WARNING, GST_CORE_ERROR, GST_CORE_ERROR_SEEK, g_strdup("stop_type != GST_SEEK_TYPE_NONE. Seeking to stop is not supported."), NULL, ("progressbuffer.c"), ("progress_buffer_perform_push_seek"), 0); return FALSE; } if (flags & GST_SEEK_FLAG_FLUSH) gst_pad_push_event(pad, gst_event_new_flush_start()); // Signal the task to stop if it's waiting. g_mutex_lock(&element->lock); element->srcresult = GST_FLOW_FLUSHING; g_cond_signal(&element->add_cond); g_mutex_unlock(&element->lock); GST_PAD_STREAM_LOCK(pad); // Wait for task to stop g_mutex_lock(&element->lock); element->srcresult = GST_FLOW_OK; #ifdef ENABLE_SOURCE_SEEKING element->instant_seek = (position >= element->sink_segment.start && (position - (gint64)element->sink_segment.position) <= element->bandwidth * element->wait_tolerance); if (element->instant_seek) { cache_set_read_position(element->cache, position - element->cache_read_offset); gst_segment_init(&segment, GST_FORMAT_BYTES); segment.rate = rate; segment.start = position; segment.stop = element->sink_segment.stop; segment.position = position; progress_buffer_set_pending_event(element, gst_event_new_segment(&segment)); } else { // Clear any pending events, since we doing seek. reset_eos(element, TRUE); } #else cache_set_read_position(element->cache, position - element->cache_read_offset); gst_segment_init(&segment, GST_FORMAT_BYTES); segment.rate = rate; segment.start = position; segment.stop = element->sink_segment.stop; segment.position = position; progress_buffer_set_pending_event(element, gst_event_new_segment(&segment)); #endif g_mutex_unlock(&element->lock); #ifdef ENABLE_SOURCE_SEEKING if (!element->instant_seek) { element->is_source_seeking = TRUE; if (!gst_pad_push_event(element->sinkpad, gst_event_new_seek(rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, 0))) { element->instant_seek = TRUE; cache_set_read_position(element->cache, position - element->cache_read_offset); gst_segment_init(&segment, GST_FORMAT_BYTES); segment.rate = rate; segment.start = position; segment.stop = element->sink_segment.stop; segment.position = position; progress_buffer_set_pending_event(element, gst_event_new_segment(&segment)); } element->is_source_seeking = FALSE; } #endif if (flags & GST_SEEK_FLAG_FLUSH) gst_pad_push_event(pad, gst_event_new_flush_stop(TRUE)); gst_pad_start_task(element->srcpad, progress_buffer_loop, element, NULL); GST_PAD_STREAM_UNLOCK(pad); // INLINE - gst_event_unref() gst_event_unref(event); return TRUE; }
static gboolean start_image_capture (GstWrapperCameraBinSrc * self) { GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self); GstPhotography *photography = (GstPhotography *) gst_bin_get_by_interface (GST_BIN_CAST (bcamsrc), GST_TYPE_PHOTOGRAPHY); gboolean ret = FALSE; GstCaps *caps; GstPad *pad, *peer; GST_DEBUG_OBJECT (self, "Starting image capture"); gst_element_set_state (self->src_vid_src, GST_STATE_READY); /* FIXME - V4L2 source will not close the device until all buffers have came * back. Flushing the pipeline, will ensure it's properly closed, and that * setting it back to PLAYING will work. This is more a workaround then a * solution to buffer reclaiming. */ pad = gst_element_get_static_pad (self->src_vid_src, "src"); peer = gst_pad_get_peer (pad); gst_object_unref (pad); gst_pad_send_event (peer, gst_event_new_flush_start ()); gst_pad_send_event (peer, gst_event_new_flush_stop (TRUE)); gst_object_unref (peer); if (self->image_renegotiate) { /* clean capsfilter caps so they don't interfere here */ g_object_set (self->src_filter, "caps", NULL, NULL); if (self->src_zoom_filter) g_object_set (self->src_zoom_filter, "caps", NULL, NULL); caps = gst_pad_get_allowed_caps (self->imgsrc); gst_caps_replace (&self->image_capture_caps, caps); gst_caps_unref (caps); /* FIXME - do we need to update basecamerasrc width/height somehow here? * if not, i think we need to do something about _when_ they get updated * to be sure that set_element_zoom doesn't use the wrong values */ /* We caught this event in the src pad event handler and now we want to * actually push it upstream */ gst_pad_send_event (self->outsel_imgpad, gst_event_new_reconfigure ()); self->image_renegotiate = FALSE; } if (photography) { gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING); GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT, self->image_capture_caps); ret = gst_photography_prepare_for_capture (photography, (GstPhotographyCapturePrepared) img_capture_prepared, self->image_capture_caps, self); } else { g_mutex_unlock (&bcamsrc->capturing_mutex); gst_wrapper_camera_bin_reset_video_src_caps (self, self->image_capture_caps); g_mutex_lock (&bcamsrc->capturing_mutex); ret = TRUE; gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING); } return ret; }
static gboolean gst_gme_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstGmeDec *gme = GST_GME_DEC (parent); gboolean result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gboolean flush; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); gst_event_unref (event); if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (gme, "seeking is only supported in TIME format"); break; } if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) { GST_DEBUG_OBJECT (gme, "unsupported seek type"); break; } if (stop_type == GST_SEEK_TYPE_NONE) stop = GST_CLOCK_TIME_NONE; if (start_type == GST_SEEK_TYPE_SET) { GstSegment seg; guint64 cur = gme_tell (gme->player) * GST_MSECOND; guint64 dest = (guint64) start; if (gme->total_duration != GST_CLOCK_TIME_NONE) dest = CLAMP (dest, 0, gme->total_duration); else dest = MAX (0, dest); if (dest == cur) break; flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH; if (flush) { gst_pad_push_event (gme->srcpad, gst_event_new_flush_start ()); } else { gst_pad_stop_task (gme->srcpad); } GST_PAD_STREAM_LOCK (gme->srcpad); if (flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (gme), gst_message_new_segment_start (GST_OBJECT (gme), format, cur)); } if (flush) { gst_pad_push_event (gme->srcpad, gst_event_new_flush_stop (TRUE)); } if (stop == GST_CLOCK_TIME_NONE && gme->total_duration != GST_CLOCK_TIME_NONE) stop = gme->total_duration; gst_segment_init (&seg, GST_FORMAT_TIME); seg.rate = rate; seg.start = dest; seg.stop = stop; seg.time = dest; gst_pad_push_event (gme->srcpad, gst_event_new_segment (&seg)); gme->seekpoint = dest / GST_MSECOND; /* nsecs to msecs */ gme->seeking = TRUE; gst_pad_start_task (gme->srcpad, (GstTaskFunction) gst_gme_play, gme->srcpad, NULL); GST_PAD_STREAM_UNLOCK (gme->srcpad); result = TRUE; } break; } default: result = gst_pad_push_event (gme->sinkpad, event); break; } return result; }
static gboolean gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse, GstEvent * event) { GstSeekFlags seek_flags; GstSeekType start_type; GstSeekType stop_type; GstSegment segment; GstFormat format; gboolean only_update; gboolean flush, ret; gdouble speed; gint64 stop; gint64 start; /* sample we want to seek to */ gint64 byte_offset; /* byte offset the chunk we seek to starts at */ gint64 chunk_start; /* first sample in chunk we seek to */ guint rate; gint64 last_stop; if (wvparse->adapter) { GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet"); return FALSE; } gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) { GST_DEBUG ("seeking is only supported in TIME or DEFAULT format"); return FALSE; } if (speed < 0.0) { GST_DEBUG ("only forward playback supported, rate %f not allowed", speed); return FALSE; } GST_OBJECT_LOCK (wvparse); rate = wvparse->samplerate; if (rate == 0) { GST_OBJECT_UNLOCK (wvparse); GST_DEBUG ("haven't read header yet"); return FALSE; } /* figure out the last position we need to play. If it's configured (stop != * -1), use that, else we play until the total duration of the file */ if (stop == -1) stop = wvparse->segment.duration; /* convert from time to samples if necessary */ if (format == GST_FORMAT_TIME) { if (start_type != GST_SEEK_TYPE_NONE) start = gst_util_uint64_scale_int (start, rate, GST_SECOND); if (stop_type != GST_SEEK_TYPE_NONE) stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND); } if (start < 0) { GST_OBJECT_UNLOCK (wvparse); GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start); return FALSE; } flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0); /* operate on segment copy until we know the seek worked */ segment = wvparse->segment; gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT, seek_flags, start_type, start, stop_type, stop, &only_update); #if 0 if (only_update) { wvparse->segment = segment; gst_wavpack_parse_send_newsegment (wvparse, TRUE); goto done; } #endif gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ()); if (flush) { gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ()); } else { gst_pad_pause_task (wvparse->sinkpad); } GST_PAD_STREAM_LOCK (wvparse->sinkpad); /* Save current position */ last_stop = wvparse->segment.last_stop; gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ()); if (flush) { gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ()); } GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %" G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate), start); ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start, &byte_offset, &chunk_start); if (ret) { GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset); wvparse->current_offset = byte_offset; /* we want to send a newsegment event with the actual seek position * as start, even though our first buffer might start before the * configured segment. We leave it up to the decoder or sink to crop * the output buffers accordingly */ wvparse->segment = segment; wvparse->segment.last_stop = chunk_start; wvparse->need_newsegment = TRUE; wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE; /* if we're doing a segment seek, post a SEGMENT_START message */ if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT_CAST (wvparse), gst_message_new_segment_start (GST_OBJECT_CAST (wvparse), wvparse->segment.format, wvparse->segment.last_stop)); } } else { GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to"); } GST_PAD_STREAM_UNLOCK (wvparse->sinkpad); GST_OBJECT_UNLOCK (wvparse); gst_pad_start_task (wvparse->sinkpad, (GstTaskFunction) gst_wavpack_parse_loop, wvparse); return ret; }
static gboolean gst_type_find_element_seek (GstTypeFindElement * typefind, GstEvent * event) { GstSeekFlags flags; GstSeekType start_type, stop_type; GstFormat format; gboolean flush; gdouble rate; gint64 start, stop; GstSegment seeksegment = { 0, }; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); /* we can only seek on bytes */ if (format != GST_FORMAT_BYTES) { GST_DEBUG_OBJECT (typefind, "Can only seek on BYTES"); return FALSE; } /* copy segment, we need this because we still need the old * segment when we close the current segment. */ memcpy (&seeksegment, &typefind->segment, sizeof (GstSegment)); GST_DEBUG_OBJECT (typefind, "configuring seek"); gst_segment_do_seek (&seeksegment, rate, format, flags, start_type, start, stop_type, stop, NULL); flush = ! !(flags & GST_SEEK_FLAG_FLUSH); GST_DEBUG_OBJECT (typefind, "New segment %" GST_SEGMENT_FORMAT, &seeksegment); if (flush) { GST_DEBUG_OBJECT (typefind, "Starting flush"); gst_pad_push_event (typefind->sink, gst_event_new_flush_start ()); gst_pad_push_event (typefind->src, gst_event_new_flush_start ()); } else { GST_DEBUG_OBJECT (typefind, "Non-flushing seek, pausing task"); gst_pad_pause_task (typefind->sink); } /* now grab the stream lock so that streaming cannot continue, for * non flushing seeks when the element is in PAUSED this could block * forever. */ GST_DEBUG_OBJECT (typefind, "Waiting for streaming to stop"); GST_PAD_STREAM_LOCK (typefind->sink); if (flush) { GST_DEBUG_OBJECT (typefind, "Stopping flush"); gst_pad_push_event (typefind->sink, gst_event_new_flush_stop (TRUE)); gst_pad_push_event (typefind->src, gst_event_new_flush_stop (TRUE)); } /* now update the real segment info */ GST_DEBUG_OBJECT (typefind, "Committing new seek segment"); memcpy (&typefind->segment, &seeksegment, sizeof (GstSegment)); typefind->offset = typefind->segment.start; /* notify start of new segment */ if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) { GstMessage *msg; msg = gst_message_new_segment_start (GST_OBJECT (typefind), GST_FORMAT_BYTES, typefind->segment.start); gst_element_post_message (GST_ELEMENT (typefind), msg); } typefind->need_segment = TRUE; /* restart our task since it might have been stopped when we did the * flush. */ gst_pad_start_task (typefind->sink, (GstTaskFunction) gst_type_find_element_loop, typefind->sink, NULL); /* streaming can continue now */ GST_PAD_STREAM_UNLOCK (typefind->sink); return TRUE; }
static gboolean gst_spc_dec_src_event (GstPad * pad, GstEvent * event) { GstSpcDec *spc = GST_SPC_DEC (gst_pad_get_parent (pad)); gboolean result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gboolean flush; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (spc, "seeking is only supported in TIME format"); break; } if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) { GST_DEBUG_OBJECT (spc, "unsupported seek type"); break; } if (stop_type == GST_SEEK_TYPE_NONE) stop = GST_CLOCK_TIME_NONE; if (start_type == GST_SEEK_TYPE_SET) { guint64 cur = gst_util_uint64_scale (spc->byte_pos, GST_SECOND, 32000 * 2 * 2); guint64 dest = (guint64) start; dest = CLAMP (dest, 0, gst_spc_duration (spc) + gst_spc_fadeout (spc)); if (dest == cur) break; flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH; if (flush) { gst_pad_push_event (spc->srcpad, gst_event_new_flush_start ()); } else { gst_pad_stop_task (spc->srcpad); } GST_PAD_STREAM_LOCK (spc->srcpad); if (flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (spc), gst_message_new_segment_start (GST_OBJECT (spc), format, cur)); } if (flush) { gst_pad_push_event (spc->srcpad, gst_event_new_flush_stop ()); } if (stop == GST_CLOCK_TIME_NONE) stop = (guint64) (gst_spc_duration (spc) + gst_spc_fadeout (spc)); gst_pad_push_event (spc->srcpad, gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME, dest, stop, dest)); /* spc->byte_pos += OSPC_Run(-1, NULL, (unsigned int) (gst_util_uint64_scale(dest - cur, 32000*2*2, GST_SECOND))); */ spc->seekpoint = gst_util_uint64_scale (dest, 32000 * 2 * 2, GST_SECOND); spc->seeking = TRUE; gst_pad_start_task (spc->srcpad, (GstTaskFunction) spc_play, spc->srcpad); GST_PAD_STREAM_UNLOCK (spc->srcpad); result = TRUE; } break; } default: break; } gst_event_unref (event); gst_object_unref (spc); return result; }
static void _create_issues (GstValidateRunner * runner) { GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2; GstElement *src1, *src2, *sink, *fakemixer; GstSegment segment; src1 = create_and_monitor_element ("fakesrc2", "fakesrc1", runner); src2 = create_and_monitor_element ("fakesrc2", "fakesrc2", runner); fakemixer = create_and_monitor_element ("fakemixer", "fakemixer", runner); sink = create_and_monitor_element ("fakesink", "fakesink", runner); srcpad1 = gst_element_get_static_pad (src1, "src"); srcpad2 = gst_element_get_static_pad (src2, "src"); funnel_sink1 = gst_element_get_request_pad (fakemixer, "sink_%u"); funnel_sink2 = gst_element_get_request_pad (fakemixer, "sink_%u"); sinkpad = gst_element_get_static_pad (sink, "sink"); fail_unless (gst_element_link (fakemixer, sink)); fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK); fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK); /* We want to handle the src behaviour ourselves */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE)); /* Setup all needed events */ gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 0; segment.stop = GST_SECOND; fail_unless (gst_pad_push_event (srcpad1, gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment))); fail_unless (gst_pad_push_event (srcpad2, gst_event_new_stream_start ("the-stream"))); fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment))); fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); /* Send an unexpected flush stop */ _gst_check_expecting_log = TRUE; fail_unless (gst_pad_push_event (srcpad1, gst_event_new_flush_stop (TRUE))); /* Once again but on the other fakemixer sink */ fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE))); /* clean up */ fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE)); fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE)); fail_unless_equals_int (gst_element_set_state (fakemixer, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS); gst_object_unref (srcpad1); gst_object_unref (srcpad2); gst_object_unref (sinkpad); gst_object_unref (funnel_sink1); gst_object_unref (funnel_sink2); gst_check_objects_destroyed_on_unref (fakemixer, funnel_sink1, funnel_sink2, NULL); gst_check_objects_destroyed_on_unref (src1, srcpad1, NULL); gst_check_objects_destroyed_on_unref (src2, srcpad2, NULL); gst_check_objects_destroyed_on_unref (sink, sinkpad, NULL); }
static gboolean gst_timidity_src_event (GstPad * pad, GstEvent * event) { gboolean res = FALSE; GstTimidity *timidity = GST_TIMIDITY (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gdouble rate; GstFormat src_format, dst_format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 orig_start, start, stop; gboolean flush, update; if (!timidity->song) break; gst_event_parse_seek (event, &rate, &src_format, &flags, &start_type, &orig_start, &stop_type, &stop); dst_format = GST_FORMAT_DEFAULT; gst_timidity_src_convert (timidity, src_format, orig_start, &dst_format, &start); gst_timidity_src_convert (timidity, src_format, stop, &dst_format, &stop); flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH); if (flush) { GST_DEBUG ("performing flush"); gst_pad_push_event (timidity->srcpad, gst_event_new_flush_start ()); } else { gst_pad_stop_task (timidity->sinkpad); } GST_PAD_STREAM_LOCK (timidity->sinkpad); if (flush) { gst_pad_push_event (timidity->srcpad, gst_event_new_flush_stop ()); } gst_segment_set_seek (timidity->o_segment, rate, dst_format, flags, start_type, start, stop_type, stop, &update); if ((flags && GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) { GST_DEBUG_OBJECT (timidity, "received segment seek %d, %d", (gint) start_type, (gint) stop_type); } else { GST_DEBUG_OBJECT (timidity, "received normal seek %d", (gint) start_type); update = FALSE; } gst_pad_push_event (timidity->srcpad, gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME, update)); timidity->o_seek = TRUE; gst_pad_start_task (timidity->sinkpad, (GstTaskFunction) gst_timidity_loop, timidity->sinkpad); GST_PAD_STREAM_UNLOCK (timidity->sinkpad); GST_DEBUG ("seek done"); } res = TRUE; break; default: break; } g_object_unref (timidity); return res; }
static gboolean gst_wildmidi_do_seek (GstWildmidi * wildmidi, GstEvent * event) { gdouble rate; GstFormat src_format, dst_format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gboolean flush, update; #ifdef HAVE_WILDMIDI_0_2_2 gboolean accurate; #endif gboolean res; unsigned long int sample; GstSegment *segment; if (!wildmidi->song) return FALSE; gst_event_parse_seek (event, &rate, &src_format, &flags, &start_type, &start, &stop_type, &stop); /* convert the input format to samples */ dst_format = GST_FORMAT_DEFAULT; res = TRUE; if (start_type != GST_SEEK_TYPE_NONE) { res = gst_wildmidi_src_convert (wildmidi, src_format, start, &dst_format, &start); } if (res && stop_type != GST_SEEK_TYPE_NONE) { res = gst_wildmidi_src_convert (wildmidi, src_format, stop, &dst_format, &stop); } /* unsupported format */ if (!res) return res; flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH); #ifdef HAVE_WILDMIDI_0_2_2 accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE); #endif if (flush) { GST_DEBUG ("performing flush"); gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_start ()); } else { gst_pad_stop_task (wildmidi->sinkpad); } segment = wildmidi->o_segment; GST_PAD_STREAM_LOCK (wildmidi->sinkpad); if (flush) { gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_stop (TRUE)); } /* update the segment now */ gst_segment_do_seek (segment, rate, dst_format, flags, start_type, start, stop_type, stop, &update); /* we need to seek to position in the segment now, sample will be updated */ sample = segment->position; GST_OBJECT_LOCK (wildmidi); #ifdef HAVE_WILDMIDI_0_2_2 if (accurate) { WildMidi_SampledSeek (wildmidi->song, &sample); } else { WildMidi_FastSeek (wildmidi->song, &sample); } #else WildMidi_FastSeek (wildmidi->song, &sample); #endif GST_OBJECT_UNLOCK (wildmidi); segment->start = segment->time = segment->position = sample; gst_pad_push_event (wildmidi->srcpad, gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME)); gst_pad_start_task (wildmidi->sinkpad, (GstTaskFunction) gst_wildmidi_loop, wildmidi->sinkpad, NULL); wildmidi->discont = TRUE; GST_PAD_STREAM_UNLOCK (wildmidi->sinkpad); GST_DEBUG ("seek done"); return TRUE; }
static GstFlowReturn new_sample_cb (GstElement * appsink, gpointer user_data) { GstElement *appsrc = GST_ELEMENT (user_data); GstFlowReturn ret; GstSample *sample; GstBuffer *buffer; GstClockTime *base_time; GstPad *src, *sink; g_signal_emit_by_name (appsink, "pull-sample", &sample); if (sample == NULL) return GST_FLOW_OK; buffer = gst_sample_get_buffer (sample); if (buffer == NULL) { ret = GST_FLOW_OK; goto end; } gst_buffer_ref (buffer); buffer = gst_buffer_make_writable (buffer); KMS_ELEMENT_LOCK (GST_OBJECT_PARENT (appsrc)); base_time = g_object_get_data (G_OBJECT (GST_OBJECT_PARENT (appsrc)), BASE_TIME_DATA); if (base_time == NULL) { GstClock *clock; clock = gst_element_get_clock (appsrc); base_time = g_slice_new0 (GstClockTime); g_object_set_data_full (G_OBJECT (GST_OBJECT_PARENT (appsrc)), BASE_TIME_DATA, base_time, release_gst_clock); *base_time = gst_clock_get_time (clock) - gst_element_get_base_time (appsrc); g_object_unref (clock); GST_DEBUG ("Setting base time to: %" G_GUINT64_FORMAT, *base_time); } src = gst_element_get_static_pad (appsrc, "src"); sink = gst_pad_get_peer (src); if (sink != NULL) { if (GST_OBJECT_FLAG_IS_SET (sink, GST_PAD_FLAG_EOS)) { GST_INFO_OBJECT (sink, "Sending flush events"); gst_pad_send_event (sink, gst_event_new_flush_start ()); gst_pad_send_event (sink, gst_event_new_flush_stop (FALSE)); } g_object_unref (sink); } g_object_unref (src); if (GST_BUFFER_PTS_IS_VALID (buffer)) buffer->pts += *base_time; if (GST_BUFFER_DTS_IS_VALID (buffer)) buffer->dts += *base_time; KMS_ELEMENT_UNLOCK (GST_OBJECT_PARENT (appsrc)); // TODO: Do something to fix a possible previous EOS event g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); gst_buffer_unref (buffer); if (ret != GST_FLOW_OK) { /* something wrong */ GST_ERROR ("Could not send buffer to appsrc %s. Cause: %s", GST_ELEMENT_NAME (appsrc), gst_flow_get_name (ret)); } end: if (sample != NULL) gst_sample_unref (sample); return ret; }
gboolean mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad, GstEvent * event) { MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); GstFlowReturn ret = GST_FLOW_ERROR; gdouble rate; gboolean flush; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; GstEvent *flush_event = NULL; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) return FALSE; if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) { GST_DEBUG_OBJECT (base, "Skipping already handled seek"); return TRUE; } if (base->mode == BASE_MODE_PUSHING) { /* First try if upstream supports seeking in TIME format */ if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) { GST_DEBUG ("upstream handled SEEK event"); return TRUE; } /* If the subclass can seek, do that */ if (klass->seek) { ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else { GstEvent *new_seek; if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) { base->mode = BASE_MODE_SEEKING; new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1); gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event)); if (!gst_pad_push_event (base->sinkpad, new_seek)) ret = GST_FLOW_ERROR; else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); } base->mode = BASE_MODE_PUSHING; } } else { GST_WARNING ("subclass has no seek implementation"); } return ret == GST_FLOW_OK; } if (!klass->seek) { GST_WARNING ("subclass has no seek implementation"); return FALSE; } if (rate <= 0.0) { GST_WARNING ("Negative rate not supported"); return FALSE; } GST_DEBUG ("seek event, rate: %f start: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); flush = flags & GST_SEEK_FLAG_FLUSH; /* stop streaming, either by flushing or by pausing the task */ base->mode = BASE_MODE_SEEKING; if (flush) { GST_DEBUG_OBJECT (base, "sending flush start"); flush_event = gst_event_new_flush_start (); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); } else gst_pad_pause_task (base->sinkpad); /* wait for streaming to finish */ GST_PAD_STREAM_LOCK (base->sinkpad); if (flush) { /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */ GST_DEBUG_OBJECT (base, "sending flush stop"); flush_event = gst_event_new_flush_stop (TRUE); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); /* ref for it to be reused later */ gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); /* And actually flush our pending data but allow to preserve some info * to perform the seek */ mpegts_base_flush (base, FALSE); mpegts_packetizer_flush (base->packetizer, FALSE); } if (flags & (GST_SEEK_FLAG_SEGMENT)) { GST_WARNING ("seek flags 0x%x are not supported", (int) flags); goto done; } /* If the subclass can seek, do that */ ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); if (flush_event) { /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ GST_DEBUG_OBJECT (base, "sending flush stop"); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); flush_event = NULL; } done: if (flush_event) gst_event_unref (flush_event); gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base, NULL); GST_PAD_STREAM_UNLOCK (base->sinkpad); return ret == GST_FLOW_OK; }
static gboolean gst_musepackdec_handle_seek_event (GstMusepackDec * dec, GstEvent * event) { GstSeekType start_type, stop_type; GstSeekFlags flags; GstSegment segment; GstFormat format; gboolean flush; gdouble rate; gint64 start, stop; gint samplerate; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) { GST_DEBUG_OBJECT (dec, "seek failed: only TIME or DEFAULT format allowed"); return FALSE; } samplerate = g_atomic_int_get (&dec->rate); if (format == GST_FORMAT_TIME) { if (start_type != GST_SEEK_TYPE_NONE) start = gst_util_uint64_scale_int (start, samplerate, GST_SECOND); if (stop_type != GST_SEEK_TYPE_NONE) stop = gst_util_uint64_scale_int (stop, samplerate, GST_SECOND); } flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH); if (flush) gst_pad_push_event (dec->srcpad, gst_event_new_flush_start ()); else gst_pad_pause_task (dec->sinkpad); /* not _stop_task()? */ GST_PAD_STREAM_LOCK (dec->sinkpad); /* operate on segment copy until we know the seek worked */ segment = dec->segment; gst_segment_do_seek (&segment, rate, GST_FORMAT_DEFAULT, flags, start_type, start, stop_type, stop, NULL); gst_pad_push_event (dec->sinkpad, gst_event_new_flush_stop (TRUE)); GST_DEBUG_OBJECT (dec, "segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]", segment.start, segment.stop, GST_TIME_ARGS (segment.start * GST_SECOND / dec->rate), GST_TIME_ARGS (segment.stop * GST_SECOND / dec->rate)); GST_DEBUG_OBJECT (dec, "performing seek to sample %" G_GINT64_FORMAT, segment.start); if (segment.start >= segment.duration) { GST_WARNING_OBJECT (dec, "seek out of bounds"); goto failed; } if (mpc_demux_seek_sample (dec->d, segment.start) != MPC_STATUS_OK) goto failed; if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) { GST_DEBUG_OBJECT (dec, "posting SEGMENT_START message"); gst_element_post_message (GST_ELEMENT (dec), gst_message_new_segment_start (GST_OBJECT (dec), GST_FORMAT_TIME, gst_util_uint64_scale_int (segment.start, GST_SECOND, dec->rate))); } if (flush) { gst_pad_push_event (dec->srcpad, gst_event_new_flush_stop (TRUE)); } segment.position = segment.start; dec->segment = segment; gst_musepackdec_send_newsegment (dec); GST_DEBUG_OBJECT (dec, "seek successful"); gst_pad_start_task (dec->sinkpad, (GstTaskFunction) gst_musepackdec_loop, dec->sinkpad, NULL); GST_PAD_STREAM_UNLOCK (dec->sinkpad); return TRUE; failed: { GST_WARNING_OBJECT (dec, "seek failed"); GST_PAD_STREAM_UNLOCK (dec->sinkpad); return FALSE; } }
static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event) { GstAdder *adder; gboolean result; adder = GST_ADDER (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (pad, "Got %s event on src pad from %s", GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event))); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { GstSeekFlags flags; GstSeekType curtype, endtype; gint64 cur, end; gboolean flush; /* parse the seek parameters */ gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype, &cur, &endtype, &end); if ((curtype != GST_SEEK_TYPE_NONE) && (curtype != GST_SEEK_TYPE_SET)) { result = FALSE; GST_DEBUG_OBJECT (adder, "seeking failed, unhandled seek type for start: %d", curtype); goto done; } if ((endtype != GST_SEEK_TYPE_NONE) && (endtype != GST_SEEK_TYPE_SET)) { result = FALSE; GST_DEBUG_OBJECT (adder, "seeking failed, unhandled seek type for end: %d", endtype); goto done; } flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH; /* check if we are flushing */ if (flush) { /* flushing seek, start flush downstream, the flush will be done * when all pads received a FLUSH_STOP. * Make sure we accept nothing anymore and return WRONG_STATE. * We send a flush-start before, to ensure no streaming is done * as we need to take the stream lock. */ gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ()); gst_collect_pads2_set_flushing (adder->collect, TRUE); /* We can't send FLUSH_STOP here since upstream could start pushing data * after we unlock adder->collect. * We set flush_stop_pending to TRUE instead and send FLUSH_STOP after * forwarding the seek upstream or from gst_adder_collected, * whichever happens first. */ g_atomic_int_set (&adder->flush_stop_pending, TRUE); } GST_DEBUG_OBJECT (adder, "handling seek event: %" GST_PTR_FORMAT, event); /* now wait for the collected to be finished and mark a new * segment. After we have the lock, no collect function is running and no * new collect function will be called for as long as we're flushing. */ GST_COLLECT_PADS2_STREAM_LOCK (adder->collect); if (curtype == GST_SEEK_TYPE_SET) adder->segment_start = cur; else adder->segment_start = 0; if (endtype == GST_SEEK_TYPE_SET) adder->segment_end = end; else adder->segment_end = GST_CLOCK_TIME_NONE; if (flush) { /* Yes, we need to call _set_flushing again *WHEN* the streaming threads * have stopped so that the cookie gets properly updated. */ gst_collect_pads2_set_flushing (adder->collect, TRUE); } GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect); GST_DEBUG_OBJECT (adder, "forwarding seek event: %" GST_PTR_FORMAT, event); /* we're forwarding seek to all upstream peers and wait for one to reply * with a newsegment-event before we send a newsegment-event downstream */ g_atomic_int_set (&adder->wait_for_new_segment, TRUE); result = forward_event (adder, event, flush); if (!result) { /* seek failed. maybe source is a live source. */ GST_DEBUG_OBJECT (adder, "seeking failed"); } if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending, TRUE, FALSE)) { GST_DEBUG_OBJECT (adder, "pending flush stop"); gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ()); } break; } case GST_EVENT_QOS: /* QoS might be tricky */ result = FALSE; break; case GST_EVENT_NAVIGATION: /* navigation is rather pointless. */ result = FALSE; break; default: /* just forward the rest for now */ GST_DEBUG_OBJECT (adder, "forward unhandled event: %s", GST_EVENT_TYPE_NAME (event)); result = forward_event (adder, event, FALSE); break; } done: gst_object_unref (adder); return result; }
static gboolean gst_hls_demux_src_event (GstPad * pad, GstEvent * event) { GstHLSDemux *demux; demux = GST_HLS_DEMUX (gst_pad_get_element_private (pad)); switch (event->type) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; GList *walk; gint current_pos; gint current_sequence; gint target_second; GstM3U8MediaFile *file; GST_INFO_OBJECT (demux, "Received GST_EVENT_SEEK"); if (gst_m3u8_client_is_live (demux->client)) { GST_WARNING_OBJECT (demux, "Received seek event for live stream"); return FALSE; } gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) return FALSE; GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data); current_sequence = file->sequence; current_pos = 0; target_second = start / GST_SECOND; GST_DEBUG_OBJECT (demux, "Target seek to %d", target_second); for (walk = demux->client->current->files; walk; walk = walk->next) { file = walk->data; current_sequence = file->sequence; if (current_pos <= target_second && target_second < current_pos + file->duration) { break; } current_pos += file->duration; } if (walk == NULL) { GST_WARNING_OBJECT (demux, "Could not find seeked fragment"); return FALSE; } if (flags & GST_SEEK_FLAG_FLUSH) { GST_DEBUG_OBJECT (demux, "sending flush start"); gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ()); } demux->cancelled = TRUE; gst_task_pause (demux->task); g_mutex_lock (demux->fetcher_lock); gst_hls_demux_stop_fetcher (demux, TRUE); g_mutex_unlock (demux->fetcher_lock); g_mutex_lock (demux->thread_lock); g_cond_signal (demux->thread_cond); g_mutex_unlock (demux->thread_lock); gst_task_pause (demux->task); /* wait for streaming to finish */ g_static_rec_mutex_lock (&demux->task_lock); demux->need_cache = TRUE; while (!g_queue_is_empty (demux->queue)) { GstBuffer *buf = g_queue_pop_head (demux->queue); gst_buffer_unref (buf); } GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence); demux->client->sequence = current_sequence; demux->position = start; demux->need_segment = TRUE; if (flags & GST_SEEK_FLAG_FLUSH) { GST_DEBUG_OBJECT (demux, "sending flush stop"); gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ()); } demux->cancelled = FALSE; gst_task_start (demux->task); g_static_rec_mutex_unlock (&demux->task_lock); return TRUE; } default: break; } return gst_pad_event_default (pad, event); }
static gboolean gst_real_audio_demux_handle_seek (GstRealAudioDemux * demux, GstEvent * event) { GstFormat format; GstSeekFlags flags; GstSeekType cur_type, stop_type; gboolean flush, update; gdouble rate; guint64 seek_pos; gint64 cur, stop; if (!demux->seekable) goto not_seekable; if (demux->byterate_num == 0 || demux->byterate_denom == 0) goto no_bitrate; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); if (format != GST_FORMAT_TIME) goto only_time_format_supported; if (rate <= 0.0) goto cannot_do_backwards_playback; flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0); GST_DEBUG_OBJECT (demux, "flush=%d, rate=%g", flush, rate); /* unlock streaming thread and make streaming stop */ if (flush) { gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ()); gst_pad_push_event (demux->srcpad, gst_event_new_flush_start ()); } else { gst_pad_pause_task (demux->sinkpad); } GST_PAD_STREAM_LOCK (demux->sinkpad); if (demux->segment_running && !flush) { GstEvent *newseg; newseg = gst_event_new_new_segment_full (TRUE, demux->segment.rate, demux->segment.applied_rate, GST_FORMAT_TIME, demux->segment.start, demux->segment.last_stop, demux->segment.time); GST_DEBUG_OBJECT (demux, "sending NEWSEGMENT event to close the current " "segment: %" GST_PTR_FORMAT, newseg); gst_pad_push_event (demux->srcpad, newseg); } gst_segment_set_seek (&demux->segment, rate, format, flags, cur_type, cur, stop_type, stop, &update); GST_DEBUG_OBJECT (demux, "segment: %" GST_SEGMENT_FORMAT, &demux->segment); seek_pos = gst_util_uint64_scale (demux->segment.start, demux->byterate_num, demux->byterate_denom * GST_SECOND); if (demux->packet_size > 0) { seek_pos -= seek_pos % demux->packet_size; } seek_pos += demux->data_offset; GST_DEBUG_OBJECT (demux, "seek_pos = %" G_GUINT64_FORMAT, seek_pos); /* stop flushing */ gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop ()); demux->offset = seek_pos; demux->need_newsegment = TRUE; /* notify start of new segment */ if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (demux), gst_message_new_segment_start (GST_OBJECT (demux), GST_FORMAT_TIME, demux->segment.last_stop)); } demux->segment_running = TRUE; /* restart our task since it might have been stopped when we did the flush */ gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_real_audio_demux_loop, demux); /* streaming can continue now */ GST_PAD_STREAM_UNLOCK (demux->sinkpad); return TRUE; /* ERRORS */ not_seekable: { GST_DEBUG_OBJECT (demux, "seek failed: cannot seek in streaming mode"); return FALSE; } no_bitrate: { GST_DEBUG_OBJECT (demux, "seek failed: bitrate unknown"); return FALSE; } only_time_format_supported: { GST_DEBUG_OBJECT (demux, "can only seek in TIME format"); return FALSE; } cannot_do_backwards_playback: { GST_DEBUG_OBJECT (demux, "can only seek with positive rate, not %lf", rate); return FALSE; } }
/* This function is used to perform seeks on the element in * pull mode. * * It also works when event is NULL, in which case it will just * start from the last configured segment. This technique is * used when activating the element and to perform the seek in * READY. */ static gboolean gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event) { gboolean res; gdouble rate; GstFormat format, bformat; GstSeekFlags flags; GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; gint64 cur, stop, upstream_size; gboolean flush; gboolean update; GstSegment seeksegment = { 0, }; gint64 last_stop; if (event) { GST_DEBUG_OBJECT (aiff, "doing seek with event"); gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); /* no negative rates yet */ if (rate < 0.0) goto negative_rate; if (format != aiff->segment.format) { GST_INFO_OBJECT (aiff, "converting seek-event from %s to %s", gst_format_get_name (format), gst_format_get_name (aiff->segment.format)); res = TRUE; if (cur_type != GST_SEEK_TYPE_NONE) res = gst_pad_query_convert (aiff->srcpad, format, cur, &aiff->segment.format, &cur); if (res && stop_type != GST_SEEK_TYPE_NONE) res = gst_pad_query_convert (aiff->srcpad, format, stop, &aiff->segment.format, &stop); if (!res) goto no_format; format = aiff->segment.format; } } else { GST_DEBUG_OBJECT (aiff, "doing seek without event"); flags = 0; rate = 1.0; cur_type = GST_SEEK_TYPE_SET; stop_type = GST_SEEK_TYPE_SET; } /* get flush flag */ flush = flags & GST_SEEK_FLAG_FLUSH; /* now we need to make sure the streaming thread is stopped. We do this by * either sending a FLUSH_START event downstream which will cause the * streaming thread to stop with a WRONG_STATE. * For a non-flushing seek we simply pause the task, which will happen as soon * as it completes one iteration (and thus might block when the sink is * blocking in preroll). */ if (flush) { GST_DEBUG_OBJECT (aiff, "sending flush start"); gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ()); } else { gst_pad_pause_task (aiff->sinkpad); } /* we should now be able to grab the streaming thread because we stopped it * with the above flush/pause code */ GST_PAD_STREAM_LOCK (aiff->sinkpad); /* save current position */ last_stop = aiff->segment.last_stop; GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, last_stop); /* copy segment, we need this because we still need the old * segment when we close the current segment. */ memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment)); /* configure the seek parameters in the seeksegment. We will then have the * right values in the segment to perform the seek */ if (event) { GST_DEBUG_OBJECT (aiff, "configuring seek"); gst_segment_set_seek (&seeksegment, rate, format, flags, cur_type, cur, stop_type, stop, &update); } /* figure out the last position we need to play. If it's configured (stop != * -1), use that, else we play until the total duration of the file */ if ((stop = seeksegment.stop) == -1) stop = seeksegment.duration; GST_DEBUG_OBJECT (aiff, "cur_type =%d", cur_type); if ((cur_type != GST_SEEK_TYPE_NONE)) { /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and * we can just copy the last_stop. If not, we use the bps to convert TIME to * bytes. */ if (aiff->bps > 0) aiff->offset = uint64_ceiling_scale (seeksegment.last_stop, (guint64) aiff->bps, GST_SECOND); else aiff->offset = seeksegment.last_stop; GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset); aiff->offset -= (aiff->offset % aiff->bytes_per_sample); GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset); aiff->offset += aiff->datastart; GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset); } else { GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT, aiff->offset); } if (stop_type != GST_SEEK_TYPE_NONE) { if (aiff->bps > 0) aiff->end_offset = uint64_ceiling_scale (stop, (guint64) aiff->bps, GST_SECOND); else aiff->end_offset = stop; GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset); aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample); GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset); aiff->end_offset += aiff->datastart; GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset); } else { GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT, aiff->end_offset); } /* make sure filesize is not exceeded due to rounding errors or so, * same precaution as in _stream_headers */ bformat = GST_FORMAT_BYTES; if (gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size)) aiff->end_offset = MIN (aiff->end_offset, upstream_size); /* this is the range of bytes we will use for playback */ aiff->offset = MIN (aiff->offset, aiff->end_offset); aiff->dataleft = aiff->end_offset - aiff->offset; GST_DEBUG_OBJECT (aiff, "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, aiff->offset, aiff->end_offset, GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop)); /* prepare for streaming again */ if (flush) { /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ GST_DEBUG_OBJECT (aiff, "sending flush stop"); gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop ()); } else if (aiff->segment_running) { /* we are running the current segment and doing a non-flushing seek, * close the segment first based on the previous last_stop. */ GST_DEBUG_OBJECT (aiff, "closing running segment %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, aiff->segment.accum, aiff->segment.last_stop); /* queue the segment for sending in the stream thread */ if (aiff->close_segment) gst_event_unref (aiff->close_segment); aiff->close_segment = gst_event_new_new_segment (TRUE, aiff->segment.rate, aiff->segment.format, aiff->segment.accum, aiff->segment.last_stop, aiff->segment.accum); /* keep track of our last_stop */ seeksegment.accum = aiff->segment.last_stop; } /* now we did the seek and can activate the new segment values */ memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment)); /* if we're doing a segment seek, post a SEGMENT_START message */ if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT_CAST (aiff), gst_message_new_segment_start (GST_OBJECT_CAST (aiff), aiff->segment.format, aiff->segment.last_stop)); } /* now create the newsegment */ GST_DEBUG_OBJECT (aiff, "Creating newsegment from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, aiff->segment.last_stop, stop); /* store the newsegment event so it can be sent from the streaming thread. */ if (aiff->start_segment) gst_event_unref (aiff->start_segment); aiff->start_segment = gst_event_new_new_segment (FALSE, aiff->segment.rate, aiff->segment.format, aiff->segment.last_stop, stop, aiff->segment.last_stop); /* mark discont if we are going to stream from another position. */ if (last_stop != aiff->segment.last_stop) { GST_DEBUG_OBJECT (aiff, "mark DISCONT, we did a seek to another position"); aiff->discont = TRUE; } /* and start the streaming task again */ aiff->segment_running = TRUE; if (!aiff->streaming) { gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop, aiff->sinkpad); } GST_PAD_STREAM_UNLOCK (aiff->sinkpad); return TRUE; /* ERRORS */ negative_rate: { GST_DEBUG_OBJECT (aiff, "negative playback rates are not supported yet."); return FALSE; } no_format: { GST_DEBUG_OBJECT (aiff, "unsupported format given, seek aborted."); return FALSE; } }
static gboolean gst_raw_parse_handle_seek_pull (GstRawParse * rp, GstEvent * event) { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gint64 last_stop; gboolean ret = FALSE; gboolean flush; GstSegment seeksegment; if (event) { gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); /* convert input offsets to time */ ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start); ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop); if (!ret) goto convert_failed; GST_DEBUG_OBJECT (rp, "converted start - stop to time"); format = GST_FORMAT_TIME; gst_event_unref (event); } else { format = GST_FORMAT_TIME; flags = 0; } flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0); /* start flushing up and downstream so that the loop function pauses and we * can acquire the STREAM_LOCK. */ if (flush) { GST_LOG_OBJECT (rp, "flushing"); gst_pad_push_event (rp->sinkpad, gst_event_new_flush_start ()); gst_pad_push_event (rp->srcpad, gst_event_new_flush_start ()); } else { GST_LOG_OBJECT (rp, "pause task"); gst_pad_pause_task (rp->sinkpad); } GST_PAD_STREAM_LOCK (rp->sinkpad); memcpy (&seeksegment, &rp->segment, sizeof (GstSegment)); if (event) { /* configure the seek values */ gst_segment_do_seek (&seeksegment, rate, format, flags, start_type, start, stop_type, stop, NULL); } /* get the desired position */ last_stop = seeksegment.position; GST_LOG_OBJECT (rp, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (last_stop)); /* convert the desired position to bytes */ ret = gst_raw_parse_convert (rp, format, last_stop, GST_FORMAT_BYTES, &last_stop); /* prepare for streaming */ if (flush) { GST_LOG_OBJECT (rp, "stop flush"); gst_pad_push_event (rp->sinkpad, gst_event_new_flush_stop (TRUE)); gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop (TRUE)); } if (ret) { /* seek done */ /* Seek on a frame boundary */ last_stop -= last_stop % rp->framesize; rp->offset = last_stop; rp->n_frames = last_stop / rp->framesize; GST_LOG_OBJECT (rp, "seeking to bytes %" G_GINT64_FORMAT, last_stop); memcpy (&rp->segment, &seeksegment, sizeof (GstSegment)); if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT_CAST (rp), gst_message_new_segment_start (GST_OBJECT_CAST (rp), rp->segment.format, rp->segment.position)); } /* for deriving a stop position for the playback segment from the seek * segment, we must take the duration when the stop is not set */ if ((stop = rp->segment.stop) == -1) stop = rp->segment.duration; GST_DEBUG_OBJECT (rp, "preparing newsegment from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, rp->segment.start, stop); /* now replace the old segment so that we send it in the stream thread the * next time it is scheduled. */ if (rp->start_segment) gst_event_unref (rp->start_segment); rp->start_segment = gst_event_new_segment (&rp->segment); } rp->discont = TRUE; GST_LOG_OBJECT (rp, "start streaming"); gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp, NULL); GST_PAD_STREAM_UNLOCK (rp->sinkpad); return ret; /* ERRORS */ convert_failed: { GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions"); return FALSE; } }