summaryrefslogtreecommitdiffstats
path: root/kaffeine/src/player-parts/xine-part/kxinewidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kaffeine/src/player-parts/xine-part/kxinewidget.cpp')
-rw-r--r--kaffeine/src/player-parts/xine-part/kxinewidget.cpp4117
1 files changed, 4117 insertions, 0 deletions
diff --git a/kaffeine/src/player-parts/xine-part/kxinewidget.cpp b/kaffeine/src/player-parts/xine-part/kxinewidget.cpp
new file mode 100644
index 0000000..77f26e2
--- /dev/null
+++ b/kaffeine/src/player-parts/xine-part/kxinewidget.cpp
@@ -0,0 +1,4117 @@
+/*
+ * kxinewidget.cpp - a kde / qt api for xine-lib
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <[email protected]>
+ * Copyright (C) 2005-2006 Christophe Thommeret <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qapplication.h>
+#include <qwidget.h>
+#include <qstringlist.h>
+
+#include <qtimer.h>
+#include <qevent.h>
+#include <qdir.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qdatetime.h>
+#include <qtextcodec.h>
+
+#include <xine/xineutils.h>
+
+#include <cmath>
+
+#include "kxinewidget.h"
+#include "kaffeinepart.h"
+
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#ifndef USE_QT_ONLY
+#include "kxinewidget.moc"
+#include <klocale.h>
+#include <kdebug.h>
+#endif
+
+#define TIMER_EVENT_PLAYBACK_FINISHED 100
+#define TIMER_EVENT_NEW_CHANNELS 101
+#define TIMER_EVENT_NEW_TITLE 102
+#define TIMER_EVENT_NEW_STATUS 103
+#define TIMER_EVENT_CHANGE_CURSOR 104
+#define TIMER_EVENT_NEW_MRL_REFERENCE 105
+#define TIMER_EVENT_NEW_XINE_MESSAGE 106
+#define TIMER_EVENT_NEW_XINE_ERROR 107
+#define TIMER_EVENT_FRAME_FORMAT_CHANGE 108
+#define TIMER_EVENT_NEW_VOLUME_LEVEL 109
+#define TIMER_EVENT_RESTART_PLAYBACK 200
+#define TIMER_EVENT_RESIZE_PARENT 300
+
+
+KXineWidget::KXineWidget(QWidget* parent, const char* name,
+ const QString& pathToConfigFile, const QString& pathToLogoFile,
+ const QString& audioDriver, const QString& videoDriver,
+ bool startManual, bool verbose)
+ : QWidget(parent,name), m_startXineManual(startManual), m_xineReady(false),
+ m_logoFile(pathToLogoFile), m_preferedAudio(audioDriver), m_preferedVideo(videoDriver), m_xineVerbose(verbose),
+ m_xineEngine(NULL), m_audioDriver(NULL), m_videoDriver(NULL), m_xineStream(NULL), connection(NULL),
+ m_eventQueue(NULL), m_osd(NULL), m_osdUnscaled(false), m_osdShow(false), m_osdSize(0), m_osdFont(NULL),
+ m_audioChoices(NULL), m_audioInfo(NULL), m_videoChoices(NULL), m_videoInfo(NULL), m_mixerInfo(NULL),
+ m_osdShowInfo(NULL),
+ m_osdSizeOptions(NULL), m_osdSizeInfo(NULL), m_osdFontInfo(NULL),
+#ifndef USE_QT_ONLY
+ m_videoFiltersEnabled(true), m_audioFiltersEnabled(true), m_deinterlaceFilter(NULL),
+ m_deinterlaceEnabled(false),
+ m_visualPlugin(NULL),
+#else
+ m_xinePost(NULL), m_postAudioSource(NULL), m_postInput(NULL),
+#endif
+ m_visualPluginName(QString::null), m_currentSpeed(Normal), m_softwareMixer(false), m_volumeGain(false),
+ m_currentZoom(100), m_currentZoomX(100), m_currentZoomY(100), m_currentAudio(0), m_currentSub(0), m_savedPos(0), m_autoresizeEnabled(false)
+{
+ setMinimumSize(QSize(20,20)); // set a size hint
+ setPaletteBackgroundColor(QColor(0,0,0)); //black
+
+ /* dvb */
+ TimeShiftFilename = "";
+ dvbHaveVideo = 0;
+ dvbOSD = 0;
+ dvbColor[0] = 0;
+ connect( &dvbOSDHideTimer, SIGNAL(timeout()), this, SLOT(dvbHideOSD()) );
+
+ if (pathToConfigFile.isNull())
+ {
+ debugOut("Using default config file ~/.xine/config");
+ m_configFilePath = QDir::homeDirPath();
+ m_configFilePath.append("/.xine/config");
+ }
+ else
+ m_configFilePath = pathToConfigFile;
+
+ if (!m_logoFile.isNull())
+ appendToQueue(m_logoFile);
+
+#ifndef USE_QT_ONLY
+ m_videoFilterList.setAutoDelete(true); /*** delete post plugin on removing from list ***/
+ m_audioFilterList.setAutoDelete(true); /*** delete post plugin on removing from list ***/
+#endif
+
+ connect(&m_posTimer, SIGNAL(timeout()), this, SLOT(slotSendPosition()));
+ connect(&m_lengthInfoTimer, SIGNAL(timeout()), this, SLOT(slotEmitLengthInfo()));
+ connect(&m_mouseHideTimer, SIGNAL(timeout()), this, SLOT(slotHideMouse()));
+ connect(&m_osdTimer, SIGNAL(timeout()), this, SLOT(slotOSDHide()));
+ connect(&m_recentMessagesTimer, SIGNAL(timeout()), this, SLOT(slotNoRecentMessage()));
+
+ setUpdatesEnabled(false);
+ setMouseTracking(true);
+}
+
+
+KXineWidget::~KXineWidget()
+{
+ /* "careful" shutdown, maybe xine initialization was not successful */
+ m_xineReady = false;
+
+ /* stop all timers */
+ m_posTimer.stop();
+ m_mouseHideTimer.stop();
+
+#ifndef USE_QT_ONLY
+ slotRemoveAllAudioFilters();
+ slotRemoveAllVideoFilters();
+#endif
+ if (m_osd)
+ xine_osd_free(m_osd);
+
+ if (m_xineStream)
+ xine_close(m_xineStream);
+
+ debugOut("Shut down xine engine");
+
+#ifndef USE_QT_ONLY
+ if (m_deinterlaceFilter)
+ {
+ debugOut("Unwire video filters");
+ unwireVideoFilters();
+ delete m_deinterlaceFilter;
+ m_deinterlaceFilter = NULL;
+ }
+ if (m_visualPlugin)
+ {
+ debugOut("Unwire audio filters");
+ unwireAudioFilters();
+ debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName ));
+ delete m_visualPlugin;
+ m_visualPlugin = NULL;
+ }
+#else
+ if (m_xinePost)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
+ m_postAudioSource = xine_get_audio_source(m_xineStream);
+ xine_post_wire_audio_port(m_postAudioSource, m_audioDriver);
+ xine_post_dispose(m_xineEngine, m_xinePost);
+ }
+#endif
+ if (m_eventQueue)
+ {
+ debugOut("Dispose event queue");
+ xine_event_dispose_queue(m_eventQueue);
+ }
+ if (m_xineStream)
+ {
+ debugOut("Dispose stream");
+ xine_dispose(m_xineStream);
+ }
+ if (m_audioDriver)
+ {
+ debugOut("Close audio driver");
+ xine_close_audio_driver(m_xineEngine, m_audioDriver);
+ }
+ if (m_videoDriver)
+ {
+ debugOut("Close video driver");
+ xine_close_video_driver(m_xineEngine, m_videoDriver);
+ }
+ if (m_xineEngine)
+ {
+ saveXineConfig();
+ debugOut("Close xine engine");
+ xine_exit(m_xineEngine);
+ }
+ m_xineEngine = NULL;
+
+ /* free xine config strings */
+ if (m_osdShowInfo) free(m_osdShowInfo);
+
+ if (m_osdFontInfo) free(m_osdFontInfo);
+ if (m_osdFont) free(m_osdFont);
+
+ if (m_osdSizeInfo) free(m_osdSizeInfo);
+ if (m_osdSizeOptions)
+ {
+ int i=0;
+ while (m_osdSizeOptions[i])
+ {
+ free(m_osdSizeOptions[i]);
+ i++;
+ }
+ delete [] m_osdSizeOptions;
+ }
+
+ if (m_mixerInfo) free(m_mixerInfo);
+
+ if (m_videoInfo) free(m_videoInfo);
+ if (m_videoChoices)
+ {
+ int i=0;
+ while (m_videoChoices[i])
+ {
+ free(m_videoChoices[i]);
+ i++;
+ }
+ delete [] m_videoChoices;
+ }
+
+ if (m_audioInfo) free(m_audioInfo);
+ if (m_audioChoices)
+ {
+ int i=0;
+ while (m_audioChoices[i])
+ {
+ free(m_audioChoices[i]);
+ i++;
+ }
+ delete [] m_audioChoices;
+ }
+
+ if (connection)
+ {
+ debugOut("Close xine display");
+#ifndef HAVE_XCB
+ XCloseDisplay(connection); /* close xine display */
+#else
+ xcb_disconnect(connection); /* close xine display */
+#endif
+ }
+ connection = NULL;
+
+ debugOut("xine closed");
+}
+
+
+void KXineWidget::saveXineConfig()
+{
+ debugOut("Set CD/VCD/DVD path back");
+ xine_cfg_entry_t config;
+
+ if (!m_cachedCDPath.isNull())
+ {
+ xine_config_lookup_entry (m_xineEngine, "input.cdda_device", &config);
+ config.str_value = (char*)m_cachedCDPath.latin1();
+ xine_config_update_entry (m_xineEngine, &config);
+ }
+
+ if (!m_cachedVCDPath.isNull())
+ {
+ xine_config_lookup_entry (m_xineEngine, "input.vcd_device", &config);
+ config.str_value = (char*)m_cachedVCDPath.latin1();
+ xine_config_update_entry (m_xineEngine, &config);
+ }
+
+ if (!m_cachedDVDPath.isNull())
+ {
+ xine_config_lookup_entry (m_xineEngine, "input.dvd_device", &config);
+ config.str_value = (char*)m_cachedDVDPath.latin1();
+ xine_config_update_entry (m_xineEngine, &config);
+ }
+
+ debugOut(QString("Save xine config to: %1").arg(m_configFilePath));
+ xine_config_save(m_xineEngine, m_configFilePath.ascii());
+}
+
+
+/***************************************************
+ * CALLBACKS
+ ***************************************************/
+
+void KXineWidget::destSizeCallback(void* p, int /*video_width*/, int /*video_height*/, double /*video_aspect*/,
+ int* dest_width, int* dest_height, double* dest_aspect)
+
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ *dest_width = vw->width();
+ *dest_height = vw->height();
+ *dest_aspect = vw->m_displayRatio;
+}
+
+
+void KXineWidget::frameOutputCallback(void* p, int video_width, int video_height, double video_aspect,
+ int* dest_x, int* dest_y, int* dest_width, int* dest_height,
+ double* dest_aspect, int* win_x, int* win_y)
+
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ *dest_x = 0;
+ *dest_y = 0 ;
+ *dest_width = vw->width();
+ *dest_height = vw->height();
+ *win_x = vw->m_globalX;
+ *win_y = vw->m_globalY;
+ *dest_aspect = vw->m_displayRatio;
+
+ /* give false aspect for audio visualization*/
+ if ( !vw->hasVideo() ) {
+ *dest_aspect = (video_width*video_aspect)/((vw->width()*video_height/vw->height())-0.5);
+ }
+
+ /* correct size with video aspect */
+ if (video_aspect >= vw->m_displayRatio)
+ video_width = (int) ( (double) (video_width * video_aspect / vw->m_displayRatio + 0.5) );
+ else
+ video_height = (int) ( (double) (video_height * vw->m_displayRatio / video_aspect) + 0.5);
+
+ /* frame size changed */
+ if ( (video_width != vw->m_videoFrameWidth) || (video_height != vw->m_videoFrameHeight) )
+ {
+ debugOut(QString("New video frame size: %1x%2 - aspect ratio: %3").arg(video_width).arg(video_height).arg(video_aspect));
+ vw->m_videoFrameWidth = video_width;
+ vw->m_videoFrameHeight = video_height;
+ vw->m_videoAspect = video_aspect;
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_FRAME_FORMAT_CHANGE));
+
+ /* auto-resize parent widget */
+ if ((vw->m_autoresizeEnabled) && (vw->parentWidget()) && (vw->m_posTimer.isActive()) && (!vw->parentWidget()->isFullScreen())
+ && (video_width > 0) && (video_height > 0))
+ {
+ vw->m_newParentSize = vw->parentWidget()->size() - QSize((vw->width() - video_width), vw->height() - video_height);
+
+ debugOut(QString("Resize video window to: %1x%2").arg(vw->m_newParentSize.width()).arg(vw->m_newParentSize.height()));
+
+ /* we should not do a resize() inside a xine thread,
+ but post an event to the main thread */
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESIZE_PARENT));
+ }
+ }
+}
+
+
+/*
+ * XINE EVENT THREAD
+ * only the QT event thread should do GUI operations,
+ * we use QApplication::postEvent() and a reimplementation of QObject::timerEvent() to
+ * make sure all critical jobs are done within the QT main thread context
+ *
+ * for more information see http://doc.trolltech.com/3.1/threads.html
+ */
+
+void KXineWidget::xineEventListener(void *p, const xine_event_t* xineEvent)
+{
+
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ switch (xineEvent->type)
+ {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ {
+ debugOut("xine event: playback finished");
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_PLAYBACK_FINISHED ));
+ break;
+ }
+ case XINE_EVENT_UI_CHANNELS_CHANGED: /* new channel informations */
+ {
+ debugOut("xine event: channels changed");
+ int i,channels;
+ char* lang = new char[128];
+ QString slang;
+ int num;
+ QStringList tmp;
+ bool update=false, sk;
+
+ /*** get audio channels ***/
+ tmp.append(i18n("auto"));
+ channels = xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL);
+ for(i = 0; i < channels; i++)
+ {
+ slang = QString("%1.").arg(i+1);
+ if (xine_get_audio_lang(vw->m_xineStream, i, lang))
+ slang += lang;
+ tmp << slang;
+ }
+ if ( tmp!=vw->m_audioCh ) {
+ update = true;
+ vw->m_audioCh = tmp;
+ }
+ num = xine_get_param(vw->m_xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL);
+ if ( vw->m_currentAudio!=num ) {
+ update = true;
+ if ( num>channels )
+ vw->m_currentAudio = -1;
+ else
+ vw->m_currentAudio = num;
+ }
+
+ /*** get subtitle channels ***/
+ tmp.clear();
+ tmp.append(i18n("off"));
+ channels = xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_MAX_SPU_CHANNEL);
+ for(i = 0; i<channels; i++)
+ {
+ slang = QString("%1.").arg(i+1);
+ if (xine_get_spu_lang(vw->m_xineStream, i, lang))
+ slang += lang;
+ tmp << slang;
+ }
+ if ( tmp!=vw->m_subCh ) {
+ update = true;
+ vw->m_subCh = tmp;
+ }
+ num = xine_get_param(vw->m_xineStream, XINE_PARAM_SPU_CHANNEL);
+ if ( vw->m_currentSub!=num ) {
+ update = true;
+ if ( num>channels )
+ vw->m_currentSub = -1;
+ else
+ vw->m_currentSub = num;
+ }
+
+ delete [] lang;
+
+ //check if stream is seekable
+ sk = (bool)xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_SEEKABLE);
+ if ( vw->m_trackIsSeekable!=sk ) {
+ update = true;
+ vw->m_trackIsSeekable = sk;
+ }
+
+ if ( update )
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_CHANNELS));
+ break;
+ }
+ case XINE_EVENT_UI_SET_TITLE: /* set new title */
+ {
+ debugOut("xine event: ui set title");
+ xine_ui_data_t* xd = (xine_ui_data_t*)xineEvent->data;
+ vw->m_trackTitle = QString::fromLocal8Bit( (char*)xd->str );
+
+ vw->m_lengthInfoTries = 0;
+ vw->m_lengthInfoTimer.start(1000); /* May be new Length on Changing DVD/VCD titles */
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_TITLE));
+ break;
+ }
+ case XINE_EVENT_PROGRESS:
+ {
+ debugOut("xine event: progress info");
+ xine_progress_data_t* pd = (xine_progress_data_t*)xineEvent->data;
+
+ vw->m_statusString = QString::fromLocal8Bit(pd->description) + " " + QString::number(pd->percent) + "%";
+
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
+ break;
+ }
+ case XINE_EVENT_DROPPED_FRAMES:
+ {
+ debugOut("xine event: dropped frames");
+ xine_dropped_frames_t* dropped = (xine_dropped_frames_t*)xineEvent->data;
+
+ warningOut(QString("Skipped frames: %1 - discarded frames: %2").arg(dropped->skipped_frames/10).arg(dropped->discarded_frames/10));
+
+ break;
+ }
+ case XINE_EVENT_SPU_BUTTON:
+ {
+ debugOut("xine event: spu button");
+ xine_spu_button_t* button = (xine_spu_button_t*)xineEvent->data;
+
+ if (button->direction == 1) /* enter a button */
+ {
+ debugOut("DVD Menu: Mouse entered button");
+ vw->m_DVDButtonEntered = true;
+ }
+ else
+ {
+ debugOut("DVD Menu: Mouse left button");
+ vw->m_DVDButtonEntered = false;
+ }
+
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_CHANGE_CURSOR));
+ break;
+ }
+ case XINE_EVENT_UI_NUM_BUTTONS:
+ {
+ debugOut("xine event: ui num buttons");
+
+ break;
+ }
+ case XINE_EVENT_MRL_REFERENCE:
+ {
+ debugOut("xine event: mrl reference");
+ xine_mrl_reference_data_t* mrldata = (xine_mrl_reference_data_t*)xineEvent->data;
+ vw->m_newMRLReference = mrldata->mrl;
+
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_MRL_REFERENCE));
+ break;
+ }
+ case XINE_EVENT_FRAME_FORMAT_CHANGE:
+ {
+ // debugOut("xine event: frame format change");
+
+ // QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_FRAME_FORMAT_CHANGE));
+ break;
+ }
+ case XINE_EVENT_AUDIO_LEVEL:
+ {
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_VOLUME_LEVEL));
+ break;
+ }
+ case XINE_EVENT_UI_MESSAGE:
+ {
+ debugOut("xine event: xine message");
+
+ xine_ui_message_data_t *data = (xine_ui_message_data_t *)xineEvent->data;
+ QString message;
+
+ switch(data->type)
+ {
+ case XINE_MSG_NO_ERROR:
+ {
+ /* copy strings, and replace '\0' separators by '\n' */
+ char* s = data->messages;
+ char* d = new char[2000];
+
+ while(s && (*s != '\0') && ((*s + 1) != '\0'))
+ {
+ switch(*s)
+ {
+ case '\0':
+ {
+ *d = '\n';
+ break;
+ }
+ default:
+ {
+ *d = *s;
+ break;
+ }
+ }
+ s++;
+ d++;
+ }
+ *++d = '\0';
+
+ message = d;
+ delete [] d;
+ break;
+ }
+ case XINE_MSG_GENERAL_WARNING:
+ {
+ message = i18n("General Warning: \n");
+
+ if(data->explanation)
+ message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
+ else
+ message = message + i18n("No Informations available.");
+
+ break;
+ }
+ case XINE_MSG_SECURITY:
+ {
+ message = i18n("Security Warning: \n");
+
+ if(data->explanation)
+ message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
+
+ break;
+ }
+ case XINE_MSG_UNKNOWN_HOST:
+ {
+ message = i18n("The host you're trying to connect is unknown.\nCheck the validity of the specified hostname. ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_UNKNOWN_DEVICE:
+ {
+ message = i18n("The device name you specified seems invalid. ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_NETWORK_UNREACHABLE:
+ {
+ message = i18n("The network looks unreachable.\nCheck your network setup and the server name. ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
+ {
+ message = i18n("Audio output unavailable. Device is busy. ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_CONNECTION_REFUSED:
+ {
+ message = i18n("The connection was refused.\nCheck the host name. ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_FILE_NOT_FOUND:
+ {
+ message = "@"+i18n("The specified file or url was not found. Please check it. ");
+ if(data->explanation)
+ message = message + "(" + QString::fromLocal8Bit((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_PERMISSION_ERROR:
+ {
+ message = i18n("Permission to this source was denied. ");
+ // if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ case XINE_MSG_READ_ERROR:
+ {
+ message = i18n("The source can't be read.\nMaybe you don't have enough rights for this, or source doesn't contain data (e.g: no disc in drive). ");
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ debugOut(message);
+ return; // This error is handled by autoinstallation
+ }
+ case XINE_MSG_LIBRARY_LOAD_ERROR:
+ {
+ message = i18n("A problem occur while loading a library or a decoder: ");
+ if(data->explanation)
+ message = message + ((char *) data + data->parameters);
+ break;
+ }
+ case XINE_MSG_ENCRYPTED_SOURCE:
+ {
+ message = i18n("The source seems encrypted, and can't be read. ");
+ if (vw->m_trackURL.contains("dvd:/"))
+ {
+ if (KaffeinePart::installDistroCodec(vw, "xine-engine", "dvdcss"))
+ return;
+ message = message + i18n("\nYour DVD is probably crypted. According to your country laws, you can or can't use libdvdcss to be able to read this disc. ");
+ }
+ if(data->explanation)
+ message = message + "(" + ((char *) data + data->parameters) + ")";
+ break;
+ }
+ default:
+ {
+ message = i18n("Unknown error: \n");
+ if(data->explanation)
+ message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
+ break;
+ }
+ }
+
+ vw->m_xineMessage = message;
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_XINE_MESSAGE));
+ break;
+ }
+ default:
+ {
+ //debugOut("xine event: unhandled type ");
+ break;
+ }
+ }
+}
+
+void KXineWidget::timerEvent( QTimerEvent* tevent )
+{
+ switch ( tevent->timerId() )
+ {
+ case TIMER_EVENT_PLAYBACK_FINISHED:
+ {
+ if ( !TimeShiftFilename.isEmpty() )
+ {
+ QTimer::singleShot(0, this, SLOT(slotPlayTimeShift()));
+ break;
+ }
+ if ( m_trackURL=="DVB" || m_trackURL.contains(".kaxtv") )
+ break;
+
+#ifdef XINE_PARAM_GAPLESS_SWITCH
+ if ( xine_check_version(1,1,1) )
+ xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 1);
+#endif
+ if (isQueueEmpty())
+ {
+ if (m_trackURL != m_logoFile)
+ emit signalPlaybackFinished();
+ else
+ xine_stop(m_xineStream);
+ }
+ else
+ QTimer::singleShot(0, this, SLOT(slotPlay()));
+ break;
+ }
+ case TIMER_EVENT_NEW_CHANNELS:
+ {
+ emit signalNewChannels(m_audioCh, m_subCh, m_currentAudio, m_currentSub);
+ break;
+ }
+ case TIMER_EVENT_NEW_TITLE:
+ {
+ emit signalTitleChanged();
+ break;
+ }
+ case TIMER_EVENT_FRAME_FORMAT_CHANGE:
+ {
+ if ((m_trackHasVideo) && (m_trackURL != m_logoFile))
+ emit signalVideoSizeChanged();
+ break;
+ }
+ case TIMER_EVENT_NEW_STATUS:
+ {
+ emit signalXineStatus(m_statusString);
+ break;
+ }
+ case TIMER_EVENT_CHANGE_CURSOR:
+ {
+ if (m_DVDButtonEntered)
+ setCursor(QCursor(Qt::PointingHandCursor));
+ else
+ setCursor(QCursor(Qt::ArrowCursor));
+ break;
+ }
+ case TIMER_EVENT_NEW_MRL_REFERENCE:
+ {
+ m_queue.prepend(m_newMRLReference );
+ break;
+ }
+ case TIMER_EVENT_NEW_VOLUME_LEVEL:
+ {
+ emit signalSyncVolume();
+ break;
+ }
+ case TIMER_EVENT_NEW_XINE_MESSAGE:
+ {
+ if (!m_recentMessagesTimer.isActive())
+ {
+ m_recentMessagesTimer.start(1500);
+ emit signalXineMessage(m_xineMessage);
+ }
+ else
+ {
+ //restart
+ warningOut(QString("Message: '%1' was blocked!").arg(m_xineMessage));
+ m_recentMessagesTimer.start(1500);
+ }
+ break;
+ }
+ case TIMER_EVENT_NEW_XINE_ERROR:
+ {
+ emit signalXineError(m_xineError);
+ break;
+ }
+ case TIMER_EVENT_RESTART_PLAYBACK:
+ {
+ appendToQueue(m_trackURL);
+ slotPlay();
+ break;
+ }
+ case TIMER_EVENT_RESIZE_PARENT:
+ {
+ parentWidget()->resize(m_newParentSize);
+ break;
+ }
+ default: break;
+ }
+}
+
+void KXineWidget::slotNoRecentMessage()
+{
+ m_recentMessagesTimer.stop();
+}
+
+/******************* new video driver *********************/
+
+void KXineWidget::videoDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ if (entry == NULL) return;
+#ifndef USE_QT_ONLY
+ KXineWidget* vw = (KXineWidget*) p;
+ xine_video_port_t* oldVideoDriver = vw->m_videoDriver;
+ xine_video_port_t* noneVideoDriver;
+
+ int pos, time, length;
+
+ debugOut(QString("New video driver: %1").arg(entry->enum_values[entry->num_value]));
+
+ if (vw->m_osd)
+ {
+ xine_osd_free(vw->m_osd);
+ vw->m_osd = NULL;
+ }
+
+ noneVideoDriver = xine_open_video_driver(vw->m_xineEngine, "none",
+ XINE_VISUAL_TYPE_NONE, NULL);
+ if (!noneVideoDriver)
+ {
+ errorOut("Can't init Video Driver 'none', operation aborted.");
+ return;
+ }
+
+ bool playing = false;
+ if (vw->isPlaying())
+ {
+ playing = true;
+ vw->m_savedPos = 0;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(vw->m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret != 0 )
+ vw->m_savedPos = pos;
+ }
+
+ xine_close(vw->m_xineStream);
+
+ /* wire filters to "none" driver so the old one can be safely disposed */
+ vw->m_videoDriver = noneVideoDriver;
+ vw->unwireVideoFilters();
+ vw->wireVideoFilters();
+
+ vw->unwireAudioFilters();
+ if (vw->m_visualPlugin)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(vw->m_visualPluginName));
+ delete vw->m_visualPlugin;
+ vw->m_visualPlugin = NULL;
+ }
+
+ xine_event_dispose_queue(vw->m_eventQueue);
+ xine_dispose(vw->m_xineStream);
+
+ xine_close_video_driver(vw->m_xineEngine, oldVideoDriver);
+
+ vw->m_videoDriver = xine_open_video_driver(vw->m_xineEngine,
+#ifndef HAVE_XCB
+ entry->enum_values[entry->num_value], XINE_VISUAL_TYPE_X11,
+#else
+ entry->enum_values[entry->num_value], XINE_VISUAL_TYPE_XCB,
+#endif
+ (void *) &(vw->m_x11Visual));
+
+ if (!vw->m_videoDriver)
+ {
+ vw->m_xineError = i18n("Error: Can't init new Video Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->m_videoDriverName);
+ QApplication::postEvent(vw, new QTimerEvent( TIMER_EVENT_NEW_XINE_ERROR));
+ playing = false;
+ vw->m_videoDriver = xine_open_video_driver(vw->m_xineEngine,
+#ifndef HAVE_XCB
+ vw->m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
+#else
+ vw->m_videoDriverName.ascii(), XINE_VISUAL_TYPE_XCB,
+#endif
+ (void *) &(vw->m_x11Visual));
+ }
+ else
+ {
+ vw->m_videoDriverName = entry->enum_values[entry->num_value];
+ vw->m_statusString = i18n("Using Video Driver: %1").arg(vw->m_videoDriverName);
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
+ }
+
+ vw->m_xineStream = xine_stream_new(vw->m_xineEngine, vw->m_audioDriver, vw->m_videoDriver);
+ vw->m_eventQueue = xine_event_new_queue (vw->m_xineStream);
+ xine_event_create_listener_thread(vw->m_eventQueue, &KXineWidget::xineEventListener, p);
+
+ /* rewire filters to the new driver */
+ vw->unwireVideoFilters();
+ vw->wireVideoFilters();
+
+ /* "none" can now be disposed too */
+ xine_close_video_driver(vw->m_xineEngine, noneVideoDriver);
+
+ vw->initOSD();
+
+ if (playing)
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESTART_PLAYBACK));
+#endif
+}
+
+/*********************** new audio driver *************************/
+
+void KXineWidget::audioDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ if (entry == NULL) return;
+#ifndef USE_QT_ONLY
+ KXineWidget* vw = (KXineWidget*) p;
+
+ int pos, time, length;
+
+ debugOut(QString("New audio driver: %1").arg(entry->enum_values[entry->num_value]));
+
+ if (vw->m_osd)
+ {
+ xine_osd_free(vw->m_osd);
+ vw->m_osd = NULL;
+ }
+
+ vw->unwireVideoFilters();
+
+ bool playing = false;
+ if (vw->isPlaying())
+ {
+ playing = true;
+ vw->m_savedPos = 0;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(vw->m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret != 0 )
+ vw->m_savedPos = pos;
+ }
+
+ xine_close(vw->m_xineStream);
+
+ vw->unwireAudioFilters();
+ if (vw->m_visualPlugin)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(vw->m_visualPluginName));
+ delete vw->m_visualPlugin;
+ vw->m_visualPlugin = NULL;
+ }
+
+ xine_event_dispose_queue(vw->m_eventQueue);
+ xine_dispose(vw->m_xineStream);
+ xine_close_audio_driver(vw->m_xineEngine, vw->m_audioDriver);
+ vw->m_audioDriver = NULL;
+
+ vw->m_audioDriver = xine_open_audio_driver(vw->m_xineEngine, entry->enum_values[entry->num_value], NULL);
+
+ if (!vw->m_audioDriver)
+ {
+ vw->m_xineError = i18n("Error: Can't init new Audio Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->m_audioDriverName);
+ QApplication::postEvent(vw, new QTimerEvent( TIMER_EVENT_NEW_XINE_ERROR));
+ playing = false;
+ vw->m_audioDriver = xine_open_audio_driver(vw->m_xineEngine, vw->m_audioDriverName.ascii(), NULL);
+ }
+ else
+ {
+ vw->m_audioDriverName = entry->enum_values[entry->num_value];
+ vw->m_statusString = i18n("Using Audio Driver: %1").arg(vw->m_audioDriverName);
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
+ }
+
+ vw->m_xineStream = xine_stream_new(vw->m_xineEngine, vw->m_audioDriver, vw->m_videoDriver);
+ vw->m_eventQueue = xine_event_new_queue (vw->m_xineStream);
+ xine_event_create_listener_thread(vw->m_eventQueue, &KXineWidget::xineEventListener, p);
+
+ vw->wireVideoFilters();
+
+ vw->initOSD();
+
+ if (playing)
+ QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESTART_PLAYBACK));
+#endif
+}
+
+/******** change audio mixer method ****************/
+void KXineWidget::audioMixerMethodChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ vw->m_softwareMixer = (bool)entry->num_value;
+}
+
+/******** Callback for OSD configuration ****************/
+void KXineWidget::showOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ if (vw->m_osd)
+ vw->m_osdShow = (bool)entry->num_value;
+}
+
+void KXineWidget::sizeForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ const int fontsizetable[] = { 16,20,24,32,48,64 };
+
+ if (entry->num_value >= 6)
+ {
+ debugOut("Font size not defined: Shouldn't have happened");
+ return;
+ }
+
+ if (vw->m_osd)
+ {
+ vw->m_osdSize = entry->num_value;
+ xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]);
+ }
+}
+
+void KXineWidget::fontForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ const int fontsizetable[] = { 16,20,24,32,48,64 };
+
+ if (vw->m_osd)
+ if (entry->str_value)
+ {
+ free(vw->m_osdFont);
+ vw->m_osdFont = strdup(entry->str_value);
+ if (!xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]))
+ {
+ free(vw->m_osdFont);
+ vw->m_osdFont = strdup("sans");
+ if (!xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]))
+ warningOut("Default SANS font not found: shouldn't have happened.");
+ }
+ }
+}
+
+void KXineWidget::monitorXResChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ vw->monitorXRes = (double)entry->num_value;
+ double m_displayRatio = vw->monitorYRes / vw->monitorXRes;
+ if ((m_displayRatio >= 0.98) && (m_displayRatio <= 1.02))
+ m_displayRatio = 1;
+ vw->m_displayRatio = m_displayRatio;
+}
+
+void KXineWidget::monitorYResChangedCallback(void* p, xine_cfg_entry_t* entry)
+{
+ if (p == NULL) return;
+ KXineWidget* vw = (KXineWidget*) p;
+
+ vw->monitorYRes = (double)entry->num_value;
+ double m_displayRatio = vw->monitorYRes / vw->monitorXRes;
+ if ((m_displayRatio >= 0.98) && (m_displayRatio <= 1.02))
+ m_displayRatio = 1;
+ vw->m_displayRatio = m_displayRatio;
+}
+
+/**********************************************
+ * EVENT LOOP
+ *********************************************/
+
+#ifndef HAVE_XCB
+bool KXineWidget::x11Event(XEvent *event)
+{
+ if (isXineReady())
+ if (event->type == Expose)
+ if (event->xexpose.count == 0)
+ xine_port_send_gui_data(m_videoDriver, XINE_GUI_SEND_EXPOSE_EVENT, event);
+
+ return false;
+}
+#else
+void KXineWidget::paintEvent(QPaintEvent *event)
+{
+ if (isXineReady()) {
+ const QRect &rect = event->rect();
+
+ xcb_expose_event_t xcb_event;
+ memset(&xcb_event, 0, sizeof(xcb_event));
+
+ xcb_event.window = winId();
+ xcb_event.x = rect.x();
+ xcb_event.y = rect.y();
+ xcb_event.width = rect.width();
+ xcb_event.height = rect.height();
+ xcb_event.count = 0;
+
+ xine_port_send_gui_data(m_videoDriver, XINE_GUI_SEND_EXPOSE_EVENT, &xcb_event);
+ }
+
+ QWidget::paintEvent(event);
+}
+#endif
+
+/**********************************************************
+ * INIT XINE ENGINE
+ *********************************************************/
+
+void KXineWidget::polish()
+{
+ if ((!m_startXineManual) && (!isXineReady())) /* start xine engine automatically? */
+ {
+ initXine();
+ }
+}
+
+bool KXineWidget::initXine()
+{
+ if (isXineReady())
+ return true;
+
+ emit signalXineStatus(i18n("Init xine..."));
+ globalPosChanged(); /* get global pos of the window */
+
+ /**** INIT XINE DISPLAY ****/
+
+#ifndef HAVE_XCB
+ XInitThreads();
+
+ connection = XOpenDisplay(NULL);
+#else
+ int screen_nbr = 0;
+ connection = xcb_connect(NULL, &screen_nbr);
+#endif
+
+ if (!connection)
+ {
+ emit signalXineFatal(i18n("Failed to connect to X-Server!"));
+ return false;
+ }
+
+ int m_xineWindow = winId();
+
+/* // determine display aspect ratio
+ double resHor = ((double) DisplayWidth(x11Display(), x11Screen())) / DisplayWidthMM(x11Display(), x11Screen());
+ double resVer = ((double) DisplayHeight(x11Display(), x11Screen())) / DisplayHeightMM(x11Display(), x11Screen());
+
+ m_displayRatio = resVer / resHor;
+
+ if ((m_displayRatio >= 0.98) && (m_displayRatio <= 1.02))
+ m_displayRatio = 1;
+
+#ifdef HAVE_XINERAMA
+ int dummy_event, dummy_error;
+
+ if (XineramaQueryExtension(x11Display(), &dummy_event, &dummy_error))
+ {
+ int count = 1;
+ debugOut("Xinerama extension present");
+ XineramaQueryScreens(x11Display(), &count);
+ debugOut(QString("%1 screens detected").arg(count));
+ if (count > 1)
+ // multihead -> assuming square pixels
+ m_displayRatio = 1.0;
+ }
+#endif
+
+ debugOut(QString("Display aspect ratio (v/h): %1").arg(m_displayRatio));*/
+
+ /**** INIT XINE ENGINE ****/
+
+ debugOut(QString("Using xine version %1").arg(xine_get_version_string()));
+
+ m_xineEngine = xine_new();
+ if (!m_xineEngine)
+ {
+ emit signalXineFatal(i18n("Can't init xine Engine!"));
+ return false;
+ }
+
+ if (m_xineVerbose)
+ xine_engine_set_param(m_xineEngine, XINE_ENGINE_PARAM_VERBOSITY, 99);
+
+ /* load configuration */
+
+ if (!QFile::exists(m_configFilePath))
+ warningOut("No config file found, will create one...");
+ else
+ xine_config_load(m_xineEngine, QFile::encodeName(m_configFilePath));
+
+
+ debugOut("Post-init xine engine");
+ xine_init(m_xineEngine);
+
+ /** set xine parameters **/
+
+ const char* const* drivers = NULL;
+ drivers = xine_list_audio_output_plugins(m_xineEngine);
+ int i = 0;
+ while (drivers[i] != NULL) i++;
+ m_audioChoices = new char*[i+2];
+ m_audioChoices[0] = strdup("auto");
+ m_audioDriverList << m_audioChoices[0];
+ i = 0;
+ while(drivers[i])
+ {
+ m_audioChoices[i+1] = strdup(drivers[i]);
+ m_audioDriverList << m_audioChoices[i+1];
+ i++;
+ }
+ m_audioChoices[i+1] = NULL;
+
+ m_audioInfo = strdup(i18n("Audiodriver to use (default: auto)").local8Bit());
+ i = xine_config_register_enum(m_xineEngine, "audio.driver", 0,
+ m_audioChoices, m_audioInfo, NULL, 10, &KXineWidget::audioDriverChangedCallback, this);
+
+ if (m_audioDriverList.contains(m_preferedAudio))
+ m_audioDriverName = m_preferedAudio;
+ else
+ m_audioDriverName = m_audioChoices[i];
+
+ debugOut(QString("Use audio driver %1").arg(m_audioDriverName));
+
+ drivers = xine_list_video_output_plugins(m_xineEngine);
+ i = 0;
+ while (drivers[i] != NULL) i++;
+ m_videoChoices = new char*[i+2];
+ m_videoChoices[0] = strdup("auto");
+ m_videoDriverList << m_videoChoices[0];
+ i = 0;
+ while(drivers[i])
+ {
+ m_videoChoices[i+1] = strdup(drivers[i]);
+ m_videoDriverList << m_videoChoices[i+1];
+ i++;
+ }
+ m_videoChoices[i+1] = NULL;
+
+ m_videoInfo = strdup(i18n("Videodriver to use (default: auto)").local8Bit());
+ i = xine_config_register_enum(m_xineEngine, "video.driver", 0,
+ m_videoChoices, m_videoInfo, NULL, 10, &KXineWidget::videoDriverChangedCallback, this);
+
+ if (m_videoDriverList.contains(m_preferedVideo))
+ m_videoDriverName = m_preferedVideo;
+ else
+ m_videoDriverName = m_videoChoices[i];
+
+ debugOut(QString("Use video driver %1").arg(m_videoDriverName));
+
+ m_mixerInfo = strdup(i18n("Use software audio mixer").local8Bit());
+ m_softwareMixer = (bool)xine_config_register_bool(m_xineEngine, "audio.mixer_software", 1, m_mixerInfo,
+ NULL, 10, &KXineWidget::audioMixerMethodChangedCallback, this);
+
+ m_osdShowInfo = strdup(i18n("Show OSD Messages").local8Bit());
+ m_osdShow = (bool)xine_config_register_bool(m_xineEngine, "osd.osd_messages", 1, m_osdShowInfo,
+ NULL, 10, &KXineWidget::showOSDMessagesChangedCallback, this);
+
+ m_osdSizeOptions = new char*[7];
+ m_osdSizeOptions[0] = strdup("tiny");
+ m_osdSizeOptions[1] = strdup("small");
+ m_osdSizeOptions[2] = strdup("medium");
+ m_osdSizeOptions[3] = strdup("large");
+ m_osdSizeOptions[4] = strdup("very large");
+ m_osdSizeOptions[5] = strdup("huge");
+ m_osdSizeOptions[6] = NULL;
+
+ m_osdSizeInfo = strdup(i18n("Size of OSD text").local8Bit());
+ m_osdSize = (int)xine_config_register_enum(m_xineEngine, "osd.osd_size", 1 /*small - 20P*/, m_osdSizeOptions, m_osdSizeInfo,
+ NULL, 10, &KXineWidget::sizeForOSDMessagesChangedCallback, this);
+
+ m_osdFontInfo = strdup(i18n("Font for OSD Messages").local8Bit());
+ m_osdFont = strdup((char*)xine_config_register_string(m_xineEngine, "osd.osd_font", "sans", m_osdFontInfo,
+ NULL, 10, &KXineWidget::fontForOSDMessagesChangedCallback, this));
+
+ xResInfo = strdup(i18n("Monitor horizontal resolution (dpi).").local8Bit());
+ monitorXRes = (bool)xine_config_register_range(m_xineEngine, "video.screen_x_res", 78, 1, 200, xResInfo,
+ NULL, 10, &KXineWidget::monitorXResChangedCallback, this);
+ yResInfo = strdup(i18n("Monitor vertical resolution (dpi).").local8Bit());
+ monitorYRes = (bool)xine_config_register_range(m_xineEngine, "video.screen_y_res", 78, 1, 200, yResInfo,
+ NULL, 10, &KXineWidget::monitorYResChangedCallback, this);
+
+ double resHor = (double)monitorXRes;
+ double resVer = (double)monitorYRes;
+ m_displayRatio = resVer / resHor;
+ if ((m_displayRatio >= 0.98) && (m_displayRatio <= 1.02))
+ m_displayRatio = 1;
+
+ /* init video driver */
+ debugOut("Init video driver");
+
+#ifndef HAVE_XCB
+ m_x11Visual.display = connection;
+ m_x11Visual.screen = DefaultScreen(connection);
+ m_x11Visual.d = m_xineWindow;
+#else
+ xcb_screen_iterator_t screen_it = xcb_setup_roots_iterator(xcb_get_setup(connection));
+ while ((screen_it.rem > 1) && (screen_nbr > 0)) {
+ xcb_screen_next(&screen_it);
+ --screen_nbr;
+ }
+
+ m_x11Visual.connection = connection;
+ m_x11Visual.screen = screen_it.data;
+ m_x11Visual.window = m_xineWindow;
+#endif
+ m_x11Visual.dest_size_cb = &KXineWidget::destSizeCallback;
+ m_x11Visual.frame_output_cb = &KXineWidget::frameOutputCallback;
+ m_x11Visual.user_data = (void*)this;
+
+ m_videoDriver = xine_open_video_driver(m_xineEngine,
+#ifndef HAVE_XCB
+ m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
+#else
+ m_videoDriverName.ascii(), XINE_VISUAL_TYPE_XCB,
+#endif
+ (void *) &(m_x11Visual));
+
+ if (!m_videoDriver && m_videoDriverName != "auto")
+ {
+ emit signalXineError(i18n("Can't init Video Driver '%1' - trying 'auto'...").arg(m_videoDriverName));
+ m_videoDriverName = "auto";
+ m_videoDriver = xine_open_video_driver(m_xineEngine,
+#ifndef HAVE_XCB
+ m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
+#else
+ m_videoDriverName.ascii(), XINE_VISUAL_TYPE_XCB,
+#endif
+ (void *) &(m_x11Visual));
+ }
+
+ if (!m_videoDriver)
+ {
+ emit signalXineFatal(i18n("All Video Drivers failed to initialize!"));
+ return false;
+ }
+
+ /* init audio driver */
+ debugOut("Init audio driver");
+
+ m_audioDriver = xine_open_audio_driver(m_xineEngine, m_audioDriverName.ascii(), NULL);
+
+ if (!m_audioDriver && m_audioDriverName != "auto")
+ {
+ emit signalXineError(i18n("Can't init Audio Driver '%1' - trying 'auto'...").arg(m_audioDriverName));
+ m_audioDriverName = "auto";
+ m_audioDriver = xine_open_audio_driver (m_xineEngine, m_audioDriverName.ascii(), NULL);
+ }
+
+ if (!m_audioDriver)
+ {
+ emit signalXineFatal(i18n("All Audio Drivers failed to initialize!"));
+ return false;
+ }
+
+ //debugOut("Open xine stream");
+
+ m_xineStream = xine_stream_new(m_xineEngine, m_audioDriver, m_videoDriver);
+ if (!m_xineStream)
+ {
+ emit signalXineFatal(i18n("Can't create a new xine Stream!"));
+ return false;
+ }
+
+#ifdef XINE_PARAM_EARLY_FINISHED_EVENT
+ if ( xine_check_version(1,1,1) ) {
+ // enable gapless playback
+ xine_set_param(m_xineStream, XINE_PARAM_EARLY_FINISHED_EVENT, 1 );
+ }
+#endif
+
+ /*** OSD ***/
+
+ initOSD();
+
+ /** event handling **/
+
+ m_eventQueue = xine_event_new_queue (m_xineStream);
+ xine_event_create_listener_thread(m_eventQueue, &KXineWidget::xineEventListener, (void*)this);
+
+ //maybe user closed player in muted state
+ if (m_softwareMixer)
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_MUTE, 0);
+ else
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_MUTE, 0);
+
+ m_xineReady = true;
+
+ debugOut("xine init successful");
+
+ emit signalXineStatus(i18n("Ready"));
+ emit signalXineReady();
+
+ /** something to play? **/
+ slotPlay();
+
+ return true;
+}
+
+void KXineWidget::initOSD()
+{
+ debugOut("Init OSD");
+ const int fontsizetable[] = { 16,20,24,32,48,64 };
+ m_osd = xine_osd_new(m_xineStream, 10, 10, 1000, 200);
+ if (m_osd)
+ {
+ if (!xine_osd_set_font(m_osd, m_osdFont, fontsizetable[m_osdSize]))
+ {
+ debugOut(QString("Font ->%1<- specified for OSD doesn't exists.").arg(m_osdFont));
+ free(m_osdFont);
+ m_osdFont = strdup("sans");
+ xine_osd_set_font(m_osd, m_osdFont, fontsizetable[m_osdSize]);
+ }
+ debugOut(QString("Font for OSD: %1").arg(m_osdFont));
+ xine_osd_set_text_palette(m_osd, XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
+ m_osdUnscaled = (xine_osd_get_capabilities(m_osd) & XINE_OSD_CAP_UNSCALED);
+ if (m_osdUnscaled)
+ debugOut("Unscaled OSD available");
+ }
+ else
+ warningOut("Initialisation of xine OSD failed.");
+}
+
+/************************************************
+ * PLAY MRL
+ ************************************************/
+
+bool KXineWidget::playDvb()
+{
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+
+ QPtrList<PostFilter> activeList;
+
+ if (m_audioFilterList.count() && m_audioFiltersEnabled)
+ activeList = m_audioFilterList;
+
+ if ( !dvbHaveVideo )
+ {
+ if (!m_visualPlugin)
+ {
+ debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
+ m_visualPlugin = new PostFilter(m_visualPluginName, m_xineEngine, m_audioDriver, m_videoDriver, NULL);
+ }
+
+ activeList.insert (0, m_visualPlugin);
+ }
+ else
+ {
+ if (m_visualPlugin)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
+ delete m_visualPlugin;
+ m_visualPlugin = NULL;
+ }
+ }
+
+ if (activeList.count())
+ {
+ xine_post_wire_audio_port(activeList.at(activeList.count()-1)->getOutput(), m_audioDriver);
+
+ for (uint i = activeList.count()-1; i >0; i--)
+ {
+ xine_post_wire(activeList.at(i-1)->getOutput(), activeList.at(i)->getInput());
+ }
+
+ xine_post_wire( xine_get_audio_source(m_xineStream), activeList.at(0)->getInput());
+ }
+#endif
+
+ if (!xine_play(m_xineStream, 0,0))
+ {
+ sendXineError();
+ return false;
+ }
+
+ m_currentSpeed = Normal;
+ m_trackHasChapters = false;
+ m_trackArtist = QString::null;
+ m_trackAlbum = QString::null;
+ m_trackNumber = QString::null;
+ m_trackYear = QString::null;
+ m_trackComment = QString::null;
+
+ m_trackIsSeekable = false;
+
+ if ( !dvbHaveVideo ) m_trackHasVideo = false;
+ else m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
+ if (m_trackHasVideo)
+ {
+ m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
+ m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
+ m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
+ m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
+ }
+ else
+ {
+ m_trackVideoCodec = QString::null;
+ m_videoFrameWidth = 0;
+ m_videoFrameHeight = 0;
+ m_trackVideoBitrate = 0;
+ }
+
+ m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
+ if (m_trackHasAudio)
+ {
+ m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
+ m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
+ }
+ else
+ {
+ m_trackAudioCodec = QString::null;
+ m_trackAudioBitrate = 0;
+ }
+
+ m_trackLength = getLengthInfo();
+
+ slotSetAudioChannel(0); //refresh channel info
+ m_posTimer.start(1000);
+
+ emit signalXinePlaying();
+ emit signalXineStatus(i18n("Playing"));
+
+ return true;
+}
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+#define rgb2yuv(R,G,B) ((((((66*R+129*G+25*B+128)>>8)+16)<<8)|(((112*R-94*G-18*B+128)>>8)+128))<<8|(((-38*R-74*G+112*B+128)>>8)+128))
+#else
+#define rgb2yuv(R,G,B) (((((((-38*R-74*G+112*B+128)>>8)+128)<<8)|(((112*R-94*G-18*B+128)>>8)+128))<<8|(((66*R+129*G+25*B+128)>>8)+16))<<8)
+#endif
+
+void KXineWidget::initDvbPalette()
+{
+ if ( dvbColor[0] ) return;
+
+ memset( dvbColor, 0, sizeof(dvbColor) );
+ memset( dvbTrans, 0, sizeof(dvbTrans) );
+ dvbColor[0]=1;
+
+ unsigned int blueText[11] = {
+ rgb2yuv(0,0,0), /* 0 : not used */
+ rgb2yuv(0,0,0), /* 1 : font bg */
+ rgb2yuv(10,50,40), /* 2 : transition bg->border */
+ rgb2yuv(30,100,85), /* 3 */
+ rgb2yuv(50,150,130), /* 4 */
+ rgb2yuv(70,200,175), /* 5 */
+ rgb2yuv(90,255,220), /* 6 : border */
+ rgb2yuv(90,255,220), /* 7 : transition border->fg */
+ rgb2yuv(90,255,220), /* 8 */
+ rgb2yuv(90,255,220), /* 9 */
+ rgb2yuv(90,255,220), /* 10 : font fg */
+ };
+ unsigned int whiteText[11] = {
+ rgb2yuv(0,0,0),
+ rgb2yuv(0,0,0),
+ rgb2yuv(50,50,50),
+ rgb2yuv(100,100,100),
+ rgb2yuv(150,150,150),
+ rgb2yuv(200,200,200),
+ rgb2yuv(255,255,255),
+ rgb2yuv(255,255,255),
+ rgb2yuv(255,255,255),
+ rgb2yuv(255,255,255),
+ rgb2yuv(255,255,255),
+ };
+ unsigned int greenText[11] = {
+ rgb2yuv(0,0,0),
+ rgb2yuv(0,0,0),
+ rgb2yuv(30,50,30),
+ rgb2yuv(60,100,30),
+ rgb2yuv(90,150,90),
+ rgb2yuv(120,200,120),
+ rgb2yuv(150,255,150),
+ rgb2yuv(150,255,150),
+ rgb2yuv(150,255,150),
+ rgb2yuv(150,255,150),
+ rgb2yuv(150,255,150),
+ };
+ unsigned char textAlpha[11] = { 0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, };
+#define DVB_TEXT_WHITE 100
+#define DVB_TEXT_BLUE 111
+#define DVB_TEXT_GREEN 122
+ int a;
+ for ( a=DVB_TEXT_BLUE; a<DVB_TEXT_BLUE+11; a++ )
+ {
+ dvbColor[a]=blueText[a-DVB_TEXT_BLUE];
+ dvbTrans[a]=textAlpha[a-DVB_TEXT_BLUE];
+ }
+ for ( a=DVB_TEXT_GREEN; a<DVB_TEXT_GREEN+11; a++ )
+ {
+ dvbColor[a]=greenText[a-DVB_TEXT_GREEN];
+ dvbTrans[a]=textAlpha[a-DVB_TEXT_GREEN];
+ }
+ for ( a=DVB_TEXT_WHITE; a<DVB_TEXT_WHITE+11; a++ )
+ {
+ dvbColor[a]=whiteText[a-DVB_TEXT_WHITE];
+ dvbTrans[a]=textAlpha[a-DVB_TEXT_WHITE];
+ }
+#define DVB_COLOR_RED 200
+ dvbColor[DVB_COLOR_RED] = rgb2yuv(255,0,0); dvbTrans[DVB_COLOR_RED] = 15;
+#define DVB_COLOR_GREEN 201
+ dvbColor[DVB_COLOR_GREEN] = rgb2yuv(0,255,0); dvbTrans[DVB_COLOR_GREEN] = 15;
+#define DVB_COLOR_MAGENTA 202
+ dvbColor[DVB_COLOR_MAGENTA] = rgb2yuv(255,128,255); dvbTrans[DVB_COLOR_MAGENTA] = 15;
+#define DVB_COLOR_BAR 203
+ dvbColor[DVB_COLOR_BAR] = rgb2yuv(255,128,0); dvbTrans[DVB_COLOR_BAR] = 8;
+}
+
+void getOSDLine( xine_osd_t *osd, int w, QCString &dest, QCString &source )
+{
+ int prevPos, pos, tw, th;
+ bool wrap=false;
+
+ pos = source.find(" ");
+ if ( pos==-1 ) {
+ dest = source;
+ source = "";
+ return;
+ }
+ prevPos = pos;
+ dest = source.left( pos );
+ while ( !wrap ) {
+ xine_osd_get_text_size( osd, dest, &tw, &th );
+ if ( tw>w ) {
+ wrap = true;
+ break;
+ }
+ if ( pos==-1 )
+ break;
+ prevPos = pos;
+ pos = source.find(" ",pos+1);
+ dest = source.left( pos );
+ }
+ if ( wrap ) {
+ dest = source.left( prevPos );
+ source = source.right( source.length()-dest.length()-1 );
+ }
+ else {
+ dest = source;
+ source = "";
+ }
+}
+
+void KXineWidget::dvbShowOSD()
+{
+ if ( m_trackURL!="DVB" )
+ return;
+
+ if ( xine_get_status(m_xineStream)!=XINE_STATUS_PLAY )
+ return;
+
+ if ( !dvbHaveVideo )
+ m_trackHasVideo = false;
+ else
+ m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
+
+ if (m_trackHasVideo) {
+ m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
+ m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
+ m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
+ m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
+ }
+ else {
+ m_trackVideoCodec = QString::null;
+ m_videoFrameWidth = 0;
+ m_videoFrameHeight = 0;
+ m_trackVideoBitrate = 0;
+ }
+
+ m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
+ if (m_trackHasAudio) {
+ m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
+ m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
+ }
+ else {
+ m_trackAudioCodec = QString::null;
+ m_trackAudioBitrate = 0;
+ }
+
+ if ( dvbOSD ) {
+ xine_osd_free( dvbOSD );
+ dvbOSD = 0;
+ }
+
+ int border=40;
+ int w = m_videoFrameWidth;
+ int h = m_videoFrameHeight;
+ if ( !w || !h )
+ return;
+ if ( w<800 ) {
+ if ( dvbCurrentNext[0]=="E" ) {
+ dvbOSDHideTimer.stop();
+ dvbOSD = xine_osd_new( m_xineStream, border, border, w-(2*border), h-(2/border) );
+ }
+ else
+ dvbOSD = xine_osd_new( m_xineStream, border, h-border-100, w-(2*border), 100 );
+ }
+ if ( dvbOSD ) {
+ QCString ct, cs;
+ if ( !dvbColor[0] ) initDvbPalette();
+ xine_osd_set_palette( dvbOSD, dvbColor, dvbTrans );
+ xine_osd_set_font( dvbOSD, m_osdFont, 16 );
+ xine_osd_set_encoding( dvbOSD, "utf-8" );
+ if ( dvbCurrentNext[0]=="E" )
+ xine_osd_draw_rect( dvbOSD, 0, 0, w-(2*border), h-(2*border), DVB_TEXT_WHITE+1, 1 );
+ else
+ xine_osd_draw_rect( dvbOSD, 0, 0, w-(2*border), 100, DVB_TEXT_WHITE+1, 1 );
+ QString t = QTime::currentTime().toString( "hh:mm" );
+ int tw, th, len;
+ xine_osd_get_text_size(dvbOSD, t.utf8(), &tw, &th);
+ len = tw;
+ int offset = 5;
+ xine_osd_draw_text( dvbOSD, w-(2*border)-tw-offset, 5, t.utf8(), DVB_TEXT_BLUE );
+ int i;
+ for ( i=0; i<(int)dvbCurrentNext.count(); i++ ) {
+ if ( dvbCurrentNext[i]=="R" ) {
+ xine_osd_draw_rect( dvbOSD, offset, 5, offset+16, 21, DVB_COLOR_RED, 1 );
+ offset+=21;
+ }
+ else if ( dvbCurrentNext[i]=="T" ) {
+ xine_osd_draw_rect( dvbOSD, offset, 5, offset+16, 21, DVB_COLOR_GREEN, 1 );
+ offset+=21;
+ }
+ }
+ if (m_dvbChannelName == "")
+ t = m_trackTitle;
+ else
+ t = m_dvbChannelName;
+
+ i=0;
+ ct = t.utf8();
+ while ( i<(int)t.length() ) {
+ xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
+ if ( tw<=(w-(2*border)-offset-5-len) ) break;
+ ct = ct.remove( ct.length()-1, ct.length() );
+ i++;
+ }
+ xine_osd_draw_text( dvbOSD, offset, 5, ct, DVB_TEXT_BLUE );
+ xine_osd_draw_line( dvbOSD, 5, 10+18, w-(2*border)-5, 10+18, DVB_COLOR_MAGENTA );
+
+ QString s, c;
+ int y=43;
+ int pos;
+ if ( dvbCurrentNext[0]=="E" ) {
+ if ( dvbCurrentNext.count()<2 ) {
+ xine_osd_show( dvbOSD, 0 );
+ return;
+ }
+ if ( !dvbCurrentNext[1].isEmpty() ) {
+ s = dvbCurrentNext[1];
+ pos = s.find("-");
+ c = s.left( pos+1 );
+ s = s.right( s.length()-pos-1 );
+ t = s;
+ xine_osd_draw_text( dvbOSD, 10, y, c.utf8(), DVB_TEXT_GREEN );
+ xine_osd_get_text_size( dvbOSD, c.utf8(), &offset, &th );
+ i=0;
+ cs = s.utf8();
+ while ( i<(int)t.length() ) {
+ ct = cs.remove( cs.length()-i, cs.length() );
+ xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
+ if ( tw<=(w-(2*border)-20-offset) ) break;
+ i++;
+ }
+ xine_osd_draw_text( dvbOSD, 10+offset, y, ct, DVB_TEXT_WHITE );
+ y+= 40;
+ }
+ if ( !dvbCurrentNext[2].isEmpty() ) {
+ cs = dvbCurrentNext[2].utf8();
+ while ( y<(h-(2*border)-23) ) {
+ getOSDLine( dvbOSD, (w-(2*border)-20), ct, cs );
+ xine_osd_draw_text( dvbOSD, 10, y, ct, DVB_TEXT_BLUE );
+ y+= 28;
+ if ( !cs.length() )
+ break;
+ }
+ y+= 40;
+ }
+ if ( !dvbCurrentNext[3].isEmpty() ) {
+ cs = dvbCurrentNext[3].utf8();
+ while ( y<(h-(2*border)-23) ) {
+ getOSDLine( dvbOSD, (w-(2*border)-20), ct, cs );
+ xine_osd_draw_text( dvbOSD, 10, y, ct, DVB_TEXT_WHITE );
+ y+= 28;
+ if ( !cs.length() )
+ break;
+ }
+ }
+ xine_osd_show( dvbOSD, 0 );
+ return;
+ }
+ int bar=-1;
+ int barOffset=0;
+ for ( int j=0; j<(int)dvbCurrentNext.count(); j++ ) {
+ if ( (dvbCurrentNext[ j ]=="T") || (dvbCurrentNext[ j ]=="R") ) continue;
+ if ( dvbCurrentNext[ j ].startsWith("BAR") ) {
+ s = dvbCurrentNext[ j ];
+ s = s.remove("BAR");
+ bar = s.toInt();
+ //fprintf( stderr, "BAR : %d\n", bar );
+ continue;
+ }
+ s = dvbCurrentNext[ j ];
+ pos = s.find("-");
+ c = s.left( pos+1 );
+ s = s.right( s.length()-pos-1 );
+ ct = cs = s.utf8();
+ xine_osd_draw_text( dvbOSD, 10, y, c.utf8(), DVB_TEXT_GREEN );
+ xine_osd_get_text_size( dvbOSD, c.utf8(), &offset, &th );
+ i=0;
+ while ( i<(int)t.length() ) {
+ ct = cs.remove( cs.length()-i, cs.length() );
+ xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
+ if ( tw<=(w-(2*border)-20-offset-35) ) break;
+ i++;
+ }
+ if ( !barOffset )
+ barOffset = tw;
+ xine_osd_draw_text( dvbOSD, 10+offset, y, ct, DVB_TEXT_WHITE );
+ y+= 28;
+ if ( bar>-1 ) {
+ int x1=10+offset+barOffset+10;
+ int x2=w-(2*border)-5;
+ if ( (x1+30)>x2 )
+ x1 = x2 - 30;
+ int x3=x1+((bar*(x2-x1))/100);
+ //fprintf( stderr, "x1=%d - x2=%d - x3=%d\n", x1, x2, x3 );
+ int y1=46;
+ int y2=60;
+ xine_osd_draw_line( dvbOSD, x1, y1, x2, y1, DVB_COLOR_BAR );
+ xine_osd_draw_line( dvbOSD, x1, y2, x2, y2, DVB_COLOR_BAR );
+ xine_osd_draw_line( dvbOSD, x1, y1, x1, y2, DVB_COLOR_BAR );
+ xine_osd_draw_line( dvbOSD, x2, y1, x2, y2, DVB_COLOR_BAR );
+ xine_osd_draw_rect( dvbOSD, x1, y1, x3, y2, DVB_COLOR_BAR, 1 );
+ }
+ }
+ xine_osd_show( dvbOSD, 0 );
+ dvbOSDHideTimer.start( 5000, true );
+ }
+}
+
+void KXineWidget::dvbHideOSD()
+{
+ if ( dvbOSD ) {
+ xine_osd_hide( dvbOSD, 0 );
+ xine_osd_free( dvbOSD );
+ dvbOSD = 0;
+
+ if (m_dvbChannelName != "")
+ m_dvbChannelName = "";
+
+ emit signalDvbOSDHidden();
+ }
+}
+
+void KXineWidget::setDvbCurrentNext( const QString &channelName, const QStringList &list )
+{
+ if ( list[0]=="STOP" ) {
+ dvbHideOSD();
+ return;
+ }
+ dvbCurrentNext = list;
+
+ m_dvbChannelName = channelName;
+
+ QTimer::singleShot( 0, this, SLOT(dvbShowOSD()) );
+}
+
+void KXineWidget::setDvb( const QString &pipeName, const QString &chanName, int haveVideo )
+{
+ m_trackURL = pipeName;
+ m_trackTitle = chanName;
+ dvbHaveVideo = haveVideo;
+}
+
+bool KXineWidget::openDvb()
+{
+ if ( dvbOSD ) {
+ dvbOSDHideTimer.stop();
+ xine_osd_hide( dvbOSD, 0 );
+ xine_osd_free( dvbOSD );
+ dvbOSD = 0;
+ }
+
+ clearQueue();
+ m_lengthInfoTimer.stop();
+ m_posTimer.stop();
+ xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 180000);
+ if (!xine_open(m_xineStream, QFile::encodeName(m_trackURL))) {
+ sendXineError();
+ return false;
+ }
+ else fprintf(stderr,"xine pipe opened %s\n", m_trackURL.ascii());
+ m_trackURL = "DVB";
+ emit signalXineStatus(i18n("DVB: opening..."));
+ QTimer::singleShot( 0, this, SLOT(playDvb()) );
+
+ return true;
+}
+
+void KXineWidget::slotPlayTimeShift()
+{
+ m_lengthInfoTimer.stop();
+ m_posTimer.stop();
+ xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 0);
+ if (!xine_open(m_xineStream, QFile::encodeName(TimeShiftFilename))) {
+ sendXineError();
+#ifdef XINE_PARAM_GAPLESS_SWITCH
+ if ( xine_check_version(1,1,1) )
+ xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 0);
+#endif
+ return;
+ }
+ if (!xine_play(m_xineStream, 0,0)) {
+ sendXineError();
+ return;
+ }
+ m_trackIsSeekable = true;
+ m_lengthInfoTimer.start(1000);
+ m_posTimer.start(1000);
+}
+
+bool KXineWidget::unhandledStreamsPresent()
+{
+ unsigned int hasAudio = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
+ unsigned int hasVideo = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
+
+ return (hasAudio && !xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_HANDLED)) ||
+ (hasVideo && !xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HANDLED));
+}
+
+void KXineWidget::slotPlay()
+{
+ if ((!isXineReady()) || (isQueueEmpty()))
+ return;
+
+ if (m_logoFile != NULL && m_trackURL == m_logoFile && isPlaying())
+ return;
+
+ /* dvb */
+ if ( dvbOSD ) {
+ dvbOSDHideTimer.stop();
+ xine_osd_hide( dvbOSD, 0 );
+ xine_osd_free( dvbOSD );
+ dvbOSD = 0;
+ }
+
+ m_lengthInfoTimer.stop();
+ m_posTimer.stop();
+ m_currentSpeed = Normal;
+
+ setCursor(QCursor(Qt::WaitCursor));
+
+ m_trackURL = m_queue.first();
+ m_queue.remove(m_queue.find(m_trackURL));
+
+ if (m_trackURL != m_logoFile)
+ emit signalXineStatus(i18n("Opening..."));
+
+ /* check for external subtitle file or save url */
+ m_trackSubtitleURL = QString::null;
+ m_trackSaveURL = QString::null;
+
+ /*for (int i = 1; i <= m_trackURL.contains('#'); i++) {
+ ref = m_trackURL.section('#', i, i);
+ if (ref.section(':', 0, 0) == "subtitle")
+ m_trackSubtitleURL = ref.section(':', 1);
+ if (ref.section(':', 0, 0) == "save")
+ m_trackSaveURL = ref.section(':', 1);
+ }*/
+
+ QString turl;
+ int pos;
+
+ if ( (pos=m_trackURL.find("#subtitle:"))>-1 ) {
+ turl = m_trackURL.left(pos);
+ m_trackSubtitleURL = m_trackURL.right( m_trackURL.length()-pos );
+ if ( (pos=m_trackSubtitleURL.find("#save:"))>-1 ) {
+ m_trackSaveURL = m_trackSubtitleURL.right( m_trackSubtitleURL.length()-pos );
+ m_trackSubtitleURL = m_trackSubtitleURL.left(pos);
+ }
+ }
+ else if ( (pos=m_trackURL.find("#save:"))>-1 ) {
+ turl = m_trackURL.left(pos);
+ m_trackSaveURL = m_trackURL.right( m_trackURL.length()-pos );
+ }
+ else turl = m_trackURL;
+
+ m_trackSubtitleURL.remove("#subtitle:");
+ m_trackSaveURL.remove("#save:");
+
+ turl = turl.replace( "%", "%25" ).replace( "#", "%23" ).replace( ";", "%3b" ).replace( " ", "%20" );
+ if ( !m_trackSubtitleURL.isEmpty() )
+ turl = turl + "#subtitle:" + m_trackSubtitleURL.replace( "%", "%25" ).replace( "#", "%23" ).replace( ";", "%3b" ).replace( " ", "%20" );
+ if ( !m_trackSaveURL.isEmpty() )
+ turl = turl + "#save:" + m_trackSaveURL.replace( "%", "%25" ).replace( "#", "%23" ).replace( ";", "%3b" ).replace( " ", "%20" );
+ if ( turl.startsWith("/") )
+ turl.prepend("file://");
+
+ debugOut(QString("Playing: %1").arg(turl.local8Bit()));
+
+ xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 12000 );
+ if (!xine_open(m_xineStream, QFile::encodeName(turl))) {
+
+ sendXineError();
+ setCursor(QCursor(Qt::ArrowCursor));
+#ifdef XINE_PARAM_GAPLESS_SWITCH
+ if ( xine_check_version(1,1,1) )
+ xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 0);
+#endif
+ return;
+ }
+
+ if (unhandledStreamsPresent())
+ {
+ errorOut("No codecs to handle media");
+ sendXineError();
+ return;
+ }
+
+ /**** use visualization ? ****/
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+ wireAudioFilters();
+#else
+ if ((xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO)) &&
+ (!xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)))
+ {
+ if (m_visualPluginName && (!m_xinePost))
+ {
+ debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
+ m_xinePost = xine_post_init(m_xineEngine, m_visualPluginName, 0,
+ &m_audioDriver,
+ &m_videoDriver);
+
+ m_postAudioSource = xine_get_audio_source(m_xineStream);
+ m_postInput = (xine_post_in_t*)xine_post_input (m_xinePost, const_cast<char*>("audio in"));
+ xine_post_wire(m_postAudioSource, m_postInput);
+ }
+ }
+ else
+ {
+ if (m_xinePost)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
+ m_postAudioSource = xine_get_audio_source(m_xineStream);
+ xine_post_wire_audio_port(m_postAudioSource, m_audioDriver);
+ xine_post_dispose(m_xineEngine, m_xinePost);
+ m_xinePost = NULL;
+ }
+ }
+#endif
+
+ /*** play ***/
+ int savedPos = m_savedPos;
+ m_savedPos = 0;
+ if (!xine_play(m_xineStream, savedPos, 0))
+ {
+ sendXineError();
+ setCursor(QCursor(Qt::ArrowCursor));
+ return;
+ }
+
+ /* do the stream have chapters ? */
+ m_trackHasChapters = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_CHAPTERS);
+
+ /** information requirement **/
+
+ m_trackTitle = QString::null;
+
+ bool currentUtf8Locale;
+ QTextCodec* testUtf8Local = QTextCodec::codecForLocale();
+ if (!strcmp(testUtf8Local->name(),"UTF-8"))
+ currentUtf8Locale = true;
+ else
+ currentUtf8Locale = false;
+
+ QTextCodec *CodecUtf8;
+ CodecUtf8 = QTextCodec::codecForName("UTF-8");
+
+ QString infotag;
+ infotag = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_TITLE));
+
+ if (currentUtf8Locale)
+ m_trackTitle = infotag;
+ else
+ m_trackTitle = QString::fromLocal8Bit(infotag.ascii());
+
+ if (CodecUtf8->heuristicContentMatch(infotag.ascii(), infotag.length()) >= 0)
+ m_trackTitle = QString::fromUtf8(infotag.ascii());
+
+ if ((!m_trackTitle.isNull()) && (!m_trackTitle.isEmpty())) /* no meta? */
+ {
+ QString trackArtist=NULL;
+ QString trackAlbum=NULL;
+ QString trackComment=NULL;
+ trackArtist = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ARTIST));
+ trackAlbum = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ALBUM));
+ trackComment = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_COMMENT));
+ if (currentUtf8Locale)
+ {
+ m_trackArtist = trackArtist;
+ m_trackAlbum = trackAlbum;
+ m_trackComment = trackComment;
+ }
+ else
+ {
+ m_trackArtist = QString::fromLocal8Bit(trackArtist.ascii());
+ m_trackAlbum = QString::fromLocal8Bit(trackAlbum.ascii());
+ m_trackComment = QString::fromLocal8Bit(trackComment.ascii());
+ }
+ if (CodecUtf8->heuristicContentMatch(trackArtist.ascii(), trackArtist.length()) >= 0)
+ m_trackArtist = QString::fromUtf8(trackArtist.ascii());
+ if (CodecUtf8->heuristicContentMatch(trackAlbum.ascii(), trackAlbum.length()) >= 0)
+ m_trackAlbum = QString::fromUtf8(trackAlbum.ascii());
+ if (CodecUtf8->heuristicContentMatch(trackComment.ascii(), trackComment.length()) >= 0)
+ m_trackComment = QString::fromUtf8(trackComment.ascii());
+
+ m_trackYear = xine_get_meta_info(m_xineStream, XINE_META_INFO_YEAR);
+ m_trackNumber = xine_get_meta_info(m_xineStream, XINE_META_INFO_TRACK_NUMBER);
+ }
+ else
+ {
+ m_trackArtist = QString::null;
+ m_trackAlbum = QString::null;
+ m_trackNumber = QString::null;
+ m_trackYear = QString::null;
+ m_trackComment = QString::null;
+ }
+
+ m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
+ if (m_trackHasVideo)
+ {
+ m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
+ m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
+ m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
+ m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
+ }
+ else
+ {
+ m_trackVideoCodec = QString::null;
+ m_videoFrameWidth = 0;
+ m_videoFrameHeight = 0;
+ m_trackVideoBitrate = 0;
+ }
+
+ m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
+ if (m_trackHasAudio)
+ {
+ m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
+ m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
+ }
+ else
+ {
+ m_trackAudioCodec = QString::null;
+ m_trackAudioBitrate = 0;
+ }
+
+ /*** we need a little delay for some meta info ***/
+ QTimer::singleShot(1000, this, SLOT(slotGetInfoDelayed()));
+
+
+ m_trackLength = getLengthInfo();
+ if ((m_trackLength.isNull()) && (m_trackURL != m_logoFile))
+ {
+ debugOut("Wait for valid length information");
+ m_lengthInfoTries = 0;
+ m_lengthInfoTimer.start(1000); /* wait for available track length info */
+ }
+
+ if (m_trackTitle.isNull() || m_trackTitle.isEmpty())
+ {
+ /* no meta info */
+ m_trackTitle = m_trackURL;
+ }
+
+ slotSetAudioChannel(0); //refresh channel info
+ if (m_trackURL != m_logoFile)
+ m_posTimer.start(200);
+ setCursor(QCursor(Qt::ArrowCursor));
+
+ if (m_trackURL != m_logoFile)
+ {
+ emit signalXinePlaying();
+ if (hasSaveURL())
+ emit signalXineStatus(i18n("Recording"));
+ else
+ emit signalXineStatus(i18n("Playing"));
+ }
+}
+
+int KXineWidget::getVideoWidth()
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
+}
+
+int KXineWidget::getVideoHeight()
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
+}
+
+void KXineWidget::slotGetInfoDelayed()
+{
+ if (!m_xineStream)
+ return;
+
+ if (m_trackHasVideo)
+ m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
+ if (m_trackHasAudio)
+ m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
+}
+
+
+/****** error processing ****/
+
+void KXineWidget::sendXineError()
+{
+ QString error;
+ int errCode = xine_get_error(m_xineStream);
+
+ QString addInfo;
+ QString audioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
+ QString videoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
+ if ((!audioCodec.isEmpty()) || (!videoCodec.isEmpty()))
+ {
+ if (!audioCodec.isEmpty())
+ addInfo.append(QString("(") + i18n("Audio Codec") + ": " + audioCodec + ")");
+ if (!videoCodec.isEmpty())
+ addInfo.append(QString("(") + i18n("Video Codec") + ": " + videoCodec + ")");
+ }
+ else
+ addInfo.append(QString("(") + m_trackURL + ")");
+
+ switch (errCode)
+ {
+ case XINE_ERROR_NO_INPUT_PLUGIN:
+ case XINE_ERROR_NO_DEMUX_PLUGIN:
+ {
+ if (m_trackURL.startsWith("dvd:/"))
+ {
+ if (KaffeinePart::installDistroCodec(this, "xine-engine", "dvdcss"))
+ return;
+ }
+ else
+ {
+ if (KaffeinePart::installDistroCodec(this, "xine-engine", "ffmpeg"))
+ return;
+ }
+
+ error = i18n("No plugin found to handle this resource") + " " + addInfo;
+ break;
+ }
+ case XINE_ERROR_DEMUX_FAILED:
+ {
+ error = i18n("Resource seems to be broken") + " (" + m_trackURL + ")";
+ break;
+ }
+ case XINE_ERROR_MALFORMED_MRL:
+ {
+ error = i18n("Requested resource does not exist") + " (" + m_trackURL + ")";
+ break;
+ }
+ case XINE_ERROR_INPUT_FAILED:
+ {
+ error = i18n("Resource can not be opened") + " (" + m_trackURL + ")";
+ break;
+ }
+ default:
+ {
+ if (unhandledStreamsPresent() && KaffeinePart::installDistroCodec(this, "xine-engine", "ffmpeg"))
+ return;
+
+ error = i18n("Generic error") + " (" + m_trackURL + ")";
+ break;
+ }
+ }
+
+ if (isQueueEmpty())
+ {
+ if (m_trackURL != m_logoFile)
+ {
+ emit signalXineStatus(i18n("Error"));
+ emit signalXineError(error);
+ }
+ else
+ errorOut("Can't find/play logo file!");
+ }
+ else
+ {
+ errorOut(error);
+ errorOut(QString("Can't play: %1 - trying next").arg(m_trackURL));
+ QTimer::singleShot(0, this, SLOT(slotPlay()));
+ }
+}
+
+bool KXineWidget::isPlaying() const
+{
+ if (isXineReady())
+ return ((xine_get_status(m_xineStream) == XINE_STATUS_PLAY) && (m_trackURL != m_logoFile));
+ else
+ return false;
+}
+
+QString KXineWidget::getXineLog() const
+{
+ QString logStr;
+ int i = 0;
+ QTextStream ts(&logStr, IO_WriteOnly);
+
+ const char* const* log = xine_get_log(m_xineEngine, /* XINE_LOG_MSG*/ 0);
+ if (log == NULL)
+ return QString();
+
+ while(log[i])
+ {
+ ts << QString::fromLocal8Bit(log[i]);
+ i++;
+ }
+
+ return logStr;
+}
+
+void KXineWidget::showOSDMessage(const QString& message, uint duration, int priority)
+{
+ if ((!m_osd) || (!m_osdShow) || (isHidden()))
+ return;
+
+ static int prevOsdPriority = 0;
+ if (m_osdTimer.isActive() && prevOsdPriority > priority)
+ return;
+ prevOsdPriority = priority;
+
+ //debugOut(QString("OSD: draw text: %1").arg(message));
+ xine_osd_clear(m_osd);
+ xine_osd_draw_text(m_osd, 0, 0, message.local8Bit(), XINE_OSD_TEXT1);
+
+ if (m_osdUnscaled)
+ xine_osd_show_unscaled(m_osd, 0);
+ else
+ xine_osd_show(m_osd, 0);
+
+ m_osdTimer.start(duration);
+}
+
+void KXineWidget::slotOSDHide()
+{
+ xine_osd_hide(m_osd, 0);
+ m_osdTimer.stop();
+}
+
+#ifndef USE_QT_ONLY
+/****************** postprocessing filter management ****************/
+
+QStringList KXineWidget::getVideoFilterNames() const
+{
+ QStringList filters;
+ const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_VIDEO_FILTER);
+
+ for (int i = 0; plugins[i]; i++)
+ {
+ filters << plugins[i];
+ }
+ return filters;
+}
+
+QStringList KXineWidget::getAudioFilterNames() const
+{
+ QStringList filters;
+ const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_AUDIO_FILTER);
+
+ for (int i = 0; plugins[i]; i++)
+ {
+ filters << plugins[i];
+ }
+ return filters;
+}
+#endif
+
+void KXineWidget::slotCreateVideoFilter(const QString& name, QWidget* parent)
+{
+#ifndef USE_QT_ONLY
+ unwireVideoFilters();
+
+ PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
+ connect(filter, SIGNAL(signalDeleteMe(PostFilter*)), this, SLOT(slotDeleteVideoFilter(PostFilter*)));
+ m_videoFilterList.append(filter);
+
+ wireVideoFilters();
+#else
+ parent = parent;
+ warningOut(QString("Not implemented [CreateVideoFilter %1]").arg(name));
+#endif
+}
+
+void KXineWidget::slotCreateAudioFilter(const QString& name, QWidget* parent)
+{
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+
+ PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
+ connect(filter, SIGNAL(signalDeleteMe(PostFilter*)), this, SLOT(slotDeleteAudioFilter(PostFilter*)));
+ m_audioFilterList.append(filter);
+
+ wireAudioFilters();
+#else
+ parent = parent;
+ warningOut(QString("Not implemented [CreateAudioFilter %1]").arg(name));
+#endif
+}
+
+
+void KXineWidget::slotRemoveAllVideoFilters()
+{
+#ifndef USE_QT_ONLY
+ unwireVideoFilters();
+ while (m_videoFilterList.count())
+ m_videoFilterList.removeLast();
+ wireVideoFilters();
+#else
+ warningOut("Not implemented!");
+#endif
+}
+
+void KXineWidget::slotRemoveAllAudioFilters()
+{
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+ while (m_audioFilterList.count())
+ m_audioFilterList.removeLast();
+ wireAudioFilters();
+#else
+ warningOut("Not implemented!");
+#endif
+}
+
+void KXineWidget::slotDeleteVideoFilter(PostFilter* filter)
+{
+#ifndef USE_QT_ONLY
+ unwireVideoFilters();
+ m_videoFilterList.remove(filter);
+ wireVideoFilters();
+#else
+ filter = filter;
+ warningOut("Not implemented!");
+#endif
+}
+
+void KXineWidget::slotDeleteAudioFilter(PostFilter* filter)
+{
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+ m_audioFilterList.remove(filter);
+ wireAudioFilters();
+#else
+ filter = filter;
+ warningOut("Not implemented!");
+#endif
+}
+
+#ifndef USE_QT_ONLY
+void KXineWidget::unwireVideoFilters()
+{
+ if (m_xineStream && m_videoDriver)
+ xine_post_wire_video_port(xine_get_video_source(m_xineStream), m_videoDriver);
+}
+
+void KXineWidget::wireVideoFilters()
+{
+ if (!m_xineStream)
+ {
+ debugOut("wireVideoFilters() - xine stream not initialized, nothing happend.");
+ return;
+ }
+
+ QPtrList<PostFilter> activeList;
+
+ if (m_videoFilterList.count() && m_videoFiltersEnabled)
+ activeList = m_videoFilterList;
+
+ if (m_deinterlaceFilter && m_deinterlaceEnabled )
+ activeList.insert (0, m_deinterlaceFilter);
+
+ if (activeList.count())
+ {
+ xine_post_wire_video_port(activeList.at(activeList.count()-1)->getOutput(), m_videoDriver);
+
+ for (uint i = activeList.count()-1; i >0; i--)
+ {
+ xine_post_wire(activeList.at( i-1 )->getOutput(), activeList.at(i)->getInput());
+ }
+
+ xine_post_wire( xine_get_video_source(m_xineStream), activeList.at(0)->getInput());
+ }
+}
+
+void KXineWidget::unwireAudioFilters()
+{
+ if (m_xineStream && m_audioDriver)
+ xine_post_wire_audio_port( xine_get_audio_source (m_xineStream), m_audioDriver);
+}
+
+void KXineWidget::wireAudioFilters()
+{
+ if (!m_xineStream)
+ {
+ debugOut("wireAudioFilters() - xine stream not initialized, nothing happend.");
+ return;
+ }
+
+ QPtrList<PostFilter> activeList;
+
+ if (m_audioFilterList.count() && m_audioFiltersEnabled)
+ activeList = m_audioFilterList;
+
+ if ((xine_get_stream_info (m_xineStream, XINE_STREAM_INFO_HAS_AUDIO)) &&
+ (!xine_get_stream_info (m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)) &&
+ m_visualPluginName.ascii())
+ {
+ if (!m_visualPlugin)
+ {
+ debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
+ m_visualPlugin = new PostFilter(m_visualPluginName, m_xineEngine, m_audioDriver, m_videoDriver, NULL);
+ }
+
+ activeList.insert (0, m_visualPlugin);
+ }
+ else
+ {
+ if (m_visualPlugin)
+ {
+ debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
+ delete m_visualPlugin;
+ m_visualPlugin = NULL;
+ }
+ }
+
+ if (activeList.count())
+ {
+ xine_post_wire_audio_port(activeList.at(activeList.count()-1)->getOutput(), m_audioDriver);
+
+ for (uint i = activeList.count()-1; i >0; i--)
+ {
+ xine_post_wire(activeList.at(i-1)->getOutput(), activeList.at(i)->getInput());
+ }
+
+ xine_post_wire( xine_get_audio_source(m_xineStream), activeList.at(0)->getInput());
+ }
+}
+#endif
+
+void KXineWidget::slotEnableVideoFilters(bool enable)
+{
+#ifndef USE_QT_ONLY
+ m_videoFiltersEnabled = enable;
+
+ unwireVideoFilters();
+ wireVideoFilters();
+#else
+ enable = enable;
+ warningOut("Not implemented!");
+#endif
+}
+
+void KXineWidget::slotEnableAudioFilters(bool enable)
+{
+#ifndef USE_QT_ONLY
+ m_audioFiltersEnabled = enable;
+
+ unwireAudioFilters();
+ wireAudioFilters();
+#else
+ enable = enable;
+ warningOut("Not implemented!");
+#endif
+}
+
+#ifndef USE_QT_ONLY
+QStringList KXineWidget::getAudioFilterConfig()
+{
+ QStringList configStrings;
+ for (uint i=0; i<m_audioFilterList.count(); i++)
+ configStrings << m_audioFilterList.at(i)->getConfig();
+ return configStrings;
+}
+
+QStringList KXineWidget::getVideoFilterConfig()
+{
+ QStringList configStrings;
+ for (uint i=0; i<m_videoFilterList.count(); i++)
+ configStrings << m_videoFilterList.at(i)->getConfig();
+ return configStrings;
+}
+#endif
+
+/**** visual plugin **********/
+
+QStringList KXineWidget::getVisualPlugins() const
+{
+ QStringList visuals;
+ const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_AUDIO_VISUALIZATION);
+
+ for (int i = 0; plugins[i]; i++)
+ {
+ visuals << plugins[i];
+ }
+ return visuals;
+}
+
+/**************** change visualization plugin *****************/
+
+void KXineWidget::slotSetVisualPlugin(const QString& visual)
+{
+ if (m_visualPluginName == visual) return;
+ debugOut(QString("New visualization plugin: %1").arg(visual));
+
+#ifndef USE_QT_ONLY
+ unwireAudioFilters();
+ if(m_visualPlugin)
+ {
+ delete m_visualPlugin;
+ m_visualPlugin = NULL;
+ }
+
+ if (visual == "none")
+ m_visualPluginName = QString::null;
+ else
+ m_visualPluginName = visual;
+
+ wireAudioFilters();
+#else
+ if (visual == "none")
+ m_visualPluginName = QString::null;
+ else
+ m_visualPluginName = visual;
+
+ if (m_xinePost)
+ {
+ xine_post_out_t *pp;
+
+ pp = xine_get_audio_source(m_xineStream);
+ xine_post_wire_audio_port(pp, m_audioDriver);
+ xine_post_dispose(m_xineEngine, m_xinePost);
+ m_xinePost = NULL;
+ }
+
+ if ( (xine_get_status(m_xineStream ) == XINE_STATUS_PLAY)
+ && (!xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)) && (m_visualPluginName) )
+ {
+ m_xinePost = xine_post_init(m_xineEngine, m_visualPluginName, 0, &m_audioDriver, &m_videoDriver);
+ m_postAudioSource = xine_get_audio_source(m_xineStream);
+ m_postInput = (xine_post_in_t*)xine_post_input(m_xinePost, const_cast<char*>("audio in"));
+ xine_post_wire(m_postAudioSource, m_postInput);
+ }
+#endif
+}
+
+/*****/
+
+void KXineWidget::getAutoplayPlugins(QStringList& autoPlayList) const
+{
+ char** pluginIds = NULL;
+ int i = 0;
+
+ pluginIds = (char**)xine_get_autoplay_input_plugin_ids(m_xineEngine);
+
+ while(pluginIds[i])
+ {
+ autoPlayList << pluginIds[i];
+
+ autoPlayList << xine_get_input_plugin_description(m_xineEngine, pluginIds[i]);
+ i++;
+ }
+}
+
+bool KXineWidget::getAutoplayPluginURLS(const QString& plugin, QStringList& list)
+{
+ char** urls = NULL;
+ int num;
+ int i = 0;
+
+ urls = xine_get_autoplay_mrls(m_xineEngine, plugin.ascii(), &num);
+
+ if (urls)
+ {
+ while (urls[i])
+ {
+ list << urls[i];
+ i++;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void KXineWidget::slotSetVolume(int vol)
+{
+ if (!isXineReady()) return;
+ if (m_softwareMixer)
+ {
+ //debugOut(QString("Set software amplification level: %1").arg(vol));
+ if (m_volumeGain)
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, vol*2);
+ else
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, vol);
+ }
+ else
+ {
+ //debugOut(QString("Set audio mixer volume: %1").arg(vol));
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_VOLUME, vol);
+ }
+ emit signalXineStatus(i18n("Volume") + ": " + QString::number(vol) +"%");
+}
+
+uint KXineWidget::getVolume() const
+{
+ if (!isXineReady()) return 0;
+ uint vol;
+ if (m_softwareMixer)
+ {
+ vol = xine_get_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL);
+ if (vol > 200)
+ {
+ // when amp is high > 100, xine_get_param sometimes returns incorrect amp level
+ errorOut("Amp level returned weird results, set Amp to 100");
+ vol = 100;
+ }
+ if (m_volumeGain) vol = vol/2;
+ }
+ else
+ {
+ vol = xine_get_param(m_xineStream, XINE_PARAM_AUDIO_VOLUME);
+ }
+ return vol;
+}
+
+void KXineWidget::slotToggleMute()
+{
+ int muteParam;
+ if (m_softwareMixer)
+ muteParam = XINE_PARAM_AUDIO_AMP_MUTE;
+ else
+ muteParam = XINE_PARAM_AUDIO_MUTE;
+
+ if (xine_get_param(m_xineStream, muteParam))
+ {
+ xine_set_param(m_xineStream, muteParam, 0); /* mute off */
+ emit signalXineStatus(i18n("Mute Off"));
+ }
+ else
+ {
+ xine_set_param(m_xineStream, muteParam, 1); /* mute on */
+ emit signalXineStatus(i18n("Mute On"));
+ }
+}
+
+bool KXineWidget::SoftwareMixing() const
+{
+ if (m_softwareMixer)
+ return true;
+ else
+ return false;
+}
+
+void KXineWidget::mouseMoveEvent(QMouseEvent* mev)
+{
+ if (!m_xineReady) return;
+
+ if (cursor().shape() == Qt::BlankCursor)
+ {
+ setCursor(QCursor(Qt::ArrowCursor));
+ }
+
+ x11_rectangle_t rect;
+ xine_event_t event;
+ xine_input_data_t input;
+
+ rect.x = mev->x();
+ rect.y = mev->y();
+ rect.w = 0;
+ rect.h = 0;
+
+ xine_port_send_gui_data (m_videoDriver, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect);
+
+ event.type = XINE_EVENT_INPUT_MOUSE_MOVE;
+ event.data = &input;
+ event.data_length = sizeof(input);
+ input.button = 0;
+ input.x = rect.x;
+ input.y = rect.y;
+ xine_event_send(m_xineStream, &event);
+ mev->ignore();
+}
+
+
+void KXineWidget::mousePressEvent(QMouseEvent* mev)
+{
+ if (!m_xineReady) return;
+ int cur = cursor().shape();
+
+ if (mev->button() == Qt::MidButton)
+ {
+ emit signalMiddleClick();
+ mev->ignore();
+ return;
+ }
+
+ if (mev->button() == Qt::RightButton)
+ {
+ if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
+ {
+ emit signalRightClick(mev->globalPos());
+ mev->accept();
+ return;
+ }
+ }
+
+ if (mev->button() == Qt::LeftButton)
+ {
+ if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
+ {
+ emit signalLeftClick(mev->globalPos());
+ mev->ignore();
+ return;
+ }
+
+ x11_rectangle_t rect;
+ xine_event_t event;
+ xine_input_data_t input;
+
+ rect.x = mev->x();
+ rect.y = mev->y();
+ rect.w = 0;
+ rect.h = 0;
+
+ xine_port_send_gui_data(m_videoDriver, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect);
+
+ event.type = XINE_EVENT_INPUT_MOUSE_BUTTON;
+ event.data = &input;
+ event.data_length = sizeof(input);
+ input.button = 1;
+ input.x = rect.x;
+ input.y = rect.y;
+ xine_event_send (m_xineStream, &event);
+ mev->accept(); /* don't send event to parent */
+ }
+}
+
+void KXineWidget::mouseDoubleClickEvent(QMouseEvent* mev)
+{
+ emit signalDoubleClick();
+ mev->ignore();
+}
+
+void KXineWidget::wheelEvent(QWheelEvent* e)
+{
+ int oldVal = getPosition();
+ if (oldVal == 0) // no valid position
+ return;
+
+ float offset = log10( QABS(e->delta()) ) / 0.002;
+ int newVal = 0;
+ if (e->delta()>0)
+ newVal = oldVal - int(offset);
+ else
+ newVal = oldVal + int(offset);
+ if (newVal < 0) newVal = 0;
+ slotSeekToPosition(newVal);
+ e->accept();
+}
+
+void KXineWidget::playNextChapter() const
+{
+ xine_event_t xev;
+
+ xev.type = XINE_EVENT_INPUT_NEXT;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::playPreviousChapter() const
+{
+ xine_event_t xev;
+
+ xev.type = XINE_EVENT_INPUT_PREVIOUS;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotStop()
+{
+ m_posTimer.stop();
+ if ( m_lengthInfoTimer.isActive() ) m_lengthInfoTimer.stop();
+ //emit signalNewPosition(0, QTime());
+
+ xine_stop(m_xineStream);
+
+ emit signalXineStatus(i18n("Stop"));
+}
+
+void KXineWidget::slotSetAudiocdDevice(const QString& device)
+{
+ debugOut(QString("Set AudioCD device to %1").arg(device));
+
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.cdda_device", &config);
+ if (m_cachedCDPath.isNull())
+ m_cachedCDPath = config.str_value;
+ config.str_value = QFile::encodeName(device).data();
+ xine_config_update_entry (m_xineEngine, &config);
+}
+
+void KXineWidget::slotSetVcdDevice(const QString& device)
+{
+ debugOut(QString("Set VCD device to %1").arg(device));
+
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.vcd_device", &config);
+ if (m_cachedVCDPath.isNull())
+ m_cachedVCDPath = config.str_value;
+ config.str_value = QFile::encodeName(device).data();
+ xine_config_update_entry (m_xineEngine, &config);
+}
+
+void KXineWidget::slotSetDvdDevice(const QString& device)
+{
+ debugOut(QString("Set DVD device to %1").arg(device));
+
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.dvd_device", &config);
+ if (m_cachedDVDPath.isNull())
+ m_cachedDVDPath = config.str_value;
+ config.str_value = QFile::encodeName(device).data();
+ xine_config_update_entry (m_xineEngine, &config);
+}
+
+QString KXineWidget::audiocdDevice() const
+{
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.cdda_device", &config);
+
+ return QFile::decodeName(config.str_value);
+}
+
+QString KXineWidget::vcdDevice() const
+{
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.vcd_device", &config);
+
+ return QFile::decodeName(config.str_value);
+}
+
+QString KXineWidget::dvdDevice() const
+{
+ xine_cfg_entry_t config;
+ xine_config_lookup_entry(m_xineEngine, "input.dvd_device", &config);
+
+ return QFile::decodeName(config.str_value);
+}
+
+uint KXineWidget::currentDVDTitleNumber() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_TITLE_NUMBER);
+}
+
+uint KXineWidget::getDVDTitleCount() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_TITLE_COUNT);
+}
+
+uint KXineWidget::currentDVDChapterNumber() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
+}
+
+uint KXineWidget::getDVDChapterCount() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT);
+}
+
+uint KXineWidget::currentDVDAngleNumber() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER);
+}
+
+uint KXineWidget::getDVDAngleCount() const
+{
+ return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_ANGLE_COUNT);
+}
+
+void KXineWidget::setStreamSaveDir(const QString& dir)
+{
+ xine_cfg_entry_t config;
+
+ if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return; /* older xine-lib */
+
+ debugOut(QString("Set misc.save_dir to: %1").arg(dir));
+ config.str_value = QFile::encodeName(dir).data();
+ xine_config_update_entry (m_xineEngine, &config);
+}
+
+const QString KXineWidget::getStreamSaveDir()
+{
+ xine_cfg_entry_t config;
+
+ if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return QString::null; /* older xine-lib */
+
+ return QFile::decodeName(config.str_value);
+}
+
+void KXineWidget::setBroadcasterPort(const uint port)
+{
+ debugOut(QString("Set broadcaster port to %1").arg(port));
+ xine_set_param(m_xineStream, XINE_PARAM_BROADCASTER_PORT, port);
+}
+
+void KXineWidget::slotSpeedPause()
+{
+ if (m_currentSpeed == Pause)
+ {
+ slotSpeedNormal();
+ }
+ else if (m_trackURL != m_logoFile) // don't pause logo
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ m_posTimer.stop();
+ if (m_currentSpeed != Undefined)
+ emit signalXineStatus(i18n("Pause"));
+ m_currentSpeed = Pause;
+ }
+}
+
+void KXineWidget::slotSpeedNormal()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+ m_posTimer.start(200);
+ m_currentSpeed = Normal;
+ emit signalXineStatus(i18n("Playing") + " ");
+}
+
+void KXineWidget::slotSpeedFaster()
+{
+ switch (m_currentSpeed)
+ {
+ case Fast1:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_4);
+ m_currentSpeed = Fast2;
+ emit signalXineStatus(i18n("Fast Forward %1").arg("x2"));
+ break;
+ }
+ case Fast2:
+ {
+ slotSpeedNormal();
+ break;
+ }
+ case Slow1:
+ {
+ slotSpeedNormal();
+ break;
+ }
+ case Slow2:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_2);
+ m_currentSpeed = Slow1;
+ emit signalXineStatus(i18n("Slow Motion %1").arg("x1"));
+ break;
+ }
+ default:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_2);
+ m_currentSpeed = Fast1;
+ emit signalXineStatus(i18n("Fast Forward %1").arg("x1"));
+ break;
+ }
+ }
+}
+
+void KXineWidget::slotSpeedSlower()
+{
+ switch (m_currentSpeed)
+ {
+ case Slow1:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_4);
+ m_currentSpeed = Slow2;
+ emit signalXineStatus(i18n("Slow Motion %1").arg("x2"));
+ break;
+ }
+ case Slow2:
+ {
+ slotSpeedNormal();
+ break;
+ }
+ case Fast1:
+ {
+ slotSpeedNormal();
+ break;
+ }
+ case Fast2:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_2);
+ m_currentSpeed = Fast1;
+ emit signalXineStatus(i18n("Fast Forward %1").arg("x1"));
+ break;
+ }
+ default:
+ {
+ xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_2);
+ m_currentSpeed = Slow1;
+ emit signalXineStatus(i18n("Slow Motion %1").arg("x1"));
+ break;
+ }
+ }
+}
+
+QString KXineWidget::getSupportedExtensions() const
+{
+ return xine_get_file_extensions(m_xineEngine);
+}
+
+void KXineWidget::slotSetAudioChannel(int ch)
+{
+ debugOut(QString("Switch to audio channel %1").arg(ch-1));
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ch-1);
+}
+
+
+void KXineWidget::slotSetSubtitleChannel(int ch)
+{
+ debugOut(QString("Switch to subtitle channel %1").arg(ch-1));
+ xine_set_param(m_xineStream, XINE_PARAM_SPU_CHANNEL, ch-1);
+}
+
+
+void KXineWidget::slotSetFileSubtitles(QString url)
+{
+ int pos;
+ int time;
+ int length;
+
+ m_queue.prepend(url);
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret == 0 )
+ {
+ debugOut("No valid stream position information");
+ return;
+ }
+
+ if (isPlaying())
+ xine_stop(m_xineStream);
+ m_posTimer.stop();
+
+ slotPlay();
+ slotSeekToPosition(pos);
+}
+
+
+
+uint KXineWidget::getPosition() const
+{
+ if (!m_xineReady) return 0;
+
+ int pos, time, length;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret == 0 )
+ {
+ debugOut("No valid stream position information");
+ return 0;
+ }
+
+ return (uint)pos;
+}
+
+QTime KXineWidget::getPlaytime() const
+{
+ if (!m_xineReady) return QTime();
+
+ int pos, time, length;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret == 0 )
+ {
+ debugOut("No valid stream position information");
+ return QTime();
+ }
+
+ return msToTime(time);
+}
+
+void KXineWidget::slotSendPosition()
+{
+ if (!m_xineReady) return;
+
+ int pos, time, length;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( ret == 0 )
+ {
+ debugOut("No valid stream position information");
+ return;
+ }
+
+ emit signalNewPosition(pos, msToTime(time));
+}
+
+void KXineWidget::slotStartSeeking()
+{
+ debugOut("Seeking started");
+ m_posTimer.stop();
+}
+
+void KXineWidget::run()
+{
+ if ( seekThreadPos )
+ xine_play(m_xineStream, seekThreadPos, 0);
+ else if ( seekThreadTime )
+ xine_play(m_xineStream, 0, seekThreadTime);
+ else
+ xine_play(m_xineStream, seekThreadPos, 0);
+
+ if ( seekThreadPause ) {
+ m_currentSpeed = Undefined;
+ slotSpeedPause();
+ }
+}
+
+void KXineWidget::slotSeekToPositionBlocking(int pos)
+{
+ while ( running() )
+ usleep( 1000 );
+ if ( pos!=seekThreadPos )
+ slotSeekToPosition(pos);
+}
+
+
+void KXineWidget::slotSeekToPosition(int pos)
+{
+ if ( running() ) {
+ return;
+ }
+
+ if ((!isXineReady()) || (!isPlaying()) || (!isSeekable()))
+ return;
+
+ seekThreadPause = false;
+ if (m_currentSpeed == Pause)
+ seekThreadPause = true;
+ seekThreadPos = pos;
+ seekThreadTime = 0;
+ start();
+}
+
+void KXineWidget::slotSeekToTime(const QTime& postime)
+{
+ if ( running() )
+ return;
+
+ if ((!isXineReady()) || (!isPlaying()) || (!isSeekable()))
+ return;
+
+ seekThreadPause = false;
+ if (m_currentSpeed == Pause)
+ seekThreadPause = true;
+ seekThreadPos = 0;
+ seekThreadTime = QTime().msecsTo(postime);
+ start();
+}
+
+void KXineWidget::slotStopSeeking()
+{
+ debugOut("Seeking stopped");
+ m_posTimer.start(200, false);
+}
+
+void KXineWidget::slotEject()
+{
+ xine_eject(m_xineStream);
+}
+
+void KXineWidget::slotEnableAutoresize(bool enable)
+{
+ m_autoresizeEnabled = enable;
+ if (!m_autoresizeEnabled)
+ {
+ m_videoFrameHeight = 0;
+ m_videoFrameWidth = 0;
+ }
+}
+
+/***************************************
+ * tvtime deinterlacer plugin *
+ ***************************************/
+
+#ifndef USE_QT_ONLY
+void KXineWidget::createDeinterlacePlugin(const QString& config, QWidget* parent)
+{
+ m_deinterlaceFilter = new PostFilter(config.section(':',0,0), m_xineEngine, m_audioDriver, m_videoDriver, parent);
+ if( !m_deinterlaceFilter->getInput() || !m_deinterlaceFilter->getOutput() )
+ {
+ delete m_deinterlaceFilter;
+ m_deinterlaceFilter = NULL;
+ }
+
+ slotSetDeinterlaceConfig(config);
+}
+
+const QString KXineWidget::getDeinterlaceConfig() const
+{
+ if (m_deinterlaceFilter)
+ return m_deinterlaceFilter->getConfig();
+
+ return DEFAULT_TVTIME_CONFIG;
+}
+#endif
+
+void KXineWidget::slotSetDeinterlaceConfig(const QString& config)
+{
+#ifndef USE_QT_ONLY
+ if (m_deinterlaceFilter)
+ m_deinterlaceFilter->setConfig(config);
+#else
+ warningOut(QString ("Not implemented [SetDeinterlaceConfig %1]").arg(config));
+#endif
+}
+
+void KXineWidget::slotToggleDeinterlace()
+{
+#ifndef USE_QT_ONLY
+ QString s;
+
+ if (m_deinterlaceFilter)
+ {
+ m_deinterlaceEnabled = !m_deinterlaceEnabled;
+ debugOut(QString("Deinterlace enabled: %1").arg(m_deinterlaceEnabled));
+ if ( m_deinterlaceEnabled ) s = i18n("Deinterlace: on");
+ else s = i18n("Deinterlace: off");
+ showOSDMessage( s, 2000 );
+ unwireVideoFilters();
+ wireVideoFilters();
+ }
+ else
+ {
+ /* fallback - this method is deprecated */
+ if (xine_get_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE))
+ xine_set_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE, false);
+ else
+ xine_set_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE, true);
+ }
+#else
+ warningOut("Not implemented!");
+#endif
+}
+
+/**************************/
+
+void KXineWidget::slotAspectRatioAuto()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_AUTO);
+ emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("Auto"));
+}
+
+void KXineWidget::slotAspectRatio4_3()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_4_3);
+ emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("4:3"));
+}
+
+void KXineWidget::slotAspectRatioAnamorphic()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_ANAMORPHIC);
+ emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("16:9"));
+}
+
+void KXineWidget::slotAspectRatioSquare()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_SQUARE);
+ emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("1:1"));
+}
+
+void KXineWidget::slotAspectRatioDVB()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_DVB);
+ emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("2.11:1"));
+}
+
+void KXineWidget::slotZoomOutX()
+{
+ if ((m_currentZoomX - 5) >= 100)
+ {
+ m_currentZoomX -= 5;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoomX);
+ emit signalXineStatus(i18n("Zoom X") + ": " + QString::number(m_currentZoomX) + "%");
+ }
+}
+
+void KXineWidget::slotZoomInX()
+{
+ if ((m_currentZoomX + 5) <= XINE_VO_ZOOM_MAX)
+ {
+ m_currentZoomX += 5;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoomX);
+ emit signalXineStatus(i18n("Zoom X") + ": " + QString::number(m_currentZoomX) + "%");
+ }
+}
+
+void KXineWidget::slotZoomOutY()
+{
+ if ((m_currentZoomY - 5) >= 100)
+ {
+ m_currentZoomY -= 5;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoomY);
+ emit signalXineStatus(i18n("Zoom Y") + ": " + QString::number(m_currentZoomY) + "%");
+ }
+}
+
+void KXineWidget::slotZoomInY()
+{
+ if ((m_currentZoomY + 5) <= XINE_VO_ZOOM_MAX)
+ {
+ m_currentZoomY += 5;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoomY);
+ emit signalXineStatus(i18n("Zoom Y") + ": " + QString::number(m_currentZoomY) + "%");
+ }
+}
+
+void KXineWidget::slotZoomOut()
+{
+ if ((m_currentZoom - 5) >= 100)
+ {
+ m_currentZoom -= 5;
+ m_currentZoomX = m_currentZoomY = m_currentZoom;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoom);
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoom);
+ emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
+ }
+}
+
+void KXineWidget::slotZoomIn()
+{
+ if ((m_currentZoom + 5) <= XINE_VO_ZOOM_MAX)
+ {
+ m_currentZoom += 5;
+ m_currentZoomX = m_currentZoomY = m_currentZoom;
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoom);
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoom);
+ emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
+ }
+}
+
+void KXineWidget::slotZoomOff()
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, 100);
+ xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, 100);
+ m_currentZoom = 100;
+ m_currentZoomX = m_currentZoomY = m_currentZoom;
+ emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
+}
+
+QTime KXineWidget::getLengthInfo()
+{
+ int pos, time, length;
+
+ int t = 0, ret = 0;
+ while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
+ xine_usec_sleep(100000);
+
+ if ( (ret != 0) && (length > 0) )
+ {
+ return msToTime(length);
+ }
+
+ return QTime();
+}
+
+void KXineWidget::slotEmitLengthInfo()
+{
+ QTime length = getLengthInfo();
+ if (!(length.isNull()))
+ {
+ if ( m_trackURL!="DVB" ) m_lengthInfoTimer.stop();
+ m_trackLength = length;
+ emit signalLengthChanged();
+ }
+ else
+ {
+ if (m_lengthInfoTries > 10) // wait 10 seconds
+ m_lengthInfoTimer.stop();
+ else
+ {
+ debugOut("Wait for valid length information");
+ m_lengthInfoTries ++;
+ }
+ }
+}
+
+void KXineWidget::globalPosChanged()
+{
+ QPoint g = mapToGlobal(QPoint(0,0));
+ m_globalX = g.x();
+ m_globalY = g.y();
+}
+
+const xine_t* const KXineWidget::getXineEngine()const
+{
+ return m_xineEngine;
+}
+
+/************ video settings ****************/
+
+void KXineWidget::getVideoSettings(int& hue, int& sat, int& contrast, int& bright,
+ int& avOffset, int& spuOffset) const
+{
+ hue = xine_get_param(m_xineStream, XINE_PARAM_VO_HUE);
+ sat = xine_get_param(m_xineStream, XINE_PARAM_VO_SATURATION);
+ contrast = xine_get_param(m_xineStream, XINE_PARAM_VO_CONTRAST);
+ bright = xine_get_param(m_xineStream, XINE_PARAM_VO_BRIGHTNESS);
+ avOffset = xine_get_param(m_xineStream, XINE_PARAM_AV_OFFSET);
+ spuOffset = xine_get_param(m_xineStream, XINE_PARAM_SPU_OFFSET);
+}
+
+void KXineWidget::getspuOffset(int& spuOffset) const
+{
+ spuOffset = xine_get_param(m_xineStream, XINE_PARAM_SPU_OFFSET);
+}
+
+void KXineWidget::slotSetHue(int hue)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_HUE, hue);
+ emit signalXineStatus(i18n("Hue") + ": " + QString::number((hue*100)/65535) + "%");
+}
+
+void KXineWidget::slotSetSaturation(int sat)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_SATURATION, sat);
+ emit signalXineStatus(i18n("Saturation") + ": " + QString::number((sat*100)/65535) + "%");
+}
+
+void KXineWidget::slotSetContrast(int contrast)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_CONTRAST, contrast);
+ emit signalXineStatus(i18n("Contrast") + ": " + QString::number((contrast*100)/65535) + "%");
+}
+
+void KXineWidget::slotSetBrightness(int bright)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_VO_BRIGHTNESS, bright);
+ emit signalXineStatus(i18n("Brightness") + ": " + QString::number((bright*100)/65535) + "%");
+}
+
+void KXineWidget::slotSetAVOffset(int av)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_AV_OFFSET, av);
+ emit signalXineStatus(i18n("Audio/Video Offset") + ": " + QString::number(av/90) + i18n("msec"));
+}
+
+void KXineWidget::slotSetSpuOffset(int spu)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_SPU_OFFSET, spu);
+ emit signalXineStatus(i18n("Subtitle Offset") + ": " + QString::number(spu/90) + i18n("msec"));
+}
+
+
+/**************** equalizer *****************/
+
+void KXineWidget::slotSetEq30(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_30HZ, -val);
+}
+
+void KXineWidget::slotSetEq60(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_60HZ, -val);
+}
+
+void KXineWidget::slotSetEq125(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_125HZ, -val);
+}
+
+void KXineWidget::slotSetEq250(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_250HZ, -val);
+}
+
+void KXineWidget::slotSetEq500(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_500HZ, -val);
+}
+
+void KXineWidget::slotSetEq1k(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_1000HZ, -val);
+}
+
+void KXineWidget::slotSetEq2k(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_2000HZ, -val);
+}
+
+void KXineWidget::slotSetEq4k(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_4000HZ, -val);
+}
+
+void KXineWidget::slotSetEq8k(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_8000HZ, -val);
+}
+
+void KXineWidget::slotSetEq16k(int val)
+{
+ xine_set_param(m_xineStream, XINE_PARAM_EQ_16000HZ, -val);
+}
+
+void KXineWidget::slotSetVolumeGain(bool gain)
+{
+ int amp = 0;
+
+ if (gain)
+ {
+ if (m_softwareMixer)
+ amp = getVolume()*2;
+ else
+ amp = 200;
+ }
+ else
+ {
+ if (m_softwareMixer)
+ amp = getVolume();
+ else
+ amp = 100;
+ }
+ xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, amp);
+
+ m_volumeGain = gain;
+}
+
+/*************** dvd menus ******************/
+
+void KXineWidget::slotMenuToggle()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU1;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuTitle()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU2;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuRoot()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU3;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuSubpicture()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU4;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuAudio()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU5;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuAngle()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU6;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotMenuPart()
+{
+ xine_event_t xev;
+ xev.type = XINE_EVENT_INPUT_MENU7;
+ xev.data = NULL;
+ xev.data_length = 0;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotDVDMenuLeft()
+{
+ xine_event_t xev;
+ xev.data = NULL;
+ xev.data_length = 0;
+ xev.type = XINE_EVENT_INPUT_LEFT;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotDVDMenuRight()
+{
+ xine_event_t xev;
+ xev.data = NULL;
+ xev.data_length = 0;
+ xev.type = XINE_EVENT_INPUT_RIGHT;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotDVDMenuUp()
+{
+ xine_event_t xev;
+ xev.data = NULL;
+ xev.data_length = 0;
+ xev.type = XINE_EVENT_INPUT_UP;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotDVDMenuDown()
+{
+ xine_event_t xev;
+ xev.data = NULL;
+ xev.data_length = 0;
+ xev.type = XINE_EVENT_INPUT_DOWN;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+void KXineWidget::slotDVDMenuSelect()
+{
+ xine_event_t xev;
+ xev.data = NULL;
+ xev.data_length = 0;
+ xev.type = XINE_EVENT_INPUT_SELECT;
+
+ xine_event_send(m_xineStream, &xev);
+}
+
+
+/******** mouse hideing at fullscreen ****/
+
+void KXineWidget::startMouseHideTimer()
+{
+ m_mouseHideTimer.start(5000);
+}
+
+void KXineWidget::stopMouseHideTimer()
+{
+ m_mouseHideTimer.stop();
+}
+
+void KXineWidget::slotHideMouse()
+{
+ if (cursor().shape() == Qt::ArrowCursor)
+ {
+ setCursor(QCursor(Qt::BlankCursor));
+ }
+}
+
+
+/************************************************************
+ * Take a Screenshot *
+ ************************************************************/
+
+QImage KXineWidget::getScreenshot() const
+{
+ uchar *rgbPile = NULL;
+ int width, height;
+ double scaleFactor;
+
+ getScreenshot(rgbPile, width, height, scaleFactor);
+
+ if (!rgbPile) return QImage();
+
+ QImage screenShot(rgbPile, width, height, 32, 0, 0, QImage::IgnoreEndian);
+ if (scaleFactor >= 1.0)
+ width = (int)((double) width * scaleFactor + 0.5);
+ else
+ height = (int)((double) height / scaleFactor + 0.5);
+
+ debugOut(QString("Screenshot: scale picture from %1x%2 to %3x%4").arg(screenShot.width()).arg(screenShot.height()).arg(width).arg(height));
+ screenShot = screenShot.smoothScale(width, height);
+
+ delete []rgbPile;
+ return screenShot;
+}
+
+void KXineWidget::getScreenshot(uchar*& rgb32BitData, int& videoWidth, int& videoHeight, double& scaleFactor) const
+{
+
+ uint8_t *yuv = NULL, *y = NULL, *u = NULL, *v =NULL;
+
+ int width, height, ratio, format;
+ // double desired_ratio, image_ratio;
+
+ if (!xine_get_current_frame(m_xineStream, &width, &height, &ratio, &format, NULL))
+ return;
+
+ yuv = new uint8_t[((width+8) * (height+1) * 2)];
+ if (yuv == NULL)
+ {
+ errorOut("Not enough memory to make screenshot!");
+ return;
+ }
+
+ xine_get_current_frame(m_xineStream, &width, &height, &ratio, &format, yuv);
+
+ videoWidth = width;
+ videoHeight = height;
+
+ /*
+ * convert to yv12 if necessary
+ */
+
+ switch (format)
+ {
+ case XINE_IMGFMT_YUY2:
+ {
+ uint8_t *yuy2 = yuv;
+
+ yuv = new uint8_t[(width * height * 2)];
+ if (yuv == NULL)
+ {
+ errorOut("Not enough memory to make screenshot!");
+ return;
+ }
+ y = yuv;
+ u = yuv + width * height;
+ v = yuv + width * height * 5 / 4;
+
+ yuy2Toyv12 (y, u, v, yuy2, width, height);
+
+ delete [] yuy2;
+ }
+ break;
+ case XINE_IMGFMT_YV12:
+ y = yuv;
+ u = yuv + width * height;
+ v = yuv + width * height * 5 / 4;
+
+ break;
+ default:
+ {
+ warningOut(QString("Screenshot: Format %1 not supportet!").arg((char*)&format));
+ delete [] yuv;
+ return;
+ }
+ }
+
+ /*
+ * convert to rgb
+ */
+
+ rgb32BitData = yv12ToRgb (y, u, v, width, height);
+
+
+ // image_ratio = (double) height / (double) width;
+
+ /*
+ switch (ratio)
+ {
+ case XINE_VO_ASPECT_ANAMORPHIC:
+ debugOut("Screenshot: got video aspect: anamorphic");
+ desired_ratio = 16.0 /9.0;
+ break;
+ case XINE_VO_ASPECT_DVB:
+ debugOut("Screenshot: got video aspect: 2.11:1");
+ desired_ratio = 2.11/1.0;
+ break;
+ case XINE_VO_ASPECT_4_3:
+ debugOut("Screenshot: got video aspect: 4:3");
+ desired_ratio = 4.0 / 3.0;
+ break;
+ default:
+ warningOut(QString("Screenshot: Unknown aspect ratio: %1 - using 4:3").arg(ratio));
+ case XINE_VO_ASPECT_SQUARE:
+ debugOut("Screenshot: got video aspect: 1:1");
+ desired_ratio = image_ratio;
+ break;
+ }
+ */
+
+ debugOut(QString("Screenshot: using scale factor: %1").arg(m_videoAspect));
+ scaleFactor = m_videoAspect;
+
+ delete [] yuv;
+}
+
+
+/************************************************
+ * HELPER FUNCTIONS *
+ ************************************************/
+
+QTime KXineWidget::msToTime(int msec)
+{
+ QTime t;
+ t = t.addMSecs(msec);
+ return t;
+}
+
+#ifdef USE_QT_ONLY
+QString KXineWidget::i18n(const char *text)
+{
+ return QApplication::tr(text);
+}
+#endif
+
+void KXineWidget::debugOut (QString qsDebug)
+{
+#ifdef USE_QT_ONLY
+ QString qsDebugging = QString ("Debug: ") + qsDebug +"\n";
+ printf ((const char *)qsDebugging);
+#else
+ kdDebug() << "KXineWidget: " << (const char *)qsDebug.ascii() << "\n";
+#endif
+}
+void KXineWidget::errorOut (QString qsError)
+{
+#ifdef USE_QT_ONLY
+ QString qsErroring = QString ("Error: ") + qsError+ "\n";
+ printf ((const char *)qsErroring);
+#else
+ kdError() << "KXineWidget: " << (const char *)qsError.ascii() << "\n";
+#endif
+}
+void KXineWidget::warningOut (QString qsWarning)
+{
+#ifdef USE_QT_ONLY
+ QString qsWarninging = QString ("Warning: ") + qsWarning + "\n";
+ printf ((const char *)qsWarninging);
+#else
+ kdWarning() << "KXineWidget: " << (const char *)qsWarning.ascii() << "\n";
+#endif
+}
+
+
+/************************************************************
+ * Helpers to convert yuy and yv12 frames to rgb *
+ * code from gxine modified for 32bit output *
+ * Copyright (C) 2000-2003 the xine project *
+ ************************************************************/
+
+void KXineWidget::yuy2Toyv12 (uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height)
+{
+
+ int i, j, w2;
+
+ w2 = width / 2;
+
+ for (i = 0; i < height; i += 2)
+ {
+ for (j = 0; j < w2; j++)
+ {
+ /*
+ * packed YUV 422 is: Y[i] U[i] Y[i+1] V[i]
+ */
+ *(y++) = *(input++);
+ *(u++) = *(input++);
+ *(y++) = *(input++);
+ *(v++) = *(input++);
+ }
+
+ /*
+ * down sampling
+ */
+
+ for (j = 0; j < w2; j++)
+ {
+ /*
+ * skip every second line for U and V
+ */
+ *(y++) = *(input++);
+ input++;
+ *(y++) = *(input++);
+ input++;
+ }
+ }
+}
+
+
+uchar* KXineWidget::yv12ToRgb (uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height)
+{
+ /*
+ * Create rgb data from yv12
+ */
+
+#define clip_8_bit(val) \
+{ \
+ if (val < 0) \
+ val = 0; \
+ else \
+ if (val > 255) val = 255; \
+}
+
+ int i, j;
+
+ int y, u, v;
+ int r, g, b;
+
+ int sub_i_uv;
+ int sub_j_uv;
+
+ int uv_width, uv_height;
+
+ uchar *rgb;
+
+ uv_width = width / 2;
+ uv_height = height / 2;
+
+ rgb = new uchar[(width * height * 4)]; //qt needs a 32bit align
+ if (!rgb)
+ {
+ // kdError(555) << "Not enough memory!" << endl;
+ return NULL;
+ }
+
+ for (i = 0; i < height; ++i)
+ {
+ /*
+ * calculate u & v rows
+ */
+ sub_i_uv = ((i * uv_height) / height);
+
+ for (j = 0; j < width; ++j)
+ {
+ /*
+ * calculate u & v columns
+ */
+ sub_j_uv = ((j * uv_width) / width);
+
+ /***************************************************
+ *
+ * Colour conversion from
+ * http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
+ *
+ * Thanks to Billy Biggs <[email protected]>
+ * for the pointer and the following conversion.
+ *
+ * R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
+ * G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
+ * B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
+ *
+ * Where in xine the above values are represented as
+ *
+ * Y' == image->y
+ * Cb == image->u
+ * Cr == image->v
+ *
+ ***************************************************/
+
+ y = src_y[(i * width) + j] - 16;
+ u = src_u[(sub_i_uv * uv_width) + sub_j_uv] - 128;
+ v = src_v[(sub_i_uv * uv_width) + sub_j_uv] - 128;
+
+ r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
+ g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
+ b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
+
+ clip_8_bit (r);
+ clip_8_bit (g);
+ clip_8_bit (b);
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ rgb[(i * width + j) * 4 + 0] = b;
+ rgb[(i * width + j) * 4 + 1] = g;
+ rgb[(i * width + j) * 4 + 2] = r;
+ rgb[(i * width + j) * 4 + 3] = 0;
+#else
+ rgb[(i * width + j) * 4 + 3] = b;
+ rgb[(i * width + j) * 4 + 2] = g;
+ rgb[(i * width + j) * 4 + 1] = r;
+ rgb[(i * width + j) * 4 + 0] = 0;
+#endif
+
+ }
+ }
+
+ return rgb;
+}