static gboolean bus_watch_handler(GstBus *bus, GstMessage *msg, gpointer data) { struct ausrc_st *st = data; GMainLoop *loop = st->loop; GstTagList *tag_list; gchar *title; GError *err; gchar *d; (void)bus; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: DEBUG_NOTICE("End-of-stream\n"); /* XXX decrementing repeat count? */ /* Re-start stream */ if (st->run) { gst_element_set_state(st->pipeline, GST_STATE_NULL); gst_element_set_state(st->pipeline, GST_STATE_PLAYING); } else { g_main_loop_quit(loop); } break; case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &d); DEBUG_WARNING("Error: %d(%m) message=%s\n", err->code, err->code, err->message); DEBUG_WARNING("Debug: %s\n", d); g_free(d); /* Call error handler */ if (st->errh) st->errh(err->code, err->message, st->arg); g_error_free(err); st->run = false; g_main_loop_quit(loop); break; case GST_MESSAGE_TAG: gst_message_parse_tag(msg, &tag_list); if (gst_tag_list_get_string(tag_list, GST_TAG_TITLE, &title)) { DEBUG_NOTICE("Title: %s\n", title); g_free(title); } break; default: break; } return TRUE; }
GstBusSyncReply Gst_bus_call(GstBus * bus, GstMessage *msg, gpointer user_data) { gchar * sourceName; // source GstObject * source; source = GST_MESSAGE_SRC(msg); if (!GST_IS_OBJECT(source)) return GST_BUS_DROP; sourceName = gst_object_get_name(source); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: { g_message("End-of-stream"); end_eof = 1; break; } case GST_MESSAGE_ERROR: { gchar * debug; GError *err; gst_message_parse_error(msg, &err, &debug); g_free (debug); lt_info_c( "%s:%s - GST_MESSAGE_ERROR: %s (%i) from %s\n", FILENAME, __FUNCTION__, 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") ) lt_info_c( "%s:%s - GST_MESSAGE_ERROR: videosink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? else if ( g_strrstr(sourceName, "audiosink") ) lt_info_c( "%s:%s - GST_MESSAGE_ERROR: audioSink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? } } g_error_free(err); end_eof = 1; // NOTE: just to exit 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") ) lt_info_c( "%s:%s - GST_MESSAGE_INFO: videosink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? } 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); if(fd >= 0) { int ret = write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image)); close(fd); lt_info_c( "%s:%s - GST_MESSAGE_INFO: cPlayback::state /tmp/.id3coverart %d bytes written\n", FILENAME, __FUNCTION__ , ret); } //FIXME: how shall playback handle this event??? } gst_tag_list_free(tags); lt_info_c( "%s:%s - GST_MESSAGE_INFO: update info tags\n", FILENAME, __FUNCTION__); //FIXME: how shall playback handle this event??? 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; lt_info_c( "%s:%s - GST_MESSAGE_STATE_CHANGED: state transition %s -> %s\n", FILENAME, __FUNCTION__, 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: { GstIterator *children; if (audioSink) { gst_object_unref(GST_OBJECT(audioSink)); audioSink = NULL; } if (videoSink) { gst_object_unref(GST_OBJECT(videoSink)); videoSink = NULL; } children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin)); audioSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBAudioSink")); videoSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBVideoSink")); gst_iterator_free(children); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { } break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: { } break; case GST_STATE_CHANGE_PAUSED_TO_READY: { if (audioSink) { gst_object_unref(GST_OBJECT(audioSink)); audioSink = NULL; } if (videoSink) { gst_object_unref(GST_OBJECT(videoSink)); videoSink = NULL; } } break; case GST_STATE_CHANGE_READY_TO_NULL: { } break; } break; } #if 0 case GST_MESSAGE_ELEMENT: { if(gst_structure_has_name(gst_message_get_structure(msg), "prepare-xwindow-id")) { // set window id gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC (msg)), glfb->getWindowID()); // reshape window gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(GST_MESSAGE_SRC (msg)), 0, 0, glfb->getOSDWidth(), glfb->getOSDHeight()); // sync frames gst_x_overlay_expose(GST_X_OVERLAY(GST_MESSAGE_SRC (msg))); } } #endif break; default: break; } return GST_BUS_DROP; }
/* FIXME: Copy from owr/orw.c without any error handling whatsoever */ static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer user_data) { gboolean ret, is_warning = FALSE; GstStateChangeReturn change_status; gchar *message_type, *debug; GError *error; OwrMediaSource *media_source = user_data; GstElement *pipeline; g_return_val_if_fail(GST_IS_BUS(bus), TRUE); (void)user_data; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_LATENCY: pipeline = _owr_media_source_get_source_bin(media_source); g_return_val_if_fail(pipeline, TRUE); ret = gst_bin_recalculate_latency(GST_BIN(pipeline)); g_warn_if_fail(ret); g_object_unref(pipeline); break; case GST_MESSAGE_CLOCK_LOST: pipeline = _owr_media_source_get_source_bin(media_source); g_return_val_if_fail(pipeline, TRUE); change_status = gst_element_set_state(pipeline, GST_STATE_PAUSED); g_warn_if_fail(change_status != GST_STATE_CHANGE_FAILURE); change_status = gst_element_set_state(pipeline, GST_STATE_PLAYING); g_warn_if_fail(change_status != GST_STATE_CHANGE_FAILURE); g_object_unref(pipeline); break; case GST_MESSAGE_EOS: g_print("End of stream\n"); break; case GST_MESSAGE_WARNING: is_warning = TRUE; case GST_MESSAGE_ERROR: if (is_warning) { message_type = "Warning"; gst_message_parse_warning(msg, &error, &debug); } else { message_type = "Error"; gst_message_parse_error(msg, &error, &debug); } g_printerr("==== %s message start ====\n", message_type); g_printerr("%s in element %s.\n", message_type, GST_OBJECT_NAME(msg->src)); g_printerr("%s: %s\n", message_type, error->message); g_printerr("Debugging info: %s\n", (debug) ? debug : "none"); g_printerr("==== %s message stop ====\n", message_type); /*GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline.dot");*/ if (!is_warning) { OWR_POST_ERROR(media_source, PROCESSING_ERROR, NULL); } g_error_free(error); g_free(debug); break; default: break; } return TRUE; }
static gboolean gst_inter_test_handle_message (GstBus * bus, GstMessage * message, gpointer data) { GstInterTest *intertest = (GstInterTest *) data; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: gst_inter_test_handle_eos (intertest); break; case GST_MESSAGE_ERROR: { GError *error = NULL; gchar *debug; gst_message_parse_error (message, &error, &debug); gst_inter_test_handle_error (intertest, error, debug); } break; case GST_MESSAGE_WARNING: { GError *error = NULL; gchar *debug; gst_message_parse_warning (message, &error, &debug); gst_inter_test_handle_warning (intertest, error, debug); } break; case GST_MESSAGE_INFO: { GError *error = NULL; gchar *debug; gst_message_parse_info (message, &error, &debug); gst_inter_test_handle_info (intertest, 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) == intertest->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_inter_test_handle_null_to_ready (intertest); break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_inter_test_handle_ready_to_paused (intertest); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: gst_inter_test_handle_paused_to_playing (intertest); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: gst_inter_test_handle_playing_to_paused (intertest); break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_inter_test_handle_paused_to_ready (intertest); break; case GST_STATE_CHANGE_READY_TO_NULL: gst_inter_test_handle_ready_to_null (intertest); 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 (!intertest->paused_for_buffering && percent < 100) { g_print ("pausing for buffing\n"); intertest->paused_for_buffering = TRUE; gst_element_set_state (intertest->pipeline, GST_STATE_PAUSED); } else if (intertest->paused_for_buffering && percent == 100) { g_print ("unpausing for buffing\n"); intertest->paused_for_buffering = FALSE; gst_element_set_state (intertest->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: default: if (verbose) { g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message)); } break; case GST_MESSAGE_QOS: break; } return TRUE; }
/*! * \brief handleMessage * Handles gstreamer bus messages. Mainly for debugging purposes and ensuring clean shutdown on error */ void handleMessage(GstElement * pipeline) { CV_FUNCNAME("handlemessage"); GError *err = NULL; gchar *debug = NULL; GstBus* bus = NULL; GstStreamStatusType tp; GstElement * elem = NULL; GstMessage* msg = NULL; __BEGIN__; bus = gst_element_get_bus(pipeline); while(gst_bus_have_pending(bus)) { msg = gst_bus_pop(bus); //printf("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg)); if(gst_is_missing_plugin_message(msg)) { CV_ERROR(CV_StsError, "GStreamer: your gstreamer installation is missing a required plugin\n"); } else { switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_STATE_CHANGED: GstState oldstate, newstate, pendstate; gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate); //fprintf(stderr, "state changed from %s to %s (pending: %s)\n", gst_element_state_get_name(oldstate), // gst_element_state_get_name(newstate), gst_element_state_get_name(pendstate)); break; case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &debug); //fprintf(stderr, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s\n", // gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message); g_error_free(err); g_free(debug); gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL); break; case GST_MESSAGE_EOS: //fprintf(stderr, "reached the end of the stream."); break; case GST_MESSAGE_STREAM_STATUS: gst_message_parse_stream_status(msg,&tp,&elem); //fprintf(stderr, "stream status: elem %s, %i\n", GST_ELEMENT_NAME(elem), tp); break; default: //fprintf(stderr, "unhandled message\n"); break; } } gst_message_unref(msg); } gst_object_unref(GST_OBJECT(bus)); __END__ }
void NPlaybackEngineGStreamer::checkStatus() { GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_playbin)); GstMessage *msg; while ((msg = gst_bus_pop_filtered(bus, GstMessageType(GST_MESSAGE_EOS | GST_MESSAGE_ERROR))) != NULL) { switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: { stop(); emit finished(); emit stateChanged(m_oldState = N::PlaybackStopped); break; } case GST_MESSAGE_ERROR: { gchar *debug; GError *err = NULL; gst_message_parse_error(msg, &err, &debug); g_free(debug); emit message(QMessageBox::Critical, QFileInfo(m_currentMedia).absoluteFilePath(), err ? QString::fromUtf8(err->message) : "unknown error"); fail(); if (err) g_error_free(err); break; } default: break; } gst_message_unref(msg); } gst_object_unref(bus); GstState gstState; if (gst_element_get_state(m_playbin, &gstState, NULL, 0) != GST_STATE_CHANGE_SUCCESS) return; N::PlaybackState state = fromGstState(gstState); if (m_oldState != state) emit stateChanged(m_oldState = state); if (state == N::PlaybackPlaying || state == N::PlaybackPaused) { // duration may change for some reason // TODO use DURATION_CHANGED in gstreamer1.0 gboolean res = gst_element_query_duration(m_playbin, GST_FORMAT_TIME, &m_durationNsec); if (!res) m_durationNsec = 0; } if (m_posponedPosition >= 0 && m_durationNsec > 0) { setPosition(m_posponedPosition); m_posponedPosition = -1; emit positionChanged(m_posponedPosition); } else { qreal pos; gint64 gstPos = 0; if (!hasMedia() || m_durationNsec <= 0) { pos = -1; } else { gboolean res = gst_element_query_position(m_playbin, GST_FORMAT_TIME, &gstPos); if (!res) gstPos = 0; pos = (qreal)gstPos / m_durationNsec; } if (m_oldPosition != pos) { if (m_oldPosition > pos) m_crossfading = false; m_oldPosition = pos; emit positionChanged(m_crossfading ? 0 : m_oldPosition); } emit tick(m_crossfading ? 0 : gstPos / NSEC_IN_MSEC); } qreal vol = volume(); if (qAbs(m_oldVolume - vol) > 0.0001) { m_oldVolume = vol; emit volumeChanged(vol); } if (state == N::PlaybackStopped) m_timer->stop(); }
static VALUE set_type(VALUE self, VALUE type) { GST_MESSAGE_TYPE(SELF(self)) = RVAL2GST_MSG_TYPE(type); return Qnil; }
static gboolean bus_cb (GstBus *bus, GstMessage *message, RBPlayerGst *mp) { const GstStructure *structure; g_return_val_if_fail (mp != NULL, FALSE); switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { char *debug; GError *error = NULL; GError *sig_error = NULL; int code; gboolean emit = TRUE; gst_message_parse_error (message, &error, &debug); /* If we've already got an error, ignore 'internal data flow error' * type messages, as they're too generic to be helpful. */ if (mp->priv->emitted_error && error->domain == GST_STREAM_ERROR && error->code == GST_STREAM_ERROR_FAILED) { rb_debug ("Ignoring generic error \"%s\"", error->message); emit = FALSE; } code = rb_gst_error_get_error_code (error); if (emit) { if (message_from_sink (mp->priv->audio_sink, message)) { rb_debug ("got error from sink: %s (%s)", error->message, debug); /* Translators: the parameter here is an error message */ g_set_error (&sig_error, RB_PLAYER_ERROR, code, _("Failed to open output device: %s"), error->message); } else { rb_debug ("got error from stream: %s (%s)", error->message, debug); g_set_error (&sig_error, RB_PLAYER_ERROR, code, "%s", error->message); } state_change_finished (mp, sig_error); mp->priv->emitted_error = TRUE; if (mp->priv->playbin_stream_changing) { emit_playing_stream_and_tags (mp, TRUE); } _rb_player_emit_error (RB_PLAYER (mp), mp->priv->stream_data, sig_error); } /* close if not already closing */ if (mp->priv->uri != NULL) rb_player_close (RB_PLAYER (mp), NULL, NULL); g_error_free (error); g_free (debug); break; } case GST_MESSAGE_EOS: _rb_player_emit_eos (RB_PLAYER (mp), mp->priv->stream_data, FALSE); break; case GST_MESSAGE_STATE_CHANGED: { GstState oldstate; GstState newstate; GstState pending; gst_message_parse_state_changed (message, &oldstate, &newstate, &pending); if (GST_MESSAGE_SRC (message) == GST_OBJECT (mp->priv->playbin)) { if (pending == GST_STATE_VOID_PENDING) { rb_debug ("playbin reached state %s", gst_element_state_get_name (newstate)); state_change_finished (mp, NULL); } } break; } case GST_MESSAGE_TAG: { GstTagList *tags; gst_message_parse_tag (message, &tags); if (mp->priv->stream_change_pending || mp->priv->playbin_stream_changing) { mp->priv->stream_tags = g_list_append (mp->priv->stream_tags, tags); } else { gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, mp); gst_tag_list_free (tags); } break; } case GST_MESSAGE_BUFFERING: { gint progress; structure = gst_message_get_structure (message); if (!gst_structure_get_int (structure, "buffer-percent", &progress)) { g_warning ("Could not get value from BUFFERING message"); break; } if (progress >= 100) { mp->priv->buffering = FALSE; if (mp->priv->playing) { rb_debug ("buffering done, setting pipeline back to PLAYING"); gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING); } else { rb_debug ("buffering done, leaving pipeline PAUSED"); } } else if (mp->priv->buffering == FALSE && mp->priv->playing) { rb_debug ("buffering - temporarily pausing playback"); gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED); mp->priv->buffering = TRUE; } _rb_player_emit_buffering (RB_PLAYER (mp), mp->priv->stream_data, progress); break; } case GST_MESSAGE_APPLICATION: structure = gst_message_get_structure (message); _rb_player_emit_event (RB_PLAYER (mp), mp->priv->stream_data, gst_structure_get_name (structure), NULL); break; case GST_MESSAGE_ELEMENT: structure = gst_message_get_structure (message); if (gst_is_missing_plugin_message (message)) { handle_missing_plugin_message (mp, message); } else if (mp->priv->playbin_stream_changing && gst_structure_has_name (structure, "playbin2-stream-changed")) { rb_debug ("got playbin2-stream-changed message"); mp->priv->playbin_stream_changing = FALSE; emit_playing_stream_and_tags (mp, TRUE); } else if (gst_structure_has_name (structure, "redirect")) { const char *uri = gst_structure_get_string (structure, "new-location"); _rb_player_emit_redirect (RB_PLAYER (mp), mp->priv->stream_data, uri); } break; default: break; } /* emit message signals too, so plugins can process messages */ gst_bus_async_signal_func (bus, message, NULL); return TRUE; }
static int run_test (const char *format, ...) { GstStateChangeReturn ret; GstElement *pipe, *src, *sink; GstBuffer *buf = NULL; GstMessage *msg; gchar *url; va_list args; int rc = -1; pipe = gst_pipeline_new (NULL); src = gst_element_factory_make ("souphttpsrc", NULL); fail_unless (src != NULL); sink = gst_element_factory_make ("fakesink", NULL); fail_unless (sink != NULL); gst_bin_add (GST_BIN (pipe), src); gst_bin_add (GST_BIN (pipe), sink); fail_unless (gst_element_link (src, sink)); if (http_port == 0) { GST_DEBUG ("failed to start soup http server"); } fail_unless (http_port != 0); va_start (args, format); g_vasprintf (&url, format, args); va_end (args); fail_unless (url != NULL); g_object_set (src, "location", url, NULL); g_free (url); g_object_set (src, "automatic-redirect", redirect, NULL); if (cookies != NULL) g_object_set (src, "cookies", cookies, NULL); g_object_set (sink, "signal-handoffs", TRUE, NULL); g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf); if (user_id != NULL) g_object_set (src, "user-id", user_id, NULL); if (user_pw != NULL) g_object_set (src, "user-pw", user_pw, NULL); ret = gst_element_set_state (pipe, GST_STATE_PAUSED); if (ret != GST_STATE_CHANGE_ASYNC) { GST_DEBUG ("failed to start up soup http src, ret = %d", ret); goto done; } gst_element_set_state (pipe, GST_STATE_PLAYING); msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1); if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { gchar *debug = NULL; GError *err = NULL; gst_message_parse_error (msg, &err, &debug); GST_INFO ("error: %s", err->message); if (g_str_has_suffix (err->message, "Not Found")) rc = 404; else if (g_str_has_suffix (err->message, "Forbidden")) rc = 403; else if (g_str_has_suffix (err->message, "Unauthorized")) rc = 401; else if (g_str_has_suffix (err->message, "Found")) rc = 302; GST_INFO ("debug: %s", debug); g_error_free (err); g_free (debug); gst_message_unref (msg); goto done; } gst_message_unref (msg); /* don't wait for more than 10 seconds */ ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND); GST_LOG ("ret = %u", ret); if (buf == NULL) { /* we want to test the buffer offset, nothing else; if there's a failure * it might be for lots of reasons (no network connection, whatever), we're * not interested in those */ GST_DEBUG ("didn't manage to get data within 10 seconds, skipping test"); goto done; } GST_DEBUG ("buffer offset = %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf)); /* first buffer should have a 0 offset */ fail_unless (GST_BUFFER_OFFSET (buf) == 0); gst_buffer_unref (buf); rc = 0; done: gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); return rc; }
gboolean MediaPluginGStreamer010::processGSTEvents(GstBus *bus, GstMessage *message) { if (!message) return TRUE; // shield against GStreamer bug // TODO: grok 'duration' message type if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING && GST_MESSAGE_TYPE(message) != GST_MESSAGE_TAG) { writeToLog("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); writeToLog("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. writeToLog("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); writeToLog("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); writeToLog("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); writeToLog("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) ) { //writeToLog("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 */ writeToLog("GST end-of-stream."); if (mIsLooping) { //writeToLog("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 writeToLog("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 writeToLog("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; }
nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); nsresult ret = NS_OK; /* * Parse MP3 headers before we kick off the GStreamer pipeline otherwise there * might be concurrent stream operations happening on both decoding and gstreamer * threads which will screw the GStreamer state machine. */ bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3); if (isMP3) { ParseMP3Headers(); } /* We do 3 attempts here: decoding audio and video, decoding video only, * decoding audio only. This allows us to play streams that have one broken * stream but that are otherwise decodeable. */ guint flags[3] = {GST_PLAY_FLAG_VIDEO|GST_PLAY_FLAG_AUDIO, static_cast<guint>(~GST_PLAY_FLAG_AUDIO), static_cast<guint>(~GST_PLAY_FLAG_VIDEO)}; guint default_flags, current_flags; g_object_get(mPlayBin, "flags", &default_flags, nullptr); GstMessage* message = nullptr; for (unsigned int i = 0; i < G_N_ELEMENTS(flags); i++) { current_flags = default_flags & flags[i]; g_object_set(G_OBJECT(mPlayBin), "flags", current_flags, nullptr); /* reset filter caps to ANY */ GstCaps* caps = gst_caps_new_any(); GstElement* filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter"); g_object_set(filter, "caps", caps, nullptr); gst_object_unref(filter); filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter"); g_object_set(filter, "caps", caps, nullptr); gst_object_unref(filter); gst_caps_unref(caps); filter = nullptr; if (!(current_flags & GST_PLAY_FLAG_AUDIO)) filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter"); else if (!(current_flags & GST_PLAY_FLAG_VIDEO)) filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter"); if (filter) { /* Little trick: set the target caps to "skip" so that playbin2 fails to * find a decoder for the stream we want to skip. */ GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr, nullptr); g_object_set(filter, "caps", filterCaps, nullptr); gst_caps_unref(filterCaps); gst_object_unref(filter); } LOG(PR_LOG_DEBUG, "starting metadata pipeline"); if (gst_element_set_state(mPlayBin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { LOG(PR_LOG_DEBUG, "metadata pipeline state change failed"); ret = NS_ERROR_FAILURE; continue; } /* Wait for ASYNC_DONE, which is emitted when the pipeline is built, * prerolled and ready to play. Also watch for errors. */ message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ASYNC_DONE) { LOG(PR_LOG_DEBUG, "read metadata pipeline prerolled"); gst_message_unref(message); ret = NS_OK; break; } else { LOG(PR_LOG_DEBUG, "read metadata pipeline failed to preroll: %s", gst_message_type_get_name (GST_MESSAGE_TYPE (message))); if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { GError* error; gchar* debug; gst_message_parse_error(message, &error, &debug); LOG(PR_LOG_ERROR, "read metadata error: %s: %s", error->message, debug); g_error_free(error); g_free(debug); } /* Unexpected stream close/EOS or other error. We'll give up if all * streams are in error/eos. */ gst_element_set_state(mPlayBin, GST_STATE_NULL); gst_message_unref(message); ret = NS_ERROR_FAILURE; } } if (NS_SUCCEEDED(ret)) ret = CheckSupportedFormats(); if (NS_FAILED(ret)) /* we couldn't get this to play */ return ret; /* report the duration */ gint64 duration; if (isMP3 && mMP3FrameParser.IsMP3()) { // The MP3FrameParser has reported a duration; use that over the gstreamer // reported duration for inter-platform consistency. ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mUseParserDuration = true; mLastParserDuration = mMP3FrameParser.GetDuration(); mDecoder->SetMediaDuration(mLastParserDuration); } else { LOG(PR_LOG_DEBUG, "querying duration"); // Otherwise use the gstreamer duration. #if GST_VERSION_MAJOR >= 1 if (gst_element_query_duration(GST_ELEMENT(mPlayBin), GST_FORMAT_TIME, &duration)) { #else GstFormat format = GST_FORMAT_TIME; if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration) && format == GST_FORMAT_TIME) { #endif ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); LOG(PR_LOG_DEBUG, "have duration %" GST_TIME_FORMAT, GST_TIME_ARGS(duration)); duration = GST_TIME_AS_USECONDS (duration); mDecoder->SetMediaDuration(duration); } else { mDecoder->SetMediaSeekable(false); } } int n_video = 0, n_audio = 0; g_object_get(mPlayBin, "n-video", &n_video, "n-audio", &n_audio, nullptr); mInfo.mVideo.mHasVideo = n_video != 0; mInfo.mAudio.mHasAudio = n_audio != 0; *aInfo = mInfo; *aTags = nullptr; // Watch the pipeline for fatal errors #if GST_VERSION_MAJOR >= 1 gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this, nullptr); #else gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this); #endif /* set the pipeline to PLAYING so that it starts decoding and queueing data in * the appsinks */ gst_element_set_state(mPlayBin, GST_STATE_PLAYING); return NS_OK; } nsresult GStreamerReader::CheckSupportedFormats() { bool done = false; bool unsupported = false; GstIterator* it = gst_bin_iterate_recurse(GST_BIN(mPlayBin)); while (!done) { GstIteratorResult res; GstElement* element; #if GST_VERSION_MAJOR >= 1 GValue value = {0,}; res = gst_iterator_next(it, &value); #else res = gst_iterator_next(it, (void **) &element); #endif switch(res) { case GST_ITERATOR_OK: { #if GST_VERSION_MAJOR >= 1 element = GST_ELEMENT (g_value_get_object (&value)); #endif GstElementFactory* factory = gst_element_get_factory(element); if (factory) { const char* klass = gst_element_factory_get_klass(factory); GstPad* pad = gst_element_get_static_pad(element, "sink"); if (pad) { GstCaps* caps; #if GST_VERSION_MAJOR >= 1 caps = gst_pad_get_current_caps(pad); #else caps = gst_pad_get_negotiated_caps(pad); #endif if (caps) { /* check for demuxers but ignore elements like id3demux */ if (strstr (klass, "Demuxer") && !strstr(klass, "Metadata")) unsupported = !GStreamerFormatHelper::Instance()->CanHandleContainerCaps(caps); else if (strstr (klass, "Decoder") && !strstr(klass, "Generic")) unsupported = !GStreamerFormatHelper::Instance()->CanHandleCodecCaps(caps); gst_caps_unref(caps); } gst_object_unref(pad); } } #if GST_VERSION_MAJOR >= 1 g_value_unset (&value); #else gst_object_unref(element); #endif done = unsupported; break; } case GST_ITERATOR_RESYNC: unsupported = false; done = false; break; case GST_ITERATOR_ERROR: done = true; break; case GST_ITERATOR_DONE: done = true; break; } } return unsupported ? NS_ERROR_FAILURE : NS_OK; } nsresult GStreamerReader::ResetDecode() { nsresult res = NS_OK; LOG(PR_LOG_DEBUG, "reset decode"); if (NS_FAILED(MediaDecoderReader::ResetDecode())) { res = NS_ERROR_FAILURE; } mVideoQueue.Reset(); mAudioQueue.Reset(); mVideoSinkBufferCount = 0; mAudioSinkBufferCount = 0; mReachedAudioEos = false; mReachedVideoEos = false; #if GST_VERSION_MAJOR >= 1 mConfigureAlignment = true; #endif LOG(PR_LOG_DEBUG, "reset decode done"); return res; } bool GStreamerReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); GstBuffer *buffer = nullptr; { ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); if (mReachedAudioEos && !mAudioSinkBufferCount) { return false; } /* Wait something to be decoded before return or continue */ if (!mAudioSinkBufferCount) { if(!mVideoSinkBufferCount) { /* We have nothing decoded so it makes no sense to return to the state machine * as it will call us back immediately, we'll return again and so on, wasting * CPU cycles for no job done. So, block here until there is either video or * audio data available */ mon.Wait(); if (!mAudioSinkBufferCount) { /* There is still no audio data available, so either there is video data or * something else has happened (Eos, etc...). Return to the state machine * to process it. */ return true; } } else { return true; } } #if GST_VERSION_MAJOR >= 1 GstSample *sample = gst_app_sink_pull_sample(mAudioAppSink); buffer = gst_buffer_ref(gst_sample_get_buffer(sample)); gst_sample_unref(sample); #else buffer = gst_app_sink_pull_buffer(mAudioAppSink); #endif mAudioSinkBufferCount--; } int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); timestamp = gst_segment_to_stream_time(&mAudioSegment, GST_FORMAT_TIME, timestamp); timestamp = GST_TIME_AS_USECONDS(timestamp); int64_t offset = GST_BUFFER_OFFSET(buffer); guint8* data; #if GST_VERSION_MAJOR >= 1 GstMapInfo info; gst_buffer_map(buffer, &info, GST_MAP_READ); unsigned int size = info.size; data = info.data; #else unsigned int size = GST_BUFFER_SIZE(buffer); data = GST_BUFFER_DATA(buffer); #endif int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels; typedef AudioCompactor::NativeCopy GstCopy; mAudioCompactor.Push(offset, timestamp, mInfo.mAudio.mRate, frames, mInfo.mAudio.mChannels, GstCopy(data, size, mInfo.mAudio.mChannels)); #if GST_VERSION_MAJOR >= 1 gst_buffer_unmap(buffer, &info); #endif gst_buffer_unref(buffer); return true; }
void MediaImpl::_postRun() { // Parse message. if (_bus != NULL) { GstMessage *msg = gst_bus_timed_pop_filtered( _bus, 0, (GstMessageType) (GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); if (msg != NULL) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &debug_info); g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error(&err); g_free(debug_info); _terminate = true; // _finish(); break; case GST_MESSAGE_EOS: g_print("End-Of-Stream reached.\n"); // _terminate = true; // _finish(); break; case GST_MESSAGE_STATE_CHANGED: // We are only interested in state-changed messages from the pipeline. if (GST_MESSAGE_SRC (msg) == GST_OBJECT (_pipeline)) { GstState oldState, newState, pendingState; gst_message_parse_state_changed(msg, &oldState, &newState, &pendingState); g_print("Pipeline state for movie %s changed from %s to %s:\n", _currentMovie.toUtf8().constData(), gst_element_state_get_name(oldState), gst_element_state_get_name(newState)); // if (oldState == GST_STATE_PAUSED && newState == GST_STATE_READY) // gst_adapter_clear(_audioBufferAdapter); if (newState == GST_STATE_PLAYING) { // Check if seeking is allowed. gint64 start, end; GstQuery *query = gst_query_new_seeking (GST_FORMAT_TIME); if (gst_element_query (_pipeline, query)) { gst_query_parse_seeking (query, NULL, (gboolean*)&_seekEnabled, &start, &end); if (_seekEnabled) { g_print ("Seeking is ENABLED from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (start), GST_TIME_ARGS (end)); } else { g_print ("Seeking is DISABLED for this stream.\n"); } } else { g_printerr ("Seeking query failed."); } gst_query_unref (query); } } break; default: // We should not reach here. g_printerr("Unexpected message received.\n"); break; } gst_message_unref(msg); } } }
QGlib::RefCountedObject *Message_new(void *instance) { QGst::Message *cppClass = NULL; switch(GST_MESSAGE_TYPE(instance)) { case QGst::MessageEos: cppClass = new QGst::EosMessage; break; case QGst::MessageError: cppClass = new QGst::ErrorMessage; break; case QGst::MessageWarning: cppClass = new QGst::WarningMessage; break; case QGst::MessageInfo: cppClass = new QGst::InfoMessage; break; case QGst::MessageTag: cppClass = new QGst::TagMessage; break; case QGst::MessageBuffering: cppClass = new QGst::BufferingMessage; break; case QGst::MessageStateChanged: cppClass = new QGst::StateChangedMessage; break; case QGst::MessageStepDone: cppClass = new QGst::StepDoneMessage; break; case QGst::MessageStreamStatus: cppClass = new QGst::StreamStatusMessage; break; case QGst::MessageApplication: cppClass = new QGst::ApplicationMessage; break; case QGst::MessageElement: cppClass = new QGst::ElementMessage; break; case QGst::MessageSegmentDone: cppClass = new QGst::SegmentDoneMessage; break; case QGst::MessageDuration: cppClass = new QGst::DurationMessage; break; case QGst::MessageLatency: cppClass = new QGst::LatencyMessage; break; case QGst::MessageAsyncDone: cppClass = new QGst::AsyncDoneMessage; break; case QGst::MessageRequestState: cppClass = new QGst::RequestStateMessage; break; case QGst::MessageStepStart: cppClass = new QGst::StepStartMessage; break; case QGst::MessageQos: cppClass = new QGst::QosMessage; break; default: cppClass = new QGst::Message; break; } cppClass->m_object = instance; return cppClass; }
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; }
/** * gst_video_convert_sample: * @sample: a #GstSample * @to_caps: the #GstCaps to convert to * @timeout: the maximum amount of time allowed for the processing. * @error: pointer to a #GError. Can be %NULL. * * Converts a raw video buffer into the specified output caps. * * The output caps can be any raw video formats or any image formats (jpeg, png, ...). * * The width, height and pixel-aspect-ratio can also be specified in the output caps. * * Returns: The converted #GstSample, or %NULL if an error happened (in which case @err * will point to the #GError). */ GstSample * gst_video_convert_sample (GstSample * sample, const GstCaps * to_caps, GstClockTime timeout, GError ** error) { GstMessage *msg; GstBuffer *buf; GstSample *result = NULL; GError *err = NULL; GstBus *bus; GstCaps *from_caps, *to_caps_copy = NULL; GstFlowReturn ret; GstElement *pipeline, *src, *sink; guint i, n; g_return_val_if_fail (sample != NULL, NULL); g_return_val_if_fail (to_caps != NULL, NULL); buf = gst_sample_get_buffer (sample); g_return_val_if_fail (buf != NULL, NULL); from_caps = gst_sample_get_caps (sample); g_return_val_if_fail (from_caps != NULL, NULL); to_caps_copy = gst_caps_new_empty (); n = gst_caps_get_size (to_caps); for (i = 0; i < n; i++) { GstStructure *s = gst_caps_get_structure (to_caps, i); s = gst_structure_copy (s); gst_structure_remove_field (s, "framerate"); gst_caps_append_structure (to_caps_copy, s); } pipeline = build_convert_frame_pipeline (&src, &sink, from_caps, gst_buffer_get_video_crop_meta (buf), to_caps_copy, &err); if (!pipeline) goto no_pipeline; /* now set the pipeline to the paused state, after we push the buffer into * appsrc, this should preroll the converted buffer in appsink */ GST_DEBUG ("running conversion pipeline to caps %" GST_PTR_FORMAT, to_caps_copy); gst_element_set_state (pipeline, GST_STATE_PAUSED); /* feed buffer in appsrc */ GST_DEBUG ("feeding buffer %p, size %" G_GSIZE_FORMAT ", caps %" GST_PTR_FORMAT, buf, gst_buffer_get_size (buf), from_caps); g_signal_emit_by_name (src, "push-buffer", buf, &ret); /* now see what happens. We either got an error somewhere or the pipeline * prerolled */ bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, timeout, GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE); if (msg) { switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ASYNC_DONE: { /* we're prerolled, get the frame from appsink */ g_signal_emit_by_name (sink, "pull-preroll", &result); if (result) { GST_DEBUG ("conversion successful: result = %p", result); } else { GST_ERROR ("prerolled but no result frame?!"); } break; } case GST_MESSAGE_ERROR:{ gchar *dbg = NULL; gst_message_parse_error (msg, &err, &dbg); if (err) { GST_ERROR ("Could not convert video frame: %s", err->message); GST_DEBUG ("%s [debug: %s]", err->message, GST_STR_NULL (dbg)); if (error) *error = err; else g_error_free (err); } g_free (dbg); break; } default:{ g_return_val_if_reached (NULL); } } gst_message_unref (msg); } else { GST_ERROR ("Could not convert video frame: timeout during conversion"); if (error) *error = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, "Could not convert video frame: timeout during conversion"); } gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (bus); gst_object_unref (pipeline); gst_caps_unref (to_caps_copy); return result; /* ERRORS */ no_pipeline: { gst_caps_unref (to_caps_copy); if (error) *error = err; else g_error_free (err); return NULL; } }
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); gchar * name = gst_element_get_name(GST_MESSAGE_SRC (msg)); ofLogError("ofGstUtils") << "gstHandleMessage(): embedded video playback halted for plugin, module " << name << " reported: " << err->message; g_free(name); 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"; bool isClosing = closing; eos_cb(); if(isClosing){ busWatchID = 0; return false; } switch(loopMode){ case OF_LOOP_NORMAL:{ GstFormat format = GST_FORMAT_TIME; GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT); if(speed>0){ if(!gst_element_seek(GST_ELEMENT(gstPipeline), speed, format, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, -1)) { ofLogWarning("ofGstUtils") << "gstHandleMessage(): unable to seek"; } }else if(speed<0){ if(!gst_element_seek(GST_ELEMENT(gstPipeline),speed, format, flags, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, durationNanos-1000000)) { 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; case GST_MESSAGE_LATENCY: gst_bin_recalculate_latency (GST_BIN (getPipeline())); break; case GST_MESSAGE_REQUEST_STATE: { GstState state; gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (msg)); gst_message_parse_request_state (msg, &state); gst_element_set_state (getPipeline(), state); g_free (name); break; } case GST_MESSAGE_HAVE_CONTEXT:{ GstContext *context; const gchar *context_type; gchar *context_str; gst_message_parse_have_context (msg, &context); context_type = gst_context_get_context_type (context); context_str = gst_structure_to_string (gst_context_get_structure (context)); ofLogNotice("ofGstUtils","Got context from element '%s': %s=%s\n", GST_ELEMENT_NAME (GST_MESSAGE_SRC (msg)), context_type, context_str); g_free (context_str); gst_context_unref (context); break; } default: ofLogVerbose("ofGstUtils") << "gstHandleMessage(): unhandled message from " << GST_MESSAGE_SRC_NAME(msg); break; } return true; }
static void bus_message (GstBus * bus, GstMessage * msg, KmsHttpEndpoint * self) { if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) g_signal_emit_by_name (G_OBJECT (self), "eos", 0); }
static GstBusSyncReply bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { const GstStructure *structure; gint64 position, length; GstFormat format = GST_FORMAT_TIME; const GValue *x_value, *y_value; gint x, i, y; /* select msg */ if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT || !gst_structure_has_name (gst_message_get_structure (message), "hand-gesture")) return GST_BUS_PASS; /* parse msg structure */ structure = gst_message_get_structure (message); /* if PALM gesture detected */ if (structure && strcmp (gst_structure_get_name (structure), "hand-gesture") == 0 && strcmp (gst_structure_get_string (structure, "gesture"), "palm") == 0) { /* media operation - closed palm to stop media play */ gst_element_set_state (playbin, GST_STATE_PAUSED); } /* if FIST gesture detected */ if (structure && strcmp (gst_structure_get_name (structure), "hand-gesture") == 0 && strcmp (gst_structure_get_string (structure, "gesture"), "fist") == 0) { /* print message type and structure name */ g_print ("%s{{%s}}\n", gst_message_type_get_name (message->type), gst_structure_get_name (structure)); /* print msg structure names&values */ for (i = 0; i < gst_structure_n_fields (structure); i++) { const gchar *name = gst_structure_nth_field_name (structure, i); GType type = gst_structure_get_field_type (structure, name); const GValue *value = gst_structure_get_value (structure, name); type == G_TYPE_STRING ? g_print ("-%s[%s]{%s}\n", name, g_type_name (type), g_value_get_string (value)) : g_print ("-%s[%s]{%d}\n", name, g_type_name (type), g_value_get_uint (value)); } g_print ("\n"); /* get X,Y positions in frame */ x_value = gst_structure_get_value (structure, "x"); x = g_value_get_uint (x_value); y_value = gst_structure_get_value (structure, "y"); y = g_value_get_uint (y_value); /* set object volumes [0-10] based on Y */ g_object_set (G_OBJECT (playbin), "volume", (gdouble) (10 - y / 24), NULL); /* seek playback positions */ gst_element_query_duration (playbin, format, &length); /* Width = 320 is specified in caps */ position = (gint64) length *x / 320; gst_element_set_state (playbin, GST_STATE_PAUSED); gst_element_seek (GST_ELEMENT (playbin), 1.0, format, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); gst_element_set_state (GST_ELEMENT (playbin), GST_STATE_PLAYING); } gst_message_unref (message); return GST_BUS_DROP; }
static VALUE get_type(VALUE self) { return GST_MSG_TYPE2RVAL(GST_MESSAGE_TYPE(SELF(self))); }
/* 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 VALUE instance2robj(gpointer instance, G_GNUC_UNUSED gpointer user_data) { VALUE klass; GstMessage *message; message = instance; switch (GST_MESSAGE_TYPE(message)) { case GST_MESSAGE_UNKNOWN: klass = rb_cGstMessageUnknown; break; case GST_MESSAGE_EOS: klass = rb_cGstMessageEos; break; case GST_MESSAGE_ERROR: klass = rb_cGstMessageError; break; case GST_MESSAGE_WARNING: klass = rb_cGstMessageWarning; break; case GST_MESSAGE_INFO: klass = rb_cGstMessageInfo; break; case GST_MESSAGE_TAG: klass = rb_cGstMessageTag; break; case GST_MESSAGE_BUFFERING: klass = rb_cGstMessageBuffering; break; case GST_MESSAGE_STATE_CHANGED: klass = rb_cGstMessageStateChanged; break; case GST_MESSAGE_STATE_DIRTY: klass = rb_cGstMessageStateDirty; break; case GST_MESSAGE_STEP_DONE: klass = rb_cGstMessageStepDone; break; case GST_MESSAGE_CLOCK_PROVIDE: klass = rb_cGstMessageClockProvide; break; case GST_MESSAGE_CLOCK_LOST: klass = rb_cGstMessageClockLost; break; case GST_MESSAGE_NEW_CLOCK: klass = rb_cGstMessageNewClock; break; case GST_MESSAGE_STRUCTURE_CHANGE: klass = rb_cGstMessageStructureChange; break; case GST_MESSAGE_STREAM_STATUS: klass = rb_cGstMessageStreamStatus; break; case GST_MESSAGE_APPLICATION: klass = rb_cGstMessageApplication; break; case GST_MESSAGE_ELEMENT: if (gst_is_missing_plugin_message(message)) { klass = rb_cGstMissingMessage; } else { klass = rb_cGstMessageElement; } break; case GST_MESSAGE_SEGMENT_START: klass = rb_cGstMessageSegmentStart; break; case GST_MESSAGE_SEGMENT_DONE: klass = rb_cGstMessageSegmentDone; break; case GST_MESSAGE_DURATION: klass = rb_cGstMessageDuration; break; case GST_MESSAGE_LATENCY: klass = rb_cGstMessageLatency; break; case GST_MESSAGE_ASYNC_START: klass = rb_cGstMessageAsyncStart; break; case GST_MESSAGE_ASYNC_DONE: klass = rb_cGstMessageAsyncDone; break; case GST_MESSAGE_ANY: klass = rb_cGstMessageAny; break; default: klass = rb_cGstMessage; break; } gst_mini_object_ref(instance); return Data_Wrap_Struct(klass, NULL, _rbgst_mini_object_free, instance); }
static gboolean rejilla_song_control_bus_messages (GstBus *bus, GstMessage *msg, RejillaSongControl *player) { RejillaSongControlPrivate *priv; GstStateChangeReturn result; GError *error = NULL; GstState state; priv = REJILLA_SONG_CONTROL_PRIVATE (player); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); if (priv->update_scale_id) { g_source_remove (priv->update_scale_id); priv->update_scale_id = 0; } gtk_range_set_value (GTK_RANGE (priv->progress), 0.0); gst_element_set_state (priv->pipe, GST_STATE_PAUSED); rejilla_song_control_set_pos (player, priv->start); break; case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &error, NULL); g_warning ("%s", error->message); g_error_free (error); gtk_widget_set_sensitive (priv->button, FALSE); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); gtk_widget_set_sensitive (priv->progress, FALSE); gtk_range_set_value (GTK_RANGE (priv->progress), 0.0); break; case GST_MESSAGE_STATE_CHANGED: result = gst_element_get_state (GST_ELEMENT (priv->pipe), &state, NULL, 500); if (result != GST_STATE_CHANGE_SUCCESS) break; if (priv->state == state || state < GST_STATE_READY) break; if (state == GST_STATE_PLAYING) { if (priv->state == GST_STATE_READY) { gdouble pos; pos = gtk_range_get_value (GTK_RANGE (priv->progress)); rejilla_song_control_set_pos (player, priv->start + pos); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE); } if (!priv->update_scale_id) priv->update_scale_id = g_timeout_add (500, (GSourceFunc) rejilla_song_control_update_progress_cb, player); } else if (state == GST_STATE_PAUSED) { if (priv->state != GST_STATE_PLAYING) { gdouble pos; pos = gtk_range_get_value (GTK_RANGE (priv->progress)); rejilla_song_control_set_pos (player, priv->start + pos); } gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); if (priv->update_scale_id) { g_source_remove (priv->update_scale_id); priv->update_scale_id = 0; } } priv->state = state; break; default: break; } return TRUE; }
/* Caution: This function is executed on all sorts of strange threads, which should * not be excessively delayed, deadlocked, or used for anything GUI-related. Primarily, * we want to emit signals (which will result in queued slot calls) or do queued method * invocation to handle GUI updates. */ GstBusSyncReply VideoPlayerBackend::busHandler(GstBus *bus, GstMessage *msg) { Q_UNUSED(bus); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_BUFFERING: { gint percent = 0; gst_message_parse_buffering(msg, &percent); qDebug() << "gstreamer: buffering" << percent << "%"; emit bufferingStatus(percent); } break; case GST_MESSAGE_STATE_CHANGED: { if (m_state == PermanentError) break; GstState oldState, newState; gst_message_parse_state_changed(msg, &oldState, &newState, 0); VideoState vpState = m_state; switch (newState) { case GST_STATE_VOID_PENDING: case GST_STATE_NULL: if (m_state == Error) break; case GST_STATE_READY: vpState = Stopped; break; case GST_STATE_PAUSED: vpState = Paused; emit durationChanged(duration()); break; case GST_STATE_PLAYING: vpState = Playing; emit durationChanged(duration()); break; } if (vpState != m_state) { VideoState old = m_state; m_state = vpState; emit stateChanged(m_state, old); } } break; case GST_MESSAGE_DURATION: emit durationChanged(duration()); break; case GST_MESSAGE_EOS: { qDebug("gstreamer: end of stream"); VideoState old = m_state; m_state = Done; emit stateChanged(m_state, old); emit endOfStream(); } break; case GST_MESSAGE_ERROR: { gchar *debug; GError *error; gst_message_parse_error(msg, &error, &debug); qDebug() << "gstreamer: Error:" << error->message; qDebug() << "gstreamer: Debug:" << debug; /* Set the error message, but don't move to the error state, because that will stop playback, * possibly incorrectly. */ m_errorMessage = QString::fromLatin1(error->message); g_free(debug); g_error_free(error); } break; case GST_MESSAGE_WARNING: { gchar *debug; GError *error; gst_message_parse_warning(msg, &error, &debug); qDebug() << "gstreamer: Warning:" << error->message; qDebug() << "gstreamer: Debug:" << debug; g_free(debug); g_error_free(error); } break; default: break; } return GST_BUS_PASS; }
static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) { GMainLoop *loop = data; GstObject *src_obj; const GstStructure *s; guint32 seqnum; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gst_message_parse_error (message, &err, &debug); g_print ("Error: %s\n", err->message); g_error_free (err); g_free (debug); g_main_loop_quit (loop); break; } case GST_MESSAGE_EOS: /* end-of-stream */ g_main_loop_quit (loop); break; case GST_MESSAGE_ELEMENT: { /* seqnum = gst_message_get_seqnum (message); s = gst_message_get_structure (message); src_obj = GST_MESSAGE_SRC (message); if (GST_IS_ELEMENT (src_obj)) { g_print (("Got message #%u from element \"%s\" (%s): "), (guint) seqnum, GST_ELEMENT_NAME (src_obj), GST_MESSAGE_TYPE_NAME (message)); } else if (GST_IS_PAD (src_obj)) { g_print (("Got message #%u from pad \"%s:%s\" (%s): "), (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj), GST_MESSAGE_TYPE_NAME (message)); } else if (GST_IS_OBJECT (src_obj)) { g_print (("Got message #%u from object \"%s\" (%s): "), (guint) seqnum, GST_OBJECT_NAME (src_obj), GST_MESSAGE_TYPE_NAME (message)); } else { g_print (("Got message #%u (%s): "), (guint) seqnum, GST_MESSAGE_TYPE_NAME (message)); } if (s) { gchar *sstr; sstr = gst_structure_to_string (s); g_print ("%s\n", sstr); g_free (sstr); } else { g_print ("no message details\n"); } */ } default: /* unhandled message */ break; } /* remove message from the queue */ return TRUE; }
static void rb_mtp_sink_handle_message (GstBin *bin, GstMessage *message) { /* when we get an EOS message from the fdsink, close the fd and upload the * file to the device. */ if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) { int fd; struct stat stat_buf; RBMTPSink *sink = RB_MTP_SINK (bin); /* fill in the file size and close the fd */ g_object_get (sink->fdsink, "fd", &fd, NULL); fstat (fd, &stat_buf); sink->track->filesize = stat_buf.st_size; close (fd); rb_debug ("handling EOS from fdsink; file size is %" G_GUINT64_FORMAT, sink->track->filesize); /* we can just block waiting for mtp thread operations to finish here * as we're on a streaming thread. */ g_mutex_lock (sink->upload_mutex); if (sink->folder_path != NULL) { /* find or create the target folder. * if this fails, we just upload to the default music folder * rather than giving up entirely. */ sink->got_folder = FALSE; rb_mtp_thread_create_folder (sink->device_thread, (const char **)sink->folder_path, (RBMtpCreateFolderCallback) folder_callback, g_object_ref (sink), g_object_unref); while (sink->got_folder == FALSE) { g_cond_wait (sink->upload_cond, sink->upload_mutex); } } /* and upload the file */ sink->upload_done = FALSE; rb_mtp_thread_upload_track (sink->device_thread, sink->track, sink->tempfile, (RBMtpUploadCallback) upload_callback, g_object_ref (sink), g_object_unref); while (sink->upload_done == FALSE) { g_cond_wait (sink->upload_cond, sink->upload_mutex); } g_mutex_unlock (sink->upload_mutex); /* post error message if the upload failed - this should get there before * this EOS message does, so it should work OK. */ if (sink->upload_error != NULL) { int code; switch (sink->upload_error->code) { case RB_MTP_THREAD_ERROR_NO_SPACE: code = GST_RESOURCE_ERROR_NO_SPACE_LEFT; break; default: case RB_MTP_THREAD_ERROR_SEND_TRACK: code = GST_RESOURCE_ERROR_WRITE; break; } GST_WARNING_OBJECT (sink, "error: %s", sink->upload_error->message); gst_element_message_full (GST_ELEMENT (sink), GST_MESSAGE_ERROR, GST_RESOURCE_ERROR, code, g_strdup (sink->upload_error->message), NULL, __FILE__, GST_FUNCTION, __LINE__); } } GST_BIN_CLASS (parent_class)->handle_message (bin, message); }
static void test_clicked_cb (GtkButton *button, GtkWidget *combo) { GstStateChangeReturn ret; gchar *partialpipe = NULL; gchar *extension = NULL; gchar *pipeline_desc; GError *error = NULL; GMAudioProfile *profile; GstElement *pipeline = NULL; GstMessage *msg = NULL; GstBus *bus = NULL; profile = gm_audio_profile_choose_get_active (combo); g_return_if_fail (profile != NULL); gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE); extension = g_strdup (gm_audio_profile_get_extension (profile)); partialpipe = g_strdup (gm_audio_profile_get_pipeline (profile)); g_print ("You chose profile with name %s and pipeline %s\n", gm_audio_profile_get_name (profile), gm_audio_profile_get_pipeline (profile)); pipeline_desc = g_strdup_printf ("audiotestsrc wave=sine num-buffers=4096 " " ! audioconvert " " ! %s " " ! filesink location=test.%s", partialpipe, extension); g_print ("Going to run pipeline %s\n", pipeline_desc); pipeline = gst_parse_launch (pipeline_desc, &error); if (error) { g_warning ("Error parsing pipeline: %s", error->message); goto done; } bus = gst_element_get_bus (pipeline); gst_element_set_state (pipeline, GST_STATE_PLAYING); /* wait for state change to complete or to have failed */ ret = gst_element_get_state (pipeline, NULL, NULL, -1); if (ret == GST_STATE_CHANGE_FAILURE) { /* check if an error was posted on the bus */ if ((msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) { gst_message_parse_error (msg, &error, NULL); } g_warning ("Error starting pipeline: %s", (error) ? error->message : "UNKNOWN ERROR"); goto done; } g_print ("Writing test sound to test.%s ...\n", extension); /* wait for it finish (error or EOS), but no more than 30 secs */ msg = gst_bus_poll (bus, GST_MESSAGE_ERROR | GST_MESSAGE_EOS, 30*GST_SECOND); if (msg) { switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: g_print ("Test finished successfully.\n"); break; case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &error, NULL); g_warning ("Error starting pipeline: %s", (error) ? error->message : "UNKNOWN ERROR"); break; default: g_assert_not_reached (); } } else { g_warning ("Test did not finish within 30 seconds!\n"); } done: g_print ("==============================================================\n"); if (error) g_error_free (error); if (pipeline) { gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); } if (msg) gst_message_unref (msg); if (bus) gst_object_unref (bus); g_free (pipeline_desc); g_free (partialpipe); g_free (extension); gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE); }
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); }
/** * Called every time there is a message on the GStreamer pipeline's bus. * * We are mostly interested in the new pixbug message. * In that case, checks if the video recording or the intervalometer is enabled. * If so, grabs an image if it's time to do so. */ void Pipeline::bus_message_cb(GstBus* /*bus*/, GstMessage *msg, gpointer user_data) { Pipeline *context = static_cast<Pipeline*>(user_data); bool verbose = context->owner_->get_configuration()->get_verbose(); switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_ELEMENT: { const GValue *val; GdkPixbuf *pixbuf = NULL; /* only interested in element messages from our gdkpixbufsink */ if (msg->src != GST_OBJECT_CAST(context->gdkpixbufsink_)) break; /* only interested in these two messages */ if (!gst_structure_has_name(msg->structure, "preroll-pixbuf") && !gst_structure_has_name(msg->structure, "pixbuf")) { break; } //g_print("pixbuf\n"); val = gst_structure_get_value(msg->structure, "pixbuf"); g_return_if_fail(val != NULL); pixbuf = GDK_PIXBUF(g_value_dup_object(val)); if (context->get_record_all_frames() || context->get_intervalometer_is_on()) // if video grabbing is enabled { Clip *current_clip = context->owner_->get_current_clip(); unsigned long last_time_grabbed = current_clip->get_last_time_grabbed_image(); unsigned long now = timing::get_timestamp_now(); bool must_grab_now = false; // VIDEO RECORDING: if (context->get_record_all_frames()) { //std::cout << "Video grabbing is on." << std::endl; unsigned long time_between_frames = (unsigned long)(1.0f / float(current_clip->get_playhead_fps()) * timing::TIMESTAMP_PRECISION); if (verbose) std::cout << "now=" << now << " last_time_grabbed=" << last_time_grabbed << " time_between_frames" << time_between_frames << std::endl; if ((now - last_time_grabbed) > time_between_frames) { must_grab_now = true; } } // not mutually exclusive - why not have both on? // INTERVALOMETER: if (context->get_intervalometer_is_on()) { long time_between_intervalometer_ticks = long(current_clip->get_intervalometer_rate() * timing::TIMESTAMP_PRECISION); long passed = (now - last_time_grabbed); if (verbose) std::cout << "time between intervalometer ticks: " << passed << "/" << time_between_intervalometer_ticks << std::endl; if (passed > time_between_intervalometer_ticks) { if (verbose) std::cout << "Interval has passed. Time to grab." << std::endl; must_grab_now = true; } } if (must_grab_now) { if (verbose) std::cout << "Grabbing an image" << std::endl; context->save_image_to_current_clip(pixbuf); current_clip->set_last_time_grabbed_image(now); } } g_object_unref(pixbuf); break; } case GST_MESSAGE_ERROR: { GError *err = NULL; gchar *dbg = NULL; gst_message_parse_error(msg, &err, &dbg); g_error("Error: %s\n%s\n", err->message, (dbg) ? dbg : ""); g_error_free(err); g_free(dbg); break; } default: break; } }
gboolean ges_generate_test_file_audio_video (const gchar * filedest, const gchar * audio_enc, const gchar * video_enc, const gchar * mux, const gchar * video_pattern, const gchar * audio_wave) { GError *error = NULL; GstElement *pipeline; GstBus *bus; GstMessage *message; gchar *pipeline_str; gboolean done = FALSE; gboolean ret = FALSE; if (g_file_test (filedest, G_FILE_TEST_EXISTS)) { GST_INFO ("The file %s already existed.", filedest); return TRUE; } pipeline_str = g_strdup_printf ("audiotestsrc num-buffers=430 wave=%s " "%c %s ! %s name=m ! filesink location= %s/%s " "videotestsrc pattern=%s num-buffers=300 ! %s ! m.", audio_wave, audio_enc ? '!' : ' ', audio_enc ? audio_enc : "", mux, g_get_current_dir (), filedest, video_pattern, video_enc); pipeline = gst_parse_launch (pipeline_str, &error); if (pipeline == NULL) return FALSE; g_free (pipeline_str); bus = gst_element_get_bus (GST_ELEMENT (pipeline)); gst_bus_add_signal_watch (bus); gst_element_set_state (pipeline, GST_STATE_PLAYING); while (!done) { message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_CLOCK_TIME_NONE); if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS) { done = TRUE; ret = TRUE; } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) { gchar *debug = NULL; GError *err = NULL; gst_message_parse_error (message, &err, &debug); done = TRUE; ret = FALSE; GST_ERROR ("Got error %s from %s fron the bus while generation: %s" "debug infos: %s", GST_OBJECT_NAME (message->src), err->message, debug ? debug : "none", filedest); g_clear_error (&err); g_free (debug); } } gst_bus_remove_signal_watch (bus); gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return ret; }
G_MODULE_EXPORT gboolean live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data) { signal_user_data_t *ud = (signal_user_data_t*)data; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_UNKNOWN: { //printf("unknown"); } break; case GST_MESSAGE_EOS: { // Done //printf("eos\n"); live_preview_stop(ud); gst_element_seek(ud->preview->play, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); } break; case GST_MESSAGE_ERROR: { //printf("error\n"); GError *err; gchar *debug; gst_message_parse_error(msg, &err, &debug); g_warning("Gstreamer Error: %s", err->message); g_error_free(err); g_free(debug); } break; case GST_MESSAGE_WARNING: case GST_MESSAGE_INFO: case GST_MESSAGE_TAG: case GST_MESSAGE_BUFFERING: case GST_MESSAGE_STATE_CHANGED: { //printf("state change %x\n", state); GstState state, pending; gst_element_get_state(ud->preview->play, &state, &pending, 0); if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING) { update_stream_info(ud); } } break; case GST_MESSAGE_STATE_DIRTY: { //printf("state dirty\n"); } break; case GST_MESSAGE_STEP_DONE: { //printf("step done\n"); } break; case GST_MESSAGE_CLOCK_PROVIDE: { //printf("clock provide\n"); } break; case GST_MESSAGE_CLOCK_LOST: { //printf("clock lost\n"); } break; case GST_MESSAGE_NEW_CLOCK: { //printf("new clock\n"); } break; case GST_MESSAGE_STRUCTURE_CHANGE: { //printf("structure change\n"); } break; case GST_MESSAGE_STREAM_STATUS: { //printf("stream status\n"); } break; case GST_MESSAGE_APPLICATION: { //printf("application\n"); } break; case GST_MESSAGE_ELEMENT: { //printf("element\n"); if (gst_is_missing_plugin_message(msg)) { GtkWindow *hb_window; hb_window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window")); gst_element_set_state(ud->preview->play, GST_STATE_PAUSED); gchar *message, *desc; desc = gst_missing_plugin_message_get_description(msg); message = g_strdup_printf( _("Missing GStreamer plugin\n" "Audio or Video may not play as expected\n\n%s"), desc); ghb_message_dialog(hb_window, GTK_MESSAGE_WARNING, message, "Ok", NULL); g_free(message); gst_element_set_state(ud->preview->play, GST_STATE_PLAYING); } else if (msg->src == GST_OBJECT_CAST(ud->preview->vsink)) { const GstStructure *gstStruct; const GValue *val; gstStruct = gst_message_get_structure(msg); if (gstStruct != NULL && (gst_structure_has_name(gstStruct, "preroll-pixbuf") || gst_structure_has_name(gstStruct, "pixbuf"))) { val = gst_structure_get_value(gstStruct, "pixbuf"); if (val != NULL) { GdkPixbuf * pix; GtkWidget *widget; int width, height; if (ud->preview->pix != NULL) g_object_unref(ud->preview->pix); if (ud->preview->scaled_pix != NULL) g_object_unref(ud->preview->scaled_pix); pix = GDK_PIXBUF(g_value_dup_object(val)); width = gdk_pixbuf_get_width(pix); height = gdk_pixbuf_get_height(pix); if (width != ud->preview->width || height != ud->preview->height || width != ud->preview->render_width || height != ud->preview->render_height) { double xscale, yscale; xscale = (double)ud->preview->render_width / ud->preview->width; yscale = (double)ud->preview->render_height / ud->preview->height; if (xscale <= yscale) { width = ud->preview->render_width; height = ud->preview->height * xscale; } else { width = ud->preview->width * yscale; height = ud->preview->render_height; } ud->preview->scaled_pix = gdk_pixbuf_scale_simple(pix, width, height, GDK_INTERP_BILINEAR); g_object_ref(pix); } else { ud->preview->scaled_pix = pix; } ud->preview->pix = ud->preview->scaled_pix; g_object_ref(ud->preview->pix); widget = GHB_WIDGET (ud->builder, "preview_image"); gtk_widget_queue_draw(widget); } } } } break; case GST_MESSAGE_SEGMENT_START: { //printf("segment start\n"); } break; case GST_MESSAGE_SEGMENT_DONE: { //printf("segment done\n"); } break; case GST_MESSAGE_DURATION_CHANGED: { //printf("duration change\n"); }; case GST_MESSAGE_LATENCY: { //printf("latency\n"); }; case GST_MESSAGE_ASYNC_START: { //printf("async start\n"); } break; case GST_MESSAGE_ASYNC_DONE: { //printf("async done\n"); } break; case GST_MESSAGE_REQUEST_STATE: { //printf("request state\n"); } break; case GST_MESSAGE_STEP_START: { //printf("step start\n"); } break; case GST_MESSAGE_QOS: { //printf("qos\n"); } break; case GST_MESSAGE_PROGRESS: { //printf("progress\n"); } break; case GST_MESSAGE_TOC: { //printf("toc\n"); } break; case GST_MESSAGE_RESET_TIME: { //printf("reset time\n"); } break; case GST_MESSAGE_STREAM_START: { //printf("stream start\n"); }; case GST_MESSAGE_ANY: { //printf("any\n"); } break; default: { // Ignore //printf("?msg? %x\n", GST_MESSAGE_TYPE(msg)); } } return TRUE; }