PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/release-0.5.2.1/player/kxinewidget.cpp

http://kmediafactory.googlecode.com/
C++ | 3929 lines | 3129 code | 614 blank | 186 comment | 468 complexity | b529aab7b4f5caa1b90f7740683af989 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /***************************************************************************
  2. kxinewidget.cpp
  3. A KDE/QT API for the xine-lib. Define USE_QT_ONLY if you use QT only.
  4. -------------------
  5. begin : Fre Apr 18 2003
  6. revision : $Revision: 1.48 $
  7. last modified : $Date: 2005/08/22 19:36:46 $ by $Author: juergenk $
  8. copyright : (C) 2003-2005 by JÌrgen Kofler
  9. email : kaffeine@gmx.net
  10. ***************************************************************************/
  11. /***************************************************************************
  12. * *
  13. * This program is free software; you can redistribute it and/or modify *
  14. * it under the terms of the GNU General Public License as published by *
  15. * the Free Software Foundation; either version 2 of the License, or *
  16. * (at your option) any later version. *
  17. * *
  18. ***************************************************************************/
  19. #include <qapplication.h>
  20. #include <qwidget.h>
  21. #include <qstringlist.h>
  22. #include <qtimer.h>
  23. #include <qevent.h>
  24. #include <qthread.h>
  25. #include <qdir.h>
  26. #include <qcursor.h>
  27. #include <qimage.h>
  28. #include <qdatetime.h>
  29. #include <qtextcodec.h>
  30. #include <xine/xineutils.h>
  31. #include <math.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include "kxinewidget.h"
  35. #ifdef HAVE_XINERAMA
  36. #include <X11/extensions/Xinerama.h>
  37. #endif
  38. #ifndef USE_QT_ONLY
  39. #include "kxinewidget.moc"
  40. #include <klocale.h>
  41. #include <kdebug.h>
  42. #endif
  43. #define TIMER_EVENT_PLAYBACK_FINISHED 100
  44. #define TIMER_EVENT_NEW_CHANNELS 101
  45. #define TIMER_EVENT_NEW_TITLE 102
  46. #define TIMER_EVENT_NEW_STATUS 103
  47. #define TIMER_EVENT_CHANGE_CURSOR 104
  48. #define TIMER_EVENT_NEW_MRL_REFERENCE 105
  49. #define TIMER_EVENT_NEW_XINE_MESSAGE 106
  50. #define TIMER_EVENT_NEW_XINE_ERROR 107
  51. #define TIMER_EVENT_FRAME_FORMAT_CHANGE 108
  52. #define TIMER_EVENT_NEW_VOLUME_LEVEL 109
  53. #define TIMER_EVENT_RESTART_PLAYBACK 200
  54. #define TIMER_EVENT_RESIZE_PARENT 300
  55. KXineWidget::KXineWidget(QWidget* parent, const char* name,
  56. const QString& pathToConfigFile, const QString& pathToLogoFile,
  57. const QString& audioDriver, const QString& videoDriver,
  58. bool startManual, bool verbose)
  59. : QWidget(parent,name), QThread(), m_startXineManual(startManual), m_xineReady(false),
  60. m_logoFile(pathToLogoFile), m_preferedAudio(audioDriver), m_preferedVideo(videoDriver), m_xineVerbose(verbose),
  61. m_xineDisplay(NULL), m_xineEngine(NULL), m_audioDriver(NULL), m_videoDriver(NULL), m_xineStream(NULL),
  62. m_eventQueue(NULL), m_osd(NULL), m_osdUnscaled(false), m_osdShow(false), m_osdSize(0), m_osdFont(NULL),
  63. m_audioChoices(NULL), m_audioInfo(NULL), m_videoChoices(NULL), m_videoInfo(NULL), m_mixerInfo(NULL),
  64. m_osdShowInfo(NULL),
  65. m_osdSizeOptions(NULL), m_osdSizeInfo(NULL), m_osdFontInfo(NULL),
  66. #ifndef USE_QT_ONLY
  67. m_videoFiltersEnabled(true), m_audioFiltersEnabled(true), m_deinterlaceFilter(NULL),
  68. m_deinterlaceEnabled(false),
  69. m_visualPlugin(NULL),
  70. #else
  71. m_xinePost(NULL), m_postAudioSource(NULL), m_postInput(NULL),
  72. #endif
  73. m_visualPluginName(QString::null), m_currentSpeed(Normal), m_softwareMixer(false), m_volumeGain(false),
  74. m_currentZoom(100), m_currentZoomX(100), m_currentZoomY(100), m_currentAudio(0), m_currentSub(0), m_savedPos(0), m_autoresizeEnabled(false)
  75. {
  76. setMinimumSize(QSize(20,20)); // set a size hint
  77. setPaletteBackgroundColor(QColor(0,0,0)); //black
  78. /* dvb */
  79. TimeShiftFilename = "";
  80. dvbHaveVideo = 0;
  81. dvbOSD = 0;
  82. dvbColor[0] = 0;
  83. connect( &dvbOSDHideTimer, SIGNAL(timeout()), this, SLOT(dvbHideOSD()) );
  84. if (pathToConfigFile.isNull())
  85. {
  86. debugOut("Using default config file ~/.xine/config");
  87. m_configFilePath = QDir::homeDirPath();
  88. m_configFilePath.append("/.xine/config");
  89. }
  90. else
  91. m_configFilePath = pathToConfigFile;
  92. if (!m_logoFile.isNull())
  93. appendToQueue(m_logoFile);
  94. #ifndef USE_QT_ONLY
  95. m_videoFilterList.setAutoDelete(true); /*** delete post plugin on removing from list ***/
  96. m_audioFilterList.setAutoDelete(true); /*** delete post plugin on removing from list ***/
  97. #endif
  98. connect(&m_posTimer, SIGNAL(timeout()), this, SLOT(slotSendPosition()));
  99. connect(&m_lengthInfoTimer, SIGNAL(timeout()), this, SLOT(slotEmitLengthInfo()));
  100. connect(&m_mouseHideTimer, SIGNAL(timeout()), this, SLOT(slotHideMouse()));
  101. connect(&m_osdTimer, SIGNAL(timeout()), this, SLOT(slotOSDHide()));
  102. connect(&m_recentMessagesTimer, SIGNAL(timeout()), this, SLOT(slotNoRecentMessage()));
  103. setUpdatesEnabled(false);
  104. setMouseTracking(true);
  105. }
  106. KXineWidget::~KXineWidget()
  107. {
  108. /* "careful" shutdown, maybe xine initialization was not successful */
  109. m_xineReady = false;
  110. /* stop all timers */
  111. m_posTimer.stop();
  112. m_mouseHideTimer.stop();
  113. #ifndef USE_QT_ONLY
  114. slotRemoveAllAudioFilters();
  115. slotRemoveAllVideoFilters();
  116. #endif
  117. if (m_osd)
  118. xine_osd_free(m_osd);
  119. if (m_xineStream)
  120. xine_close(m_xineStream);
  121. if (running())
  122. {
  123. XEvent ev;
  124. ev.type = Expose;
  125. ev.xexpose.display = m_xineDisplay;
  126. ev.xexpose.window = winId();
  127. ev.xexpose.x = x();
  128. ev.xexpose.y = y();
  129. ev.xexpose.width = width();
  130. ev.xexpose.height = height();
  131. ev.xexpose.count = 0;
  132. XSendEvent( x11Display(), winId(), False, ExposureMask, &ev ); /* send a fake expose event */
  133. XFlush(x11Display());
  134. if( !wait(1000) ) /* wait a second for thread exiting */
  135. {
  136. warningOut("XEvent thread don't exit. Terminating it...");
  137. terminate();
  138. }
  139. }
  140. debugOut("Shut down xine engine");
  141. #ifndef USE_QT_ONLY
  142. if (m_deinterlaceFilter)
  143. {
  144. debugOut("Unwire video filters");
  145. unwireVideoFilters();
  146. delete m_deinterlaceFilter;
  147. m_deinterlaceFilter = NULL;
  148. }
  149. if (m_visualPlugin)
  150. {
  151. debugOut("Unwire audio filters");
  152. unwireAudioFilters();
  153. debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName ));
  154. delete m_visualPlugin;
  155. m_visualPlugin = NULL;
  156. }
  157. #else
  158. if (m_xinePost)
  159. {
  160. debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
  161. m_postAudioSource = xine_get_audio_source(m_xineStream);
  162. xine_post_wire_audio_port(m_postAudioSource, m_audioDriver);
  163. xine_post_dispose(m_xineEngine, m_xinePost);
  164. }
  165. #endif
  166. if (m_eventQueue)
  167. {
  168. debugOut("Dispose event queue");
  169. xine_event_dispose_queue(m_eventQueue);
  170. }
  171. if (m_xineStream)
  172. {
  173. debugOut("Dispose stream");
  174. xine_dispose(m_xineStream);
  175. }
  176. if (m_audioDriver)
  177. {
  178. debugOut("Close audio driver");
  179. xine_close_audio_driver(m_xineEngine, m_audioDriver);
  180. }
  181. if (m_videoDriver)
  182. {
  183. debugOut("Close video driver");
  184. xine_close_video_driver(m_xineEngine, m_videoDriver);
  185. }
  186. if (m_xineEngine)
  187. {
  188. saveXineConfig();
  189. debugOut("Close xine engine");
  190. xine_exit(m_xineEngine);
  191. }
  192. m_xineEngine = NULL;
  193. /* free xine config strings */
  194. if (m_osdShowInfo) free(m_osdShowInfo);
  195. if (m_osdFontInfo) free(m_osdFontInfo);
  196. if (m_osdFont) free(m_osdFont);
  197. if (m_osdSizeInfo) free(m_osdSizeInfo);
  198. if (m_osdSizeOptions)
  199. {
  200. int i=0;
  201. while (m_osdSizeOptions[i])
  202. {
  203. free(m_osdSizeOptions[i]);
  204. i++;
  205. }
  206. delete [] m_osdSizeOptions;
  207. }
  208. if (m_mixerInfo) free(m_mixerInfo);
  209. if (m_videoInfo) free(m_videoInfo);
  210. if (m_videoChoices)
  211. {
  212. int i=0;
  213. while (m_videoChoices[i])
  214. {
  215. free(m_videoChoices[i]);
  216. i++;
  217. }
  218. delete [] m_videoChoices;
  219. }
  220. if (m_audioInfo) free(m_audioInfo);
  221. if (m_audioChoices)
  222. {
  223. int i=0;
  224. while (m_audioChoices[i])
  225. {
  226. free(m_audioChoices[i]);
  227. i++;
  228. }
  229. delete [] m_audioChoices;
  230. }
  231. if (m_xineDisplay)
  232. {
  233. debugOut("Close xine display");
  234. XCloseDisplay(m_xineDisplay); /* close xine display */
  235. }
  236. m_xineDisplay = NULL;
  237. debugOut("xine closed");
  238. }
  239. void KXineWidget::saveXineConfig()
  240. {
  241. debugOut("Set CD/VCD/DVD path back");
  242. xine_cfg_entry_t config;
  243. if (!m_cachedCDPath.isNull())
  244. {
  245. xine_config_lookup_entry (m_xineEngine, "input.cdda_device", &config);
  246. config.str_value = (char*)m_cachedCDPath.latin1();
  247. xine_config_update_entry (m_xineEngine, &config);
  248. }
  249. if (!m_cachedVCDPath.isNull())
  250. {
  251. xine_config_lookup_entry (m_xineEngine, "input.vcd_device", &config);
  252. config.str_value = (char*)m_cachedVCDPath.latin1();
  253. xine_config_update_entry (m_xineEngine, &config);
  254. }
  255. if (!m_cachedDVDPath.isNull())
  256. {
  257. xine_config_lookup_entry (m_xineEngine, "input.dvd_device", &config);
  258. config.str_value = (char*)m_cachedDVDPath.latin1();
  259. xine_config_update_entry (m_xineEngine, &config);
  260. }
  261. debugOut(QString("Save xine config to: %1").arg(m_configFilePath));
  262. xine_config_save(m_xineEngine, m_configFilePath.ascii());
  263. }
  264. /***************************************************
  265. * CALLBACKS
  266. ***************************************************/
  267. void KXineWidget::destSizeCallback(void* p, int /*video_width*/, int /*video_height*/, double /*video_aspect*/,
  268. int* dest_width, int* dest_height, double* dest_aspect)
  269. {
  270. if (p == NULL) return;
  271. KXineWidget* vw = (KXineWidget*) p;
  272. *dest_width = vw->width();
  273. *dest_height = vw->height();
  274. *dest_aspect = vw->m_displayRatio;
  275. }
  276. void KXineWidget::frameOutputCallback(void* p, int video_width, int video_height, double video_aspect,
  277. int* dest_x, int* dest_y, int* dest_width, int* dest_height,
  278. double* dest_aspect, int* win_x, int* win_y)
  279. {
  280. if (p == NULL) return;
  281. KXineWidget* vw = (KXineWidget*) p;
  282. *dest_x = 0;
  283. *dest_y = 0 ;
  284. *dest_width = vw->width();
  285. *dest_height = vw->height();
  286. *win_x = vw->m_globalX;
  287. *win_y = vw->m_globalY;
  288. *dest_aspect = vw->m_displayRatio;
  289. /* give false aspect for audio visualization*/
  290. if ( !vw->hasVideo() ) {
  291. *dest_aspect = (video_width*video_aspect)/((vw->width()*video_height/vw->height())-0.5);
  292. }
  293. /* correct size with video aspect */
  294. if (video_aspect >= vw->m_displayRatio)
  295. video_width = (int) ( (double) (video_width * video_aspect / vw->m_displayRatio + 0.5) );
  296. else
  297. video_height = (int) ( (double) (video_height * vw->m_displayRatio / video_aspect) + 0.5);
  298. /* frame size changed */
  299. if ( (video_width != vw->m_videoFrameWidth) || (video_height != vw->m_videoFrameHeight) )
  300. {
  301. debugOut(QString("New video frame size: %1x%2 - aspect ratio: %3").arg(video_width).arg(video_height).arg(video_aspect));
  302. vw->m_videoFrameWidth = video_width;
  303. vw->m_videoFrameHeight = video_height;
  304. vw->m_videoAspect = video_aspect;
  305. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_FRAME_FORMAT_CHANGE));
  306. /* auto-resize parent widget */
  307. if ((vw->m_autoresizeEnabled) && (vw->parentWidget()) && (vw->m_posTimer.isActive()) && (!vw->parentWidget()->isFullScreen())
  308. && (video_width > 0) && (video_height > 0))
  309. {
  310. vw->m_newParentSize = vw->parentWidget()->size() - QSize((vw->width() - video_width), vw->height() - video_height);
  311. debugOut(QString("Resize video window to: %1x%2").arg(vw->m_newParentSize.width()).arg(vw->m_newParentSize.height()));
  312. /* we should not do a resize() inside a xine thread,
  313. but post an event to the main thread */
  314. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESIZE_PARENT));
  315. }
  316. }
  317. }
  318. /*
  319. * XINE EVENT THREAD
  320. * only the QT event thread should do GUI operations,
  321. * we use QApplication::postEvent() and a reimplementation of QObject::timerEvent() to
  322. * make sure all critical jobs are done within the QT main thread context
  323. *
  324. * for more information see http://doc.trolltech.com/3.1/threads.html
  325. */
  326. void KXineWidget::xineEventListener(void *p, const xine_event_t* xineEvent)
  327. {
  328. if (p == NULL) return;
  329. KXineWidget* vw = (KXineWidget*) p;
  330. switch (xineEvent->type)
  331. {
  332. case XINE_EVENT_UI_PLAYBACK_FINISHED:
  333. {
  334. debugOut("xine event: playback finished");
  335. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_PLAYBACK_FINISHED ));
  336. break;
  337. }
  338. case XINE_EVENT_UI_CHANNELS_CHANGED: /* new channel informations */
  339. {
  340. debugOut("xine event: channels changed");
  341. int i,j,channels;
  342. char* lang = new char[128];
  343. QString num;
  344. vw->m_audioCh.clear();
  345. vw->m_audioCh.append(i18n("auto"));
  346. vw->m_subCh.clear();
  347. vw->m_subCh.append(i18n("off"));
  348. /*** get audio channels ***/
  349. channels = QMAX(10, xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_MAX_AUDIO_CHANNEL));
  350. for(i = 0; i < channels; i++)
  351. {
  352. if (xine_get_audio_lang(vw->m_xineStream, i, lang))
  353. vw->m_audioCh << lang;
  354. else
  355. vw->m_audioCh << i18n("Ch ") + num.setNum(i+1);
  356. }
  357. /*** get subtitle channels ***/
  358. channels = QMAX(10, xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_MAX_SPU_CHANNEL));
  359. for(j = 0; j < channels; j++)
  360. {
  361. if (xine_get_spu_lang(vw->m_xineStream, j, lang))
  362. vw->m_subCh << lang;
  363. else
  364. vw->m_subCh << i18n("Ch ") + num.setNum(j+1);
  365. }
  366. delete [] lang;
  367. vw->m_currentAudio = xine_get_param(vw->m_xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1;
  368. vw->m_currentSub = xine_get_param(vw->m_xineStream, XINE_PARAM_SPU_CHANNEL) + 1;
  369. if (vw->m_currentAudio > (i-1))
  370. {
  371. vw->slotSetAudioChannel(0);
  372. vw->m_currentAudio = -1;
  373. }
  374. if (vw->m_currentSub > (j-1))
  375. {
  376. vw->slotSetSubtitleChannel(0);
  377. vw->m_currentSub = -1;
  378. }
  379. //check if stream is seekable
  380. vw->m_trackIsSeekable = (bool)xine_get_stream_info(vw->m_xineStream, XINE_STREAM_INFO_SEEKABLE);
  381. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_CHANNELS));
  382. break;
  383. }
  384. case XINE_EVENT_UI_SET_TITLE: /* set new title */
  385. {
  386. debugOut("xine event: ui set title");
  387. xine_ui_data_t* xd = (xine_ui_data_t*)xineEvent->data;
  388. vw->m_trackTitle = QString::fromLocal8Bit( (char*)xd->str );
  389. vw->m_lengthInfoTries = 0;
  390. vw->m_lengthInfoTimer.start(1000); /* May be new Length on Changing DVD/VCD titles */
  391. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_TITLE));
  392. break;
  393. }
  394. case XINE_EVENT_PROGRESS:
  395. {
  396. debugOut("xine event: progress info");
  397. xine_progress_data_t* pd = (xine_progress_data_t*)xineEvent->data;
  398. vw->m_statusString = QString::fromLocal8Bit(pd->description) + " " + QString::number(pd->percent) + "%";
  399. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
  400. break;
  401. }
  402. case XINE_EVENT_DROPPED_FRAMES:
  403. {
  404. debugOut("xine event: dropped frames");
  405. xine_dropped_frames_t* dropped = (xine_dropped_frames_t*)xineEvent->data;
  406. warningOut(QString("Skipped frames: %1 - discarded frames: %2").arg(dropped->skipped_frames/10).arg(dropped->discarded_frames/10));
  407. break;
  408. }
  409. case XINE_EVENT_SPU_BUTTON:
  410. {
  411. debugOut("xine event: spu button");
  412. xine_spu_button_t* button = (xine_spu_button_t*)xineEvent->data;
  413. if (button->direction == 1) /* enter a button */
  414. {
  415. debugOut("DVD Menu: Mouse entered button");
  416. vw->m_DVDButtonEntered = true;
  417. }
  418. else
  419. {
  420. debugOut("DVD Menu: Mouse leaved button");
  421. vw->m_DVDButtonEntered = false;
  422. }
  423. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_CHANGE_CURSOR));
  424. break;
  425. }
  426. case XINE_EVENT_UI_NUM_BUTTONS:
  427. {
  428. debugOut("xine event: ui num buttons");
  429. break;
  430. }
  431. case XINE_EVENT_MRL_REFERENCE:
  432. {
  433. debugOut("xine event: mrl reference");
  434. xine_mrl_reference_data_t* mrldata = (xine_mrl_reference_data_t*)xineEvent->data;
  435. vw->m_newMRLReference = mrldata->mrl;
  436. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_MRL_REFERENCE));
  437. break;
  438. }
  439. case XINE_EVENT_FRAME_FORMAT_CHANGE:
  440. {
  441. // debugOut("xine event: frame format change");
  442. // QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_FRAME_FORMAT_CHANGE));
  443. break;
  444. }
  445. case XINE_EVENT_AUDIO_LEVEL:
  446. {
  447. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_VOLUME_LEVEL));
  448. break;
  449. }
  450. case XINE_EVENT_UI_MESSAGE:
  451. {
  452. debugOut("xine event: xine message");
  453. xine_ui_message_data_t *data = (xine_ui_message_data_t *)xineEvent->data;
  454. QString message;
  455. switch(data->type)
  456. {
  457. case XINE_MSG_NO_ERROR:
  458. {
  459. /* copy strings, and replace '\0' separators by '\n' */
  460. char* s = data->messages;
  461. char* d = new char[2000];
  462. while(s && (*s != '\0') && ((*s + 1) != '\0'))
  463. {
  464. switch(*s)
  465. {
  466. case '\0':
  467. {
  468. *d = '\n';
  469. break;
  470. }
  471. default:
  472. {
  473. *d = *s;
  474. break;
  475. }
  476. }
  477. s++;
  478. d++;
  479. }
  480. *++d = '\0';
  481. message = d;
  482. delete [] d;
  483. break;
  484. }
  485. case XINE_MSG_GENERAL_WARNING:
  486. {
  487. message = i18n("General Warning: \n");
  488. if(data->explanation)
  489. message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
  490. else
  491. message = message + i18n("No Informations available.");
  492. break;
  493. }
  494. case XINE_MSG_SECURITY:
  495. {
  496. message = i18n("Security Warning: \n");
  497. if(data->explanation)
  498. message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
  499. break;
  500. }
  501. case XINE_MSG_UNKNOWN_HOST:
  502. {
  503. message = i18n("The host you're trying to connect is unknown.\nCheck the validity of the specified hostname. ");
  504. if(data->explanation)
  505. message = message + "(" + ((char *) data + data->parameters) + ")";
  506. break;
  507. }
  508. case XINE_MSG_UNKNOWN_DEVICE:
  509. {
  510. message = i18n("The device name you specified seems invalid. ");
  511. if(data->explanation)
  512. message = message + "(" + ((char *) data + data->parameters) + ")";
  513. break;
  514. }
  515. case XINE_MSG_NETWORK_UNREACHABLE:
  516. {
  517. message = i18n("The network looks unreachable.\nCheck your network setup and the server name. ");
  518. if(data->explanation)
  519. message = message + "(" + ((char *) data + data->parameters) + ")";
  520. break;
  521. }
  522. case XINE_MSG_AUDIO_OUT_UNAVAILABLE:
  523. {
  524. message = i18n("Audio output unavailable. Device is busy. ");
  525. if(data->explanation)
  526. message = message + "(" + ((char *) data + data->parameters) + ")";
  527. break;
  528. }
  529. case XINE_MSG_CONNECTION_REFUSED:
  530. {
  531. message = i18n("The connection was refused.\nCheck the host name. ");
  532. if(data->explanation)
  533. message = message + "(" + ((char *) data + data->parameters) + ")";
  534. break;
  535. }
  536. case XINE_MSG_FILE_NOT_FOUND:
  537. {
  538. message = i18n("The specified file or url was not found. Please check it. ");
  539. if(data->explanation)
  540. message = message + "(" + QString::fromLocal8Bit((char *) data + data->parameters) + ")";
  541. break;
  542. }
  543. case XINE_MSG_PERMISSION_ERROR:
  544. {
  545. message = i18n("Permission to this source was denied. ");
  546. // if(data->explanation)
  547. message = message + "(" + ((char *) data + data->parameters) + ")";
  548. break;
  549. }
  550. case XINE_MSG_READ_ERROR:
  551. {
  552. 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). ");
  553. if(data->explanation)
  554. message = message + "(" + ((char *) data + data->parameters) + ")";
  555. break;
  556. }
  557. case XINE_MSG_LIBRARY_LOAD_ERROR:
  558. {
  559. message = i18n("A problem occur while loading a library or a decoder: ");
  560. if(data->explanation)
  561. message = message + ((char *) data + data->parameters);
  562. break;
  563. }
  564. case XINE_MSG_ENCRYPTED_SOURCE:
  565. {
  566. message = i18n("The source seems encrypted, and can't be read. ");
  567. if (vw->m_trackURL.contains("dvd:/"))
  568. 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. ");
  569. if(data->explanation)
  570. message = message + "(" + ((char *) data + data->parameters) + ")";
  571. break;
  572. }
  573. default:
  574. {
  575. message = i18n("Unknown error: \n");
  576. if(data->explanation)
  577. message = message + ((char *) data + data->explanation) + " " + ((char *) data + data->parameters);
  578. break;
  579. }
  580. }
  581. vw->m_xineMessage = message;
  582. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_XINE_MESSAGE));
  583. break;
  584. }
  585. default:
  586. {
  587. //debugOut("xine event: unhandled type ");
  588. break;
  589. }
  590. }
  591. }
  592. void KXineWidget::timerEvent( QTimerEvent* tevent )
  593. {
  594. switch ( tevent->timerId() )
  595. {
  596. case TIMER_EVENT_PLAYBACK_FINISHED:
  597. {
  598. #ifdef XINE_PARAM_GAPLESS_SWITCH
  599. if ( xine_check_version(1,1,1) )
  600. xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 1);
  601. #endif
  602. if ( !TimeShiftFilename.isEmpty() )
  603. {
  604. QTimer::singleShot(0, this, SLOT(slotPlayTimeShift()));
  605. break;
  606. }
  607. if ( m_trackURL=="DVB" || m_trackURL.contains(".kaxtv.ts") )
  608. break;
  609. if (isQueueEmpty())
  610. {
  611. if (m_trackURL != m_logoFile)
  612. emit signalPlaybackFinished();
  613. else
  614. xine_stop(m_xineStream);
  615. }
  616. else
  617. QTimer::singleShot(0, this, SLOT(slotPlay()));
  618. break;
  619. }
  620. case TIMER_EVENT_NEW_CHANNELS:
  621. {
  622. emit signalNewChannels(m_audioCh, m_subCh, m_currentAudio, m_currentSub);
  623. break;
  624. }
  625. case TIMER_EVENT_NEW_TITLE:
  626. {
  627. emit signalTitleChanged();
  628. break;
  629. }
  630. case TIMER_EVENT_FRAME_FORMAT_CHANGE:
  631. {
  632. if ((m_trackHasVideo) && (m_trackURL != m_logoFile))
  633. emit signalVideoSizeChanged();
  634. break;
  635. }
  636. case TIMER_EVENT_NEW_STATUS:
  637. {
  638. emit signalXineStatus(m_statusString);
  639. break;
  640. }
  641. case TIMER_EVENT_CHANGE_CURSOR:
  642. {
  643. if (m_DVDButtonEntered)
  644. setCursor(QCursor(Qt::PointingHandCursor));
  645. else
  646. setCursor(QCursor(Qt::ArrowCursor));
  647. break;
  648. }
  649. case TIMER_EVENT_NEW_MRL_REFERENCE:
  650. {
  651. m_queue.prepend(m_newMRLReference );
  652. break;
  653. }
  654. case TIMER_EVENT_NEW_VOLUME_LEVEL:
  655. {
  656. emit signalSyncVolume();
  657. break;
  658. }
  659. case TIMER_EVENT_NEW_XINE_MESSAGE:
  660. {
  661. if (!m_recentMessagesTimer.isActive())
  662. {
  663. m_recentMessagesTimer.start(1500);
  664. emit signalXineMessage(m_xineMessage);
  665. }
  666. else
  667. {
  668. //restart
  669. warningOut(QString("Message: '%1' was blocked!").arg(m_xineMessage));
  670. m_recentMessagesTimer.start(1500);
  671. }
  672. break;
  673. }
  674. case TIMER_EVENT_NEW_XINE_ERROR:
  675. {
  676. emit signalXineError(m_xineError);
  677. break;
  678. }
  679. case TIMER_EVENT_RESTART_PLAYBACK:
  680. {
  681. appendToQueue(m_trackURL);
  682. slotPlay();
  683. break;
  684. }
  685. case TIMER_EVENT_RESIZE_PARENT:
  686. {
  687. parentWidget()->resize(m_newParentSize);
  688. break;
  689. }
  690. default: break;
  691. }
  692. }
  693. void KXineWidget::slotNoRecentMessage()
  694. {
  695. m_recentMessagesTimer.stop();
  696. }
  697. /******************* new video driver *********************/
  698. void KXineWidget::videoDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
  699. {
  700. if (p == NULL) return;
  701. if (entry == NULL) return;
  702. #ifndef USE_QT_ONLY
  703. KXineWidget* vw = (KXineWidget*) p;
  704. xine_video_port_t* oldVideoDriver = vw->m_videoDriver;
  705. xine_video_port_t* noneVideoDriver;
  706. int pos, time, length;
  707. debugOut(QString("New video driver: %1").arg(entry->enum_values[entry->num_value]));
  708. if (vw->m_osd)
  709. {
  710. xine_osd_free(vw->m_osd);
  711. vw->m_osd = NULL;
  712. }
  713. noneVideoDriver = xine_open_video_driver(vw->m_xineEngine, "none",
  714. XINE_VISUAL_TYPE_NONE, NULL);
  715. if (!noneVideoDriver)
  716. {
  717. errorOut("Can't init Video Driver 'none', operation aborted.");
  718. return;
  719. }
  720. bool playing = false;
  721. if (vw->isPlaying())
  722. {
  723. playing = true;
  724. vw->m_savedPos = 0;
  725. int t = 0, ret = 0;
  726. while(((ret = xine_get_pos_length(vw->m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  727. xine_usec_sleep(100000);
  728. if ( ret != 0 )
  729. vw->m_savedPos = pos;
  730. }
  731. xine_close(vw->m_xineStream);
  732. /* wire filters to "none" driver so the old one can be safely disposed */
  733. vw->m_videoDriver = noneVideoDriver;
  734. vw->unwireVideoFilters();
  735. vw->wireVideoFilters();
  736. vw->unwireAudioFilters();
  737. if (vw->m_visualPlugin)
  738. {
  739. debugOut(QString("Dispose visual plugin: %1").arg(vw->m_visualPluginName));
  740. delete vw->m_visualPlugin;
  741. vw->m_visualPlugin = NULL;
  742. }
  743. xine_event_dispose_queue(vw->m_eventQueue);
  744. xine_dispose(vw->m_xineStream);
  745. xine_close_video_driver(vw->m_xineEngine, oldVideoDriver);
  746. vw->m_videoDriver = xine_open_video_driver(vw->m_xineEngine,
  747. entry->enum_values[entry->num_value], XINE_VISUAL_TYPE_X11,
  748. (void *) &(vw->m_x11Visual));
  749. if (!vw->m_videoDriver)
  750. {
  751. vw->m_xineError = i18n("Error: Can't init new Video Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->m_videoDriverName);
  752. QApplication::postEvent(vw, new QTimerEvent( TIMER_EVENT_NEW_XINE_ERROR));
  753. playing = false;
  754. vw->m_videoDriver = xine_open_video_driver(vw->m_xineEngine,
  755. vw->m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
  756. (void *) &(vw->m_x11Visual));
  757. }
  758. else
  759. {
  760. vw->m_videoDriverName = entry->enum_values[entry->num_value];
  761. vw->m_statusString = i18n("Using Video Driver: ") + vw->m_videoDriverName;
  762. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
  763. }
  764. vw->m_xineStream = xine_stream_new(vw->m_xineEngine, vw->m_audioDriver, vw->m_videoDriver);
  765. vw->m_eventQueue = xine_event_new_queue (vw->m_xineStream);
  766. xine_event_create_listener_thread(vw->m_eventQueue, &KXineWidget::xineEventListener, p);
  767. /* rewire filters to the new driver */
  768. vw->unwireVideoFilters();
  769. vw->wireVideoFilters();
  770. /* "none" can now be disposed too */
  771. xine_close_video_driver(vw->m_xineEngine, noneVideoDriver);
  772. vw->initOSD();
  773. if (playing)
  774. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESTART_PLAYBACK));
  775. #endif
  776. }
  777. /*********************** new audio driver *************************/
  778. void KXineWidget::audioDriverChangedCallback(void* p, xine_cfg_entry_t* entry)
  779. {
  780. if (p == NULL) return;
  781. if (entry == NULL) return;
  782. #ifndef USE_QT_ONLY
  783. KXineWidget* vw = (KXineWidget*) p;
  784. int pos, time, length;
  785. debugOut(QString("New audio driver: %1").arg(entry->enum_values[entry->num_value]));
  786. if (vw->m_osd)
  787. {
  788. xine_osd_free(vw->m_osd);
  789. vw->m_osd = NULL;
  790. }
  791. vw->unwireVideoFilters();
  792. bool playing = false;
  793. if (vw->isPlaying())
  794. {
  795. playing = true;
  796. vw->m_savedPos = 0;
  797. int t = 0, ret = 0;
  798. while(((ret = xine_get_pos_length(vw->m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  799. xine_usec_sleep(100000);
  800. if ( ret != 0 )
  801. vw->m_savedPos = pos;
  802. }
  803. xine_close(vw->m_xineStream);
  804. vw->unwireAudioFilters();
  805. if (vw->m_visualPlugin)
  806. {
  807. debugOut(QString("Dispose visual plugin: %1").arg(vw->m_visualPluginName));
  808. delete vw->m_visualPlugin;
  809. vw->m_visualPlugin = NULL;
  810. }
  811. xine_event_dispose_queue(vw->m_eventQueue);
  812. xine_dispose(vw->m_xineStream);
  813. xine_close_audio_driver(vw->m_xineEngine, vw->m_audioDriver);
  814. vw->m_audioDriver = NULL;
  815. vw->m_audioDriver = xine_open_audio_driver(vw->m_xineEngine, entry->enum_values[entry->num_value], NULL);
  816. if (!vw->m_audioDriver)
  817. {
  818. vw->m_xineError = i18n("Error: Can't init new Audio Driver %1 - using %2!").arg(entry->enum_values[entry->num_value]).arg(vw->m_audioDriverName);
  819. QApplication::postEvent(vw, new QTimerEvent( TIMER_EVENT_NEW_XINE_ERROR));
  820. playing = false;
  821. vw->m_audioDriver = xine_open_audio_driver(vw->m_xineEngine, vw->m_audioDriverName.ascii(), NULL);
  822. }
  823. else
  824. {
  825. vw->m_audioDriverName = entry->enum_values[entry->num_value];
  826. vw->m_statusString = i18n("Using Audio Driver: ") + vw->m_audioDriverName;
  827. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_NEW_STATUS));
  828. }
  829. vw->m_xineStream = xine_stream_new(vw->m_xineEngine, vw->m_audioDriver, vw->m_videoDriver);
  830. vw->m_eventQueue = xine_event_new_queue (vw->m_xineStream);
  831. xine_event_create_listener_thread(vw->m_eventQueue, &KXineWidget::xineEventListener, p);
  832. vw->wireVideoFilters();
  833. vw->initOSD();
  834. if (playing)
  835. QApplication::postEvent(vw, new QTimerEvent(TIMER_EVENT_RESTART_PLAYBACK));
  836. #endif
  837. }
  838. /******** change audio mixer method ****************/
  839. void KXineWidget::audioMixerMethodChangedCallback(void* p, xine_cfg_entry_t* entry)
  840. {
  841. if (p == NULL) return;
  842. KXineWidget* vw = (KXineWidget*) p;
  843. vw->m_softwareMixer = (bool)entry->num_value;
  844. }
  845. /******** Callback for OSD configuration ****************/
  846. void KXineWidget::showOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
  847. {
  848. if (p == NULL) return;
  849. KXineWidget* vw = (KXineWidget*) p;
  850. if (vw->m_osd)
  851. vw->m_osdShow = (bool)entry->num_value;
  852. }
  853. void KXineWidget::sizeForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
  854. {
  855. if (p == NULL) return;
  856. KXineWidget* vw = (KXineWidget*) p;
  857. const int fontsizetable[] = { 16,20,24,32,48,64 };
  858. if (entry->num_value >= 6)
  859. {
  860. debugOut("Font size not defined: Shouldn't have happened");
  861. return;
  862. }
  863. if (vw->m_osd)
  864. {
  865. vw->m_osdSize = entry->num_value;
  866. xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]);
  867. }
  868. }
  869. void KXineWidget::fontForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry)
  870. {
  871. if (p == NULL) return;
  872. KXineWidget* vw = (KXineWidget*) p;
  873. const int fontsizetable[] = { 16,20,24,32,48,64 };
  874. if (vw->m_osd)
  875. if (entry->str_value)
  876. {
  877. free(vw->m_osdFont);
  878. vw->m_osdFont = strdup(entry->str_value);
  879. if (!xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]))
  880. {
  881. free(vw->m_osdFont);
  882. vw->m_osdFont = strdup("sans");
  883. if (!xine_osd_set_font(vw->m_osd, vw->m_osdFont, fontsizetable[vw->m_osdSize]))
  884. warningOut("Default SANS font not found: shouldn't have happened.");
  885. }
  886. }
  887. }
  888. /**********************************************
  889. * EVENT LOOP
  890. *********************************************/
  891. void KXineWidget::run()
  892. {
  893. debugOut("Start event loop...");
  894. XEvent event;
  895. while (isXineReady())
  896. {
  897. XNextEvent (m_xineDisplay, &event);
  898. XLockDisplay(m_xineDisplay);
  899. if (event.type == Expose)
  900. {
  901. if (event.xexpose.count == 0)
  902. {
  903. xine_port_send_gui_data(m_videoDriver, XINE_GUI_SEND_EXPOSE_EVENT, &event);
  904. }
  905. }
  906. XUnlockDisplay(m_xineDisplay);
  907. }
  908. debugOut("Exiting event loop...");
  909. }
  910. /**********************************************************
  911. * INIT XINE ENGINE
  912. *********************************************************/
  913. void KXineWidget::polish()
  914. {
  915. if ((!m_startXineManual) && (!isXineReady())) /* start xine engine automatically? */
  916. {
  917. initXine();
  918. }
  919. }
  920. bool KXineWidget::initXine()
  921. {
  922. if (isXineReady())
  923. return true;
  924. emit signalXineStatus(i18n("Init xine..."));
  925. globalPosChanged(); /* get global pos of the window */
  926. /**** INIT XINE DISPLAY ****/
  927. XInitThreads();
  928. m_xineDisplay = XOpenDisplay( getenv("DISPLAY") );
  929. if (!m_xineDisplay)
  930. {
  931. emit signalXineFatal(i18n("Failed to connect to X-Server!"));
  932. return false;
  933. }
  934. m_xineScreen = DefaultScreen(m_xineDisplay);
  935. m_xineWindow = winId();
  936. XLockDisplay(m_xineDisplay);
  937. XSelectInput(m_xineDisplay, m_xineWindow, ExposureMask);
  938. /* determine display aspect ratio */
  939. double resHor = DisplayWidth(m_xineDisplay, m_xineScreen)*1000 / DisplayWidthMM(m_xineDisplay, m_xineScreen);
  940. double resVer = DisplayHeight(m_xineDisplay, m_xineScreen)*1000 / DisplayHeightMM(m_xineDisplay, m_xineScreen);
  941. m_displayRatio = resVer / resHor;
  942. #ifdef HAVE_XINERAMA
  943. int dummy_event, dummy_error;
  944. if (XineramaQueryExtension(m_xineDisplay, &dummy_event, &dummy_error))
  945. {
  946. int count = 1;
  947. debugOut("Xinerama extension present");
  948. XineramaQueryScreens(m_xineDisplay, &count);
  949. debugOut(QString("%1 screens detected").arg(count));
  950. if (count > 1)
  951. /* multihead -> assuming square pixels */
  952. m_displayRatio = 1.0;
  953. }
  954. #endif
  955. debugOut(QString("Display aspect ratio (v/h): %1").arg(m_displayRatio));
  956. XUnlockDisplay(m_xineDisplay);
  957. /**** INIT XINE ENGINE ****/
  958. debugOut(QString("Using xine version %1").arg(xine_get_version_string()));
  959. m_xineEngine = xine_new();
  960. if (!m_xineEngine)
  961. {
  962. emit signalXineFatal(i18n("Can't init xine Engine!"));
  963. return false;
  964. }
  965. if (m_xineVerbose)
  966. xine_engine_set_param(m_xineEngine, XINE_ENGINE_PARAM_VERBOSITY, 99);
  967. /* load configuration */
  968. if (!QFile::exists(m_configFilePath))
  969. warningOut("No config file found, will create one...");
  970. else
  971. xine_config_load(m_xineEngine, m_configFilePath.ascii());
  972. debugOut("Post-init xine engine");
  973. xine_init(m_xineEngine);
  974. /** set xine parameters **/
  975. const char* const* drivers = NULL;
  976. drivers = xine_list_audio_output_plugins(m_xineEngine);
  977. int i = 0;
  978. while (drivers[i] != NULL) i++;
  979. m_audioChoices = new char*[i+2];
  980. m_audioChoices[0] = strdup("auto");
  981. m_audioDriverList << m_audioChoices[0];
  982. i = 0;
  983. while(drivers[i])
  984. {
  985. m_audioChoices[i+1] = strdup(drivers[i]);
  986. m_audioDriverList << m_audioChoices[i+1];
  987. i++;
  988. }
  989. m_audioChoices[i+1] = NULL;
  990. m_audioInfo = strdup(i18n("Audiodriver to use (default: auto)").utf8());
  991. i = xine_config_register_enum(m_xineEngine, "audio.driver", 0,
  992. m_audioChoices, m_audioInfo, NULL, 10, &KXineWidget::audioDriverChangedCallback, this);
  993. if (m_audioDriverList.contains(m_preferedAudio))
  994. m_audioDriverName = m_preferedAudio;
  995. else
  996. m_audioDriverName = m_audioChoices[i];
  997. debugOut(QString("Use audio driver %1").arg(m_audioDriverName));
  998. drivers = xine_list_video_output_plugins(m_xineEngine);
  999. i = 0;
  1000. while (drivers[i] != NULL) i++;
  1001. m_videoChoices = new char*[i+2];
  1002. m_videoChoices[0] = strdup("auto");
  1003. m_videoDriverList << m_videoChoices[0];
  1004. i = 0;
  1005. while(drivers[i])
  1006. {
  1007. m_videoChoices[i+1] = strdup(drivers[i]);
  1008. m_videoDriverList << m_videoChoices[i+1];
  1009. i++;
  1010. }
  1011. m_videoChoices[i+1] = NULL;
  1012. m_videoInfo = strdup(i18n("Videodriver to use (default: auto)").utf8());
  1013. i = xine_config_register_enum(m_xineEngine, "video.driver", 0,
  1014. m_videoChoices, m_videoInfo, NULL, 10, &KXineWidget::videoDriverChangedCallback, this);
  1015. if (m_videoDriverList.contains(m_preferedVideo))
  1016. m_videoDriverName = m_preferedVideo;
  1017. else
  1018. m_videoDriverName = m_videoChoices[i];
  1019. debugOut(QString("Use video driver %1").arg(m_videoDriverName));
  1020. m_mixerInfo = strdup(i18n("Use software audio mixer").utf8());
  1021. m_softwareMixer = (bool)xine_config_register_bool(m_xineEngine, "audio.mixer_software", 1, m_mixerInfo,
  1022. NULL, 10, &KXineWidget::audioMixerMethodChangedCallback, this);
  1023. m_osdShowInfo = strdup(i18n("Show OSD Messages").utf8());
  1024. m_osdShow = (bool)xine_config_register_bool(m_xineEngine, "osd.osd_messages", 1, m_osdShowInfo,
  1025. NULL, 10, &KXineWidget::showOSDMessagesChangedCallback, this);
  1026. m_osdSizeOptions = new char*[7];
  1027. m_osdSizeOptions[0] = strdup("tiny");
  1028. m_osdSizeOptions[1] = strdup("small");
  1029. m_osdSizeOptions[2] = strdup("medium");
  1030. m_osdSizeOptions[3] = strdup("large");
  1031. m_osdSizeOptions[4] = strdup("very large");
  1032. m_osdSizeOptions[5] = strdup("huge");
  1033. m_osdSizeOptions[6] = NULL;
  1034. m_osdSizeInfo = strdup(i18n("Size of OSD text").utf8());
  1035. m_osdSize = (int)xine_config_register_enum(m_xineEngine, "osd.osd_size", 1 /*small - 20P*/, m_osdSizeOptions, m_osdSizeInfo,
  1036. NULL, 10, &KXineWidget::sizeForOSDMessagesChangedCallback, this);
  1037. m_osdFontInfo = strdup(i18n("Font for OSD Messages").utf8());
  1038. m_osdFont = strdup((char*)xine_config_register_string(m_xineEngine, "osd.osd_font", "sans", m_osdFontInfo,
  1039. NULL, 10, &KXineWidget::fontForOSDMessagesChangedCallback, this));
  1040. /* init video driver */
  1041. debugOut("Init video driver");
  1042. m_x11Visual.display = m_xineDisplay;
  1043. m_x11Visual.screen = m_xineScreen;
  1044. m_x11Visual.d = m_xineWindow;
  1045. m_x11Visual.dest_size_cb = &KXineWidget::destSizeCallback;
  1046. m_x11Visual.frame_output_cb = &KXineWidget::frameOutputCallback;
  1047. m_x11Visual.user_data = (void*)this;
  1048. m_videoDriver = xine_open_video_driver(m_xineEngine,
  1049. m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
  1050. (void *) &(m_x11Visual));
  1051. if (!m_videoDriver && m_videoDriverName != "auto")
  1052. {
  1053. emit signalXineError(i18n("Can't init Video Driver '%1' - trying 'auto'...").arg(m_videoDriverName));
  1054. m_videoDriverName = "auto";
  1055. m_videoDriver = xine_open_video_driver(m_xineEngine,
  1056. m_videoDriverName.ascii(), XINE_VISUAL_TYPE_X11,
  1057. (void *) &(m_x11Visual));
  1058. }
  1059. if (!m_videoDriver)
  1060. {
  1061. emit signalXineFatal(i18n("All Video Drivers failed to initialize!"));
  1062. return false;
  1063. }
  1064. /* init audio driver */
  1065. debugOut("Init audio driver");
  1066. m_audioDriver = xine_open_audio_driver(m_xineEngine, m_audioDriverName.ascii(), NULL);
  1067. if (!m_audioDriver && m_audioDriverName != "auto")
  1068. {
  1069. emit signalXineError(i18n("Can't init Audio Driver '%1' - trying 'auto'...").arg(m_audioDriverName));
  1070. m_audioDriverName = "auto";
  1071. m_audioDriver = xine_open_audio_driver (m_xineEngine, m_audioDriverName.ascii(), NULL);
  1072. }
  1073. if (!m_audioDriver)
  1074. {
  1075. emit signalXineFatal(i18n("All Audio Drivers failed to initialize!"));
  1076. return false;
  1077. }
  1078. //debugOut("Open xine stream");
  1079. m_xineStream = xine_stream_new(m_xineEngine, m_audioDriver, m_videoDriver);
  1080. if (!m_xineStream)
  1081. {
  1082. emit signalXineFatal(i18n("Can't create a new xine Stream!"));
  1083. return false;
  1084. }
  1085. #ifdef XINE_PARAM_EARLY_FINISHED_EVENT
  1086. if ( xine_check_version(1,1,1) ) {
  1087. // enable gapless playback
  1088. xine_set_param(m_xineStream, XINE_PARAM_EARLY_FINISHED_EVENT, 1 );
  1089. }
  1090. #endif
  1091. /*** OSD ***/
  1092. initOSD();
  1093. /** event handling **/
  1094. m_eventQueue = xine_event_new_queue (m_xineStream);
  1095. xine_event_create_listener_thread(m_eventQueue, &KXineWidget::xineEventListener, (void*)this);
  1096. //maybe user closed player in muted state
  1097. if (m_softwareMixer)
  1098. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_MUTE, 0);
  1099. else
  1100. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_MUTE, 0);
  1101. m_xineReady = true;
  1102. start();
  1103. debugOut("xine init successful");
  1104. emit signalXineStatus(i18n("Ready"));
  1105. emit signalXineReady();
  1106. /** something to play? **/
  1107. slotPlay();
  1108. return true;
  1109. }
  1110. void KXineWidget::initOSD()
  1111. {
  1112. debugOut("Init OSD");
  1113. const int fontsizetable[] = { 16,20,24,32,48,64 };
  1114. m_osd = xine_osd_new(m_xineStream, 10, 10, 1000, 200);
  1115. if (m_osd)
  1116. {
  1117. if (!xine_osd_set_font(m_osd, m_osdFont, fontsizetable[m_osdSize]))
  1118. {
  1119. debugOut(QString("Font ->%1<- specified for OSD doesn't exists.").arg(m_osdFont));
  1120. free(m_osdFont);
  1121. m_osdFont = strdup("sans");
  1122. xine_osd_set_font(m_osd, m_osdFont, fontsizetable[m_osdSize]);
  1123. }
  1124. debugOut(QString("Font for OSD: %1").arg(m_osdFont));
  1125. xine_osd_set_text_palette(m_osd, XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
  1126. m_osdUnscaled = (xine_osd_get_capabilities(m_osd) & XINE_OSD_CAP_UNSCALED);
  1127. if (m_osdUnscaled)
  1128. debugOut("Unscaled OSD available");
  1129. }
  1130. else
  1131. warningOut("Initialisation of xine OSD failed.");
  1132. }
  1133. /************************************************
  1134. * PLAY MRL
  1135. ************************************************/
  1136. bool KXineWidget::playDvb()
  1137. {
  1138. #ifndef USE_QT_ONLY
  1139. unwireAudioFilters();
  1140. QPtrList<PostFilter> activeList;
  1141. if (m_audioFilterList.count() && m_audioFiltersEnabled)
  1142. activeList = m_audioFilterList;
  1143. if ( !dvbHaveVideo )
  1144. {
  1145. if (!m_visualPlugin)
  1146. {
  1147. debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
  1148. m_visualPlugin = new PostFilter(m_visualPluginName, m_xineEngine, m_audioDriver, m_videoDriver, NULL);
  1149. }
  1150. activeList.insert (0, m_visualPlugin);
  1151. }
  1152. else
  1153. {
  1154. if (m_visualPlugin)
  1155. {
  1156. debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
  1157. delete m_visualPlugin;
  1158. m_visualPlugin = NULL;
  1159. }
  1160. }
  1161. if (activeList.count())
  1162. {
  1163. xine_post_wire_audio_port(activeList.at(activeList.count()-1)->getOutput(), m_audioDriver);
  1164. for (uint i = activeList.count()-1; i >0; i--)
  1165. {
  1166. xine_post_wire(activeList.at(i-1)->getOutput(), activeList.at(i)->getInput());
  1167. }
  1168. xine_post_wire( xine_get_audio_source(m_xineStream), activeList.at(0)->getInput());
  1169. }
  1170. #endif
  1171. if (!xine_play(m_xineStream, 0,0))
  1172. {
  1173. sendXineError();
  1174. return false;
  1175. }
  1176. m_currentSpeed = Normal;
  1177. m_trackHasChapters = false;
  1178. m_trackArtist = QString::null;
  1179. m_trackAlbum = QString::null;
  1180. m_trackNumber = QString::null;
  1181. m_trackYear = QString::null;
  1182. m_trackComment = QString::null;
  1183. m_trackIsSeekable = false;
  1184. if ( !dvbHaveVideo ) m_trackHasVideo = false;
  1185. else m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
  1186. if (m_trackHasVideo)
  1187. {
  1188. m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
  1189. m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
  1190. m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
  1191. m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
  1192. }
  1193. else
  1194. {
  1195. m_trackVideoCodec = QString::null;
  1196. m_videoFrameWidth = 0;
  1197. m_videoFrameHeight = 0;
  1198. m_trackVideoBitrate = 0;
  1199. }
  1200. m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
  1201. if (m_trackHasAudio)
  1202. {
  1203. m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
  1204. m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
  1205. }
  1206. else
  1207. {
  1208. m_trackAudioCodec = QString::null;
  1209. m_trackAudioBitrate = 0;
  1210. }
  1211. m_trackLength = getLengthInfo();
  1212. slotSetAudioChannel(0); //refresh channel info
  1213. m_posTimer.start(1000);
  1214. emit signalXinePlaying();
  1215. emit signalXineStatus(i18n("Playing"));
  1216. return true;
  1217. }
  1218. unsigned int KXineWidget::rgb2yuv( unsigned int R, unsigned int G, unsigned int B )
  1219. {
  1220. return ((((((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));
  1221. }
  1222. void KXineWidget::initDvbPalette()
  1223. {
  1224. if ( dvbColor[0] ) return;
  1225. memset( dvbColor, 0, sizeof(dvbColor) );
  1226. memset( dvbTrans, 0, sizeof(dvbTrans) );
  1227. dvbColor[0]=1;
  1228. unsigned int blueText[11] = {
  1229. rgb2yuv(0,0,0), /* 0 : not used */
  1230. rgb2yuv(0,0,0), /* 1 : font bg */
  1231. rgb2yuv(10,50,40), /* 2 : transition bg->border */
  1232. rgb2yuv(30,100,85), /* 3 */
  1233. rgb2yuv(50,150,130), /* 4 */
  1234. rgb2yuv(70,200,175), /* 5 */
  1235. rgb2yuv(90,255,220), /* 6 : border */
  1236. rgb2yuv(90,255,220), /* 7 : transition border->fg */
  1237. rgb2yuv(90,255,220), /* 8 */
  1238. rgb2yuv(90,255,220), /* 9 */
  1239. rgb2yuv(90,255,220), /* 10 : font fg */
  1240. };
  1241. unsigned int whiteText[11] = {
  1242. rgb2yuv(0,0,0),
  1243. rgb2yuv(0,0,0),
  1244. rgb2yuv(50,50,50),
  1245. rgb2yuv(100,100,100),
  1246. rgb2yuv(150,150,150),
  1247. rgb2yuv(200,200,200),
  1248. rgb2yuv(255,255,255),
  1249. rgb2yuv(255,255,255),
  1250. rgb2yuv(255,255,255),
  1251. rgb2yuv(255,255,255),
  1252. rgb2yuv(255,255,255),
  1253. };
  1254. unsigned int greenText[11] = {
  1255. rgb2yuv(0,0,0),
  1256. rgb2yuv(0,0,0),
  1257. rgb2yuv(30,50,30),
  1258. rgb2yuv(60,100,30),
  1259. rgb2yuv(90,150,90),
  1260. rgb2yuv(120,200,120),
  1261. rgb2yuv(150,255,150),
  1262. rgb2yuv(150,255,150),
  1263. rgb2yuv(150,255,150),
  1264. rgb2yuv(150,255,150),
  1265. rgb2yuv(150,255,150),
  1266. };
  1267. unsigned char textAlpha[11] = { 0, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, };
  1268. #define DVB_TEXT_WHITE 100
  1269. #define DVB_TEXT_BLUE 111
  1270. #define DVB_TEXT_GREEN 122
  1271. int a;
  1272. for ( a=DVB_TEXT_BLUE; a<DVB_TEXT_BLUE+11; a++ )
  1273. {
  1274. dvbColor[a]=blueText[a-DVB_TEXT_BLUE];
  1275. dvbTrans[a]=textAlpha[a-DVB_TEXT_BLUE];
  1276. }
  1277. for ( a=DVB_TEXT_GREEN; a<DVB_TEXT_GREEN+11; a++ )
  1278. {
  1279. dvbColor[a]=greenText[a-DVB_TEXT_GREEN];
  1280. dvbTrans[a]=textAlpha[a-DVB_TEXT_GREEN];
  1281. }
  1282. for ( a=DVB_TEXT_WHITE; a<DVB_TEXT_WHITE+11; a++ )
  1283. {
  1284. dvbColor[a]=whiteText[a-DVB_TEXT_WHITE];
  1285. dvbTrans[a]=textAlpha[a-DVB_TEXT_WHITE];
  1286. }
  1287. #define DVB_COLOR_RED 200
  1288. dvbColor[DVB_COLOR_RED] = rgb2yuv(255,0,0); dvbTrans[DVB_COLOR_RED] = 15;
  1289. #define DVB_COLOR_GREEN 201
  1290. dvbColor[DVB_COLOR_GREEN] = rgb2yuv(0,255,0); dvbTrans[DVB_COLOR_GREEN] = 15;
  1291. #define DVB_COLOR_MAGENTA 202
  1292. dvbColor[DVB_COLOR_MAGENTA] = rgb2yuv(255,128,255); dvbTrans[DVB_COLOR_MAGENTA] = 15;
  1293. }
  1294. void KXineWidget::dvbShowOSD()
  1295. {
  1296. if ( m_trackURL!="DVB" )
  1297. return;
  1298. if ( xine_get_status(m_xineStream)!=XINE_STATUS_PLAY )
  1299. return;
  1300. if ( !dvbHaveVideo )
  1301. m_trackHasVideo = false;
  1302. else
  1303. m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
  1304. if (m_trackHasVideo) {
  1305. m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
  1306. m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
  1307. m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
  1308. m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
  1309. }
  1310. else {
  1311. m_trackVideoCodec = QString::null;
  1312. m_videoFrameWidth = 0;
  1313. m_videoFrameHeight = 0;
  1314. m_trackVideoBitrate = 0;
  1315. }
  1316. m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
  1317. if (m_trackHasAudio) {
  1318. m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
  1319. m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
  1320. }
  1321. else {
  1322. m_trackAudioCodec = QString::null;
  1323. m_trackAudioBitrate = 0;
  1324. }
  1325. if ( dvbOSD ) {
  1326. xine_osd_free( dvbOSD );
  1327. dvbOSD = 0;
  1328. }
  1329. int border=40;
  1330. int w = m_videoFrameWidth;
  1331. int h = m_videoFrameHeight;
  1332. if ( !w || !h )
  1333. return;
  1334. if ( w<800 ) {
  1335. if ( dvbCurrentNext[0]=="E" ) {
  1336. dvbOSDHideTimer.stop();
  1337. dvbOSD = xine_osd_new( m_xineStream, border, border, w-(2*border), h-(2/border) );
  1338. }
  1339. else
  1340. dvbOSD = xine_osd_new( m_xineStream, border, h-border-100, w-(2*border), 100 );
  1341. }
  1342. if ( dvbOSD ) {
  1343. QCString ct, cs;
  1344. if ( !dvbColor[0] ) initDvbPalette();
  1345. //xine_osd_get_palette( dvbOSD, dvbColor, dvbTrans );
  1346. xine_osd_set_palette( dvbOSD, dvbColor, dvbTrans );
  1347. xine_osd_set_font( dvbOSD, m_osdFont, 16 );
  1348. xine_osd_set_encoding( dvbOSD, "utf-8" );
  1349. if ( dvbCurrentNext[0]=="E" )
  1350. xine_osd_draw_rect( dvbOSD, 0, 0, w-(2*border), h-(2*border), DVB_TEXT_WHITE+1, 1 );
  1351. else
  1352. xine_osd_draw_rect( dvbOSD, 0, 0, w-(2*border), 100, DVB_TEXT_WHITE+1, 1 );
  1353. QString t = QTime::currentTime().toString( "hh:mm" );
  1354. int tw, th, len;
  1355. xine_osd_get_text_size(dvbOSD, t.utf8(), &tw, &th);
  1356. len = tw;
  1357. int offset = 5;
  1358. xine_osd_draw_text( dvbOSD, w-(2*border)-tw-offset, 5, t.utf8(), DVB_TEXT_BLUE );
  1359. int i;
  1360. for ( i=0; i<(int)dvbCurrentNext.count(); i++ ) {
  1361. if ( dvbCurrentNext[i]=="R" ) {
  1362. xine_osd_draw_rect( dvbOSD, offset, 5, offset+16, 21, DVB_COLOR_RED, 1 );
  1363. offset+=21;
  1364. }
  1365. else if ( dvbCurrentNext[i]=="T" ) {
  1366. xine_osd_draw_rect( dvbOSD, offset, 5, offset+16, 21, DVB_COLOR_GREEN, 1 );
  1367. offset+=21;
  1368. }
  1369. }
  1370. if (m_dvbChannelName == "")
  1371. t = m_trackTitle;
  1372. else
  1373. t = m_dvbChannelName;
  1374. i=0;
  1375. ct = t.utf8();
  1376. while ( i<(int)t.length() ) {
  1377. xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
  1378. if ( tw<=(w-(2*border)-offset-5-len) ) break;
  1379. ct = ct.remove( ct.length()-1, ct.length() );
  1380. i++;
  1381. }
  1382. xine_osd_draw_text( dvbOSD, offset, 5, ct, DVB_TEXT_BLUE );
  1383. xine_osd_draw_line( dvbOSD, 5, 10+18, w-(2*border)-5, 10+18, DVB_COLOR_MAGENTA );
  1384. QString s, c;
  1385. int y=43;
  1386. int pos;
  1387. if ( dvbCurrentNext[0]=="E" ) {
  1388. if ( dvbCurrentNext.count()<2 ) {
  1389. xine_osd_show( dvbOSD, 0 );
  1390. return;
  1391. }
  1392. if ( !dvbCurrentNext[1].isEmpty() ) {
  1393. s = dvbCurrentNext[1];
  1394. pos = s.find("-");
  1395. c = s.left( pos+1 );
  1396. s = s.right( s.length()-pos-1 );
  1397. t = s;
  1398. xine_osd_draw_text( dvbOSD, 10, y, c.utf8(), DVB_TEXT_GREEN );
  1399. xine_osd_get_text_size( dvbOSD, c.utf8(), &offset, &th );
  1400. i=0;
  1401. cs = s.utf8();
  1402. while ( i<(int)t.length() ) {
  1403. ct = cs.remove( cs.length()-i, cs.length() );
  1404. xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
  1405. if ( tw<=(w-(2*border)-20) ) break;
  1406. i++;
  1407. }
  1408. xine_osd_draw_text( dvbOSD, 10+offset, y, ct, DVB_TEXT_WHITE );
  1409. y+= 40;
  1410. }
  1411. if ( !dvbCurrentNext[2].isEmpty() ) {
  1412. cs = dvbCurrentNext[2].utf8();
  1413. pos = 0;
  1414. while ( pos!=-1 && y<(h-(2*border)-23) ) {
  1415. ct = cs;
  1416. i = 0;
  1417. while ( pos!=-1 ) {
  1418. xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
  1419. if ( tw<=(w-(2*border)-20) ) break;
  1420. pos = ct.findRev(" ");
  1421. ct = ct.left( pos );
  1422. i++;
  1423. }
  1424. xine_osd_draw_text( dvbOSD, 10, y, ct, DVB_TEXT_BLUE );
  1425. if ( !ct.length() || !i ) break;
  1426. cs = cs.right( cs.length()-ct.length()-1 );
  1427. y+= 28;
  1428. }
  1429. y+= 40;
  1430. }
  1431. if ( !dvbCurrentNext[3].isEmpty() ) {
  1432. cs = dvbCurrentNext[3].utf8();
  1433. pos = 0;
  1434. while ( pos!=-1 && y<(h-(2*border)-23) ) {
  1435. ct = cs;
  1436. i = 0;
  1437. while ( pos!=-1 ) {
  1438. xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
  1439. if ( tw<=(w-(2*border)-20) ) break;
  1440. pos = ct.findRev(" ");
  1441. ct = ct.left( pos );
  1442. i++;
  1443. }
  1444. xine_osd_draw_text( dvbOSD, 10, y, ct, DVB_TEXT_WHITE );
  1445. if ( !ct.length() || !i ) break;
  1446. cs = cs.right( cs.length()-ct.length()-1 );
  1447. y+= 28;
  1448. }
  1449. }
  1450. xine_osd_show( dvbOSD, 0 );
  1451. return;
  1452. }
  1453. for ( int j=0; j<(int)dvbCurrentNext.count(); j++ ) {
  1454. if ( (dvbCurrentNext[ j ]=="T") || (dvbCurrentNext[ j ]=="R") ) continue;
  1455. s = dvbCurrentNext[ j ];
  1456. pos = s.find("-");
  1457. c = s.left( pos+1 );
  1458. s = s.right( s.length()-pos-1 );
  1459. ct = cs = s.utf8();
  1460. xine_osd_draw_text( dvbOSD, 10, y, c.utf8(), DVB_TEXT_GREEN );
  1461. xine_osd_get_text_size( dvbOSD, c.utf8(), &offs

Large files files are truncated, but you can click here to view the full file