static void mpegts_base_loop (MpegTSBase * base) { GstFlowReturn ret = GST_FLOW_ERROR; switch (base->mode) { case BASE_MODE_SCANNING: /* Find first sync point */ ret = mpegts_base_scan (base); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto error; base->mode = BASE_MODE_STREAMING; GST_DEBUG ("Changing to Streaming"); break; case BASE_MODE_SEEKING: /* FIXME : unclear if we still need mode_seeking... */ base->mode = BASE_MODE_STREAMING; break; case BASE_MODE_STREAMING: { GstBuffer *buf = NULL; GST_DEBUG ("Pulling data from %" G_GUINT64_FORMAT, base->seek_offset); ret = gst_pad_pull_range (base->sinkpad, base->seek_offset, 100 * base->packetsize, &buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto error; base->seek_offset += gst_buffer_get_size (buf); ret = mpegts_base_chain (base->sinkpad, GST_OBJECT_CAST (base), buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto error; } break; case BASE_MODE_PUSHING: GST_WARNING ("wrong BASE_MODE_PUSHING mode in pull loop"); break; } return; error: { const gchar *reason = gst_flow_get_name (ret); GST_DEBUG_OBJECT (base, "Pausing task, reason %s", reason); if (ret == GST_FLOW_EOS) { if (!GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ())) GST_ELEMENT_ERROR (base, STREAM, FAILED, (_("Internal data stream error.")), ("No program activated before EOS")); } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (base, STREAM, FAILED, (_("Internal data stream error.")), ("stream stopped, reason %s", reason)); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, gst_event_new_eos ()); } gst_pad_pause_task (base->sinkpad); } }
/** * hls_progress_buffer_loop() * * Primary function for push-mode. Pulls data from progressbuffer's cache queue. */ static void hls_progress_buffer_loop(void *data) { HLSProgressBuffer* element = HLS_PROGRESS_BUFFER(data); GstFlowReturn result = GST_FLOW_OK; g_mutex_lock(element->lock); while (element->srcresult == GST_FLOW_OK && !cache_has_enough_data(element->cache[element->cache_read_index])) { if (element->is_eos) { gst_pad_push_event(element->srcpad, gst_event_new_eos()); element->srcresult = GST_FLOW_WRONG_STATE; break; } if (!element->is_eos) { g_cond_wait(element->add_cond, element->lock); } } result = element->srcresult; if (result == GST_FLOW_OK) { GstBuffer *buffer = NULL; guint64 read_position = cache_read_buffer(element->cache[element->cache_read_index], &buffer); if (read_position == element->cache_size[element->cache_read_index]) { element->cache_write_ready[element->cache_read_index] = TRUE; element->cache_read_index = (element->cache_read_index + 1) % NUM_OF_CACHED_SEGMENTS; send_hls_not_full_message(element); g_cond_signal(element->del_cond); } g_mutex_unlock(element->lock); gst_buffer_set_caps(buffer, GST_PAD_CAPS(element->sinkpad)); // Send the data to the hls progressbuffer source pad result = gst_pad_push(element->srcpad, buffer); g_mutex_lock(element->lock); if (GST_FLOW_OK == element->srcresult || GST_FLOW_OK != result) element->srcresult = result; else result = element->srcresult; g_mutex_unlock(element->lock); } else { g_mutex_unlock(element->lock); } if (result != GST_FLOW_OK && !element->is_flushing) gst_pad_pause_task(element->srcpad); }
static void user_read_data (png_structp png_ptr, png_bytep data, png_size_t length) { GstPngDec *pngdec; GstBuffer *buffer; GstFlowReturn ret = GST_FLOW_OK; guint size; pngdec = GST_PNGDEC (png_get_io_ptr (png_ptr)); GST_LOG ("reading %" G_GSIZE_FORMAT " bytes of data at offset %d", length, pngdec->offset); ret = gst_pad_pull_range (pngdec->sinkpad, pngdec->offset, length, &buffer); if (ret != GST_FLOW_OK) goto pause; size = GST_BUFFER_SIZE (buffer); if (size != length) goto short_buffer; memcpy (data, GST_BUFFER_DATA (buffer), size); gst_buffer_unref (buffer); pngdec->offset += length; return; /* ERRORS */ pause: { GST_INFO_OBJECT (pngdec, "pausing task, reason %s", gst_flow_get_name (ret)); gst_pad_pause_task (pngdec->sinkpad); if (ret == GST_FLOW_UNEXPECTED) { gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) { GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, (_("Internal data stream error.")), ("stream stopped, reason %s", gst_flow_get_name (ret))); gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); } png_error (png_ptr, "Internal data stream error."); return; } short_buffer: { gst_buffer_unref (buffer); GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, (_("Internal data stream error.")), ("Read %u, needed %" G_GSIZE_FORMAT "bytes", size, length)); ret = GST_FLOW_ERROR; goto pause; } }
static gboolean gst_tcp_mix_src_pad_pause (GstTCPMixSrcPad * pad, GstTaskFunction func) { gboolean res; if (GST_PAD_TASK (pad) != NULL) { // FIXME: pad->status == started res = gst_pad_pause_task (GST_PAD (pad)); } return res; }
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 void gst_vaapiencode_buffer_loop (GstVaapiEncode * encode) { GstFlowReturn ret; const gint64 timeout = 50000; /* microseconds */ ret = gst_vaapiencode_push_frame (encode, timeout); if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT) return; gst_pad_pause_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode)); }
/* called repeadedly with @pad as the source pad. This function should push out * data to the peer element. */ static void gst_ts_shifter_loop (GstPad * pad) { GstTSShifter *ts; GstFlowReturn ret; ts = GST_TS_SHIFTER (GST_PAD_PARENT (pad)); /* have to lock for thread-safety */ FLOW_MUTEX_LOCK_CHECK (ts, ts->srcresult, out_flushing); if (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos) { GST_CAT_LOG_OBJECT (ts_flow, ts, "empty, waiting for new data"); do { /* Wait for data to be available, we could be unlocked because of a flush. */ FLOW_WAIT_ADD_CHECK (ts, ts->srcresult, out_flushing); } while (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos); } ret = gst_ts_shifter_pop (ts); ts->srcresult = ret; if (ret != GST_FLOW_OK) goto out_flushing; FLOW_MUTEX_UNLOCK (ts); return; /* ERRORS */ out_flushing: { gboolean eos = ts->is_eos; GstFlowReturn ret = ts->srcresult; gst_pad_pause_task (ts->srcpad); FLOW_MUTEX_UNLOCK (ts); GST_CAT_LOG_OBJECT (ts_flow, ts, "pause task, reason: %s", gst_flow_get_name (ts->srcresult)); /* let app know about us giving up if upstream is not expected to do so */ /* UNEXPECTED is already taken care of elsewhere */ if (eos && (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) { GST_ELEMENT_ERROR (ts, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused, reason %s (%d)", gst_flow_get_name (ret), ret)); GST_CAT_LOG_OBJECT (ts_flow, ts, "pushing EOS"); gst_pad_push_event (ts->srcpad, gst_event_new_eos ()); } return; } }
static gboolean gst_type_find_element_activate_src_mode (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { gboolean res; GstTypeFindElement *typefind; typefind = GST_TYPE_FIND_ELEMENT (parent); switch (mode) { case GST_PAD_MODE_PULL: /* make sure our task stops pushing, we can't call _stop here because this * activation might happen from the streaming thread. */ gst_pad_pause_task (typefind->sink); res = gst_pad_activate_mode (typefind->sink, mode, active); break; default: res = TRUE; break; } return res; }
static void gst_tta_parse_loop (GstTtaParse * ttaparse) { GstFlowReturn ret; if (!ttaparse->header_parsed) if ((ret = gst_tta_parse_parse_header (ttaparse)) != GST_FLOW_OK) goto pause; if ((ret = gst_tta_parse_stream_data (ttaparse)) != GST_FLOW_OK) goto pause; return; pause: GST_LOG_OBJECT (ttaparse, "pausing task, %s", gst_flow_get_name (ret)); gst_pad_pause_task (ttaparse->sinkpad); if (ret == GST_FLOW_UNEXPECTED) { gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ()); } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) { GST_ELEMENT_FLOW_ERROR (ttaparse, ret); gst_pad_push_event (ttaparse->srcpad, gst_event_new_eos ()); } }
static GstFlowReturn gst_rtp_dtmf_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) { GstRTPDTMFSrcEvent *event; GstRTPDTMFSrc *dtmfsrc; GstClock *clock; GstClockID *clockid; GstClockReturn clockret; GstMessage *message; GQueue messages = G_QUEUE_INIT; dtmfsrc = GST_RTP_DTMF_SRC (basesrc); do { if (dtmfsrc->payload == NULL) { GST_DEBUG_OBJECT (dtmfsrc, "popping"); event = g_async_queue_pop (dtmfsrc->event_queue); GST_DEBUG_OBJECT (dtmfsrc, "popped %d", event->event_type); switch (event->event_type) { case RTP_DTMF_EVENT_TYPE_STOP: GST_WARNING_OBJECT (dtmfsrc, "Received a DTMF stop event when already stopped"); gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); break; case RTP_DTMF_EVENT_TYPE_START: dtmfsrc->first_packet = TRUE; dtmfsrc->last_packet = FALSE; /* Set the redundancy on the first packet */ dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy; if (!gst_rtp_dtmf_prepare_timestamps (dtmfsrc)) goto no_clock; g_queue_push_tail (&messages, gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed", event)); dtmfsrc->payload = event->payload; dtmfsrc->payload->duration = dtmfsrc->ptime * dtmfsrc->clock_rate / 1000; event->payload = NULL; break; case RTP_DTMF_EVENT_TYPE_PAUSE_TASK: /* * We're pushing it back because it has to stay in there until * the task is really paused (and the queue will then be flushed */ GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) { g_async_queue_push (dtmfsrc->event_queue, event); goto paused_locked; } GST_OBJECT_UNLOCK (dtmfsrc); break; } gst_rtp_dtmf_src_event_free (event); } else if (!dtmfsrc->first_packet && !dtmfsrc->last_packet && (dtmfsrc->timestamp - dtmfsrc->start_timestamp) / GST_MSECOND >= MIN_PULSE_DURATION) { GST_DEBUG_OBJECT (dtmfsrc, "try popping"); event = g_async_queue_try_pop (dtmfsrc->event_queue); if (event != NULL) { GST_DEBUG_OBJECT (dtmfsrc, "try popped %d", event->event_type); switch (event->event_type) { case RTP_DTMF_EVENT_TYPE_START: GST_WARNING_OBJECT (dtmfsrc, "Received two consecutive DTMF start events"); gst_dtmf_src_post_message (dtmfsrc, "dtmf-event-dropped", event); break; case RTP_DTMF_EVENT_TYPE_STOP: dtmfsrc->first_packet = FALSE; dtmfsrc->last_packet = TRUE; /* Set the redundancy on the last packet */ dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy; g_queue_push_tail (&messages, gst_dtmf_src_prepare_message (dtmfsrc, "dtmf-event-processed", event)); break; case RTP_DTMF_EVENT_TYPE_PAUSE_TASK: /* * We're pushing it back because it has to stay in there until * the task is really paused (and the queue will then be flushed) */ GST_DEBUG_OBJECT (dtmfsrc, "pushing pause_task..."); GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) { g_async_queue_push (dtmfsrc->event_queue, event); goto paused_locked; } GST_OBJECT_UNLOCK (dtmfsrc); break; } gst_rtp_dtmf_src_event_free (event); } } } while (dtmfsrc->payload == NULL); GST_DEBUG_OBJECT (dtmfsrc, "Processed events, now lets wait on the clock"); clock = gst_element_get_clock (GST_ELEMENT (basesrc)); if (!clock) goto no_clock; clockid = gst_clock_new_single_shot_id (clock, dtmfsrc->timestamp + gst_element_get_base_time (GST_ELEMENT (dtmfsrc))); gst_object_unref (clock); GST_OBJECT_LOCK (dtmfsrc); if (!dtmfsrc->paused) { dtmfsrc->clockid = clockid; GST_OBJECT_UNLOCK (dtmfsrc); clockret = gst_clock_id_wait (clockid, NULL); GST_OBJECT_LOCK (dtmfsrc); if (dtmfsrc->paused) clockret = GST_CLOCK_UNSCHEDULED; } else { clockret = GST_CLOCK_UNSCHEDULED; } gst_clock_id_unref (clockid); dtmfsrc->clockid = NULL; GST_OBJECT_UNLOCK (dtmfsrc); while ((message = g_queue_pop_head (&messages)) != NULL) gst_element_post_message (GST_ELEMENT (dtmfsrc), message); if (clockret == GST_CLOCK_UNSCHEDULED) { goto paused; } send_last: if (dtmfsrc->dirty) if (!gst_rtp_dtmf_src_negotiate (basesrc)) return GST_FLOW_NOT_NEGOTIATED; /* create buffer to hold the payload */ *buffer = gst_rtp_dtmf_src_create_next_rtp_packet (dtmfsrc); if (dtmfsrc->redundancy_count) dtmfsrc->redundancy_count--; /* Only the very first one has a marker */ dtmfsrc->first_packet = FALSE; /* This is the end of the event */ if (dtmfsrc->last_packet == TRUE && dtmfsrc->redundancy_count == 0) { g_slice_free (GstRTPDTMFPayload, dtmfsrc->payload); dtmfsrc->payload = NULL; dtmfsrc->last_packet = FALSE; } return GST_FLOW_OK; paused_locked: GST_OBJECT_UNLOCK (dtmfsrc); paused: if (dtmfsrc->payload) { dtmfsrc->first_packet = FALSE; dtmfsrc->last_packet = TRUE; /* Set the redundanc on the last packet */ dtmfsrc->redundancy_count = dtmfsrc->packet_redundancy; goto send_last; } else { return GST_FLOW_FLUSHING; } no_clock: GST_ELEMENT_ERROR (dtmfsrc, STREAM, MUX, ("No available clock"), ("No available clock")); gst_pad_pause_task (GST_BASE_SRC_PAD (dtmfsrc)); return GST_FLOW_ERROR; }
static void gst_rnd_buffer_size_loop (GstRndBufferSize * self) { GstBuffer *buf = NULL; GstFlowReturn ret; guint num_bytes, size; if (G_UNLIKELY (self->min > self->max)) goto bogus_minmax; if (G_UNLIKELY (self->min != self->max)) { num_bytes = g_rand_int_range (self->rand, self->min, self->max); } else { num_bytes = self->min; } GST_LOG_OBJECT (self, "pulling %u bytes at offset %" G_GUINT64_FORMAT, num_bytes, self->offset); ret = gst_pad_pull_range (self->sinkpad, self->offset, num_bytes, &buf); if (ret != GST_FLOW_OK) goto pull_failed; size = gst_buffer_get_size (buf); if (size < num_bytes) { GST_WARNING_OBJECT (self, "short buffer: %u bytes", size); } if (self->need_newsegment) { GstSegment segment; gst_segment_init (&segment, GST_FORMAT_BYTES); segment.start = self->offset; gst_pad_push_event (self->srcpad, gst_event_new_segment (&segment)); self->need_newsegment = FALSE; } self->offset += size; ret = gst_pad_push (self->srcpad, buf); if (ret != GST_FLOW_OK) goto push_failed; return; pause_task: { GST_DEBUG_OBJECT (self, "pausing task"); gst_pad_pause_task (self->sinkpad); return; } pull_failed: { if (ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "eos"); gst_pad_push_event (self->srcpad, gst_event_new_eos ()); } else { GST_WARNING_OBJECT (self, "pull_range flow: %s", gst_flow_get_name (ret)); } goto pause_task; } push_failed: { GST_DEBUG_OBJECT (self, "push flow: %s", gst_flow_get_name (ret)); if (ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "eos"); gst_pad_push_event (self->srcpad, gst_event_new_eos ()); } else if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("streaming stopped, reason: %s", gst_flow_get_name (ret))); } goto pause_task; } bogus_minmax: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, ("The minimum buffer size is smaller than the maximum buffer size."), ("buffer sizes: max=%d, min=%d", self->min, self->max)); goto pause_task; } }
static void gst_amc_audio_dec_loop (GstAmcAudioDec * self) { GstFlowReturn flow_ret = GST_FLOW_OK; gboolean is_eos; GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; gint idx; GError *err = NULL; GST_AUDIO_DECODER_STREAM_LOCK (self); retry: /*if (self->input_caps_changed) { idx = INFO_OUTPUT_FORMAT_CHANGED; } else { */ GST_DEBUG_OBJECT (self, "Waiting for available output buffer"); GST_AUDIO_DECODER_STREAM_UNLOCK (self); /* Wait at most 100ms here, some codecs don't fail dequeueing if * the codec is flushing, causing deadlocks during shutdown */ idx = gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000, &err); GST_AUDIO_DECODER_STREAM_LOCK (self); /*} */ if (idx < 0) { if (self->flushing) { g_clear_error (&err); goto flushing; } switch (idx) { case INFO_OUTPUT_BUFFERS_CHANGED: /* Handled internally */ g_assert_not_reached (); break; case INFO_OUTPUT_FORMAT_CHANGED:{ GstAmcFormat *format; gchar *format_string; GST_DEBUG_OBJECT (self, "Output format has changed"); format = gst_amc_codec_get_output_format (self->codec, &err); if (!format) goto format_error; format_string = gst_amc_format_to_string (format, &err); if (err) { gst_amc_format_free (format); goto format_error; } GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string); g_free (format_string); if (!gst_amc_audio_dec_set_src_caps (self, format)) { gst_amc_format_free (format); goto format_error; } gst_amc_format_free (format); goto retry; } case INFO_TRY_AGAIN_LATER: GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out"); goto retry; case G_MININT: GST_ERROR_OBJECT (self, "Failure dequeueing output buffer"); goto dequeue_error; default: g_assert_not_reached (); break; } goto retry; } GST_DEBUG_OBJECT (self, "Got output buffer at index %d: offset %d size %d time %" G_GINT64_FORMAT " flags 0x%08x", idx, buffer_info.offset, buffer_info.size, buffer_info.presentation_time_us, buffer_info.flags); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); if (!buf) goto failed_to_get_output_buffer; if (buffer_info.size > 0) { GstBuffer *outbuf; GstMapInfo minfo; /* This sometimes happens at EOS or if the input is not properly framed, * let's handle it gracefully by allocating a new buffer for the current * caps and filling it */ if (buffer_info.size % self->info.bpf != 0) goto invalid_buffer_size; outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self), buffer_info.size); if (!outbuf) goto failed_allocate; gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); if (self->needs_reorder) { gint i, n_samples, c, n_channels; gint *reorder_map = self->reorder_map; gint16 *dest, *source; dest = (gint16 *) minfo.data; source = (gint16 *) (buf->data + buffer_info.offset); n_samples = buffer_info.size / self->info.bpf; n_channels = self->info.channels; for (i = 0; i < n_samples; i++) { for (c = 0; c < n_channels; c++) { dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c]; } } } else { orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size); } gst_buffer_unmap (outbuf, &minfo); if (self->spf != -1) { gst_adapter_push (self->output_adapter, outbuf); } else { flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1); } } gst_amc_buffer_free (buf); buf = NULL; if (self->spf != -1) { GstBuffer *outbuf; guint avail = gst_adapter_available (self->output_adapter); guint nframes; /* On EOS we take the complete adapter content, no matter * if it is a multiple of the codec frame size or not. * Otherwise we take a multiple of codec frames and push * them downstream */ avail /= self->info.bpf; if (!is_eos) { nframes = avail / self->spf; avail = nframes * self->spf; } else { nframes = (avail + self->spf - 1) / self->spf; } avail *= self->info.bpf; if (avail > 0) { outbuf = gst_adapter_take_buffer (self->output_adapter, avail); flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, nframes); } } if (!gst_amc_codec_release_output_buffer (self->codec, idx, &err)) { if (self->flushing) { g_clear_error (&err); goto flushing; } goto failed_release; } if (is_eos || flow_ret == GST_FLOW_EOS) { GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); if (self->draining) { GST_DEBUG_OBJECT (self, "Drained"); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); } else if (flow_ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (self, "Component signalled EOS"); flow_ret = GST_FLOW_EOS; } g_mutex_unlock (&self->drain_lock); GST_AUDIO_DECODER_STREAM_LOCK (self); } else { GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); } self->downstream_flow_ret = flow_ret; if (flow_ret != GST_FLOW_OK) goto flow_error; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; dequeue_error: { GST_ELEMENT_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } format_error: { if (err) GST_ELEMENT_ERROR_FROM_ERROR (self, err); else GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to handle format")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_release: { GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_FLUSHING; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } flow_error: { if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else if (flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_to_get_output_buffer: { GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } invalid_buffer_size: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Invalid buffer size %u (bfp %d)", buffer_info.size, self->info.bpf)); gst_amc_codec_release_output_buffer (self->codec, idx, &err); if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_allocate: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to allocate output buffer")); gst_amc_codec_release_output_buffer (self->codec, idx, &err); if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } }
static void gst_asf_parse_loop (GstPad * pad) { GstFlowReturn ret = GST_FLOW_OK; GstAsfParse *asfparse = GST_ASF_PARSE_CAST (GST_OBJECT_PARENT (pad)); GST_LOG_OBJECT (asfparse, "Processing data in loop function"); switch (asfparse->parse_state) { case ASF_PARSING_HEADERS: GST_INFO_OBJECT (asfparse, "Starting to parse headers"); ret = gst_asf_parse_pull_headers (asfparse); if (ret != GST_FLOW_OK) goto pause; asfparse->parse_state = ASF_PARSING_DATA; case ASF_PARSING_DATA: GST_INFO_OBJECT (asfparse, "Parsing data object headers"); ret = gst_asf_parse_pull_data_header (asfparse); if (ret != GST_FLOW_OK) goto pause; asfparse->parse_state = ASF_PARSING_PACKETS; case ASF_PARSING_PACKETS: GST_INFO_OBJECT (asfparse, "Starting packet parsing"); GST_INFO_OBJECT (asfparse, "Broadcast mode %s", asfparse->asfinfo->broadcast ? "on" : "off"); ret = gst_asf_parse_pull_packets (asfparse); if (ret != GST_FLOW_OK) goto pause; /* test if all packets have been processed */ if (!asfparse->asfinfo->broadcast && asfparse->parsed_packets == asfparse->asfinfo->packets_count) { GST_INFO_OBJECT (asfparse, "All %" G_GUINT64_FORMAT " packets processed", asfparse->parsed_packets); asfparse->parse_state = ASF_PARSING_INDEXES; } case ASF_PARSING_INDEXES: /* we currently don't care about indexes, so just push them forward */ GST_INFO_OBJECT (asfparse, "Starting indexes parsing"); ret = gst_asf_parse_pull_indexes (asfparse); if (ret != GST_FLOW_OK) goto pause; default: break; } pause: { const gchar *reason = gst_flow_get_name (ret); GST_INFO_OBJECT (asfparse, "Pausing sinkpad task"); gst_pad_pause_task (pad); if (ret == GST_FLOW_EOS) { gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ()); } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (asfparse, STREAM, FAILED, (NULL), ("streaming task paused, reason %s (%d)", reason, ret)); gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ()); } } }
static void gst_type_find_element_loop (GstPad * pad) { GstTypeFindElement *typefind; GstFlowReturn ret = GST_FLOW_OK; typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad)); if (typefind->need_stream_start) { gchar *stream_id; GstEvent *event; stream_id = gst_pad_create_stream_id (typefind->src, GST_ELEMENT_CAST (typefind), NULL); GST_DEBUG_OBJECT (typefind, "Pushing STREAM_START"); event = gst_event_new_stream_start (stream_id); gst_event_set_group_id (event, gst_util_group_id_next ()); gst_pad_push_event (typefind->src, event); typefind->need_stream_start = FALSE; g_free (stream_id); } if (typefind->mode == MODE_TYPEFIND) { GstPad *peer = NULL; GstCaps *found_caps = NULL; GstTypeFindProbability probability = GST_TYPE_FIND_NONE; GST_DEBUG_OBJECT (typefind, "find type in pull mode"); GST_OBJECT_LOCK (typefind); if (typefind->force_caps) { found_caps = gst_caps_ref (typefind->force_caps); probability = GST_TYPE_FIND_MAXIMUM; } GST_OBJECT_UNLOCK (typefind); if (!found_caps) { peer = gst_pad_get_peer (pad); if (peer) { gint64 size; gchar *ext; if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &size)) { GST_WARNING_OBJECT (typefind, "Could not query upstream length!"); gst_object_unref (peer); ret = GST_FLOW_ERROR; goto pause; } /* the size if 0, we cannot continue */ if (size == 0) { /* keep message in sync with message in sink event handler */ GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (_("Stream contains no data.")), ("Can't typefind empty stream")); gst_object_unref (peer); ret = GST_FLOW_ERROR; goto pause; } ext = gst_type_find_get_extension (typefind, pad); found_caps = gst_type_find_helper_get_range (GST_OBJECT_CAST (peer), GST_OBJECT_PARENT (peer), (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)), (guint64) size, ext, &probability); g_free (ext); GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps); gst_object_unref (peer); } } if (!found_caps || probability < typefind->min_probability) { GST_DEBUG ("Trying to guess using extension"); gst_caps_replace (&found_caps, NULL); found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability); } if (!found_caps || probability < typefind->min_probability) { GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); gst_caps_replace (&found_caps, NULL); ret = GST_FLOW_ERROR; goto pause; } GST_DEBUG ("Emiting found caps %" GST_PTR_FORMAT, found_caps); gst_type_find_element_emit_have_type (typefind, probability, found_caps); typefind->mode = MODE_NORMAL; gst_caps_unref (found_caps); } else if (typefind->mode == MODE_NORMAL) { GstBuffer *outbuf = NULL; if (typefind->need_segment) { typefind->need_segment = FALSE; gst_pad_push_event (typefind->src, gst_event_new_segment (&typefind->segment)); } /* Pull 4k blocks and send downstream */ ret = gst_pad_pull_range (typefind->sink, typefind->offset, 4096, &outbuf); if (ret != GST_FLOW_OK) goto pause; typefind->offset += gst_buffer_get_size (outbuf); ret = gst_pad_push (typefind->src, outbuf); if (ret != GST_FLOW_OK) goto pause; } else { /* Error out */ ret = GST_FLOW_ERROR; goto pause; } return; pause: { const gchar *reason = gst_flow_get_name (ret); gboolean push_eos = FALSE; GST_LOG_OBJECT (typefind, "pausing task, reason %s", reason); gst_pad_pause_task (typefind->sink); if (ret == GST_FLOW_EOS) { /* perform EOS logic */ if (typefind->segment.flags & GST_SEGMENT_FLAG_SEGMENT) { gint64 stop; /* for segment playback we need to post when (in stream time) * we stopped, this is either stop (when set) or the duration. */ if ((stop = typefind->segment.stop) == -1) stop = typefind->offset; GST_LOG_OBJECT (typefind, "Sending segment done, at end of segment"); gst_element_post_message (GST_ELEMENT (typefind), gst_message_new_segment_done (GST_OBJECT (typefind), GST_FORMAT_BYTES, stop)); gst_pad_push_event (typefind->src, gst_event_new_segment_done (GST_FORMAT_BYTES, stop)); } else { push_eos = TRUE; } } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { /* for fatal errors we post an error message */ GST_ELEMENT_ERROR (typefind, STREAM, FAILED, (NULL), ("stream stopped, reason %s", reason)); push_eos = TRUE; } if (push_eos) { /* send EOS, and prevent hanging if no streams yet */ GST_LOG_OBJECT (typefind, "Sending EOS, at end of stream"); gst_pad_push_event (typefind->src, gst_event_new_eos ()); } return; } }
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 void gst_timidity_loop (GstPad * sinkpad) { GstTimidity *timidity = GST_TIMIDITY (GST_PAD_PARENT (sinkpad)); GstBuffer *out; GstFlowReturn ret; if (timidity->mididata_size == 0) { if (!gst_timidity_get_upstream_size (timidity, &timidity->mididata_size)) { GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL), ("Unable to get song length")); goto paused; } if (timidity->mididata) g_free (timidity->mididata); timidity->mididata = g_malloc (timidity->mididata_size); timidity->mididata_offset = 0; return; } if (timidity->mididata_offset < timidity->mididata_size) { GstBuffer *buffer; gint64 size; GST_DEBUG_OBJECT (timidity, "loading song"); ret = gst_pad_pull_range (timidity->sinkpad, timidity->mididata_offset, -1, &buffer); if (ret != GST_FLOW_OK) { GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL), ("Unable to load song")); goto paused; } size = timidity->mididata_size - timidity->mididata_offset; if (GST_BUFFER_SIZE (buffer) < size) size = GST_BUFFER_SIZE (buffer); memmove (timidity->mididata + timidity->mididata_offset, GST_BUFFER_DATA (buffer), size); gst_buffer_unref (buffer); timidity->mididata_offset += size; GST_DEBUG_OBJECT (timidity, "Song loaded"); return; } if (!timidity->song) { MidIStream *stream; GstTagList *tags = NULL; gchar *text; GST_DEBUG_OBJECT (timidity, "Parsing song"); stream = mid_istream_open_mem (timidity->mididata, timidity->mididata_size, 0); timidity->song = mid_song_load (stream, timidity->song_options); mid_istream_close (stream); if (!timidity->song) { GST_ELEMENT_ERROR (timidity, STREAM, DECODE, (NULL), ("Unable to parse midi")); goto paused; } mid_song_start (timidity->song); timidity->o_len = (GST_MSECOND * (GstClockTime) mid_song_get_total_time (timidity->song)) / timidity->time_per_frame; gst_segment_set_newsegment (timidity->o_segment, FALSE, 1.0, GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0); gst_pad_push_event (timidity->srcpad, gst_timidity_get_new_segment_event (timidity, GST_FORMAT_TIME, FALSE)); /* extract tags */ text = mid_song_get_meta (timidity->song, MID_SONG_TEXT); if (text) { tags = gst_tag_list_new (); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, text, NULL); //g_free (text); } text = mid_song_get_meta (timidity->song, MID_SONG_COPYRIGHT); if (text) { if (tags == NULL) tags = gst_tag_list_new (); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_COPYRIGHT, text, NULL); //g_free (text); } if (tags) { gst_element_found_tags (GST_ELEMENT (timidity), tags); } GST_DEBUG_OBJECT (timidity, "Parsing song done"); return; } if (timidity->o_segment_changed) { GstSegment *segment = gst_timidity_get_segment (timidity, GST_FORMAT_TIME, !timidity->o_new_segment); GST_LOG_OBJECT (timidity, "sending newsegment from %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT ", pos=%" GST_TIME_FORMAT, GST_TIME_ARGS ((guint64) segment->start), GST_TIME_ARGS ((guint64) segment->stop), GST_TIME_ARGS ((guint64) segment->time)); if (timidity->o_segment->flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (timidity), gst_message_new_segment_start (GST_OBJECT (timidity), segment->format, segment->start)); } gst_segment_free (segment); timidity->o_segment_changed = FALSE; return; } if (timidity->o_seek) { /* perform a seek internally */ timidity->o_segment->last_stop = timidity->o_segment->time; mid_song_seek (timidity->song, (timidity->o_segment->last_stop * timidity->time_per_frame) / GST_MSECOND); } out = gst_timidity_get_buffer (timidity); if (!out) { GST_LOG_OBJECT (timidity, "Song ended, generating eos"); gst_pad_push_event (timidity->srcpad, gst_event_new_eos ()); timidity->o_seek = FALSE; goto paused; } if (timidity->o_seek) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT); timidity->o_seek = FALSE; } gst_buffer_set_caps (out, timidity->out_caps); ret = gst_pad_push (timidity->srcpad, out); if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) goto error; return; paused: { GST_DEBUG_OBJECT (timidity, "pausing task"); gst_pad_pause_task (timidity->sinkpad); return; } error: { GST_ELEMENT_ERROR (timidity, STREAM, FAILED, ("Internal data stream error"), ("Streaming stopped, reason %s", gst_flow_get_name (ret))); gst_pad_push_event (timidity->srcpad, gst_event_new_eos ()); goto paused; } }
static void gst_real_audio_demux_loop (GstRealAudioDemux * demux) { GstFlowReturn ret; GstBuffer *buf; guint bytes_needed; /* check how much data we need */ switch (demux->state) { case REAL_AUDIO_DEMUX_STATE_MARKER: bytes_needed = 6 + 16; /* 16 are beginning of header */ break; case REAL_AUDIO_DEMUX_STATE_HEADER: if (!gst_real_audio_demux_get_data_offset_from_header (demux)) goto parse_header_error; bytes_needed = demux->data_offset - (6 + 16); break; case REAL_AUDIO_DEMUX_STATE_DATA: if (demux->packet_size > 0) { /* TODO: should probably take into account width/height as well? */ bytes_needed = demux->packet_size; } else { bytes_needed = 1024; } break; default: g_return_if_reached (); } /* now get the data */ GST_LOG_OBJECT (demux, "getting data: %5u bytes @ %8" G_GINT64_MODIFIER "u", bytes_needed, demux->offset); if (demux->upstream_size > 0 && demux->offset >= demux->upstream_size) goto eos; ret = gst_pad_pull_range (demux->sinkpad, demux->offset, bytes_needed, &buf); if (ret != GST_FLOW_OK) goto pull_range_error; if (GST_BUFFER_SIZE (buf) != bytes_needed) goto pull_range_short_read; ret = gst_real_audio_demux_handle_buffer (demux, buf); if (ret != GST_FLOW_OK) goto handle_flow_error; /* TODO: increase this in chain function too (for timestamps)? */ demux->offset += bytes_needed; /* check for the end of the segment */ if (demux->segment.stop != -1 && demux->segment.last_stop != -1 && demux->segment.last_stop > demux->segment.stop) { GST_DEBUG_OBJECT (demux, "reached end of segment"); goto eos; } return; /* ERRORS */ parse_header_error: { GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } handle_flow_error: { GST_WARNING_OBJECT (demux, "handle_buf flow: %s", gst_flow_get_name (ret)); goto pause_task; } pull_range_error: { GST_WARNING_OBJECT (demux, "pull range flow: %s", gst_flow_get_name (ret)); goto pause_task; } pull_range_short_read: { GST_WARNING_OBJECT (demux, "pull range short read: wanted %u bytes, but " "got only %u bytes", bytes_needed, GST_BUFFER_SIZE (buf)); gst_buffer_unref (buf); goto eos; } eos: { if (demux->state != REAL_AUDIO_DEMUX_STATE_DATA) { GST_WARNING_OBJECT (demux, "reached EOS before finished parsing header"); goto parse_header_error; } GST_INFO_OBJECT (demux, "EOS"); if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) != 0) { gint64 stop; /* for segment playback we need to post when (in stream time) * we stopped, this is either stop (when set) or the duration. */ if ((stop = demux->segment.stop) == -1) stop = demux->segment.duration; GST_DEBUG_OBJECT (demux, "sending segment done, at end of segment"); gst_element_post_message (GST_ELEMENT (demux), gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME, stop)); } else { /* normal playback, send EOS event downstream */ GST_DEBUG_OBJECT (demux, "sending EOS event, at end of stream"); gst_pad_push_event (demux->srcpad, gst_event_new_eos ()); } goto pause_task; } pause_task: { demux->segment_running = FALSE; gst_pad_pause_task (demux->sinkpad); GST_DEBUG_OBJECT (demux, "pausing task"); return; } }
static void gst_aiff_parse_loop (GstPad * pad) { GstFlowReturn ret; GstAiffParse *aiff = GST_AIFF_PARSE (GST_PAD_PARENT (pad)); GST_LOG_OBJECT (aiff, "process data"); switch (aiff->state) { case AIFF_PARSE_START: GST_INFO_OBJECT (aiff, "AIFF_PARSE_START"); if ((ret = gst_aiff_parse_stream_init (aiff)) != GST_FLOW_OK) goto pause; aiff->state = AIFF_PARSE_HEADER; /* fall-through */ case AIFF_PARSE_HEADER: GST_INFO_OBJECT (aiff, "AIFF_PARSE_HEADER"); if ((ret = gst_aiff_parse_stream_headers (aiff)) != GST_FLOW_OK) goto pause; aiff->state = AIFF_PARSE_DATA; GST_INFO_OBJECT (aiff, "AIFF_PARSE_DATA"); /* fall-through */ case AIFF_PARSE_DATA: if ((ret = gst_aiff_parse_stream_data (aiff)) != GST_FLOW_OK) goto pause; break; default: g_assert_not_reached (); } return; /* ERRORS */ pause: { const gchar *reason = gst_flow_get_name (ret); GST_DEBUG_OBJECT (aiff, "pausing task, reason %s", reason); aiff->segment_running = FALSE; gst_pad_pause_task (pad); if (ret == GST_FLOW_UNEXPECTED) { /* perform EOS logic */ if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) { GstClockTime stop; if ((stop = aiff->segment.stop) == -1) stop = aiff->segment.duration; gst_element_post_message (GST_ELEMENT_CAST (aiff), gst_message_new_segment_done (GST_OBJECT_CAST (aiff), aiff->segment.format, stop)); } else { gst_pad_push_event (aiff->srcpad, gst_event_new_eos ()); } } else if (ret < GST_FLOW_UNEXPECTED || ret == GST_FLOW_NOT_LINKED) { /* for fatal errors we post an error message, post the error * first so the app knows about the error first. */ GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (_("Internal data flow error.")), ("streaming task paused, reason %s (%d)", reason, ret)); gst_pad_push_event (aiff->srcpad, gst_event_new_eos ()); } return; } }
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; } }
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 void gst_pngdec_task (GstPad * pad) { GstPngDec *pngdec; GstBuffer *buffer = NULL; size_t buffer_size = 0; gint i = 0; png_bytep *rows, inp; png_uint_32 rowbytes; GstFlowReturn ret = GST_FLOW_OK; pngdec = GST_PNGDEC (GST_OBJECT_PARENT (pad)); GST_LOG_OBJECT (pngdec, "read frame"); /* Let libpng come back here on error */ if (setjmp (png_jmpbuf (pngdec->png))) { ret = GST_FLOW_ERROR; goto pause; } /* Set reading callback */ png_set_read_fn (pngdec->png, pngdec, user_read_data); /* Read info */ png_read_info (pngdec->png, pngdec->info); /* Generate the caps and configure */ ret = gst_pngdec_caps_create_and_set (pngdec); if (ret != GST_FLOW_OK) { goto pause; } /* Allocate output buffer */ rowbytes = png_get_rowbytes (pngdec->png, pngdec->info); if (rowbytes > (G_MAXUINT32 - 3) || pngdec->height > G_MAXUINT32 / rowbytes) { ret = GST_FLOW_ERROR; goto pause; } rowbytes = GST_ROUND_UP_4 (rowbytes); buffer_size = pngdec->height * rowbytes; ret = gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE, buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer); if (ret != GST_FLOW_OK) goto pause; rows = (png_bytep *) g_malloc (sizeof (png_bytep) * pngdec->height); inp = GST_BUFFER_DATA (buffer); for (i = 0; i < pngdec->height; i++) { rows[i] = inp; inp += rowbytes; } /* Read the actual picture */ png_read_image (pngdec->png, rows); g_free (rows); /* Push the raw RGB frame */ ret = gst_pad_push (pngdec->srcpad, buffer); if (ret != GST_FLOW_OK) goto pause; /* And we are done */ gst_pad_pause_task (pngdec->sinkpad); gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); return; pause: { GST_INFO_OBJECT (pngdec, "pausing task, reason %s", gst_flow_get_name (ret)); gst_pad_pause_task (pngdec->sinkpad); if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, (_("Internal data stream error.")), ("stream stopped, reason %s", gst_flow_get_name (ret))); gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); } } }
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; } }
static void gst_raw_parse_loop (GstElement * element) { GstRawParse *rp = GST_RAW_PARSE (element); GstRawParseClass *rp_class = GST_RAW_PARSE_GET_CLASS (rp); GstFlowReturn ret; GstBuffer *buffer; gint size; if (!gst_raw_parse_set_src_caps (rp)) goto no_caps; if (rp->start_segment) { GST_DEBUG_OBJECT (rp, "sending start segment"); gst_pad_push_event (rp->srcpad, rp->start_segment); rp->start_segment = NULL; } if (rp_class->multiple_frames_per_buffer && rp->framesize < 4096) size = 4096 - (4096 % rp->framesize); else size = rp->framesize; if (rp->segment.rate >= 0) { if (rp->offset + size > rp->upstream_length) { GstFormat fmt = GST_FORMAT_BYTES; if (!gst_pad_peer_query_duration (rp->sinkpad, fmt, &rp->upstream_length)) { GST_WARNING_OBJECT (rp, "Could not get upstream duration, trying to pull frame by frame"); size = rp->framesize; } else if (rp->upstream_length < rp->offset + rp->framesize) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset + size > rp->upstream_length) { size = rp->upstream_length - rp->offset; size -= size % rp->framesize; } } } else { if (rp->offset == 0) { ret = GST_FLOW_EOS; goto pause; } else if (rp->offset < size) { size -= rp->offset; } rp->offset -= size; } buffer = NULL; ret = gst_pad_pull_range (rp->sinkpad, rp->offset, size, &buffer); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (rp, "pull_range (%" G_GINT64_FORMAT ", %u) " "failed, flow: %s", rp->offset, size, gst_flow_get_name (ret)); buffer = NULL; goto pause; } if (gst_buffer_get_size (buffer) < size) { GST_DEBUG_OBJECT (rp, "Short read at offset %" G_GINT64_FORMAT ", got only %" G_GSIZE_FORMAT " of %u bytes", rp->offset, gst_buffer_get_size (buffer), size); if (size > rp->framesize) { gst_buffer_set_size (buffer, gst_buffer_get_size (buffer) - gst_buffer_get_size (buffer) % rp->framesize); } else { gst_buffer_unref (buffer); buffer = NULL; ret = GST_FLOW_EOS; goto pause; } } ret = gst_raw_parse_push_buffer (rp, buffer); if (ret != GST_FLOW_OK) goto pause; return; /* ERRORS */ no_caps: { GST_ERROR_OBJECT (rp, "could not negotiate caps"); ret = GST_FLOW_NOT_NEGOTIATED; goto pause; } pause: { const gchar *reason = gst_flow_get_name (ret); GST_LOG_OBJECT (rp, "pausing task, reason %s", reason); gst_pad_pause_task (rp->sinkpad); if (ret == GST_FLOW_EOS) { if (rp->segment.flags & GST_SEEK_FLAG_SEGMENT) { GstClockTime stop; GST_LOG_OBJECT (rp, "Sending segment done"); if ((stop = rp->segment.stop) == -1) stop = rp->segment.duration; gst_element_post_message (GST_ELEMENT_CAST (rp), gst_message_new_segment_done (GST_OBJECT_CAST (rp), rp->segment.format, stop)); gst_pad_push_event (rp->srcpad, gst_event_new_segment_done (rp->segment.format, stop)); } else { GST_LOG_OBJECT (rp, "Sending EOS, at end of stream"); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (rp, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", reason)); gst_pad_push_event (rp->srcpad, gst_event_new_eos ()); } return; } }
static void gst_musepackdec_loop (GstPad * sinkpad) { GstMusepackDec *musepackdec; GstFlowReturn flow; GstBuffer *out; #ifdef MPC_IS_OLD_API guint32 update_acc, update_bits; #else mpc_frame_info frame; mpc_status err; #endif gint num_samples, samplerate, bitspersample; musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad)); samplerate = g_atomic_int_get (&musepackdec->rate); if (samplerate == 0) { if (!gst_musepack_stream_init (musepackdec)) goto pause_task; gst_musepackdec_send_newsegment (musepackdec); samplerate = g_atomic_int_get (&musepackdec->rate); } bitspersample = g_atomic_int_get (&musepackdec->bps); flow = gst_pad_alloc_buffer_and_set_caps (musepackdec->srcpad, -1, MPC_DECODER_BUFFER_LENGTH * 4, GST_PAD_CAPS (musepackdec->srcpad), &out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } #ifdef MPC_IS_OLD_API num_samples = mpc_decoder_decode (musepackdec->d, (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out), &update_acc, &update_bits); if (num_samples < 0) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (num_samples == 0) { goto eos_and_pause; } #else frame.buffer = (MPC_SAMPLE_FORMAT *) GST_BUFFER_DATA (out); err = mpc_demux_decode (musepackdec->d, &frame); if (err != MPC_STATUS_OK) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (frame.bits == -1) { goto eos_and_pause; } num_samples = frame.samples; #endif GST_BUFFER_SIZE (out) = num_samples * bitspersample; GST_BUFFER_OFFSET (out) = musepackdec->segment.last_stop; GST_BUFFER_TIMESTAMP (out) = gst_util_uint64_scale_int (musepackdec->segment.last_stop, GST_SECOND, samplerate); GST_BUFFER_DURATION (out) = gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate); musepackdec->segment.last_stop += num_samples; GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out))); flow = gst_pad_push (musepackdec->srcpad, out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } /* check if we're at the end of a configured segment */ if (musepackdec->segment.stop != -1 && musepackdec->segment.last_stop >= musepackdec->segment.stop) { gint64 stop_time; GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment"); if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) goto eos_and_pause; GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message"); stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop, GST_SECOND, samplerate); gst_element_post_message (GST_ELEMENT (musepackdec), gst_message_new_segment_done (GST_OBJECT (musepackdec), GST_FORMAT_TIME, stop_time)); goto pause_task; } return; eos_and_pause: { GST_DEBUG_OBJECT (musepackdec, "sending EOS event"); gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ()); /* fall through to pause */ } pause_task: { GST_DEBUG_OBJECT (musepackdec, "Pausing task"); gst_pad_pause_task (sinkpad); return; } }
/* push packets from the queue to the downstream demuxer */ static void gst_rdt_manager_loop (GstPad * pad) { GstRDTManager *rdtmanager; GstRDTManagerSession *session; GstBuffer *buffer; GstFlowReturn result; rdtmanager = GST_RDT_MANAGER (GST_PAD_PARENT (pad)); session = gst_pad_get_element_private (pad); JBUF_LOCK_CHECK (session, flushing); GST_DEBUG_OBJECT (rdtmanager, "Peeking item"); while (TRUE) { /* always wait if we are blocked */ if (!session->blocked) { /* if we have a packet, we can exit the loop and grab it */ if (rdt_jitter_buffer_num_packets (session->jbuf) > 0) break; /* no packets but we are EOS, do eos logic */ if (session->eos) goto do_eos; } /* underrun, wait for packets or flushing now */ session->waiting = TRUE; JBUF_WAIT_CHECK (session, flushing); session->waiting = FALSE; } buffer = rdt_jitter_buffer_pop (session->jbuf); GST_DEBUG_OBJECT (rdtmanager, "Got item %p", buffer); if (session->discont) { GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); session->discont = FALSE; } JBUF_UNLOCK (session); result = gst_pad_push (session->recv_rtp_src, buffer); if (result != GST_FLOW_OK) goto pause; return; /* ERRORS */ flushing: { GST_DEBUG_OBJECT (rdtmanager, "we are flushing"); gst_pad_pause_task (session->recv_rtp_src); JBUF_UNLOCK (session); return; } do_eos: { /* store result, we are flushing now */ GST_DEBUG_OBJECT (rdtmanager, "We are EOS, pushing EOS downstream"); session->srcresult = GST_FLOW_EOS; gst_pad_pause_task (session->recv_rtp_src); gst_pad_push_event (session->recv_rtp_src, gst_event_new_eos ()); JBUF_UNLOCK (session); return; } pause: { GST_DEBUG_OBJECT (rdtmanager, "pausing task, reason %s", gst_flow_get_name (result)); JBUF_LOCK (session); /* store result */ session->srcresult = result; /* we don't post errors or anything because upstream will do that for us * when we pass the return value upstream. */ gst_pad_pause_task (session->recv_rtp_src); JBUF_UNLOCK (session); return; } }
static void gst_tcp_mix_src_loop (GstTCPMixSrcPad * pad) { GstTCPMixSrc *src = GST_TCP_MIX_SRC (GST_PAD_PARENT (pad)); GstBuffer *buffer = NULL; GstFlowReturn ret; /* INFO ("%p, %s", g_thread_self (), GST_PAD_NAME (pad)); */ if (!pad->running) { gst_tcp_mix_src_pad_wait_for_client (pad); pad->running = TRUE; } ret = gst_tcp_mix_src_pad_read (pad, &buffer); if (ret != GST_FLOW_OK) goto error_read_pad; ret = gst_pad_push (GST_PAD (pad), buffer); if (ret != GST_FLOW_OK) goto error_push_buffer; return; /* Handling Errors */ error_read_pad: { GST_ERROR_OBJECT (src, "Can't read from %s:%s", GST_ELEMENT_NAME (src), GST_PAD_NAME (pad)); goto pause; } error_push_buffer: { GST_ERROR_OBJECT (src, "Can't push buffer to %s:%s", GST_ELEMENT_NAME (src), GST_PAD_NAME (pad)); goto pause; } pause: { if (src->mode == MODE_LOOP) goto loop; GstEvent *event; if (ret == GST_FLOW_EOS) { event = gst_event_new_eos (); gst_pad_push_event (GST_PAD (pad), event); } else if (ret == GST_FLOW_NOT_LINKED || ret <= GST_FLOW_EOS) { event = gst_event_new_eos (); GST_ELEMENT_ERROR (src, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused (%s (%d))", gst_flow_get_name (ret), ret)); gst_pad_push_event (GST_PAD (pad), event); } /* GST_DEBUG_OBJECT (pad, "Paused %s.%s (%s)", GST_ELEMENT_NAME (src), GST_PAD_NAME (pad), gst_flow_get_name (ret)); */ gst_pad_pause_task (GST_PAD (pad)); return; } loop: { if (ret == GST_FLOW_NOT_LINKED || ret <= GST_FLOW_EOS) { GST_ELEMENT_ERROR (src, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused (%s (%d))", gst_flow_get_name (ret), ret)); } return; } }
static void gst_musepackdec_loop (GstPad * sinkpad) { GstMusepackDec *musepackdec; GstFlowReturn flow; GstBuffer *out; GstMapInfo info; mpc_frame_info frame; mpc_status err; gint num_samples, samplerate, bitspersample; musepackdec = GST_MUSEPACK_DEC (GST_PAD_PARENT (sinkpad)); samplerate = g_atomic_int_get (&musepackdec->rate); if (samplerate == 0) { if (!gst_musepack_stream_init (musepackdec)) goto pause_task; gst_musepackdec_send_newsegment (musepackdec); samplerate = g_atomic_int_get (&musepackdec->rate); } bitspersample = g_atomic_int_get (&musepackdec->bps); out = gst_buffer_new_allocate (NULL, MPC_DECODER_BUFFER_LENGTH * 4, NULL); gst_buffer_map (out, &info, GST_MAP_READWRITE); frame.buffer = (MPC_SAMPLE_FORMAT *) info.data; err = mpc_demux_decode (musepackdec->d, &frame); gst_buffer_unmap (out, &info); if (err != MPC_STATUS_OK) { GST_ERROR_OBJECT (musepackdec, "Failed to decode sample"); GST_ELEMENT_ERROR (musepackdec, STREAM, DECODE, (NULL), (NULL)); goto pause_task; } else if (frame.bits == -1) { goto eos_and_pause; } num_samples = frame.samples; gst_buffer_set_size (out, num_samples * bitspersample); GST_BUFFER_OFFSET (out) = musepackdec->segment.position; GST_BUFFER_PTS (out) = gst_util_uint64_scale_int (musepackdec->segment.position, GST_SECOND, samplerate); GST_BUFFER_DURATION (out) = gst_util_uint64_scale_int (num_samples, GST_SECOND, samplerate); musepackdec->segment.position += num_samples; GST_LOG_OBJECT (musepackdec, "Pushing buffer, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out))); flow = gst_pad_push (musepackdec->srcpad, out); if (flow != GST_FLOW_OK) { GST_DEBUG_OBJECT (musepackdec, "Flow: %s", gst_flow_get_name (flow)); goto pause_task; } /* check if we're at the end of a configured segment */ if (musepackdec->segment.stop != -1 && musepackdec->segment.position >= musepackdec->segment.stop) { gint64 stop_time; GST_DEBUG_OBJECT (musepackdec, "Reached end of configured segment"); if ((musepackdec->segment.flags & GST_SEEK_FLAG_SEGMENT) == 0) goto eos_and_pause; GST_DEBUG_OBJECT (musepackdec, "Posting SEGMENT_DONE message"); stop_time = gst_util_uint64_scale_int (musepackdec->segment.stop, GST_SECOND, samplerate); gst_element_post_message (GST_ELEMENT (musepackdec), gst_message_new_segment_done (GST_OBJECT (musepackdec), GST_FORMAT_TIME, stop_time)); gst_pad_push_event (musepackdec->srcpad, gst_event_new_segment_done (GST_FORMAT_TIME, stop_time)); goto pause_task; } return; eos_and_pause: { GST_DEBUG_OBJECT (musepackdec, "sending EOS event"); gst_pad_push_event (musepackdec->srcpad, gst_event_new_eos ()); /* fall through to pause */ } pause_task: { GST_DEBUG_OBJECT (musepackdec, "Pausing task"); gst_pad_pause_task (sinkpad); return; } }
static void gst_wildmidi_loop (GstPad * sinkpad) { GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad)); GstFlowReturn ret; switch (wildmidi->state) { case GST_WILDMIDI_STATE_LOAD: { GstBuffer *buffer = NULL; GST_DEBUG_OBJECT (wildmidi, "loading song"); ret = gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer); if (ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (wildmidi, "Song loaded"); wildmidi->state = GST_WILDMIDI_STATE_PARSE; } else if (ret != GST_FLOW_OK) { GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL), ("Unable to read song")); goto pause; } else { GST_DEBUG_OBJECT (wildmidi, "pushing buffer"); gst_adapter_push (wildmidi->adapter, buffer); wildmidi->offset += gst_buffer_get_size (buffer); } break; } case GST_WILDMIDI_STATE_PARSE: ret = gst_wildmidi_parse_song (wildmidi); if (ret != GST_FLOW_OK) goto pause; wildmidi->state = GST_WILDMIDI_STATE_PLAY; break; case GST_WILDMIDI_STATE_PLAY: ret = gst_wildmidi_do_play (wildmidi); if (ret != GST_FLOW_OK) goto pause; break; default: break; } return; pause: { const gchar *reason = gst_flow_get_name (ret); GstEvent *event; GST_DEBUG_OBJECT (wildmidi, "pausing task, reason %s", reason); gst_pad_pause_task (sinkpad); if (ret == GST_FLOW_EOS) { /* perform EOS logic */ event = gst_event_new_eos (); gst_pad_push_event (wildmidi->srcpad, event); } 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. */ GST_ELEMENT_ERROR (wildmidi, STREAM, FAILED, ("Internal data flow error."), ("streaming task paused, reason %s (%d)", reason, ret)); gst_pad_push_event (wildmidi->srcpad, event); } } }
/* 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 void gst_amc_audio_dec_loop (GstAmcAudioDec * self) { GstFlowReturn flow_ret = GST_FLOW_OK; gboolean is_eos; GstAmcBufferInfo buffer_info; gint idx; GST_AUDIO_DECODER_STREAM_LOCK (self); retry: /*if (self->input_caps_changed) { idx = INFO_OUTPUT_FORMAT_CHANGED; } else { */ GST_DEBUG_OBJECT (self, "Waiting for available output buffer"); GST_AUDIO_DECODER_STREAM_UNLOCK (self); /* Wait at most 100ms here, some codecs don't fail dequeueing if * the codec is flushing, causing deadlocks during shutdown */ idx = gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000); GST_AUDIO_DECODER_STREAM_LOCK (self); /*} */ if (idx < 0) { if (self->flushing) goto flushing; switch (idx) { case INFO_OUTPUT_BUFFERS_CHANGED:{ GST_DEBUG_OBJECT (self, "Output buffers have changed"); if (self->output_buffers) gst_amc_codec_free_buffers (self->output_buffers, self->n_output_buffers); self->output_buffers = gst_amc_codec_get_output_buffers (self->codec, &self->n_output_buffers); if (!self->output_buffers) goto get_output_buffers_error; break; } case INFO_OUTPUT_FORMAT_CHANGED:{ GstAmcFormat *format; gchar *format_string; GST_DEBUG_OBJECT (self, "Output format has changed"); format = gst_amc_codec_get_output_format (self->codec); if (!format) goto format_error; format_string = gst_amc_format_to_string (format); GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string); g_free (format_string); if (!gst_amc_audio_dec_set_src_caps (self, format)) { gst_amc_format_free (format); goto format_error; } gst_amc_format_free (format); if (self->output_buffers) gst_amc_codec_free_buffers (self->output_buffers, self->n_output_buffers); self->output_buffers = gst_amc_codec_get_output_buffers (self->codec, &self->n_output_buffers); if (!self->output_buffers) goto get_output_buffers_error; goto retry; break; } case INFO_TRY_AGAIN_LATER: GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out"); goto retry; break; case G_MININT: GST_ERROR_OBJECT (self, "Failure dequeueing output buffer"); goto dequeue_error; break; default: g_assert_not_reached (); break; } goto retry; } GST_DEBUG_OBJECT (self, "Got output buffer at index %d: size %d time %" G_GINT64_FORMAT " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us, buffer_info.flags); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); self->n_buffers++; if (buffer_info.size > 0) { GstAmcAudioDecClass *klass = GST_AMC_AUDIO_DEC_GET_CLASS (self); GstBuffer *outbuf; GstAmcBuffer *buf; GstMapInfo minfo; /* This sometimes happens at EOS or if the input is not properly framed, * let's handle it gracefully by allocating a new buffer for the current * caps and filling it */ if (idx >= self->n_output_buffers) goto invalid_buffer_index; if (strcmp (klass->codec_info->name, "OMX.google.mp3.decoder") == 0) { /* Google's MP3 decoder outputs garbage in the first output buffer * so we just drop it here */ if (self->n_buffers == 1) { GST_DEBUG_OBJECT (self, "Skipping first buffer of Google MP3 decoder output"); goto done; } } outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self), buffer_info.size); if (!outbuf) goto failed_allocate; gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); buf = &self->output_buffers[idx]; if (self->needs_reorder) { gint i, n_samples, c, n_channels; gint *reorder_map = self->reorder_map; gint16 *dest, *source; dest = (gint16 *) minfo.data; source = (gint16 *) (buf->data + buffer_info.offset); n_samples = buffer_info.size / self->info.bpf; n_channels = self->info.channels; for (i = 0; i < n_samples; i++) { for (c = 0; c < n_channels; c++) { dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c]; } } } else { orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size); } gst_buffer_unmap (outbuf, &minfo); /* FIXME: We should get one decoded input frame here for * every buffer. If this is not the case somewhere, we will * error out at some point and will need to add workarounds */ flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1); } done: if (!gst_amc_codec_release_output_buffer (self->codec, idx)) goto failed_release; if (is_eos || flow_ret == GST_FLOW_EOS) { GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); if (self->draining) { GST_DEBUG_OBJECT (self, "Drained"); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); } else if (flow_ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (self, "Component signalled EOS"); flow_ret = GST_FLOW_EOS; } g_mutex_unlock (&self->drain_lock); GST_AUDIO_DECODER_STREAM_LOCK (self); } else { GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); } self->downstream_flow_ret = flow_ret; if (flow_ret != GST_FLOW_OK) goto flow_error; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; dequeue_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to dequeue output buffer")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } get_output_buffers_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to get output buffers")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } format_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to handle format")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } failed_release: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to release output buffer index %d", idx)); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_FLUSHING; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } flow_error: { if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } invalid_buffer_index: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } failed_allocate: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to allocate output buffer")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } }