X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9dc44eff0235c5f30940f32ccc6d9d82a236e7d2..bb996f289574defb0ae4339ae8e46ff3cf6fa54c:/src/unix/mediactrl.cpp diff --git a/src/unix/mediactrl.cpp b/src/unix/mediactrl.cpp index 01a3ed607f..cd29fba5d9 100644 --- a/src/unix/mediactrl.cpp +++ b/src/unix/mediactrl.cpp @@ -34,7 +34,9 @@ #include "wx/timer.h" // wxTimer #endif +#include "wx/filesys.h" // FileNameToURL() #include "wx/thread.h" // wxMutex/wxMutexLocker +#include "wx/vector.h" // wxVector #ifdef __WXGTK__ #include @@ -185,6 +187,7 @@ public: virtual double GetVolume(); //------------implementation from now on----------------------------------- + bool CheckForErrors(); bool DoLoad(const wxString& locstring); wxMediaCtrl* GetControl() { return m_ctrl; } // for C Callbacks void HandleStateChange(GstElementState oldstate, GstElementState newstate); @@ -205,6 +208,23 @@ public: wxMutex m_asynclock; // See "discussion of internals" class wxGStreamerMediaEventHandler* m_eventHandler; // see below + // Mutex protecting just the variables below which are set from + // gst_error_callback() called from a different thread. + wxMutex m_mutexErr; + struct Error + { + Error(const gchar* message, const gchar* debug) + : m_message(message, wxConvUTF8), + m_debug(debug, wxConvUTF8) + { + } + + wxString m_message, + m_debug; + }; + + wxVector m_errors; + friend class wxGStreamerMediaEventHandler; friend class wxGStreamerLoadWaitTimer; DECLARE_DYNAMIC_CLASS(wxGStreamerMediaBackend) @@ -381,15 +401,10 @@ static void gst_error_callback(GstElement *WXUNUSED(play), GstElement *WXUNUSED(src), GError *err, gchar *debug, - wxGStreamerMediaBackend* WXUNUSED(be)) + wxGStreamerMediaBackend* be) { - wxString sError; - sError.Printf(wxT("gst_error_callback\n") - wxT("Error Message:%s\nDebug:%s\n"), - (const wxChar*)wxConvUTF8.cMB2WX(err->message), - (const wxChar*)wxConvUTF8.cMB2WX(debug)); - wxLogTrace(wxTRACE_GStreamer, sError); - wxLogSysError(sError); + wxMutexLocker lock(be->m_mutexErr); + be->m_errors.push_back(wxGStreamerMediaBackend::Error(err->message, debug)); } } @@ -480,6 +495,15 @@ static gboolean gst_bus_async_callback(GstBus* WXUNUSED(bus), GstMessage* message, wxGStreamerMediaBackend* be) { + if ( GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR ) + { + GError* error; + gchar* debug; + gst_message_parse_error(message, &error, &debug); + gst_error_callback(NULL, NULL, error, debug, be); + return FALSE; + } + if(((GstElement*)GST_MESSAGE_SRC(message)) != be->m_playbin) return TRUE; if(be->m_asynclock.TryLock() != wxMUTEX_NO_ERROR) @@ -500,14 +524,7 @@ static gboolean gst_bus_async_callback(GstBus* WXUNUSED(bus), gst_finish_callback(NULL, be); break; } - case GST_MESSAGE_ERROR: - { - GError* error; - gchar* debug; - gst_message_parse_error(message, &error, &debug); - gst_error_callback(NULL, NULL, error, debug, be); - break; - } + default: break; } @@ -969,6 +986,32 @@ wxGStreamerMediaBackend::~wxGStreamerMediaBackend() } } +//----------------------------------------------------------------------------- +// wxGStreamerMediaBackend::CheckForErrors +// +// Reports any errors received from gstreamer. Should be called after any +// failure. +//----------------------------------------------------------------------------- +bool wxGStreamerMediaBackend::CheckForErrors() +{ + wxMutexLocker lock(m_mutexErr); + if ( m_errors.empty() ) + return false; + + for ( unsigned n = 0; n < m_errors.size(); n++ ) + { + const Error& err = m_errors[n]; + + wxLogTrace(wxTRACE_GStreamer, + "gst_error_callback: %s", err.m_debug); + wxLogError(_("Media playback error: %s"), err.m_message); + } + + m_errors.clear(); + + return true; +} + //----------------------------------------------------------------------------- // wxGStreamerMediaBackend::CreateControl // @@ -1168,7 +1211,7 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent, //----------------------------------------------------------------------------- bool wxGStreamerMediaBackend::Load(const wxString& fileName) { - return DoLoad(wxString( wxT("file://") ) + fileName); + return DoLoad(wxFileSystem::FileNameToURL(fileName)); } //----------------------------------------------------------------------------- @@ -1221,9 +1264,10 @@ bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring) 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; + CheckForErrors(); + + wxLogError(_("Failed to prepare playing \"%s\"."), locstring); + return false; } // free current media resources @@ -1243,11 +1287,18 @@ bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring) GST_STATE_PAUSED) == GST_STATE_FAILURE || !SyncStateChange(m_playbin, GST_STATE_PAUSED)) { + CheckForErrors(); 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 } + // It may happen that both calls above succeed but we actually had some + // errors during the pipeline setup and it doesn't play. E.g. this happens + // if XVideo extension is unavailable but xvimagesink is still used. + if ( CheckForErrors() ) + return false; + NotifyMovieLoaded(); // Notify the user - all we can do for now return true; @@ -1265,7 +1316,11 @@ bool wxGStreamerMediaBackend::Play() { if (gst_element_set_state (m_playbin, GST_STATE_PLAYING) == GST_STATE_FAILURE) + { + CheckForErrors(); return false; + } + return true; } @@ -1281,7 +1336,10 @@ bool wxGStreamerMediaBackend::Pause() m_llPausedPos = wxGStreamerMediaBackend::GetPosition(); if (gst_element_set_state (m_playbin, GST_STATE_PAUSED) == GST_STATE_FAILURE) + { + CheckForErrors(); return false; + } return true; } @@ -1301,6 +1359,7 @@ bool wxGStreamerMediaBackend::Stop() GST_STATE_PAUSED) == GST_STATE_FAILURE || !SyncStateChange(m_playbin, GST_STATE_PAUSED)) { + CheckForErrors(); wxLogSysError(wxT("Could not set state to paused for Stop()")); return false; }