static void udpsink_test (gboolean use_buffer_lists) { GstElement *udpsink; GstPad *srcpad; GstBufferList *list; guint data_size; list = _create_buffer_list (&data_size); udpsink = gst_check_setup_element ("udpsink"); if (use_buffer_lists) _set_render_function (udpsink); srcpad = gst_check_setup_src_pad_by_name (udpsink, &srctemplate, "sink"); gst_element_set_state (udpsink, GST_STATE_PLAYING); gst_pad_push_event (srcpad, gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0)); gst_pad_push_list (srcpad, list); gst_check_teardown_pad_by_name (udpsink, "sink"); gst_check_teardown_element (udpsink); if (use_buffer_lists) fail_if (data_size != render_list_bytes_received); }
/** * gst_event_new_new_segment: * @update: is this segment an update to a previous one * @rate: a new rate for playback * @format: The format of the segment values * @start: the start value of the segment * @stop: the stop value of the segment * @position: stream position * * Allocate a new newsegment event with the given format/values tripplets * * This method calls gst_event_new_new_segment_full() passing a default * value of 1.0 for applied_rate * * Returns: (transfer full): a new newsegment event. */ GstEvent * gst_event_new_new_segment (gboolean update, gdouble rate, GstFormat format, gint64 start, gint64 stop, gint64 position) { return gst_event_new_new_segment_full (update, rate, 1.0, format, start, stop, position); }
static HRESULT WINAPI Gstreamer_transform_NewSegment(TransformFilter *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { GstTfImpl *This = (GstTfImpl*)iface; TRACE("%p\n", This); gst_pad_push_event(This->my_src, gst_event_new_new_segment_full(1, 1.0, dRate, GST_FORMAT_TIME, 0, tStop <= tStart ? -1 : tStop * 100, tStart*100)); return S_OK; }
static GstFlowReturn gst_real_audio_demux_parse_data (GstRealAudioDemux * demux) { GstFlowReturn ret = GST_FLOW_OK; guint avail, unit_size; avail = gst_adapter_available (demux->adapter); if (demux->packet_size > 0) unit_size = demux->packet_size; else unit_size = avail & 0xfffffff0; /* round down to next multiple of 16 */ GST_LOG_OBJECT (demux, "available = %u, unit_size = %u", avail, unit_size); while (ret == GST_FLOW_OK && unit_size > 0 && avail >= unit_size) { GstClockTime ts; const guint8 *data; GstBuffer *buf = NULL; buf = gst_buffer_new_and_alloc (unit_size); gst_buffer_set_caps (buf, GST_PAD_CAPS (demux->srcpad)); data = gst_adapter_peek (demux->adapter, unit_size); memcpy (GST_BUFFER_DATA (buf), data, unit_size); gst_adapter_flush (demux->adapter, unit_size); avail -= unit_size; if (demux->need_newsegment) { gst_pad_push_event (demux->srcpad, gst_event_new_new_segment_full (FALSE, demux->segment.rate, demux->segment.applied_rate, GST_FORMAT_TIME, demux->segment.start, demux->segment.stop, demux->segment.time)); demux->need_newsegment = FALSE; } if (demux->pending_tags) { gst_element_found_tags_for_pad (GST_ELEMENT (demux), demux->srcpad, demux->pending_tags); demux->pending_tags = NULL; } if (demux->fourcc == GST_RM_AUD_DNET) { buf = gst_rm_utils_descramble_dnet_buffer (buf); } ts = gst_real_demux_get_timestamp_from_offset (demux, demux->offset); GST_BUFFER_TIMESTAMP (buf) = ts; gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME, ts); ret = gst_pad_push (demux->srcpad, buf); } return ret; }
static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) { RsnStreamSelector *sel; GstFlowReturn res; GstPad *active_sinkpad; RsnSelectorPad *selpad; GstClockTime timestamp; GstSegment *seg; sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad)); selpad = GST_SELECTOR_PAD_CAST (pad); seg = &selpad->segment; active_sinkpad = rsn_stream_selector_get_active (sel, pad); timestamp = GST_BUFFER_TIMESTAMP (buf); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); gst_segment_set_last_stop (seg, seg->format, timestamp); } /* Ignore buffers from pads except the selected one */ if (pad != active_sinkpad) goto ignore; /* if we have a pending segment, push it out now */ if (selpad->segment_pending) { gst_pad_push_event (sel->srcpad, gst_event_new_new_segment_full (FALSE, seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop, seg->time)); selpad->segment_pending = FALSE; } /* forward */ GST_DEBUG_OBJECT (sel, "Forwarding buffer %p from pad %s:%s", buf, GST_DEBUG_PAD_NAME (pad)); res = gst_pad_push (sel->srcpad, buf); done: gst_object_unref (sel); return res; /* dropped buffers */ ignore: { GST_DEBUG_OBJECT (sel, "Ignoring buffer %p from pad %s:%s", buf, GST_DEBUG_PAD_NAME (pad)); gst_buffer_unref (buf); res = GST_FLOW_NOT_LINKED; goto done; } }
static void distribute_running_time (GstElement * element, const GstSegment * segment) { GstEvent *event; GstPad *pad; pad = gst_element_get_static_pad (element, "sink"); if (segment->accum) { event = gst_event_new_new_segment_full (FALSE, segment->rate, segment->applied_rate, segment->format, 0, segment->accum, 0); gst_pad_push_event (pad, event); } event = gst_event_new_new_segment_full (FALSE, segment->rate, segment->applied_rate, segment->format, segment->start, segment->stop, segment->time); gst_pad_push_event (pad, event); gst_object_unref (pad); }
static GstEvent * gst_timidity_get_new_segment_event (GstTimidity * timidity, GstFormat format, gboolean update) { GstSegment *segment; GstEvent *event; segment = gst_timidity_get_segment (timidity, format, update); event = gst_event_new_new_segment_full (update, segment->rate, segment->applied_rate, segment->format, segment->start, segment->stop, segment->time); gst_segment_free (segment); return event; }
static VALUE newsegment_initialize(VALUE self, VALUE update, VALUE rate, VALUE applied_rate, VALUE format, VALUE start, VALUE stop, VALUE position) { GstEvent *event; event = gst_event_new_new_segment_full(RVAL2CBOOL(update), NUM2DBL(rate), NUM2DBL(applied_rate), RVAL2GST_FORMAT(format), NUM2LL(start), NUM2LL(stop), NUM2LL(position)); G_INITIALIZE(self, event); return Qnil; }
static GstEvent * create_segment_event (GstRDTDepay * depay, gboolean update, GstClockTime position) { GstEvent *event; GstClockTime stop; if (depay->npt_stop != -1) stop = depay->npt_stop - depay->npt_start; else stop = -1; event = gst_event_new_new_segment_full (update, depay->play_speed, depay->play_scale, GST_FORMAT_TIME, position, stop, position + depay->npt_start); return event; }
static GstEvent * create_segment_event (GstBaseRTPDepayload * filter, gboolean update, GstClockTime position) { GstEvent *event; GstClockTime stop; GstBaseRTPDepayloadPrivate *priv; priv = filter->priv; if (priv->npt_stop != -1) stop = priv->npt_stop - priv->npt_start; else stop = -1; event = gst_event_new_new_segment_full (update, priv->play_speed, priv->play_scale, GST_FORMAT_TIME, position, stop, position + priv->npt_start); return event; }
static gboolean gst_vcd_parse_sink_event (GstPad * pad, GstEvent * event) { GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad)); gboolean res; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT:{ GstFormat format; gboolean update; gdouble rate, applied_rate; gint64 start, stop, position; gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &position); if (format == GST_FORMAT_BYTES) { gst_event_unref (event); event = gst_event_new_new_segment_full (update, rate, applied_rate, GST_FORMAT_BYTES, gst_vcd_parse_get_out_offset (start), gst_vcd_parse_get_out_offset (stop), position); } else { GST_WARNING_OBJECT (vcd, "newsegment event in non-byte format"); } res = gst_pad_event_default (pad, event); break; } case GST_EVENT_FLUSH_START: gst_adapter_clear (vcd->adapter); /* fall through */ default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (vcd); return res; }
static GstEvent * gst_wildmidi_get_new_segment_event (GstWildmidi * wildmidi, GstFormat format) { gint64 start, stop, time; GstSegment *segment; GstEvent *event; GstFormat src_format; segment = wildmidi->o_segment; src_format = segment->format; /* convert the segment values to the target format */ gst_wildmidi_src_convert (wildmidi, src_format, segment->start, &format, &start); gst_wildmidi_src_convert (wildmidi, src_format, segment->stop, &format, &stop); gst_wildmidi_src_convert (wildmidi, src_format, segment->time, &format, &time); event = gst_event_new_new_segment_full (FALSE, segment->rate, segment->applied_rate, format, start, stop, time); return event; }
static GstFlowReturn fs_funnel_chain (GstPad * pad, GstBuffer * buffer) { GstFlowReturn res; FsFunnel *funnel = FS_FUNNEL (gst_pad_get_parent (pad)); FsFunnelPadPrivate *priv = gst_pad_get_element_private (pad); GstEvent *event = NULL; GstClockTime newts; GstCaps *padcaps; GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer); GST_OBJECT_LOCK (funnel); if (priv->segment.format == GST_FORMAT_UNDEFINED) { GST_WARNING_OBJECT (funnel, "Got buffer without segment," " setting segment [0,inf["); gst_segment_set_newsegment_full (&priv->segment, FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0); } if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) gst_segment_set_last_stop (&priv->segment, priv->segment.format, GST_BUFFER_TIMESTAMP (buffer)); newts = gst_segment_to_running_time (&priv->segment, priv->segment.format, GST_BUFFER_TIMESTAMP (buffer)); if (newts != GST_BUFFER_TIMESTAMP (buffer)) { buffer = gst_buffer_make_metadata_writable (buffer); GST_BUFFER_TIMESTAMP (buffer) = newts; } if (!funnel->has_segment) { event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0); funnel->has_segment = TRUE; } GST_OBJECT_UNLOCK (funnel); if (event) { if (!gst_pad_push_event (funnel->srcpad, event)) GST_WARNING_OBJECT (funnel, "Could not push out newsegment event"); } GST_OBJECT_LOCK (pad); padcaps = GST_PAD_CAPS (funnel->srcpad); GST_OBJECT_UNLOCK (pad); if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) { if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) { res = GST_FLOW_NOT_NEGOTIATED; goto out; } } res = gst_pad_push (funnel->srcpad, buffer); GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res)); out: gst_object_unref (funnel); return res; }
static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf) { GstInputSelector *sel; GstFlowReturn res; GstPad *active_sinkpad; GstPad *prev_active_sinkpad; GstSelectorPad *selpad; GstClockTime start_time; GstSegment *seg; GstEvent *close_event = NULL, *start_event = NULL; GstCaps *caps; sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad)); selpad = GST_SELECTOR_PAD_CAST (pad); seg = &selpad->segment; GST_INPUT_SELECTOR_LOCK (sel); /* wait or check for flushing */ if (gst_input_selector_wait (sel, pad)) goto flushing; GST_LOG_OBJECT (pad, "getting active pad"); prev_active_sinkpad = sel->active_sinkpad; active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); /* update the segment on the srcpad */ start_time = GST_BUFFER_TIMESTAMP (buf); if (GST_CLOCK_TIME_IS_VALID (start_time)) { GST_LOG_OBJECT (pad, "received start time %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time)); if (GST_BUFFER_DURATION_IS_VALID (buf)) GST_LOG_OBJECT (pad, "received end time %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time + GST_BUFFER_DURATION (buf))); GST_OBJECT_LOCK (pad); gst_segment_set_last_stop (seg, seg->format, start_time); GST_OBJECT_UNLOCK (pad); } /* Ignore buffers from pads except the selected one */ if (pad != active_sinkpad) goto ignore; if (G_UNLIKELY (sel->pending_close)) { GstSegment *cseg = &sel->segment; GST_DEBUG_OBJECT (sel, "pushing close NEWSEGMENT update %d, rate %lf, applied rate %lf, " "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT, TRUE, cseg->rate, cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time); /* create update segment */ close_event = gst_event_new_new_segment_full (TRUE, cseg->rate, cseg->applied_rate, cseg->format, cseg->start, cseg->stop, cseg->time); sel->pending_close = FALSE; } /* if we have a pending segment, push it out now */ if (G_UNLIKELY (selpad->segment_pending)) { GST_DEBUG_OBJECT (pad, "pushing pending NEWSEGMENT update %d, rate %lf, applied rate %lf, " "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT, FALSE, seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop, seg->time); start_event = gst_event_new_new_segment_full (FALSE, seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop, seg->time); selpad->segment_pending = FALSE; } GST_INPUT_SELECTOR_UNLOCK (sel); if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad) g_object_notify (G_OBJECT (sel), "active-pad"); if (close_event) gst_pad_push_event (sel->srcpad, close_event); if (start_event) gst_pad_push_event (sel->srcpad, start_event); if (selpad->discont) { buf = gst_buffer_make_metadata_writable (buf); GST_DEBUG_OBJECT (pad, "Marking discont buffer %p", buf); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); selpad->discont = FALSE; } /* forward */ GST_LOG_OBJECT (pad, "Forwarding buffer %p", buf); if ((caps = GST_BUFFER_CAPS (buf))) { if (GST_PAD_CAPS (sel->srcpad) != caps) gst_pad_set_caps (sel->srcpad, caps); } res = gst_pad_push (sel->srcpad, buf); done: gst_object_unref (sel); return res; /* dropped buffers */ ignore: { GST_DEBUG_OBJECT (pad, "Pad not active, discard buffer %p", buf); /* when we drop a buffer, we're creating a discont on this pad */ selpad->discont = TRUE; GST_INPUT_SELECTOR_UNLOCK (sel); gst_buffer_unref (buf); /* figure out what to return upstream */ GST_OBJECT_LOCK (selpad); if (selpad->always_ok) res = GST_FLOW_OK; else res = GST_FLOW_NOT_LINKED; GST_OBJECT_UNLOCK (selpad); goto done; } flushing: { GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf); GST_INPUT_SELECTOR_UNLOCK (sel); gst_buffer_unref (buf); res = GST_FLOW_WRONG_STATE; goto done; } }
static GstFlowReturn theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet) { GstCaps *caps; gint par_num, par_den; GstFlowReturn ret = GST_FLOW_OK; gboolean eret; GstEvent *event; guint32 bitstream_version; GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d", dec->info.fps_numerator, dec->info.fps_denominator, dec->info.aspect_numerator, dec->info.aspect_denominator); /* calculate par * the info.aspect_* values reflect PAR; * 0:0 is allowed and can be interpreted as 1:1, so correct for it. * x:0 for other x isn't technically allowed, but it's seen in the wild and * is reasonable to treat the same. */ par_num = dec->info.aspect_numerator; par_den = dec->info.aspect_denominator; if (par_den == 0) { par_num = par_den = 1; } /* theora has: * * width/height : dimension of the encoded frame * frame_width/frame_height : dimension of the visible part * offset_x/offset_y : offset in encoded frame where visible part starts */ GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width, dec->info.height, par_num, par_den); GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d", dec->info.frame_width, dec->info.frame_height, dec->info.offset_x, dec->info.offset_y); if (dec->info.pixelformat != OC_PF_420) { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("pixel formats other than 4:2:0 not yet supported")); return GST_FLOW_ERROR; } if (dec->crop) { /* add black borders to make width/height/offsets even. we need this because * we cannot express an offset to the peer plugin. */ dec->width = GST_ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1)); dec->height = GST_ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1)); dec->offset_x = dec->info.offset_x & ~1; dec->offset_y = dec->info.offset_y & ~1; } else { /* no cropping, use the encoded dimensions */ dec->width = dec->info.width; dec->height = dec->info.height; dec->offset_x = 0; dec->offset_y = 0; } dec->granule_shift = _theora_ilog (dec->info.keyframe_frequency_force - 1); /* With libtheora-1.0beta1 the granulepos scheme was changed: * where earlier the granulepos refered to the index/beginning * of a frame, it now refers to the end, which matches the use * in vorbis/speex. We check the bitstream version from the header so * we know which way to interpret the incoming granuepos */ bitstream_version = (dec->info.version_major << 16) | (dec->info.version_minor << 8) | dec->info.version_subminor; dec->is_old_bitstream = (bitstream_version <= 0x00030200); GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d", dec->width, dec->height, dec->offset_x, dec->offset_y); /* done */ theora_decode_init (&dec->state, &dec->info); caps = gst_caps_new_simple ("video/x-raw-yuv", "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), "framerate", GST_TYPE_FRACTION, dec->info.fps_numerator, dec->info.fps_denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den, "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL); gst_pad_set_caps (dec->srcpad, caps); gst_caps_unref (caps); dec->have_header = TRUE; if (!dec->sent_newsegment) { GST_DEBUG_OBJECT (dec, "Sending newsegment event"); event = gst_event_new_new_segment_full (FALSE, dec->segment.rate, dec->segment.applied_rate, dec->segment.format, dec->segment.start, dec->segment.stop, dec->segment.time); eret = gst_pad_push_event (dec->srcpad, event); dec->sent_newsegment = TRUE; } if (dec->tags) { gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), dec->srcpad, dec->tags); dec->tags = NULL; } return ret; }
static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event) { GstAuParse *auparse; gboolean ret = TRUE; auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NEWSEGMENT: { GstFormat format; gdouble rate, arate; gint64 start, stop, time, offset = 0; gboolean update; GstSegment segment; GstEvent *new_event = NULL; gst_segment_init (&segment, GST_FORMAT_UNDEFINED); gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time); gst_segment_set_newsegment_full (&segment, update, rate, arate, format, start, stop, time); if (auparse->sample_size > 0) { if (start > 0) { offset = start; start -= auparse->offset; start = MAX (start, 0); } if (stop > 0) { stop -= auparse->offset; stop = MAX (stop, 0); } gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, start, GST_FORMAT_TIME, &start); gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, stop, GST_FORMAT_TIME, &stop); } if (auparse->srcpad) { GST_INFO_OBJECT (auparse, "new segment: %" GST_TIME_FORMAT " ... %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); new_event = gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, start, stop, start); ret = gst_pad_push_event (auparse->srcpad, new_event); } auparse->buffer_offset = offset; gst_event_unref (event); break; } case GST_EVENT_EOS: if (!auparse->srcpad) { GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, ("No valid input found before end of stream"), (NULL)); } /* fall-through */ default: ret = gst_pad_event_default (pad, event); break; } gst_object_unref (auparse); return ret; }
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 GstFlowReturn gst_interleave_collected (GstCollectPads * pads, GstInterleave * self) { guint size; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; GSList *collected; guint nsamples; guint ncollected = 0; gboolean empty = TRUE; gint width = self->width / 8; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED); size = gst_collect_pads_available (pads); g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR); GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size, self->channels); nsamples = size / width; ret = gst_pad_alloc_buffer (self->src, GST_BUFFER_OFFSET_NONE, size * self->channels, GST_PAD_CAPS (self->src), &outbuf); if (ret != GST_FLOW_OK) { return ret; } else if (outbuf == NULL || GST_BUFFER_SIZE (outbuf) < size * self->channels) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } else if (!gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), GST_PAD_CAPS (self->src))) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels); for (collected = pads->data; collected != NULL; collected = collected->next) { GstCollectData *cdata; GstBuffer *inbuf; guint8 *outdata; cdata = (GstCollectData *) collected->data; inbuf = gst_collect_pads_take_buffer (pads, cdata, size); if (inbuf == NULL) { GST_DEBUG_OBJECT (cdata->pad, "No buffer available"); goto next; } ncollected++; if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) goto next; empty = FALSE; outdata = GST_BUFFER_DATA (outbuf) + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel; self->func (outdata, GST_BUFFER_DATA (inbuf), self->channels, nsamples); next: if (inbuf) gst_buffer_unref (inbuf); } if (ncollected == 0) goto eos; if (self->segment_pending) { GstEvent *event; event = gst_event_new_new_segment_full (FALSE, self->segment_rate, 1.0, GST_FORMAT_TIME, self->timestamp, -1, self->segment_position); gst_pad_push_event (self->src, event); self->segment_pending = FALSE; self->segment_position = 0; } GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp; GST_BUFFER_OFFSET (outbuf) = self->offset; self->offset += nsamples; self->timestamp = gst_util_uint64_scale_int (self->offset, GST_SECOND, self->rate); GST_BUFFER_DURATION (outbuf) = self->timestamp - GST_BUFFER_TIMESTAMP (outbuf); if (empty) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } }
static gboolean gst_raw_parse_sink_event (GstPad * pad, GstEvent * event) { GstRawParse *rp = GST_RAW_PARSE (gst_pad_get_parent (pad)); gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: case GST_EVENT_FLUSH_STOP: /* Only happens in push mode */ gst_raw_parse_reset (rp); ret = gst_pad_push_event (rp->srcpad, event); break; case GST_EVENT_NEWSEGMENT: { GstClockTimeDiff start, stop, time; gdouble rate, arate; gboolean update; GstFormat format; /* Only happens in push mode */ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, &start, &stop, &time); if (format == GST_FORMAT_TIME) { gst_segment_set_newsegment_full (&rp->segment, update, rate, arate, GST_FORMAT_TIME, start, stop, time); ret = gst_pad_push_event (rp->srcpad, event); } else { gst_event_unref (event); ret = gst_raw_parse_convert (rp, format, start, GST_FORMAT_TIME, &start); ret &= gst_raw_parse_convert (rp, format, time, GST_FORMAT_TIME, &time); ret &= gst_raw_parse_convert (rp, format, stop, GST_FORMAT_TIME, &stop); if (!ret) { GST_ERROR_OBJECT (rp, "Failed converting to GST_FORMAT_TIME format (%d)", format); break; } gst_segment_set_newsegment_full (&rp->segment, update, rate, arate, GST_FORMAT_TIME, start, stop, time); /* create new segment with the fields converted to time */ event = gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, start, stop, time); ret = gst_pad_push_event (rp->srcpad, event); } break; } default: ret = gst_pad_event_default (rp->sinkpad, event); break; } gst_object_unref (rp); return ret; }
static void gst_live_adder_loop (gpointer data) { GstLiveAdder *adder = GST_LIVE_ADDER (data); GstClockTime buffer_timestamp = 0; GstClockTime sync_time = 0; GstClock *clock = NULL; GstClockID id = NULL; GstClockReturn ret; GstBuffer *buffer = NULL; GstFlowReturn result; GstEvent *newseg_event = NULL; GST_OBJECT_LOCK (adder); again: for (;;) { if (adder->srcresult != GST_FLOW_OK) goto flushing; if (!g_queue_is_empty (adder->buffers)) break; if (check_eos_locked (adder)) goto eos; g_cond_wait (adder->not_empty_cond, GST_OBJECT_GET_LOCK (adder)); } buffer_timestamp = GST_BUFFER_TIMESTAMP (g_queue_peek_head (adder->buffers)); clock = GST_ELEMENT_CLOCK (adder); /* If we have no clock, then we can't do anything.. error */ if (!clock) { if (adder->playing) goto no_clock; else goto push_buffer; } GST_DEBUG_OBJECT (adder, "sync to timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (buffer_timestamp)); sync_time = buffer_timestamp + GST_ELEMENT_CAST (adder)->base_time; /* add latency, this includes our own latency and the peer latency. */ sync_time += adder->latency_ms * GST_MSECOND; sync_time += adder->peer_latency; /* create an entry for the clock */ id = adder->clock_id = gst_clock_new_single_shot_id (clock, sync_time); GST_OBJECT_UNLOCK (adder); ret = gst_clock_id_wait (id, NULL); GST_OBJECT_LOCK (adder); /* and free the entry */ gst_clock_id_unref (id); adder->clock_id = NULL; /* at this point, the clock could have been unlocked by a timeout, a new * head element was added to the queue or because we are shutting down. Check * for shutdown first. */ if (adder->srcresult != GST_FLOW_OK) goto flushing; if (ret == GST_CLOCK_UNSCHEDULED) { GST_DEBUG_OBJECT (adder, "Wait got unscheduled, will retry to push with new buffer"); goto again; } if (ret != GST_CLOCK_OK && ret != GST_CLOCK_EARLY) goto clock_error; push_buffer: buffer = g_queue_pop_head (adder->buffers); if (!buffer) goto again; /* * We make sure the timestamps are exactly contiguous * If its only small skew (due to rounding errors), we correct it * silently. Otherwise we put the discont flag */ if (GST_CLOCK_TIME_IS_VALID (adder->next_timestamp) && GST_BUFFER_TIMESTAMP (buffer) != adder->next_timestamp) { GstClockTimeDiff diff = GST_CLOCK_DIFF (GST_BUFFER_TIMESTAMP (buffer), adder->next_timestamp); if (diff < 0) diff = -diff; if (diff < GST_SECOND / adder->rate) { GST_BUFFER_TIMESTAMP (buffer) = adder->next_timestamp; GST_DEBUG_OBJECT (adder, "Correcting slight skew"); GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); } else { GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); GST_DEBUG_OBJECT (adder, "Expected buffer at %" GST_TIME_FORMAT ", but is at %" GST_TIME_FORMAT ", setting discont", GST_TIME_ARGS (adder->next_timestamp), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); } } else { GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT); } GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE; GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE; if (GST_BUFFER_DURATION_IS_VALID (buffer)) adder->next_timestamp = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); else adder->next_timestamp = GST_CLOCK_TIME_NONE; if (adder->segment_pending) { /* * We set the start at 0, because we re-timestamps to the running time */ newseg_event = gst_event_new_new_segment_full (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0, -1, 0); adder->segment_pending = FALSE; } GST_OBJECT_UNLOCK (adder); if (newseg_event) gst_pad_push_event (adder->srcpad, newseg_event); GST_LOG_OBJECT (adder, "About to push buffer time:%" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer))); result = gst_pad_push (adder->srcpad, buffer); if (result != GST_FLOW_OK) goto pause; return; flushing: { GST_DEBUG_OBJECT (adder, "we are flushing"); gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); return; } clock_error: { gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); GST_ELEMENT_ERROR (adder, STREAM, MUX, ("Error with the clock"), ("Error with the clock: %d", ret)); GST_ERROR_OBJECT (adder, "Error with the clock: %d", ret); return; } no_clock: { gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); GST_ELEMENT_ERROR (adder, STREAM, MUX, ("No available clock"), ("No available clock")); GST_ERROR_OBJECT (adder, "No available clock"); return; } pause: { GST_DEBUG_OBJECT (adder, "pausing task, reason %s", gst_flow_get_name (result)); GST_OBJECT_LOCK (adder); /* store result */ adder->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 (adder->srcpad); GST_OBJECT_UNLOCK (adder); return; } eos: { /* store result, we are flushing now */ GST_DEBUG_OBJECT (adder, "We are EOS, pushing EOS downstream"); adder->srcresult = GST_FLOW_UNEXPECTED; gst_pad_pause_task (adder->srcpad); GST_OBJECT_UNLOCK (adder); gst_pad_push_event (adder->srcpad, gst_event_new_eos ()); return; } }
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_set_seek (&seeksegment, rate, format, flags, start_type, start, stop_type, stop, NULL); } /* get the desired position */ last_stop = seeksegment.last_stop; 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 ()); gst_pad_push_event (rp->srcpad, gst_event_new_flush_stop ()); } else if (ret && rp->running) { /* we are running the current segment and doing a non-flushing seek, * close the segment first based on the last_stop. */ GST_DEBUG_OBJECT (rp, "prepare close segment %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT, rp->segment.start, rp->segment.last_stop); /* queue the segment for sending in the stream thread */ if (rp->close_segment) gst_event_unref (rp->close_segment); rp->close_segment = gst_event_new_new_segment_full (TRUE, rp->segment.rate, rp->segment.applied_rate, rp->segment.format, rp->segment.start, rp->segment.last_stop, rp->segment.time); } 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.last_stop)); } /* 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); if (rp->segment.rate >= 0.0) { /* forward, we send data from last_stop to stop */ rp->start_segment = gst_event_new_new_segment_full (FALSE, rp->segment.rate, rp->segment.applied_rate, rp->segment.format, rp->segment.last_stop, stop, rp->segment.time); } else { /* reverse, we send data from last_stop to start */ rp->start_segment = gst_event_new_new_segment_full (FALSE, rp->segment.rate, rp->segment.applied_rate, rp->segment.format, rp->segment.start, rp->segment.last_stop, rp->segment.time); } } rp->discont = TRUE; GST_LOG_OBJECT (rp, "start streaming"); rp->running = TRUE; gst_pad_start_task (rp->sinkpad, (GstTaskFunction) gst_raw_parse_loop, rp); 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; } }