summaryrefslogtreecommitdiffstats
path: root/src/part/xineEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/part/xineEngine.cpp')
-rw-r--r--src/part/xineEngine.cpp345
1 files changed, 345 insertions, 0 deletions
diff --git a/src/part/xineEngine.cpp b/src/part/xineEngine.cpp
new file mode 100644
index 0000000..2365f83
--- /dev/null
+++ b/src/part/xineEngine.cpp
@@ -0,0 +1,345 @@
+// (C) 2005 Max Howell ([email protected])
+// See COPYING file for licensing information
+
+#define CODEINE_DEBUG_PREFIX "engine"
+
+#include "debug.h"
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include "mxcl.library.h"
+#include <qapplication.h> //::sendEvent()
+#include <qdatetime.h> //::play()
+#include <qdir.h> //QDir::homeDir()
+#include <xine.h>
+#include "videoWindow.h"
+
+
+namespace Codeine {
+
+
+bool
+VideoWindow::init()
+{
+ mxcl::WaitCursor allocateOnStack;
+
+ debug() << "xine_new()\n";
+ m_xine = xine_new();
+ if( !m_xine )
+ return false;
+
+ debug() << "xine_config_load()\n";
+ xine_config_load( m_xine, QFile::encodeName( QDir::homeDirPath() + "/.xine/config" ) );
+
+ debug() << "xine_init()\n";
+ xine_init( m_xine );
+
+ debug() << "xine_open_video_driver()\n";
+ m_videoPort = xine_open_video_driver( m_xine, "auto", XINE_VISUAL_TYPE_X11, x11Visual() );
+
+ debug() << "xine_open_audio_driver()\n";
+ m_audioPort = xine_open_audio_driver( m_xine, "auto", NULL );
+
+ debug() << "xine_stream_new()\n";
+ m_stream = xine_stream_new( m_xine, m_audioPort, m_videoPort );
+ if( !m_stream )
+ return false;
+
+ if( !m_audioPort )
+ MessageBox::error( i18n("xine was unable to initialize any audio-drivers.") );
+ if( !m_videoPort )
+ MessageBox::error( i18n("xine was unable to initialize any video-drivers.") );
+
+ debug() << "xine_osd_new()\n";
+ m_osd = xine_osd_new( m_stream, 10, 10, 1000, 18 * 6 + 10 );
+ if( m_osd ) {
+ xine_osd_set_font( m_osd, "sans", 18 );
+ xine_osd_set_text_palette( m_osd, XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1 );
+ }
+
+ debug() << "xine_event_create_listener_thread()\n";
+ xine_event_create_listener_thread(
+ m_eventQueue = xine_event_new_queue( m_stream ),
+ &VideoWindow::xineEventListener, (void*)this );
+
+ { /// set save directory
+ xine_cfg_entry_t config;
+
+ if( xine_config_lookup_entry( m_xine, "misc.save_dir", &config ) ) {
+ const QCString dir = KGlobalSettings::desktopPath().local8Bit();
+ config.str_value = qstrdup( dir );
+ xine_config_update_entry( m_xine, &config );
+ }
+ }
+
+ return true;
+}
+
+bool
+VideoWindow::play( KURL url )
+{
+ DEBUG_BLOCK
+
+ m_url = url;
+
+ mxcl::WaitCursor allocateOnStack;
+
+ //TODO make sensible
+ if( url.protocol() == "http" ) {
+ /// automatically save http streams to Desktop folder
+
+ const QString fileName = url.filename();
+
+ QString
+ u = url.url();
+ u += "#save:";
+ u += url.host();
+ u += " [";
+ u += QDate::currentDate().toString();
+ u += ']';
+ u += fileName.mid( fileName.findRev( '.' ) + 1 ).lower();
+
+ url = u;
+ }
+
+ debug() << "About to load..\n";
+ if( xine_open( m_stream, url.url().local8Bit() ) )
+ {
+ debug() << "About to play..\n";
+ if( xine_play( m_stream, 0, 0 ) )
+ return true;
+ }
+
+ showErrorMessage();
+ return false;
+}
+
+void
+VideoWindow::togglePlay()
+{
+ if( xine_get_param( m_stream, XINE_PARAM_SPEED ) ) {
+ xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE );
+ xine_set_param( m_stream, XINE_PARAM_AUDIO_CLOSE_DEVICE, 1);
+ }
+ else
+ xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL );
+}
+
+void
+VideoWindow::toggleMute()
+{
+ bool const muted = xine_get_param( m_stream, XINE_PARAM_AUDIO_MUTE );
+ xine_set_param( m_stream, XINE_PARAM_AUDIO_MUTE, !muted );
+}
+
+void
+VideoWindow::eject()
+{
+ m_url = KURL();
+
+ xine_stop( m_stream );
+}
+
+int
+VideoWindow::position()
+{
+ int pos = 0, time = 0, length = 0;
+ xine_get_pos_length( m_stream, &pos, &time, &length );
+
+ return pos;
+}
+
+void
+VideoWindow::showErrorMessage()
+{
+ const QString filename = m_url.fileName();
+
+ debug() << "xine_get_error()\n";
+
+ // NOTE these error messages are somewhat customised
+ // relative to the main application
+ // This is because when embedded in some other application
+ // the error messages have no context, so we must say that we are a video player!
+
+ switch( xine_get_error( m_stream ) )
+ {
+ case XINE_ERROR_NO_INPUT_PLUGIN:
+ MessageBox::sorry( i18n("The Codeine video player could not find an input plugin for '%1'.").arg( filename ) );
+ break;
+ case XINE_ERROR_NO_DEMUX_PLUGIN:
+ MessageBox::sorry( i18n("The Codeine video player could not find a demux plugin for '%1'.").arg( filename ) );
+ break;
+ case XINE_ERROR_DEMUX_FAILED:
+ MessageBox::sorry( i18n("The Codeine video player failed to demux '%1'; please check your xine installation.").arg( filename ) );
+ break;
+ case XINE_ERROR_INPUT_FAILED:
+ case XINE_ERROR_MALFORMED_MRL:
+ case XINE_ERROR_NONE:
+ MessageBox::sorry( i18n("The Codeine video player reports an internal error; please check your xine installation.") );
+ break;
+ }
+}
+
+void
+VideoWindow::customEvent( QCustomEvent *e )
+{
+ switch( e->type() - 2000 ) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+//FIXME emit stateChanged( Engine::TrackEnded );
+ break;
+
+ case 1000:
+ #define message static_cast<QString*>(e->data())
+ emit statusMessage( *message );
+ delete message;
+ break;
+
+ case 1001:
+ MessageBox::sorry( (*message).arg( "FIXME" ) ); //FIXME
+ delete message;
+ break;
+
+ case 1002:
+ emit titleChanged( *message );
+ delete message;
+ break;
+ #undef message
+
+ default:
+ ;
+ }
+}
+
+void
+VideoWindow::xineEventListener( void *p, const xine_event_t* xineEvent )
+{
+ if( !p )
+ return;
+
+ #define engine static_cast<VideoWindow*>(p)
+
+ switch( xineEvent->type ) {
+ case XINE_EVENT_MRL_REFERENCE:
+ {
+ mxcl::WaitCursor allocateOnStack;
+ const char *mrl = ((xine_mrl_reference_data_t*)xineEvent->data)->mrl;
+
+ debug() << "XINE_EVENT_MRL_REFERENCE: " << mrl << endl;
+
+ if( xine_open( engine->m_stream, mrl ) )
+ xine_play( engine->m_stream, 0, 0 );
+
+ break;
+ }
+
+ case XINE_EVENT_UI_NUM_BUTTONS: debug() << "XINE_EVENT_UI_NUM_BUTTONS\n"; break;
+ case XINE_EVENT_DROPPED_FRAMES: debug() << "XINE_EVENT_DROPPED_FRAMES\n"; break;
+
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ case XINE_EVENT_FRAME_FORMAT_CHANGE:
+ case XINE_EVENT_UI_CHANNELS_CHANGED:
+ {
+ QCustomEvent *ce;
+ ce = new QCustomEvent( 2000 + xineEvent->type );
+ ce->setData( const_cast<xine_event_t*>(xineEvent) );
+ QApplication::postEvent( engine, ce );
+ break;
+ }
+
+ case XINE_EVENT_UI_SET_TITLE:
+ QApplication::postEvent( engine, new QCustomEvent(
+ QEvent::Type(3002),
+ new QString( QString::fromUtf8( static_cast<xine_ui_data_t*>(xineEvent->data)->str ) ) ) );
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t* pd = (xine_progress_data_t*)xineEvent->data;
+
+ QString
+ msg = "%1 %2%";
+ msg = msg.arg( QString::fromUtf8( pd->description ) )
+ .arg( KGlobal::locale()->formatNumber( pd->percent, 0 ) );
+
+ QApplication::postEvent( engine, new QCustomEvent( QEvent::Type(3000), new QString( msg ) ) );
+ break;
+ }
+ case XINE_EVENT_UI_MESSAGE:
+ {
+ debug() << "Message received from xine\n";
+
+ xine_ui_message_data_t *data = (xine_ui_message_data_t *)xineEvent->data;
+ QString message;
+
+ switch( data->type ) {
+ case XINE_MSG_NO_ERROR:
+ {
+ //series of \0 separated strings, terminated with a \0\0
+ char str[2000];
+ char *p = str;
+ for( char *msg = data->messages; !(*msg == '\0' && *(msg+1) == '\0'); ++msg, ++p )
+ *p = *msg == '\0' ? '\n' : *msg;
+ *p = '\0';
+
+ debug() << str << endl;
+
+ break;
+ }
+
+ case XINE_MSG_ENCRYPTED_SOURCE:
+ message = i18n("The source is encrypted and can not be decrypted."); goto param;
+ case XINE_MSG_UNKNOWN_HOST:
+ message = i18n("The host is unknown for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_UNKNOWN_DEVICE:
+ message = i18n("The device name you specified seems invalid."); goto param;
+ case XINE_MSG_NETWORK_UNREACHABLE:
+ message = i18n("The network appears unreachable."); goto param;
+ case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
+ message = i18n("Audio output unavailable; the device is busy."); goto param;
+ case XINE_MSG_CONNECTION_REFUSED:
+ message = i18n("The connection was refused for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_FILE_NOT_FOUND:
+ message = i18n("xine could not find the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_PERMISSION_ERROR:
+ message = i18n("Access was denied for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_READ_ERROR:
+ message = i18n("The source cannot be read for the URL: <i>%1</i>"); goto param;
+ case XINE_MSG_LIBRARY_LOAD_ERROR:
+ message = i18n("A problem occurred while loading a library or decoder."); goto param;
+
+ case XINE_MSG_GENERAL_WARNING:
+ case XINE_MSG_SECURITY:
+ default:
+
+ if(data->explanation)
+ {
+ message += "<b>";
+ message += QString::fromUtf8( (char*) data + data->explanation );
+ message += "</b>";
+ }
+ else break; //if no explanation then why bother!
+
+ //FALL THROUGH
+
+ param:
+
+ message.prepend( "<p>" );
+ message += "<p>";
+
+ if(data->parameters)
+ {
+ message += "xine says: <i>";
+ message += QString::fromUtf8( (char*) data + data->parameters);
+ message += "</i>";
+ }
+ else message += i18n("Sorry, no additional information is available.");
+
+ QApplication::postEvent( engine, new QCustomEvent(QEvent::Type(3001), new QString(message)) );
+ }
+
+ } //case
+ } //switch
+
+ #undef engine
+}
+
+} //namespace Codeine