PageRenderTime 39ms CodeModel.GetById 28ms RepoModel.GetById 0ms 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
  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(), &offset, &th );
  1462. i=0;
  1463. while ( i<(int)t.length() ) {
  1464. ct = cs.remove( cs.length()-i, cs.length() );
  1465. xine_osd_get_text_size( dvbOSD, ct, &tw, &th );
  1466. if ( tw<=(w-(2*border)-20) ) break;
  1467. i++;
  1468. }
  1469. xine_osd_draw_text( dvbOSD, 10+offset, y, ct, DVB_TEXT_WHITE );
  1470. y+= 28;
  1471. }
  1472. xine_osd_show( dvbOSD, 0 );
  1473. dvbOSDHideTimer.start( 5000, true );
  1474. }
  1475. }
  1476. void KXineWidget::dvbHideOSD()
  1477. {
  1478. if ( dvbOSD ) {
  1479. xine_osd_hide( dvbOSD, 0 );
  1480. xine_osd_free( dvbOSD );
  1481. dvbOSD = 0;
  1482. if (m_dvbChannelName != "")
  1483. m_dvbChannelName = "";
  1484. emit signalDvbOSDHidden();
  1485. }
  1486. }
  1487. void KXineWidget::setDvbCurrentNext( const QString &channelName, const QStringList &list )
  1488. {
  1489. if ( list[0]=="STOP" ) {
  1490. dvbHideOSD();
  1491. return;
  1492. }
  1493. dvbCurrentNext = list;
  1494. m_dvbChannelName = channelName;
  1495. QTimer::singleShot( 0, this, SLOT(dvbShowOSD()) );
  1496. }
  1497. void KXineWidget::setDvb( const QString &pipeName, const QString &chanName, int haveVideo )
  1498. {
  1499. m_trackURL = pipeName;
  1500. m_trackTitle = chanName;
  1501. dvbHaveVideo = haveVideo;
  1502. }
  1503. bool KXineWidget::openDvb()
  1504. {
  1505. if ( dvbOSD ) {
  1506. dvbOSDHideTimer.stop();
  1507. xine_osd_hide( dvbOSD, 0 );
  1508. xine_osd_free( dvbOSD );
  1509. dvbOSD = 0;
  1510. }
  1511. clearQueue();
  1512. m_lengthInfoTimer.stop();
  1513. m_posTimer.stop();
  1514. xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 180000);
  1515. if (!xine_open(m_xineStream, m_trackURL.ascii())) {
  1516. sendXineError();
  1517. return false;
  1518. }
  1519. else fprintf(stderr,"xine pipe opened\n");
  1520. m_trackURL = "DVB";
  1521. emit signalXineStatus(i18n("DVB: opening..."));
  1522. QTimer::singleShot( 0, this, SLOT(playDvb()) );
  1523. return true;
  1524. }
  1525. void KXineWidget::slotPlayTimeShift()
  1526. {
  1527. m_lengthInfoTimer.stop();
  1528. m_posTimer.stop();
  1529. xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 0);
  1530. if (!xine_open(m_xineStream, TimeShiftFilename.ascii())) {
  1531. sendXineError();
  1532. #ifdef XINE_PARAM_GAPLESS_SWITCH
  1533. if ( xine_check_version(1,1,1) )
  1534. xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 0);
  1535. #endif
  1536. return;
  1537. }
  1538. if (!xine_play(m_xineStream, 0,0)) {
  1539. sendXineError();
  1540. return;
  1541. }
  1542. m_trackIsSeekable = true;
  1543. m_lengthInfoTimer.start(1000);
  1544. m_posTimer.start(1000);
  1545. }
  1546. void KXineWidget::slotPlay()
  1547. {
  1548. if ((!isXineReady()) || (isQueueEmpty()))
  1549. return;
  1550. if (m_logoFile != NULL && m_trackURL == m_logoFile && isPlaying())
  1551. return;
  1552. /* dvb */
  1553. if ( dvbOSD ) {
  1554. dvbOSDHideTimer.stop();
  1555. xine_osd_hide( dvbOSD, 0 );
  1556. xine_osd_free( dvbOSD );
  1557. dvbOSD = 0;
  1558. }
  1559. m_lengthInfoTimer.stop();
  1560. m_posTimer.stop();
  1561. m_currentSpeed = Normal;
  1562. setCursor(QCursor(Qt::WaitCursor));
  1563. m_trackURL = m_queue.first();
  1564. m_queue.remove(m_queue.find(m_trackURL));
  1565. if (m_trackURL != m_logoFile)
  1566. emit signalXineStatus(i18n("Opening..."));
  1567. /* check for external subtitle file or save url */
  1568. m_trackSubtitleURL = QString::null;
  1569. m_trackSaveURL = QString::null;
  1570. QString ref;
  1571. for (int i = 1; i <= m_trackURL.contains('#'); i++) {
  1572. ref = m_trackURL.section('#', i, i);
  1573. if (ref.section(':', 0, 0) == "subtitle")
  1574. m_trackSubtitleURL = ref.section(':', 1);
  1575. if (ref.section(':', 0, 0) == "save")
  1576. m_trackSaveURL = ref.section(':', 1);
  1577. }
  1578. debugOut(QString("Playing: %1").arg(m_trackURL.local8Bit()));
  1579. xine_set_param( m_xineStream, XINE_PARAM_METRONOM_PREBUFFER, 12000 );
  1580. if (!xine_open(m_xineStream, m_trackURL.local8Bit())) {/** pass mrl local 8Bit encoded **/
  1581. sendXineError();
  1582. setCursor(QCursor(Qt::ArrowCursor));
  1583. #ifdef XINE_PARAM_GAPLESS_SWITCH
  1584. if ( xine_check_version(1,1,1) )
  1585. xine_set_param( m_xineStream, XINE_PARAM_GAPLESS_SWITCH, 0);
  1586. #endif
  1587. return;
  1588. }
  1589. /**** use visualization ? ****/
  1590. #ifndef USE_QT_ONLY
  1591. unwireAudioFilters();
  1592. wireAudioFilters();
  1593. #else
  1594. if ((xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO)) &&
  1595. (!xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)))
  1596. {
  1597. if (m_visualPluginName && (!m_xinePost))
  1598. {
  1599. debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
  1600. m_xinePost = xine_post_init(m_xineEngine, m_visualPluginName, 0,
  1601. &m_audioDriver,
  1602. &m_videoDriver);
  1603. m_postAudioSource = xine_get_audio_source(m_xineStream);
  1604. m_postInput = (xine_post_in_t*)xine_post_input (m_xinePost, const_cast<char*>("audio in"));
  1605. xine_post_wire(m_postAudioSource, m_postInput);
  1606. }
  1607. }
  1608. else
  1609. {
  1610. if (m_xinePost)
  1611. {
  1612. debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
  1613. m_postAudioSource = xine_get_audio_source(m_xineStream);
  1614. xine_post_wire_audio_port(m_postAudioSource, m_audioDriver);
  1615. xine_post_dispose(m_xineEngine, m_xinePost);
  1616. m_xinePost = NULL;
  1617. }
  1618. }
  1619. #endif
  1620. /*** play ***/
  1621. int savedPos = m_savedPos;
  1622. m_savedPos = 0;
  1623. if (!xine_play(m_xineStream, savedPos, 0))
  1624. {
  1625. sendXineError();
  1626. setCursor(QCursor(Qt::ArrowCursor));
  1627. return;
  1628. }
  1629. /* do the stream have chapters ? */
  1630. m_trackHasChapters = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_CHAPTERS);
  1631. /** information requirement **/
  1632. m_trackTitle = QString::null;
  1633. bool currentUtf8Locale;
  1634. QTextCodec* testUtf8Local = QTextCodec::codecForLocale();
  1635. if (!strcmp(testUtf8Local->name(),"UTF-8"))
  1636. currentUtf8Locale = true;
  1637. else
  1638. currentUtf8Locale = false;
  1639. QTextCodec *CodecUtf8;
  1640. CodecUtf8 = QTextCodec::codecForName("UTF-8");
  1641. QString infotag;
  1642. infotag = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_TITLE));
  1643. if (currentUtf8Locale)
  1644. m_trackTitle = infotag;
  1645. else
  1646. m_trackTitle = QString::fromLocal8Bit(infotag.ascii());
  1647. if (CodecUtf8->heuristicContentMatch(infotag.ascii(), infotag.length()) >= 0)
  1648. m_trackTitle = QString::fromUtf8(infotag.ascii());
  1649. if ((!m_trackTitle.isNull()) && (!m_trackTitle.isEmpty())) /* no meta? */
  1650. {
  1651. QString trackArtist=NULL;
  1652. QString trackAlbum=NULL;
  1653. QString trackComment=NULL;
  1654. trackArtist = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ARTIST));
  1655. trackAlbum = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_ALBUM));
  1656. trackComment = QString::fromLatin1(xine_get_meta_info(m_xineStream, XINE_META_INFO_COMMENT));
  1657. if (currentUtf8Locale)
  1658. {
  1659. m_trackArtist = trackArtist;
  1660. m_trackAlbum = trackAlbum;
  1661. m_trackComment = trackComment;
  1662. }
  1663. else
  1664. {
  1665. m_trackArtist = QString::fromLocal8Bit(trackArtist.ascii());
  1666. m_trackAlbum = QString::fromLocal8Bit(trackAlbum.ascii());
  1667. m_trackComment = QString::fromLocal8Bit(trackComment.ascii());
  1668. }
  1669. if (CodecUtf8->heuristicContentMatch(trackArtist.ascii(), trackArtist.length()) >= 0)
  1670. m_trackArtist = QString::fromUtf8(trackArtist.ascii());
  1671. if (CodecUtf8->heuristicContentMatch(trackAlbum.ascii(), trackAlbum.length()) >= 0)
  1672. m_trackAlbum = QString::fromUtf8(trackAlbum.ascii());
  1673. if (CodecUtf8->heuristicContentMatch(trackComment.ascii(), trackComment.length()) >= 0)
  1674. m_trackComment = QString::fromUtf8(trackComment.ascii());
  1675. m_trackYear = xine_get_meta_info(m_xineStream, XINE_META_INFO_YEAR);
  1676. m_trackNumber = xine_get_meta_info(m_xineStream, XINE_META_INFO_TRACK_NUMBER);
  1677. }
  1678. else
  1679. {
  1680. m_trackArtist = QString::null;
  1681. m_trackAlbum = QString::null;
  1682. m_trackNumber = QString::null;
  1683. m_trackYear = QString::null;
  1684. m_trackComment = QString::null;
  1685. }
  1686. m_trackHasVideo = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO);
  1687. if (m_trackHasVideo)
  1688. {
  1689. m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
  1690. m_videoFrameWidth = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
  1691. m_videoFrameHeight = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
  1692. m_trackVideoBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_BITRATE);
  1693. }
  1694. else
  1695. {
  1696. m_trackVideoCodec = QString::null;
  1697. m_videoFrameWidth = 0;
  1698. m_videoFrameHeight = 0;
  1699. m_trackVideoBitrate = 0;
  1700. }
  1701. m_trackHasAudio = (bool)xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_AUDIO);
  1702. if (m_trackHasAudio)
  1703. {
  1704. m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
  1705. m_trackAudioBitrate = xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_AUDIO_BITRATE);
  1706. }
  1707. else
  1708. {
  1709. m_trackAudioCodec = QString::null;
  1710. m_trackAudioBitrate = 0;
  1711. }
  1712. /*** we need a little delay for some meta info ***/
  1713. QTimer::singleShot(1000, this, SLOT(slotGetInfoDelayed()));
  1714. m_trackLength = getLengthInfo();
  1715. if ((m_trackLength.isNull()) && (m_trackURL != m_logoFile))
  1716. {
  1717. debugOut("Wait for valid length information");
  1718. m_lengthInfoTries = 0;
  1719. m_lengthInfoTimer.start(1000); /* wait for available track length info */
  1720. }
  1721. if (m_trackTitle.isNull() || m_trackTitle.isEmpty())
  1722. {
  1723. /* no meta info */
  1724. m_trackTitle = m_trackURL;
  1725. }
  1726. slotSetAudioChannel(0); //refresh channel info
  1727. if (m_trackURL != m_logoFile)
  1728. m_posTimer.start(500);
  1729. setCursor(QCursor(Qt::ArrowCursor));
  1730. if (m_trackURL != m_logoFile)
  1731. {
  1732. emit signalXinePlaying();
  1733. if (hasSaveURL())
  1734. emit signalXineStatus(i18n("Recording"));
  1735. else
  1736. emit signalXineStatus(i18n("Playing"));
  1737. }
  1738. }
  1739. int KXineWidget::getVideoWidth()
  1740. {
  1741. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_WIDTH);
  1742. }
  1743. int KXineWidget::getVideoHeight()
  1744. {
  1745. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_VIDEO_HEIGHT);
  1746. }
  1747. void KXineWidget::slotGetInfoDelayed()
  1748. {
  1749. if (!m_xineStream)
  1750. return;
  1751. if (m_trackHasVideo)
  1752. m_trackVideoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
  1753. if (m_trackHasAudio)
  1754. m_trackAudioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
  1755. }
  1756. /****** error processing ****/
  1757. void KXineWidget::sendXineError()
  1758. {
  1759. QString error;
  1760. int errCode = xine_get_error(m_xineStream);
  1761. QString addInfo;
  1762. QString audioCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_AUDIOCODEC);
  1763. QString videoCodec = xine_get_meta_info(m_xineStream, XINE_META_INFO_VIDEOCODEC);
  1764. if ((!audioCodec.isEmpty()) || (!videoCodec.isEmpty()))
  1765. {
  1766. if (!audioCodec.isEmpty())
  1767. addInfo.append(QString("(") + i18n("Audio Codec") + ": " + audioCodec + ")");
  1768. if (!videoCodec.isEmpty())
  1769. addInfo.append(QString("(") + i18n("Video Codec") + ": " + videoCodec + ")");
  1770. }
  1771. else
  1772. addInfo.append(QString("(") + m_trackURL + ")");
  1773. switch (errCode)
  1774. {
  1775. case XINE_ERROR_NO_INPUT_PLUGIN:
  1776. case XINE_ERROR_NO_DEMUX_PLUGIN:
  1777. {
  1778. error = i18n("No plugin found to handle this resource") + " " + addInfo;
  1779. break;
  1780. }
  1781. case XINE_ERROR_DEMUX_FAILED:
  1782. {
  1783. error = i18n("Resource seems to be broken") + " (" + m_trackURL + ")";
  1784. break;
  1785. }
  1786. case XINE_ERROR_MALFORMED_MRL:
  1787. {
  1788. error = i18n("Requested resource does not exist") + " (" + m_trackURL + ")";
  1789. break;
  1790. }
  1791. case XINE_ERROR_INPUT_FAILED:
  1792. {
  1793. error = i18n("Resource can not be opened") + " (" + m_trackURL + ")";
  1794. break;
  1795. }
  1796. default:
  1797. {
  1798. error = i18n("Generic error") + " (" + m_trackURL + ")";
  1799. break;
  1800. }
  1801. }
  1802. if (isQueueEmpty())
  1803. {
  1804. if (m_trackURL != m_logoFile)
  1805. {
  1806. emit signalXineStatus(i18n("Error"));
  1807. emit signalXineError(error);
  1808. }
  1809. else
  1810. errorOut("Can't find/play logo file!");
  1811. }
  1812. else
  1813. {
  1814. errorOut(error);
  1815. errorOut(QString("Can't play: %1 - trying next").arg(m_trackURL));
  1816. QTimer::singleShot(0, this, SLOT(slotPlay()));
  1817. }
  1818. }
  1819. bool KXineWidget::isPlaying() const
  1820. {
  1821. if (isXineReady())
  1822. return ((xine_get_status(m_xineStream) == XINE_STATUS_PLAY) && (m_trackURL != m_logoFile));
  1823. else
  1824. return false;
  1825. }
  1826. QString KXineWidget::getXineLog() const
  1827. {
  1828. QString logStr;
  1829. int i = 0;
  1830. QTextStream ts(&logStr, IO_WriteOnly);
  1831. const char* const* log = xine_get_log(m_xineEngine, /* XINE_LOG_MSG*/ 0);
  1832. while(log[i])
  1833. {
  1834. ts << QString::fromLocal8Bit(log[i]);
  1835. i++;
  1836. }
  1837. return logStr;
  1838. }
  1839. void KXineWidget::showOSDMessage(const QString& message, uint duration, int priority)
  1840. {
  1841. if ((!m_osd) || (!m_osdShow) || (isHidden()))
  1842. return;
  1843. static int prevOsdPriority = 0;
  1844. if (m_osdTimer.isActive() && prevOsdPriority > priority)
  1845. return;
  1846. prevOsdPriority = priority;
  1847. //debugOut(QString("OSD: draw text: %1").arg(message));
  1848. xine_osd_clear(m_osd);
  1849. xine_osd_draw_text(m_osd, 0, 0, message.local8Bit(), XINE_OSD_TEXT1);
  1850. if (m_osdUnscaled)
  1851. xine_osd_show_unscaled(m_osd, 0);
  1852. else
  1853. xine_osd_show(m_osd, 0);
  1854. m_osdTimer.start(duration);
  1855. }
  1856. void KXineWidget::slotOSDHide()
  1857. {
  1858. xine_osd_hide(m_osd, 0);
  1859. m_osdTimer.stop();
  1860. }
  1861. #ifndef USE_QT_ONLY
  1862. /****************** postprocessing filter management ****************/
  1863. QStringList KXineWidget::getVideoFilterNames() const
  1864. {
  1865. QStringList filters;
  1866. const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_VIDEO_FILTER);
  1867. for (int i = 0; plugins[i]; i++)
  1868. {
  1869. filters << plugins[i];
  1870. }
  1871. return filters;
  1872. }
  1873. QStringList KXineWidget::getAudioFilterNames() const
  1874. {
  1875. QStringList filters;
  1876. const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_AUDIO_FILTER);
  1877. for (int i = 0; plugins[i]; i++)
  1878. {
  1879. filters << plugins[i];
  1880. }
  1881. return filters;
  1882. }
  1883. #endif
  1884. void KXineWidget::slotCreateVideoFilter(const QString& name, QWidget* parent)
  1885. {
  1886. #ifndef USE_QT_ONLY
  1887. unwireVideoFilters();
  1888. PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
  1889. connect(filter, SIGNAL(signalDeleteMe(PostFilter*)), this, SLOT(slotDeleteVideoFilter(PostFilter*)));
  1890. m_videoFilterList.append(filter);
  1891. wireVideoFilters();
  1892. #else
  1893. parent = parent;
  1894. warningOut(QString("Not implemented [CreateVideoFilter %1]").arg(name));
  1895. #endif
  1896. }
  1897. void KXineWidget::slotCreateAudioFilter(const QString& name, QWidget* parent)
  1898. {
  1899. #ifndef USE_QT_ONLY
  1900. unwireAudioFilters();
  1901. PostFilter* filter = new PostFilter(name, m_xineEngine, m_audioDriver, m_videoDriver, parent);
  1902. connect(filter, SIGNAL(signalDeleteMe(PostFilter*)), this, SLOT(slotDeleteAudioFilter(PostFilter*)));
  1903. m_audioFilterList.append(filter);
  1904. wireAudioFilters();
  1905. #else
  1906. parent = parent;
  1907. warningOut(QString("Not implemented [CreateAudioFilter %1]").arg(name));
  1908. #endif
  1909. }
  1910. void KXineWidget::slotRemoveAllVideoFilters()
  1911. {
  1912. #ifndef USE_QT_ONLY
  1913. unwireVideoFilters();
  1914. while (m_videoFilterList.count())
  1915. m_videoFilterList.removeLast();
  1916. wireVideoFilters();
  1917. #else
  1918. warningOut("Not implemented!");
  1919. #endif
  1920. }
  1921. void KXineWidget::slotRemoveAllAudioFilters()
  1922. {
  1923. #ifndef USE_QT_ONLY
  1924. unwireAudioFilters();
  1925. while (m_audioFilterList.count())
  1926. m_audioFilterList.removeLast();
  1927. wireAudioFilters();
  1928. #else
  1929. warningOut("Not implemented!");
  1930. #endif
  1931. }
  1932. void KXineWidget::slotDeleteVideoFilter(PostFilter* filter)
  1933. {
  1934. #ifndef USE_QT_ONLY
  1935. unwireVideoFilters();
  1936. m_videoFilterList.remove(filter);
  1937. wireVideoFilters();
  1938. #else
  1939. filter = filter;
  1940. warningOut("Not implemented!");
  1941. #endif
  1942. }
  1943. void KXineWidget::slotDeleteAudioFilter(PostFilter* filter)
  1944. {
  1945. #ifndef USE_QT_ONLY
  1946. unwireAudioFilters();
  1947. m_audioFilterList.remove(filter);
  1948. wireAudioFilters();
  1949. #else
  1950. filter = filter;
  1951. warningOut("Not implemented!");
  1952. #endif
  1953. }
  1954. #ifndef USE_QT_ONLY
  1955. void KXineWidget::unwireVideoFilters()
  1956. {
  1957. if (m_xineStream && m_videoDriver)
  1958. xine_post_wire_video_port(xine_get_video_source(m_xineStream), m_videoDriver);
  1959. }
  1960. void KXineWidget::wireVideoFilters()
  1961. {
  1962. if (!m_xineStream)
  1963. {
  1964. debugOut("wireVideoFilters() - xine stream not initialized, nothing happend.");
  1965. return;
  1966. }
  1967. QPtrList<PostFilter> activeList;
  1968. if (m_videoFilterList.count() && m_videoFiltersEnabled)
  1969. activeList = m_videoFilterList;
  1970. if (m_deinterlaceFilter && m_deinterlaceEnabled )
  1971. activeList.insert (0, m_deinterlaceFilter);
  1972. if (activeList.count())
  1973. {
  1974. xine_post_wire_video_port(activeList.at(activeList.count()-1)->getOutput(), m_videoDriver);
  1975. for (uint i = activeList.count()-1; i >0; i--)
  1976. {
  1977. xine_post_wire(activeList.at( i-1 )->getOutput(), activeList.at(i)->getInput());
  1978. }
  1979. xine_post_wire( xine_get_video_source(m_xineStream), activeList.at(0)->getInput());
  1980. }
  1981. }
  1982. void KXineWidget::unwireAudioFilters()
  1983. {
  1984. if (m_xineStream && m_audioDriver)
  1985. xine_post_wire_audio_port( xine_get_audio_source (m_xineStream), m_audioDriver);
  1986. }
  1987. void KXineWidget::wireAudioFilters()
  1988. {
  1989. if (!m_xineStream)
  1990. {
  1991. debugOut("wireAudioFilters() - xine stream not initialized, nothing happend.");
  1992. return;
  1993. }
  1994. QPtrList<PostFilter> activeList;
  1995. if (m_audioFilterList.count() && m_audioFiltersEnabled)
  1996. activeList = m_audioFilterList;
  1997. if ((xine_get_stream_info (m_xineStream, XINE_STREAM_INFO_HAS_AUDIO)) &&
  1998. (!xine_get_stream_info (m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)) &&
  1999. m_visualPluginName.ascii())
  2000. {
  2001. if (!m_visualPlugin)
  2002. {
  2003. debugOut(QString("Init visual plugin: %1").arg(m_visualPluginName));
  2004. m_visualPlugin = new PostFilter(m_visualPluginName, m_xineEngine, m_audioDriver, m_videoDriver, NULL);
  2005. }
  2006. activeList.insert (0, m_visualPlugin);
  2007. }
  2008. else
  2009. {
  2010. if (m_visualPlugin)
  2011. {
  2012. debugOut(QString("Dispose visual plugin: %1").arg(m_visualPluginName));
  2013. delete m_visualPlugin;
  2014. m_visualPlugin = NULL;
  2015. }
  2016. }
  2017. if (activeList.count())
  2018. {
  2019. xine_post_wire_audio_port(activeList.at(activeList.count()-1)->getOutput(), m_audioDriver);
  2020. for (uint i = activeList.count()-1; i >0; i--)
  2021. {
  2022. xine_post_wire(activeList.at(i-1)->getOutput(), activeList.at(i)->getInput());
  2023. }
  2024. xine_post_wire( xine_get_audio_source(m_xineStream), activeList.at(0)->getInput());
  2025. }
  2026. }
  2027. #endif
  2028. void KXineWidget::slotEnableVideoFilters(bool enable)
  2029. {
  2030. #ifndef USE_QT_ONLY
  2031. m_videoFiltersEnabled = enable;
  2032. unwireVideoFilters();
  2033. wireVideoFilters();
  2034. #else
  2035. enable = enable;
  2036. warningOut("Not implemented!");
  2037. #endif
  2038. }
  2039. void KXineWidget::slotEnableAudioFilters(bool enable)
  2040. {
  2041. #ifndef USE_QT_ONLY
  2042. m_audioFiltersEnabled = enable;
  2043. unwireAudioFilters();
  2044. wireAudioFilters();
  2045. #else
  2046. enable = enable;
  2047. warningOut("Not implemented!");
  2048. #endif
  2049. }
  2050. #ifndef USE_QT_ONLY
  2051. QStringList KXineWidget::getAudioFilterConfig()
  2052. {
  2053. QStringList configStrings;
  2054. for (uint i=0; i<m_audioFilterList.count(); i++)
  2055. configStrings << m_audioFilterList.at(i)->getConfig();
  2056. return configStrings;
  2057. }
  2058. QStringList KXineWidget::getVideoFilterConfig()
  2059. {
  2060. QStringList configStrings;
  2061. for (uint i=0; i<m_videoFilterList.count(); i++)
  2062. configStrings << m_videoFilterList.at(i)->getConfig();
  2063. return configStrings;
  2064. }
  2065. #endif
  2066. /**** visual plugin **********/
  2067. QStringList KXineWidget::getVisualPlugins() const
  2068. {
  2069. QStringList visuals;
  2070. const char* const* plugins = xine_list_post_plugins_typed(m_xineEngine, XINE_POST_TYPE_AUDIO_VISUALIZATION);
  2071. for (int i = 0; plugins[i]; i++)
  2072. {
  2073. visuals << plugins[i];
  2074. }
  2075. return visuals;
  2076. }
  2077. /**************** change visualization plugin *****************/
  2078. void KXineWidget::slotSetVisualPlugin(const QString& visual)
  2079. {
  2080. if (m_visualPluginName == visual) return;
  2081. debugOut(QString("New visualization plugin: %1").arg(visual));
  2082. #ifndef USE_QT_ONLY
  2083. unwireAudioFilters();
  2084. if(m_visualPlugin)
  2085. {
  2086. delete m_visualPlugin;
  2087. m_visualPlugin = NULL;
  2088. }
  2089. if (visual == "none")
  2090. m_visualPluginName = QString::null;
  2091. else
  2092. m_visualPluginName = visual;
  2093. wireAudioFilters();
  2094. #else
  2095. if (visual == "none")
  2096. m_visualPluginName = QString::null;
  2097. else
  2098. m_visualPluginName = visual;
  2099. if (m_xinePost)
  2100. {
  2101. xine_post_out_t *pp;
  2102. pp = xine_get_audio_source(m_xineStream);
  2103. xine_post_wire_audio_port(pp, m_audioDriver);
  2104. xine_post_dispose(m_xineEngine, m_xinePost);
  2105. m_xinePost = NULL;
  2106. }
  2107. if ( (xine_get_status(m_xineStream ) == XINE_STATUS_PLAY)
  2108. && (!xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_HAS_VIDEO)) && (m_visualPluginName) )
  2109. {
  2110. m_xinePost = xine_post_init(m_xineEngine, m_visualPluginName, 0, &m_audioDriver, &m_videoDriver);
  2111. m_postAudioSource = xine_get_audio_source(m_xineStream);
  2112. m_postInput = (xine_post_in_t*)xine_post_input(m_xinePost, const_cast<char*>("audio in"));
  2113. xine_post_wire(m_postAudioSource, m_postInput);
  2114. }
  2115. #endif
  2116. }
  2117. /*****/
  2118. void KXineWidget::getAutoplayPlugins(QStringList& autoPlayList) const
  2119. {
  2120. char** pluginIds = NULL;
  2121. int i = 0;
  2122. pluginIds = (char**)xine_get_autoplay_input_plugin_ids(m_xineEngine);
  2123. while(pluginIds[i])
  2124. {
  2125. autoPlayList << pluginIds[i];
  2126. autoPlayList << xine_get_input_plugin_description(m_xineEngine, pluginIds[i]);
  2127. i++;
  2128. }
  2129. }
  2130. bool KXineWidget::getAutoplayPluginURLS(const QString& plugin, QStringList& list)
  2131. {
  2132. char** urls = NULL;
  2133. int num;
  2134. int i = 0;
  2135. urls = xine_get_autoplay_mrls(m_xineEngine, plugin.ascii(), &num);
  2136. if (urls)
  2137. {
  2138. while (urls[i])
  2139. {
  2140. list << urls[i];
  2141. i++;
  2142. }
  2143. return true;
  2144. }
  2145. else
  2146. {
  2147. return false;
  2148. }
  2149. }
  2150. void KXineWidget::slotSetVolume(int vol)
  2151. {
  2152. if (!isXineReady()) return;
  2153. if (m_softwareMixer)
  2154. {
  2155. //debugOut(QString("Set software amplification level: %1").arg(vol));
  2156. if (m_volumeGain)
  2157. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, vol*2);
  2158. else
  2159. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, vol);
  2160. }
  2161. else
  2162. {
  2163. //debugOut(QString("Set audio mixer volume: %1").arg(vol));
  2164. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_VOLUME, vol);
  2165. }
  2166. emit signalXineStatus(i18n("Volume") + ": " + QString::number(vol) +"%");
  2167. }
  2168. uint KXineWidget::getVolume() const
  2169. {
  2170. if (!isXineReady()) return 0;
  2171. uint vol;
  2172. if (m_softwareMixer)
  2173. {
  2174. vol = xine_get_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL);
  2175. if (vol > 200)
  2176. {
  2177. // when amp is high > 100, xine_get_param sometimes returns incorrect amp level
  2178. errorOut("Amp level returned weird results, set Amp to 100");
  2179. vol = 100;
  2180. }
  2181. if (m_volumeGain) vol = vol/2;
  2182. }
  2183. else
  2184. {
  2185. vol = xine_get_param(m_xineStream, XINE_PARAM_AUDIO_VOLUME);
  2186. }
  2187. return vol;
  2188. }
  2189. void KXineWidget::slotToggleMute()
  2190. {
  2191. int muteParam;
  2192. if (m_softwareMixer)
  2193. muteParam = XINE_PARAM_AUDIO_AMP_MUTE;
  2194. else
  2195. muteParam = XINE_PARAM_AUDIO_MUTE;
  2196. if (xine_get_param(m_xineStream, muteParam))
  2197. {
  2198. xine_set_param(m_xineStream, muteParam, 0); /* mute off */
  2199. emit signalXineStatus(i18n("Mute") + ": " + i18n("Off"));
  2200. }
  2201. else
  2202. {
  2203. xine_set_param(m_xineStream, muteParam, 1); /* mute on */
  2204. emit signalXineStatus(i18n("Mute") + ": " + i18n("On"));
  2205. }
  2206. }
  2207. bool KXineWidget::SoftwareMixing() const
  2208. {
  2209. if (m_softwareMixer)
  2210. return true;
  2211. else
  2212. return false;
  2213. }
  2214. void KXineWidget::mouseMoveEvent(QMouseEvent* mev)
  2215. {
  2216. if (!m_xineReady) return;
  2217. if (cursor().shape() == Qt::BlankCursor)
  2218. {
  2219. setCursor(QCursor(Qt::ArrowCursor));
  2220. }
  2221. x11_rectangle_t rect;
  2222. xine_event_t event;
  2223. xine_input_data_t input;
  2224. rect.x = mev->x();
  2225. rect.y = mev->y();
  2226. rect.w = 0;
  2227. rect.h = 0;
  2228. xine_port_send_gui_data (m_videoDriver, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect);
  2229. event.type = XINE_EVENT_INPUT_MOUSE_MOVE;
  2230. event.data = &input;
  2231. event.data_length = sizeof(input);
  2232. input.button = 0;
  2233. input.x = rect.x;
  2234. input.y = rect.y;
  2235. xine_event_send(m_xineStream, &event);
  2236. mev->ignore();
  2237. }
  2238. void KXineWidget::mousePressEvent(QMouseEvent* mev)
  2239. {
  2240. if (!m_xineReady) return;
  2241. int cur = cursor().shape();
  2242. if (mev->button() == Qt::MidButton)
  2243. {
  2244. emit signalMiddleClick();
  2245. mev->ignore();
  2246. return;
  2247. }
  2248. if (mev->button() == Qt::RightButton)
  2249. {
  2250. if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
  2251. {
  2252. emit signalRightClick(mev->globalPos());
  2253. mev->accept();
  2254. return;
  2255. }
  2256. }
  2257. if (mev->button() == Qt::LeftButton)
  2258. {
  2259. if ( (cur == Qt::ArrowCursor) || (cur == Qt::BlankCursor) )
  2260. {
  2261. emit signalLeftClick(mev->globalPos());
  2262. mev->ignore();
  2263. return;
  2264. }
  2265. x11_rectangle_t rect;
  2266. xine_event_t event;
  2267. xine_input_data_t input;
  2268. rect.x = mev->x();
  2269. rect.y = mev->y();
  2270. rect.w = 0;
  2271. rect.h = 0;
  2272. xine_port_send_gui_data(m_videoDriver, XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO, (void*)&rect);
  2273. event.type = XINE_EVENT_INPUT_MOUSE_BUTTON;
  2274. event.data = &input;
  2275. event.data_length = sizeof(input);
  2276. input.button = 1;
  2277. input.x = rect.x;
  2278. input.y = rect.y;
  2279. xine_event_send (m_xineStream, &event);
  2280. mev->accept(); /* don't send event to parent */
  2281. }
  2282. }
  2283. void KXineWidget::mouseDoubleClickEvent(QMouseEvent* mev)
  2284. {
  2285. emit signalDoubleClick();
  2286. mev->ignore();
  2287. }
  2288. void KXineWidget::wheelEvent(QWheelEvent* e)
  2289. {
  2290. int oldVal = getPosition();
  2291. if (oldVal == 0) // no valid position
  2292. return;
  2293. float offset = log10( QABS(e->delta()) ) / 0.002;
  2294. int newVal = 0;
  2295. if (e->delta()>0)
  2296. newVal = oldVal - int(offset);
  2297. else
  2298. newVal = oldVal + int(offset);
  2299. if (newVal < 0) newVal = 0;
  2300. slotSeekToPosition(newVal);
  2301. e->accept();
  2302. }
  2303. void KXineWidget::playNextChapter() const
  2304. {
  2305. xine_event_t xev;
  2306. xev.type = XINE_EVENT_INPUT_NEXT;
  2307. xev.data = NULL;
  2308. xev.data_length = 0;
  2309. xine_event_send(m_xineStream, &xev);
  2310. }
  2311. void KXineWidget::playPreviousChapter() const
  2312. {
  2313. xine_event_t xev;
  2314. xev.type = XINE_EVENT_INPUT_PREVIOUS;
  2315. xev.data = NULL;
  2316. xev.data_length = 0;
  2317. xine_event_send(m_xineStream, &xev);
  2318. }
  2319. void KXineWidget::slotStop()
  2320. {
  2321. m_posTimer.stop();
  2322. if ( m_lengthInfoTimer.isActive() ) m_lengthInfoTimer.stop();
  2323. //emit signalNewPosition(0, QTime());
  2324. if ((m_logoFile.isNull()) && (isPlaying()))
  2325. xine_stop(m_xineStream);
  2326. else
  2327. {
  2328. appendToQueue(m_logoFile);
  2329. QTimer::singleShot(0, this, SLOT(slotPlay()));
  2330. }
  2331. emit signalXineStatus(i18n("Stop"));
  2332. }
  2333. void KXineWidget::slotSetAudiocdDevice(const QString& device)
  2334. {
  2335. debugOut(QString("Set AudioCD device to %1").arg(device));
  2336. xine_cfg_entry_t config;
  2337. xine_config_lookup_entry(m_xineEngine, "input.cdda_device", &config);
  2338. if (m_cachedCDPath.isNull())
  2339. m_cachedCDPath = config.str_value;
  2340. config.str_value = (char*)device.latin1();
  2341. xine_config_update_entry (m_xineEngine, &config);
  2342. }
  2343. void KXineWidget::slotSetVcdDevice(const QString& device)
  2344. {
  2345. debugOut(QString("Set VCD device to %1").arg(device));
  2346. xine_cfg_entry_t config;
  2347. xine_config_lookup_entry(m_xineEngine, "input.vcd_device", &config);
  2348. if (m_cachedVCDPath.isNull())
  2349. m_cachedVCDPath = config.str_value;
  2350. config.str_value = (char*)device.latin1();
  2351. xine_config_update_entry (m_xineEngine, &config);
  2352. }
  2353. void KXineWidget::slotSetDvdDevice(const QString& device)
  2354. {
  2355. debugOut(QString("Set DVD device to %1").arg(device));
  2356. xine_cfg_entry_t config;
  2357. xine_config_lookup_entry(m_xineEngine, "input.dvd_device", &config);
  2358. if (m_cachedDVDPath.isNull())
  2359. m_cachedDVDPath = config.str_value;
  2360. config.str_value = (char*)device.latin1();
  2361. xine_config_update_entry (m_xineEngine, &config);
  2362. }
  2363. QString KXineWidget::audiocdDevice() const
  2364. {
  2365. xine_cfg_entry_t config;
  2366. xine_config_lookup_entry(m_xineEngine, "input.cdda_device", &config);
  2367. return QString(config.str_value);
  2368. }
  2369. QString KXineWidget::vcdDevice() const
  2370. {
  2371. xine_cfg_entry_t config;
  2372. xine_config_lookup_entry(m_xineEngine, "input.vcd_device", &config);
  2373. return QString(config.str_value);
  2374. }
  2375. QString KXineWidget::dvdDevice() const
  2376. {
  2377. xine_cfg_entry_t config;
  2378. xine_config_lookup_entry(m_xineEngine, "input.dvd_device", &config);
  2379. return QString(config.str_value);
  2380. }
  2381. #if XINE_MAJOR_VERSION >= 1 && XINE_MINOR_VERSION >= 1
  2382. uint KXineWidget::currentDVDTitleNumber() const
  2383. {
  2384. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_TITLE_NUMBER);
  2385. }
  2386. uint KXineWidget::getDVDTitleCount() const
  2387. {
  2388. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_TITLE_COUNT);
  2389. }
  2390. uint KXineWidget::currentDVDChapterNumber() const
  2391. {
  2392. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER);
  2393. }
  2394. uint KXineWidget::getDVDChapterCount() const
  2395. {
  2396. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT);
  2397. }
  2398. uint KXineWidget::currentDVDAngleNumber() const
  2399. {
  2400. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER);
  2401. }
  2402. uint KXineWidget::getDVDAngleCount() const
  2403. {
  2404. return xine_get_stream_info(m_xineStream, XINE_STREAM_INFO_DVD_ANGLE_COUNT);
  2405. }
  2406. #endif
  2407. void KXineWidget::setStreamSaveDir(const QString& dir)
  2408. {
  2409. xine_cfg_entry_t config;
  2410. if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return; /* older xine-lib */
  2411. debugOut(QString("Set misc.save_dir to: %1").arg(dir));
  2412. config.str_value = (char*)dir.latin1();
  2413. xine_config_update_entry (m_xineEngine, &config);
  2414. }
  2415. const QString KXineWidget::getStreamSaveDir()
  2416. {
  2417. xine_cfg_entry_t config;
  2418. if (!xine_config_lookup_entry(m_xineEngine, "misc.save_dir", &config)) return QString::null; /* older xine-lib */
  2419. return QString(config.str_value);
  2420. }
  2421. void KXineWidget::setBroadcasterPort(const uint port)
  2422. {
  2423. debugOut(QString("Set broadcaster port to %1").arg(port));
  2424. xine_set_param(m_xineStream, XINE_PARAM_BROADCASTER_PORT, port);
  2425. }
  2426. void KXineWidget::slotSpeedPause()
  2427. {
  2428. if (m_currentSpeed == Pause)
  2429. {
  2430. slotSpeedNormal();
  2431. }
  2432. else if (m_trackURL != m_logoFile) // don't pause logo
  2433. {
  2434. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
  2435. m_posTimer.stop();
  2436. if (m_currentSpeed != Undefined)
  2437. emit signalXineStatus(i18n("Pause"));
  2438. m_currentSpeed = Pause;
  2439. }
  2440. }
  2441. void KXineWidget::slotSpeedNormal()
  2442. {
  2443. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
  2444. m_posTimer.start(500);
  2445. m_currentSpeed = Normal;
  2446. emit signalXineStatus(i18n("Playing") + " ");
  2447. }
  2448. void KXineWidget::slotSpeedFaster()
  2449. {
  2450. switch (m_currentSpeed)
  2451. {
  2452. case Fast1:
  2453. {
  2454. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_4);
  2455. m_currentSpeed = Fast2;
  2456. emit signalXineStatus(i18n("Fast Forward %1").arg("x2"));
  2457. break;
  2458. }
  2459. case Fast2:
  2460. {
  2461. slotSpeedNormal();
  2462. break;
  2463. }
  2464. case Slow1:
  2465. {
  2466. slotSpeedNormal();
  2467. break;
  2468. }
  2469. case Slow2:
  2470. {
  2471. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_2);
  2472. m_currentSpeed = Slow1;
  2473. emit signalXineStatus(i18n("Slow Motion %1").arg("x1"));
  2474. break;
  2475. }
  2476. default:
  2477. {
  2478. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_2);
  2479. m_currentSpeed = Fast1;
  2480. emit signalXineStatus(i18n("Fast Forward %1").arg("x1"));
  2481. break;
  2482. }
  2483. }
  2484. }
  2485. void KXineWidget::slotSpeedSlower()
  2486. {
  2487. switch (m_currentSpeed)
  2488. {
  2489. case Slow1:
  2490. {
  2491. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_4);
  2492. m_currentSpeed = Slow2;
  2493. emit signalXineStatus(i18n("Slow Motion %1").arg("x2"));
  2494. break;
  2495. }
  2496. case Slow2:
  2497. {
  2498. slotSpeedNormal();
  2499. break;
  2500. }
  2501. case Fast1:
  2502. {
  2503. slotSpeedNormal();
  2504. break;
  2505. }
  2506. case Fast2:
  2507. {
  2508. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_FAST_2);
  2509. m_currentSpeed = Fast1;
  2510. emit signalXineStatus(i18n("Fast Forward %1").arg("x1"));
  2511. break;
  2512. }
  2513. default:
  2514. {
  2515. xine_set_param(m_xineStream, XINE_PARAM_SPEED, XINE_SPEED_SLOW_2);
  2516. m_currentSpeed = Slow1;
  2517. emit signalXineStatus(i18n("Slow Motion %1").arg("x1"));
  2518. break;
  2519. }
  2520. }
  2521. }
  2522. QString KXineWidget::getSupportedExtensions() const
  2523. {
  2524. return xine_get_file_extensions(m_xineEngine);
  2525. }
  2526. void KXineWidget::slotSetAudioChannel(int ch)
  2527. {
  2528. debugOut(QString("Switch to audio channel %1").arg(ch-1));
  2529. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, ch-1);
  2530. }
  2531. void KXineWidget::slotSetSubtitleChannel(int ch)
  2532. {
  2533. debugOut(QString("Switch to subtitle channel %1").arg(ch-1));
  2534. xine_set_param(m_xineStream, XINE_PARAM_SPU_CHANNEL, ch-1);
  2535. }
  2536. void KXineWidget::slotSetFileSubtitles(QString url)
  2537. {
  2538. int pos;
  2539. int time;
  2540. int length;
  2541. m_queue.prepend(url);
  2542. int t = 0, ret = 0;
  2543. while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  2544. xine_usec_sleep(100000);
  2545. if ( ret == 0 )
  2546. {
  2547. debugOut("No valid stream position information");
  2548. return;
  2549. }
  2550. if (isPlaying())
  2551. xine_stop(m_xineStream);
  2552. m_posTimer.stop();
  2553. slotPlay();
  2554. slotSeekToPosition(pos);
  2555. }
  2556. uint KXineWidget::getPosition() const
  2557. {
  2558. if (!m_xineReady) return 0;
  2559. int pos, time, length;
  2560. int t = 0, ret = 0;
  2561. while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  2562. xine_usec_sleep(100000);
  2563. if ( ret == 0 )
  2564. {
  2565. debugOut("No valid stream position information");
  2566. return 0;
  2567. }
  2568. return (uint)pos;
  2569. }
  2570. QTime KXineWidget::getPlaytime() const
  2571. {
  2572. if (!m_xineReady) return QTime();
  2573. int pos, time, length;
  2574. int t = 0, ret = 0;
  2575. while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  2576. xine_usec_sleep(100000);
  2577. if ( ret == 0 )
  2578. {
  2579. debugOut("No valid stream position information");
  2580. return QTime();
  2581. }
  2582. return msToTime(time);
  2583. }
  2584. void KXineWidget::slotSendPosition()
  2585. {
  2586. if (!m_xineReady) return;
  2587. int pos, time, length;
  2588. int t = 0, ret = 0;
  2589. while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  2590. xine_usec_sleep(100000);
  2591. if ( ret == 0 )
  2592. {
  2593. debugOut("No valid stream position information");
  2594. return;
  2595. }
  2596. emit signalNewPosition(pos, msToTime(time));
  2597. }
  2598. void KXineWidget::slotStartSeeking()
  2599. {
  2600. debugOut("Seeking started");
  2601. m_posTimer.stop();
  2602. }
  2603. void KXineWidget::slotSeekToPosition(int pos)
  2604. {
  2605. if ((!isXineReady()) || (!isPlaying()) || (!isSeekable())) return;
  2606. bool pause = false;
  2607. if (m_currentSpeed == Pause)
  2608. pause = true;
  2609. xine_play(m_xineStream, pos, 0);
  2610. double length = QTime().msecsTo(getLengthInfo());
  2611. length = (length * pos)/65535;
  2612. QTime time = QTime().addMSecs((int)length);
  2613. emit signalNewPosition(pos, time);
  2614. emit signalXineStatus(i18n("Position") + ": " + time.toString("h:mm:ss"));
  2615. if (pause)
  2616. {
  2617. m_currentSpeed = Undefined;
  2618. slotSpeedPause();
  2619. }
  2620. }
  2621. void KXineWidget::slotSeekToTime(const QTime& postime)
  2622. {
  2623. if ((!isXineReady()) || (!isPlaying()) || (!isSeekable())) return;
  2624. bool pause = false;
  2625. if (m_currentSpeed == Pause)
  2626. pause = true;
  2627. xine_play(m_xineStream, 0, QTime().msecsTo(postime));
  2628. double length = QTime().msecsTo(getLengthInfo());
  2629. double posfract = QTime().msecsTo(postime);
  2630. posfract = (posfract / length) * 65535;
  2631. emit signalNewPosition((int)posfract, postime);
  2632. emit signalXineStatus(i18n("Position") + ": " + postime.toString("h:mm:ss"));
  2633. if (pause)
  2634. {
  2635. m_currentSpeed = Undefined;
  2636. slotSpeedPause();
  2637. }
  2638. }
  2639. void KXineWidget::slotStopSeeking()
  2640. {
  2641. debugOut("Seeking stopped");
  2642. m_posTimer.start(500, false);
  2643. }
  2644. void KXineWidget::slotEject()
  2645. {
  2646. xine_eject(m_xineStream);
  2647. }
  2648. void KXineWidget::slotEnableAutoresize(bool enable)
  2649. {
  2650. m_autoresizeEnabled = enable;
  2651. if (!m_autoresizeEnabled)
  2652. {
  2653. m_videoFrameHeight = 0;
  2654. m_videoFrameWidth = 0;
  2655. }
  2656. }
  2657. /***************************************
  2658. * tvtime deinterlacer plugin *
  2659. ***************************************/
  2660. #ifndef USE_QT_ONLY
  2661. void KXineWidget::createDeinterlacePlugin(const QString& config, QWidget* parent)
  2662. {
  2663. m_deinterlaceFilter = new PostFilter(config.section(':',0,0), m_xineEngine, m_audioDriver, m_videoDriver, parent);
  2664. if( !m_deinterlaceFilter->getInput() || !m_deinterlaceFilter->getOutput() )
  2665. {
  2666. delete m_deinterlaceFilter;
  2667. m_deinterlaceFilter = NULL;
  2668. }
  2669. slotSetDeinterlaceConfig(config);
  2670. }
  2671. const QString KXineWidget::getDeinterlaceConfig() const
  2672. {
  2673. if (m_deinterlaceFilter)
  2674. return m_deinterlaceFilter->getConfig();
  2675. return DEFAULT_TVTIME_CONFIG;
  2676. }
  2677. #endif
  2678. void KXineWidget::slotSetDeinterlaceConfig(const QString& config)
  2679. {
  2680. #ifndef USE_QT_ONLY
  2681. if (m_deinterlaceFilter)
  2682. m_deinterlaceFilter->setConfig(config);
  2683. #else
  2684. warningOut(QString ("Not implemented [SetDeinterlaceConfig %1]").arg(config));
  2685. #endif
  2686. }
  2687. void KXineWidget::slotToggleDeinterlace()
  2688. {
  2689. #ifndef USE_QT_ONLY
  2690. QString s;
  2691. if (m_deinterlaceFilter)
  2692. {
  2693. m_deinterlaceEnabled = !m_deinterlaceEnabled;
  2694. debugOut(QString("Deinterlace enabled: %1").arg(m_deinterlaceEnabled));
  2695. if ( m_deinterlaceEnabled ) s = i18n("Deinterlace: on");
  2696. else s = i18n("Deinterlace: off");
  2697. showOSDMessage( s, 2000 );
  2698. unwireVideoFilters();
  2699. wireVideoFilters();
  2700. }
  2701. else
  2702. {
  2703. /* fallback - this method is deprecated */
  2704. if (xine_get_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE))
  2705. xine_set_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE, false);
  2706. else
  2707. xine_set_param(m_xineStream, XINE_PARAM_VO_DEINTERLACE, true);
  2708. }
  2709. #else
  2710. warningOut("Not implemented!");
  2711. #endif
  2712. }
  2713. /**************************/
  2714. void KXineWidget::slotAspectRatioAuto()
  2715. {
  2716. xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_AUTO);
  2717. emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("Auto"));
  2718. }
  2719. void KXineWidget::slotAspectRatio4_3()
  2720. {
  2721. xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_4_3);
  2722. emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("4:3"));
  2723. }
  2724. void KXineWidget::slotAspectRatioAnamorphic()
  2725. {
  2726. xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_ANAMORPHIC);
  2727. emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("16:9"));
  2728. }
  2729. void KXineWidget::slotAspectRatioSquare()
  2730. {
  2731. xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_SQUARE);
  2732. emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("1:1"));
  2733. }
  2734. void KXineWidget::slotAspectRatioDVB()
  2735. {
  2736. xine_set_param(m_xineStream, XINE_PARAM_VO_ASPECT_RATIO, XINE_VO_ASPECT_DVB);
  2737. emit signalXineStatus(i18n("Aspect Ratio") + ": " + i18n("2.11:1"));
  2738. }
  2739. void KXineWidget::slotZoomOutX()
  2740. {
  2741. if ((m_currentZoomX - 5) >= 100)
  2742. {
  2743. m_currentZoomX -= 5;
  2744. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoomX);
  2745. emit signalXineStatus(i18n("Zoom X") + ": " + QString::number(m_currentZoomX) + "%");
  2746. }
  2747. }
  2748. void KXineWidget::slotZoomInX()
  2749. {
  2750. if ((m_currentZoomX + 5) <= XINE_VO_ZOOM_MAX)
  2751. {
  2752. m_currentZoomX += 5;
  2753. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoomX);
  2754. emit signalXineStatus(i18n("Zoom X") + ": " + QString::number(m_currentZoomX) + "%");
  2755. }
  2756. }
  2757. void KXineWidget::slotZoomOutY()
  2758. {
  2759. if ((m_currentZoomY - 5) >= 100)
  2760. {
  2761. m_currentZoomY -= 5;
  2762. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoomY);
  2763. emit signalXineStatus(i18n("Zoom Y") + ": " + QString::number(m_currentZoomY) + "%");
  2764. }
  2765. }
  2766. void KXineWidget::slotZoomInY()
  2767. {
  2768. if ((m_currentZoomY + 5) <= XINE_VO_ZOOM_MAX)
  2769. {
  2770. m_currentZoomY += 5;
  2771. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoomY);
  2772. emit signalXineStatus(i18n("Zoom Y") + ": " + QString::number(m_currentZoomY) + "%");
  2773. }
  2774. }
  2775. void KXineWidget::slotZoomOut()
  2776. {
  2777. if ((m_currentZoom - 5) >= 100)
  2778. {
  2779. m_currentZoom -= 5;
  2780. m_currentZoomX = m_currentZoomY = m_currentZoom;
  2781. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoom);
  2782. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoom);
  2783. emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
  2784. }
  2785. }
  2786. void KXineWidget::slotZoomIn()
  2787. {
  2788. if ((m_currentZoom + 5) <= XINE_VO_ZOOM_MAX)
  2789. {
  2790. m_currentZoom += 5;
  2791. m_currentZoomX = m_currentZoomY = m_currentZoom;
  2792. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, m_currentZoom);
  2793. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, m_currentZoom);
  2794. emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
  2795. }
  2796. }
  2797. void KXineWidget::slotZoomOff()
  2798. {
  2799. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_X, 100);
  2800. xine_set_param(m_xineStream, XINE_PARAM_VO_ZOOM_Y, 100);
  2801. m_currentZoom = 100;
  2802. m_currentZoomX = m_currentZoomY = m_currentZoom;
  2803. emit signalXineStatus(i18n("Zoom") + ": " + QString::number(m_currentZoom) + "%");
  2804. }
  2805. QTime KXineWidget::getLengthInfo()
  2806. {
  2807. int pos, time, length;
  2808. int t = 0, ret = 0;
  2809. while(((ret = xine_get_pos_length(m_xineStream, &pos, &time, &length)) == 0) && (++t < 5))
  2810. xine_usec_sleep(100000);
  2811. if ( (ret != 0) && (length > 0) )
  2812. {
  2813. return msToTime(length);
  2814. }
  2815. return QTime();
  2816. }
  2817. void KXineWidget::slotEmitLengthInfo()
  2818. {
  2819. QTime length = getLengthInfo();
  2820. if (!(length.isNull()))
  2821. {
  2822. if ( m_trackURL!="DVB" ) m_lengthInfoTimer.stop();
  2823. m_trackLength = length;
  2824. emit signalLengthChanged();
  2825. }
  2826. else
  2827. {
  2828. if (m_lengthInfoTries > 10) // wait 10 seconds
  2829. m_lengthInfoTimer.stop();
  2830. else
  2831. {
  2832. debugOut("Wait for valid length information");
  2833. m_lengthInfoTries ++;
  2834. }
  2835. }
  2836. }
  2837. void KXineWidget::globalPosChanged()
  2838. {
  2839. QPoint g = mapToGlobal(QPoint(0,0));
  2840. m_globalX = g.x();
  2841. m_globalY = g.y();
  2842. }
  2843. const xine_t* const KXineWidget::getXineEngine()const
  2844. {
  2845. return m_xineEngine;
  2846. }
  2847. /************ video settings ****************/
  2848. void KXineWidget::getVideoSettings(int& hue, int& sat, int& contrast, int& bright,
  2849. int& avOffset, int& spuOffset) const
  2850. {
  2851. hue = xine_get_param(m_xineStream, XINE_PARAM_VO_HUE);
  2852. sat = xine_get_param(m_xineStream, XINE_PARAM_VO_SATURATION);
  2853. contrast = xine_get_param(m_xineStream, XINE_PARAM_VO_CONTRAST);
  2854. bright = xine_get_param(m_xineStream, XINE_PARAM_VO_BRIGHTNESS);
  2855. avOffset = xine_get_param(m_xineStream, XINE_PARAM_AV_OFFSET);
  2856. spuOffset = xine_get_param(m_xineStream, XINE_PARAM_SPU_OFFSET);
  2857. }
  2858. void KXineWidget::slotSetHue(int hue)
  2859. {
  2860. xine_set_param(m_xineStream, XINE_PARAM_VO_HUE, hue);
  2861. emit signalXineStatus(i18n("Hue") + ": " + QString::number((hue*100)/65535) + "%");
  2862. }
  2863. void KXineWidget::slotSetSaturation(int sat)
  2864. {
  2865. xine_set_param(m_xineStream, XINE_PARAM_VO_SATURATION, sat);
  2866. emit signalXineStatus(i18n("Saturation") + ": " + QString::number((sat*100)/65535) + "%");
  2867. }
  2868. void KXineWidget::slotSetContrast(int contrast)
  2869. {
  2870. xine_set_param(m_xineStream, XINE_PARAM_VO_CONTRAST, contrast);
  2871. emit signalXineStatus(i18n("Contrast") + ": " + QString::number((contrast*100)/65535) + "%");
  2872. }
  2873. void KXineWidget::slotSetBrightness(int bright)
  2874. {
  2875. xine_set_param(m_xineStream, XINE_PARAM_VO_BRIGHTNESS, bright);
  2876. emit signalXineStatus(i18n("Brightness") + ": " + QString::number((bright*100)/65535) + "%");
  2877. }
  2878. void KXineWidget::slotSetAVOffset(int av)
  2879. {
  2880. xine_set_param(m_xineStream, XINE_PARAM_AV_OFFSET, av);
  2881. emit signalXineStatus(i18n("Audio/Video Offset") + ": " + QString::number(av/90) + i18n("msec"));
  2882. }
  2883. void KXineWidget::slotSetSpuOffset(int spu)
  2884. {
  2885. xine_set_param(m_xineStream, XINE_PARAM_SPU_OFFSET, spu);
  2886. emit signalXineStatus(i18n("Subtitle Offset") + ": " + QString::number(spu/90) + i18n("msec"));
  2887. }
  2888. /**************** equalizer *****************/
  2889. void KXineWidget::slotSetEq30(int val)
  2890. {
  2891. xine_set_param(m_xineStream, XINE_PARAM_EQ_30HZ, -val);
  2892. }
  2893. void KXineWidget::slotSetEq60(int val)
  2894. {
  2895. xine_set_param(m_xineStream, XINE_PARAM_EQ_60HZ, -val);
  2896. }
  2897. void KXineWidget::slotSetEq125(int val)
  2898. {
  2899. xine_set_param(m_xineStream, XINE_PARAM_EQ_125HZ, -val);
  2900. }
  2901. void KXineWidget::slotSetEq250(int val)
  2902. {
  2903. xine_set_param(m_xineStream, XINE_PARAM_EQ_250HZ, -val);
  2904. }
  2905. void KXineWidget::slotSetEq500(int val)
  2906. {
  2907. xine_set_param(m_xineStream, XINE_PARAM_EQ_500HZ, -val);
  2908. }
  2909. void KXineWidget::slotSetEq1k(int val)
  2910. {
  2911. xine_set_param(m_xineStream, XINE_PARAM_EQ_1000HZ, -val);
  2912. }
  2913. void KXineWidget::slotSetEq2k(int val)
  2914. {
  2915. xine_set_param(m_xineStream, XINE_PARAM_EQ_2000HZ, -val);
  2916. }
  2917. void KXineWidget::slotSetEq4k(int val)
  2918. {
  2919. xine_set_param(m_xineStream, XINE_PARAM_EQ_4000HZ, -val);
  2920. }
  2921. void KXineWidget::slotSetEq8k(int val)
  2922. {
  2923. xine_set_param(m_xineStream, XINE_PARAM_EQ_8000HZ, -val);
  2924. }
  2925. void KXineWidget::slotSetEq16k(int val)
  2926. {
  2927. xine_set_param(m_xineStream, XINE_PARAM_EQ_16000HZ, -val);
  2928. }
  2929. void KXineWidget::slotSetVolumeGain(bool gain)
  2930. {
  2931. int amp = 0;
  2932. if (gain)
  2933. {
  2934. if (m_softwareMixer)
  2935. amp = getVolume()*2;
  2936. else
  2937. amp = 200;
  2938. }
  2939. else
  2940. {
  2941. if (m_softwareMixer)
  2942. amp = getVolume();
  2943. else
  2944. amp = 100;
  2945. }
  2946. xine_set_param(m_xineStream, XINE_PARAM_AUDIO_AMP_LEVEL, amp);
  2947. m_volumeGain = gain;
  2948. }
  2949. /*************** dvd menus ******************/
  2950. void KXineWidget::slotMenuToggle()
  2951. {
  2952. xine_event_t xev;
  2953. xev.type = XINE_EVENT_INPUT_MENU1;
  2954. xev.data = NULL;
  2955. xev.data_length = 0;
  2956. xine_event_send(m_xineStream, &xev);
  2957. }
  2958. void KXineWidget::slotMenuTitle()
  2959. {
  2960. xine_event_t xev;
  2961. xev.type = XINE_EVENT_INPUT_MENU2;
  2962. xev.data = NULL;
  2963. xev.data_length = 0;
  2964. xine_event_send(m_xineStream, &xev);
  2965. }
  2966. void KXineWidget::slotMenuRoot()
  2967. {
  2968. xine_event_t xev;
  2969. xev.type = XINE_EVENT_INPUT_MENU3;
  2970. xev.data = NULL;
  2971. xev.data_length = 0;
  2972. xine_event_send(m_xineStream, &xev);
  2973. }
  2974. void KXineWidget::slotMenuSubpicture()
  2975. {
  2976. xine_event_t xev;
  2977. xev.type = XINE_EVENT_INPUT_MENU4;
  2978. xev.data = NULL;
  2979. xev.data_length = 0;
  2980. xine_event_send(m_xineStream, &xev);
  2981. }
  2982. void KXineWidget::slotMenuAudio()
  2983. {
  2984. xine_event_t xev;
  2985. xev.type = XINE_EVENT_INPUT_MENU5;
  2986. xev.data = NULL;
  2987. xev.data_length = 0;
  2988. xine_event_send(m_xineStream, &xev);
  2989. }
  2990. void KXineWidget::slotMenuAngle()
  2991. {
  2992. xine_event_t xev;
  2993. xev.type = XINE_EVENT_INPUT_MENU6;
  2994. xev.data = NULL;
  2995. xev.data_length = 0;
  2996. xine_event_send(m_xineStream, &xev);
  2997. }
  2998. void KXineWidget::slotMenuPart()
  2999. {
  3000. xine_event_t xev;
  3001. xev.type = XINE_EVENT_INPUT_MENU7;
  3002. xev.data = NULL;
  3003. xev.data_length = 0;
  3004. xine_event_send(m_xineStream, &xev);
  3005. }
  3006. void KXineWidget::slotDVDMenuLeft()
  3007. {
  3008. xine_event_t xev;
  3009. xev.data = NULL;
  3010. xev.data_length = 0;
  3011. xev.type = XINE_EVENT_INPUT_LEFT;
  3012. xine_event_send(m_xineStream, &xev);
  3013. }
  3014. void KXineWidget::slotDVDMenuRight()
  3015. {
  3016. xine_event_t xev;
  3017. xev.data = NULL;
  3018. xev.data_length = 0;
  3019. xev.type = XINE_EVENT_INPUT_RIGHT;
  3020. xine_event_send(m_xineStream, &xev);
  3021. }
  3022. void KXineWidget::slotDVDMenuUp()
  3023. {
  3024. xine_event_t xev;
  3025. xev.data = NULL;
  3026. xev.data_length = 0;
  3027. xev.type = XINE_EVENT_INPUT_UP;
  3028. xine_event_send(m_xineStream, &xev);
  3029. }
  3030. void KXineWidget::slotDVDMenuDown()
  3031. {
  3032. xine_event_t xev;
  3033. xev.data = NULL;
  3034. xev.data_length = 0;
  3035. xev.type = XINE_EVENT_INPUT_DOWN;
  3036. xine_event_send(m_xineStream, &xev);
  3037. }
  3038. void KXineWidget::slotDVDMenuSelect()
  3039. {
  3040. xine_event_t xev;
  3041. xev.data = NULL;
  3042. xev.data_length = 0;
  3043. xev.type = XINE_EVENT_INPUT_SELECT;
  3044. xine_event_send(m_xineStream, &xev);
  3045. }
  3046. /******** mouse hideing at fullscreen ****/
  3047. void KXineWidget::startMouseHideTimer()
  3048. {
  3049. m_mouseHideTimer.start(5000);
  3050. }
  3051. void KXineWidget::stopMouseHideTimer()
  3052. {
  3053. m_mouseHideTimer.stop();
  3054. }
  3055. void KXineWidget::slotHideMouse()
  3056. {
  3057. if (cursor().shape() == Qt::ArrowCursor)
  3058. {
  3059. setCursor(QCursor(Qt::BlankCursor));
  3060. }
  3061. }
  3062. /************************************************************
  3063. * Take a Screenshot *
  3064. ************************************************************/
  3065. QImage KXineWidget::getScreenshot() const
  3066. {
  3067. uchar *rgbPile = NULL;
  3068. int width, height;
  3069. double scaleFactor;
  3070. getScreenshot(rgbPile, width, height, scaleFactor);
  3071. if (!rgbPile) return QImage();
  3072. QImage screenShot(rgbPile, width, height, 32, 0, 0, QImage::IgnoreEndian);
  3073. if (scaleFactor >= 1.0)
  3074. width = (int)((double) width * scaleFactor + 0.5);
  3075. else
  3076. height = (int)((double) height / scaleFactor + 0.5);
  3077. debugOut(QString("Screenshot: scale picture from %1x%2 to %3x%4").arg(screenShot.width()).arg(screenShot.height()).arg(width).arg(height));
  3078. screenShot = screenShot.smoothScale(width, height);
  3079. delete []rgbPile;
  3080. return screenShot;
  3081. }
  3082. void KXineWidget::getScreenshot(uchar*& rgb32BitData, int& videoWidth, int& videoHeight, double& scaleFactor) const
  3083. {
  3084. uint8_t *yuv = NULL, *y = NULL, *u = NULL, *v =NULL;
  3085. int width, height, ratio, format;
  3086. // double desired_ratio, image_ratio;
  3087. if (!xine_get_current_frame(m_xineStream, &width, &height, &ratio, &format, NULL))
  3088. return;
  3089. yuv = new uint8_t[((width+8) * (height+1) * 2)];
  3090. if (yuv == NULL)
  3091. {
  3092. errorOut("Not enough memory to make screenshot!");
  3093. return;
  3094. }
  3095. xine_get_current_frame(m_xineStream, &width, &height, &ratio, &format, yuv);
  3096. videoWidth = width;
  3097. videoHeight = height;
  3098. /*
  3099. * convert to yv12 if necessary
  3100. */
  3101. switch (format)
  3102. {
  3103. case XINE_IMGFMT_YUY2:
  3104. {
  3105. uint8_t *yuy2 = yuv;
  3106. yuv = new uint8_t[(width * height * 2)];
  3107. if (yuv == NULL)
  3108. {
  3109. errorOut("Not enough memory to make screenshot!");
  3110. return;
  3111. }
  3112. y = yuv;
  3113. u = yuv + width * height;
  3114. v = yuv + width * height * 5 / 4;
  3115. yuy2Toyv12 (y, u, v, yuy2, width, height);
  3116. delete [] yuy2;
  3117. }
  3118. break;
  3119. case XINE_IMGFMT_YV12:
  3120. y = yuv;
  3121. u = yuv + width * height;
  3122. v = yuv + width * height * 5 / 4;
  3123. break;
  3124. default:
  3125. {
  3126. warningOut(QString("Screenshot: Format %1 not supportet!").arg((char*)&format));
  3127. delete [] yuv;
  3128. return;
  3129. }
  3130. }
  3131. /*
  3132. * convert to rgb
  3133. */
  3134. rgb32BitData = yv12ToRgb (y, u, v, width, height);
  3135. // image_ratio = (double) height / (double) width;
  3136. /*
  3137. switch (ratio)
  3138. {
  3139. case XINE_VO_ASPECT_ANAMORPHIC:
  3140. debugOut("Screenshot: got video aspect: anamorphic");
  3141. desired_ratio = 16.0 /9.0;
  3142. break;
  3143. case XINE_VO_ASPECT_DVB:
  3144. debugOut("Screenshot: got video aspect: 2.11:1");
  3145. desired_ratio = 2.11/1.0;
  3146. break;
  3147. case XINE_VO_ASPECT_4_3:
  3148. debugOut("Screenshot: got video aspect: 4:3");
  3149. desired_ratio = 4.0 / 3.0;
  3150. break;
  3151. default:
  3152. warningOut(QString("Screenshot: Unknown aspect ratio: %1 - using 4:3").arg(ratio));
  3153. case XINE_VO_ASPECT_SQUARE:
  3154. debugOut("Screenshot: got video aspect: 1:1");
  3155. desired_ratio = image_ratio;
  3156. break;
  3157. }
  3158. */
  3159. debugOut(QString("Screenshot: using scale factor: %1").arg(m_videoAspect));
  3160. scaleFactor = m_videoAspect;
  3161. delete [] yuv;
  3162. }
  3163. /************************************************
  3164. * HELPER FUNCTIONS *
  3165. ************************************************/
  3166. QTime KXineWidget::msToTime(int msec)
  3167. {
  3168. QTime t;
  3169. t = t.addMSecs(msec);
  3170. return t;
  3171. }
  3172. #ifdef USE_QT_ONLY
  3173. QString KXineWidget::i18n(const char *text)
  3174. {
  3175. return QApplication::tr(text);
  3176. }
  3177. #endif
  3178. void KXineWidget::debugOut (QString qsDebug)
  3179. {
  3180. #ifdef USE_QT_ONLY
  3181. QString qsDebugging = QString ("Debug: ") + qsDebug +"\n";
  3182. printf ((const char *)qsDebugging);
  3183. #else
  3184. kdDebug() << "KXineWidget: " << (const char *)qsDebug.ascii() << "\n";
  3185. #endif
  3186. }
  3187. void KXineWidget::errorOut (QString qsError)
  3188. {
  3189. #ifdef USE_QT_ONLY
  3190. QString qsErroring = QString ("Error: ") + qsError+ "\n";
  3191. printf ((const char *)qsErroring);
  3192. #else
  3193. kdError() << "KXineWidget: " << (const char *)qsError.ascii() << "\n";
  3194. #endif
  3195. }
  3196. void KXineWidget::warningOut (QString qsWarning)
  3197. {
  3198. #ifdef USE_QT_ONLY
  3199. QString qsWarninging = QString ("Warning: ") + qsWarning + "\n";
  3200. printf ((const char *)qsWarninging);
  3201. #else
  3202. kdWarning() << "KXineWidget: " << (const char *)qsWarning.ascii() << "\n";
  3203. #endif
  3204. }
  3205. /************************************************************
  3206. * Helpers to convert yuy and yv12 frames to rgb *
  3207. * code from gxine modified for 32bit output *
  3208. * Copyright (C) 2000-2003 the xine project *
  3209. ************************************************************/
  3210. void KXineWidget::yuy2Toyv12 (uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height)
  3211. {
  3212. int i, j, w2;
  3213. w2 = width / 2;
  3214. for (i = 0; i < height; i += 2)
  3215. {
  3216. for (j = 0; j < w2; j++)
  3217. {
  3218. /*
  3219. * packed YUV 422 is: Y[i] U[i] Y[i+1] V[i]
  3220. */
  3221. *(y++) = *(input++);
  3222. *(u++) = *(input++);
  3223. *(y++) = *(input++);
  3224. *(v++) = *(input++);
  3225. }
  3226. /*
  3227. * down sampling
  3228. */
  3229. for (j = 0; j < w2; j++)
  3230. {
  3231. /*
  3232. * skip every second line for U and V
  3233. */
  3234. *(y++) = *(input++);
  3235. input++;
  3236. *(y++) = *(input++);
  3237. input++;
  3238. }
  3239. }
  3240. }
  3241. uchar* KXineWidget::yv12ToRgb (uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height)
  3242. {
  3243. /*
  3244. * Create rgb data from yv12
  3245. */
  3246. #define clip_8_bit(val) \
  3247. { \
  3248. if (val < 0) \
  3249. val = 0; \
  3250. else \
  3251. if (val > 255) val = 255; \
  3252. }
  3253. int i, j;
  3254. int y, u, v;
  3255. int r, g, b;
  3256. int sub_i_uv;
  3257. int sub_j_uv;
  3258. int uv_width, uv_height;
  3259. uchar *rgb;
  3260. uv_width = width / 2;
  3261. uv_height = height / 2;
  3262. rgb = new uchar[(width * height * 4)]; //qt needs a 32bit align
  3263. if (!rgb)
  3264. {
  3265. // kdError(555) << "Not enough memory!" << endl;
  3266. return NULL;
  3267. }
  3268. for (i = 0; i < height; ++i)
  3269. {
  3270. /*
  3271. * calculate u & v rows
  3272. */
  3273. sub_i_uv = ((i * uv_height) / height);
  3274. for (j = 0; j < width; ++j)
  3275. {
  3276. /*
  3277. * calculate u & v columns
  3278. */
  3279. sub_j_uv = ((j * uv_width) / width);
  3280. /***************************************************
  3281. *
  3282. * Colour conversion from
  3283. * http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
  3284. *
  3285. * Thanks to Billy Biggs <vektor@dumbterm.net>
  3286. * for the pointer and the following conversion.
  3287. *
  3288. * R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
  3289. * G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
  3290. * B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
  3291. *
  3292. * Where in xine the above values are represented as
  3293. *
  3294. * Y' == image->y
  3295. * Cb == image->u
  3296. * Cr == image->v
  3297. *
  3298. ***************************************************/
  3299. y = src_y[(i * width) + j] - 16;
  3300. u = src_u[(sub_i_uv * uv_width) + sub_j_uv] - 128;
  3301. v = src_v[(sub_i_uv * uv_width) + sub_j_uv] - 128;
  3302. r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
  3303. g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
  3304. b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
  3305. clip_8_bit (r);
  3306. clip_8_bit (g);
  3307. clip_8_bit (b);
  3308. rgb[(i * width + j) * 4 + 0] = b;
  3309. rgb[(i * width + j) * 4 + 1] = g;
  3310. rgb[(i * width + j) * 4 + 2] = r;
  3311. rgb[(i * width + j) * 4 + 3] = 0;
  3312. }
  3313. }
  3314. return rgb;
  3315. }