static void bus_message_cb (GstBus * bus, GstMessage * message, GMainLoop * mainloop) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: g_print ("ERROR\n"); g_main_loop_quit (mainloop); break; case GST_MESSAGE_EOS: if (repeat > 0) { g_print ("Looping again\n"); /* No need to change state before */ gst_element_seek_simple (GST_ELEMENT (pipeline), GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); repeat -= 1; } else { g_print ("Done\n"); g_main_loop_quit (mainloop); } break; default: break; } }
P_INVOKE void bp_set_subtitle_uri (BansheePlayer *player, const gchar *uri) { g_return_if_fail (IS_BANSHEE_PLAYER (player)); gint64 pos = -1; GstState state; gboolean paused = FALSE; // Gstreamer playbin do not support to set suburi during playback // so have to stop/play and seek gst_element_get_state (player->playbin, &state, NULL, 0); paused = (state == GST_STATE_PAUSED); if (state >= GST_STATE_PAUSED) { gst_element_query_position (player->playbin, GST_FORMAT_BYTES, &pos); gst_element_set_state (player->playbin, GST_STATE_READY); // Force to wait asynch operation gst_element_get_state (player->playbin, &state, NULL, -1); } g_object_set (G_OBJECT (player->playbin), "suburi", uri, NULL); gst_element_set_state (player->playbin, paused ? GST_STATE_PAUSED : GST_STATE_PLAYING); // Force to wait asynch operation gst_element_get_state (player->playbin, &state, NULL, -1); if (pos != -1) { gst_element_seek_simple (player->playbin, GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, pos); } }
static void position_value_changed_cb (GtkAdjustment *adjustment, gpointer user_data) { GthMediaViewerPage *self = user_data; gint64 current_value; char *s; if (self->priv->playbin == NULL) return; current_value = (gint64) (gtk_adjustment_get_value (adjustment) / 100.0 * self->priv->duration); if (! gst_element_seek_simple (self->priv->playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, current_value)) { g_warning ("seek failed"); } s = _g_format_duration_for_display (GST_TIME_AS_MSECONDS (current_value)); gtk_label_set_text (GTK_LABEL (GET_WIDGET ("label_position")), s); g_free (s); }
static void handle_player_pause_message (SnraClient * client, GstStructure * s) { GstClockTime old_position = client->position; gint64 tmp; if (!snra_json_structure_get_int64 (s, "position", &tmp)) return; /* Invalid message */ client->position = (GstClockTime) (tmp); client->paused = TRUE; if (client->enabled && client->player) { g_print ("Pausing at position %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (client->position)); gst_element_set_state (GST_ELEMENT (client->player), GST_STATE_PAUSED); if (!gst_element_seek_simple (client->player, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, client->position)) { g_warning ("Pausing seek failed"); client->position = old_position; } } g_object_notify (G_OBJECT (client), "paused"); g_object_notify (G_OBJECT (client), "position"); }
static gboolean set_new_position(gpointer pipeline) { gint64 seek_pos = 0; GRand* rand_generator = g_rand_new(); g_debug("Starting seek :-)"); if(counter >= SEEK_COUNT){ g_rand_free (rand_generator); return FALSE; } counter++; if(volta_inicio){ seek_pos = 0; volta_inicio = FALSE; }else{ seek_pos = GST_SECOND * g_rand_int_range(rand_generator, 1, 30); volta_inicio = TRUE; } if(!gst_element_seek_simple(pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, seek_pos)){ g_debug("Error seeking!"); g_rand_free (rand_generator); return TRUE; } g_debug("Seeked with success :-), position set is[%lld]", seek_pos / GST_SECOND); g_rand_free (rand_generator); return TRUE; }
nsRefPtr<MediaDecoderReader::SeekPromise> GStreamerReader::Seek(int64_t aTarget, int64_t aEndTime) { MOZ_ASSERT(OnTaskQueue()); gint64 seekPos = aTarget * GST_USECOND; LOG(LogLevel::Debug, "%p About to seek to %" GST_TIME_FORMAT, mDecoder, GST_TIME_ARGS(seekPos)); int flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; if (!gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME, static_cast<GstSeekFlags>(flags), seekPos)) { LOG(LogLevel::Error, "seek failed"); return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } LOG(LogLevel::Debug, "seek succeeded"); GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR)); gst_message_unref(message); LOG(LogLevel::Debug, "seek completed"); return SeekPromise::CreateAndResolve(aTarget, __func__); }
static void seek_to (AppInfo * info, gdouble percent) { GstSeekFlags seek_flags; gint64 seek_pos, dur = -1; if (!gst_element_query_duration (info->pipe, GST_FORMAT_TIME, &dur) || dur <= 0) { g_printerr ("Could not query duration\n"); return; } seek_pos = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (dur) * percent); g_print ("Seeking to %" GST_TIME_FORMAT ", accurate: %d\n", GST_TIME_ARGS (seek_pos), info->accurate); seek_flags = GST_SEEK_FLAG_FLUSH; if (info->accurate) seek_flags |= GST_SEEK_FLAG_ACCURATE; else seek_flags |= GST_SEEK_FLAG_KEY_UNIT; if (!gst_element_seek_simple (info->pipe, GST_FORMAT_TIME, seek_flags, seek_pos)) { g_printerr ("Seek failed.\n"); return; } }
static void command_consume(struct command_ctx* ctx) { char* argv[2]; char* input = ctx->command_line; int i = 0; while((argv[i] = strsep(&input, " ")) != NULL) { i += 1; if(i > 1) { break; } } if(strcmp(argv[0], "quality") == 0) { int quality = atoi(argv[1]); ctx->set_quality(ctx, quality); } else if(strcmp(argv[0], "seek") == 0) { int seconds = atoi(argv[1]); GstElement* decode = gst_bin_get_by_name(GST_BIN(ctx->pipeline), "decode"); assert(decode); if(!gst_element_seek_simple(decode, GST_FORMAT_TIME, 0, seconds * GST_SECOND)) { fprintf(stderr, "Seek failed\n"); } } ctx->command_line[0] = '\0'; }
bool VideoImpl::seekTo(guint64 positionNanoSeconds) { if (!_appsink0 || !_seekEnabled) { return false; } else { lockMutex(); // Free the current sample and reset. _freeCurrentSample(); _bitsChanged = false; // Seek to position. bool result = gst_element_seek_simple( _appsink0, GST_FORMAT_TIME, GstSeekFlags( GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE ), positionNanoSeconds); unlockMutex(); return result; } }
void GStreamerReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); gint64 seekPos = aTarget * GST_USECOND; LOG(PR_LOG_DEBUG, "%p About to seek to %" GST_TIME_FORMAT, mDecoder, GST_TIME_ARGS(seekPos)); int flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; if (!gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME, static_cast<GstSeekFlags>(flags), seekPos)) { LOG(PR_LOG_ERROR, "seek failed"); GetCallback()->OnSeekCompleted(NS_ERROR_FAILURE); return; } LOG(PR_LOG_DEBUG, "seek succeeded"); GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR)); gst_message_unref(message); LOG(PR_LOG_DEBUG, "seek completed"); GetCallback()->OnSeekCompleted(NS_OK); }
static void handle_player_seek_message (SnraClient * client, GstStructure * s) { GstClockTime old_position = client->position; gint64 tmp; if (!snra_json_structure_get_int64 (s, "base-time", &tmp)) return; /* Invalid message */ client->base_time = (GstClockTime) tmp; if (!snra_json_structure_get_int64 (s, "position", &tmp)) return; /* Invalid message */ client->position = (GstClockTime) (tmp); if (client->enabled && client->player) { g_print ("Seeking at position %" GST_TIME_FORMAT " (base_time %" GST_TIME_FORMAT ")\n", GST_TIME_ARGS (client->position), GST_TIME_ARGS (client->base_time)); if (!gst_element_seek_simple (client->player, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, client->position)) { g_warning ("Seeking failed, client may run faster or block."); client->position = old_position; } gst_element_set_base_time (client->player, client->base_time + client->position); } g_object_notify (G_OBJECT (client), "base-time"); g_object_notify (G_OBJECT (client), "position"); }
/* Perform seek, if we are not too close to the previous seek. Otherwise, schedule the seek for * some time in the future. */ static void execute_seek (gint64 desired_position, CustomData *data) { gint64 diff; if (desired_position == GST_CLOCK_TIME_NONE) return; diff = gst_util_get_timestamp () - data->last_seek_time; if (GST_CLOCK_TIME_IS_VALID (data->last_seek_time) && diff < SEEK_MIN_DELAY) { /* The previous seek was too close, delay this one */ GSource *timeout_source; if (data->desired_position == GST_CLOCK_TIME_NONE) { /* There was no previous seek scheduled. Setup a timer for some time in the future */ timeout_source = g_timeout_source_new ((SEEK_MIN_DELAY - diff) / GST_MSECOND); g_source_set_callback (timeout_source, (GSourceFunc)delayed_seek_cb, data, NULL); g_source_attach (timeout_source, data->context); g_source_unref (timeout_source); } /* Update the desired seek position. If multiple petitions are received before it is time * to perform a seek, only the last one is remembered. */ data->desired_position = desired_position; GST_DEBUG ("Throttling seek to %" GST_TIME_FORMAT ", will be in %" GST_TIME_FORMAT, GST_TIME_ARGS (desired_position), GST_TIME_ARGS (SEEK_MIN_DELAY - diff)); } else { /* Perform the seek now */ GST_DEBUG ("Seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (desired_position)); data->last_seek_time = gst_util_get_timestamp (); gst_element_seek_simple (data->pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, desired_position); data->desired_position = GST_CLOCK_TIME_NONE; } }
int music_seek(struct music_rtp_pipeline *pipe, int64_t position) { int ok = gst_element_seek_simple(pipe->pipeline, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), position); if(!ok) return -1; return 0; }
void PlaybinSession::seek(quint32 ms) { if (d->playbin != 0) { gint64 position = (gint64)ms * 1000000; gst_element_seek_simple(d->playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position); } }
void seek (int64_t pos) { if (pipeline != NULL) { gst_element_seek_simple (pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, pos); } }
void AlertTonePreview::rewind () { SYS_DEBUG (""); if (!gst_element_seek_simple ( m_gstPipeline, GST_FORMAT_TIME, (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0l)) SYS_WARNING ("seek failed"); }
void NPlaybackEngineGStreamer::jump(qint64 msec) { if (!hasMedia()) return; gst_element_seek_simple(m_playbin, GST_FORMAT_TIME, GstSeekFlags(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), position() * m_durationNsec + msec * NSEC_IN_MSEC); }
GstBusSyncReply AVPlayer::bus_async(GstMessage* msg) { switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: { th_->run_async([this]() { pmanage<MPtr(&PContainer::set_str_str)>("started", "false"); }); break; } case GST_MESSAGE_STATE_CHANGED: { if (position_id_ == 0) { gst_element_query_duration( gst_pipeline_->get_pipeline(), GST_FORMAT_TIME, &track_duration_); if (track_duration_ != 0) { position_id_ = pmanage<MPtr(&PContainer::make_int)>("track_position", [this](const int& pos) { std::lock_guard<std::mutex> lock(seek_mutex_); position_ = pos; seek_called_ = true; gst_pipeline_->play(false); return true; }, [this]() { return position_; }, "Track position", "Current position of the track", 0, 0, track_duration_ / GST_SECOND); position_task_ = std::make_unique<PeriodicTask<>>( [this]() { gint64 position; gst_element_query_position( gst_pipeline_->get_pipeline(), GST_FORMAT_TIME, &position); position_ = static_cast<int>(position / GST_SECOND); pmanage<MPtr(&PContainer::notify)>(position_id_); }, std::chrono::milliseconds(500)); } } std::lock_guard<std::mutex> lock(seek_mutex_); if (seek_called_) { seek_called_ = false; gst_element_seek_simple(gst_pipeline_->get_pipeline(), GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, position_ * GST_SECOND); gst_pipeline_->play(true); } break; } default: break; } return GST_BUS_PASS; }
void on_click (ClutterActor *actor, ClutterEvent *event, gpointer data) { HandCar *all = (HandCar *)data; gint x, y; gint64 pos = -1; clutter_event_get_coords (event, &x, &y); if (coord_within_actor (all->btn_actor_play, x, y)) { if (!all->playing) { play_video (all); clutter_texture_set_pixbuf (CLUTTER_TEXTURE(all->btn_actor_play), all->stop, NULL); all->playing = TRUE; } else { stop_video (all); clutter_texture_set_pixbuf (CLUTTER_TEXTURE(all->btn_actor_play), all->play, NULL); all->playing = FALSE; } } else if ((coord_within_actor (all->btn_actor_next, x, y) && (all->playing))) { if (!gst_element_query_position (all->player, &all->format, &pos)) pos = 0; gst_element_seek_simple (all->player, all->format, GST_SEEK_FLAG_FLUSH, pos + 5 * GST_SECOND); } else if ((coord_within_actor (all->btn_actor_previous, x, y) && (all->playing))) { if (!gst_element_query_position (all->player, &all->format, &pos)) pos = 5 * GST_SECOND; gst_element_seek_simple (all->player, all->format, GST_SEEK_FLAG_FLUSH, pos - 5 * GST_SECOND); } }
static gboolean idle_restart_pipeline (void) { gst_element_set_state (glob_pipeline, GST_STATE_PAUSED); gst_element_get_state (glob_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); gst_element_seek_simple (glob_pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0); gst_element_set_state (glob_pipeline, GST_STATE_PLAYING); glob_pipeline_restarted = TRUE; return FALSE; }
static void _gst_load_image(int size_w EINA_UNUSED, int size_h EINA_UNUSED, double pos) { GstBuffer *buffer; D("load image\n"); if (pos >= 0.0) gst_element_seek_simple(pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, pos * 1000000000.0); else gst_element_seek_simple(pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, duration / 2); g_signal_emit_by_name(sink, "pull-preroll", &buffer, NULL); D("load image : %p %d\n", GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); shm_alloc(width * height * sizeof(DATA32)); if (!shm_addr) return; data = shm_addr; memcpy(data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); }
static void stopIt (GtkWidget *widget, GstElement* pipeline) { g_print("Rewinding Video Stream (and resetting speedRate)\n"); /* * gst_element_set_state (pipeline, GST_STATE_READY); * causes SIGSEG for no apparent reasons ? * so here's a workaround */ gst_element_set_state (pipeline, GST_STATE_PAUSED); gst_element_seek_simple (pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0); speedRate=1; }
static void set_media (AurClient * client) { if (client->player == NULL) { construct_player (client); if (client->player == NULL) return; } gst_element_set_state (client->player, GST_STATE_READY); g_print ("Setting media URI %s base_time %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT " paused %i\n", client->uri, GST_TIME_ARGS (client->base_time), GST_TIME_ARGS (client->position), client->paused); g_object_set (client->player, "uri", client->uri, NULL); gst_element_set_start_time (client->player, GST_CLOCK_TIME_NONE); gst_pipeline_use_clock (GST_PIPELINE (client->player), client->net_clock); /* Do the preroll */ gst_element_set_state (client->player, GST_STATE_PAUSED); gst_element_get_state (client->player, NULL, NULL, GST_CLOCK_TIME_NONE); /* Compensate preroll time if playing */ if (!client->paused) { GstClockTime now = gst_clock_get_time (client->net_clock); if (now > (client->base_time + client->position)) client->position = now - client->base_time; } /* If position is off by more than 0.5 sec, seek to that position * (otherwise, just let the player skip) */ if (client->position > GST_SECOND/2) { /* FIXME Query duration, so we don't seek after EOS */ if (!gst_element_seek_simple (client->player, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, client->position)) { g_warning ("Initial seekd failed, player will go faster instead"); client->position = 0; } } /* Set base time considering seek position after seek */ gst_element_set_base_time (client->player, client->base_time + client->position); /* Before we start playing, ensure we have selected the right audio track */ set_language (client); if (!client->paused) gst_element_set_state (client->player, GST_STATE_PLAYING); }
void NPlaybackEngineGStreamer::setPosition(qreal pos) { if (!hasMedia() || pos < 0 || pos > 1) return; if (m_durationNsec > 0) { gst_element_seek_simple(m_playbin, GST_FORMAT_TIME, GstSeekFlags(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), pos * m_durationNsec); } else { m_posponedPosition = pos; } }
/* * 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); }
bool GstEnginePipeline::Seek(qint64 nanosec) { if (ignore_next_seek_) { ignore_next_seek_ = false; return true; } if (!pipeline_is_connected_ || !pipeline_is_initialised_) { pending_seek_nanosec_ = nanosec; return true; } pending_seek_nanosec_ = -1; return gst_element_seek_simple(pipeline_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, nanosec); }
void GstSound::Stop() { if (this->state == PAUSED || this->state == PLAYING) { this->state = STOPPED; gst_element_set_state(this->pipeline, GST_STATE_NULL); GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT); gst_element_seek_simple( this->pipeline, GST_FORMAT_TIME, flags, 0); } }
/* Perform seek, if we are not too close to the previous seek. Otherwise, schedule the seek for * some time in the future. */ void execute_seek(gint64 desired_position, CustomData *data) { gint64 diff; if (desired_position == GST_CLOCK_TIME_NONE || !data->allow_seek) return; diff = gst_util_get_timestamp() - data->last_seek_time; if (!data->is_live) { GPlayerDEBUG("Seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS(desired_position)); data->last_seek_time = gst_util_get_timestamp(); gst_element_seek_simple(data->pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, desired_position); data->desired_position = GST_CLOCK_TIME_NONE; } }
void GstPlayer::seekStart(){ double start = ((double)track->getStartTime())*GST_MSECOND; double end = ((double)track->getEndTime())*GST_MSECOND; bool ok; if(0 < end){ QLOG_TRACE() << "Playing from: "<< start << " to " << end; ok = gst_element_seek(pipeline,1,GST_FORMAT_TIME,GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,start, GST_SEEK_TYPE_SET, end ); }else{ QLOG_TRACE() << "Moving to position: "<< start; ok = gst_element_seek_simple(pipeline,GST_FORMAT_TIME,GST_SEEK_FLAG_FLUSH,start); } QLOG_TRACE() << "Moving result: "<< (ok?"ok":"failed"); mustSeek = !ok; }
static void relative_seek (GstPlay * play, gdouble percent) { GstQuery *query; gboolean seekable = FALSE; gint64 dur = -1, pos = -1; g_return_if_fail (percent >= -1.0 && percent <= 1.0); if (!gst_element_query_position (play->playbin, GST_FORMAT_TIME, &pos)) goto seek_failed; query = gst_query_new_seeking (GST_FORMAT_TIME); if (!gst_element_query (play->playbin, query)) { gst_query_unref (query); goto seek_failed; } gst_query_parse_seeking (query, NULL, &seekable, NULL, &dur); gst_query_unref (query); if (!seekable || dur <= 0) goto seek_failed; pos = pos + dur * percent; if (pos > dur) { if (!play_next (play)) { g_print ("\nReached end of play list.\n"); g_main_loop_quit (play->loop); } } else { if (pos < 0) pos = 0; if (!gst_element_seek_simple (play->playbin, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, pos)) goto seek_failed; } return; seek_failed: { g_print ("\nCould not seek.\n"); } }