src/3rdparty/phonon/qt7/mediaobject.mm
changeset 30 5dc02b23752f
parent 0 1918ee327afb
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    44     m_nextVideoPlayer = new QuickTimeVideoPlayer();
    44     m_nextVideoPlayer = new QuickTimeVideoPlayer();
    45     m_nextAudioPlayer = new QuickTimeAudioPlayer();
    45     m_nextAudioPlayer = new QuickTimeAudioPlayer();
    46     m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
    46     m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
    47     setAudioNode(m_mediaObjectAudioNode);
    47     setAudioNode(m_mediaObjectAudioNode);
    48 
    48 
       
    49     m_metaData = new QuickTimeMetaData();
    49     m_audioGraph = new AudioGraph(this);
    50     m_audioGraph = new AudioGraph(this);
    50 
    51 
    51     m_tickInterval = 0;
    52     m_tickInterval = 0;
    52     m_prefinishMark = 0;
    53     m_prefinishMark = 0;
    53     m_currentTime = 0;
    54     m_currentTime = 0;
    54     m_transitionTime = 0;
    55     m_transitionTime = 0;
    55     m_percentageLoaded = 0;
    56     m_percentageLoaded = 0;
    56     m_waitNextSwap = false;
    57     m_waitNextSwap = false;
    57     m_autoplayTitles = true;
       
    58     m_audioEffectCount = 0;
    58     m_audioEffectCount = 0;
    59     m_audioOutputCount = 0;
    59     m_audioOutputCount = 0;
    60     m_videoEffectCount = 0;
    60     m_videoEffectCount = 0;
    61     m_videoOutputCount = 0;
    61     m_videoOutputCount = 0;
    62     m_audioSystem = AS_Unset;
    62     m_audioSystem = AS_Unset;
    63     m_errorType = Phonon::NoError;
    63     m_errorType = Phonon::NoError;
    64 
    64 
    65     m_tickTimer = 0;
    65     m_tickTimer = 0;
    66     m_videoTimer = 0;
    66     m_bufferTimer = 0;
    67     m_audioTimer = 0;
       
    68     m_rapidTimer = 0;
    67     m_rapidTimer = 0;
    69 
    68 
    70 #if QT_ALLOW_QUICKTIME
       
    71     m_displayLink = 0;
       
    72     m_pendingDisplayLinkEvent = false;
       
    73 #endif
       
    74 
       
    75     checkForError();
    69     checkForError();
    76 }
    70 }
    77 
    71 
    78 MediaObject::~MediaObject()
    72 MediaObject::~MediaObject()
    79 {
    73 {   
    80     // m_mediaObjectAudioNode is owned by super class.
    74     // m_mediaObjectAudioNode is owned by super class.    
    81 #if QT_ALLOW_QUICKTIME
       
    82     stopDisplayLink();
       
    83 #endif
       
    84     m_audioPlayer->unsetVideoPlayer();
    75     m_audioPlayer->unsetVideoPlayer();
    85     m_nextAudioPlayer->unsetVideoPlayer();
    76     m_nextAudioPlayer->unsetVideoPlayer();
    86     delete m_videoPlayer;
    77     delete m_videoPlayer;
    87     delete m_nextVideoPlayer;
    78     delete m_nextVideoPlayer;
       
    79     delete m_metaData;
    88     checkForError();
    80     checkForError();
    89 }
    81 }
    90 
    82 
    91 bool MediaObject::setState(Phonon::State state)
    83 bool MediaObject::setState(Phonon::State state)
    92 {
    84 {
    94     m_state = state;
    86     m_state = state;
    95     if (prevState != m_state){
    87     if (prevState != m_state){
    96         emit stateChanged(m_state, prevState);
    88         emit stateChanged(m_state, prevState);
    97         if (m_state != state){
    89         if (m_state != state){
    98             // End-application did something
    90             // End-application did something
    99             // upon  receiving the signal.
    91             // upon  receiving the signal. 
   100             return false;
    92             return false;
   101         }
    93         }
   102     }
    94     }
   103     return true;
    95     return true;
   104 }
    96 }
   128 void MediaObject::inspectGraph()
   120 void MediaObject::inspectGraph()
   129 {
   121 {
   130     // Inspect the graph to check wether there are any
   122     // Inspect the graph to check wether there are any
   131     // effects or outputs connected. This will have
   123     // effects or outputs connected. This will have
   132     // influence on the audio system and video system that ends up beeing used:
   124     // influence on the audio system and video system that ends up beeing used:
   133     int prevVideoOutputCount = m_videoOutputCount;
   125     int prevVideoOutputCount = m_videoOutputCount;	
   134     m_audioEffectCount = 0;
   126     m_audioEffectCount = 0;
   135     m_audioOutputCount = 0;
   127     m_audioOutputCount = 0;
   136     m_videoEffectCount = 0;
   128     m_videoEffectCount = 0;
   137     m_videoOutputCount = 0;
   129     m_videoOutputCount = 0;
   138     AudioConnection rootConnection(this);
   130     AudioConnection rootConnection(this);
   140     inspectVideoGraphRecursive(this, m_videoEffectCount, m_videoOutputCount);
   132     inspectVideoGraphRecursive(this, m_videoEffectCount, m_videoOutputCount);
   141 
   133 
   142 	if (m_videoOutputCount != prevVideoOutputCount){
   134 	if (m_videoOutputCount != prevVideoOutputCount){
   143 	    MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
   135 	    MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
   144 	    notify(&e1);
   136 	    notify(&e1);
   145     }
   137 	}	
   146 }
   138 }
   147 
   139 
   148 void MediaObject::setupAudioSystem()
   140 void MediaObject::setupAudioSystem()
   149 {
   141 {
   150     // Select which audio system to use:
   142     // Select which audio system to use:
   173     }
   165     }
   174 #endif
   166 #endif
   175 
   167 
   176     if (newAudioSystem == m_audioSystem)
   168     if (newAudioSystem == m_audioSystem)
   177         return;
   169         return;
   178 
   170   
   179     // Enable selected audio system:
   171     // Enable selected audio system:
   180     m_audioSystem = newAudioSystem;
   172     m_audioSystem = newAudioSystem; 
   181     switch (newAudioSystem){
   173     switch (newAudioSystem){
   182         case AS_Silent:
   174         case AS_Silent:
   183             m_audioGraph->stop();
   175             m_audioGraph->stop();
   184             m_videoPlayer->enableAudio(false);
   176             m_videoPlayer->enableAudio(false);
   185             m_nextVideoPlayer->enableAudio(false);
   177             m_nextVideoPlayer->enableAudio(false);    
   186             m_audioPlayer->enableAudio(false);
   178             m_audioPlayer->enableAudio(false);
   187             m_nextAudioPlayer->enableAudio(false);
   179             m_nextAudioPlayer->enableAudio(false);
   188         break;
   180         break;
   189         case AS_Graph:
   181         case AS_Graph:
   190             if (m_state == Phonon::PausedState)
   182             if (m_state == Phonon::PausedState)
   220 void MediaObject::setSource(const MediaSource &source)
   212 void MediaObject::setSource(const MediaSource &source)
   221 {
   213 {
   222     IMPLEMENTED;
   214     IMPLEMENTED;
   223 	PhononAutoReleasePool pool;
   215 	PhononAutoReleasePool pool;
   224     setState(Phonon::LoadingState);
   216     setState(Phonon::LoadingState);
   225 
   217     
   226     // Save current state for event/signal handling below:
   218     // Save current state for event/signal handling below:
   227     bool prevHasVideo = m_videoPlayer->hasVideo();
   219     bool prevHasVideo = m_videoPlayer->hasVideo();
   228     qint64 prevTotalTime = totalTime();
   220     qint64 prevTotalTime = totalTime();
   229     int prevTrackCount = m_videoPlayer->trackCount();
       
   230     m_waitNextSwap = false;
   221     m_waitNextSwap = false;
   231 
   222         
   232     // Cancel cross-fade if any:
   223     // Cancel cross-fade if any:
   233     m_nextVideoPlayer->pause();
   224     m_nextVideoPlayer->pause();
   234     m_nextAudioPlayer->pause();
   225     m_nextAudioPlayer->pause();
   235     m_mediaObjectAudioNode->cancelCrossFade();
   226     m_mediaObjectAudioNode->cancelCrossFade();
   236 
   227     
   237     // Set new source:
   228     // Set new source:
   238     m_audioPlayer->unsetVideoPlayer();
   229     m_audioPlayer->unsetVideoPlayer();
   239     m_videoPlayer->setMediaSource(source);
   230     m_videoPlayer->setMediaSource(source);
   240     m_audioPlayer->setVideoPlayer(m_videoPlayer);
   231     m_audioPlayer->setVideoPlayer(m_videoPlayer);
   241 
   232     m_metaData->setVideo(m_videoPlayer);        
   242     m_audioGraph->updateStreamSpecifications();
   233 
       
   234     m_audioGraph->updateStreamSpecifications();        
   243     m_nextAudioPlayer->unsetVideoPlayer();
   235     m_nextAudioPlayer->unsetVideoPlayer();
   244     m_nextVideoPlayer->unsetCurrentMediaSource();
   236     m_nextVideoPlayer->unsetVideo();
   245     m_currentTime = 0;
   237     m_currentTime = 0;
   246 
   238         
   247     // Emit/notify information about the new source:
   239     // Emit/notify information about the new source:
   248     QRect videoRect = m_videoPlayer->videoRect();
   240     QRect videoRect = m_videoPlayer->videoRect();
   249     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
   241     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
   250     notify(&e1);
   242     notify(&e1);
   251 
   243 
   252     // Clear video widgets:
   244     // Clear video widgets:
   253     VideoFrame emptyFrame;
   245     VideoFrame emptyFrame;
   254     updateVideo(emptyFrame);
   246     updateVideo(emptyFrame);
   255 
   247 
   256     emit currentSourceChanged(source);
   248     emit currentSourceChanged(source);
   257     emit metaDataChanged(m_videoPlayer->metaData());
   249     emit metaDataChanged(m_metaData->metaData());
   258 
   250 
   259     if (prevHasVideo != m_videoPlayer->hasVideo())
   251     if (prevHasVideo != m_videoPlayer->hasVideo())
   260         emit hasVideoChanged(m_videoPlayer->hasVideo());
   252         emit hasVideoChanged(m_videoPlayer->hasVideo());        
   261     if (prevTotalTime != totalTime())
   253     if (prevTotalTime != totalTime())
   262         emit totalTimeChanged(totalTime());
   254         emit totalTimeChanged(totalTime());        
   263     if (prevTrackCount != m_videoPlayer->trackCount())
       
   264         emit availableTitlesChanged(m_videoPlayer->trackCount());
       
   265     if (checkForError())
   255     if (checkForError())
   266         return;
   256         return;
   267     if (!m_videoPlayer->isDrmAuthorized())
   257     if (!m_videoPlayer->isDrmAuthorized())
   268         SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
   258         SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
   269     if (checkForError())
   259     if (checkForError())
   270         return;
   260         return;
   271     if (!m_videoPlayer->canPlayMedia())
   261     if (!m_videoPlayer->canPlayMedia())
   272         SET_ERROR("Cannot play media.", FATAL_ERROR)
   262         SET_ERROR("Cannot play media.", FATAL_ERROR)
   273 
   263         
   274     // The state might have changed from LoadingState
   264     // The state might have changed from LoadingState
   275     // as a response to an error state change. So we
   265     // as a response to an error state change. So we
   276     // need to check it before stopping: 
   266     // need to check it before stopping: 
   277     if (m_state == Phonon::LoadingState)
   267     if (m_state == Phonon::LoadingState)
   278         stop();
   268         stop();
   295 	PhononAutoReleasePool pool;
   285 	PhononAutoReleasePool pool;
   296     setState(Phonon::LoadingState);
   286     setState(Phonon::LoadingState);
   297     // Save current state for event/signal handling below:
   287     // Save current state for event/signal handling below:
   298     bool prevHasVideo = m_videoPlayer->hasVideo();
   288     bool prevHasVideo = m_videoPlayer->hasVideo();
   299     qint64 prevTotalTime = totalTime();
   289     qint64 prevTotalTime = totalTime();
   300     int prevTrackCount = m_videoPlayer->trackCount();
       
   301 
   290 
   302     qSwap(m_audioPlayer, m_nextAudioPlayer);
   291     qSwap(m_audioPlayer, m_nextAudioPlayer);
   303     qSwap(m_videoPlayer, m_nextVideoPlayer);
   292     qSwap(m_videoPlayer, m_nextVideoPlayer);
   304     m_mediaObjectAudioNode->startCrossFade(transitionTime);
   293     m_mediaObjectAudioNode->startCrossFade(transitionTime);
   305     m_audioGraph->updateStreamSpecifications();
   294     m_audioGraph->updateStreamSpecifications();
       
   295     m_metaData->setVideo(m_videoPlayer);
   306 
   296 
   307     m_waitNextSwap = false;
   297     m_waitNextSwap = false;
   308     m_currentTime = 0;
   298     m_currentTime = 0;
   309 
   299         
   310     // Emit/notify information about the new source:
   300     // Emit/notify information about the new source:
   311     QRect videoRect = m_videoPlayer->videoRect();
   301     QRect videoRect = m_videoPlayer->videoRect();
   312     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
   302     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
   313     notify(&e1);
   303     notify(&e1);
   314 
   304 
   315     emit currentSourceChanged(m_videoPlayer->mediaSource());
   305     emit currentSourceChanged(m_videoPlayer->mediaSource());
   316     emit metaDataChanged(m_videoPlayer->metaData());
   306     emit metaDataChanged(m_metaData->metaData());
   317 
   307 
   318     if (prevHasVideo != m_videoPlayer->hasVideo())
   308     if (prevHasVideo != m_videoPlayer->hasVideo())
   319         emit hasVideoChanged(m_videoPlayer->hasVideo());
   309         emit hasVideoChanged(m_videoPlayer->hasVideo());        
   320     if (prevTotalTime != totalTime())
   310     if (prevTotalTime != totalTime())
   321         emit totalTimeChanged(totalTime());
   311         emit totalTimeChanged(totalTime());
   322     if (prevTrackCount != m_videoPlayer->trackCount())
       
   323         emit availableTitlesChanged(m_videoPlayer->trackCount());
       
   324     if (checkForError())
   312     if (checkForError())
   325         return;
   313         return;
   326     if (!m_videoPlayer->isDrmAuthorized())
   314     if (!m_videoPlayer->isDrmAuthorized())
   327         SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
   315         SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
   328     if (checkForError())
   316     if (checkForError())
   337             play_internal();
   325             play_internal();
   338         checkForError();
   326         checkForError();
   339     }
   327     }
   340 }
   328 }
   341 
   329 
   342 #if QT_ALLOW_QUICKTIME
   330 void MediaObject::updateTimer(int &timer, int interval)
   343 static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/,
   331 {
   344 								 const CVTimeStamp */*inNow*/,
   332     if (timer)
   345 								 const CVTimeStamp */*inOutputTime*/,
   333         killTimer(timer);
   346 								 CVOptionFlags /*flagsIn*/,
   334     timer = 0;
   347 								 CVOptionFlags */*flagsOut*/,
   335     if (interval >= 0)    
   348                                  void *userData)
   336         timer = startTimer(interval); 
   349 {
       
   350     MediaObject *mediaObject = static_cast<MediaObject *>(userData);
       
   351     mediaObject->displayLinkEvent();
       
   352     return kCVReturnSuccess;
       
   353 }
       
   354 
       
   355 void MediaObject::displayLinkEvent()
       
   356 {
       
   357     // This function is called from a
       
   358     // thread != gui thread. So we post the event.
       
   359     // But we need to make sure that we don't post faster
       
   360     // than the event loop can eat:
       
   361     m_displayLinkMutex.lock();
       
   362     bool pending = m_pendingDisplayLinkEvent;
       
   363     m_pendingDisplayLinkEvent = true;
       
   364     m_displayLinkMutex.unlock();
       
   365 
       
   366     if (!pending)
       
   367         qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
       
   368 }
       
   369 
       
   370 void MediaObject::startDisplayLink()
       
   371 {
       
   372     if (m_displayLink)
       
   373         return;
       
   374     OSStatus err = CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
       
   375     if (err != noErr)
       
   376         goto fail;
       
   377     err = CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay);
       
   378     if (err != noErr)
       
   379         goto fail;
       
   380     err = CVDisplayLinkSetOutputCallback(m_displayLink, displayLinkCallback, this);
       
   381     if (err != noErr)
       
   382         goto fail;
       
   383     err = CVDisplayLinkStart(m_displayLink);
       
   384     if (err != noErr)
       
   385         goto fail;
       
   386     return;
       
   387 fail:
       
   388     stopDisplayLink();
       
   389 }
       
   390 
       
   391 void MediaObject::stopDisplayLink()
       
   392 {
       
   393     if (!m_displayLink)
       
   394         return;
       
   395     CVDisplayLinkStop(m_displayLink);
       
   396     CFRelease(m_displayLink);
       
   397     m_displayLink = 0;
       
   398 }
       
   399 #endif
       
   400 
       
   401 void MediaObject::restartAudioVideoTimers()
       
   402 {
       
   403     if (m_videoTimer)
       
   404         killTimer(m_videoTimer);
       
   405     if (m_audioTimer)
       
   406         killTimer(m_audioTimer);
       
   407 
       
   408 #if QT_ALLOW_QUICKTIME
       
   409     // We prefer to use a display link as timer if available, since
       
   410     // it is more steady, and results in better and smoother frame drawing:
       
   411     startDisplayLink();
       
   412     if (!m_displayLink){
       
   413         float fps = m_videoPlayer->staticFps();
       
   414         long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
       
   415         m_videoTimer = startTimer(videoUpdateFrequency);
       
   416     }
       
   417 #else
       
   418     float fps = m_videoPlayer->staticFps();
       
   419     long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
       
   420     m_videoTimer = startTimer(videoUpdateFrequency);
       
   421 #endif
       
   422 
       
   423     long audioUpdateFrequency = m_audioPlayer->regularTaskFrequency();
       
   424     m_audioTimer = startTimer(audioUpdateFrequency);
       
   425     updateVideoFrames();
       
   426     updateAudioBuffers();
       
   427 }
   337 }
   428 
   338 
   429 void MediaObject::play_internal()
   339 void MediaObject::play_internal()
   430 {
   340 {
   431     // Play main audio/video:
   341     // Play main audio/video:
   432     m_videoPlayer->play();
   342     m_videoPlayer->play();
   433     m_audioPlayer->play();
   343     m_audioPlayer->play();     
   434     updateLipSynch(0);
   344     updateLipSynch(0);
   435     // Play old audio/video to finish cross-fade:
   345     // Play old audio/video to finish cross-fade:
   436     if (m_nextVideoPlayer->currentTime() > 0){
   346     if (m_nextVideoPlayer->currentTime() > 0){
   437         m_nextVideoPlayer->play();
   347         m_nextVideoPlayer->play();
   438         m_nextAudioPlayer->play();
   348         m_nextAudioPlayer->play();
   439     }
   349     }
   440     restartAudioVideoTimers();
   350     bufferAudioVideo();
   441     if (!m_rapidTimer)
   351     updateTimer(m_rapidTimer, 100);
   442         m_rapidTimer = startTimer(100);
       
   443 }
   352 }
   444 
   353 
   445 void MediaObject::pause_internal()
   354 void MediaObject::pause_internal()
   446 {
   355 {
   447     m_audioGraph->stop();
   356     m_audioGraph->stop();
   448     m_audioPlayer->pause();
   357     m_audioPlayer->pause();
   449     m_nextAudioPlayer->pause();
   358     m_nextAudioPlayer->pause();
   450     m_videoPlayer->pause();
   359     m_videoPlayer->pause();
   451     m_nextVideoPlayer->pause();
   360     m_nextVideoPlayer->pause();
   452     killTimer(m_rapidTimer);
   361     updateTimer(m_rapidTimer, -1);
   453     killTimer(m_videoTimer);
   362     updateTimer(m_bufferTimer, -1);
   454     killTimer(m_audioTimer);
   363 
   455     m_rapidTimer = 0;
       
   456     m_videoTimer = 0;
       
   457     m_audioTimer = 0;
       
   458 #if QT_ALLOW_QUICKTIME
       
   459     stopDisplayLink();
       
   460 #endif
       
   461     if (m_waitNextSwap)
   364     if (m_waitNextSwap)
   462         m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
   365         m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
   463 }
   366 }
   464 
   367 
   465 void MediaObject::play()
   368 void MediaObject::play()
   477     if (m_currentTime == m_videoPlayer->duration())
   380     if (m_currentTime == m_videoPlayer->duration())
   478         return;
   381         return;
   479     if (!m_videoPlayer->canPlayMedia())
   382     if (!m_videoPlayer->canPlayMedia())
   480         return;
   383         return;
   481     if (!setState(Phonon::PlayingState))
   384     if (!setState(Phonon::PlayingState))
   482         return;
   385         return;        
   483     if (m_audioSystem == AS_Graph){
   386     if (m_audioSystem == AS_Graph){
   484         m_audioGraph->start();
   387         m_audioGraph->start();
   485         m_mediaObjectAudioNode->setMute(true);
   388         m_mediaObjectAudioNode->setMute(true);
   486     }
   389     }
   487 	// Inform the graph that we are about to play:
   390 	// Inform the graph that we are about to play:
   518     if (m_state == Phonon::StoppedState)
   421     if (m_state == Phonon::StoppedState)
   519         return;
   422         return;
   520     if (!setState(Phonon::StoppedState))
   423     if (!setState(Phonon::StoppedState))
   521         return;
   424         return;
   522     m_waitNextSwap = false;
   425     m_waitNextSwap = false;
   523     m_nextVideoPlayer->unsetCurrentMediaSource();
   426     m_nextVideoPlayer->unsetVideo();
   524     m_nextAudioPlayer->unsetVideoPlayer();
   427     m_nextAudioPlayer->unsetVideoPlayer();
   525     pause_internal();
   428     pause_internal();
   526     seek(0);
   429     seek(0);
   527     checkForError();
   430     checkForError();
   528 }
   431 }
   530 void MediaObject::seek(qint64 milliseconds)
   433 void MediaObject::seek(qint64 milliseconds)
   531 {
   434 {
   532     IMPLEMENTED;
   435     IMPLEMENTED;
   533     if (m_state == Phonon::ErrorState)
   436     if (m_state == Phonon::ErrorState)
   534         return;
   437         return;
   535 
   438         
   536     // Stop cross-fade if any:
   439     // Stop cross-fade if any:
   537     m_nextVideoPlayer->unsetCurrentMediaSource();
   440     m_nextVideoPlayer->unsetVideo();
   538     m_nextAudioPlayer->unsetVideoPlayer();
   441     m_nextAudioPlayer->unsetVideoPlayer();
   539     m_mediaObjectAudioNode->cancelCrossFade();
   442     m_mediaObjectAudioNode->cancelCrossFade();
   540 
   443 
   541     // Seek to new position:
   444     // Seek to new position:
   542     m_mediaObjectAudioNode->setMute(true);
   445     m_mediaObjectAudioNode->setMute(true);
   543     m_videoPlayer->seek(milliseconds);
   446     m_videoPlayer->seek(milliseconds);
   544     m_audioPlayer->seek(m_videoPlayer->currentTime());
   447     m_audioPlayer->seek(m_videoPlayer->currentTime());
   545     m_mediaObjectAudioNode->setMute(false);
   448     m_mediaObjectAudioNode->setMute(false);
   546 
   449     
   547     // Update time and cancel pending swap:
   450     // Update time and cancel pending swap:
   548     if (m_currentTime < m_videoPlayer->duration())
   451     if (m_currentTime < m_videoPlayer->duration())
   549         m_waitNextSwap = false;
   452         m_waitNextSwap = false;
   550 
   453 
   551     updateCurrentTime();
   454     updateCurrentTime();
   652 }
   555 }
   653 
   556 
   654 qint64 MediaObject::currentTime() const
   557 qint64 MediaObject::currentTime() const
   655 {
   558 {
   656     IMPLEMENTED_SILENT;
   559     IMPLEMENTED_SILENT;
   657     const_cast<MediaObject *>(this)->updateCurrentTime();
   560     const_cast<MediaObject *>(this)->updateCurrentTime(); 
   658     return m_currentTime;
   561     return m_currentTime;
   659 }
   562 }
   660 
   563 
   661 void MediaObject::updateCurrentTime()
   564 void MediaObject::updateCurrentTime()
   662 {
   565 {
   663     quint64 lastUpdateTime = m_currentTime;
   566     quint64 lastUpdateTime = m_currentTime;
   664     m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
   567     m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
   665     quint64 total = m_videoPlayer->duration();
   568     quint64 total = m_videoPlayer->duration();
   666 
   569 
   667     if (m_videoPlayer->currentTrack() < m_videoPlayer->trackCount() - 1){
   570     // Check if it's time to emit aboutToFinish:
   668         // There are still more tracks to play after the current track.
   571     quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
   669         if (m_autoplayTitles) {
   572     if (lastUpdateTime < mark && mark <= m_currentTime)
   670             if (lastUpdateTime < m_currentTime && m_currentTime == total)
   573         emit aboutToFinish();
   671                 setCurrentTrack(m_videoPlayer->currentTrack() + 1);
   574 
   672         }
   575     // Check if it's time to emit prefinishMarkReached:
   673     } else if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
   576     mark = qMax(quint64(0), total - m_prefinishMark);
   674         // There is no more sources or tracks to play after the current source.
   577     if (lastUpdateTime < mark && mark <= m_currentTime)
   675         // Check if it's time to emit aboutToFinish:
   578         emit prefinishMarkReached(total - m_currentTime);
   676         quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
   579 
   677         if (lastUpdateTime < mark && mark <= m_currentTime)
   580     if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
   678             emit aboutToFinish();
   581         // There is no next source in que.
   679 
   582         // Check if it's time to emit finished:
   680         // Check if it's time to emit prefinishMarkReached:
       
   681         mark = qMax(quint64(0), total - m_prefinishMark);
       
   682         if (lastUpdateTime < mark && mark <= m_currentTime)
       
   683             emit prefinishMarkReached(total - m_currentTime);
       
   684 
       
   685         if (lastUpdateTime < m_currentTime && m_currentTime == total){
   583         if (lastUpdateTime < m_currentTime && m_currentTime == total){
   686             emit finished();
   584             emit finished();
   687             m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
   585             m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
   688             if (m_state == Phonon::PlayingState && m_currentTime == total)
   586             if (m_state == Phonon::PlayingState && m_currentTime == total)
   689                 pause();
   587                 pause();
   690         }
   588         }
   691     } else {
   589     } else {
   692         // We have a next source.
   590         // We have a next source.
   693         // Check if it's time to swap to next source:
   591         // Check if it's time to swap to next source:
   694         quint32 mark = qMax(quint64(0), total + m_transitionTime);
   592         mark = qMax(quint64(0), total + m_transitionTime);
   695         if (m_waitNextSwap && m_state == Phonon::PlayingState &&
   593         if (m_waitNextSwap && m_state == Phonon::PlayingState &&
   696             m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
   594             m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
   697             swapCurrentWithNext(0);
   595             swapCurrentWithNext(0);
   698         } else if (mark >= total){
   596         } else if (mark >= total){
   699             if (lastUpdateTime < total && total == m_currentTime){
   597             if (lastUpdateTime < total && total == m_currentTime){
   792     return m_videoPlayer->setAudioDevice(id);
   690     return m_videoPlayer->setAudioDevice(id);
   793 }
   691 }
   794 
   692 
   795 void MediaObject::updateCrossFade()
   693 void MediaObject::updateCrossFade()
   796 {
   694 {
   797     m_mediaObjectAudioNode->updateCrossFade(m_currentTime);
   695     m_mediaObjectAudioNode->updateCrossFade(m_currentTime);   
   798     // Clean-up previous movie if done fading:
   696     // Clean-up previous movie if done fading:
   799     if (m_mediaObjectAudioNode->m_fadeDuration == 0){
   697     if (m_mediaObjectAudioNode->m_fadeDuration == 0){
   800         if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
   698         if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
   801             m_nextVideoPlayer->unsetCurrentMediaSource();
   699             m_nextVideoPlayer->unsetVideo();
   802             m_nextAudioPlayer->unsetVideoPlayer();
   700             m_nextAudioPlayer->unsetVideoPlayer();
   803         }
   701         }
   804     }
   702     }        
   805 }
   703 }
   806 
   704 
   807 void MediaObject::updateBufferStatus()
   705 void MediaObject::updateBufferStatus()
   808 {
   706 {
   809     float percent = m_videoPlayer->percentageLoaded();
   707     float percent = m_videoPlayer->percentageLoaded();
   828 void MediaObject::updateVideoFrames()
   726 void MediaObject::updateVideoFrames()
   829 {
   727 {
   830     // Draw next frame if awailable:
   728     // Draw next frame if awailable:
   831     if (m_videoPlayer->videoFrameChanged()){
   729     if (m_videoPlayer->videoFrameChanged()){
   832         updateLipSynch(50);
   730         updateLipSynch(50);
   833         VideoFrame frame(m_videoPlayer);
   731         VideoFrame frame(m_videoPlayer);           
   834         if (m_nextVideoPlayer->isPlaying()
   732         if (m_nextVideoPlayer->isPlaying()
   835             && m_nextVideoPlayer->hasVideo()
   733             && m_nextVideoPlayer->hasVideo()
   836             && isCrossFading()){
   734             && isCrossFading()){
   837             VideoFrame bgFrame(m_nextVideoPlayer);
   735             VideoFrame bgFrame(m_nextVideoPlayer);
   838             frame.setBackgroundFrame(bgFrame);
   736             frame.setBackgroundFrame(bgFrame);
   839             frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
   737             frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
   840         }
   738         }
   841 
   739         
   842         // Send the frame through the graph:
   740         // Send the frame through the graph:
   843         updateVideo(frame);
   741         updateVideo(frame);    
   844         checkForError();
   742         checkForError();
   845     }
   743     }
   846 }
   744 }
   847 
   745 
   848 void MediaObject::updateLipSynch(int allowedOffset)
   746 void MediaObject::updateLipSynch(int allowedOffset)
   849 {
   747 {
   850     if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning())
   748     if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning())
   851         return;
   749         return;
   852     if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
   750     if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
   853         return;
   751         return;
   854 
   752         
   855     if (m_videoPlayer->hasVideo()){
   753     if (m_videoPlayer->hasVideo()){
   856         qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
   754         qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
   857         if (-allowedOffset > diff || diff > allowedOffset)
   755         if (-allowedOffset > diff || diff > allowedOffset)
   858             m_audioPlayer->seek(m_videoPlayer->currentTime());
   756             m_audioPlayer->seek(m_videoPlayer->currentTime());
   859     }
   757     }
   861     if (isCrossFading() && m_nextVideoPlayer->hasVideo()){
   759     if (isCrossFading() && m_nextVideoPlayer->hasVideo()){
   862         qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime();
   760         qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime();
   863         if (-(allowedOffset*2) > diff || diff > (allowedOffset*2))
   761         if (-(allowedOffset*2) > diff || diff > (allowedOffset*2))
   864             m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
   762             m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
   865     }
   763     }
       
   764 }
       
   765 
       
   766 void MediaObject::bufferAudioVideo()
       
   767 {
       
   768     long nextVideoUpdate = m_videoPlayer->hasVideo() ? 30 : INT_MAX;
       
   769     long nextAudioUpdate = m_audioPlayer->regularTaskFrequency();
       
   770     updateAudioBuffers();
       
   771     updateVideoFrames();
       
   772     if (m_state == Phonon::PlayingState)
       
   773         updateTimer(m_bufferTimer, qMin(nextVideoUpdate, nextAudioUpdate));
   866 }
   774 }
   867 
   775 
   868 void MediaObject::updateRapidly()
   776 void MediaObject::updateRapidly()
   869 {
   777 {
   870     updateCurrentTime();
   778     updateCurrentTime();
   887             inspectGraph();
   795             inspectGraph();
   888             setupAudioSystem();
   796             setupAudioSystem();
   889             synchAudioVideo();
   797             synchAudioVideo();
   890             checkForError();
   798             checkForError();
   891             m_mediaObjectAudioNode->setMute(false);
   799             m_mediaObjectAudioNode->setMute(false);
   892             if (m_state == Phonon::PlayingState)
   800              if (m_state == Phonon::PlayingState)
   893                 restartAudioVideoTimers();
   801                 bufferAudioVideo();
   894             break;
   802             break;
   895         case MediaNodeEvent::AudioGraphCannotPlay:
   803         case MediaNodeEvent::AudioGraphCannotPlay:
   896         case MediaNodeEvent::AudioGraphInitialized:
   804         case MediaNodeEvent::AudioGraphInitialized:
   897             if (m_state != Phonon::LoadingState){
   805             if (m_state != Phonon::LoadingState){
   898                 m_mediaObjectAudioNode->setMute(true);
   806                 m_mediaObjectAudioNode->setMute(true);
   899                 setupAudioSystem();
   807                 setupAudioSystem();
   900                 updateLipSynch(0);
   808                 updateLipSynch(0);
   901                 checkForError();
   809                 checkForError();
   902                 m_mediaObjectAudioNode->setMute(false);
   810                 m_mediaObjectAudioNode->setMute(false);
   903             }
   811             }
       
   812             break; 
       
   813         default:
       
   814             break;
       
   815     }
       
   816 }
       
   817 
       
   818 bool MediaObject::event(QEvent *event)
       
   819 {
       
   820     switch (event->type()){
       
   821         case QEvent::Timer: {
       
   822             QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
       
   823             if (timerEvent->timerId() == m_rapidTimer)
       
   824                 updateRapidly();
       
   825             else if (timerEvent->timerId() == m_tickTimer)
       
   826                 emit tick(currentTime());
       
   827             else if (timerEvent->timerId() == m_bufferTimer)
       
   828                 bufferAudioVideo();
       
   829             }
   904             break;
   830             break;
   905         default:
   831         default:
   906             break;
   832             break;
   907     }
   833     }
   908 }
       
   909 
       
   910 bool MediaObject::event(QEvent *event)
       
   911 {
       
   912     switch (event->type()){
       
   913 #if QT_ALLOW_QUICKTIME
       
   914         case QEvent::User:{
       
   915             m_displayLinkMutex.lock();
       
   916             m_pendingDisplayLinkEvent = false;
       
   917             m_displayLinkMutex.unlock();
       
   918             updateVideoFrames();
       
   919             break; }
       
   920 #endif
       
   921         case QEvent::Timer:{
       
   922             int timerId = static_cast<QTimerEvent *>(event)->timerId();
       
   923             if (timerId == m_rapidTimer)
       
   924                 updateRapidly();
       
   925             else if (timerId == m_tickTimer)
       
   926                 emit tick(currentTime());
       
   927             else if (timerId == m_videoTimer)
       
   928                 updateVideoFrames();
       
   929             else if (timerId == m_audioTimer)
       
   930                 updateAudioBuffers();
       
   931             break; }
       
   932         default:
       
   933             break;
       
   934     }
       
   935     return QObject::event(event);
   834     return QObject::event(event);
   936 }
   835 }
   937 
   836 
   938 void MediaObject::setCurrentTrack(int track)
   837 bool MediaObject::hasInterface(Interface /*interface*/) const
   939 {
   838 {
   940     if (track == m_videoPlayer->currentTrack() || track < 0 || track >= m_videoPlayer->trackCount())
   839     return false;
   941         return;
   840 }
   942 
   841 
   943     m_videoPlayer->setCurrentTrack(track);
   842 QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/)
   944     emit titleChanged(track);
   843 {
   945     emit metaDataChanged(m_videoPlayer->metaData());
       
   946 }
       
   947 
       
   948 bool MediaObject::hasInterface(Interface iface) const
       
   949 {
       
   950     return iface == AddonInterface::TitleInterface;
       
   951 }
       
   952 
       
   953 QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> &params)
       
   954 {
       
   955     switch (iface) {
       
   956         case TitleInterface:
       
   957             switch (command) {
       
   958                 case availableTitles:
       
   959                     return m_videoPlayer->trackCount();
       
   960                 case title:
       
   961                     return m_videoPlayer->currentTrack();
       
   962                 case setTitle:
       
   963                     setCurrentTrack(params.first().toInt());
       
   964                     break;
       
   965                 case autoplayTitles:
       
   966                     return m_autoplayTitles;
       
   967                 case setAutoplayTitles:
       
   968                     m_autoplayTitles = params.first().toBool();
       
   969                     break;
       
   970             }
       
   971         default:
       
   972             break;
       
   973     }
       
   974     return QVariant();
   844     return QVariant();
   975 }
   845 }
   976 
   846 
   977 }} // namespace Phonon::QT7
   847 }} // namespace Phonon::QT7
   978 
   848