]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/mediactrl.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / unix / mediactrl.cpp
index 01a3ed607f86d93d3eb5d801240d271a06c68391..cd29fba5d913a558c5d9599bfa2b9cc04c0d73c9 100644 (file)
@@ -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<wxString>
 
 #ifdef __WXGTK__
     #include <gtk/gtk.h>
@@ -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<Error> 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;
         }