static void gst_navseek_segseek (GstNavSeek * navseek) { GstEvent *event; GstPad *peer_pad; if ((navseek->segment_start == GST_CLOCK_TIME_NONE) || (navseek->segment_end == GST_CLOCK_TIME_NONE) || (!GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad))) { return; } if (navseek->loop) { event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT, GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET, navseek->segment_end); } else { event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET, navseek->segment_end); } peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad); gst_pad_send_event (peer_pad, event); gst_object_unref (peer_pad); }
static gboolean play_do_seek (GstElement * pipeline, gint64 pos, gdouble rate, GstPlayTrickMode mode) { GstSeekFlags seek_flags; GstQuery *query; GstEvent *seek; gboolean seekable = FALSE; query = gst_query_new_seeking (GST_FORMAT_TIME); if (!gst_element_query (pipeline, query)) { gst_query_unref (query); return FALSE; } gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); gst_query_unref (query); if (!seekable) return FALSE; seek_flags = GST_SEEK_FLAG_FLUSH; switch (mode) { case GST_PLAY_TRICK_MODE_DEFAULT: seek_flags |= GST_SEEK_FLAG_TRICKMODE; break; case GST_PLAY_TRICK_MODE_DEFAULT_NO_AUDIO: seek_flags |= GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_NO_AUDIO; break; case GST_PLAY_TRICK_MODE_KEY_UNITS: seek_flags |= GST_SEEK_FLAG_TRICKMODE_KEY_UNITS; break; case GST_PLAY_TRICK_MODE_KEY_UNITS_NO_AUDIO: seek_flags |= GST_SEEK_FLAG_TRICKMODE_KEY_UNITS | GST_SEEK_FLAG_TRICKMODE_NO_AUDIO; break; case GST_PLAY_TRICK_MODE_NONE: default: break; } if (rate >= 0) seek = gst_event_new_seek (rate, GST_FORMAT_TIME, seek_flags | GST_SEEK_FLAG_ACCURATE, /* start */ GST_SEEK_TYPE_SET, pos, /* stop */ GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE); else seek = gst_event_new_seek (rate, GST_FORMAT_TIME, seek_flags | GST_SEEK_FLAG_ACCURATE, /* start */ GST_SEEK_TYPE_SET, 0, /* stop */ GST_SEEK_TYPE_SET, pos); if (!gst_element_send_event (pipeline, seek)) return FALSE; cur_rate = rate; trick_mode = mode; return TRUE; }
void MediaImpl::resetMovie() { // XXX: There used to be an issue that when we reached EOS (_eos() == true) we could not seek anymore. if (_seekEnabled) { qDebug() << "Seeking at position 0."; GstEvent* seek_event; if (_rate > 0) { seek_event = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0); } else { seek_event = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_END, 0); } /* Send the event */ gst_element_send_event (_appsink0, seek_event); // gst_element_seek_simple (_pipeline, GST_FORMAT_TIME, // (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0); // this->_currentFrameSample = NULL; _setMovieReady(true); } else { // Just reload movie. qDebug() << "Reloading the movie" << _seekEnabled; loadMovie(_uri); } }
void VideoImpl::_updateRate() { // Check different things. if (_pipeline == NULL) { qWarning() << "Cannot set rate: no pipeline!" << endl; return; } if (!_seekEnabled) { qWarning() << "Cannot set rate: seek not working" << endl; return; } if (!_isMovieReady()) { qWarning() << "Movie is not yet ready to play, cannot seek yet." << endl; } // Obtain the current position, needed for the seek event. gint64 position; if (!gst_element_query_position (_pipeline, GST_FORMAT_TIME, &position)) { qWarning() << "Unable to retrieve current position." << endl; return; } // Create the seek event. GstEvent *seekEvent; if (_rate > 0.0) { // Rate is positive (playing the video in normal direction) // Set new rate as a first argument. Provide position 0 so that we go to 0:00 seekEvent = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, 0); // Go to 0:00 } else { // Rate is negative // Set new rate as a first arguemnt. Provide the position we were already at. seekEvent = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, position); } // If we have not done so, obtain the sink through which we will send the seek events. if (_appsink0 == NULL) { g_object_get (_pipeline, "video-sink", &_appsink0, NULL); } // Send the event. if (!gst_element_send_event (_appsink0, seekEvent)) { qWarning() << "Cannot perform seek event" << endl; } qDebug() << "Current rate: " << _rate << "." << endl; }
static void check_correct_buffer (guint8 * src_data, guint src_size, guint8 * dst_data, guint dst_size) { GstBuffer *buffer = gst_buffer_new_allocate (NULL, src_size, 0); GstBuffer *newBuffer; GstElement *avisubtitle = setup_avisubtitle (); GstEvent *event; fail_unless (g_list_length (buffers) == 0, "Buffers list needs to be empty"); gst_buffer_fill (buffer, 0, src_data, src_size); fail_unless (gst_element_set_state (avisubtitle, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); ASSERT_BUFFER_REFCOUNT (buffer, "inbuffer", 1); event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 2 * GST_SECOND, GST_SEEK_TYPE_SET, 5 * GST_SECOND); fail_unless (gst_element_send_event (avisubtitle, event) == FALSE, "Seeking is not possible when there is no buffer yet"); fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK, "not accepted a correct buffer"); /* we gave away our reference to the buffer, don't assume anything */ buffer = NULL; /* a new buffer is created in the list */ fail_unless (g_list_length (buffers) == 1, "No new buffer in the buffers list"); event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 2 * GST_SECOND, GST_SEEK_TYPE_SET, 5 * GST_SECOND); fail_unless (gst_element_send_event (avisubtitle, event) == TRUE, "seeking should be working now"); fail_unless (g_list_length (buffers) == 2, "After seeking we need another buffer in the buffers"); newBuffer = GST_BUFFER (buffers->data); buffers = g_list_remove (buffers, newBuffer); fail_unless (g_list_length (buffers) == 1, "Buffers list needs to be empty"); fail_unless (gst_buffer_get_size (newBuffer) == dst_size, "size of the new buffer is wrong ( %d != %d)", gst_buffer_get_size (newBuffer), dst_size); fail_unless (gst_buffer_memcmp (newBuffer, 0, dst_data, dst_size) == 0, "data of the buffer is not correct"); gst_buffer_unref (newBuffer); /* free the buffer from seeking */ gst_buffer_unref (GST_BUFFER (buffers->data)); buffers = g_list_remove (buffers, buffers->data); fail_unless (gst_element_set_state (avisubtitle, GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); cleanup_avisubtitle (avisubtitle); }
static void gst_navseek_seek (GstNavSeek * navseek, gint64 offset) { gboolean ret; GstPad *peer_pad; gint64 peer_value; /* Query for the current time then attempt to set to time + offset */ peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad); ret = gst_pad_query_position (peer_pad, GST_FORMAT_TIME, &peer_value); if (ret) { GstEvent *event; peer_value += offset; if (peer_value < 0) peer_value = 0; event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, peer_value, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); gst_pad_send_event (peer_pad, event); } gst_object_unref (peer_pad); }
static void gst_navseek_change_playback_rate (GstNavSeek * navseek, gdouble rate) { gboolean ret; GstPad *peer_pad; gint64 current_position; peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad); ret = gst_pad_query_position (peer_pad, GST_FORMAT_TIME, ¤t_position); if (ret) { GstEvent *event; gint64 start; gint64 stop; if (rate > 0.0) { start = current_position; stop = -1; } else { /* negative rate: we play from stop to start */ start = 0; stop = current_position; } event = gst_event_new_seek (rate, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP, GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop); gst_pad_send_event (peer_pad, event); } gst_object_unref (peer_pad); }
gboolean eos_callback(GstPad *pad, GstObject *parent, GstEvent *event) { GstEvent *seek_event; GstElement *bkgdec; GValue v=G_VALUE_INIT; GstPad *srcpad; GstIterator *srcpads; gboolean result; g_print("Decodebin received EOS. Someone should handle that...\n"); bkgdec=gst_pad_get_parent_element(pad); if(bkgdec->numsrcpads>0) { srcpads=gst_element_iterate_src_pads(bkgdec); gst_iterator_next(srcpads,&v); srcpad=GST_PAD(g_value_get_object(&v)); seek_event=gst_event_new_seek ( 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); result=gst_pad_send_event(srcpad,seek_event); if(result==TRUE) { g_print("seek event sent OK.\n"); } else { g_print("seek sent FAILED.\n"); } g_value_reset(&v); g_value_unset(&v); gst_iterator_free(srcpads); return TRUE; } return gst_pad_event_default(pad,parent,event); }
static gboolean vorbis_dec_src_event (GstPad * pad, GstEvent * event) { gboolean res = TRUE; GstVorbisDec *dec; dec = GST_VORBIS_DEC (gst_pad_get_parent (pad)); if (G_UNLIKELY (dec == NULL)) { gst_event_unref (event); return FALSE; } switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { GstFormat format, tformat; gdouble rate; GstEvent *real_seek; GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; gint64 tcur, tstop; guint32 seqnum; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); seqnum = gst_event_get_seqnum (event); gst_event_unref (event); /* First bring the requested format to time */ tformat = GST_FORMAT_TIME; if (!(res = vorbis_dec_convert (pad, format, cur, &tformat, &tcur))) goto convert_error; if (!(res = vorbis_dec_convert (pad, format, stop, &tformat, &tstop))) goto convert_error; /* then seek with time on the peer */ real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, cur_type, tcur, stop_type, tstop); gst_event_set_seqnum (real_seek, seqnum); res = gst_pad_push_event (dec->sinkpad, real_seek); break; } default: res = gst_pad_push_event (dec->sinkpad, event); break; } done: gst_object_unref (dec); return res; /* ERRORS */ convert_error: { GST_DEBUG_OBJECT (dec, "cannot convert start/stop for seek"); goto done; } }
static gboolean gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event) { GstSeekType start_type, stop_type; GstSeekFlags flags; GstFormat format; gdouble rate; gint64 start, stop; gboolean res; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format"); return FALSE; } res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, start, GST_FORMAT_BYTES, &start); if (stop > 0) { res = gst_au_parse_src_convert (auparse, GST_FORMAT_TIME, stop, GST_FORMAT_BYTES, &stop); } GST_INFO_OBJECT (auparse, "seeking: %" G_GINT64_FORMAT " ... %" G_GINT64_FORMAT, start, stop); event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start, stop_type, stop); res = gst_pad_push_event (auparse->sinkpad, event); return res; }
static gboolean gst_sub_parse_src_event (GstPad * pad, GstEvent * event) { GstSubParse *self = GST_SUBPARSE (gst_pad_get_parent (pad)); gboolean ret = FALSE; GST_DEBUG ("Handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { GstFormat format; GstSeekType start_type, stop_type; gint64 start, stop; gdouble rate; gboolean update; gst_event_parse_seek (event, &rate, &format, &self->segment_flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) { GST_WARNING_OBJECT (self, "we only support seeking in TIME format"); gst_event_unref (event); goto beach; } /* Convert that seek to a seeking in bytes at position 0, FIXME: could use an index */ ret = gst_pad_push_event (self->sinkpad, gst_event_new_seek (rate, GST_FORMAT_BYTES, self->segment_flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0)); if (ret) { /* Apply the seek to our segment */ gst_segment_set_seek (&self->segment, rate, format, self->segment_flags, start_type, start, stop_type, stop, &update); GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT, &self->segment); self->next_offset = 0; self->need_segment = TRUE; } else { GST_WARNING_OBJECT (self, "seek to 0 bytes failed"); } gst_event_unref (event); break; } default: ret = gst_pad_event_default (pad, event); break; } beach: gst_object_unref (self); return ret; }
void MediaImpl::_updateRate() { if (_pipeline == NULL) { qDebug() << "Cannot set rate: no pipeline!" << endl; return; } if (!_seekEnabled) { qDebug() << "Cannot set rate: seek not working" << endl; return; } if (!_isMovieReady()) { qDebug() << "Movie is not yet ready to play, cannot seek yet." << endl; } gint64 position; GstEvent *seekEvent; /* Obtain the current position, needed for the seek event */ if (!gst_element_query_position (_pipeline, GST_FORMAT_TIME, &position)) { g_printerr ("Unable to retrieve current position.\n"); return; } /* Create the seek event */ if (_rate > 0) { seekEvent = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, 0); } else { seekEvent = gst_event_new_seek (_rate, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, position); } if (_appsink0 == NULL) { /* If we have not done so, obtain the sink through which we will send the seek events */ g_object_get (_pipeline, "video-sink", &_appsink0, NULL); } /* Send the event */ gst_element_send_event (_appsink0, seekEvent); g_print ("Current rate: %g\n", _rate); }
static gboolean seek_mode_testing (InsanityTest * test) { gboolean res; GstEvent *event; GstSeekFlags flags = GST_SEEK_FLAG_FLUSH; GstSeekType stop_type = GST_SEEK_TYPE_NONE; /* Reset global seek props */ glob_seek_first_buf_ts = GST_CLOCK_TIME_NONE; glob_seek_stop_ts = GST_CLOCK_TIME_NONE; glob_seek_segment_seektime = 0; /* Set seeking arguments */ switch (glob_in_progress) { case TEST_BACKWARD_PLAYBACK: glob_seek_rate = -1; glob_seek_stop_ts = glob_duration; stop_type = GST_SEEK_TYPE_SET; break; case TEST_FAST_FORWARD: glob_seek_rate = 2; glob_seek_stop_ts = glob_duration / 2; break; case TEST_FAST_BACKWARD: glob_seek_rate = -2; glob_seek_stop_ts = glob_duration; stop_type = GST_SEEK_TYPE_SET; break; default: return FALSE; } glob_seek_got_segment = FALSE; event = gst_event_new_seek (glob_seek_rate, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, glob_seek_segment_seektime, stop_type, glob_seek_stop_ts); /* We didn't find any event/message with the seqnum we previously set */ if (glob_seqnum != 0 && glob_seqnum_found == FALSE) glob_wrong_seqnum = TRUE; glob_seqnum_found = FALSE; glob_seqnum = gst_util_seqnum_next (); gst_event_set_seqnum (event, glob_seqnum); res = gst_element_send_event (glob_pipeline, event); global_last_seek = g_get_monotonic_time (); if (!res) { validate_current_test (test, FALSE, "Could not send seek event"); glob_seek_rate = 0; glob_seqnum = 0; /* ... Next test */ next_test (test); } return FALSE; }
static void run_seek_position_test (gdouble rate, GstSeekType start_type, guint64 seek_start, GstSeekType stop_type, guint64 seek_stop, GstSeekFlags flags, guint64 segment_start, guint64 segment_stop, gint segments) { const guint segment_size = 60 * TS_PACKET_LEN; const gchar *manifest = "#EXTM3U \n" "#EXT-X-TARGETDURATION:1\n" "#EXTINF:1,Test\n" "001.ts\n" "#EXTINF:1,Test\n" "002.ts\n" "#EXTINF:1,Test\n" "003.ts\n" "#EXTINF:1,Test\n" "004.ts\n" "#EXT-X-ENDLIST\n"; GstHlsDemuxTestInputData inputTestData[] = { {"http://unit.test/media.m3u8", (guint8 *) manifest, 0}, {"http://unit.test/001.ts", NULL, segment_size}, {"http://unit.test/002.ts", NULL, segment_size}, {"http://unit.test/003.ts", NULL, segment_size}, {"http://unit.test/004.ts", NULL, segment_size}, {NULL, NULL, 0}, }; GstAdaptiveDemuxTestExpectedOutput outputTestData[] = { {"src_0", segment_size * segments, NULL}, {NULL, 0, NULL} }; GstTestHTTPSrcCallbacks http_src_callbacks = { 0 }; GstAdaptiveDemuxTestCase *engineTestData; GstHlsDemuxTestCase hlsTestCase = { 0 }; GByteArray *mpeg_ts = NULL; engineTestData = gst_adaptive_demux_test_case_new (); mpeg_ts = setup_test_variables (inputTestData, outputTestData, &hlsTestCase, engineTestData, segment_size); http_src_callbacks.src_start = gst_hlsdemux_test_src_start; http_src_callbacks.src_create = gst_hlsdemux_test_src_create; /* FIXME hack to avoid having a 0 seqnum */ gst_util_seqnum_next (); /* Seek to 1.5s, expect it to start from 1s */ engineTestData->threshold_for_seek = 20 * TS_PACKET_LEN; engineTestData->seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type, seek_start, stop_type, seek_stop); gst_segment_init (&outputTestData[0].post_seek_segment, GST_FORMAT_TIME); outputTestData[0].post_seek_segment.rate = rate; outputTestData[0].post_seek_segment.start = segment_start; outputTestData[0].post_seek_segment.time = segment_start; outputTestData[0].post_seek_segment.stop = segment_stop; outputTestData[0].segment_verification_needed = TRUE; gst_test_http_src_install_callbacks (&http_src_callbacks, &hlsTestCase); gst_adaptive_demux_test_seek (DEMUX_ELEMENT_NAME, inputTestData[0].uri, engineTestData); TESTCASE_UNREF_BOILERPLATE; }
static gboolean gst_y4m_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res; GstY4mDec *y4mdec; y4mdec = GST_Y4M_DEC (parent); GST_DEBUG_OBJECT (y4mdec, "event"); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gint64 framenum; guint64 byte; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) { res = FALSE; break; } framenum = gst_y4m_dec_timestamp_to_frames (y4mdec, start); GST_DEBUG ("seeking to frame %" G_GINT64_FORMAT, framenum); if (framenum == -1) { res = FALSE; break; } byte = gst_y4m_dec_frames_to_bytes (y4mdec, framenum); GST_DEBUG ("offset %" G_GUINT64_FORMAT, (guint64) byte); if (byte == -1) { res = FALSE; break; } gst_event_unref (event); event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, byte, stop_type, -1); res = gst_pad_push_event (y4mdec->sinkpad, event); } break; default: res = gst_pad_event_default (pad, parent, event); break; } return res; }
static void update_playback_speed() { gboolean error; gint64 pos = gstreamer_get_position(&error); if (error) return; GstElement *video_sink = get_video_sink(); if (!video_sink) return; GstEvent *seek_event; if (playback_rate > 0) seek_event = gst_event_new_seek(playback_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_NONE, 0); else seek_event = gst_event_new_seek (playback_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, pos); gst_element_send_event (video_sink, seek_event); }
static GstFlowReturn progress_buffer_getrange(GstPad *pad, GstObject *parent, guint64 start_position, guint size, GstBuffer **buffer) { #if ENABLE_PULL_MODE ProgressBuffer *element = PROGRESS_BUFFER(parent); GstFlowReturn result = GST_FLOW_OK; guint64 end_position = start_position + size; gboolean needs_seeking = FALSE; g_mutex_lock(&element->lock); // Use one lock for push and pull modes if (element->sink_segment.stop < (gint64)end_position) result = GST_FLOW_EOS; else if (element->sink_segment.start <= (gint64)start_position && element->sink_segment.position >= (gint64)end_position) result = cache_read_buffer_from_position(element->cache, start_position, size, buffer); else { #if ENABLE_SOURCE_SEEKING needs_seeking = element->sink_segment.start > (gint64)start_position; if (needs_seeking) { element->range_start = start_position; reset_eos(element, TRUE); } #endif if (element->sink_segment.position < (gint64)end_position) { element->range_stop = end_position + (gint64)(element->bandwidth * element->prebuffer_time); if (element->sink_segment.stop < element->range_stop) element->range_stop = element->sink_segment.stop; #if ENABLE_SOURCE_SEEKING needs_seeking = element->bandwidth > 0 && end_position - element->sink_segment.position > element->bandwidth * element->wait_tolerance; #endif } send_underrun_message(element); result = GST_FLOW_FLUSHING; } g_mutex_unlock(&element->lock); if (needs_seeking) gst_pad_push_event(element->sinkpad, gst_event_new_seek(element->sink_segment.rate, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, start_position, GST_SEEK_TYPE_NONE, 0)); return result; #else ProgressBuffer *element = PROGRESS_BUFFER(GST_PAD_PARENT(pad)); return gst_pad_pull_range(element->sinkpad, parent, start_position, size, buffer); #endif }
static gboolean gst_raw_parse_handle_seek_push (GstRawParse * rp, GstEvent * event) { GstFormat format; gdouble rate; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gboolean ret = FALSE; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); /* can't seek backwards yet */ if (rate <= 0.0) goto wrong_rate; /* First try if upstream handles the seek */ ret = gst_pad_push_event (rp->sinkpad, event); if (ret) return ret; /* Otherwise convert to bytes and push upstream */ if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) { ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_BYTES, &start); ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_BYTES, &stop); if (ret) { /* Seek on a frame boundary */ start -= start % rp->framesize; if (stop != -1) stop += rp->framesize - stop % rp->framesize; event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start, stop_type, stop); ret = gst_pad_push_event (rp->sinkpad, event); } else { GST_DEBUG_OBJECT (rp, "Seek failed: couldn't convert to byte positions"); } } else { GST_DEBUG_OBJECT (rp, "seeking is only supported in TIME or DEFAULT format"); } return ret; /* ERRORS */ wrong_rate: { GST_DEBUG_OBJECT (rp, "Seek failed: negative rates not supported yet"); return FALSE; } }
static gboolean wait_and_do_seek (gpointer data) { InsanityTest *test = data; GstEvent *event; gboolean res; if (GST_CLOCK_TIME_IS_VALID (glob_wait_time)) { GstClockTime cur = hls_test_get_position (test); if (glob_first_wait == 0) glob_first_wait = g_get_monotonic_time (); if (cur < glob_wait_time) { guint64 diff = g_get_monotonic_time () - glob_first_wait; if (diff > glob_playback_time * G_USEC_PER_SEC + PLAY_TIMEOUT) glob_play_in_time = FALSE; else return TRUE; } } glob_first_wait = 0; LOG ("Seeking at %i\n", seek_targets[glob_seek_nb].perc); /* If duration did not become known yet, we cannot test */ if (!GST_CLOCK_TIME_IS_VALID (glob_duration)) { insanity_test_validate_checklist_item (test, "duration-known", FALSE, NULL); insanity_test_done (test); return FALSE; } glob_target = gst_util_uint64_scale (glob_duration, seek_targets[glob_seek_nb].perc, 100); event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, glob_target, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); glob_validate_on_playing = "seek"; res = gst_element_send_event (glob_pipeline, event); if (!res) { glob_validate_on_playing = NULL; insanity_test_validate_checklist_item (test, "seek", FALSE, "Failed to send seek event"); return FALSE; } seek_targets[glob_seek_nb].seeked = TRUE; gst_element_get_state (glob_pipeline, NULL, NULL, SEEK_TIMEOUT); insanity_test_validate_checklist_item (test, "seek", TRUE, NULL); return FALSE; }
static void pipeline_seek (APP_STATE_T * state, gint64 position) { if (state->pipeline) { GstEvent *event; event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE); if (!gst_element_send_event (state->vsink, event)) { g_print ("seek failed\n"); } } }
void MediaPlayer::seekTo(qint64 pos) { // Seek with m_tempoRate is also used to change the tempo (that's actually the only way in GStreamer) GstEvent * seek_event = gst_event_new_seek( m_tempoRate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), GST_SEEK_TYPE_SET, pos * GST_MSECOND, GST_SEEK_TYPE_NONE, 0 ); gst_element_send_event( m_gst_pipeline, seek_event ); }
/* * PsychGSSetMovieTimeIndex() -- Set current playback time of movie, perform active seek if needed. */ double PsychGSSetMovieTimeIndex(int moviehandle, double timeindex, psych_bool indexIsFrames) { GstElement *theMovie; double oldtime; long targetIndex; GstEvent *event; if (moviehandle < 0 || moviehandle >= PSYCH_MAX_MOVIES) { PsychErrorExitMsg(PsychError_user, "Invalid moviehandle provided!"); } // Fetch references to objects we need: theMovie = movieRecordBANK[moviehandle].theMovie; if (theMovie == NULL) { PsychErrorExitMsg(PsychError_user, "Invalid moviehandle provided. No movie associated with this handle !!!"); } // Retrieve current timeindex: oldtime = PsychGSGetMovieTimeIndex(moviehandle); // TODO NOTE: We could use GST_SEEK_FLAG_SKIP to allow framedropping on fast forward/reverse playback... // Index based or target time based seeking? if (indexIsFrames) { // Index based seeking: // TODO FIXME: This doesn't work (well) at all! Something's wrong here... // Seek to given targetIndex: targetIndex = (long) (timeindex + 0.5); // Simple seek, frame buffer (index) oriented, with pipeline flush and accurate seek, // i.e., not locked to keyframes, but frame-accurate: GST_FORMAT_DEFAULT? // gst_element_seek_simple(theMovie, GST_FORMAT_BUFFERS, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, targetIndex); event = gst_event_new_seek(1.0, GST_FORMAT_BUFFERS, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, targetIndex, GST_SEEK_TYPE_END, 0); gst_element_send_event(theMovie, event); } else { // Time based seeking: // Set new timeindex as time in seconds: // Simple seek, time-oriented, with pipeline flush and accurate seek, // i.e., not locked to keyframes, but frame-accurate: gst_element_seek_simple(theMovie, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, (gint64) (timeindex * (double) 1e9)); } // Block until seek completed, failed or timeout of 30 seconds reached: gst_element_get_state(theMovie, NULL, NULL, (GstClockTime) (30 * 1e9)); // Return old time value of previous position: return(oldtime); }
static gboolean speex_dec_src_event (GstPad * pad, GstEvent * event) { gboolean res = FALSE; GstSpeexDec *dec = GST_SPEEX_DEC (gst_pad_get_parent (pad)); GST_LOG_OBJECT (dec, "handling %s event", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK:{ GstFormat format, tformat; gdouble rate; GstEvent *real_seek; GstSeekFlags flags; GstSeekType cur_type, stop_type; gint64 cur, stop; gint64 tcur, tstop; gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); /* we have to ask our peer to seek to time here as we know * nothing about how to generate a granulepos from the src * formats or anything. * * First bring the requested format to time */ tformat = GST_FORMAT_TIME; if (!(res = speex_dec_convert (pad, format, cur, &tformat, &tcur))) break; if (!(res = speex_dec_convert (pad, format, stop, &tformat, &tstop))) break; /* then seek with time on the peer */ real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, cur_type, tcur, stop_type, tstop); GST_LOG_OBJECT (dec, "seek to %" GST_TIME_FORMAT, GST_TIME_ARGS (tcur)); res = gst_pad_push_event (dec->sinkpad, real_seek); gst_event_unref (event); break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (dec); return res; }
static gboolean speed_src_event (GstPad * pad, GstEvent * event) { GstSpeed *filter; gboolean ret = FALSE; filter = GST_SPEED (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK:{ gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; 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 (filter, "only support seeks in TIME format"); break; } if (start_type != GST_SEEK_TYPE_NONE && start != -1) { start *= filter->speed; } if (stop_type != GST_SEEK_TYPE_NONE && stop != -1) { stop *= filter->speed; } event = gst_event_new_seek (rate, format, flags, start_type, start, stop_type, stop); GST_LOG ("sending seek event: %" GST_PTR_FORMAT, event->structure); ret = gst_pad_send_event (GST_PAD_PEER (filter->sinkpad), event); break; } default: ret = gst_pad_event_default (pad, event); break; } gst_object_unref (filter); return ret; }
static VALUE seek_initialize(VALUE self, VALUE rate, VALUE format, VALUE flags, VALUE start_type, VALUE start, VALUE stop_type, VALUE stop) { GstEvent *event; event = gst_event_new_seek(NUM2DBL(rate), RVAL2GST_FORMAT(format), RVAL2GFLAGS(flags, GST_TYPE_SEEK_FLAGS), RVAL2GENUM(start_type, GST_TYPE_SEEK_TYPE), NUM2ULL(start), RVAL2GENUM(stop_type, GST_TYPE_SEEK_TYPE), NUM2ULL(stop)); G_INITIALIZE(self, event); return Qnil; }
static gboolean gst_uri_downloader_set_range (GstUriDownloader * downloader, gint64 range_start, gint64 range_end) { g_return_val_if_fail (range_start >= 0, FALSE); g_return_val_if_fail (range_end >= -1, FALSE); if (range_start || (range_end >= 0)) { GstEvent *seek; seek = gst_event_new_seek (1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, range_start, GST_SEEK_TYPE_SET, range_end); return gst_element_send_event (downloader->priv->urisrc, seek); } return TRUE; }
static void speed_cb (GtkWidget * widget) { GstEvent *s_event; gboolean res; GST_DEBUG ("speed change"); cur_speed = gtk_range_get_value (GTK_RANGE (widget)); if (cur_speed == 0.0) return; s_event = gst_event_new_seek (cur_speed, GST_FORMAT_TIME, 0, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1); res = gst_element_send_event (pipeline, s_event); if (!res) g_print ("speed change failed\n"); }
static void loop_segment_done (GstBus * bus, GstMessage * message, GstElement * bin) { GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT, GST_MESSAGE_SRC (message), message); if (looped) { g_main_loop_quit (main_loop); } else { GstEvent *seek_event; gboolean res; seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_SEGMENT, GST_SEEK_TYPE_SET, (GstClockTime) 0, GST_SEEK_TYPE_SET, (GstClockTime) 1 * GST_SECOND); res = gst_element_send_event (bin, seek_event); fail_unless (res == TRUE, NULL); looped = TRUE; } }
static gboolean gst_vcd_parse_src_event (GstPad * pad, GstEvent * event) { GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad)); gboolean res; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK:{ GstSeekType start_type, stop_type; GstSeekFlags flags; GstFormat format; gdouble rate; gint64 start, stop; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format == GST_FORMAT_BYTES) { gst_event_unref (event); if (start_type != GST_SEEK_TYPE_NONE) start = gst_vcd_parse_get_in_offset (start); if (stop_type != GST_SEEK_TYPE_NONE) stop = gst_vcd_parse_get_in_offset (stop); event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, start, stop_type, stop); } else { GST_WARNING_OBJECT (vcd, "seek event in non-byte format"); } res = gst_pad_event_default (pad, event); break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (vcd); return res; }
gboolean command_seek (const char* line) { gboolean result = FALSE; gint direction = 0; gint64 useconds; gint64 position = 0LL; GstEvent* seek_event; g_return_val_if_fail (line != NULL, FALSE); if (g_str_has_prefix (line, "+")) { direction = 1; } else { if (g_str_has_prefix (line, "-")) { direction = -1; } else { direction = 0; } } if (direction != 0) { line = g_utf8_next_char (line); } useconds = (gint64) (g_ascii_strtod (line, NULL) * GST_SECOND); if (direction != 0) { GstFormat time_format; time_format = GST_FORMAT_TIME; if (gst_element_query_position ((GstElement*) pipeline, &time_format, &position)) { position = position + (useconds * direction); } else { g_printerr ("Could not get the current position\n"); result = FALSE; return result; } } else { position = useconds; } seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, (gint64) 0); result = gst_element_send_event ((GstElement*) pipeline, _gst_event_ref0 (seek_event)); _gst_event_unref0 (seek_event); return result; }