GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg, gpointer self) { GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self); qLog(Debug) << instance->id() << "sync bus message" << GST_MESSAGE_TYPE_NAME(msg); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: emit instance->EndOfStreamReached(instance->id(), false); break; case GST_MESSAGE_TAG: instance->TagMessageReceived(msg); break; case GST_MESSAGE_ERROR: instance->ErrorMessageReceived(msg); break; case GST_MESSAGE_ELEMENT: instance->ElementMessageReceived(msg); break; case GST_MESSAGE_STATE_CHANGED: instance->StateChangedMessageReceived(msg); break; case GST_MESSAGE_BUFFERING: instance->BufferingMessageReceived(msg); break; case GST_MESSAGE_STREAM_STATUS: instance->StreamStatusMessageReceived(msg); break; case GST_MESSAGE_STREAM_START: if (instance->emit_track_ended_on_stream_start_) { qLog(Debug) << "New segment started, EOS will signal on next buffer " "discontinuity"; instance->emit_track_ended_on_stream_start_ = false; instance->emit_track_ended_on_time_discontinuity_ = true; } break; default: break; } return GST_BUS_PASS; }
static void do_post_message_pre (GstStatsTracer * self, guint64 ts, GstElement * elem, GstMessage * msg) { GstElementStats *stats = get_element_stats (self, elem); const GstStructure *msg_s = gst_message_get_structure (msg); GstStructure *s = msg_s ? (GstStructure *) msg_s : gst_structure_new_empty ("dummy"); stats->last_ts = ts; /* FIXME: work out whether using NULL instead of a dummy struct would work */ gst_tracer_record_log (tr_message, (guint64) (guintptr) g_thread_self (), ts, stats->index, GST_MESSAGE_TYPE_NAME (msg), s); if (s != msg_s) gst_structure_free (s); }
static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) { g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message)); switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_QOS: g_print("GST_MESSAGE_QOS\n"); break; default: g_print("GST_MESSAGE_*\n"); break; } /* we want to be notified again the next time there is a message * on the bus, so returning TRUE (FALSE means we want to stop watching * for messages on the bus and our callback should not be called again) */ return TRUE; }
GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg, gpointer self) { GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self); qLog(Debug) << instance->id() << "sync bus message" << GST_MESSAGE_TYPE_NAME(msg); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: emit instance->EndOfStreamReached(instance->id(), false); break; case GST_MESSAGE_TAG: instance->TagMessageReceived(msg); break; case GST_MESSAGE_ERROR: instance->ErrorMessageReceived(msg); break; case GST_MESSAGE_ELEMENT: instance->ElementMessageReceived(msg); break; case GST_MESSAGE_STATE_CHANGED: instance->StateChangedMessageReceived(msg); break; case GST_MESSAGE_BUFFERING: instance->BufferingMessageReceived(msg); break; case GST_MESSAGE_STREAM_STATUS: instance->StreamStatusMessageReceived(msg); break; default: break; } return GST_BUS_PASS; }
gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data) { GOwnPtr<GError> err; GOwnPtr<gchar> debug; MediaPlayer::NetworkState error; MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); gint percent = 0; switch (GST_MESSAGE_TYPE(message)) { case GST_MESSAGE_ERROR: gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); error = MediaPlayer::Empty; if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) error = MediaPlayer::DecodeError; else if (err->domain == GST_RESOURCE_ERROR) error = MediaPlayer::FormatError; else if (err->domain == GST_STREAM_ERROR) error = MediaPlayer::NetworkError; if (mp) mp->loadingFailed(error); break; case GST_MESSAGE_EOS: LOG_VERBOSE(Media, "End of Stream"); mp->didEnd(); break; case GST_MESSAGE_STATE_CHANGED: mp->updateStates(); break; case GST_MESSAGE_BUFFERING: gst_message_parse_buffering(message, &percent); LOG_VERBOSE(Media, "Buffering %d", percent); break; default: LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s", GST_MESSAGE_TYPE_NAME(message)); break; } return true; }
static void do_post_message_pre (GstStatsTracer * self, guint64 ts, GstElement * elem, GstMessage * msg) { GstElementStats *stats = get_element_stats (self, elem); const GstStructure *msg_s = gst_message_get_structure (msg); GstStructure *s; stats->last_ts = ts; s = gst_structure_new ("message", "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (g_thread_self ()), "ts", G_TYPE_UINT64, ts, "elem-ix", G_TYPE_UINT, stats->index, "name", G_TYPE_STRING, GST_MESSAGE_TYPE_NAME (msg), NULL); if (msg_s) { gst_structure_set (s, "structure", GST_TYPE_STRUCTURE, msg_s, NULL); } gst_tracer_log_trace (s); }
static gboolean mybusfunc(GstBus *bus, GstMessage *message, gpointer user_data) { GMainLoop *loop = (GMainLoop *) user_data; GstState prev_state, curr_state; GError *err = NULL; gchar *debug_info = NULL; g_print("Got %s\n", GST_MESSAGE_TYPE_NAME(message)); switch (GST_MESSAGE_TYPE(message)) { case GST_MESSAGE_EOS: g_print("End of stream\n"); g_main_loop_quit(loop); break; case GST_MESSAGE_ERROR: gst_message_parse_error(message, &err, &debug_info); g_printerr("Error from element %s: %s\n", GST_OBJECT_NAME(message->src), err->message); g_printerr("Debugging info: %s\n", (debug_info) ? debug_info : "none"); g_error_free(err); g_free(debug_info); g_main_loop_quit(loop); break; case GST_MESSAGE_STATE_CHANGED: gst_message_parse_state_changed(message, &prev_state, &curr_state, NULL); g_print("Element %s changed from %s to %s\n", GST_OBJECT_NAME(message->src), gst_element_state_get_name(prev_state), gst_element_state_get_name(curr_state)); break; default: g_print("Unhandled messages"); break; } g_print("\n"); return TRUE; }
void media_bus_message(GstBus *bus, GstMessage *message, gpointer user_data) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { GError *err = NULL; gchar *dbg = NULL; gst_message_parse_error(message, &err, &dbg); if (err) { g_error("RTSP Pipeline ERROR: %s", err->message); g_error_free(err); } if (dbg) { g_message("Debug details: %s", dbg); g_free(dbg); } break; } /* case GST_MESSAGE_STATE_CHANGED: case GST_MESSAGE_STREAM_STATUS: case GST_MESSAGE_TAG: case GST_MESSAGE_NEW_CLOCK: { // Ignore break; } */ default: { const GstStructure* mstruct = gst_message_get_structure(message); char* struct_info = mstruct ? gst_structure_to_string(mstruct) : g_strdup("no-struct"); g_message("RTSP bus Message '%s' from '%s': %s", GST_MESSAGE_TYPE_NAME(message), GST_MESSAGE_SRC_NAME(message), struct_info); g_free(struct_info); break; } } }
gboolean GstEnginePipeline::BusCallback(GstBus*, GstMessage* msg, gpointer self) { GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self); qLog(Debug) << instance->id() << "bus message" << GST_MESSAGE_TYPE_NAME(msg); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: instance->ErrorMessageReceived(msg); break; case GST_MESSAGE_TAG: instance->TagMessageReceived(msg); break; case GST_MESSAGE_STATE_CHANGED: instance->StateChangedMessageReceived(msg); break; default: break; } return FALSE; }
void QGstreamerGLTextureRenderer::handleBusMessage(GstMessage* gm) { #ifdef GL_TEXTURE_SINK_DEBUG qDebug() << Q_FUNC_INFO << GST_MESSAGE_TYPE_NAME(gm); #endif if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED) { GstState oldState; GstState newState; gst_message_parse_state_changed(gm, &oldState, &newState, 0); #ifdef GL_TEXTURE_SINK_DEBUG qDebug() << Q_FUNC_INFO << "State changed:" << oldState << newState; #endif if (newState == GST_STATE_READY || newState == GST_STATE_NULL) { stopRenderer(); } if (oldState == GST_STATE_READY && newState == GST_STATE_PAUSED) { updateNativeVideoSize(); } } }
static void do_perfect_stream_test (guint rate, guint width, gdouble drop_probability, gdouble inject_probability) { GstElement *pipe, *src, *conv, *filter, *injector, *audiorate, *sink; GstMessage *msg; GstCaps *caps; GstPad *srcpad; GList *l, *bufs = NULL; GstClockTime next_time = GST_CLOCK_TIME_NONE; guint64 next_offset = GST_BUFFER_OFFSET_NONE; caps = gst_caps_new_simple ("audio/x-raw-int", "rate", G_TYPE_INT, rate, "width", G_TYPE_INT, width, NULL); GST_INFO ("-------- drop=%.0f%% caps = %" GST_PTR_FORMAT " ---------- ", drop_probability * 100.0, caps); g_assert (drop_probability >= 0.0 && drop_probability <= 1.0); g_assert (inject_probability >= 0.0 && inject_probability <= 1.0); g_assert (width > 0 && (width % 8) == 0); pipe = gst_pipeline_new ("pipeline"); fail_unless (pipe != NULL); src = gst_element_factory_make ("audiotestsrc", "audiotestsrc"); fail_unless (src != NULL); g_object_set (src, "num-buffers", 100, NULL); conv = gst_element_factory_make ("audioconvert", "audioconvert"); fail_unless (conv != NULL); filter = gst_element_factory_make ("capsfilter", "capsfilter"); fail_unless (filter != NULL); g_object_set (filter, "caps", caps, NULL); injector_inject_probability = inject_probability; injector = GST_ELEMENT (g_object_new (test_injector_get_type (), NULL)); srcpad = gst_element_get_pad (injector, "src"); fail_unless (srcpad != NULL); gst_pad_add_buffer_probe (srcpad, G_CALLBACK (probe_cb), &drop_probability); gst_object_unref (srcpad); audiorate = gst_element_factory_make ("audiorate", "audiorate"); fail_unless (audiorate != NULL); sink = gst_element_factory_make ("fakesink", "fakesink"); fail_unless (sink != NULL); g_object_set (sink, "signal-handoffs", TRUE, NULL); g_signal_connect (sink, "handoff", G_CALLBACK (got_buf), &bufs); gst_bin_add_many (GST_BIN (pipe), src, conv, filter, injector, audiorate, sink, NULL); gst_element_link_many (src, conv, filter, injector, audiorate, sink, NULL); fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC); fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1), GST_STATE_CHANGE_SUCCESS); msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); fail_unless_equals_string (GST_MESSAGE_TYPE_NAME (msg), "eos"); for (l = bufs; l != NULL; l = l->next) { GstBuffer *buf = GST_BUFFER (l->data); guint num_samples; fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf)); fail_unless (GST_BUFFER_DURATION_IS_VALID (buf)); fail_unless (GST_BUFFER_OFFSET_IS_VALID (buf)); fail_unless (GST_BUFFER_OFFSET_END_IS_VALID (buf)); GST_LOG ("buffer: ts=%" GST_TIME_FORMAT ", end_ts=%" GST_TIME_FORMAT " off=%" G_GINT64_FORMAT ", end_off=%" G_GINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf)); if (GST_CLOCK_TIME_IS_VALID (next_time)) { fail_unless_equals_uint64 (next_time, GST_BUFFER_TIMESTAMP (buf)); } if (next_offset != GST_BUFFER_OFFSET_NONE) { fail_unless_equals_uint64 (next_offset, GST_BUFFER_OFFSET (buf)); } /* check buffer size for sanity */ fail_unless_equals_int (GST_BUFFER_SIZE (buf) % (width / 8), 0); /* check there is actually as much data as there should be */ num_samples = GST_BUFFER_OFFSET_END (buf) - GST_BUFFER_OFFSET (buf); fail_unless_equals_int (GST_BUFFER_SIZE (buf), num_samples * (width / 8)); next_time = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); next_offset = GST_BUFFER_OFFSET_END (buf); } gst_message_unref (msg); gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); g_list_foreach (bufs, (GFunc) gst_mini_object_unref, NULL); g_list_free (bufs); gst_caps_unref (caps); }
static void gst_alloc_trace_print (const GstAllocTrace * trace) { GSList *mem_live; g_return_if_fail (trace != NULL); if (trace->flags & GST_ALLOC_TRACE_LIVE) { g_print ("%-22.22s : %d\n", trace->name, trace->live); } else { g_print ("%-22.22s : (no live count)\n", trace->name); } if (trace->flags & GST_ALLOC_TRACE_MEM_LIVE) { mem_live = trace->mem_live; while (mem_live) { gpointer data = mem_live->data; const gchar *type_name; gchar *extra = NULL; gint refcount = -1; if (trace->offset == -2) { if (G_IS_OBJECT (data)) { type_name = G_OBJECT_TYPE_NAME (data); refcount = G_OBJECT (data)->ref_count; } else type_name = "<invalid>"; } else if (trace->offset == -1) { type_name = "<unknown>"; } else { GType type; type = G_STRUCT_MEMBER (GType, data, trace->offset); type_name = g_type_name (type); if (type == GST_TYPE_CAPS) { extra = gst_caps_to_string (data); } else if (type == GST_TYPE_EVENT) { const GstStructure *s = gst_event_get_structure (data); if (s == NULL) extra = g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (data)); else extra = gst_structure_to_string (s); } else if (type == GST_TYPE_MESSAGE) { const GstStructure *s = gst_message_get_structure (data); if (s == NULL) extra = g_strdup_printf ("%s", GST_MESSAGE_TYPE_NAME (data)); else extra = gst_structure_to_string (s); } else if (type == GST_TYPE_BUFFER) { guint size = gst_buffer_get_size (data); extra = g_strdup_printf ("%u bytes", size); } else if (type == GST_TYPE_MEMORY) { GstMemory *mem = (GstMemory *) data; extra = g_strdup_printf ("%u bytes, %s allocator", (guint) mem->size, mem->allocator ? mem->allocator->mem_type : "unknown"); } refcount = GST_MINI_OBJECT_REFCOUNT_VALUE (data); } if (extra) { g_print (" %-20.20s : (%d) %p (\"%s\")\n", type_name, refcount, data, extra); g_free (extra); } else g_print (" %-20.20s : (%d) %p\n", type_name, refcount, data); mem_live = mem_live->next; } } }
/** * gst_bus_timed_pop_filtered: * @bus: a #GstBus to pop from * @timeout: a timeout in nanoseconds, or GST_CLOCK_TIME_NONE to wait forever * @types: message types to take into account, GST_MESSAGE_ANY for any type * * Get a message from the bus whose type matches the message type mask @types, * waiting up to the specified timeout (and discarding any messages that do not * match the mask provided). * * If @timeout is 0, this function behaves like gst_bus_pop_filtered(). If * @timeout is #GST_CLOCK_TIME_NONE, this function will block forever until a * matching message was posted on the bus. * * Returns: a #GstMessage matching the filter in @types, or NULL if no matching * message was found on the bus until the timeout expired. * The message is taken from the bus and needs to be unreffed with * gst_message_unref() after usage. * * MT safe. * * Since: 0.10.15 */ GstMessage * gst_bus_timed_pop_filtered (GstBus * bus, GstClockTime timeout, GstMessageType types) { GstMessage *message; GTimeVal *timeval, abstimeout; gboolean first_round = TRUE; g_return_val_if_fail (GST_IS_BUS (bus), NULL); g_return_val_if_fail (types != 0, NULL); g_mutex_lock (bus->queue_lock); while (TRUE) { GST_LOG_OBJECT (bus, "have %d messages", g_queue_get_length (bus->queue)); while ((message = g_queue_pop_head (bus->queue))) { GST_DEBUG_OBJECT (bus, "got message %p, %s, type mask is %u", message, GST_MESSAGE_TYPE_NAME (message), (guint) types); if ((GST_MESSAGE_TYPE (message) & types) != 0) { /* exit the loop, we have a message */ goto beach; } else { GST_DEBUG_OBJECT (bus, "discarding message, does not match mask"); gst_message_unref (message); message = NULL; } } /* no need to wait, exit loop */ if (timeout == 0) break; if (timeout == GST_CLOCK_TIME_NONE) { /* wait forever */ timeval = NULL; } else if (first_round) { glong add = timeout / 1000; if (add == 0) /* no need to wait */ break; /* make timeout absolute */ g_get_current_time (&abstimeout); g_time_val_add (&abstimeout, add); timeval = &abstimeout; first_round = FALSE; GST_DEBUG_OBJECT (bus, "blocking for message, timeout %ld", add); } else { /* calculated the absolute end time already, no need to do it again */ GST_DEBUG_OBJECT (bus, "blocking for message, again"); timeval = &abstimeout; /* fool compiler */ } if (!g_cond_timed_wait (bus->priv->queue_cond, bus->queue_lock, timeval)) { GST_INFO_OBJECT (bus, "timed out, breaking loop"); break; } else { GST_INFO_OBJECT (bus, "we got woken up, recheck for message"); } } beach: g_mutex_unlock (bus->queue_lock); return message; }
/** * gst_bus_post: * @bus: a #GstBus to post on * @message: The #GstMessage to post * * Post a message on the given bus. Ownership of the message * is taken by the bus. * * Returns: TRUE if the message could be posted, FALSE if the bus is flushing. * * MT safe. */ gboolean gst_bus_post (GstBus * bus, GstMessage * message) { GstBusSyncReply reply = GST_BUS_PASS; GstBusSyncHandler handler; gboolean emit_sync_message; gpointer handler_data; g_return_val_if_fail (GST_IS_BUS (bus), FALSE); g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE); GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus, type %s, %" GST_PTR_FORMAT " from source %" GST_PTR_FORMAT, message, GST_MESSAGE_TYPE_NAME (message), message->structure, message->src); GST_OBJECT_LOCK (bus); /* check if the bus is flushing */ if (GST_OBJECT_FLAG_IS_SET (bus, GST_BUS_FLUSHING)) goto is_flushing; handler = bus->sync_handler; handler_data = bus->sync_handler_data; emit_sync_message = bus->priv->num_sync_message_emitters > 0; GST_OBJECT_UNLOCK (bus); /* first call the sync handler if it is installed */ if (handler) reply = handler (bus, message, handler_data); /* emit sync-message if requested to do so via gst_bus_enable_sync_message_emission. terrible but effective */ if (emit_sync_message && reply != GST_BUS_DROP && handler != gst_bus_sync_signal_handler) gst_bus_sync_signal_handler (bus, message, NULL); /* now see what we should do with the message */ switch (reply) { case GST_BUS_DROP: /* drop the message */ GST_DEBUG_OBJECT (bus, "[msg %p] dropped", message); break; case GST_BUS_PASS: /* pass the message to the async queue, refcount passed in the queue */ GST_DEBUG_OBJECT (bus, "[msg %p] pushing on async queue", message); g_mutex_lock (bus->queue_lock); g_queue_push_tail (bus->queue, message); g_cond_broadcast (bus->priv->queue_cond); g_mutex_unlock (bus->queue_lock); GST_DEBUG_OBJECT (bus, "[msg %p] pushed on async queue", message); gst_bus_wakeup_main_context (bus); break; case GST_BUS_ASYNC: { /* async delivery, we need a mutex and a cond to block * on */ GMutex *lock = g_mutex_new (); GCond *cond = g_cond_new (); GST_MESSAGE_COND (message) = cond; GST_MESSAGE_GET_LOCK (message) = lock; GST_DEBUG_OBJECT (bus, "[msg %p] waiting for async delivery", message); /* now we lock the message mutex, send the message to the async * queue. When the message is handled by the app and destroyed, * the cond will be signalled and we can continue */ g_mutex_lock (lock); g_mutex_lock (bus->queue_lock); g_queue_push_tail (bus->queue, message); g_cond_broadcast (bus->priv->queue_cond); g_mutex_unlock (bus->queue_lock); gst_bus_wakeup_main_context (bus); /* now block till the message is freed */ g_cond_wait (cond, lock); g_mutex_unlock (lock); GST_DEBUG_OBJECT (bus, "[msg %p] delivered asynchronously", message); g_mutex_free (lock); g_cond_free (cond); break; } default: g_warning ("invalid return from bus sync handler"); break; } return TRUE; /* ERRORS */ is_flushing: { GST_DEBUG_OBJECT (bus, "bus is flushing"); gst_message_unref (message); GST_OBJECT_UNLOCK (bus); return FALSE; } }
void eServiceMP3::gstBusCall(GstMessage *msg) { if (!msg) return; gchar *sourceName; GstObject *source; source = GST_MESSAGE_SRC(msg); if (!GST_IS_OBJECT(source)) return; sourceName = gst_object_get_name(source); #if 0 gchar *string; if (gst_message_get_structure(msg)) string = gst_structure_to_string(gst_message_get_structure(msg)); else string = g_strdup(GST_MESSAGE_TYPE_NAME(msg)); eDebug("eTsRemoteSource::gst_message from %s: %s", sourceName, string); g_free(string); #endif switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: m_event((iPlayableService*)this, evEOF); break; case GST_MESSAGE_STATE_CHANGED: { if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin)) break; GstState old_state, new_state; gst_message_parse_state_changed(msg, &old_state, &new_state, NULL); if(old_state == new_state) break; eDebug("eServiceMP3::state transition %s -> %s", gst_element_state_get_name(old_state), gst_element_state_get_name(new_state)); GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION(old_state, new_state); switch(transition) { case GST_STATE_CHANGE_NULL_TO_READY: { } break; case GST_STATE_CHANGE_READY_TO_PAUSED: { GstElement *subsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink"); if (subsink) { #ifdef GSTREAMER_SUBTITLE_SYNC_MODE_BUG /* * HACK: disable sync mode for now, gstreamer suffers from a bug causing sparse streams to loose sync, after pause/resume / skip * see: https://bugzilla.gnome.org/show_bug.cgi?id=619434 * Sideeffect of using sync=false is that we receive subtitle buffers (far) ahead of their * display time. * Not too far ahead for subtitles contained in the media container. * But for external srt files, we could receive all subtitles at once. * And not just once, but after each pause/resume / skip. * So as soon as gstreamer has been fixed to keep sync in sparse streams, sync needs to be re-enabled. */ g_object_set (G_OBJECT (subsink), "sync", FALSE, NULL); #endif #if 0 /* we should not use ts-offset to sync with the decoder time, we have to do our own decoder timekeeping */ g_object_set (G_OBJECT (subsink), "ts-offset", -2L * GST_SECOND, NULL); /* late buffers probably will not occur very often */ g_object_set (G_OBJECT (subsink), "max-lateness", 0L, NULL); /* avoid prerolling (it might not be a good idea to preroll a sparse stream) */ g_object_set (G_OBJECT (subsink), "async", TRUE, NULL); #endif eDebug("eServiceMP3::subsink properties set!"); gst_object_unref(subsink); } setAC3Delay(ac3_delay); setPCMDelay(pcm_delay); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { if ( m_sourceinfo.is_streaming && m_streamingsrc_timeout ) m_streamingsrc_timeout->stop(); } break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: { } break; case GST_STATE_CHANGE_PAUSED_TO_READY: { } break; case GST_STATE_CHANGE_READY_TO_NULL: { } break; } break; } case GST_MESSAGE_ERROR: { gchar *debug; GError *err; gst_message_parse_error (msg, &err, &debug); g_free (debug); eWarning("Gstreamer error: %s (%i) from %s", err->message, err->code, sourceName ); if ( err->domain == GST_STREAM_ERROR ) { if ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND ) { if ( g_strrstr(sourceName, "videosink") ) m_event((iPlayableService*)this, evUser+11); else if ( g_strrstr(sourceName, "audiosink") ) m_event((iPlayableService*)this, evUser+10); } } g_error_free(err); break; } case GST_MESSAGE_INFO: { gchar *debug; GError *inf; gst_message_parse_info (msg, &inf, &debug); g_free (debug); if ( inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE ) { if ( g_strrstr(sourceName, "videosink") ) m_event((iPlayableService*)this, evUser+14); } g_error_free(inf); break; } case GST_MESSAGE_TAG: { GstTagList *tags, *result; gst_message_parse_tag(msg, &tags); result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_REPLACE); if (result) { if (m_stream_tags) gst_tag_list_free(m_stream_tags); m_stream_tags = result; } const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0); if ( gv_image ) { GstBuffer *buf_image; buf_image = gst_value_get_buffer (gv_image); int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644); int ret = write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image)); close(fd); eDebug("eServiceMP3::/tmp/.id3coverart %d bytes written ", ret); m_event((iPlayableService*)this, evUser+13); } gst_tag_list_free(tags); m_event((iPlayableService*)this, evUpdatedInfo); break; } case GST_MESSAGE_ASYNC_DONE: { if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin)) break; GstTagList *tags; gint i, active_idx, n_video = 0, n_audio = 0, n_text = 0; g_object_get (m_gst_playbin, "n-video", &n_video, NULL); g_object_get (m_gst_playbin, "n-audio", &n_audio, NULL); g_object_get (m_gst_playbin, "n-text", &n_text, NULL); eDebug("eServiceMP3::async-done - %d video, %d audio, %d subtitle", n_video, n_audio, n_text); if ( n_video + n_audio <= 0 ) stop(); active_idx = 0; m_audioStreams.clear(); m_subtitleStreams.clear(); for (i = 0; i < n_audio; i++) { audioStream audio; gchar *g_codec, *g_lang; GstPad* pad = 0; g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad); GstCaps* caps = gst_pad_get_negotiated_caps(pad); if (!caps) continue; GstStructure* str = gst_caps_get_structure(caps, 0); const gchar *g_type = gst_structure_get_name(str); eDebug("AUDIO STRUCT=%s", g_type); audio.type = gstCheckAudioPad(str); g_codec = g_strdup(g_type); g_lang = g_strdup_printf ("und"); g_signal_emit_by_name (m_gst_playbin, "get-audio-tags", i, &tags); if ( tags && gst_is_tag_list(tags) ) { gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_codec); gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang); gst_tag_list_free(tags); } audio.language_code = std::string(g_lang); audio.codec = std::string(g_codec); eDebug("eServiceMP3::audio stream=%i codec=%s language=%s", i, g_codec, g_lang); m_audioStreams.push_back(audio); g_free (g_lang); g_free (g_codec); gst_caps_unref(caps); } for (i = 0; i < n_text; i++) { gchar *g_codec = NULL, *g_lang = NULL; g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags); subtitleStream subs; g_lang = g_strdup_printf ("und"); if ( tags && gst_is_tag_list(tags) ) { gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang); gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec); gst_tag_list_free(tags); } subs.language_code = std::string(g_lang); eDebug("eServiceMP3::subtitle stream=%i language=%s codec=%s", i, g_lang, g_codec); GstPad* pad = 0; g_signal_emit_by_name (m_gst_playbin, "get-text-pad", i, &pad); if ( pad ) g_signal_connect (G_OBJECT (pad), "notify::caps", G_CALLBACK (gstTextpadHasCAPS), this); subs.type = getSubtitleType(pad, g_codec); m_subtitleStreams.push_back(subs); g_free (g_lang); } m_event((iPlayableService*)this, evUpdatedInfo); if ( m_errorInfo.missing_codec != "" ) { if ( m_errorInfo.missing_codec.find("video/") == 0 || ( m_errorInfo.missing_codec.find("audio/") == 0 && getNumberOfTracks() == 0 ) ) m_event((iPlayableService*)this, evUser+12); } break; } case GST_MESSAGE_ELEMENT: { if (const GstStructure *msgstruct = gst_message_get_structure(msg)) { if ( gst_is_missing_plugin_message(msg) ) { GstCaps *caps; gst_structure_get (msgstruct, "detail", GST_TYPE_CAPS, &caps, NULL); std::string codec = (const char*) gst_caps_to_string(caps); gchar *description = gst_missing_plugin_message_get_description(msg); if ( description ) { eDebug("eServiceMP3::m_errorInfo.missing_codec = %s", codec.c_str()); m_errorInfo.error_message = "GStreamer plugin " + (std::string)description + " not available!\n"; m_errorInfo.missing_codec = codec.substr(0,(codec.find_first_of(','))); g_free(description); } gst_caps_unref(caps); } else { const gchar *eventname = gst_structure_get_name(msgstruct); if ( eventname ) { if (!strcmp(eventname, "eventSizeChanged") || !strcmp(eventname, "eventSizeAvail")) { gst_structure_get_int (msgstruct, "aspect_ratio", &m_aspect); gst_structure_get_int (msgstruct, "width", &m_width); gst_structure_get_int (msgstruct, "height", &m_height); if (strstr(eventname, "Changed")) m_event((iPlayableService*)this, evVideoSizeChanged); } else if (!strcmp(eventname, "eventFrameRateChanged") || !strcmp(eventname, "eventFrameRateAvail")) { gst_structure_get_int (msgstruct, "frame_rate", &m_framerate); if (strstr(eventname, "Changed")) m_event((iPlayableService*)this, evVideoFramerateChanged); } else if (!strcmp(eventname, "eventProgressiveChanged") || !strcmp(eventname, "eventProgressiveAvail")) { gst_structure_get_int (msgstruct, "progressive", &m_progressive); if (strstr(eventname, "Changed")) m_event((iPlayableService*)this, evVideoProgressiveChanged); } } } } break; } case GST_MESSAGE_BUFFERING: { GstBufferingMode mode; gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent)); gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft)); m_event((iPlayableService*)this, evBuffering); break; } case GST_MESSAGE_STREAM_STATUS: { GstStreamStatusType type; GstElement *owner; gst_message_parse_stream_status (msg, &type, &owner); if ( type == GST_STREAM_STATUS_TYPE_CREATE && m_sourceinfo.is_streaming ) { if ( GST_IS_PAD(source) ) owner = gst_pad_get_parent_element(GST_PAD(source)); else if ( GST_IS_ELEMENT(source) ) owner = GST_ELEMENT(source); else owner = 0; if ( owner ) { GstElementFactory *factory = gst_element_get_factory(GST_ELEMENT(owner)); const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); if (!strcmp(name, "souphttpsrc")) { m_streamingsrc_timeout->start(HTTP_TIMEOUT*1000, true); g_object_set (G_OBJECT (owner), "timeout", HTTP_TIMEOUT, NULL); eDebug("eServiceMP3::GST_STREAM_STATUS_TYPE_CREATE -> setting timeout on %s to %is", name, HTTP_TIMEOUT); } } if ( GST_IS_PAD(source) ) gst_object_unref(owner); } break; } default: break; } g_free (sourceName); }
void ofGstUtils::gstHandleMessage(){ GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(gstPipeline)); while(gst_bus_have_pending(bus)) { GstMessage* msg = gst_bus_pop(bus); if(appsink && appsink->on_message(msg)) continue; ofLog(OF_LOG_VERBOSE,"GStreamer: Got %s message", GST_MESSAGE_TYPE_NAME(msg)); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_BUFFERING: gint pctBuffered; gst_message_parse_buffering(msg,&pctBuffered); ofLog(OF_LOG_VERBOSE,"GStreamer: buffering %i\%", pctBuffered); if(isStream && !bLoaded && appsink){ appsink->on_stream_prepared(); } if(pctBuffered<100){ gst_element_set_state (gstPipeline, GST_STATE_PAUSED); }else if(!bPaused){ gst_element_set_state (gstPipeline, GST_STATE_PLAYING); } break; case GST_MESSAGE_DURATION:{ GstFormat format=GST_FORMAT_TIME; gst_element_query_duration(gstPipeline,&format,&durationNanos); }break; case GST_MESSAGE_STATE_CHANGED:{ GstState oldstate, newstate, pendstate; gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate); if(isStream && !bLoaded && appsink){ appsink->on_stream_prepared(); } /*seek_lock(); if(posChangingPaused && newstate==GST_STATE_PLAYING){ gst_element_set_state (gstPipeline, GST_STATE_PAUSED); posChangingPaused=false; } seek_unlock();*/ ofLog(OF_LOG_VERBOSE,"GStreamer: state changed from " + getName(oldstate) + " to " + getName(newstate) + " (" + getName(pendstate) + ")"); }break; case GST_MESSAGE_ASYNC_DONE: ofLog(OF_LOG_VERBOSE,"GStreamer: async done"); break; case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gst_message_parse_error(msg, &err, &debug); ofLog(OF_LOG_ERROR, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s", gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message); g_error_free(err); g_free(debug); gst_element_set_state(GST_ELEMENT(gstPipeline), GST_STATE_NULL); }break; case GST_MESSAGE_EOS: ofLog(OF_LOG_VERBOSE,"GStreamer: end of the stream."); bIsMovieDone = true; switch(loopMode){ case OF_LOOP_NORMAL:{ GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); gint64 pos; gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); float loopSpeed; if(pos>0) loopSpeed=-speed; else loopSpeed=speed; if(!gst_element_seek(GST_ELEMENT(gstPipeline), speed, format, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, durationNanos)) { ofLog(OF_LOG_WARNING,"GStreamer: unable to seek"); } }break; case OF_LOOP_PALINDROME:{ GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); gint64 pos; gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); float loopSpeed; if(pos>0) loopSpeed=-speed; else loopSpeed=speed; if(!gst_element_seek(GST_ELEMENT(gstPipeline), loopSpeed, GST_FORMAT_UNDEFINED, flags, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)) { ofLog(OF_LOG_WARNING,"GStreamer: unable to seek"); } }break; default: break; } break; default: ofLog(OF_LOG_VERBOSE,"GStreamer: unhandled message"); break; } gst_message_unref(msg); } gst_object_unref(GST_OBJECT(bus)); }
bool ofGstUtils::gstHandleMessage(GstBus * bus, GstMessage * msg){ if(appsink && appsink->on_message(msg)) return true; ofLogVerbose("ofGstUtils") << "gstHandleMessage(): got " << GST_MESSAGE_TYPE_NAME(msg) << " message from " << GST_MESSAGE_SRC_NAME(msg); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_BUFFERING: gint pctBuffered; gst_message_parse_buffering(msg,&pctBuffered); ofLogVerbose("ofGstUtils") << "gstHandleMessage(): buffering " << pctBuffered; /*if(pctBuffered<100){ gst_element_set_state (gstPipeline, GST_STATE_PAUSED); }else if(!bPaused){ gst_element_set_state (gstPipeline, GST_STATE_PLAYING); }*/ break; #if GST_VERSION_MAJOR==0 case GST_MESSAGE_DURATION:{ GstFormat format=GST_FORMAT_TIME; gst_element_query_duration(gstPipeline,&format,&durationNanos); }break; #else case GST_MESSAGE_DURATION_CHANGED: gst_element_query_duration(gstPipeline,GST_FORMAT_TIME,&durationNanos); break; #endif case GST_MESSAGE_STATE_CHANGED:{ GstState oldstate, newstate, pendstate; gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate); if(isStream && newstate==GST_STATE_PAUSED && !bPlaying ){ bLoaded = true; bPlaying = true; if(!bPaused){ ofLogVerbose("ofGstUtils") << "gstHandleMessage(): setting stream pipeline to play"; play(); } } ofLogVerbose("ofGstUtils") << "gstHandleMessage(): " << GST_MESSAGE_SRC_NAME(msg) << " state changed from " << getName(oldstate) << " to " << getName(newstate) << " (" + getName(pendstate) << ")"; }break; case GST_MESSAGE_ASYNC_DONE: ofLogVerbose("ofGstUtils") << "gstHandleMessage(): async done"; break; case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gst_message_parse_error(msg, &err, &debug); ofLogVerbose("ofGstUtils") << "gstHandleMessage(): embedded video playback halted for plugin, module " << gst_element_get_name(GST_MESSAGE_SRC (msg)) << " reported: " << err->message; g_error_free(err); g_free(debug); gst_element_set_state(GST_ELEMENT(gstPipeline), GST_STATE_NULL); }break; case GST_MESSAGE_EOS: ofLogVerbose("ofGstUtils") << "gstHandleMessage(): end of the stream"; bIsMovieDone = true; if(appsink && !isAppSink) appsink->on_eos(); switch(loopMode){ case OF_LOOP_NORMAL:{ GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); gint64 pos; #if GST_VERSION_MAJOR==0 gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); #else gst_element_query_position(GST_ELEMENT(gstPipeline),format,&pos); #endif if(!gst_element_seek(GST_ELEMENT(gstPipeline), speed, format, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, durationNanos)) { ofLogWarning("ofGstUtils") << "gstHandleMessage(): unable to seek"; } }break; case OF_LOOP_PALINDROME:{ GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); gint64 pos; #if GST_VERSION_MAJOR==0 gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); #else gst_element_query_position(GST_ELEMENT(gstPipeline),format,&pos); #endif float loopSpeed; if(pos>0) loopSpeed=-speed; else loopSpeed=speed; if(!gst_element_seek(GST_ELEMENT(gstPipeline), loopSpeed, GST_FORMAT_UNDEFINED, flags, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)) { ofLogWarning("ofGstUtils") << "gstHandleMessage(): unable to seek"; } }break; default: break; } break; default: ofLogVerbose("ofGstUtils") << "gstHandleMessage(): unhandled message from " << GST_MESSAGE_SRC_NAME(msg); break; } return true; }
/* Returns TRUE if processing should stop */ static gboolean handle_message (GstDiscoverer * dc, GstMessage * msg) { gboolean done = FALSE; GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "got a %s message", GST_MESSAGE_TYPE_NAME (msg)); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR:{ GError *gerr; gchar *debug; gst_message_parse_error (msg, &gerr, &debug); GST_WARNING_OBJECT (GST_MESSAGE_SRC (msg), "Got an error [debug:%s], [message:%s]", debug, gerr->message); dc->priv->current_error = gerr; g_free (debug); /* We need to stop */ done = TRUE; GST_DEBUG ("Setting result to ERROR"); dc->priv->current_info->result = GST_DISCOVERER_ERROR; } break; case GST_MESSAGE_EOS: GST_DEBUG ("Got EOS !"); done = TRUE; break; case GST_MESSAGE_ASYNC_DONE: if (GST_MESSAGE_SRC (msg) == (GstObject *) dc->priv->pipeline) { GST_DEBUG ("Finished changing state asynchronously"); done = TRUE; } break; case GST_MESSAGE_ELEMENT: { GQuark sttype = gst_structure_get_name_id (msg->structure); GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "structure %" GST_PTR_FORMAT, msg->structure); if (sttype == _MISSING_PLUGIN_QUARK) { GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "Setting result to MISSING_PLUGINS"); dc->priv->current_info->result = GST_DISCOVERER_MISSING_PLUGINS; dc->priv->current_info->misc = gst_structure_copy (msg->structure); } else if (sttype == _STREAM_TOPOLOGY_QUARK) { dc->priv->current_topology = gst_structure_copy (msg->structure); } } break; case GST_MESSAGE_TAG: { GstTagList *tl, *tmp; gst_message_parse_tag (msg, &tl); GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "Got tags %" GST_PTR_FORMAT, tl); /* Merge with current tags */ tmp = gst_tag_list_merge (dc->priv->current_info->tags, tl, GST_TAG_MERGE_APPEND); gst_tag_list_free (tl); if (dc->priv->current_info->tags) gst_tag_list_free (dc->priv->current_info->tags); dc->priv->current_info->tags = tmp; GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg), "Current info %p, tags %" GST_PTR_FORMAT, dc->priv->current_info, tmp); } break; default: break; } return done; }
//static gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gpointer data) { #ifdef LL_GST_REPORT_STATE_CHANGES LL_DEBUGS("MediaCallback") << "Got GST message type: " << GST_MESSAGE_TYPE_NAME (message) << LL_ENDL; #endif LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_BUFFERING: { gint percent = 0; gst_message_parse_buffering(message, &percent); #ifdef LL_GST_REPORT_STATE_CHANGES LL_DEBUGS("MediaBuffering") << "GST buffering: " << percent << "%%" << LL_ENDL; #endif LLMediaEvent event( impl, percent ); impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); } break; case GST_MESSAGE_STATE_CHANGED: { GstState old_state; GstState new_state; GstState pending_state; gst_message_parse_state_changed(message, &old_state, &new_state, &pending_state); #ifdef LL_GST_REPORT_STATE_CHANGES // not generally very useful, and rather spammy. LL_DEBUGS("MediaState") << "GST state change (old,<new>,pending): "<< get_gst_state_name(old_state) << ",<" << get_gst_state_name(new_state) << ">," << get_gst_state_name(pending_state) << LL_ENDL; #endif // LL_GST_REPORT_STATE_CHANGES switch (new_state) { case GST_STATE_VOID_PENDING: break; case GST_STATE_NULL: #ifdef LL_GST_REPORT_STATE_CHANGES LL_DEBUGS("MediaImpl") << "State changed to NULL" << LL_ENDL; #endif if (impl->getState() == GST_STATE_PLAYING) { // Stream was probably dropped, trying to restart impl->play(); #ifdef LL_GST_REPORT_STATE_CHANGES LL_DEBUGS("MediaImpl") << "Trying to restart." << LL_ENDL; #endif } break; case GST_STATE_READY: break; case GST_STATE_PAUSED: break; case GST_STATE_PLAYING: //impl->mLastTitle = ""; LLMediaEvent event( impl, 100 ); impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); // emit an event to say that a media source was loaded LLMediaEvent event2( impl ); impl->getEventEmitter().update( &LLMediaObserver::onMediaLoaded, event2 ); break; } break; } case GST_MESSAGE_ERROR: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_error (message, &err, &debug); LL_WARNS("MediaImpl") << "GST Error: " << err->message << LL_ENDL; g_error_free (err); g_free (debug); impl->addCommand(LLMediaBase::COMMAND_STOP); //impl->addCommand(LLMediaBase::COMMAND_START); break; } case GST_MESSAGE_INFO: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_info (message, &err, &debug); LL_INFOS("MediaImpl") << "GST info: " << err->message << LL_ENDL; g_error_free (err); g_free (debug); break; } case GST_MESSAGE_WARNING: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_warning (message, &err, &debug); LL_WARNS("MediaImpl") << "GST warning: " << err->message << LL_ENDL; g_error_free (err); g_free (debug); break; } case GST_MESSAGE_TAG: { GstTagList *new_tags; gst_message_parse_tag( message, &new_tags ); gchar *title; if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) ) { LL_INFOS("MediaInfo") << "Title: " << title << LL_ENDL; std::string newtitle(title); gst_tag_list_free(new_tags); if ( newtitle != impl->mLastTitle && newtitle != "" ) { impl->mLastTitle = newtitle; LLMediaEvent event( impl, impl->mLastTitle ); impl->getEventEmitter().update( &LLMediaObserver::onMediaTitleChange, event ); } g_free(title); } break; } case GST_MESSAGE_EOS: { /* end-of-stream */ LL_DEBUGS("MediaImpl") << "GST end-of-stream." << LL_ENDL; if (impl->isLooping()) { LL_DEBUGS("MediaImpl") << "looping media..." << LL_ENDL; impl->stop(); impl->play(); } else { // inject a COMMAND_STOP impl->addCommand(LLMediaBase::COMMAND_STOP); } break; } default: /* unhandled message */ break; } /* we want to be notified again the next time there is a message * on the bus, so return true (false means we want to stop watching * for messages on the bus and our callback should not be called again) */ return TRUE; }
QString Message::typeName() const { return QString::fromUtf8(GST_MESSAGE_TYPE_NAME(object<GstMessage>())); }
gboolean MediaPluginGStreamer010::processGSTEvents(GstBus *bus, GstMessage *message) { if (!message) return TRUE; // shield against GStreamer bug if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) { DEBUGMSG("Got GST message type: %s", GST_MESSAGE_TYPE_NAME (message)); } else { // TODO: grok 'duration' message type DEBUGMSG("Got GST message type: %s", GST_MESSAGE_TYPE_NAME (message)); } switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_BUFFERING: { // NEEDS GST 0.10.11+ and America discovered by C.Columbus gint percent = 0; gst_message_parse_buffering(message, &percent); DEBUGMSG("GST buffering: %d%%", percent); break; } case GST_MESSAGE_STATE_CHANGED: { GstState old_state; GstState new_state; GstState pending_state; gst_message_parse_state_changed(message, &old_state, &new_state, &pending_state); #ifdef LL_GST_REPORT_STATE_CHANGES // not generally very useful, and rather spammy. DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s", get_gst_state_name(old_state), get_gst_state_name(new_state), get_gst_state_name(pending_state)); #endif // LL_GST_REPORT_STATE_CHANGES switch (new_state) { case GST_STATE_VOID_PENDING: break; case GST_STATE_NULL: break; case GST_STATE_READY: setStatus(STATUS_LOADED); break; case GST_STATE_PAUSED: setStatus(STATUS_PAUSED); break; case GST_STATE_PLAYING: setStatus(STATUS_PLAYING); break; } break; } case GST_MESSAGE_ERROR: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_error (message, &err, &debug); WARNMSG("GST error: %s", err?err->message:"(unknown)"); if (err) g_error_free (err); g_free (debug); mCommand = COMMAND_STOP; setStatus(STATUS_ERROR); break; } case GST_MESSAGE_INFO: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_info (message, &err, &debug); INFOMSG("GST info: %s", err?err->message:"(unknown)"); if (err) g_error_free (err); g_free (debug); break; } case GST_MESSAGE_WARNING: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_warning (message, &err, &debug); WARNMSG("GST warning: %s", err?err->message:"(unknown)"); if (err) g_error_free (err); g_free (debug); break; } case GST_MESSAGE_TAG: { GstTagList *new_tags; gst_message_parse_tag( message, &new_tags ); gchar *title = NULL; if ( gst_tag_list_get_string(new_tags, GST_TAG_TITLE, &title) ) { //WARMING("Title: %s", title); std::string newtitle(title); gst_tag_list_free(new_tags); if ( newtitle != mLastTitle && !newtitle.empty() ) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); message.setValue("name", newtitle ); sendMessage( message ); mLastTitle = newtitle; } g_free(title); } break; } case GST_MESSAGE_EOS: { /* end-of-stream */ DEBUGMSG("GST end-of-stream."); if (mIsLooping) { DEBUGMSG("looping media..."); double eos_pos_sec = 0.0F; bool got_eos_position = getTimePos(eos_pos_sec); if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) { // if we know that the movie is really short, don't // loop it else it can easily become a time-hog // because of GStreamer spin-up overhead DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); // inject a COMMAND_PAUSE mCommand = COMMAND_PAUSE; } else { #undef LLGST_LOOP_BY_SEEKING // loop with a stop-start instead of a seek, because it actually seems rather // faster than seeking on remote streams. #ifdef LLGST_LOOP_BY_SEEKING // first, try looping by an explicit rewind bool seeksuccess = seek(0.0); if (seeksuccess) { play(1.0); } else #endif // LLGST_LOOP_BY_SEEKING { // use clumsy stop-start to loop DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); stop(); play(1.0); } } } else // not a looping media { // inject a COMMAND_STOP mCommand = COMMAND_STOP; } } break; default: /* unhandled message */ break; } /* we want to be notified again the next time there is a message * on the bus, so return true (false means we want to stop watching * for messages on the bus and our callback should not be called again) */ return TRUE; }
static gboolean gst_PlayRegion_handle_message (GstBus * bus, GstMessage * message, gpointer data) { GstPlayRegion *PlayRegion = (GstPlayRegion *) data; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_APPLICATION: if (gst_message_has_name (message, "ExPrerolled")) { /* it's our message */ g_print ("we are all prerolled, do seek\n"); gst_element_seek (PlayRegion->pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, 2 * GST_SECOND, GST_SEEK_TYPE_SET, 5 * GST_SECOND); gst_element_set_state (PlayRegion->pipeline, GST_STATE_PLAYING); } break; case GST_MESSAGE_EOS: gst_PlayRegion_handle_eos (PlayRegion); break; case GST_MESSAGE_ERROR: { GError *error = NULL; gchar *debug; gst_message_parse_error (message, &error, &debug); gst_PlayRegion_handle_error (PlayRegion, error, debug); } break; case GST_MESSAGE_WARNING: { GError *error = NULL; gchar *debug; gst_message_parse_warning (message, &error, &debug); gst_PlayRegion_handle_warning (PlayRegion, error, debug); } break; case GST_MESSAGE_INFO: { GError *error = NULL; gchar *debug; gst_message_parse_info (message, &error, &debug); gst_PlayRegion_handle_info (PlayRegion, error, debug); } break; case GST_MESSAGE_TAG: { GstTagList *tag_list; gst_message_parse_tag (message, &tag_list); if (verbose) g_print ("tag\n"); } break; case GST_MESSAGE_STATE_CHANGED: { GstState oldstate, newstate, pending; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); if (GST_ELEMENT (message->src) == PlayRegion->pipeline) { if (verbose) g_print ("state change from %s to %s\n", gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate)); switch (GST_STATE_TRANSITION (oldstate, newstate)) { case GST_STATE_CHANGE_NULL_TO_READY: gst_PlayRegion_handle_null_to_ready (PlayRegion); break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_PlayRegion_handle_ready_to_paused (PlayRegion); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: gst_PlayRegion_handle_paused_to_playing (PlayRegion); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: gst_PlayRegion_handle_playing_to_paused (PlayRegion); break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_PlayRegion_handle_paused_to_ready (PlayRegion); break; case GST_STATE_CHANGE_READY_TO_NULL: gst_PlayRegion_handle_ready_to_null (PlayRegion); break; default: if (verbose) g_print ("unknown state change from %s to %s\n", gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate)); } } } break; case GST_MESSAGE_BUFFERING: { int percent; gst_message_parse_buffering (message, &percent); //g_print("buffering %d\n", percent); if (!PlayRegion->paused_for_buffering && percent < 100) { g_print ("pausing for buffing\n"); PlayRegion->paused_for_buffering = TRUE; gst_element_set_state (PlayRegion->pipeline, GST_STATE_PAUSED); } else if (PlayRegion->paused_for_buffering && percent == 100) { g_print ("unpausing for buffing\n"); PlayRegion->paused_for_buffering = FALSE; gst_element_set_state (PlayRegion->pipeline, GST_STATE_PLAYING); } } break; case GST_MESSAGE_STATE_DIRTY: case GST_MESSAGE_CLOCK_PROVIDE: case GST_MESSAGE_CLOCK_LOST: case GST_MESSAGE_NEW_CLOCK: case GST_MESSAGE_STRUCTURE_CHANGE: case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_STEP_DONE: case GST_MESSAGE_ELEMENT: case GST_MESSAGE_SEGMENT_START: case GST_MESSAGE_SEGMENT_DONE: case GST_MESSAGE_DURATION: case GST_MESSAGE_LATENCY: case GST_MESSAGE_ASYNC_START: case GST_MESSAGE_ASYNC_DONE: case GST_MESSAGE_REQUEST_STATE: case GST_MESSAGE_STEP_START: case GST_MESSAGE_QOS: default: if (verbose) { g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message)); } break; } return TRUE; }
/** * gst_bus_timed_pop_filtered: * @bus: a #GstBus to pop from * @timeout: a timeout in nanoseconds, or GST_CLOCK_TIME_NONE to wait forever * @types: message types to take into account, GST_MESSAGE_ANY for any type * * Get a message from the bus whose type matches the message type mask @types, * waiting up to the specified timeout (and discarding any messages that do not * match the mask provided). * * If @timeout is 0, this function behaves like gst_bus_pop_filtered(). If * @timeout is #GST_CLOCK_TIME_NONE, this function will block forever until a * matching message was posted on the bus. * * Returns: (transfer full) (nullable): a #GstMessage matching the * filter in @types, or %NULL if no matching message was found on * the bus until the timeout expired. The message is taken from * the bus and needs to be unreffed with gst_message_unref() after * usage. * * MT safe. */ GstMessage * gst_bus_timed_pop_filtered (GstBus * bus, GstClockTime timeout, GstMessageType types) { GstMessage *message; GTimeVal now, then; gboolean first_round = TRUE; GstClockTime elapsed = 0; g_return_val_if_fail (GST_IS_BUS (bus), NULL); g_return_val_if_fail (types != 0, NULL); g_return_val_if_fail (timeout == 0 || bus->priv->poll != NULL, NULL); g_mutex_lock (&bus->priv->queue_lock); while (TRUE) { gint ret; GST_LOG_OBJECT (bus, "have %d messages", gst_atomic_queue_length (bus->priv->queue)); while ((message = gst_atomic_queue_pop (bus->priv->queue))) { if (bus->priv->poll) gst_poll_read_control (bus->priv->poll); GST_DEBUG_OBJECT (bus, "got message %p, %s from %s, type mask is %u", message, GST_MESSAGE_TYPE_NAME (message), GST_MESSAGE_SRC_NAME (message), (guint) types); if ((GST_MESSAGE_TYPE (message) & types) != 0) { /* Extra check to ensure extended types don't get matched unless * asked for */ if ((!GST_MESSAGE_TYPE_IS_EXTENDED (message)) || (types & GST_MESSAGE_EXTENDED)) { /* exit the loop, we have a message */ goto beach; } } GST_DEBUG_OBJECT (bus, "discarding message, does not match mask"); gst_message_unref (message); message = NULL; } /* no need to wait, exit loop */ if (timeout == 0) break; else if (timeout != GST_CLOCK_TIME_NONE) { if (first_round) { g_get_current_time (&then); first_round = FALSE; } else { g_get_current_time (&now); elapsed = GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (then); if (elapsed > timeout) break; } } /* only here in timeout case */ g_assert (bus->priv->poll); g_mutex_unlock (&bus->priv->queue_lock); ret = gst_poll_wait (bus->priv->poll, timeout - elapsed); g_mutex_lock (&bus->priv->queue_lock); if (ret == 0) { GST_INFO_OBJECT (bus, "timed out, breaking loop"); break; } else { GST_INFO_OBJECT (bus, "we got woken up, recheck for message"); } } beach: g_mutex_unlock (&bus->priv->queue_lock); return message; }
static gboolean bus_message (GstBus * bus, GstMessage * message, App * app) { gchar *sourceName; GstObject *source; gchar *string; GstState current_state; if (!message) return FALSE; source = GST_MESSAGE_SRC (message); if (!GST_IS_OBJECT (source)) return FALSE; sourceName = gst_object_get_name (source); if (gst_message_get_structure (message)) string = gst_structure_to_string (gst_message_get_structure (message)); else string = g_strdup (GST_MESSAGE_TYPE_NAME (message)); GST_DEBUG("gst_message from %s: %s", sourceName, string); g_free (string); switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { GError *gerror; gchar *debug; gst_message_parse_error (message, &gerror, &debug); gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); g_error_free (gerror); g_free (debug); g_main_loop_quit (app->loop); break; } case GST_MESSAGE_WARNING: { GError *gerror; gchar *debug; gst_message_parse_warning (message, &gerror, &debug); gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug); g_error_free (gerror); g_free (debug); // g_main_loop_quit (app->loop); break; } case GST_MESSAGE_EOS: g_message ("received EOS"); g_main_loop_quit (app->loop); break; case GST_MESSAGE_ASYNC_DONE: break; case GST_MESSAGE_ELEMENT: { const GstStructure *msgstruct = gst_message_get_structure (message); if (msgstruct) { const gchar *eventname = gst_structure_get_name (msgstruct); if (!strcmp (eventname, "seekable")) app->is_seekable = TRUE; } break; } case GST_MESSAGE_STATE_CHANGED: { GstState old_state, new_state; GstStateChange transition; if (GST_MESSAGE_SRC (message) != GST_OBJECT (app->tsdemux)) break; gst_message_parse_state_changed (message, &old_state, &new_state, NULL); transition = (GstStateChange) GST_STATE_TRANSITION (old_state, new_state); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { } break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: break; } break; } case GST_MESSAGE_SEGMENT_DONE: { GST_DEBUG ("GST_MESSAGE_SEGMENT_DONE!!!"); do_seek (app); } default: break; } gst_element_get_state (app->pipeline, ¤t_state, NULL, 0); if (app->current_segment == 0 && app->segment_count /*&& app->is_seekable*/ && current_state == GST_STATE_PLAYING) do_seek (app); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(app->pipeline),GST_DEBUG_GRAPH_SHOW_ALL,"bdremux_pipelinegraph_message"); return TRUE; }
// ---------------------------------------------------------------------------- // Retrieve and process a bus message bool GStreamerImportFileHandle::ProcessBusMessage(bool & success) { bool cont = true; // Default to no errors success = true; // Get the next message GstMessage *msg = gst_bus_timed_pop(mBus, 100 * GST_MSECOND); if (!msg) { // Timed out...not an error return cont; } #if defined(__WXDEBUG__) gchar *objname = NULL; if (msg->src != NULL) { objname = gst_object_get_name(msg->src); } wxLogMessage(wxT("GStreamer: Got %s%s%s"), wxString::FromUTF8(GST_MESSAGE_TYPE_NAME(msg)).c_str(), objname ? wxT(" from ") : wxT(""), objname ? wxString::FromUTF8(objname).c_str() : wxT("")); if (objname != NULL) { g_free(objname); } #endif // Handle based on message type switch (GST_MESSAGE_TYPE(msg)) { // Handle error message from gstreamer case GST_MESSAGE_ERROR: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_error(msg, &err, &debug); if (err) { wxString m; m.Printf(wxT("%s%s%s"), wxString::FromUTF8(err->message).c_str(), debug ? wxT("\n") : wxT(""), debug ? wxString::FromUTF8(debug).c_str() : wxT("")); #if defined(_DEBUG) wxMessageBox(m, wxT("GStreamer Error:")); #else wxLogMessage(wxT("GStreamer Error: %s"), m.c_str()); #endif g_error_free(err); } if (debug) { g_free(debug); } success = false; cont = false; } break; // Handle warning message from gstreamer case GST_MESSAGE_WARNING: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_warning(msg, &err, &debug); if (err) { wxLogMessage(wxT("GStreamer Warning: %s%s%s"), wxString::FromUTF8(err->message).c_str(), debug ? wxT("\n") : wxT(""), debug ? wxString::FromUTF8(debug).c_str() : wxT("")); g_error_free(err); } if (debug) { g_free(debug); } } break; // Handle warning message from gstreamer case GST_MESSAGE_INFO: { GError *err = NULL; gchar *debug = NULL; gst_message_parse_info(msg, &err, &debug); if (err) { wxLogMessage(wxT("GStreamer Info: %s%s%s"), wxString::FromUTF8(err->message).c_str(), debug ? wxT("\n") : wxT(""), debug ? wxString::FromUTF8(debug).c_str() : wxT("")); g_error_free(err); } if (debug) { g_free(debug); } } break; // Handle metadata tags case GST_MESSAGE_TAG: { GstTagList *tags = NULL; // Retrieve tag list from message...just ignore failure gst_message_parse_tag(msg, &tags); if (tags) { // Go process the list OnTag(GST_APP_SINK(GST_MESSAGE_SRC(msg)), tags); // Done with list gst_tag_list_unref(tags); } } break; // Pre-roll is done...will happen for each group // (like with chained OGG files) case GST_MESSAGE_ASYNC_DONE: { // If this is the first async-done message, then tell // caller to end loop, but leave it active so that // gstreamer threads can still queue up. // // We'll receive multiple async-done messages for chained // ogg files, so ignore the message the 2nd and subsequent // occurrences. if (!mAsyncDone) { cont = false; mAsyncDone = true; } } break; // End of the stream (and all sub-streams) case GST_MESSAGE_EOS: { // Terminate loop cont = false; } break; } // Release the message gst_message_unref(msg); return cont; }
static gboolean gst_switchui_handle_message (GstBus * bus, GstMessage * message, gpointer data) { GstSwitchUI *switchui = (GstSwitchUI *) data; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: gst_switchui_handle_eos (switchui); break; case GST_MESSAGE_ERROR: { GError *error = NULL; gchar *debug; gst_message_parse_error (message, &error, &debug); gst_switchui_handle_error (switchui, error, debug); } break; case GST_MESSAGE_WARNING: { GError *error = NULL; gchar *debug; gst_message_parse_warning (message, &error, &debug); gst_switchui_handle_warning (switchui, error, debug); } break; case GST_MESSAGE_INFO: { GError *error = NULL; gchar *debug; gst_message_parse_info (message, &error, &debug); gst_switchui_handle_info (switchui, error, debug); } break; case GST_MESSAGE_TAG: { GstTagList *tag_list; gst_message_parse_tag (message, &tag_list); if (verbose) g_print ("tag\n"); } break; case GST_MESSAGE_STATE_CHANGED: { GstState oldstate, newstate, pending; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); if (GST_ELEMENT (message->src) == switchui->pipeline) { if (verbose) g_print ("state change from %s to %s\n", gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate)); switch (GST_STATE_TRANSITION (oldstate, newstate)) { case GST_STATE_CHANGE_NULL_TO_READY: gst_switchui_handle_null_to_ready (switchui); break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_switchui_handle_ready_to_paused (switchui); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: gst_switchui_handle_paused_to_playing (switchui); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: gst_switchui_handle_playing_to_paused (switchui); break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_switchui_handle_paused_to_ready (switchui); break; case GST_STATE_CHANGE_READY_TO_NULL: gst_switchui_handle_ready_to_null (switchui); break; default: if (verbose) g_print ("unknown state change from %s to %s\n", gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate)); } } } break; case GST_MESSAGE_BUFFERING: { int percent; gst_message_parse_buffering (message, &percent); //g_print("buffering %d\n", percent); if (!switchui->paused_for_buffering && percent < 100) { g_print ("pausing for buffing\n"); switchui->paused_for_buffering = TRUE; gst_element_set_state (switchui->pipeline, GST_STATE_PAUSED); } else if (switchui->paused_for_buffering && percent == 100) { g_print ("unpausing for buffing\n"); switchui->paused_for_buffering = FALSE; gst_element_set_state (switchui->pipeline, GST_STATE_PLAYING); } } break; case GST_MESSAGE_STATE_DIRTY: case GST_MESSAGE_CLOCK_PROVIDE: case GST_MESSAGE_CLOCK_LOST: case GST_MESSAGE_NEW_CLOCK: case GST_MESSAGE_STRUCTURE_CHANGE: case GST_MESSAGE_STREAM_STATUS: break; case GST_MESSAGE_STEP_DONE: case GST_MESSAGE_APPLICATION: case GST_MESSAGE_ELEMENT: case GST_MESSAGE_SEGMENT_START: case GST_MESSAGE_SEGMENT_DONE: //case GST_MESSAGE_DURATION: case GST_MESSAGE_LATENCY: case GST_MESSAGE_ASYNC_START: case GST_MESSAGE_ASYNC_DONE: case GST_MESSAGE_REQUEST_STATE: case GST_MESSAGE_STEP_START: case GST_MESSAGE_QOS: default: if (verbose) { g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message)); } break; } return TRUE; }
/** * gst_bus_timed_pop_filtered: * @bus: a #GstBus to pop from * @timeout: a timeout in nanoseconds, or GST_CLOCK_TIME_NONE to wait forever * @types: message types to take into account, GST_MESSAGE_ANY for any type * * Get a message from the bus whose type matches the message type mask @types, * waiting up to the specified timeout (and discarding any messages that do not * match the mask provided). * * If @timeout is 0, this function behaves like gst_bus_pop_filtered(). If * @timeout is #GST_CLOCK_TIME_NONE, this function will block forever until a * matching message was posted on the bus. * * Returns: (transfer full) (nullable): a #GstMessage matching the * filter in @types, or %NULL if no matching message was found on * the bus until the timeout expired. The message is taken from * the bus and needs to be unreffed with gst_message_unref() after * usage. * * MT safe. */ GstMessage * gst_bus_timed_pop_filtered (GstBus * bus, GstClockTime timeout, GstMessageType types) { GstMessage *message; GTimeVal now, then; gboolean first_round = TRUE; GstClockTime elapsed = 0; g_return_val_if_fail (GST_IS_BUS (bus), NULL); g_return_val_if_fail (types != 0, NULL); g_return_val_if_fail (timeout == 0 || bus->priv->poll != NULL, NULL); g_mutex_lock (&bus->priv->queue_lock); while (TRUE) { gint ret; GST_LOG_OBJECT (bus, "have %d messages", gst_atomic_queue_length (bus->priv->queue)); while ((message = gst_atomic_queue_pop (bus->priv->queue))) { if (bus->priv->poll) { while (!gst_poll_read_control (bus->priv->poll)) { if (errno == EWOULDBLOCK) { /* Retry, this can happen if pushing to the queue has finished, * popping here succeeded but writing control did not finish * before we got to this line. */ /* Give other threads the chance to do something */ g_thread_yield (); continue; } else { /* This is a real error and means that either the bus is in an * inconsistent state, or the GstPoll is invalid. GstPoll already * prints a critical warning about this, no need to do that again * ourselves */ break; } } } GST_DEBUG_OBJECT (bus, "got message %p, %s from %s, type mask is %u", message, GST_MESSAGE_TYPE_NAME (message), GST_MESSAGE_SRC_NAME (message), (guint) types); if ((GST_MESSAGE_TYPE (message) & types) != 0) { /* Extra check to ensure extended types don't get matched unless * asked for */ if ((!GST_MESSAGE_TYPE_IS_EXTENDED (message)) || (types & GST_MESSAGE_EXTENDED)) { /* exit the loop, we have a message */ goto beach; } } GST_DEBUG_OBJECT (bus, "discarding message, does not match mask"); gst_message_unref (message); message = NULL; } /* no need to wait, exit loop */ if (timeout == 0) break; else if (timeout != GST_CLOCK_TIME_NONE) { if (first_round) { g_get_current_time (&then); first_round = FALSE; } else { g_get_current_time (&now); elapsed = GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (then); if (elapsed > timeout) break; } } /* only here in timeout case */ g_assert (bus->priv->poll); g_mutex_unlock (&bus->priv->queue_lock); ret = gst_poll_wait (bus->priv->poll, timeout - elapsed); g_mutex_lock (&bus->priv->queue_lock); if (ret == 0) { GST_INFO_OBJECT (bus, "timed out, breaking loop"); break; } else { GST_INFO_OBJECT (bus, "we got woken up, recheck for message"); } } beach: g_mutex_unlock (&bus->priv->queue_lock); return message; }