void test_no_lock() { GstTask *t; gboolean ret; //xmlfile = "test_no_lock"; std_log(LOG_FILENAME_LINE, "Test Started test_no_lock"); t = gst_task_create (task_func, NULL); fail_if (t == NULL); TEST_ASSERT_FAIL /* stop should be possible without lock */ gst_task_stop (t); /* pause should give a warning */ ASSERT_WARNING (ret = gst_task_pause (t)); //b failing fail_unless (ret == FALSE); TEST_ASSERT_FAIL /* start should give a warning */ ASSERT_WARNING (ret = gst_task_start (t)); fail_unless (ret == FALSE); TEST_ASSERT_FAIL /* stop should be possible without lock */ gst_task_stop (t); gst_object_unref (t); std_log(LOG_FILENAME_LINE, "Test Successful"); create_xml(0); }
static void gst_amlvdec_polling_eos (GstAmlVdec *amlvdec) { unsigned rp_move_count = 40,count=0; struct buf_status vbuf; unsigned last_rp = 0; int ret=1; do { if(count>2000)//avoid infinite loop break; ret = codec_get_vbuf_state(amlvdec->pcodec, &vbuf); if (ret != 0) { GST_ERROR("codec_get_vbuf_state error: %x\n", -ret); break; } if(last_rp != vbuf.read_pointer){ last_rp = vbuf.read_pointer; rp_move_count = 200; }else rp_move_count--; usleep(1000*30); count++; /* if(amlvdec->passthrough) { break; }*/ } while (vbuf.data_len > 0x100 && rp_move_count > 0); // amlvdec->passthrough = FALSE; //gst_pad_push_event (amlvdec->srcpad, gst_event_new_eos ()); gst_task_pause (amlvdec->eos_task); }
void test_lock() { GstTask *t; gboolean ret; //xmlfile = "test_lock"; std_log(LOG_FILENAME_LINE, "Test Started test_lock"); t = gst_task_create (task_func, NULL); fail_if (t == NULL); TEST_ASSERT_FAIL gst_task_set_lock (t, &task_mutex); GST_DEBUG ("pause"); ret = gst_task_pause (t); fail_unless (ret == TRUE); TEST_ASSERT_FAIL g_usleep (1 * G_USEC_PER_SEC / 2); GST_DEBUG ("joining"); ret = gst_task_join (t); fail_unless (ret == TRUE); TEST_ASSERT_FAIL g_usleep (1 * G_USEC_PER_SEC / 2); gst_object_unref (t); std_log(LOG_FILENAME_LINE, "Test Successful"); create_xml(0); }
static void gst_ss_demux_stream_loop (GstSSDemux * demux) { GThread *self = NULL; int stream_type = 0; GstSSDemuxStream *stream = NULL; self = g_thread_self (); for (stream_type = 0; stream_type < SS_STREAM_NUM; stream_type++) { if (demux->streams[stream_type]->stream_task->abidata.ABI.thread == self) { stream = demux->streams[stream_type]; break; } } /* download next fragment of stream_type */ if (!gst_ss_demux_get_next_fragment (demux, stream_type)) { GST_ERROR_OBJECT (demux, "failed to get next fragment..."); goto error; } return; error: { gst_task_pause (stream->stream_task); GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("could not download fragments"), (NULL)); gst_ss_demux_stop (demux, stream); return; } }
/* * Decrement the reference count on the curl multi loop. If this is called by * the last instance to hold a reference, shut down the worker. (Otherwise * GStreamer can't close down with a thread still running). Also offers the * "force_all" boolean parameter, which if TRUE removes all references and shuts * down. */ void gst_curl_multi_context_unref (GstCurlMultiContext * thiz) { g_mutex_lock(&thiz->mutex); thiz->refcount--; GST_INFO ("Worker thread refcount is now %u", thiz->refcount); if (thiz->refcount <= 0) { /* Everything's done! Clean up. */ gst_task_pause (thiz->task); g_cond_signal (&thiz->signal); g_mutex_unlock (&thiz->mutex); gst_task_join (thiz->task); } else { g_mutex_unlock(&thiz->mutex); } }
static void gst_hls_demux_loop (GstHLSDemux * demux) { GstBuffer *buf; GstFlowReturn ret; /* Loop for the source pad task. The task is started when we have * received the main playlist from the source element. It tries first to * cache the first fragments and then it waits until it has more data in the * queue. This task is woken up when we push a new fragment to the queue or * when we reached the end of the playlist */ if (G_UNLIKELY (demux->need_cache)) { if (!gst_hls_demux_cache_fragments (demux)) goto cache_error; /* we can start now the updates thread */ gst_hls_demux_start_update (demux); GST_INFO_OBJECT (demux, "First fragments cached successfully"); } if (g_queue_is_empty (demux->queue)) { if (demux->end_of_playlist) goto end_of_playlist; goto empty_queue; } buf = g_queue_pop_head (demux->queue); /* Figure out if we need to create/switch pads */ if (G_UNLIKELY (!demux->srcpad || GST_BUFFER_CAPS (buf) != GST_PAD_CAPS (demux->srcpad) || demux->need_segment)) { switch_pads (demux, GST_BUFFER_CAPS (buf)); demux->need_segment = TRUE; } if (demux->need_segment) { /* And send a newsegment */ GST_DEBUG_OBJECT (demux, "Sending new-segment. Segment start:%" GST_TIME_FORMAT, GST_TIME_ARGS (demux->position)); gst_pad_push_event (demux->srcpad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, demux->position, GST_CLOCK_TIME_NONE, demux->position)); demux->need_segment = FALSE; } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf))) demux->position += GST_BUFFER_DURATION (buf); ret = gst_pad_push (demux->srcpad, buf); if (ret != GST_FLOW_OK) goto error; return; end_of_playlist: { GST_DEBUG_OBJECT (demux, "Reached end of playlist, sending EOS"); gst_pad_push_event (demux->srcpad, gst_event_new_eos ()); gst_hls_demux_stop (demux); return; } cache_error: { gst_task_pause (demux->task); if (!demux->cancelled) { GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not cache the first fragments"), (NULL)); gst_hls_demux_stop (demux); } return; } error: { /* FIXME: handle error */ GST_DEBUG_OBJECT (demux, "error, stopping task"); gst_hls_demux_stop (demux); return; } empty_queue: { gst_task_pause (demux->task); return; } }
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 void task_monitor_alsa (gpointer data) { struct pollfd *pfds; unsigned int nfds, rnfds; unsigned short revents; GstAlsaMixer *mixer = (GstAlsaMixer *) data; gint ret; g_static_rec_mutex_lock (mixer->rec_mutex); nfds = snd_mixer_poll_descriptors_count (mixer->handle); if (nfds <= 0) { GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds); /* FIXME: sleep ? stop monitoring ? */ g_static_rec_mutex_unlock (mixer->rec_mutex); return; } pfds = g_newa (struct pollfd, nfds + 1); rnfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds); g_assert (rnfds <= nfds); if (rnfds < 0) { GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), ("alsa error: %s", snd_strerror (rnfds))); gst_task_pause (mixer->task); g_static_rec_mutex_unlock (mixer->rec_mutex); return; } pfds[rnfds].fd = mixer->pfd[0]; pfds[rnfds].events = POLLIN | POLLPRI | POLLHUP | POLLERR; pfds[rnfds].revents = 0; g_static_rec_mutex_unlock (mixer->rec_mutex); GST_LOG ("task loop"); ret = poll (pfds, rnfds + 1, -1); if (ret < 0) { GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); gst_task_pause (mixer->task); return; } g_static_rec_mutex_lock (mixer->rec_mutex); ret = snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents); if (ret < 0) { GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), ("alsa error: %s", snd_strerror (ret))); gst_task_pause (mixer->task); } else if (revents & (POLLIN | POLLPRI)) { GST_DEBUG ("Handling events"); snd_mixer_handle_events (mixer->handle); } else if (revents & (POLLERR | POLLNVAL | POLLHUP)) { GST_ELEMENT_ERROR (mixer, RESOURCE, READ, (NULL), (NULL)); gst_task_pause (mixer->task); } g_static_rec_mutex_unlock (mixer->rec_mutex); }
static void gst_decklink_src_task (void *priv) { GstDecklinkSrc *decklinksrc = GST_DECKLINK_SRC (priv); GstBuffer *buffer; GstBuffer *audio_buffer; IDeckLinkVideoInputFrame *video_frame; IDeckLinkAudioInputPacket *audio_frame; void *data; gsize data_size; int n_samples; GstFlowReturn ret; const GstDecklinkMode *mode; gboolean discont = FALSE; GST_DEBUG_OBJECT (decklinksrc, "task"); g_mutex_lock (&decklinksrc->mutex); while (decklinksrc->video_frame == NULL && !decklinksrc->stop) { g_cond_wait (&decklinksrc->cond, &decklinksrc->mutex); } video_frame = decklinksrc->video_frame; audio_frame = decklinksrc->audio_frame; decklinksrc->video_frame = NULL; decklinksrc->audio_frame = NULL; g_mutex_unlock (&decklinksrc->mutex); if (decklinksrc->stop) { if (video_frame) video_frame->Release (); if (audio_frame) audio_frame->Release (); GST_DEBUG ("stopping task"); return; } /* warning on dropped frames */ /* FIXME: post QoS message */ if (decklinksrc->dropped_frames - decklinksrc->dropped_frames_old > 0) { GST_ELEMENT_WARNING (decklinksrc, RESOURCE, READ, ("Dropped %d frame(s), for a total of %d frame(s)", decklinksrc->dropped_frames - decklinksrc->dropped_frames_old, decklinksrc->dropped_frames), (NULL)); decklinksrc->dropped_frames_old = decklinksrc->dropped_frames; /* FIXME: discont = TRUE; ? */ } if (!decklinksrc->started) { gst_decklink_src_send_initial_events (decklinksrc); decklinksrc->started = TRUE; } mode = gst_decklink_get_mode (decklinksrc->mode); video_frame->GetBytes (&data); data_size = mode->width * mode->height * 2; if (decklinksrc->copy_data) { buffer = gst_buffer_new_and_alloc (data_size); gst_buffer_fill (buffer, 0, data, data_size); video_frame->Release (); } else { VideoFrame *vf; vf = (VideoFrame *) g_malloc0 (sizeof (VideoFrame)); buffer = gst_buffer_new_wrapped_full ((GstMemoryFlags) 0, data, data_size, 0, data_size, vf, (GDestroyNotify) video_frame_free); vf->frame = video_frame; vf->input = decklinksrc->input; vf->input->AddRef (); } GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale_int (decklinksrc->frame_num * GST_SECOND, mode->fps_d, mode->fps_n); GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int ((decklinksrc->frame_num + 1) * GST_SECOND, mode->fps_d, mode->fps_n) - GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_OFFSET (buffer) = decklinksrc->frame_num; GST_BUFFER_OFFSET_END (buffer) = decklinksrc->frame_num; /* FIXME: +1? */ /* FIXME: set video meta */ if (decklinksrc->frame_num == 0) discont = TRUE; if (discont) GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); else GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); /* FIXME: proper flow aggregation with audio flow */ ret = gst_pad_push (decklinksrc->videosrcpad, buffer); if (!(ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED || ret == GST_FLOW_FLUSHING)) { GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (ret))); goto pause; } if (gst_pad_is_linked (decklinksrc->audiosrcpad)) { n_samples = audio_frame->GetSampleFrameCount (); audio_frame->GetBytes (&data); audio_buffer = gst_buffer_new_and_alloc (n_samples * 2 * 2); gst_buffer_fill (audio_buffer, 0, data, n_samples * 2 * 2); GST_BUFFER_TIMESTAMP (audio_buffer) = gst_util_uint64_scale_int (decklinksrc->num_audio_samples * GST_SECOND, 1, 48000); /* FIXME: should be next_timestamp - timestamp for perfect stream */ GST_BUFFER_DURATION (audio_buffer) = gst_util_uint64_scale_int (n_samples * GST_SECOND, 1, 48000); GST_BUFFER_OFFSET (audio_buffer) = decklinksrc->num_audio_samples; GST_BUFFER_OFFSET_END (audio_buffer) = GST_BUFFER_OFFSET (audio_buffer) + n_samples; decklinksrc->num_audio_samples += n_samples; /* FIXME: proper flow aggregation with video flow */ ret = gst_pad_push (decklinksrc->audiosrcpad, audio_buffer); if (!(ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED || ret == GST_FLOW_FLUSHING)) { GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (ret))); goto pause; } } done: if (audio_frame) audio_frame->Release (); return; pause: { const gchar *reason = gst_flow_get_name (ret); GstEvent *event = NULL; GST_DEBUG_OBJECT (decklinksrc, "pausing task, reason %s", reason); gst_task_pause (decklinksrc->task); if (ret == GST_FLOW_EOS) { /* perform EOS logic (very crude, we don't even keep a GstSegment) */ event = gst_event_new_eos (); } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { event = gst_event_new_eos (); /* for fatal errors we post an error message, post the error * first so the app knows about the error first. * Also don't do this for FLUSHING because it happens * due to flushing and posting an error message because of * that is the wrong thing to do, e.g. when we're doing * a flushing seek. */ GST_ELEMENT_ERROR (decklinksrc, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused, reason %s (%d)", reason, ret)); } if (event != NULL) { GST_INFO_OBJECT (decklinksrc->videosrcpad, "pushing EOS event"); gst_pad_push_event (decklinksrc->videosrcpad, gst_event_ref (event)); GST_INFO_OBJECT (decklinksrc->audiosrcpad, "pushing EOS event"); gst_pad_push_event (decklinksrc->audiosrcpad, event); } goto done; } }
static GstStateChangeReturn gst_swfdec_change_state (GstElement * element, GstStateChange transition) { GstSwfdec *swfdec = GST_SWFDEC (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: { gst_adapter_clear (swfdec->adapter); /* gst_swfdec_vo_open (swfdec); swfdec_decoder_new (swfdec->decoder, swfdec->accel, swfdec->vo); swfdec->decoder->is_sequence_needed = 1; swfdec->decoder->frame_rate_code = 0; */ swfdec->timestamp = 0; swfdec->closed = FALSE; /* reset the initial video state */ swfdec->have_format = FALSE; swfdec->format = -1; swfdec->width = -1; swfdec->height = -1; swfdec->first = TRUE; break; } case GST_STATE_CHANGE_PAUSED_TO_PLAYING: gst_task_start (swfdec->task); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: gst_task_pause (swfdec->task); gst_task_join (swfdec->task); break; case GST_STATE_CHANGE_PAUSED_TO_READY: /* if we are not closed by an EOS event do so now, this cen send a few frames but * we are prepared to not really send them (see above) */ if (!swfdec->closed) { /*swf_close (swfdec->decoder); */ swfdec->closed = TRUE; } /* gst_swfdec_vo_destroy (swfdec); */ break; case GST_STATE_CHANGE_READY_TO_NULL: gst_task_stop (swfdec->task); gst_task_join (swfdec->task); break; default: break; } return ret; }
static void gst_hls_demux_stream_loop (GstHLSDemux * demux) { GstFragment *fragment; GstBuffer *buf; GstFlowReturn ret; GstCaps *bufcaps, *srccaps = NULL; /* Loop for the source pad task. The task is started when we have * received the main playlist from the source element. It tries first to * cache the first fragments and then it waits until it has more data in the * queue. This task is woken up when we push a new fragment to the queue or * when we reached the end of the playlist */ if (G_UNLIKELY (demux->need_cache)) { if (!gst_hls_demux_cache_fragments (demux)) goto cache_error; /* we can start now the updates thread (only if on playing) */ if (GST_STATE (demux) == GST_STATE_PLAYING) gst_task_start (demux->updates_task); GST_INFO_OBJECT (demux, "First fragments cached successfully"); } if (g_queue_is_empty (demux->queue)) { if (demux->end_of_playlist) goto end_of_playlist; goto pause_task; } fragment = g_queue_pop_head (demux->queue); buf = gst_fragment_get_buffer (fragment); /* Figure out if we need to create/switch pads */ if (G_LIKELY (demux->srcpad)) srccaps = gst_pad_get_current_caps (demux->srcpad); bufcaps = gst_fragment_get_caps (fragment); if (G_UNLIKELY (!srccaps || !gst_caps_is_equal_fixed (bufcaps, srccaps) || demux->need_segment)) { switch_pads (demux, bufcaps); demux->need_segment = TRUE; } gst_caps_unref (bufcaps); if (G_LIKELY (srccaps)) gst_caps_unref (srccaps); g_object_unref (fragment); if (demux->need_segment) { GstSegment segment; GstClockTime start = GST_BUFFER_PTS (buf); start += demux->position_shift; /* And send a newsegment */ GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%" GST_TIME_FORMAT, GST_TIME_ARGS (start)); gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = start; segment.time = start; gst_pad_push_event (demux->srcpad, gst_event_new_segment (&segment)); demux->need_segment = FALSE; demux->position_shift = 0; } ret = gst_pad_push (demux->srcpad, buf); if (ret != GST_FLOW_OK) goto error_pushing; return; end_of_playlist: { GST_DEBUG_OBJECT (demux, "Reached end of playlist, sending EOS"); gst_pad_push_event (demux->srcpad, gst_event_new_eos ()); gst_hls_demux_stop (demux); return; } cache_error: { gst_task_pause (demux->stream_task); if (!demux->cancelled) { GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND, ("Could not cache the first fragments"), (NULL)); gst_hls_demux_stop (demux); } return; } error_pushing: { /* FIXME: handle error */ GST_DEBUG_OBJECT (demux, "Error pushing buffer: %s... stopping task", gst_flow_get_name (ret)); gst_hls_demux_stop (demux); return; } pause_task: { gst_task_pause (demux->stream_task); return; } }
static gboolean gst_hls_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstHLSDemux *demux; demux = GST_HLS_DEMUX (parent); switch (event->type) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; GList *walk; GstClockTime position, current_pos, target_pos; gint current_sequence; 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)); GST_M3U8_CLIENT_LOCK (demux->client); file = GST_M3U8_MEDIA_FILE (demux->client->current->files->data); current_sequence = file->sequence; current_pos = 0; target_pos = (GstClockTime) start; for (walk = demux->client->current->files; walk; walk = walk->next) { file = walk->data; current_sequence = file->sequence; if (current_pos <= target_pos && target_pos < current_pos + file->duration) { break; } current_pos += file->duration; } GST_M3U8_CLIENT_UNLOCK (demux->client); 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->stream_task); gst_uri_downloader_cancel (demux->downloader); gst_task_stop (demux->updates_task); gst_task_pause (demux->stream_task); /* wait for streaming to finish */ g_rec_mutex_lock (&demux->stream_lock); demux->need_cache = TRUE; while (!g_queue_is_empty (demux->queue)) { GstFragment *fragment = g_queue_pop_head (demux->queue); g_object_unref (fragment); } g_queue_clear (demux->queue); GST_M3U8_CLIENT_LOCK (demux->client); GST_DEBUG_OBJECT (demux, "seeking to sequence %d", current_sequence); demux->client->sequence = current_sequence; gst_m3u8_client_get_current_position (demux->client, &position); demux->position_shift = start - position; demux->need_segment = TRUE; GST_M3U8_CLIENT_UNLOCK (demux->client); if (flags & GST_SEEK_FLAG_FLUSH) { GST_DEBUG_OBJECT (demux, "sending flush stop"); gst_pad_push_event (demux->srcpad, gst_event_new_flush_stop (TRUE)); } demux->cancelled = FALSE; gst_task_start (demux->stream_task); g_rec_mutex_unlock (&demux->stream_lock); return TRUE; } default: break; } return gst_pad_event_default (pad, parent, event); }