PageRenderTime 71ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/src/core.cpp

https://github.com/rdp/smplayer-svn
C++ | 4281 lines | 3200 code | 745 blank | 336 comment | 786 complexity | 56b02342a29a9fd8e318170113e67e6c MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.1

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

  1. /* smplayer, GUI front-end for mplayer.
  2. Copyright (C) 2006-2012 Ricardo Villalba <rvm@users.sourceforge.net>
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  14. */
  15. #include "core.h"
  16. #include <QDir>
  17. #include <QFileInfo>
  18. #include <QRegExp>
  19. #include <QTextStream>
  20. #include <QUrl>
  21. #ifdef Q_OS_OS2
  22. #include <QEventLoop>
  23. #endif
  24. #include <cmath>
  25. #include "mplayerwindow.h"
  26. #include "desktopinfo.h"
  27. #include "helper.h"
  28. #include "paths.h"
  29. #include "preferences.h"
  30. #include "global.h"
  31. #include "config.h"
  32. #include "mplayerversion.h"
  33. #include "constants.h"
  34. #include "colorutils.h"
  35. #include "discname.h"
  36. #include "filters.h"
  37. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  38. #ifdef Q_OS_WIN
  39. #include <windows.h> // To change app priority
  40. #include <QSysInfo> // To get Windows version
  41. #endif
  42. #ifdef SCREENSAVER_OFF
  43. #include "screensaver.h"
  44. #endif
  45. #endif
  46. #ifndef NO_USE_INI_FILES
  47. #include "filesettings.h"
  48. #include "filesettingshash.h"
  49. #include "tvsettings.h"
  50. #endif
  51. #ifdef YOUTUBE_SUPPORT
  52. #include "retrieveyoutubeurl.h"
  53. #endif
  54. using namespace Global;
  55. Core::Core( MplayerWindow *mpw, QWidget* parent )
  56. : QObject( parent )
  57. {
  58. qRegisterMetaType<Core::State>("Core::State");
  59. mplayerwindow = mpw;
  60. _state = Stopped;
  61. we_are_restarting = false;
  62. just_loaded_external_subs = false;
  63. just_unloaded_external_subs = false;
  64. change_volume_after_unpause = false;
  65. #if DVDNAV_SUPPORT
  66. dvdnav_title_is_menu = true; // Enabled by default for compatibility with previous versions of mplayer
  67. #endif
  68. #ifndef NO_USE_INI_FILES
  69. // Create file_settings
  70. file_settings = 0;
  71. changeFileSettingsMethod(pref->file_settings_method);
  72. // TV settings
  73. tv_settings = new TVSettings(Paths::iniPath());
  74. #endif
  75. proc = new MplayerProcess(this);
  76. // Do this the first
  77. connect( proc, SIGNAL(processExited()),
  78. mplayerwindow->videoLayer(), SLOT(playingStopped()) );
  79. connect( proc, SIGNAL(error(QProcess::ProcessError)),
  80. mplayerwindow->videoLayer(), SLOT(playingStopped()) );
  81. // Necessary to hide/unhide mouse cursor on black borders
  82. connect( proc, SIGNAL(processExited()),
  83. mplayerwindow, SLOT(playingStopped()) );
  84. connect( proc, SIGNAL(error(QProcess::ProcessError)),
  85. mplayerwindow, SLOT(playingStopped()) );
  86. connect( proc, SIGNAL(receivedCurrentSec(double)),
  87. this, SLOT(changeCurrentSec(double)) );
  88. connect( proc, SIGNAL(receivedCurrentFrame(int)),
  89. this, SIGNAL(showFrame(int)) );
  90. connect( proc, SIGNAL(receivedPause()),
  91. this, SLOT(changePause()) );
  92. connect( proc, SIGNAL(processExited()),
  93. this, SLOT(processFinished()), Qt::QueuedConnection );
  94. connect( proc, SIGNAL(mplayerFullyLoaded()),
  95. this, SLOT(finishRestart()), Qt::QueuedConnection );
  96. connect( proc, SIGNAL(lineAvailable(QString)),
  97. this, SIGNAL(logLineAvailable(QString)) );
  98. connect( proc, SIGNAL(receivedCacheMessage(QString)),
  99. this, SLOT(displayMessage(QString)) );
  100. connect( proc, SIGNAL(receivedCreatingIndex(QString)),
  101. this, SLOT(displayMessage(QString)) );
  102. connect( proc, SIGNAL(receivedConnectingToMessage(QString)),
  103. this, SLOT(displayMessage(QString)) );
  104. connect( proc, SIGNAL(receivedResolvingMessage(QString)),
  105. this, SLOT(displayMessage(QString)) );
  106. connect( proc, SIGNAL(receivedScreenshot(QString)),
  107. this, SLOT(displayScreenshotName(QString)) );
  108. connect( proc, SIGNAL(receivedUpdatingFontCache()),
  109. this, SLOT(displayUpdatingFontCache()) );
  110. connect( proc, SIGNAL(receivedScanningFont(QString)),
  111. this, SLOT(displayMessage(QString)) );
  112. connect( proc, SIGNAL(receivedWindowResolution(int,int)),
  113. this, SLOT(gotWindowResolution(int,int)) );
  114. connect( proc, SIGNAL(receivedNoVideo()),
  115. this, SLOT(gotNoVideo()) );
  116. connect( proc, SIGNAL(receivedVO(QString)),
  117. this, SLOT(gotVO(QString)) );
  118. connect( proc, SIGNAL(receivedAO(QString)),
  119. this, SLOT(gotAO(QString)) );
  120. connect( proc, SIGNAL(receivedEndOfFile()),
  121. this, SLOT(fileReachedEnd()), Qt::QueuedConnection );
  122. connect( proc, SIGNAL(receivedStartingTime(double)),
  123. this, SLOT(gotStartingTime(double)) );
  124. connect( proc, SIGNAL(receivedStreamTitle(QString)),
  125. this, SLOT(streamTitleChanged(QString)) );
  126. connect( proc, SIGNAL(receivedStreamTitleAndUrl(QString,QString)),
  127. this, SLOT(streamTitleAndUrlChanged(QString,QString)) );
  128. connect( proc, SIGNAL(failedToParseMplayerVersion(QString)),
  129. this, SIGNAL(failedToParseMplayerVersion(QString)) );
  130. connect( this, SIGNAL(mediaLoaded()), this, SLOT(checkIfVideoIsHD()), Qt::QueuedConnection );
  131. #if DELAYED_AUDIO_SETUP_ON_STARTUP
  132. connect( this, SIGNAL(mediaLoaded()), this, SLOT(initAudioTrack()), Qt::QueuedConnection );
  133. #endif
  134. #if NOTIFY_SUB_CHANGES
  135. connect( proc, SIGNAL(subtitleInfoChanged(const SubTracks &)),
  136. this, SLOT(initSubtitleTrack(const SubTracks &)), Qt::QueuedConnection );
  137. connect( proc, SIGNAL(subtitleInfoReceivedAgain(const SubTracks &)),
  138. this, SLOT(setSubtitleTrackAgain(const SubTracks &)), Qt::QueuedConnection );
  139. #endif
  140. #if NOTIFY_AUDIO_CHANGES
  141. connect( proc, SIGNAL(audioInfoChanged(const Tracks &)),
  142. this, SLOT(initAudioTrack(const Tracks &)), Qt::QueuedConnection );
  143. #endif
  144. #if DVDNAV_SUPPORT
  145. connect( proc, SIGNAL(receivedDVDTitle(int)),
  146. this, SLOT(dvdTitleChanged(int)), Qt::QueuedConnection );
  147. connect( proc, SIGNAL(receivedDuration(double)),
  148. this, SLOT(durationChanged(double)), Qt::QueuedConnection );
  149. QTimer * ask_timer = new QTimer(this);
  150. connect( ask_timer, SIGNAL(timeout()), this, SLOT(askForInfo()) );
  151. ask_timer->start(5000);
  152. connect( proc, SIGNAL(receivedTitleIsMenu()),
  153. this, SLOT(dvdTitleIsMenu()) );
  154. connect( proc, SIGNAL(receivedTitleIsMovie()),
  155. this, SLOT(dvdTitleIsMovie()) );
  156. #endif
  157. connect( this, SIGNAL(stateChanged(Core::State)),
  158. this, SLOT(watchState(Core::State)) );
  159. connect( this, SIGNAL(mediaInfoChanged()), this, SLOT(sendMediaInfo()) );
  160. connect( proc, SIGNAL(error(QProcess::ProcessError)),
  161. this, SIGNAL(mplayerFailed(QProcess::ProcessError)) );
  162. //pref->load();
  163. mset.reset();
  164. // Mplayerwindow
  165. connect( this, SIGNAL(aboutToStartPlaying()),
  166. mplayerwindow->videoLayer(), SLOT(playingStarted()) );
  167. // Necessary to hide/unhide mouse cursor on black borders
  168. connect( this, SIGNAL(aboutToStartPlaying()),
  169. mplayerwindow, SLOT(playingStarted()) );
  170. #if DVDNAV_SUPPORT
  171. connect( mplayerwindow, SIGNAL(mouseMoved(QPoint)),
  172. this, SLOT(dvdnavUpdateMousePos(QPoint)) );
  173. #endif
  174. #if REPAINT_BACKGROUND_OPTION
  175. mplayerwindow->videoLayer()->setRepaintBackground(pref->repaint_video_background);
  176. #endif
  177. mplayerwindow->setMonitorAspect( pref->monitor_aspect_double() );
  178. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  179. #ifdef SCREENSAVER_OFF
  180. // Windows or OS2 screensaver
  181. win_screensaver = new WinScreenSaver();
  182. #endif
  183. #endif
  184. #if DISCNAME_TEST
  185. DiscName::test();
  186. #endif
  187. #ifdef YOUTUBE_SUPPORT
  188. yt = new RetrieveYoutubeUrl(this);
  189. connect(yt, SIGNAL(gotPreferredUrl(const QString &)), this, SLOT(openYT(const QString &)));
  190. connect(yt, SIGNAL(connecting(QString)), this, SLOT(connectingToYT(QString)));
  191. connect(yt, SIGNAL(downloadFailed(QString)), this, SLOT(YTFailed(QString)));
  192. connect(yt, SIGNAL(gotEmptyList()), this, SLOT(YTNoVideoUrl()));
  193. #endif
  194. }
  195. Core::~Core() {
  196. #ifndef NO_USE_INI_FILES
  197. saveMediaInfo();
  198. #endif
  199. if (proc->isRunning()) stopMplayer();
  200. proc->terminate();
  201. delete proc;
  202. #ifndef NO_USE_INI_FILES
  203. delete file_settings;
  204. delete tv_settings;
  205. #endif
  206. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  207. #ifdef SCREENSAVER_OFF
  208. delete win_screensaver;
  209. #endif
  210. #endif
  211. #ifdef YOUTUBE_SUPPORT
  212. delete yt;
  213. #endif
  214. }
  215. #ifndef NO_USE_INI_FILES
  216. void Core::changeFileSettingsMethod(QString method) {
  217. qDebug("Core::changeFileSettingsMethod: %s", method.toUtf8().constData());
  218. if (file_settings) delete file_settings;
  219. if (method.toLower() == "hash")
  220. file_settings = new FileSettingsHash(Paths::iniPath());
  221. else
  222. file_settings = new FileSettings(Paths::iniPath());
  223. }
  224. #endif
  225. void Core::setState(State s) {
  226. if (s != _state) {
  227. _state = s;
  228. emit stateChanged(_state);
  229. }
  230. }
  231. QString Core::stateToString() {
  232. if (state()==Playing) return "Playing";
  233. else
  234. if (state()==Stopped) return "Stopped";
  235. else
  236. if (state()==Paused) return "Paused";
  237. else
  238. return "Unknown";
  239. }
  240. // Public restart
  241. void Core::restart() {
  242. qDebug("Core::restart");
  243. if (proc->isRunning()) {
  244. restartPlay();
  245. } else {
  246. qDebug("Core::restart: mplayer is not running");
  247. }
  248. }
  249. void Core::reload() {
  250. qDebug("Core::reload");
  251. stopMplayer();
  252. we_are_restarting = false;
  253. initPlaying();
  254. }
  255. #ifndef NO_USE_INI_FILES
  256. void Core::saveMediaInfo() {
  257. qDebug("Core::saveMediaInfo");
  258. if (pref->dont_remember_media_settings) {
  259. qDebug("Core::saveMediaInfo: not saving settings, disabled by user");
  260. return;
  261. }
  262. if ( (mdat.type == TYPE_FILE) && (!mdat.filename.isEmpty()) ) {
  263. file_settings->saveSettingsFor(mdat.filename, mset);
  264. }
  265. else
  266. if ( (mdat.type == TYPE_TV) && (!mdat.filename.isEmpty()) ) {
  267. tv_settings->saveSettingsFor(mdat.filename, mset);
  268. }
  269. }
  270. #endif // NO_USE_INI_FILES
  271. void Core::initializeMenus() {
  272. qDebug("Core::initializeMenus");
  273. emit menusNeedInitialize();
  274. }
  275. void Core::updateWidgets() {
  276. qDebug("Core::updateWidgets");
  277. emit widgetsNeedUpdate();
  278. }
  279. void Core::tellmp(const QString & command) {
  280. qDebug("Core::tellmp: '%s'", command.toUtf8().data());
  281. //qDebug("Command: '%s'", command.toUtf8().data());
  282. if (proc->isRunning()) {
  283. proc->writeToStdin( command );
  284. } else {
  285. qWarning(" tellmp: no process running: %s", command.toUtf8().data());
  286. }
  287. }
  288. void Core::displayTextOnOSD(QString text, int duration, int level, QString prefix) {
  289. qDebug("Core::displayTextOnOSD: '%s'", text.toUtf8().constData());
  290. if (proc->isRunning()) {
  291. QString str = QString("osd_show_text \"%1\" %2 %3\n").arg(text.toUtf8().constData()).arg(duration).arg(level);
  292. if (!prefix.isEmpty()) str = prefix + " " + str;
  293. qDebug("Core::displayTextOnOSD: command: '%s'", str.toUtf8().constData());
  294. proc->write(str.toAscii());
  295. }
  296. }
  297. // Generic open, autodetect type
  298. void Core::open(QString file, int seek) {
  299. qDebug("Core::open: '%s'", file.toUtf8().data());
  300. if (file.startsWith("file:")) {
  301. file = QUrl(file).toLocalFile();
  302. qDebug("Core::open: converting url to local file: %s", file.toUtf8().constData());
  303. }
  304. QFileInfo fi(file);
  305. if ( (fi.exists()) && (fi.suffix().toLower()=="iso") ) {
  306. qDebug("Core::open: * identified as a dvd iso");
  307. #if DVDNAV_SUPPORT
  308. openDVD( DiscName::joinDVD(0, file, pref->use_dvdnav) );
  309. #else
  310. openDVD( DiscName::joinDVD(1, file, false) );
  311. #endif
  312. }
  313. else
  314. if ( (fi.exists()) && (!fi.isDir()) ) {
  315. qDebug("Core::open: * identified as local file");
  316. // Local file
  317. file = QFileInfo(file).absoluteFilePath();
  318. openFile(file, seek);
  319. }
  320. else
  321. if ( (fi.exists()) && (fi.isDir()) ) {
  322. // Directory
  323. qDebug("Core::open: * identified as a directory");
  324. qDebug("Core::open: checking if contains a dvd");
  325. file = QFileInfo(file).absoluteFilePath();
  326. if (Helper::directoryContainsDVD(file)) {
  327. qDebug("Core::open: * directory contains a dvd");
  328. #if DVDNAV_SUPPORT
  329. openDVD( DiscName::joinDVD(1, file, pref->use_dvdnav) );
  330. #else
  331. openDVD( DiscName::joinDVD(1, file, false) );
  332. #endif
  333. } else {
  334. qDebug("Core::open: * directory doesn't contain a dvd");
  335. qDebug("Core::open: opening nothing");
  336. }
  337. }
  338. else
  339. if ((file.toLower().startsWith("dvd:")) || (file.toLower().startsWith("dvdnav:"))) {
  340. qDebug("Core::open: * identified as dvd");
  341. openDVD(file);
  342. /*
  343. QString f = file.lower();
  344. QRegExp s("^dvd://(\\d+)");
  345. if (s.indexIn(f) != -1) {
  346. int title = s.cap(1).toInt();
  347. openDVD(title);
  348. } else {
  349. qWarning("Core::open: couldn't parse dvd title, playing first one");
  350. openDVD();
  351. }
  352. */
  353. }
  354. else
  355. if (file.toLower().startsWith("vcd:")) {
  356. qDebug("Core::open: * identified as vcd");
  357. QString f = file.toLower();
  358. QRegExp s("^vcd://(\\d+)");
  359. if (s.indexIn(f) != -1) {
  360. int title = s.cap(1).toInt();
  361. openVCD(title);
  362. } else {
  363. qWarning("Core::open: couldn't parse vcd title, playing first one");
  364. openVCD();
  365. }
  366. }
  367. else
  368. if (file.toLower().startsWith("cdda:")) {
  369. qDebug("Core::open: * identified as cdda");
  370. QString f = file.toLower();
  371. QRegExp s("^cdda://(\\d+)");
  372. if (s.indexIn(f) != -1) {
  373. int title = s.cap(1).toInt();
  374. openAudioCD(title);
  375. } else {
  376. qWarning("Core::open: couldn't parse cdda title, playing first one");
  377. openAudioCD();
  378. }
  379. }
  380. else
  381. if ((file.toLower().startsWith("dvb:")) || (file.toLower().startsWith("tv:"))) {
  382. qDebug("Core::open: * identified as TV");
  383. openTV(file);
  384. }
  385. else {
  386. qDebug("Core::open: * not identified, playing as stream");
  387. openStream(file);
  388. }
  389. }
  390. void Core::openFile(QString filename, int seek) {
  391. qDebug("Core::openFile: '%s'", filename.toUtf8().data());
  392. QFileInfo fi(filename);
  393. if (fi.exists()) {
  394. playNewFile(fi.absoluteFilePath(), seek);
  395. } else {
  396. //File doesn't exists
  397. //TODO: error message
  398. }
  399. }
  400. #ifdef YOUTUBE_SUPPORT
  401. void Core::openYT(const QString & url) {
  402. qDebug("Core::openYT: %s", url.toUtf8().constData());
  403. openStream(url);
  404. yt->close();
  405. }
  406. void Core::connectingToYT(QString host) {
  407. emit showMessage( tr("Connecting to %1").arg(host) );
  408. }
  409. void Core::YTFailed(QString /*error*/) {
  410. emit showMessage( tr("Unable to retrieve youtube page") );
  411. }
  412. void Core::YTNoVideoUrl() {
  413. emit showMessage( tr("Unable to locate the url of the video") );
  414. }
  415. #endif
  416. void Core::loadSub(const QString & sub ) {
  417. if ( (!sub.isEmpty()) && (QFile::exists(sub)) ) {
  418. #if NOTIFY_SUB_CHANGES
  419. mset.external_subtitles = sub;
  420. just_loaded_external_subs = true;
  421. QFileInfo fi(sub);
  422. if ((pref->fast_load_sub) && (fi.suffix().toLower() != "idx")) {
  423. QString sub_file = sub;
  424. #ifdef Q_OS_WIN
  425. if (pref->use_short_pathnames) {
  426. sub_file = Helper::shortPathName(sub);
  427. // For some reason it seems it's necessary to change the path separator to unix style
  428. // otherwise mplayer fails to load it
  429. sub_file = sub_file.replace("\\","/");
  430. }
  431. #endif
  432. tellmp( "sub_load \""+ sub_file +"\"" );
  433. } else {
  434. restartPlay();
  435. }
  436. #else
  437. mset.external_subtitles = sub;
  438. just_loaded_external_subs = true;
  439. restartPlay();
  440. #endif
  441. } else {
  442. qWarning("Core::loadSub: file '%s' is not valid", sub.toUtf8().constData());
  443. }
  444. }
  445. void Core::unloadSub() {
  446. if ( !mset.external_subtitles.isEmpty() ) {
  447. mset.external_subtitles = "";
  448. just_unloaded_external_subs = true;
  449. restartPlay();
  450. }
  451. }
  452. void Core::loadAudioFile(const QString & audiofile) {
  453. if (!audiofile.isEmpty()) {
  454. mset.external_audio = audiofile;
  455. restartPlay();
  456. }
  457. }
  458. void Core::unloadAudioFile() {
  459. if (!mset.external_audio.isEmpty()) {
  460. mset.external_audio = "";
  461. restartPlay();
  462. }
  463. }
  464. /*
  465. void Core::openDVD( bool from_folder, QString directory) {
  466. qDebug("Core::openDVD");
  467. if (from_folder) {
  468. if (!directory.isEmpty()) {
  469. QFileInfo fi(directory);
  470. if ( (fi.exists()) && (fi.isDir()) ) {
  471. pref->dvd_directory = directory;
  472. pref->play_dvd_from_hd = TRUE;
  473. openDVD();
  474. } else {
  475. qDebug("Core::openDVD: directory '%s' is not valid", directory.toUtf8().data());
  476. }
  477. } else {
  478. qDebug("Core::openDVD: directory is empty");
  479. }
  480. } else {
  481. pref->play_dvd_from_hd = FALSE;
  482. openDVD();
  483. }
  484. }
  485. void Core::openDVD() {
  486. openDVD(1);
  487. }
  488. void Core::openDVD(int title) {
  489. qDebug("Core::openDVD: %d", title);
  490. if (proc->isRunning()) {
  491. stopMplayer();
  492. }
  493. // Save data of previous file:
  494. saveMediaInfo();
  495. mdat.reset();
  496. mdat.filename = "dvd://" + QString::number(title);
  497. mdat.type = TYPE_DVD;
  498. mset.reset();
  499. mset.current_title_id = title;
  500. mset.current_chapter_id = 1;
  501. mset.current_angle_id = 1;
  502. initializeMenus();
  503. initPlaying();
  504. }
  505. */
  506. void Core::openVCD(int title) {
  507. qDebug("Core::openVCD: %d", title);
  508. if (title == -1) title = pref->vcd_initial_title;
  509. if (proc->isRunning()) {
  510. stopMplayer();
  511. }
  512. // Save data of previous file:
  513. #ifndef NO_USE_INI_FILES
  514. saveMediaInfo();
  515. #endif
  516. mdat.reset();
  517. mdat.filename = "vcd://" + QString::number(title);
  518. mdat.type = TYPE_VCD;
  519. mset.reset();
  520. mset.current_title_id = title;
  521. mset.current_chapter_id = -1;
  522. mset.current_angle_id = -1;
  523. /* initializeMenus(); */
  524. initPlaying();
  525. }
  526. void Core::openAudioCD(int title) {
  527. qDebug("Core::openAudioCD: %d", title);
  528. if (title == -1) title = 1;
  529. if (proc->isRunning()) {
  530. stopMplayer();
  531. }
  532. // Save data of previous file:
  533. #ifndef NO_USE_INI_FILES
  534. saveMediaInfo();
  535. #endif
  536. mdat.reset();
  537. mdat.filename = "cdda://" + QString::number(title);
  538. mdat.type = TYPE_AUDIO_CD;
  539. mset.reset();
  540. mset.current_title_id = title;
  541. mset.current_chapter_id = -1;
  542. mset.current_angle_id = -1;
  543. /* initializeMenus(); */
  544. initPlaying();
  545. }
  546. void Core::openDVD(QString dvd_url) {
  547. qDebug("Core::openDVD: '%s'", dvd_url.toUtf8().data());
  548. //Checks
  549. DiscData disc_data = DiscName::split(dvd_url);
  550. QString folder = disc_data.device;
  551. int title = disc_data.title;
  552. if (title == -1) {
  553. qWarning("Core::openDVD: title invalid, not playing dvd");
  554. return;
  555. }
  556. if (folder.isEmpty()) {
  557. qDebug("Core::openDVD: not folder");
  558. } else {
  559. QFileInfo fi(folder);
  560. if ( (!fi.exists()) /*|| (!fi.isDir())*/ ) {
  561. qWarning("Core::openDVD: folder invalid, not playing dvd");
  562. return;
  563. }
  564. }
  565. if (proc->isRunning()) {
  566. stopMplayer();
  567. we_are_restarting = false;
  568. }
  569. // Save data of previous file:
  570. #ifndef NO_USE_INI_FILES
  571. saveMediaInfo();
  572. #endif
  573. mdat.reset();
  574. mdat.filename = dvd_url;
  575. mdat.type = TYPE_DVD;
  576. mset.reset();
  577. mset.current_title_id = title;
  578. mset.current_chapter_id = firstChapter();
  579. mset.current_angle_id = 1;
  580. /* initializeMenus(); */
  581. initPlaying();
  582. }
  583. void Core::openTV(QString channel_id) {
  584. qDebug("Core::openTV: '%s'", channel_id.toUtf8().constData());
  585. if (proc->isRunning()) {
  586. stopMplayer();
  587. we_are_restarting = false;
  588. }
  589. // Save data of previous file:
  590. #ifndef NO_USE_INI_FILES
  591. saveMediaInfo();
  592. #endif
  593. // Use last channel if the name is just "dvb://" or "tv://"
  594. if ((channel_id == "dvb://") && (!pref->last_dvb_channel.isEmpty())) {
  595. channel_id = pref->last_dvb_channel;
  596. }
  597. else
  598. if ((channel_id == "tv://") && (!pref->last_tv_channel.isEmpty())) {
  599. channel_id = pref->last_tv_channel;
  600. }
  601. // Save last channel
  602. if (channel_id.startsWith("dvb://")) pref->last_dvb_channel = channel_id;
  603. else
  604. if (channel_id.startsWith("tv://")) pref->last_tv_channel = channel_id;
  605. mdat.reset();
  606. mdat.filename = channel_id;
  607. mdat.type = TYPE_TV;
  608. mset.reset();
  609. // Set the default deinterlacer for TV
  610. mset.current_deinterlacer = pref->initial_tv_deinterlace;
  611. #ifndef NO_USE_INI_FILES
  612. if (!pref->dont_remember_media_settings) {
  613. // Check if we already have info about this file
  614. if (tv_settings->existSettingsFor(channel_id)) {
  615. qDebug("Core::openTV: we have settings for this file!!!");
  616. // In this case we read info from config
  617. tv_settings->loadSettingsFor(channel_id, mset);
  618. qDebug("Core::openTV: media settings read");
  619. }
  620. }
  621. #endif
  622. /* initializeMenus(); */
  623. initPlaying();
  624. }
  625. void Core::openStream(QString name) {
  626. qDebug("Core::openStream: '%s'", name.toUtf8().data());
  627. #ifdef YOUTUBE_SUPPORT
  628. if (name.contains("youtube.com/watch", Qt::CaseInsensitive) ||
  629. name.contains("youtu.be/", Qt::CaseInsensitive) ||
  630. name.contains("y2u.be/", Qt::CaseInsensitive) )
  631. {
  632. qDebug("Core::openStream: youtube url detected");
  633. if (name.startsWith("www.youtube.com")) name = "http://" + name;
  634. if (name.startsWith("youtube.com")) name = "http://www." + name;
  635. if (name.startsWith("youtu.be")) name = "http://" + name;
  636. if (name.startsWith("y2u.be")) name = "http://" + name;
  637. yt->setPreferredQuality( (RetrieveYoutubeUrl::Quality) pref->yt_quality );
  638. yt->fetchPage(name);
  639. return;
  640. }
  641. #endif
  642. if (proc->isRunning()) {
  643. stopMplayer();
  644. we_are_restarting = false;
  645. }
  646. // Save data of previous file:
  647. #ifndef NO_USE_INI_FILES
  648. saveMediaInfo();
  649. #endif
  650. mdat.reset();
  651. mdat.filename = name;
  652. mdat.type = TYPE_STREAM;
  653. mset.reset();
  654. /* initializeMenus(); */
  655. initPlaying();
  656. }
  657. void Core::playNewFile(QString file, int seek) {
  658. qDebug("Core::playNewFile: '%s'", file.toUtf8().data());
  659. if (proc->isRunning()) {
  660. stopMplayer();
  661. we_are_restarting = false;
  662. }
  663. // Save data of previous file:
  664. #ifndef NO_USE_INI_FILES
  665. saveMediaInfo();
  666. #endif
  667. mdat.reset();
  668. mdat.filename = file;
  669. mdat.type = TYPE_FILE;
  670. int old_volume = mset.volume;
  671. mset.reset();
  672. #ifndef NO_USE_INI_FILES
  673. // Check if we already have info about this file
  674. if (file_settings->existSettingsFor(file)) {
  675. qDebug("Core::playNewFile: We have settings for this file!!!");
  676. // In this case we read info from config
  677. if (!pref->dont_remember_media_settings) {
  678. file_settings->loadSettingsFor(file, mset);
  679. qDebug("Core::playNewFile: Media settings read");
  680. // Resize the window and set the aspect as soon as possible
  681. int saved_width = mset.win_width;
  682. int saved_height = mset.win_height;
  683. // 400x300 is the default size for win_width and win_height
  684. // so we set them to 0 to avoid to resize the window on
  685. // audio files
  686. if ((saved_width == 400) && (saved_height == 300)) {
  687. saved_width = 0;
  688. saved_height = 0;
  689. }
  690. if ((saved_width > 0) && (saved_height > 0)) {
  691. emit needResize(mset.win_width, mset.win_height);
  692. changeAspectRatio(mset.aspect_ratio_id);
  693. }
  694. if (pref->dont_remember_time_pos) {
  695. mset.current_sec = 0;
  696. qDebug("Core::playNewFile: Time pos reset to 0");
  697. }
  698. } else {
  699. qDebug("Core::playNewFile: Media settings have not read because of preferences setting");
  700. }
  701. } else {
  702. // Recover volume
  703. mset.volume = old_volume;
  704. }
  705. #else
  706. // Recover volume
  707. mset.volume = old_volume;
  708. #endif // NO_USE_INI_FILES
  709. /* initializeMenus(); */
  710. qDebug("Core::playNewFile: volume: %d, old_volume: %d", mset.volume, old_volume);
  711. initPlaying(seek);
  712. }
  713. void Core::restartPlay() {
  714. we_are_restarting = true;
  715. initPlaying();
  716. }
  717. void Core::initPlaying(int seek) {
  718. qDebug("Core::initPlaying");
  719. /*
  720. mdat.list();
  721. mset.list();
  722. */
  723. /* updateWidgets(); */
  724. mplayerwindow->hideLogo();
  725. if (proc->isRunning()) {
  726. stopMplayer();
  727. }
  728. int start_sec = (int) mset.current_sec;
  729. if (seek > -1) start_sec = seek;
  730. #ifdef YOUTUBE_SUPPORT
  731. // Avoid to pass to mplayer the youtube page url
  732. if (mdat.type == TYPE_STREAM) {
  733. if (mdat.filename == yt->origUrl()) {
  734. mdat.filename = yt->latestPreferredUrl();
  735. }
  736. }
  737. #endif
  738. startMplayer( mdat.filename, start_sec );
  739. }
  740. // This is reached when a new video has just started playing
  741. // and maybe we need to give some defaults
  742. void Core::newMediaPlaying() {
  743. qDebug("Core::newMediaPlaying: --- start ---");
  744. QString file = mdat.filename;
  745. int type = mdat.type;
  746. mdat = proc->mediaData();
  747. mdat.filename = file;
  748. mdat.type = type;
  749. initializeMenus(); // Old
  750. // Video
  751. if ( (mset.current_video_id == MediaSettings::NoneSelected) &&
  752. (mdat.videos.numItems() > 0) )
  753. {
  754. changeVideo( mdat.videos.itemAt(0).ID(), false ); // Don't allow to restart
  755. }
  756. #if !DELAYED_AUDIO_SETUP_ON_STARTUP && !NOTIFY_AUDIO_CHANGES
  757. // First audio if none selected
  758. if ( (mset.current_audio_id == MediaSettings::NoneSelected) &&
  759. (mdat.audios.numItems() > 0) )
  760. {
  761. // Don't set mset.current_audio_id here! changeAudio will do.
  762. // Otherwise changeAudio will do nothing.
  763. int audio = mdat.audios.itemAt(0).ID(); // First one
  764. if (mdat.audios.existsItemAt(pref->initial_audio_track-1)) {
  765. audio = mdat.audios.itemAt(pref->initial_audio_track-1).ID();
  766. }
  767. // Check if one of the audio tracks is the user preferred.
  768. if (!pref->audio_lang.isEmpty()) {
  769. int res = mdat.audios.findLang( pref->audio_lang );
  770. if (res != -1) audio = res;
  771. }
  772. // Change the audio without restarting mplayer, it's not
  773. // safe to do it here.
  774. changeAudio( audio, false );
  775. }
  776. #endif
  777. #if !NOTIFY_SUB_CHANGES
  778. // Subtitles
  779. if (mset.external_subtitles.isEmpty()) {
  780. if (pref->autoload_sub) {
  781. //Select first subtitle if none selected
  782. if (mset.current_sub_id == MediaSettings::NoneSelected) {
  783. int sub = mdat.subs.selectOne( pref->subtitle_lang, pref->initial_subtitle_track-1 );
  784. changeSubtitle( sub );
  785. }
  786. } else {
  787. changeSubtitle( MediaSettings::SubNone );
  788. }
  789. }
  790. #endif
  791. if (mdat.n_chapters > 0) {
  792. // Just to show the first chapter checked in the menu
  793. mset.current_chapter_id = firstChapter();
  794. }
  795. mdat.initialized = TRUE;
  796. // MPlayer doesn't display the length in ID_LENGTH for audio CDs...
  797. if ((mdat.duration == 0) && (mdat.type == TYPE_AUDIO_CD)) {
  798. /*
  799. qDebug(" *** get duration here from title info *** ");
  800. qDebug(" *** current title: %d", mset.current_title_id );
  801. */
  802. if (mset.current_title_id > 0) {
  803. mdat.duration = mdat.titles.item(mset.current_title_id).duration();
  804. }
  805. }
  806. /* updateWidgets(); */
  807. mdat.list();
  808. mset.list();
  809. qDebug("Core::newMediaPlaying: --- end ---");
  810. }
  811. void Core::finishRestart() {
  812. qDebug("Core::finishRestart: --- start ---");
  813. if (!we_are_restarting) {
  814. newMediaPlaying();
  815. //QTimer::singleShot(1000, this, SIGNAL(mediaStartPlay()));
  816. emit mediaStartPlay();
  817. }
  818. if (we_are_restarting) {
  819. // Update info about codecs and demuxer
  820. mdat.video_codec = proc->mediaData().video_codec;
  821. mdat.audio_codec = proc->mediaData().audio_codec;
  822. mdat.demuxer = proc->mediaData().demuxer;
  823. }
  824. #ifdef YOUTUBE_SUPPORT
  825. // Change the real url with the youtube page url and set the title
  826. if (mdat.type == TYPE_STREAM) {
  827. if (mdat.filename == yt->latestPreferredUrl()) {
  828. mdat.filename = yt->origUrl();
  829. mdat.stream_title = yt->urlTitle();
  830. }
  831. }
  832. #endif
  833. #if !NOTIFY_SUB_CHANGES
  834. // Subtitles
  835. //if (we_are_restarting) {
  836. if ( (just_loaded_external_subs) || (just_unloaded_external_subs) ) {
  837. qDebug("Core::finishRestart: processing new subtitles");
  838. // Just to simplify things
  839. if (mset.current_sub_id == MediaSettings::NoneSelected) {
  840. mset.current_sub_id = MediaSettings::SubNone;
  841. }
  842. // Save current sub
  843. SubData::Type type;
  844. int ID;
  845. int old_item = -1;
  846. if ( mset.current_sub_id != MediaSettings::SubNone ) {
  847. old_item = mset.current_sub_id;
  848. type = mdat.subs.itemAt(old_item).type();
  849. ID = mdat.subs.itemAt(old_item).ID();
  850. }
  851. // Use the subtitle info from mplayerprocess
  852. qDebug( "Core::finishRestart: copying sub data from proc to mdat");
  853. mdat.subs = proc->mediaData().subs;
  854. initializeMenus();
  855. int item = MediaSettings::SubNone;
  856. // Try to recover old subtitle
  857. if (just_unloaded_external_subs) {
  858. if (old_item > -1) {
  859. int new_item = mdat.subs.find(type, ID);
  860. if (new_item > -1) item = new_item;
  861. }
  862. }
  863. // If we've just loaded a subtitle file
  864. // select one if the user wants to autoload
  865. // one subtitle
  866. if (just_loaded_external_subs) {
  867. if ( (pref->autoload_sub) && (item == MediaSettings::SubNone) ) {
  868. qDebug("Core::finishRestart: cannot find previous subtitle");
  869. qDebug("Core::finishRestart: selecting a new one");
  870. item = mdat.subs.selectOne( pref->subtitle_lang );
  871. }
  872. }
  873. changeSubtitle( item );
  874. just_loaded_external_subs = false;
  875. just_unloaded_external_subs = false;
  876. } else {
  877. // Normal restart, subtitles haven't changed
  878. // Recover current subtitle
  879. changeSubtitle( mset.current_sub_id );
  880. }
  881. #endif
  882. we_are_restarting = false;
  883. changeAspectRatio(mset.aspect_ratio_id);
  884. if (pref->global_volume) {
  885. bool was_muted = pref->mute;
  886. setVolume( pref->volume, true);
  887. if (was_muted) mute(true);
  888. } else {
  889. bool was_muted = mset.mute;
  890. setVolume( mset.volume, true );
  891. if (was_muted) mute(true);
  892. }
  893. if (pref->change_video_equalizer_on_startup && (mset.gamma != 0)) {
  894. int gamma = mset.gamma;
  895. mset.gamma = -1000; // if mset.gamma == new value, mset.gamma is not changed!
  896. setGamma( gamma );
  897. }
  898. // Hack to be sure that the equalizers are up to date
  899. emit videoEqualizerNeedsUpdate();
  900. emit audioEqualizerNeedsUpdate();
  901. changeZoom(mset.zoom_factor);
  902. // Toggle subtitle visibility
  903. changeSubVisibility(pref->sub_visibility);
  904. // A-B marker
  905. emit ABMarkersChanged(mset.A_marker, mset.B_marker);
  906. // Initialize the OSD level
  907. QTimer::singleShot(pref->osd_delay, this, SLOT(initializeOSD()));
  908. emit mediaLoaded();
  909. emit mediaInfoChanged();
  910. updateWidgets(); // New
  911. qDebug("Core::finishRestart: --- end ---");
  912. }
  913. void Core::initializeOSD() {
  914. changeOSD(pref->osd);
  915. }
  916. void Core::stop()
  917. {
  918. qDebug("Core::stop");
  919. qDebug("Core::stop: state: %s", stateToString().toUtf8().data());
  920. if (state()==Stopped) {
  921. // if pressed stop twice, reset video to the beginning
  922. qDebug("Core::stop: mset.current_sec: %f", mset.current_sec);
  923. mset.current_sec = 0;
  924. qDebug("Core::stop: mset.current_sec set to 0");
  925. emit showTime( mset.current_sec );
  926. #ifdef SEEKBAR_RESOLUTION
  927. emit positionChanged( 0 );
  928. #else
  929. emit posChanged( 0 );
  930. #endif
  931. //updateWidgets();
  932. }
  933. stopMplayer();
  934. emit mediaStoppedByUser();
  935. }
  936. void Core::play()
  937. {
  938. qDebug("Core::play");
  939. if ((proc->isRunning()) && (state()==Paused)) {
  940. tellmp("pause"); // Unpauses
  941. }
  942. else
  943. if ((proc->isRunning()) && (state()==Playing)) {
  944. // nothing to do, continue playing
  945. }
  946. else {
  947. // if we're stopped, play it again
  948. if ( !mdat.filename.isEmpty() ) {
  949. /*
  950. qDebug( "current_sec: %f, duration: %f", mset.current_sec, mdat.duration);
  951. if ( (floor(mset.current_sec)) >= (floor(mdat.duration)) ) {
  952. mset.current_sec = 0;
  953. }
  954. */
  955. restartPlay();
  956. }
  957. }
  958. }
  959. void Core::pause_and_frame_step() {
  960. qDebug("Core::pause_and_frame_step");
  961. if (proc->isRunning()) {
  962. if (state() == Paused) {
  963. tellmp("frame_step");
  964. }
  965. else {
  966. tellmp("pause");
  967. }
  968. }
  969. }
  970. void Core::pause() {
  971. qDebug("Core::pause");
  972. qDebug("Core::pause: current state: %s", stateToString().toUtf8().data());
  973. if (proc->isRunning()) {
  974. // Pauses and unpauses
  975. tellmp("pause");
  976. }
  977. }
  978. void Core::play_or_pause() {
  979. if (proc->isRunning()) {
  980. pause();
  981. } else {
  982. play();
  983. }
  984. }
  985. void Core::frameStep() {
  986. qDebug("Core::frameStep");
  987. if (proc->isRunning()) {
  988. tellmp("frame_step");
  989. }
  990. }
  991. void Core::screenshot() {
  992. qDebug("Core::screenshot");
  993. if ( (!pref->screenshot_directory.isEmpty()) &&
  994. (QFileInfo(pref->screenshot_directory).isDir()) )
  995. {
  996. tellmp( pausing_prefix() + " screenshot 0");
  997. qDebug("Core::screenshot: taken screenshot");
  998. } else {
  999. qDebug("Core::screenshot: error: directory for screenshots not valid");
  1000. emit showMessage( tr("Screenshot NOT taken, folder not configured") );
  1001. }
  1002. }
  1003. void Core::screenshots() {
  1004. qDebug("Core::screenshots");
  1005. if ( (!pref->screenshot_directory.isEmpty()) &&
  1006. (QFileInfo(pref->screenshot_directory).isDir()) )
  1007. {
  1008. tellmp( "screenshot 1");
  1009. } else {
  1010. qDebug("Core::screenshots: error: directory for screenshots not valid");
  1011. emit showMessage( tr("Screenshots NOT taken, folder not configured") );
  1012. }
  1013. }
  1014. void Core::processFinished()
  1015. {
  1016. qDebug("Core::processFinished");
  1017. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  1018. #ifdef SCREENSAVER_OFF
  1019. // Restores the Windows or OS2 screensaver
  1020. if (pref->turn_screensaver_off) {
  1021. win_screensaver->enable();
  1022. }
  1023. #endif
  1024. #endif
  1025. qDebug("Core::processFinished: we_are_restarting: %d", we_are_restarting);
  1026. //mset.current_sec = 0;
  1027. if (!we_are_restarting) {
  1028. qDebug("Core::processFinished: play has finished!");
  1029. setState(Stopped);
  1030. //emit stateChanged(state());
  1031. }
  1032. int exit_code = proc->exitCode();
  1033. qDebug("Core::processFinished: exit_code: %d", exit_code);
  1034. if (exit_code != 0) {
  1035. emit mplayerFinishedWithError(exit_code);
  1036. }
  1037. }
  1038. void Core::fileReachedEnd() {
  1039. /*
  1040. if (mdat.type == TYPE_VCD) {
  1041. // If the first vcd title has nothing, it doesn't start to play
  1042. // and menus are not initialized.
  1043. initializeMenus();
  1044. }
  1045. */
  1046. // If we're at the end of the movie, reset to 0
  1047. mset.current_sec = 0;
  1048. updateWidgets();
  1049. emit mediaFinished();
  1050. }
  1051. #if SEEKBAR_RESOLUTION
  1052. void Core::goToPosition(int value) {
  1053. qDebug("Core::goToPosition: value: %d", value);
  1054. if (pref->relative_seeking) {
  1055. goToPos( (double) value / (SEEKBAR_RESOLUTION / 100) );
  1056. }
  1057. else {
  1058. if (mdat.duration > 0) {
  1059. int jump_time = (int) mdat.duration * value / SEEKBAR_RESOLUTION;
  1060. goToSec(jump_time);
  1061. }
  1062. }
  1063. }
  1064. void Core::goToPos(double perc) {
  1065. qDebug("Core::goToPos: per: %f", perc);
  1066. tellmp( seek_cmd(perc, 1) );
  1067. }
  1068. #else
  1069. void Core::goToPos(int perc) {
  1070. qDebug("Core::goToPos: per: %d", perc);
  1071. tellmp( seek_cmd(perc, 1) );
  1072. }
  1073. #endif
  1074. void Core::startMplayer( QString file, double seek ) {
  1075. qDebug("Core::startMplayer");
  1076. if (file.isEmpty()) {
  1077. qWarning("Core:startMplayer: file is empty!");
  1078. return;
  1079. }
  1080. if (proc->isRunning()) {
  1081. qWarning("Core::startMplayer: MPlayer still running!");
  1082. return;
  1083. }
  1084. #ifdef YOUTUBE_SUPPORT
  1085. // Stop any pending request
  1086. qDebug("Core::startMplayer: yt state: %d", yt->state());
  1087. if (yt->state() != QHttp::Unconnected) {
  1088. //yt->abort(); /* Make the app to crash, don't know why */
  1089. }
  1090. #endif
  1091. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  1092. #ifdef SCREENSAVER_OFF
  1093. // Disable the Windows or OS2 screensaver
  1094. if (pref->turn_screensaver_off) {
  1095. win_screensaver->disable();
  1096. }
  1097. #endif
  1098. #endif
  1099. bool is_mkv = (QFileInfo(file).suffix().toLower() == "mkv");
  1100. // DVD
  1101. QString dvd_folder;
  1102. int dvd_title = -1;
  1103. if (mdat.type==TYPE_DVD) {
  1104. DiscData disc_data = DiscName::split(file);
  1105. dvd_folder = disc_data.device;
  1106. if (dvd_folder.isEmpty()) dvd_folder = pref->dvd_device;
  1107. dvd_title = disc_data.title;
  1108. file = disc_data.protocol + "://";
  1109. if (dvd_title > 0) file += QString::number(dvd_title);
  1110. }
  1111. // Check URL playlist
  1112. bool url_is_playlist = false;
  1113. if (file.endsWith("|playlist")) {
  1114. url_is_playlist = true;
  1115. file = file.remove("|playlist");
  1116. } else {
  1117. QUrl url(file);
  1118. qDebug("Core::startMplayer: checking if stream is a playlist");
  1119. qDebug("Core::startMplayer: url path: '%s'", url.path().toUtf8().constData());
  1120. QRegExp rx("\\.ram$|\\.asx$|\\.m3u$|\\.pls$", Qt::CaseInsensitive);
  1121. url_is_playlist = (rx.indexIn(url.path()) != -1);
  1122. }
  1123. qDebug("Core::startMplayer: url_is_playlist: %d", url_is_playlist);
  1124. bool screenshot_enabled = ( (pref->use_screenshot) &&
  1125. (!pref->screenshot_directory.isEmpty()) &&
  1126. (QFileInfo(pref->screenshot_directory).isDir()) );
  1127. proc->clearArguments();
  1128. // Set working directory to screenshot directory
  1129. if (screenshot_enabled) {
  1130. qDebug("Core::startMplayer: setting working directory to '%s'", pref->screenshot_directory.toUtf8().data());
  1131. proc->setWorkingDirectory( pref->screenshot_directory );
  1132. }
  1133. // Use absolute path, otherwise after changing to the screenshot directory
  1134. // the mplayer path might not be found if it's a relative path
  1135. // (seems to be necessary only for linux)
  1136. QString mplayer_bin = pref->mplayer_bin;
  1137. QFileInfo fi(mplayer_bin);
  1138. if (fi.exists() && fi.isExecutable() && !fi.isDir()) {
  1139. mplayer_bin = fi.absoluteFilePath();
  1140. }
  1141. proc->addArgument( mplayer_bin );
  1142. proc->addArgument("-noquiet");
  1143. #ifdef LOG_MPLAYER
  1144. if (pref->verbose_log) {
  1145. proc->addArgument("-v");
  1146. }
  1147. #endif
  1148. if (pref->fullscreen && pref->use_mplayer_window) {
  1149. proc->addArgument("-fs");
  1150. } else {
  1151. // No mplayer fullscreen mode
  1152. #if !USE_MPLAYER_PANSCAN
  1153. proc->addArgument("-nofs");
  1154. #else
  1155. // The command 'panscan' requires -fs
  1156. proc->addArgument("-fs");
  1157. #endif
  1158. }
  1159. proc->addArgument("-nomouseinput");
  1160. // Demuxer and audio and video codecs:
  1161. if (!mset.forced_demuxer.isEmpty()) {
  1162. proc->addArgument("-demuxer");
  1163. proc->addArgument(mset.forced_demuxer);
  1164. }
  1165. if (!mset.forced_audio_codec.isEmpty()) {
  1166. proc->addArgument("-ac");
  1167. proc->addArgument(mset.forced_audio_codec);
  1168. }
  1169. if (!mset.forced_video_codec.isEmpty()) {
  1170. proc->addArgument("-vc");
  1171. proc->addArgument(mset.forced_video_codec);
  1172. }
  1173. #ifndef Q_OS_WIN
  1174. else {
  1175. /* if (pref->vo.startsWith("x11")) { */ // My card doesn't support vdpau, I use x11 to test
  1176. if (pref->vo.startsWith("vdpau")) {
  1177. QString c;
  1178. if (pref->vdpau.ffh264vdpau) c += "ffh264vdpau,";
  1179. if (pref->vdpau.ffmpeg12vdpau) c += "ffmpeg12vdpau,";
  1180. if (pref->vdpau.ffwmv3vdpau) c += "ffwmv3vdpau,";
  1181. if (pref->vdpau.ffvc1vdpau) c += "ffvc1vdpau,";
  1182. if (pref->vdpau.ffodivxvdpau) c += "ffodivxvdpau,";
  1183. if (!c.isEmpty()) {
  1184. proc->addArgument("-vc");
  1185. proc->addArgument(c);
  1186. }
  1187. }
  1188. #endif
  1189. else {
  1190. if (pref->coreavc) {
  1191. proc->addArgument("-vc");
  1192. proc->addArgument("coreserve,");
  1193. }
  1194. }
  1195. #ifndef Q_OS_WIN
  1196. }
  1197. #endif
  1198. if (pref->use_hwac3) {
  1199. proc->addArgument("-afm");
  1200. proc->addArgument("hwac3");
  1201. }
  1202. QString lavdopts;
  1203. if ( (pref->h264_skip_loop_filter == Preferences::LoopDisabled) ||
  1204. ((pref->h264_skip_loop_filter == Preferences::LoopDisabledOnHD) &&
  1205. (mset.is264andHD)) )
  1206. {
  1207. if (!lavdopts.isEmpty()) lavdopts += ":";
  1208. lavdopts += "skiploopfilter=all";
  1209. }
  1210. if (pref->threads > 1) {
  1211. if (!lavdopts.isEmpty()) lavdopts += ":";
  1212. lavdopts += "threads=" + QString::number(pref->threads);
  1213. }
  1214. if (!lavdopts.isEmpty()) {
  1215. proc->addArgument("-lavdopts");
  1216. proc->addArgument(lavdopts);
  1217. }
  1218. proc->addArgument("-sub-fuzziness");
  1219. proc->addArgument( QString::number(pref->subfuzziness) );
  1220. proc->addArgument("-identify");
  1221. if (MplayerVersion::isMplayerAtLeast(27667)) {
  1222. // From r27667 the number of chapters can be obtained from ID_CHAPTERS
  1223. mset.current_chapter_id = 0; // Reset chapters
  1224. } else {
  1225. // We need this to get info about mkv chapters
  1226. if (is_mkv) {
  1227. proc->addArgument("-msglevel");
  1228. proc->addArgument("demux=6");
  1229. // **** Reset chapter ***
  1230. // Select first chapter, otherwise we cannot
  1231. // resume playback at the same point
  1232. // (time would be relative to chapter)
  1233. mset.current_chapter_id = 0;
  1234. }
  1235. }
  1236. proc->addArgument("-slave");
  1237. if (!pref->vo.isEmpty()) {
  1238. proc->addArgument( "-vo");
  1239. proc->addArgument( pref->vo );
  1240. } else {
  1241. proc->addArgument("-vo");
  1242. #ifdef Q_OS_WIN
  1243. if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) {
  1244. proc->addArgument("direct3d,");
  1245. } else {
  1246. proc->addArgument("directx,");
  1247. }
  1248. #else
  1249. proc->addArgument("xv,");
  1250. #endif
  1251. }
  1252. #if USE_ADAPTER
  1253. if (pref->adapter > -1) {
  1254. proc->addArgument("-adapter");
  1255. proc->addArgument(QString::number(pref->adapter));
  1256. }
  1257. #endif
  1258. if (!pref->ao.isEmpty()) {
  1259. proc->addArgument( "-ao");
  1260. proc->addArgument( pref->ao );
  1261. }
  1262. #if !defined(Q_OS_WIN) && !defined(Q_OS_OS2)
  1263. if (pref->vo.startsWith("x11")) {
  1264. proc->addArgument( "-zoom");
  1265. }
  1266. #endif
  1267. proc->addArgument("-nokeepaspect");
  1268. // Performance options
  1269. #ifdef Q_OS_WIN
  1270. QString p;
  1271. int app_p = NORMAL_PRIORITY_CLASS;
  1272. switch (pref->priority) {
  1273. case Preferences::Realtime: p = "realtime";
  1274. app_p = REALTIME_PRIORITY_CLASS;
  1275. break;
  1276. case Preferences::High: p = "high";
  1277. app_p = REALTIME_PRIORITY_CLASS;
  1278. break;
  1279. case Preferences::AboveNormal: p = "abovenormal";
  1280. app_p = HIGH_PRIORITY_CLASS;
  1281. break;
  1282. case Preferences::Normal: p = "normal";
  1283. app_p = ABOVE_NORMAL_PRIORITY_CLASS;
  1284. break;
  1285. case Preferences::BelowNormal: p = "belownormal"; break;
  1286. case Preferences::Idle: p = "idle"; break;
  1287. default: p = "normal";
  1288. }
  1289. proc->addArgument("-priority");
  1290. proc->addArgument( p );
  1291. SetPriorityClass(GetCurrentProcess(), app_p);
  1292. qDebug("Core::startMplayer: priority of smplayer process set to %d", app_p);
  1293. #endif
  1294. if (pref->frame_drop) {
  1295. proc->addArgument("-framedrop");
  1296. }
  1297. if (pref->hard_frame_drop) {
  1298. proc->addArgument("-hardframedrop");
  1299. }
  1300. if (pref->autosync) {
  1301. proc->addArgument("-autosync");
  1302. proc->addArgument( QString::number( pref->autosync_factor ) );
  1303. }
  1304. if (pref->use_mc) {
  1305. proc->addArgument("-mc");
  1306. proc->addArgument( QString::number( pref->mc_value ) );
  1307. }
  1308. if (pref->use_direct_rendering) {
  1309. proc->addArgument("-dr");
  1310. } else {
  1311. proc->addArgument("-nodr");
  1312. }
  1313. if (pref->use_double_buffer) {
  1314. proc->addArgument("-double");
  1315. } else {
  1316. proc->addArgument("-nodouble");
  1317. }
  1318. #if !defined(Q_OS_WIN) && !defined(Q_OS_OS2)
  1319. if (!pref->use_mplayer_window) {
  1320. proc->addArgument( "-input" );
  1321. if (MplayerVersion::isMplayerAtLeast(29058)) {
  1322. proc->addArgument( "nodefault-bindings:conf=/dev/null" );
  1323. } else {
  1324. proc->addArgument( "conf=" + Paths::dataPath() +"/input.conf" );
  1325. }
  1326. }
  1327. #endif
  1328. #ifdef Q_WS_X11
  1329. if (pref->disable_screensaver) {
  1330. proc->addArgument("-stop-xscreensaver");
  1331. } else {
  1332. proc->addArgument("-nostop-xscreensaver");
  1333. }
  1334. #endif
  1335. if (!pref->use_mplayer_window) {
  1336. proc->addArgument("-wid");
  1337. #if defined(Q_OS_OS2)
  1338. #define WINIDFROMHWND(hwnd) ( ( hwnd ) - 0x80000000UL )
  1339. proc->addArgument( QString::number( WINIDFROMHWND( (int) mplayerwindow->videoLayer()->winId() ) ));
  1340. #else
  1341. proc->addArgument( QString::number( (qint64) mplayerwindow->videoLayer()->winId() ) );
  1342. #endif
  1343. #if USE_COLORKEY
  1344. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  1345. if ((pref->vo.startsWith("directx")) || (pref->vo.startsWith("kva")) || (pref->vo.isEmpty())) {
  1346. proc->addArgument("-colorkey");
  1347. //proc->addArgument( "0x"+QString::number(pref->color_key, 16) );
  1348. proc->addArgument( ColorUtils::colorToRGB(pref->color_key) );
  1349. } else {
  1350. #endif
  1351. qDebug("Core::startMplayer: * not using -colorkey for %s", pref->vo.toUtf8().data());
  1352. qDebug("Core::startMplayer: * report if you can't see the video");
  1353. #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
  1354. }
  1355. #endif
  1356. #endif
  1357. // Square pixels
  1358. proc->addArgument("-monitorpixelaspect");
  1359. proc->addArgument("1");
  1360. } else {
  1361. // no -wid
  1362. if (!pref->monitor_aspect.isEmpty()) {
  1363. proc->addArgument("-monitoraspect");
  1364. proc->addArgument( pref->monitor_aspect );
  1365. }
  1366. }
  1367. // Subtitles fonts
  1368. if ((pref->use_ass_subtitles) && (pref->freetype_support)) {
  1369. // ASS:
  1370. proc->addArgument("-ass");
  1371. proc->addArgument("-embeddedfonts");
  1372. proc->addArgument("-ass-line-spacing");
  1373. proc->addArgument(QString::number(pref->ass_line_spacing));
  1374. proc->addArgument( "-ass-font-scale");
  1375. proc->addArgument( QString::number(mset.sub_scale_ass) );
  1376. if (!pref->force_ass_styles) {
  1377. // Load the styles.ass file
  1378. if (!QFile::exists(Paths::subtitleStyleFile())) {
  1379. // If file doesn't exist, create it
  1380. pref->ass_styles.exportStyles(Paths::subtitleStyleFile());
  1381. }
  1382. if (QFile::exists(Paths::subtitleStyleFile())) {
  1383. proc->addArgument("-ass-styles");
  1384. proc->addArgument( Paths::subtitleStyleFile() );
  1385. } else {
  1386. qWarning("Core::startMplayer: '%s' doesn't exist", Paths::subtitleStyleFile().toUtf8().constData());
  1387. }
  1388. } else {
  1389. // Force styles for ass subtitles too
  1390. proc->addArgument("-ass-force-style");
  1391. if (!pref->user_forced_ass_style.isEmpty()) {
  1392. proc->addArgument(pref->user_forced_ass_style);
  1393. } else {
  1394. proc->addArgument(pref->ass_styles.toString());
  1395. }
  1396. }
  1397. // Use the same font for OSD
  1398. #if !defined(Q_OS_OS2)
  1399. if (!pref->ass_styles.fontname.isEmpty()) {
  1400. proc->addArgument("-fontconfig");
  1401. proc->addArgument("-font");
  1402. proc->addArgument( pref->ass_styles.fontname );
  1403. }
  1404. #endif
  1405. // Set the size of OSD
  1406. if (pref->freetype_support) {
  1407. proc->addArgument("-subfont-autoscale");
  1408. proc->addArgument("0");
  1409. proc->addArgument("-subfont-osd-scale");
  1410. proc->addArgument(QString::number(pref->ass_styles.fontsize));
  1411. proc->addArgument("-subfont-text-scale"); // Old versions (like 1.0rc2) need this
  1412. proc->addArgument(QString::number(pref->ass_styles.fontsize));
  1413. }
  1414. } else {
  1415. // NO ASS:
  1416. if (pref->freetype_support) proc->addArgument("-noass");
  1417. #if !defined(Q_OS_OS2)
  1418. if ( (pref->use_fontconfig) && (!pref->font_name.isEmpty()) ) {
  1419. proc->addArgument("-fontconfig");
  1420. proc->addArgument("-font");
  1421. proc->addArgument( pref->font_name );
  1422. }
  1423. #endif
  1424. if ( (!pref->use_fontconfig) && (!pref->font_file.isEmpty()) ) {
  1425. proc->addArgument("-font");
  1426. proc->addArgument( pref->font_file );
  1427. }
  1428. if (pref->freetype_support) {
  1429. proc->addArgument( "-subfont-autoscale");
  1430. proc->addArgument( QString::number( pref->font_autoscale ) );
  1431. proc->addArgument( "-subfont-text-scale");
  1432. proc->addArgument( QString::number(mset.sub_scale) );
  1433. }
  1434. }
  1435. // Subtitle encoding
  1436. {
  1437. QString encoding;
  1438. if ( (pref->use_enca) && (!pref->enca_lang.isEmpty()) ) {
  1439. encoding = "enca:"+ pref->enca_lang;
  1440. if (!pref->subcp.isEmpty()) {
  1441. encoding += ":"+ pref->subcp;
  1442. }
  1443. }
  1444. else
  1445. if (!pref->subcp.isEmpty()) {
  1446. encoding = pref->subcp;
  1447. }
  1448. if (!encoding.isEmpty()) {
  1449. proc->addArgument("-subcp");
  1450. proc->addArgument( encoding );
  1451. }
  1452. }
  1453. if (mset.closed_caption_channel > 0) {
  1454. proc->addArgument("-subcc");
  1455. if (MplayerVersion::isMplayerAtLeast(32607)) {
  1456. proc->addArgument( QString::number( mset.closed_caption_channel ) );
  1457. }
  1458. }
  1459. if (pref->use_forced_subs_only) {
  1460. proc->addArgument("-forcedsubsonly");
  1461. }
  1462. #if PROGRAM_SWITCH
  1463. if ( (mset.current_program_id != MediaSettings::NoneSelected) /*&&
  1464. (mset.current_video_id == MediaSettings::NoneSelected) &&
  1465. (mset.current_audio_id == MediaSettings::NoneSelected)*/ )
  1466. {
  1467. proc->addArgument("-tsprog");
  1468. proc->addArgument( QString::number( mset.current_program_id ) );
  1469. }
  1470. // Don't set video and audio track if using -tsprog
  1471. else {
  1472. #endif
  1473. if (mset.current_video_id != MediaSettings::NoneSelected) {
  1474. proc->addArgument("-vid");
  1475. proc->addArgument( QString::number( mset.current_video_id ) );
  1476. }
  1477. if (mset.current_audio_id != MediaSettings::NoneSelected) {
  1478. // Workaround for MPlayer bug #1321 (http://bugzilla.mplayerhq.hu/show_bug.cgi?id=1321)
  1479. if (mdat.audios.numItems() != 1) {
  1480. proc->addArgument("-aid");
  1481. proc->addArgument( QString::number( mset.current_audio_id ) );
  1482. }
  1483. }
  1484. #if PROGRAM_SWITCH
  1485. }
  1486. #endif
  1487. if (!initial_subtitle.isEmpty()) {
  1488. mset.external_subtitles = initial_subtitle;
  1489. initial_subtitle = "";
  1490. just_loaded_external_subs = true; // Big ugly hack :(
  1491. }
  1492. if (!mset.external_subtitles.isEmpty()) {
  1493. if (QFileInfo(mset.external_subtitles).suffix().toLower()=="idx") {
  1494. // sub/idx subtitles
  1495. QFileInfo fi;
  1496. #ifdef Q_OS_WIN
  1497. if (pref->use_short_pathnames)
  1498. fi.setFile(Helper::shortPathName(mset.external_subtitles));
  1499. else
  1500. #endif
  1501. fi.setFile(mset.external_subtitles);
  1502. QString s = fi.path() +"/"+ fi.completeBaseName();
  1503. qDebug("Core::startMplayer: subtitle file without extension: '%s'", s.toUtf8().data());
  1504. proc->addArgument("-vobsub");
  1505. proc->addArgument( s );
  1506. } else {
  1507. proc->addArgument("-sub");
  1508. #ifdef Q_OS_WIN
  1509. if (pref->use_short_pathnames)
  1510. proc->addArgument(Helper::shortPathName(mset.external_subtitles));
  1511. else
  1512. #endif
  1513. proc->addArgument( mset.external_subtitles );
  1514. }
  1515. }
  1516. if (!mset.external_audio.isEmpty()) {
  1517. proc->addArgument("-audiofile");
  1518. #ifdef Q_OS_WIN
  1519. if (pref->use_short_pathnames)
  1520. proc->addArgument(Helper::shortPathName(mset.external_audio));
  1521. else
  1522. #endif
  1523. proc->addArgument( mset.external_audio );
  1524. }
  1525. proc->addArgument("-subpos");
  1526. proc->addArgument( QString::number(mset.sub_pos) );
  1527. if (mset.audio_delay!=0) {
  1528. proc->addArgument("-delay");
  1529. proc->addArgument( QString::number( (double) mset.audio_delay/1000 ) );
  1530. }
  1531. if (mset.sub_delay!=0) {
  1532. proc->addArgument("-subdelay");
  1533. proc->addArgument( QString::number( (double) mset.sub_delay/1000 ) );
  1534. }
  1535. // Contrast, brightness...
  1536. if (pref->change_video_equalizer_on_startup) {
  1537. if (mset.contrast != 0) {
  1538. proc->addArgument("-contrast");
  1539. proc->addArgument( QString::number( mset.contrast ) );
  1540. }
  1541. if (mset.brightness != 0) {
  1542. proc->addArgument("-brightness");
  1543. proc->addArgument( QString::number( mset.brightness ) );
  1544. }
  1545. if (mset.hue != 0) {
  1546. proc->addArgument("-hue");
  1547. proc->addArgument( QString::number( mset.hue ) );
  1548. }
  1549. if (mset.saturation != 0) {
  1550. proc->addArgument("-saturation");
  1551. proc->addArgument( QString::number( mset.saturation ) );
  1552. }
  1553. }
  1554. // Set volume, requires mplayer svn r27872
  1555. bool use_volume_option = (MplayerVersion::isMplayerAtLeast(27872));
  1556. if (pref->global_volume) {
  1557. if (use_volume_option) {
  1558. proc->addArgument("-volume");
  1559. proc->addArgument( QString::number( pref->volume ) );
  1560. }
  1561. } else {
  1562. if (use_volume_option) {
  1563. proc->addArgument("-volume");
  1564. // Note: mset.volume may not be right, it can be the volume of the previous video if
  1565. // playing a new one, but I think it's better to use anyway the current volume on
  1566. // startup than set it to 0 or something.
  1567. // The right volume will be set later, when the video starts to play.
  1568. proc->addArgument( QString::number( mset.volume ) );
  1569. }
  1570. }
  1571. if (mdat.type==TYPE_DVD) {
  1572. if (!dvd_folder.isEmpty()) {
  1573. proc->addArgument("-dvd-device");
  1574. proc->addArgument( dvd_folder );
  1575. } else {
  1576. qWarning("Core::startMplayer: dvd device is empty!");
  1577. }
  1578. }
  1579. if ((mdat.type==TYPE_VCD) || (mdat.type==TYPE_AUDIO_CD)) {
  1580. if (!pref->cdrom_device.isEmpty()) {
  1581. proc->addArgument("-cdrom-device");
  1582. proc->addArgument( pref->cdrom_device );
  1583. }
  1584. }
  1585. if (mset.current_chapter_id > 0) {
  1586. proc->addArgument("-chapter");
  1587. int chapter = mset.current_chapter_id;
  1588. // Fix for older versions of mplayer:
  1589. if ((mdat.type == TYPE_DVD) && (firstChapter() == 0)) chapter++;
  1590. proc->addArgument( QString::number( chapter ) );
  1591. }
  1592. if (mset.current_angle_id > 0) {
  1593. proc->addArgument("-dvdangle");
  1594. proc->addArgument( QString::number( mset.current_angle_id ) );
  1595. }
  1596. int cache = 0;
  1597. switch (mdat.type) {
  1598. case TYPE_FILE : cache = pref->cache_for_files; break;
  1599. case TYPE_DVD : cache = pref->cache_for_dvds;
  1600. #if DVDNAV_SUPPORT
  1601. if (file.startsWith("dvdnav:")) cache = 0;

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