]> git.saurik.com Git - wxWidgets.git/commitdiff
Show gstreamer errors in wxGStreamerMediaBackend to the user.
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 2 Jul 2012 00:16:18 +0000 (00:16 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 2 Jul 2012 00:16:18 +0000 (00:16 +0000)
If the media file fails to play, we really need to show to the user the
corresponding gstreamer error, otherwise there is no way to understand what
the problem is.

Collect the errors in gst_error_callback() and show them from the main thread
if we get a gstreamer error.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71928 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
src/unix/mediactrl.cpp

index 02e4f8c5bbb5c3a52eb7e094f5a83ce34d787fea..4c3af62f9674fdbd5bb6f34c003f4bf9df20901e 100644 (file)
@@ -576,6 +576,7 @@ GTK:
 - Fix const methods display in assert dialog (vinayakgarg).
 - Implement native tab art for wxAUI (Jens Lody and Teodor Petrov).
 - Fix pasting large amounts of text (Bradley Hawkins).
 - Fix const methods display in assert dialog (vinayakgarg).
 - Implement native tab art for wxAUI (Jens Lody and Teodor Petrov).
 - Fix pasting large amounts of text (Bradley Hawkins).
+- Show gstreamer errors if wxMediaCtrl fails to play file.
 
 MSW:
 
 
 MSW:
 
index 8283d5114a936f4a39f3e99e0e84fa2334ba12e6..cd29fba5d913a558c5d9599bfa2b9cc04c0d73c9 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "wx/filesys.h"             // FileNameToURL()
 #include "wx/thread.h"              // wxMutex/wxMutexLocker
 
 #include "wx/filesys.h"             // FileNameToURL()
 #include "wx/thread.h"              // wxMutex/wxMutexLocker
+#include "wx/vector.h"              // wxVector<wxString>
 
 #ifdef __WXGTK__
     #include <gtk/gtk.h>
 
 #ifdef __WXGTK__
     #include <gtk/gtk.h>
@@ -186,6 +187,7 @@ public:
     virtual double GetVolume();
 
     //------------implementation from now on-----------------------------------
     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);
     bool DoLoad(const wxString& locstring);
     wxMediaCtrl* GetControl() { return m_ctrl; } // for C Callbacks
     void HandleStateChange(GstElementState oldstate, GstElementState newstate);
@@ -206,6 +208,23 @@ public:
     wxMutex         m_asynclock;    // See "discussion of internals"
     class wxGStreamerMediaEventHandler* m_eventHandler; // see below
 
     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)
     friend class wxGStreamerMediaEventHandler;
     friend class wxGStreamerLoadWaitTimer;
     DECLARE_DYNAMIC_CLASS(wxGStreamerMediaBackend)
@@ -382,15 +401,10 @@ static void gst_error_callback(GstElement *WXUNUSED(play),
                                GstElement *WXUNUSED(src),
                                GError     *err,
                                gchar      *debug,
                                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));
 }
 }
 
 }
 }
 
@@ -481,6 +495,15 @@ static gboolean gst_bus_async_callback(GstBus* WXUNUSED(bus),
                                        GstMessage* message,
                                        wxGStreamerMediaBackend* be)
 {
                                        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)
     if(((GstElement*)GST_MESSAGE_SRC(message)) != be->m_playbin)
         return TRUE;
     if(be->m_asynclock.TryLock() != wxMUTEX_NO_ERROR)
@@ -501,14 +524,7 @@ static gboolean gst_bus_async_callback(GstBus* WXUNUSED(bus),
             gst_finish_callback(NULL, be);
             break;
         }
             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;
     }
         default:
             break;
     }
@@ -970,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
 //
 //-----------------------------------------------------------------------------
 // wxGStreamerMediaBackend::CreateControl
 //
@@ -1222,9 +1264,10 @@ bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring)
                                GST_STATE_READY) == GST_STATE_FAILURE ||
         !SyncStateChange(m_playbin, GST_STATE_READY))
     {
                                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
     }
 
     // free current media resources
@@ -1244,11 +1287,18 @@ bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring)
                                GST_STATE_PAUSED) == GST_STATE_FAILURE ||
         !SyncStateChange(m_playbin, GST_STATE_PAUSED))
     {
                                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
     }
 
         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;
 
     NotifyMovieLoaded(); // Notify the user - all we can do for now
     return true;
@@ -1266,7 +1316,11 @@ bool wxGStreamerMediaBackend::Play()
 {
     if (gst_element_set_state (m_playbin,
                                GST_STATE_PLAYING) == GST_STATE_FAILURE)
 {
     if (gst_element_set_state (m_playbin,
                                GST_STATE_PLAYING) == GST_STATE_FAILURE)
+    {
+        CheckForErrors();
         return false;
         return false;
+    }
+
     return true;
 }
 
     return true;
 }
 
@@ -1282,7 +1336,10 @@ bool wxGStreamerMediaBackend::Pause()
     m_llPausedPos = wxGStreamerMediaBackend::GetPosition();
     if (gst_element_set_state (m_playbin,
                                GST_STATE_PAUSED) == GST_STATE_FAILURE)
     m_llPausedPos = wxGStreamerMediaBackend::GetPosition();
     if (gst_element_set_state (m_playbin,
                                GST_STATE_PAUSED) == GST_STATE_FAILURE)
+    {
+        CheckForErrors();
         return false;
         return false;
+    }
     return true;
 }
 
     return true;
 }
 
@@ -1302,6 +1359,7 @@ bool wxGStreamerMediaBackend::Stop()
                                   GST_STATE_PAUSED) == GST_STATE_FAILURE ||
           !SyncStateChange(m_playbin, GST_STATE_PAUSED))
         {
                                   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;
         }
             wxLogSysError(wxT("Could not set state to paused for Stop()"));
             return false;
         }