static gboolean gst_gme_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstGmeDec *gme = GST_GME_DEC (parent); gboolean result = TRUE; gboolean forward = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: /* we get EOS when we loaded the complete file, now try to initialize the * decoding */ if (!(result = gme_setup (gme))) { /* can't start, post an ERROR and push EOS downstream */ GST_ELEMENT_ERROR (gme, STREAM, DEMUX, (NULL), ("can't start playback")); forward = TRUE; } break; case GST_EVENT_CAPS: case GST_EVENT_SEGMENT: break; default: forward = TRUE; break; } if (forward) result = gst_pad_push_event (gme->srcpad, event); else gst_event_unref (event); return result; }
static GstStateChangeReturn gst_gme_dec_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn result; GstGmeDec *dec; dec = GST_GME_DEC (element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: dec->total_duration = GST_CLOCK_TIME_NONE; break; default: break; } result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (result == GST_STATE_CHANGE_FAILURE) return result; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: gst_adapter_clear (dec->adapter); if (dec->player) { gme_delete (dec->player); dec->player = NULL; } break; default: break; } return result; }
static void gst_gme_play (GstPad * pad) { GstGmeDec *gme = GST_GME_DEC (gst_pad_get_parent (pad)); GstFlowReturn flow_return; GstBuffer *out; gboolean seeking = gme->seeking; gme_err_t gme_err = NULL; const int NUM_SAMPLES = 1600; /* 4 bytes (stereo 16-bit) per sample */ if (!seeking) { GstMapInfo map; out = gst_buffer_new_and_alloc (NUM_SAMPLES * 4); GST_BUFFER_TIMESTAMP (out) = gme_tell (gme->player) * GST_MSECOND; gst_buffer_map (out, &map, GST_MAP_WRITE); gme_err = gme_play (gme->player, NUM_SAMPLES * 2, (short *) map.data); gst_buffer_unmap (out, &map); if (gme_err) { GST_ELEMENT_ERROR (gme, STREAM, DEMUX, (NULL), ("%s", gme_err)); gst_pad_pause_task (pad); gst_pad_push_event (pad, gst_event_new_eos ()); gst_object_unref (gme); return; } } else { gme_seek (gme->player, gme->seekpoint); gme->seeking = FALSE; out = gst_buffer_new (); } if ((flow_return = gst_pad_push (gme->srcpad, out)) != GST_FLOW_OK) { GST_DEBUG_OBJECT (gme, "pausing task, reason %s", gst_flow_get_name (flow_return)); gst_pad_pause_task (pad); if (flow_return == GST_FLOW_EOS) { gst_pad_push_event (pad, gst_event_new_eos ()); } else if (flow_return < GST_FLOW_EOS || flow_return == GST_FLOW_NOT_LINKED) { GST_ELEMENT_ERROR (gme, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_return))); gst_pad_push_event (pad, gst_event_new_eos ()); } } if (gme_tell (gme->player) * GST_MSECOND > gme->total_duration) { gst_pad_pause_task (pad); gst_pad_push_event (pad, gst_event_new_eos ()); } gst_object_unref (gme); return; }
static GstFlowReturn gst_gme_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGmeDec *gme = GST_GME_DEC (parent); /* Accumulate GME data until end-of-stream, then commence playback. */ gst_adapter_push (gme->adapter, buffer); return GST_FLOW_OK; }
static void gst_gme_dec_dispose (GObject * object) { GstGmeDec *gme = GST_GME_DEC (object); if (gme->adapter) { g_object_unref (gme->adapter); gme->adapter = NULL; } GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); }
static gboolean gst_gme_dec_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstGmeDec *gme = GST_GME_DEC (parent); gboolean result = TRUE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_DURATION: { GstFormat format; gst_query_parse_duration (query, &format, NULL); if (!gme->initialized || format != GST_FORMAT_TIME || gme->total_duration == GST_CLOCK_TIME_NONE) { result = FALSE; break; } gst_query_set_duration (query, GST_FORMAT_TIME, gme->total_duration); break; } case GST_QUERY_POSITION: { GstFormat format; gst_query_parse_position (query, &format, NULL); if (!gme->initialized || format != GST_FORMAT_TIME) { result = FALSE; break; } gst_query_set_position (query, GST_FORMAT_TIME, (gint64) gme_tell (gme->player) * GST_MSECOND); break; } default: result = gst_pad_query_default (pad, parent, query); break; } return result; }
static gboolean gst_gme_dec_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstGmeDec *gme = GST_GME_DEC (parent); gboolean result = FALSE; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: { gdouble rate; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; gboolean flush; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); gst_event_unref (event); if (format != GST_FORMAT_TIME) { GST_DEBUG_OBJECT (gme, "seeking is only supported in TIME format"); break; } if (start_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE) { GST_DEBUG_OBJECT (gme, "unsupported seek type"); break; } if (stop_type == GST_SEEK_TYPE_NONE) stop = GST_CLOCK_TIME_NONE; if (start_type == GST_SEEK_TYPE_SET) { GstSegment seg; guint64 cur = gme_tell (gme->player) * GST_MSECOND; guint64 dest = (guint64) start; if (gme->total_duration != GST_CLOCK_TIME_NONE) dest = CLAMP (dest, 0, gme->total_duration); else dest = MAX (0, dest); if (dest == cur) break; flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH; if (flush) { gst_pad_push_event (gme->srcpad, gst_event_new_flush_start ()); } else { gst_pad_stop_task (gme->srcpad); } GST_PAD_STREAM_LOCK (gme->srcpad); if (flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT (gme), gst_message_new_segment_start (GST_OBJECT (gme), format, cur)); } if (flush) { gst_pad_push_event (gme->srcpad, gst_event_new_flush_stop (TRUE)); } if (stop == GST_CLOCK_TIME_NONE && gme->total_duration != GST_CLOCK_TIME_NONE) stop = gme->total_duration; gst_segment_init (&seg, GST_FORMAT_TIME); seg.rate = rate; seg.start = dest; seg.stop = stop; seg.time = dest; gst_pad_push_event (gme->srcpad, gst_event_new_segment (&seg)); gme->seekpoint = dest / GST_MSECOND; /* nsecs to msecs */ gme->seeking = TRUE; gst_pad_start_task (gme->srcpad, (GstTaskFunction) gst_gme_play, gme->srcpad, NULL); GST_PAD_STREAM_UNLOCK (gme->srcpad); result = TRUE; } break; } default: result = gst_pad_push_event (gme->sinkpad, event); break; } return result; }