|
|
|
/*
|
|
|
|
* kxinewidget.cpp - a kde / qt api for xine-lib
|
|
|
|
*
|
|
|
|
* Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
|
|
|
|
* Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
|
|
|
|
*
|
|
|
|
* 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 <tqapplication.h>
|
|
|
|
#include <tqwidget.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqevent.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqcursor.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
|
|
|
|
#include <xine/xineutils.h>
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include "kxinewidget.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_XINERAMA
|
|
|
|
#include <X11/extensions/Xinerama.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef USE_TQT_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(TQWidget* parent, const char* name,
|
|
|
|
const TQString& pathToConfigFile, const TQString& pathToLogoFile,
|
|
|
|
const TQString& audioDriver, const TQString& videoDriver,
|
|
|
|
bool startManual, bool verbose)
|
|
|
|
: TQWidget(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_TQT_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(TQString()), 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(TQSize(20,20)); // set a size hint
|
|
|
|
setPaletteBackgroundColor(TQColor(0,0,0)); //black
|
|
|
|
|
|
|
|
/* dvb */
|
|
|
|
TimeShiftFilename = "";
|
|
|
|
dvbHaveVideo = 0;
|
|
|
|
dvbOSD = 0;
|
|
|
|
dvbColor[0] = 0;
|
|
|
|
connect( &dvbOSDHideTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(dvbHideOSD()) );
|
|
|
|
|
|
|
|
if (pathToConfigFile.isNull())
|
|
|
|
{
|
|
|
|
debugOut("Using default config file ~/.xine/config");
|
|
|
|
m_configFilePath = TQDir::homeDirPath();
|
|
|
|
m_configFilePath.append("/.xine/config");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_configFilePath = pathToConfigFile;
|
|
|
|
|
|
|
|
if (!m_logoFile.isNull())
|
|
|
|
appendToQueue(m_logoFile);
|
|
|
|
|
|
|
|
#ifndef USE_TQT_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, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSendPosition()));
|
|
|
|
connect(&m_lengthInfoTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotEmitLengthInfo()));
|
|
|
|
connect(&m_mouseHideTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotHideMouse()));
|
|
|
|
connect(&m_osdTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotOSDHide()));
|
|
|
|
connect(&m_recentMessagesTimer, TQT_SIGNAL(timeout()), this, TQT_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_TQT_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_TQT_ONLY
|
|
|
|
if (m_deinterlaceFilter)
|
|
|
|
{
|
|
|
|
debugOut("Unwire video filters");
|
|
|
|
unwireVideoFilters();
|
|
|
|
delete m_deinterlaceFilter;
|
|
|
|
m_deinterlaceFilter = NULL;
|
|
|
|
}
|
|
|
|
if (m_visualPlugin)
|
|
|
|
{
|
|
|
|
debugOut("Unwire audio filters");
|
|
|
|
unwireAudioFilters();
|
|
|
|
debugOut(TQString("Dispose visual plugin: %1").tqarg(m_visualPluginName ));
|
|
|
|
delete m_visualPlugin;
|
|
|
|
m_visualPlugin = NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (m_xinePost)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Dispose visual plugin: %1").tqarg(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(TQString("Save xine config to: %1").tqarg(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(TQString("New video frame size: %1x%2 - aspect ratio: %3").tqarg(video_width).tqarg(video_height).tqarg(video_aspect));
|
|
|
|
vw->m_videoFrameWidth = video_width;
|
|
|
|
vw->m_videoFrameHeight = video_height;
|
|
|
|
vw->m_videoAspect = video_aspect;
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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() - TQSize((vw->width() - video_width), vw->height() - video_height);
|
|
|
|
|
|
|
|
debugOut(TQString("Resize video window to: %1x%2").tqarg(vw->m_newParentSize.width()).tqarg(vw->m_newParentSize.height()));
|
|
|
|
|
|
|
|
/* we should not do a resize() inside a xine thread,
|
|
|
|
but post an event to the main thread */
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(TIMER_EVENT_RESIZE_PARENT));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XINE EVENT THREAD
|
|
|
|
* only the QT event thread should do GUI operations,
|
|
|
|
* we use TQApplication::postEvent() and a reimplementation of TQObject::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");
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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];
|
|
|
|
TQString slang;
|
|
|
|
int num;
|
|
|
|
TQStringList 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 = TQString("%1.").tqarg(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 = TQString("%1.").tqarg(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 )
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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 = TQString::fromLocal8Bit( (char*)xd->str );
|
|
|
|
|
|
|
|
vw->m_lengthInfoTries = 0;
|
|
|
|
vw->m_lengthInfoTimer.start(1000); /* May be new Length on Changing DVD/VCD titles */
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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 = TQString::fromLocal8Bit(pd->description) + " " + TQString::number(pd->percent) + "%";
|
|
|
|
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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(TQString("Skipped frames: %1 - discarded frames: %2").tqarg(dropped->skipped_frames/10).tqarg(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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;
|
|
|
|
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(TIMER_EVENT_NEW_MRL_REFERENCE));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XINE_EVENT_FRAME_FORMAT_CHANGE:
|
|
|
|
{
|
|
|
|
// debugOut("xine event: frame format change");
|
|
|
|
|
|
|
|
// TQApplication::postEvent(vw, new TQTimerEvent(TIMER_EVENT_FRAME_FORMAT_CHANGE));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XINE_EVENT_AUDIO_LEVEL:
|
|
|
|
{
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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;
|
|
|
|
TQString 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 + "(" + TQString::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) + ")";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
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:/"))
|
|
|
|
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;
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(TIMER_EVENT_NEW_XINE_MESSAGE));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
//debugOut("xine event: unhandled type ");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::timerEvent( TQTimerEvent* tevent )
|
|
|
|
{
|
|
|
|
switch ( tevent->timerId() )
|
|
|
|
{
|
|
|
|
case TIMER_EVENT_PLAYBACK_FINISHED:
|
|
|
|
{
|
|
|
|
if ( !TimeShiftFilename.isEmpty() )
|
|
|
|
{
|
|
|
|
TQTimer::singleShot(0, this, TQT_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
|
|
|
|
TQTimer::singleShot(0, this, TQT_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(TQCursor(TQt::PointingHandCursor));
|
|
|
|
else
|
|
|
|
setCursor(TQCursor(TQt::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(TQString("Message: '%1' was blocked!").tqarg(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_TQT_ONLY
|
|
|
|
KXineWidget* vw = (KXineWidget*) p;
|
|
|
|
xine_video_port_t* oldVideoDriver = vw->m_videoDriver;
|
|
|
|
xine_video_port_t* noneVideoDriver;
|
|
|
|
|
|
|
|
int pos, time, length;
|
|
|
|
|
|
|
|
debugOut(TQString("New video driver: %1").tqarg(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(TQString("Dispose visual plugin: %1").tqarg(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!").tqarg(entry->enum_values[entry->num_value]).tqarg(vw->m_videoDriverName);
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent( 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").tqarg(vw->m_videoDriverName);
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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)
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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_TQT_ONLY
|
|
|
|
KXineWidget* vw = (KXineWidget*) p;
|
|
|
|
|
|
|
|
int pos, time, length;
|
|
|
|
|
|
|
|
debugOut(TQString("New audio driver: %1").tqarg(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(TQString("Dispose visual plugin: %1").tqarg(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!").tqarg(entry->enum_values[entry->num_value]).tqarg(vw->m_audioDriverName);
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent( 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").tqarg(vw->m_audioDriverName);
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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)
|
|
|
|
TQApplication::postEvent(vw, new TQTimerEvent(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(TQPaintEvent *event)
|
|
|
|
{
|
|
|
|
if (isXineReady()) {
|
|
|
|
const TQRect &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);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQWidget::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(TQString("%1 screens detected").tqarg(count));
|
|
|
|
if (count > 1)
|
|
|
|
// multihead -> assuming square pixels
|
|
|
|
m_displayRatio = 1.0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
debugOut(TQString("Display aspect ratio (v/h): %1").tqarg(m_displayRatio));*/
|
|
|
|
|
|
|
|
/**** INIT XINE ENGINE ****/
|
|
|
|
|
|
|
|
debugOut(TQString("Using xine version %1").tqarg(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 (!TQFile::exists(m_configFilePath))
|
|
|
|
warningOut("No config file found, will create one...");
|
|
|
|
else
|
|
|
|
xine_config_load(m_xineEngine, TQFile::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(TQString("Use audio driver %1").tqarg(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(TQString("Use video driver %1").tqarg(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'...").tqarg(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'...").tqarg(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(TQString("Font ->%1<- specified for OSD doesn't exists.").tqarg(m_osdFont));
|
|
|
|
free(m_osdFont);
|
|
|
|
m_osdFont = strdup("sans");
|
|
|
|
xine_osd_set_font(m_osd, m_osdFont, fontsizetable[m_osdSize]);
|
|
|
|
}
|
|
|
|
debugOut(TQString("Font for OSD: %1").tqarg(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_TQT_ONLY
|
|
|
|
unwireAudioFilters();
|
|
|
|
|
|
|
|
TQPtrList<PostFilter> activeList;
|
|
|
|
|
|
|
|
if (m_audioFilterList.count() && m_audioFiltersEnabled)
|
|
|
|
activeList = m_audioFilterList;
|
|
|
|
|
|
|
|
if ( !dvbHaveVideo )
|
|
|
|
{
|
|
|
|
if (!m_visualPlugin)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Init visual plugin: %1").tqarg(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(TQString("Dispose visual plugin: %1").tqarg(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 = TQString();
|
|
|
|
m_trackAlbum = TQString();
|
|
|
|
m_trackNumber = TQString();
|
|
|
|
m_trackYear = TQString();
|
|
|
|
m_trackComment = TQString();
|
|
|
|
|
|
|
|
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 = TQString();
|
|
|
|
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 = TQString();
|
|
|
|
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 == TQ_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, TQCString &dest, TQCString &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 = TQString();
|
|
|
|
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 = TQString();
|
|
|
|
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<1921 ) {
|
|
|
|
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 ) {
|
|
|
|
TQCString 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 );
|
|
|
|
TQString t = TQTime::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 );
|
|
|
|
|
|
|
|
TQString 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 TQString &channelName, const TQStringList &list )
|
|
|
|
{
|
|
|
|
if ( list[0]=="STOP" ) {
|
|
|
|
dvbHideOSD();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dvbCurrentNext = list;
|
|
|
|
|
|
|
|
m_dvbChannelName = channelName;
|
|
|
|
|
|
|
|
TQTimer::singleShot( 0, this, TQT_SLOT(dvbShowOSD()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::setDvb( const TQString &pipeName, const TQString &chanName, int haveVideo )
|
|
|
|
{
|
|
|
|
m_trackURL = /*"fifo://"+*/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, TQFile::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..."));
|
|
|
|
TQTimer::singleShot( 0, this, TQT_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, TQFile::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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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(TQCursor(TQt::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 = TQString();
|
|
|
|
m_trackSaveURL = TQString();
|
|
|
|
|
|
|
|
/*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);
|
|
|
|
}*/
|
|
|
|
|
|
|
|
TQString 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(TQString("Playing: %1").tqarg(turl.local8Bit().data()));
|
|
|
|
|
|
|
|
xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 12000 );
|
|
|
|
if (!xine_open(m_xineStream, TQFile::encodeName(turl))) {
|
|
|
|
|
|
|
|
sendXineError();
|
|
|
|
setCursor(TQCursor(TQt::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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** use visualization ? ****/
|
|
|
|
#ifndef USE_TQT_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(TQString("Init visual plugin: %1").tqarg(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(TQString("Dispose visual plugin: %1").tqarg(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(TQCursor(TQt::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 = TQString();
|
|
|
|
|
|
|
|
bool currentUtf8Locale;
|
|
|
|
TQTextCodec* testUtf8Local = TQTextCodec::codecForLocale();
|
|
|
|
if (!strcmp(testUtf8Local->name(),"UTF-8"))
|
|
|
|
currentUtf8Locale = true;
|
|
|
|
else
|
|
|
|
currentUtf8Locale = false;
|
|
|
|
|
|
|
|
TQTextCodec *CodecUtf8;
|
|
|
|
CodecUtf8 = TQTextCodec::codecForName("UTF-8");
|
|
|
|
|
|
|
|
TQString infotag;
|
|
|
|
infotag = TQString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_TITLE));
|
|
|
|
|
|
|
|
if (currentUtf8Locale)
|
|
|
|
m_trackTitle = infotag;
|
|
|
|
else
|
|
|
|
m_trackTitle = TQString::fromLocal8Bit(infotag.ascii());
|
|
|
|
|
|
|
|
if (CodecUtf8->heuristicContentMatch(infotag.ascii(), infotag.length()) >= 0)
|
|
|
|
m_trackTitle = TQString::fromUtf8(infotag.ascii());
|
|
|
|
|
|
|
|
if ((!m_trackTitle.isNull()) && (!m_trackTitle.isEmpty())) /* no meta? */
|
|
|
|
{
|
|
|
|
TQString trackArtist=NULL;
|
|
|
|
TQString trackAlbum=NULL;
|
|
|
|
TQString trackComment=NULL;
|
|
|
|
trackArtist = TQString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ARTIST));
|
|
|
|
trackAlbum = TQString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ALBUM));
|
|
|
|
trackComment = TQString::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 = TQString::fromLocal8Bit(trackArtist.ascii());
|
|
|
|
m_trackAlbum = TQString::fromLocal8Bit(trackAlbum.ascii());
|
|
|
|
m_trackComment = TQString::fromLocal8Bit(trackComment.ascii());
|
|
|
|
}
|
|
|
|
if (CodecUtf8->heuristicContentMatch(trackArtist.ascii(), trackArtist.length()) >= 0)
|
|
|
|
m_trackArtist = TQString::fromUtf8(trackArtist.ascii());
|
|
|
|
if (CodecUtf8->heuristicContentMatch(trackAlbum.ascii(), trackAlbum.length()) >= 0)
|
|
|
|
m_trackAlbum = TQString::fromUtf8(trackAlbum.ascii());
|
|
|
|
if (CodecUtf8->heuristicContentMatch(trackComment.ascii(), trackComment.length()) >= 0)
|
|
|
|
m_trackComment = TQString::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 = TQString();
|
|
|
|
m_trackAlbum = TQString();
|
|
|
|
m_trackNumber = TQString();
|
|
|
|
m_trackYear = TQString();
|
|
|
|
m_trackComment = TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = TQString();
|
|
|
|
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 = TQString();
|
|
|
|
m_trackAudioBitrate = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*** we need a little delay for some meta info ***/
|
|
|
|
TQTimer::singleShot(1000, this, TQT_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(TQCursor(TQt::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()
|
|
|
|
{
|
|
|
|
TQString error;
|
|
|
|
int errCode = xine_get_error(m_xineStream);
|
|
|
|
|
|
|
|
TQString addInfo;
|
|
|
|
TQString audioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
|
|
|
|
TQString videoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
|
|
|
|
if ((!audioCodec.isEmpty()) || (!videoCodec.isEmpty()))
|
|
|
|
{
|
|
|
|
if (!audioCodec.isEmpty())
|
|
|
|
addInfo.append(TQString("(") + i18n("Audio Codec") + ": " + audioCodec + ")");
|
|
|
|
if (!videoCodec.isEmpty())
|
|
|
|
addInfo.append(TQString("(") + i18n("Video Codec") + ": " + videoCodec + ")");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
addInfo.append(TQString("(") + m_trackURL + ")");
|
|
|
|
|
|
|
|
switch (errCode)
|
|
|
|
{
|
|
|
|
case XINE_ERROR_NO_INPUT_PLUGIN:
|
|
|
|
case XINE_ERROR_NO_DEMUX_PLUGIN:
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
{
|
|
|
|
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(TQString("Can't play: %1 - trying next").tqarg(m_trackURL));
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotPlay()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KXineWidget::isPlaying() const
|
|
|
|
{
|
|
|
|
if (isXineReady())
|
|
|
|
return ((xine_get_status(m_xineStream) == XINE_STATUS_PLAY) && (m_trackURL != m_logoFile));
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KXineWidget::getXineLog() const
|
|
|
|
{
|
|
|
|
TQString logStr;
|
|
|
|
int i = 0;
|
|
|
|
TQTextStream ts(&logStr, IO_WriteOnly);
|
|
|
|
|
|
|
|
const char* const* log = xine_get_log(m_xineEngine, /* XINE_LOG_MSG*/ 0);
|
|
|
|
if (log == NULL)
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
while(log[i])
|
|
|
|
{
|
|
|
|
ts << TQString::fromLocal8Bit(log[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return logStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::showOSDMessage(const TQString& 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(TQString("OSD: draw text: %1").tqarg(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_TQT_ONLY
|
|
|
|
/****************** postprocessing filter management ****************/
|
|
|
|
|
|
|
|
TQStringList KXineWidget::getVideoFilterNames() const
|
|
|
|
{
|
|
|
|
TQStringList 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList KXineWidget::getAudioFilterNames() const
|
|
|
|
{
|
|
|
|
TQStringList 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 TQString& name, TQWidget* parent)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireVideoFilters();
|
|
|
|
|
|
|
|
PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
|
|
|
|
connect(filter, TQT_SIGNAL(signalDeleteMe(PostFilter*)), this, TQT_SLOT(slotDeleteVideoFilter(PostFilter*)));
|
|
|
|
m_videoFilterList.append(filter);
|
|
|
|
|
|
|
|
wireVideoFilters();
|
|
|
|
#else
|
|
|
|
parent = parent;
|
|
|
|
warningOut(TQString("Not implemented [CreateVideoFilter %1]").tqarg(name));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotCreateAudioFilter(const TQString& name, TQWidget* parent)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireAudioFilters();
|
|
|
|
|
|
|
|
PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
|
|
|
|
connect(filter, TQT_SIGNAL(signalDeleteMe(PostFilter*)), this, TQT_SLOT(slotDeleteAudioFilter(PostFilter*)));
|
|
|
|
m_audioFilterList.append(filter);
|
|
|
|
|
|
|
|
wireAudioFilters();
|
|
|
|
#else
|
|
|
|
parent = parent;
|
|
|
|
warningOut(TQString("Not implemented [CreateAudioFilter %1]").tqarg(name));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KXineWidget::slotRemoveAllVideoFilters()
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireVideoFilters();
|
|
|
|
while (m_videoFilterList.count())
|
|
|
|
m_videoFilterList.removeLast();
|
|
|
|
wireVideoFilters();
|
|
|
|
#else
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotRemoveAllAudioFilters()
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireAudioFilters();
|
|
|
|
while (m_audioFilterList.count())
|
|
|
|
m_audioFilterList.removeLast();
|
|
|
|
wireAudioFilters();
|
|
|
|
#else
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotDeleteVideoFilter(PostFilter* filter)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireVideoFilters();
|
|
|
|
m_videoFilterList.remove(filter);
|
|
|
|
wireVideoFilters();
|
|
|
|
#else
|
|
|
|
filter = filter;
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotDeleteAudioFilter(PostFilter* filter)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireAudioFilters();
|
|
|
|
m_audioFilterList.remove(filter);
|
|
|
|
wireAudioFilters();
|
|
|
|
#else
|
|
|
|
filter = filter;
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef USE_TQT_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<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(TQString("Init visual plugin: %1").tqarg(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(TQString("Dispose visual plugin: %1").tqarg(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_TQT_ONLY
|
|
|
|
m_videoFiltersEnabled = enable;
|
|
|
|
|
|
|
|
unwireVideoFilters();
|
|
|
|
wireVideoFilters();
|
|
|
|
#else
|
|
|
|
enable = enable;
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotEnableAudioFilters(bool enable)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
m_audioFiltersEnabled = enable;
|
|
|
|
|
|
|
|
unwireAudioFilters();
|
|
|
|
wireAudioFilters();
|
|
|
|
#else
|
|
|
|
enable = enable;
|
|
|
|
warningOut("Not implemented!");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
TQStringList KXineWidget::getAudioFilterConfig()
|
|
|
|
{
|
|
|
|
TQStringList configStrings;
|
|
|
|
for (uint i=0; i<m_audioFilterList.count(); i++)
|
|
|
|
configStrings << m_audioFilterList.at(i)->getConfig();
|
|
|
|
return configStrings;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList KXineWidget::getVideoFilterConfig()
|
|
|
|
{
|
|
|
|
TQStringList configStrings;
|
|
|
|
for (uint i=0; i<m_videoFilterList.count(); i++)
|
|
|
|
configStrings << m_videoFilterList.at(i)->getConfig();
|
|
|
|
return configStrings;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**** visual plugin **********/
|
|
|
|
|
|
|
|
TQStringList KXineWidget::getVisualPlugins() const
|
|
|
|
{
|
|
|
|
TQStringList 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 TQString& visual)
|
|
|
|
{
|
|
|
|
if (m_visualPluginName == visual) return;
|
|
|
|
debugOut(TQString("New visualization plugin: %1").tqarg(visual));
|
|
|
|
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
unwireAudioFilters();
|
|
|
|
if(m_visualPlugin)
|
|
|
|
{
|
|
|
|
delete m_visualPlugin;
|
|
|
|
m_visualPlugin = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (visual == "none")
|
|
|
|
m_visualPluginName = TQString();
|
|
|
|
else
|
|
|
|
m_visualPluginName = visual;
|
|
|
|
|
|
|
|
wireAudioFilters();
|
|
|
|
#else
|
|
|
|
if (visual == "none")
|
|
|
|
m_visualPluginName = TQString();
|
|
|
|
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(TQStringList& 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 TQString& plugin, TQStringList& 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(TQString("Set software amplification level: %1").tqarg(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(TQString("Set audio mixer volume: %1").tqarg(vol));
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_AUDIO_VOLUME, vol);
|
|
|
|
}
|
|
|
|
emit signalXineStatus(i18n("Volume") + ": " + TQString::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(TQMouseEvent* mev)
|
|
|
|
{
|
|
|
|
if (!m_xineReady) return;
|
|
|
|
|
|
|
|
if (cursor().shape() == TQt::BlankCursor)
|
|
|
|
{
|
|
|
|
setCursor(TQCursor(TQt::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(TQMouseEvent* 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 == TQt::ArrowCursor) || (cur == TQt::BlankCursor) )
|
|
|
|
{
|
|
|
|
emit signalRightClick(mev->globalPos());
|
|
|
|
mev->accept();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mev->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
if ( (cur == TQt::ArrowCursor) || (cur == TQt::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(TQMouseEvent* mev)
|
|
|
|
{
|
|
|
|
emit signalDoubleClick();
|
|
|
|
mev->ignore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::wheelEvent(TQWheelEvent* e)
|
|
|
|
{
|
|
|
|
int oldVal = getPosition();
|
|
|
|
if (oldVal == 0) // no valid position
|
|
|
|
return;
|
|
|
|
|
|
|
|
float offset = log10( TQABS(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, TQTime());
|
|
|
|
|
|
|
|
if ((m_logoFile.isNull()) && (isPlaying()))
|
|
|
|
xine_stop(m_xineStream);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
appendToQueue(m_logoFile);
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotPlay()));
|
|
|
|
}
|
|
|
|
|
|
|
|
emit signalXineStatus(i18n("Stop"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetAudiocdDevice(const TQString& device)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Set AudioCD device to %1").tqarg(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 = TQFile::encodeName(device).data();
|
|
|
|
xine_config_update_entry (m_xineEngine, &config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetVcdDevice(const TQString& device)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Set VCD device to %1").tqarg(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 = TQFile::encodeName(device).data();
|
|
|
|
xine_config_update_entry (m_xineEngine, &config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetDvdDevice(const TQString& device)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Set DVD device to %1").tqarg(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 = TQFile::encodeName(device).data();
|
|
|
|
xine_config_update_entry (m_xineEngine, &config);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KXineWidget::audiocdDevice() const
|
|
|
|
{
|
|
|
|
xine_cfg_entry_t config;
|
|
|
|
xine_config_lookup_entry(m_xineEngine, "input.cdda_device", &config);
|
|
|
|
|
|
|
|
return TQFile::decodeName(config.str_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KXineWidget::vcdDevice() const
|
|
|
|
{
|
|
|
|
xine_cfg_entry_t config;
|
|
|
|
xine_config_lookup_entry(m_xineEngine, "input.vcd_device", &config);
|
|
|
|
|
|
|
|
return TQFile::decodeName(config.str_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KXineWidget::dvdDevice() const
|
|
|
|
{
|
|
|
|
xine_cfg_entry_t config;
|
|
|
|
xine_config_lookup_entry(m_xineEngine, "input.dvd_device", &config);
|
|
|
|
|
|
|
|
return TQFile::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 TQString& dir)
|
|
|
|
{
|
|
|
|
xine_cfg_entry_t config;
|
|
|
|
|
|
|
|
if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return; /* older xine-lib */
|
|
|
|
|
|
|
|
debugOut(TQString("Set misc.save_dir to: %1").tqarg(dir));
|
|
|
|
config.str_value = TQFile::encodeName(dir).data();
|
|
|
|
xine_config_update_entry (m_xineEngine, &config);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString KXineWidget::getStreamSaveDir()
|
|
|
|
{
|
|
|
|
xine_cfg_entry_t config;
|
|
|
|
|
|
|
|
if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return TQString(); /* older xine-lib */
|
|
|
|
|
|
|
|
return TQFile::decodeName(config.str_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::setBroadcasterPort(const uint port)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Set broadcaster port to %1").tqarg(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").tqarg("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").tqarg("x1"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_2);
|
|
|
|
m_currentSpeed = Fast1;
|
|
|
|
emit signalXineStatus(i18n("Fast Forward %1").tqarg("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").tqarg("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").tqarg("x1"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_2);
|
|
|
|
m_currentSpeed = Slow1;
|
|
|
|
emit signalXineStatus(i18n("Slow Motion %1").tqarg("x1"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KXineWidget::getSupportedExtensions() const
|
|
|
|
{
|
|
|
|
return xine_get_file_extensions(m_xineEngine);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetAudioChannel(int ch)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Switch to audio channel %1").tqarg(ch-1));
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ch-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KXineWidget::slotSetSubtitleChannel(int ch)
|
|
|
|
{
|
|
|
|
debugOut(TQString("Switch to subtitle channel %1").tqarg(ch-1));
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_SPU_CHANNEL, ch-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KXineWidget::slotSetFileSubtitles(TQString 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTime KXineWidget::getPlaytime() const
|
|
|
|
{
|
|
|
|
if (!m_xineReady) return TQTime();
|
|
|
|
|
|
|
|
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 TQTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
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 TQTime& postime)
|
|
|
|
{
|
|
|
|
if ( running() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((!isXineReady()) || (!isPlaying()) || (!isSeekable()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
seekThreadPause = false;
|
|
|
|
if (m_currentSpeed == Pause)
|
|
|
|
seekThreadPause = true;
|
|
|
|
seekThreadPos = 0;
|
|
|
|
seekThreadTime = TQTime().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_TQT_ONLY
|
|
|
|
void KXineWidget::createDeinterlacePlugin(const TQString& config, TQWidget* 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 TQString KXineWidget::getDeinterlaceConfig() const
|
|
|
|
{
|
|
|
|
if (m_deinterlaceFilter)
|
|
|
|
return m_deinterlaceFilter->getConfig();
|
|
|
|
|
|
|
|
return DEFAULT_TVTIME_CONFIG;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void KXineWidget::slotSetDeinterlaceConfig(const TQString& config)
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
if (m_deinterlaceFilter)
|
|
|
|
m_deinterlaceFilter->setConfig(config);
|
|
|
|
#else
|
|
|
|
warningOut(TQString ("Not implemented [SetDeinterlaceConfig %1]").tqarg(config));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotToggleDeinterlace()
|
|
|
|
{
|
|
|
|
#ifndef USE_TQT_ONLY
|
|
|
|
TQString s;
|
|
|
|
|
|
|
|
if (m_deinterlaceFilter)
|
|
|
|
{
|
|
|
|
m_deinterlaceEnabled = !m_deinterlaceEnabled;
|
|
|
|
debugOut(TQString("Deinterlace enabled: %1").tqarg(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") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::number(m_currentZoom) + "%");
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTime 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 TQTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotEmitLengthInfo()
|
|
|
|
{
|
|
|
|
TQTime 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()
|
|
|
|
{
|
|
|
|
TQPoint g = mapToGlobal(TQPoint(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") + ": " + TQString::number((hue*100)/65535) + "%");
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetSaturation(int sat)
|
|
|
|
{
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_VO_SATURATION, sat);
|
|
|
|
emit signalXineStatus(i18n("Saturation") + ": " + TQString::number((sat*100)/65535) + "%");
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetContrast(int contrast)
|
|
|
|
{
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_VO_CONTRAST, contrast);
|
|
|
|
emit signalXineStatus(i18n("Contrast") + ": " + TQString::number((contrast*100)/65535) + "%");
|
|
|
|
}
|
|
|
|
|
|
|
|
void KXineWidget::slotSetBrightness(int bright)
|
|
|
|
{
|
|
|
|
xine_set_param(m_xineStream, XINE_PARAM_VO_BRIGHTNESS, bright);
|
|
|
|
emit signalXineStatus(i18n("Brightness") + ": " + TQString::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") + ": " + TQString::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") + ": " + TQString::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() == TQt::ArrowCursor)
|
|
|
|
{
|
|
|
|
setCursor(TQCursor(TQt::BlankCursor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************
|
|
|
|
* Take a Screenshot *
|
|
|
|
************************************************************/
|
|
|
|
|
|
|
|
TQImage KXineWidget::getScreenshot() const
|
|
|
|
{
|
|
|
|
uchar *rgbPile = NULL;
|
|
|
|
int width, height;
|
|
|
|
double scaleFactor;
|
|
|
|
|
|
|
|
getScreenshot(rgbPile, width, height, scaleFactor);
|
|
|
|
|
|
|
|
if (!rgbPile) return TQImage();
|
|
|
|
|
|
|
|
TQImage screenShot(rgbPile, width, height, 32, 0, 0, TQImage::IgnoreEndian);
|
|
|
|
if (scaleFactor >= 1.0)
|
|
|
|
width = (int)((double) width * scaleFactor + 0.5);
|
|
|
|
else
|
|
|
|
height = (int)((double) height / scaleFactor + 0.5);
|
|
|
|
|
|
|
|
debugOut(TQString("Screenshot: scale picture from %1x%2 to %3x%4").tqarg(screenShot.width()).tqarg(screenShot.height()).tqarg(width).tqarg(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(TQString("Screenshot: Format %1 not supportet!").tqarg((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(TQString("Screenshot: Unknown aspect ratio: %1 - using 4:3").tqarg(ratio));
|
|
|
|
case XINE_VO_ASPECT_STQUARE:
|
|
|
|
debugOut("Screenshot: got video aspect: 1:1");
|
|
|
|
desired_ratio = image_ratio;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
debugOut(TQString("Screenshot: using scale factor: %1").tqarg(m_videoAspect));
|
|
|
|
scaleFactor = m_videoAspect;
|
|
|
|
|
|
|
|
delete [] yuv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* HELPER FUNCTIONS *
|
|
|
|
************************************************/
|
|
|
|
|
|
|
|
TQTime KXineWidget::msToTime(int msec)
|
|
|
|
{
|
|
|
|
TQTime t;
|
|
|
|
t = t.addMSecs(msec);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_TQT_ONLY
|
|
|
|
TQString KXineWidget::i18n(const char *text)
|
|
|
|
{
|
|
|
|
return TQApplication::tr(text);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void KXineWidget::debugOut (TQString qsDebug)
|
|
|
|
{
|
|
|
|
#ifdef USE_TQT_ONLY
|
|
|
|
TQString qsDebugging = TQString ("Debug: ") + qsDebug +"\n";
|
|
|
|
printf ((const char *)qsDebugging);
|
|
|
|
#else
|
|
|
|
kdDebug() << "KXineWidget: " << (const char *)qsDebug.ascii() << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void KXineWidget::errorOut (TQString qsError)
|
|
|
|
{
|
|
|
|
#ifdef USE_TQT_ONLY
|
|
|
|
TQString qsErroring = TQString ("Error: ") + qsError+ "\n";
|
|
|
|
printf ((const char *)qsErroring);
|
|
|
|
#else
|
|
|
|
kdError() << "KXineWidget: " << (const char *)qsError.ascii() << "\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void KXineWidget::warningOut (TQString qsWarning)
|
|
|
|
{
|
|
|
|
#ifdef USE_TQT_ONLY
|
|
|
|
TQString qsWarninging = TQString ("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 <vektor@dumbterm.net>
|
|
|
|
* 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 == TQ_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;
|
|
|
|
}
|