+ gst_message_unref(message);
+ }while(!bBreak);
+
+ return bSuccess;
+}
+#else // 0.8 implementation
+bool wxGStreamerMediaBackend::SyncStateChange(GstElement* element,
+ GstElementState desiredstate,
+ gint64 llTimeout)
+{
+ gint64 llTimeWaited = 0;
+ while(GST_STATE(element) != desiredstate)
+ {
+ if(llTimeWaited >= llTimeout)
+ break;
+ llTimeWaited += 10*GST_MSECOND;
+ wxMilliSleep(10);
+ }
+
+ return llTimeWaited != llTimeout;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::TryAudioSink
+// wxGStreamerMediaBackend::TryVideoSink
+//
+// Uses various means to determine whether a passed in video/audio sink
+// if suitable for us - if it is not we return false and unref the
+// inappropriate sink.
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::TryAudioSink(GstElement* audiosink)
+{
+ if( !GST_IS_ELEMENT(audiosink) )
+ {
+ if(G_IS_OBJECT(audiosink))
+ g_object_unref(audiosink);
+ return false;
+ }
+
+ return true;
+}
+
+bool wxGStreamerMediaBackend::TryVideoSink(GstElement* videosink)
+{
+ // Check if the video sink either is an xoverlay or might contain one...
+ if( !GST_IS_BIN(videosink) && !GST_IS_X_OVERLAY(videosink) )
+ {
+ if(G_IS_OBJECT(videosink))
+ g_object_unref(videosink);
+ return false;
+ }
+
+ // Make our video sink and make sure it supports the x overlay interface
+ // the x overlay enables us to put the video in our control window
+ // (i.e. we NEED it!) - also connect to the natural video size change event
+ if( GST_IS_BIN(videosink) )
+ m_xoverlay = (GstXOverlay*)
+ gst_bin_get_by_interface (GST_BIN (videosink),
+ GST_TYPE_X_OVERLAY);
+ else
+ m_xoverlay = (GstXOverlay*) videosink;
+
+ if ( !GST_IS_X_OVERLAY(m_xoverlay) )
+ {
+ g_object_unref(videosink);
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaEventHandler::OnMediaFinish
+//
+// Called when the media is about to stop
+//-----------------------------------------------------------------------------
+void wxGStreamerMediaEventHandler::OnMediaFinish(wxMediaEvent& WXUNUSED(event))
+{
+ // (RN - I have no idea why I thought this was good behaviour....
+ // maybe it made sense for streaming/nonseeking data but
+ // generally it seems like a really bad idea) -
+ if(m_be->SendStopEvent())
+ {
+ // Stop the media (we need to set it back to paused
+ // so that people can get the duration et al.
+ // and send the finish event (luckily we can "Sync" it out... LOL!)
+ // (We don't check return values here because we can't really do
+ // anything...)
+ wxMutexLocker lock(m_be->m_asynclock);
+
+ // Set element to ready+sync it
+ gst_element_set_state (m_be->m_playbin, GST_STATE_READY);
+ m_be->SyncStateChange(m_be->m_playbin, GST_STATE_READY);
+
+ // Now set it to paused + update pause pos to 0 and
+ // Sync that as well (note that we don't call Stop() here
+ // due to mutex issues)
+ gst_element_set_state (m_be->m_playbin, GST_STATE_PAUSED);
+ m_be->SyncStateChange(m_be->m_playbin, GST_STATE_PAUSED);
+ m_be->m_llPausedPos = 0;
+
+ // Finally, queue the finish event
+ m_be->QueueFinishEvent();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Public methods
+//
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend Constructor
+//
+// Sets m_playbin to NULL signifying we havn't loaded anything yet
+//-----------------------------------------------------------------------------
+wxGStreamerMediaBackend::wxGStreamerMediaBackend()
+ : m_playbin(NULL),
+ m_eventHandler(NULL)
+{
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend Destructor
+//
+// Stops/cleans up memory
+//
+// NB: This could trigger a critical warning but doing a SyncStateChange
+// here is just going to slow down quitting of the app, which is bad.
+//-----------------------------------------------------------------------------
+wxGStreamerMediaBackend::~wxGStreamerMediaBackend()
+{
+ // Dispose of the main player and related objects
+ if(m_playbin)
+ {
+ wxASSERT( GST_IS_OBJECT(m_playbin) );
+ gst_element_set_state (m_playbin, GST_STATE_NULL);
+ gst_object_unref (GST_OBJECT (m_playbin));
+ delete m_eventHandler;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::CreateControl
+//
+// Initializes GStreamer and creates the wx side of our media control
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name)
+{
+ //
+ //init gstreamer
+ //
+
+ //Convert arguments to unicode if enabled
+#if wxUSE_UNICODE
+ int i;
+ char **argvGST = new char*[wxTheApp->argc + 1];
+ for ( i = 0; i < wxTheApp->argc; i++ )
+ {
+#if wxUSE_UNICODE_WCHAR
+ argvGST[i] = wxStrdupA(wxConvUTF8.cWX2MB(wxTheApp->argv[i]));
+#else
+ argvGST[i] = wxStrdupA(wxTheApp->argv[i].utf8_str());
+#endif
+ }
+
+ argvGST[wxTheApp->argc] = NULL;
+
+ int argcGST = wxTheApp->argc;
+#else
+#define argcGST wxTheApp->argc
+#define argvGST wxTheApp->argv
+#endif
+
+ //Really init gstreamer
+ gboolean bInited;
+ GError* error = NULL;
+#if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
+ bInited = gst_init_check(&argcGST, &argvGST, &error);
+#else
+ bInited = gst_init_check(&argcGST, &argvGST);
+#endif
+
+ // Cleanup arguments for unicode case
+#if wxUSE_UNICODE
+ for ( i = 0; i < argcGST; i++ )
+ {
+ free(argvGST[i]);
+ }
+
+ delete [] argvGST;
+#endif
+
+ if(!bInited) //gst_init_check fail?
+ {
+ if(error)
+ {
+ wxLogSysError(wxT("Could not initialize GStreamer\n")
+ wxT("Error Message:%s"),
+ (const wxChar*) wxConvUTF8.cMB2WX(error->message)
+ );
+ g_error_free(error);
+ }
+ else
+ wxLogSysError(wxT("Could not initialize GStreamer"));
+
+ return false;
+ }
+
+ //
+ // wxControl creation
+ //
+ m_ctrl = wxStaticCast(ctrl, wxMediaCtrl);
+
+#ifdef __WXGTK__
+ // We handle our own GTK expose events
+ m_ctrl->m_noExpose = true;
+#endif
+
+ if( !m_ctrl->wxControl::Create(parent, id, pos, size,
+ style, // TODO: remove borders???
+ validator, name) )
+ {
+ wxFAIL_MSG(wxT("Could not create wxControl!!!"));
+ return false;
+ }
+
+#ifdef __WXGTK__
+ // Turn off double-buffering so that
+ // so it doesn't draw over the video and cause sporadic
+ // disappearances of the video
+ gtk_widget_set_double_buffered(m_ctrl->m_wxwindow, FALSE);
+#endif
+
+ // don't erase the background of our control window
+ // so that resizing is a bit smoother
+ m_ctrl->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+
+ // Create our playbin object
+ m_playbin = gst_element_factory_make ("playbin", "play");
+ if (!GST_IS_ELEMENT(m_playbin))
+ {
+ if(G_IS_OBJECT(m_playbin))
+ g_object_unref(m_playbin);
+ wxLogSysError(wxT("Got an invalid playbin"));
+ return false;
+ }
+
+#if GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR < 10
+ // Connect the glib events/callbacks we want to our playbin
+ g_signal_connect(m_playbin, "eos",
+ G_CALLBACK(gst_finish_callback), this);
+ g_signal_connect(m_playbin, "error",
+ G_CALLBACK(gst_error_callback), this);
+ g_signal_connect(m_playbin, "state-change",
+ G_CALLBACK(gst_state_change_callback), this);
+#else
+ // GStreamer 0.10+ uses GstBus for this now, connect to the sync
+ // handler as well so we can set the X window id of our xoverlay
+ gst_bus_add_watch (gst_element_get_bus(m_playbin),
+ (GstBusFunc) gst_bus_async_callback, this);
+ gst_bus_set_sync_handler(gst_element_get_bus(m_playbin),
+ (GstBusSyncHandler) gst_bus_sync_callback, this);
+ g_signal_connect(m_playbin, "notify::stream-info",
+ G_CALLBACK(gst_notify_stream_info_callback), this);
+#endif
+
+ // Get the audio sink
+ GstElement* audiosink = gst_gconf_get_default_audio_sink();
+ if( !TryAudioSink(audiosink) )
+ {
+ // fallback to autodetection, then alsa, then oss as a stopgap
+ audiosink = gst_element_factory_make ("autoaudiosink", "audio-sink");
+ if( !TryAudioSink(audiosink) )
+ {
+ audiosink = gst_element_factory_make ("alsasink", "alsa-output");
+ if( !TryAudioSink(audiosink) )
+ {
+ audiosink = gst_element_factory_make ("osssink", "play_audio");
+ if( !TryAudioSink(audiosink) )
+ {
+ wxLogSysError(wxT("Could not find a valid audiosink"));
+ return false;
+ }
+ }
+ }
+ }
+
+ // Setup video sink - first try gconf, then auto, then xvimage and
+ // then finally plain ximage
+ GstElement* videosink = gst_gconf_get_default_video_sink();
+ if( !TryVideoSink(videosink) )
+ {
+ videosink = gst_element_factory_make ("autovideosink", "video-sink");
+ if( !TryVideoSink(videosink) )
+ {
+ videosink = gst_element_factory_make ("xvimagesink", "video-sink");
+ if( !TryVideoSink(videosink) )
+ {
+ // finally, do a final fallback to ximagesink
+ videosink =
+ gst_element_factory_make ("ximagesink", "video-sink");
+ if( !TryVideoSink(videosink) )
+ {
+ g_object_unref(audiosink);
+ wxLogSysError(wxT("Could not find a suitable video sink"));
+ return false;
+ }
+ }
+ }
+ }
+
+#if GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR < 10
+ // Not on 0.10... called when video size changes
+ g_signal_connect(m_xoverlay, "desired-size-changed",
+ G_CALLBACK(gst_desired_size_changed_callback), this);
+#endif
+ // Tell GStreamer which window to draw to in 0.8 - 0.10
+ // sometimes needs this too...
+ SetupXOverlay();
+
+ // Now that we know (or, rather think) our video and audio sink
+ // are valid set our playbin to use them
+ g_object_set (G_OBJECT (m_playbin),
+ "video-sink", videosink,
+ "audio-sink", audiosink,
+ NULL);
+
+ m_eventHandler = new wxGStreamerMediaEventHandler(this);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Load (File version)
+//
+// Just calls DoLoad() with a prepended file scheme
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Load(const wxString& fileName)
+{
+ return DoLoad(wxString( wxT("file://") ) + fileName);
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Load (URI version)
+//
+// In the case of a file URI passes it unencoded -
+// also, as of 0.10.3 and earlier GstURI (the uri parser for gstreamer)
+// is sort of broken and only accepts uris with at least two slashes
+// after the scheme (i.e. file: == not ok, file:// == ok)
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Load(const wxURI& location)
+{
+ if(location.GetScheme().CmpNoCase(wxT("file")) == 0)
+ {
+ wxString uristring = location.BuildUnescapedURI();
+
+ //Workaround GstURI leading "//" problem and make sure it leads
+ //with that
+ return DoLoad(wxString(wxT("file://")) +
+ uristring.Right(uristring.length() - 5)
+ );
+ }
+ else
+ return DoLoad(location.BuildURI());
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::DoLoad
+//
+// Loads the media
+// 1) Reset member variables and set playbin back to ready state
+// 2) Check URI for validity and then tell the playbin to load it
+// 3) Set the playbin to the pause state
+//
+// NB: Even after this function is over with we probably don't have the
+// video size or duration - no amount of clever hacking is going to get
+// around that, unfortunately.
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring)
+{
+ wxMutexLocker lock(m_asynclock); // lock state events and async callbacks
+
+ // Reset positions & rate
+ m_llPausedPos = 0;
+ m_dRate = 1.0;
+ m_videoSize = wxSize(0,0);
+
+ // Set playbin to ready to stop the current media...
+ if( gst_element_set_state (m_playbin,
+ GST_STATE_READY) == GST_STATE_FAILURE ||
+ !SyncStateChange(m_playbin, GST_STATE_READY))
+ {
+ wxLogSysError(wxT("wxGStreamerMediaBackend::Load - ")
+ wxT("Could not set initial state to ready"));
+ return false;
+ }
+
+ // free current media resources
+ gst_element_set_state (m_playbin, GST_STATE_NULL);
+
+ // Make sure the passed URI is valid and tell playbin to load it
+ // non-file uris are encoded
+ wxASSERT(gst_uri_protocol_is_valid("file"));
+ wxASSERT(gst_uri_is_valid(locstring.mb_str()));
+
+ g_object_set (G_OBJECT (m_playbin), "uri",
+ (const char*)locstring.mb_str(), NULL);
+
+ // Try to pause media as gstreamer won't let us query attributes
+ // such as video size unless it is paused or playing
+ if( gst_element_set_state (m_playbin,
+ GST_STATE_PAUSED) == GST_STATE_FAILURE ||
+ !SyncStateChange(m_playbin, GST_STATE_PAUSED))
+ {
+ return false; // no real error message needed here as this is
+ // generic failure 99% of the time (i.e. no
+ // source etc.) and has an error message
+ }
+
+
+ NotifyMovieLoaded(); // Notify the user - all we can do for now
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Play
+//
+// Sets the stream to a playing state
+//
+// THREAD-UNSAFE in 0.8, maybe in 0.10 as well
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Play()
+{
+ if (gst_element_set_state (m_playbin,
+ GST_STATE_PLAYING) == GST_STATE_FAILURE)
+ return false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Pause
+//
+// Marks where we paused and pauses the stream
+//
+// THREAD-UNSAFE in 0.8, maybe in 0.10 as well
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Pause()
+{
+ m_llPausedPos = wxGStreamerMediaBackend::GetPosition();
+ if (gst_element_set_state (m_playbin,
+ GST_STATE_PAUSED) == GST_STATE_FAILURE)
+ return false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Stop
+//
+// Pauses the stream and sets the position to 0. Note that this is
+// synchronous (!) pausing.
+//
+// Due to the mutex locking this is probably thread-safe actually.
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Stop()
+{
+ { // begin state lock
+ wxMutexLocker lock(m_asynclock);
+ if(gst_element_set_state (m_playbin,
+ GST_STATE_PAUSED) == GST_STATE_FAILURE ||
+ !SyncStateChange(m_playbin, GST_STATE_PAUSED))
+ {
+ wxLogSysError(wxT("Could not set state to paused for Stop()"));
+ return false;
+ }
+ } // end state lock
+
+ bool bSeekedOK = wxGStreamerMediaBackend::SetPosition(0);
+
+ if(!bSeekedOK)
+ {
+ wxLogSysError(wxT("Could not seek to initial position in Stop()"));
+ return false;
+ }
+
+ QueueStopEvent(); // Success
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetState
+//
+// Gets the state of the media
+//-----------------------------------------------------------------------------
+wxMediaState wxGStreamerMediaBackend::GetState()
+{
+ switch(GST_STATE(m_playbin))
+ {
+ case GST_STATE_PLAYING:
+ return wxMEDIASTATE_PLAYING;
+ case GST_STATE_PAUSED:
+ if (m_llPausedPos == 0)
+ return wxMEDIASTATE_STOPPED;
+ else
+ return wxMEDIASTATE_PAUSED;
+ default://case GST_STATE_READY:
+ return wxMEDIASTATE_STOPPED;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetPosition
+//
+// If paused, returns our marked position - otherwise it queries the
+// GStreamer playbin for the position and returns that
+//
+// NB:
+// NB: At least in 0.8, when you pause and seek gstreamer
+// NB: doesn't update the position sometimes, so we need to keep track of
+// NB: whether we have paused or not and keep track of the time after the
+// NB: pause and whenever the user seeks while paused
+// NB:
+//
+// THREAD-UNSAFE, at least if not paused. Requires media to be at least paused.
+//-----------------------------------------------------------------------------
+wxLongLong wxGStreamerMediaBackend::GetPosition()
+{
+ if(GetState() != wxMEDIASTATE_PLAYING)
+ return m_llPausedPos;
+ else
+ {
+ gint64 pos;
+ GstFormat fmtTime = GST_FORMAT_TIME;
+
+ if (!wxGst_element_query_position(m_playbin, &fmtTime, &pos) ||
+ fmtTime != GST_FORMAT_TIME || pos == -1)
+ return 0;
+ return pos / GST_MSECOND ;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::SetPosition
+//
+// Sets the position of the stream
+// Note that GST_MSECOND is 1000000 (GStreamer uses nanoseconds - so
+// there is 1000000 nanoseconds in a millisecond)
+//
+// If we are paused we update the cached pause position.
+//
+// This is also an exceedingly ugly function due to the three implementations
+// (or, rather two plus one implementation without a seek function).
+//
+// This is asynchronous and thread-safe on both 0.8 and 0.10.
+//
+// NB: This fires both a stop and play event if the media was previously
+// playing... which in some ways makes sense. And yes, this makes the video
+// go all haywire at times - a gstreamer bug...
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::SetPosition(wxLongLong where)
+{
+#if GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR == 8 \
+ && GST_VERSION_MICRO == 0
+ // 0.8.0 has no gst_element_seek according to official docs!!!
+ wxLogSysError(wxT("GStreamer 0.8.0 does not have gst_element_seek")
+ wxT(" according to official docs"));
+ return false;
+#else // != 0.8.0
+
+# if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
+ gst_element_seek (m_playbin, m_dRate, GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
+ GST_SEEK_TYPE_SET, where.GetValue() * GST_MSECOND,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE );
+# else
+ // NB: Some gstreamer versions return false basically all the time
+ // here - even totem doesn't bother to check the return value here
+ // so I guess we'll just assume it worked -
+ // TODO: maybe check the gst error callback???
+ gst_element_seek (m_playbin, (GstSeekType) (GST_SEEK_METHOD_SET |
+ GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH),
+ where.GetValue() * GST_MSECOND );
+
+# endif // GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
+
+ {
+ m_llPausedPos = where;
+ return true;
+ }
+ return true;
+#endif //== 0.8.0
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetDuration
+//
+// Obtains the total time of our stream
+// THREAD-UNSAFE, requires media to be paused or playing
+//-----------------------------------------------------------------------------
+wxLongLong wxGStreamerMediaBackend::GetDuration()
+{
+ gint64 length;
+ GstFormat fmtTime = GST_FORMAT_TIME;
+
+ if(!wxGst_element_query_duration(m_playbin, &fmtTime, &length) ||
+ fmtTime != GST_FORMAT_TIME || length == -1)
+ return 0;
+ return length / GST_MSECOND ;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::Move
+//
+// Called when the window is moved - GStreamer takes care of this
+// for us so nothing is needed
+//-----------------------------------------------------------------------------
+void wxGStreamerMediaBackend::Move(int x, int y, int w, int h)
+{
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetVideoSize
+//
+// Returns our cached video size from Load/gst_notify_caps_callback
+// gst_x_overlay_get_desired_size also does this in 0.8...
+//-----------------------------------------------------------------------------
+wxSize wxGStreamerMediaBackend::GetVideoSize() const
+{
+ return m_videoSize;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetPlaybackRate
+// wxGStreamerMediaBackend::SetPlaybackRate
+//
+// Obtains/Sets the playback rate of the stream
+//
+//TODO: PlaybackRate not currently supported via playbin directly -
+//TODO: Ronald S. Bultje noted on gstreamer-devel:
+//TODO:
+//TODO: Like "play at twice normal speed"? Or "play at 25 fps and 44,1 kHz"? As
+//TODO: for the first, yes, we have elements for that, btu they"re not part of
+//TODO: playbin. You can create a bin (with a ghost pad) containing the actual
+//TODO: video/audiosink and the speed-changing element for this, and set that
+//TODO: element as video-sink or audio-sink property in playbin. The
+//TODO: audio-element is called "speed", the video-element is called "videodrop"
+//TODO: (although that appears to be deprecated in favour of "videorate", which
+//TODO: again cannot do this, so this may not work at all in the end). For
+//TODO: forcing frame/samplerates, see audioscale and videorate. Audioscale is
+//TODO: part of playbin.
+//
+// In 0.10 GStreamer has new gst_element_seek API that might
+// support this - and I've got an attempt to do so but it is untested
+// but it would appear to work...
+//-----------------------------------------------------------------------------
+double wxGStreamerMediaBackend::GetPlaybackRate()
+{
+ return m_dRate; // Could use GST_QUERY_RATE but the API doesn't seem
+ // final on that yet and there may not be any actual
+ // plugins that support it...
+}
+
+bool wxGStreamerMediaBackend::SetPlaybackRate(double dRate)
+{
+#if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
+#if 0 // not tested enough
+ if( gst_element_seek (m_playbin, dRate, GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
+ GST_SEEK_TYPE_CUR, 0,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ) )
+ {
+ m_dRate = dRate;
+ return true;
+ }
+#endif
+#endif
+
+ // failure
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetDownloadProgress
+//
+// Not really outwardly possible - have been suggested that one could
+// get the information from the component that "downloads"
+//-----------------------------------------------------------------------------
+wxLongLong wxGStreamerMediaBackend::GetDownloadProgress()
+{
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::GetDownloadTotal
+//
+// TODO: Cache this?
+// NB: The length changes every call for some reason due to
+// GStreamer implementation issues
+// THREAD-UNSAFE, requires media to be paused or playing
+//-----------------------------------------------------------------------------
+wxLongLong wxGStreamerMediaBackend::GetDownloadTotal()
+{
+ gint64 length;
+ GstFormat fmtBytes = GST_FORMAT_BYTES;
+
+ if (!wxGst_element_query_duration(m_playbin, &fmtBytes, &length) ||
+ fmtBytes != GST_FORMAT_BYTES || length == -1)
+ return 0;
+ return length;
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::SetVolume
+// wxGStreamerMediaBackend::GetVolume
+//
+// Sets/Gets the volume through the playbin object.
+// Note that this requires a relatively recent gst-plugins so we
+// check at runtime to see whether it is available or not otherwise
+// GST spits out an error on the command line
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::SetVolume(double dVolume)
+{
+ if(g_object_class_find_property(
+ G_OBJECT_GET_CLASS(G_OBJECT(m_playbin)),
+ "volume") != NULL)
+ {
+ g_object_set(G_OBJECT(m_playbin), "volume", dVolume, NULL);
+ return true;
+ }
+ else
+ {
+ wxLogTrace(wxTRACE_GStreamer,
+ wxT("SetVolume: volume prop not found - 0.8.5 of ")
+ wxT("gst-plugins probably needed"));
+ return false;
+ }
+}
+
+double wxGStreamerMediaBackend::GetVolume()
+{
+ double dVolume = 1.0;
+
+ if(g_object_class_find_property(
+ G_OBJECT_GET_CLASS(G_OBJECT(m_playbin)),
+ "volume") != NULL)
+ {
+ g_object_get(G_OBJECT(m_playbin), "volume", &dVolume, NULL);
+ }
+ else
+ {
+ wxLogTrace(wxTRACE_GStreamer,
+ wxT("GetVolume: volume prop not found - 0.8.5 of ")
+ wxT("gst-plugins probably needed"));
+ }
+
+ return dVolume;
+}
+
+#endif //wxUSE_GSTREAMER
+
+// Force link into main library so this backend can be loaded
+#include "wx/html/forcelnk.h"
+FORCE_LINK_ME(basewxmediabackends)
+
+#endif //wxUSE_MEDIACTRL