"Fossies" - the Fresh Open Source Software Archive

Member "kaffeine-2.0.18/src/backend-mplayer/mplayermediawidget.cpp" (14 May 2019, 14728 Bytes) of package /linux/misc/kaffeine-2.0.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mplayermediawidget.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.0.14_vs_2.0.15.

    1 /*
    2  * mplayermediawidget.cpp
    3  *
    4  * Copyright (C) 2010-2011 Christoph Pfister <christophpfister@gmail.com>
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License along
   17  * with this program; if not, write to the Free Software Foundation, Inc.,
   18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19  */
   20 
   21 #include <KLocalizedString>
   22 #include <KMessageBox>
   23 
   24 #include "mplayermediawidget.h"
   25 #include "mplayervideowidget.h"
   26 
   27 MPlayerMediaWidget::MPlayerMediaWidget(QWidget *parent) : AbstractMediaWidget(parent),
   28     muted(false), volume(0), aspectRatio(MediaWidget::AspectRatioAuto), deinterlacing(false),
   29     timerId(0), videoWidth(0), videoHeight(0), videoAspectRatio(1)
   30 {
   31     videoWidget = new MPlayerVideoWidget(this);
   32     standardError.open(stderr, QIODevice::WriteOnly);
   33     connect(&process, SIGNAL(error(QProcess::ProcessError)),
   34         this, SLOT(error(QProcess::ProcessError)));
   35     connect(&process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
   36     connect(&process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));
   37     process.start(QString("mplayer -idle -osdlevel 0 -quiet -slave -softvol -vf yadif "
   38         "-volume 0 -wid %1").arg(videoWidget->winId()));
   39 }
   40 
   41 MPlayerMediaWidget::~MPlayerMediaWidget()
   42 {
   43     sendCommand(Quit);
   44     process.waitForFinished(10000);
   45 }
   46 
   47 AbstractMediaWidget *MPlayerMediaWidget::createMPlayerMediaWidget(QWidget *parent)
   48 {
   49     return new MPlayerMediaWidget(parent);
   50 }
   51 
   52 void MPlayerMediaWidget::setMuted(bool muted_)
   53 {
   54     muted = muted_;
   55     sendCommand(SetVolume);
   56 }
   57 
   58 void MPlayerMediaWidget::setVolume(int volume_)
   59 {
   60     volume = volume_;
   61     sendCommand(SetVolume);
   62 }
   63 
   64 void MPlayerMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio_)
   65 {
   66     aspectRatio = aspectRatio_;
   67     updateVideoWidgetGeometry();
   68 }
   69 
   70 void MPlayerMediaWidget::setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing);
   71 
   72 {
   73     deinterlacing = deinterlacing_;
   74     sendCommand(SetDeinterlacing);
   75 }
   76 
   77 void MPlayerMediaWidget::play(const MediaSource &source)
   78 {
   79     resetState();
   80     QByteArray url = source.getUrl().toEncoded();
   81 
   82     switch (source.getType()) {
   83     case MediaSource::Url:
   84         if (url.endsWith(".iso")) {
   85             // FIXME use dvd://, dvdnav:// ?
   86             updateDvdMenu(true);
   87         }
   88 
   89         if (source.getUrl().isLocalFile()) {
   90             // mplayer can't deal with urls like "file:///tmp/te%20st.m2t"
   91             url = QFile::encodeName(source.getUrl().toLocalFile());
   92             url.replace(' ', "\\ ");
   93         }
   94 
   95         break;
   96     case MediaSource::AudioCd:
   97         if (url.size() >= 7) {
   98             // e.g. cdda:////dev/sr0
   99             url.replace(0, 5, "cdda:/");
  100         } else {
  101             url = "cdda://";
  102         }
  103 
  104         break;
  105     case MediaSource::VideoCd:
  106         if (url.size() >= 7) {
  107             // e.g. vcd:////dev/sr0
  108             url.replace(0, 5, "vcd:/");
  109         } else {
  110             url = "vcd://";
  111         }
  112 
  113         break;
  114     case MediaSource::Dvd:
  115         if (url.size() >= 7) {
  116             // e.g. dvdnav:////dev/sr0
  117             url.replace(0, 5, "dvdnav:/");
  118         } else {
  119             url = "dvdnav://";
  120         }
  121 
  122         updateDvdMenu(true);
  123         break;
  124     case MediaSource::Dvb:
  125         if (source.getUrl().isLocalFile()) {
  126             // mplayer can't deal with urls like "file:///tmp/te%20st.m2t"
  127             url = QFile::encodeName(source.getUrl().toLocalFile());
  128             url.replace(' ', "\\ ");
  129         }
  130 
  131         break;
  132     }
  133 
  134     updatePlaybackStatus(MediaWidget::Playing);
  135     updateSeekable(true);
  136     process.write("loadfile " + url + '\n');
  137     process.write("pausing_keep_force get_property path\n");
  138     sendCommand(SetDeinterlacing);
  139     sendCommand(SetVolume);
  140     timerId = startTimer(500);
  141 }
  142 
  143 void MPlayerMediaWidget::stop()
  144 {
  145     resetState();
  146     sendCommand(Stop);
  147 }
  148 
  149 void MPlayerMediaWidget::setPaused(bool paused)
  150 {
  151     switch (getPlaybackStatus()) {
  152     case MediaWidget::Idle:
  153         break;
  154     case MediaWidget::Playing:
  155         if (paused) {
  156             updatePlaybackStatus(MediaWidget::Paused);
  157             sendCommand(TogglePause);
  158         }
  159 
  160         break;
  161     case MediaWidget::Paused:
  162         if (!paused) {
  163             updatePlaybackStatus(MediaWidget::Playing);
  164             sendCommand(TogglePause);
  165         }
  166 
  167         break;
  168     }
  169 }
  170 
  171 void MPlayerMediaWidget::seek(int time)
  172 {
  173     process.write("pausing_keep_force set_property time_pos " +
  174         QByteArray::number(float(time) / 1000) + '\n');
  175 }
  176 
  177 void MPlayerMediaWidget::setCurrentAudioStream(int currentAudioStream)
  178 {
  179     if ((currentAudioStream >= 0) && (currentAudioStream < audioIds.size())) {
  180         process.write("pausing_keep_force set_property switch_audio " +
  181             QByteArray::number(audioIds.at(currentAudioStream)) +
  182             "\npausing_keep_force get_property switch_audio\n");
  183     }
  184 }
  185 
  186 void MPlayerMediaWidget::setCurrentSubtitle(int currentSubtitle)
  187 {
  188     process.write("pausing_keep_force set_property sub " +
  189         QByteArray::number(currentSubtitle) +
  190         "\npausing_keep_force get_property sub\n");
  191 }
  192 
  193 void MPlayerMediaWidget::setExternalSubtitle(const QUrl &subtitleUrl)
  194 {
  195     // FIXME
  196     Q_UNUSED(subtitleUrl)
  197 }
  198 
  199 void MPlayerMediaWidget::setCurrentTitle(int currentTitle)
  200 {
  201     process.write("pausing_keep_force set_property switch_title " +
  202         QByteArray::number(currentTitle) +
  203         "\npausing_keep_force get_property switch_title\n"
  204         "pausing_keep_force get_property chapter\n");
  205 }
  206 
  207 void MPlayerMediaWidget::setCurrentChapter(int currentChapter)
  208 {
  209     process.write("pausing_keep_force set_property chapter " +
  210         QByteArray::number(currentChapter) +
  211         "\npausing_keep_force get_property switch_title\n"
  212         "pausing_keep_force get_property chapter\n");
  213 }
  214 
  215 void MPlayerMediaWidget::setCurrentAngle(int currentAngle)
  216 {
  217     process.write("pausing_keep_force set_property switch_angle " +
  218         QByteArray::number(currentAngle) + '\n');
  219 }
  220 
  221 bool MPlayerMediaWidget::jumpToPreviousChapter()
  222 {
  223     if ((getCurrentChapter() - 1) >= 0) {
  224         setCurrentChapter(getCurrentChapter() - 1);
  225         return true;
  226     }
  227 
  228     if ((getCurrentTitle() - 1) >= 0) {
  229         setCurrentTitle(getCurrentTitle() - 1);
  230         return true;
  231     }
  232 
  233     return false;
  234 }
  235 
  236 bool MPlayerMediaWidget::jumpToNextChapter()
  237 {
  238     if ((getCurrentChapter() + 1) < getChapterCount()) {
  239         setCurrentChapter(getCurrentChapter() + 1);
  240         return true;
  241     }
  242 
  243     if ((getCurrentTitle() + 1) < getTitleCount()) {
  244         setCurrentTitle(getCurrentTitle() + 1);
  245         return true;
  246     }
  247 
  248     return false;
  249 }
  250 
  251 void MPlayerMediaWidget::showDvdMenu()
  252 {
  253     sendCommand(ShowDvdMenu);
  254 }
  255 
  256 void MPlayerMediaWidget::error(QProcess::ProcessError error)
  257 {
  258     Q_UNUSED(error)
  259     KMessageBox::queuedMessageBox(this, KMessageBox::Error,
  260         i18n("Cannot start mplayer process."));
  261 }
  262 
  263 void MPlayerMediaWidget::readStandardOutput()
  264 {
  265     QByteArray data = process.readAllStandardOutput();
  266     standardError.write(data); // forward
  267     standardError.flush();
  268 
  269     if ((data == "\n") || (data.indexOf("\n\n") >= 0)) {
  270         process.write("pausing_keep_force get_property path\n");
  271     }
  272 
  273     bool videoPropertiesChanged = false;
  274     QStringList audioStreams = getAudioStreams();
  275     bool audioStreamsChanged = false;
  276     QStringList subtitles = getSubtitles();
  277     bool subtitlesChanged = false;
  278 
  279     foreach (const QByteArray &line, data.split('\n')) {
  280         if (line.startsWith("VO: ")) {
  281             videoPropertiesChanged = true;
  282             continue;
  283         }
  284 
  285         if (line.startsWith("audio stream: ")) {
  286             int begin = 14;
  287             int end = line.indexOf(' ', begin);
  288 
  289             if (end < 0) {
  290                 end = line.size();
  291             }
  292 
  293             int audioStreamIndex = line.mid(begin, end - begin).toInt();
  294 
  295             while (audioStreams.size() < audioStreamIndex) {
  296                 audioStreams.append(QString::number(audioStreams.size() + 1));
  297             }
  298 
  299             while (audioIds.size() < audioStreamIndex) {
  300                 audioIds.append(-1);
  301             }
  302 
  303             audioStreams.erase(audioStreams.begin() + audioStreamIndex,
  304                 audioStreams.end());
  305             audioIds.erase(audioIds.begin() + audioStreamIndex, audioIds.end());
  306             QString audioStream;
  307             begin = line.indexOf("language: ");
  308 
  309             if (begin >= 0) {
  310                 begin += 10;
  311                 end = line.indexOf(' ', begin);
  312 
  313                 if (end < 0) {
  314                     end = line.size();
  315                 }
  316 
  317                 audioStream = line.mid(begin, end - begin);
  318             }
  319 
  320             if (audioStream.isEmpty()) {
  321                 audioStream = QString::number(audioStreams.size() + 1);
  322             }
  323 
  324             int audioId = -1;
  325             begin = line.indexOf("aid: ");
  326 
  327             if (begin >= 0) {
  328                 begin += 5;
  329                 end = line.indexOf('.', begin);
  330 
  331                 if (end < 0) {
  332                     end = line.size();
  333                 }
  334 
  335                 audioId = line.mid(begin, end - begin).toInt();
  336             }
  337 
  338             audioStreams.append(audioStream);
  339             audioIds.append(audioId);
  340             audioStreamsChanged = true;
  341             continue;
  342         }
  343 
  344         if (line.startsWith("subtitle ")) {
  345             int begin = line.indexOf("( sid ): ");
  346 
  347             if (begin < 0) {
  348                 continue;
  349             }
  350 
  351             begin += 9;
  352             int end = line.indexOf(' ', begin);
  353 
  354             if (end < 0) {
  355                 end = line.size();
  356             }
  357 
  358             int subtitleIndex = line.mid(begin, end - begin).toInt();
  359 
  360             while (subtitles.size() < subtitleIndex) {
  361                 subtitles.append(QString::number(subtitles.size() + 1));
  362             }
  363 
  364             subtitles.erase(subtitles.begin() + subtitleIndex, subtitles.end());
  365             QString subtitle;
  366             begin = line.indexOf("language: ");
  367 
  368             if (begin >= 0) {
  369                 begin += 10;
  370                 end = line.indexOf(' ', begin);
  371 
  372                 if (end < 0) {
  373                     end = line.size();
  374                 }
  375 
  376                 subtitle = line.mid(begin, end - begin);
  377             }
  378 
  379             if (subtitle.isEmpty()) {
  380                 subtitle = QString::number(subtitles.size() + 1);
  381             }
  382 
  383             subtitles.append(subtitle);
  384             subtitlesChanged = true;
  385             continue;
  386         }
  387 
  388         if (line == "ANS_path=(null)") {
  389             switch (getPlaybackStatus()) {
  390             case MediaWidget::Idle:
  391                 break;
  392             case MediaWidget::Playing:
  393             case MediaWidget::Paused:
  394                 playbackFinished();
  395                 break;
  396             }
  397 
  398             resetState();
  399             continue;
  400         }
  401 
  402         if (line.startsWith("ANS_length=")) {
  403             int totalTime = (line.mid(11).toFloat() * 1000 + 0.5);
  404             updateCurrentTotalTime(getCurrentTime(), totalTime);
  405             continue;
  406         }
  407 
  408         if (line.startsWith("ANS_time_pos=")) {
  409             int currentTime = (line.mid(13).toFloat() * 1000 + 0.5);
  410             updateCurrentTotalTime(currentTime, getTotalTime());
  411             continue;
  412         }
  413 
  414         if (line.startsWith("ANS_width=")) {
  415             videoWidth = line.mid(10).toInt();
  416 
  417             if (videoWidth < 0) {
  418                 videoWidth = 0;
  419             }
  420 
  421             continue;
  422         }
  423 
  424         if (line.startsWith("ANS_height=")) {
  425             videoHeight = line.mid(11).toInt();
  426 
  427             if (videoHeight < 0) {
  428                 videoHeight = 0;
  429             }
  430 
  431             continue;
  432         }
  433 
  434         if (line.startsWith("ANS_aspect=")) {
  435             videoAspectRatio = line.mid(11).toFloat();
  436 
  437             if ((videoAspectRatio > 0.01) && (videoAspectRatio < 100)) {
  438                 // ok
  439             } else {
  440                 videoAspectRatio = (videoWidth / float(videoHeight));
  441 
  442                 if ((videoAspectRatio > 0.01) && (videoAspectRatio < 100)) {
  443                     // ok
  444                 } else {
  445                     videoAspectRatio = 1;
  446                 }
  447             }
  448 
  449             updateVideoWidgetGeometry();
  450             continue;
  451         }
  452 
  453         if (line.startsWith("ANS_switch_audio=")) {
  454             int audioId = line.mid(17).toInt();
  455             updateCurrentAudioStream(audioIds.indexOf(audioId));
  456             continue;
  457         }
  458 
  459         if (line.startsWith("ANS_sub=")) {
  460             int currentSubtitle = line.mid(8).toInt();
  461             updateCurrentSubtitle(currentSubtitle);
  462             continue;
  463         }
  464     }
  465 
  466     if (videoPropertiesChanged) {
  467         process.write("pausing_keep_force get_property width\n"
  468             "pausing_keep_force get_property height\n"
  469             "pausing_keep_force get_property aspect\n");
  470     }
  471 
  472     if (audioStreamsChanged) {
  473         updateAudioStreams(audioStreams);
  474         process.write("pausing_keep_force get_property switch_audio\n");
  475     }
  476 
  477     if (subtitlesChanged) {
  478         updateSubtitles(subtitles);
  479         process.write("pausing_keep_force get_property sub\n");
  480     }
  481 }
  482 
  483 void MPlayerMediaWidget::readStandardError()
  484 {
  485     QByteArray data = process.readAllStandardError();
  486     standardError.write(data); // forward
  487     standardError.flush();
  488 }
  489 
  490 void MPlayerMediaWidget::mouseMoved(int x, int y)
  491 {
  492     process.write("set_mouse_pos " + QByteArray::number(x) + ' ' + QByteArray::number(y) +
  493         '\n');
  494 }
  495 
  496 void MPlayerMediaWidget::mouseClicked()
  497 {
  498     process.write("dvdnav mouse\n");
  499 }
  500 
  501 void MPlayerMediaWidget::resetState()
  502 {
  503     resetBaseState();
  504 
  505     if (timerId != 0) {
  506         killTimer(timerId);
  507         timerId = 0;
  508     }
  509 
  510     audioIds.clear();
  511     videoWidth = 0;
  512     videoHeight = 0;
  513     videoAspectRatio = 1;
  514     updateVideoWidgetGeometry();
  515 }
  516 
  517 void MPlayerMediaWidget::resizeEvent(QResizeEvent *event)
  518 {
  519     updateVideoWidgetGeometry();
  520     AbstractMediaWidget::resizeEvent(event);
  521 }
  522 
  523 void MPlayerMediaWidget::sendCommand(Command command)
  524 {
  525     switch (command) {
  526     case SetDeinterlacing:
  527         if (getPlaybackStatus() == MediaWidget::Idle) {
  528             // only works if media is loaded
  529             break;
  530         }
  531 
  532         process.write("pausing_keep_force set_property deinterlace %1\n", deinterlacing);
  533 
  534         break;
  535     case SetVolume: {
  536         if (getPlaybackStatus() == MediaWidget::Idle) {
  537             // only works if media is loaded
  538             break;
  539         }
  540 
  541         int realVolume = volume;
  542 
  543         if (muted) {
  544             realVolume = 0;
  545         }
  546 
  547         process.write("pausing_keep_force set_property volume " +
  548             QByteArray::number(realVolume) + '\n');
  549         break;
  550         }
  551     case ShowDvdMenu:
  552         process.write("dvdnav menu\n");
  553         break;
  554     case Stop:
  555         process.write("stop\n");
  556         break;
  557     case TogglePause:
  558         process.write("pause\n");
  559         break;
  560     case Quit:
  561         process.write("quit\n");
  562         break;
  563     }
  564 }
  565 
  566 void MPlayerMediaWidget::timerEvent(QTimerEvent *event)
  567 {
  568     Q_UNUSED(event)
  569     process.write("pausing_keep_force get_property length\n"
  570         "pausing_keep_force get_property time_pos\n");
  571 }
  572 
  573 void MPlayerMediaWidget::updateVideoWidgetGeometry()
  574 {
  575     float effectiveAspectRatio = videoAspectRatio;
  576 
  577     switch (aspectRatio) {
  578     case MediaWidget::AspectRatioAuto:
  579         break;
  580     case MediaWidget::AspectRatio1_1:
  581         effectiveAspectRatio = 1;
  582         break;
  583     case MediaWidget::AspectRatio4_3:
  584         effectiveAspectRatio = (4.0 / 3.0);
  585         break;
  586     case MediaWidget::AspectRatio5_4:
  587         effectiveAspectRatio = (5.0 / 4.0);
  588         break;
  589     case MediaWidget::AspectRatio16_9:
  590         effectiveAspectRatio = (16.0 / 9.0);
  591         break;
  592     case MediaWidget::AspectRatio16_10:
  593         effectiveAspectRatio = (16.0 / 10.0);
  594         break;
  595     case MediaWidget::AspectRatio221_100:
  596         effectiveAspectRatio = (221.0 / 100.0);
  597         break;
  598     case MediaWidget::AspectRatio235_100:
  599         effectiveAspectRatio = (235.0 / 100.0);
  600         break;
  601     case MediaWidget::AspectRatio239_100:
  602         effectiveAspectRatio = (239.0 / 100.0);
  603         break;
  604     }
  605 
  606     QRect geometry(QPoint(0, 0), size());
  607 
  608     if (getPlaybackStatus() == MediaWidget::Idle) {
  609         geometry.setSize(QSize(0, 0));
  610     } else if (effectiveAspectRatio > 0) {
  611         int newWidth = (geometry.height() * effectiveAspectRatio + 0.5);
  612 
  613         if (newWidth <= geometry.width()) {
  614             geometry.setX((geometry.width() - newWidth) / 2);
  615             geometry.setWidth(newWidth);
  616         } else {
  617             int newHeight = (geometry.width() / effectiveAspectRatio + 0.5);
  618             geometry.setY((geometry.height() - newHeight) / 2);
  619             geometry.setHeight(newHeight);
  620         }
  621     }
  622 
  623     if (videoWidget->geometry() != geometry) {
  624         videoWidget->setGeometry(geometry);
  625     }
  626 }