// Author: Ryan Norton <wxprojects@comcast.net>
// Modified by:
// Created: 02/04/05
-// RCS-ID: $Id$
// Copyright: (c) 2004-2005 Ryan Norton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#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>
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);
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)
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));
}
}
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)
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;
}
}
}
+//-----------------------------------------------------------------------------
+// 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
//
//-----------------------------------------------------------------------------
bool wxGStreamerMediaBackend::Load(const wxString& fileName)
{
- return DoLoad(wxString( wxT("file://") ) + fileName);
+ return DoLoad(wxFileSystem::FileNameToURL(fileName));
}
//-----------------------------------------------------------------------------
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
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;
{
if (gst_element_set_state (m_playbin,
GST_STATE_PLAYING) == GST_STATE_FAILURE)
+ {
+ CheckForErrors();
return false;
+ }
+
return true;
}
m_llPausedPos = wxGStreamerMediaBackend::GetPosition();
if (gst_element_set_state (m_playbin,
GST_STATE_PAUSED) == GST_STATE_FAILURE)
+ {
+ CheckForErrors();
return false;
+ }
return true;
}
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;
}