src/3rdparty/phonon/qt7/mediaobject.mm
changeset 30 5dc02b23752f
parent 0 1918ee327afb
--- a/src/3rdparty/phonon/qt7/mediaobject.mm	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/3rdparty/phonon/qt7/mediaobject.mm	Tue Jul 06 15:10:48 2010 +0300
@@ -46,6 +46,7 @@
     m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
     setAudioNode(m_mediaObjectAudioNode);
 
+    m_metaData = new QuickTimeMetaData();
     m_audioGraph = new AudioGraph(this);
 
     m_tickInterval = 0;
@@ -54,7 +55,6 @@
     m_transitionTime = 0;
     m_percentageLoaded = 0;
     m_waitNextSwap = false;
-    m_autoplayTitles = true;
     m_audioEffectCount = 0;
     m_audioOutputCount = 0;
     m_videoEffectCount = 0;
@@ -63,28 +63,20 @@
     m_errorType = Phonon::NoError;
 
     m_tickTimer = 0;
-    m_videoTimer = 0;
-    m_audioTimer = 0;
+    m_bufferTimer = 0;
     m_rapidTimer = 0;
 
-#if QT_ALLOW_QUICKTIME
-    m_displayLink = 0;
-    m_pendingDisplayLinkEvent = false;
-#endif
-
     checkForError();
 }
 
 MediaObject::~MediaObject()
-{
-    // m_mediaObjectAudioNode is owned by super class.
-#if QT_ALLOW_QUICKTIME
-    stopDisplayLink();
-#endif
+{   
+    // m_mediaObjectAudioNode is owned by super class.    
     m_audioPlayer->unsetVideoPlayer();
     m_nextAudioPlayer->unsetVideoPlayer();
     delete m_videoPlayer;
     delete m_nextVideoPlayer;
+    delete m_metaData;
     checkForError();
 }
 
@@ -96,7 +88,7 @@
         emit stateChanged(m_state, prevState);
         if (m_state != state){
             // End-application did something
-            // upon  receiving the signal.
+            // upon  receiving the signal. 
             return false;
         }
     }
@@ -130,7 +122,7 @@
     // Inspect the graph to check wether there are any
     // effects or outputs connected. This will have
     // influence on the audio system and video system that ends up beeing used:
-    int prevVideoOutputCount = m_videoOutputCount;
+    int prevVideoOutputCount = m_videoOutputCount;	
     m_audioEffectCount = 0;
     m_audioOutputCount = 0;
     m_videoEffectCount = 0;
@@ -142,7 +134,7 @@
 	if (m_videoOutputCount != prevVideoOutputCount){
 	    MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
 	    notify(&e1);
-    }
+	}	
 }
 
 void MediaObject::setupAudioSystem()
@@ -175,14 +167,14 @@
 
     if (newAudioSystem == m_audioSystem)
         return;
-
+  
     // Enable selected audio system:
-    m_audioSystem = newAudioSystem;
+    m_audioSystem = newAudioSystem; 
     switch (newAudioSystem){
         case AS_Silent:
             m_audioGraph->stop();
             m_videoPlayer->enableAudio(false);
-            m_nextVideoPlayer->enableAudio(false);
+            m_nextVideoPlayer->enableAudio(false);    
             m_audioPlayer->enableAudio(false);
             m_nextAudioPlayer->enableAudio(false);
         break;
@@ -222,28 +214,28 @@
     IMPLEMENTED;
 	PhononAutoReleasePool pool;
     setState(Phonon::LoadingState);
-
+    
     // Save current state for event/signal handling below:
     bool prevHasVideo = m_videoPlayer->hasVideo();
     qint64 prevTotalTime = totalTime();
-    int prevTrackCount = m_videoPlayer->trackCount();
     m_waitNextSwap = false;
-
+        
     // Cancel cross-fade if any:
     m_nextVideoPlayer->pause();
     m_nextAudioPlayer->pause();
     m_mediaObjectAudioNode->cancelCrossFade();
-
+    
     // Set new source:
     m_audioPlayer->unsetVideoPlayer();
     m_videoPlayer->setMediaSource(source);
     m_audioPlayer->setVideoPlayer(m_videoPlayer);
+    m_metaData->setVideo(m_videoPlayer);        
 
-    m_audioGraph->updateStreamSpecifications();
+    m_audioGraph->updateStreamSpecifications();        
     m_nextAudioPlayer->unsetVideoPlayer();
-    m_nextVideoPlayer->unsetCurrentMediaSource();
+    m_nextVideoPlayer->unsetVideo();
     m_currentTime = 0;
-
+        
     // Emit/notify information about the new source:
     QRect videoRect = m_videoPlayer->videoRect();
     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
@@ -254,14 +246,12 @@
     updateVideo(emptyFrame);
 
     emit currentSourceChanged(source);
-    emit metaDataChanged(m_videoPlayer->metaData());
+    emit metaDataChanged(m_metaData->metaData());
 
     if (prevHasVideo != m_videoPlayer->hasVideo())
-        emit hasVideoChanged(m_videoPlayer->hasVideo());
+        emit hasVideoChanged(m_videoPlayer->hasVideo());        
     if (prevTotalTime != totalTime())
-        emit totalTimeChanged(totalTime());
-    if (prevTrackCount != m_videoPlayer->trackCount())
-        emit availableTitlesChanged(m_videoPlayer->trackCount());
+        emit totalTimeChanged(totalTime());        
     if (checkForError())
         return;
     if (!m_videoPlayer->isDrmAuthorized())
@@ -270,7 +260,7 @@
         return;
     if (!m_videoPlayer->canPlayMedia())
         SET_ERROR("Cannot play media.", FATAL_ERROR)
-
+        
     // The state might have changed from LoadingState
     // as a response to an error state change. So we
     // need to check it before stopping: 
@@ -297,30 +287,28 @@
     // Save current state for event/signal handling below:
     bool prevHasVideo = m_videoPlayer->hasVideo();
     qint64 prevTotalTime = totalTime();
-    int prevTrackCount = m_videoPlayer->trackCount();
 
     qSwap(m_audioPlayer, m_nextAudioPlayer);
     qSwap(m_videoPlayer, m_nextVideoPlayer);
     m_mediaObjectAudioNode->startCrossFade(transitionTime);
     m_audioGraph->updateStreamSpecifications();
+    m_metaData->setVideo(m_videoPlayer);
 
     m_waitNextSwap = false;
     m_currentTime = 0;
-
+        
     // Emit/notify information about the new source:
     QRect videoRect = m_videoPlayer->videoRect();
     MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
     notify(&e1);
 
     emit currentSourceChanged(m_videoPlayer->mediaSource());
-    emit metaDataChanged(m_videoPlayer->metaData());
+    emit metaDataChanged(m_metaData->metaData());
 
     if (prevHasVideo != m_videoPlayer->hasVideo())
-        emit hasVideoChanged(m_videoPlayer->hasVideo());
+        emit hasVideoChanged(m_videoPlayer->hasVideo());        
     if (prevTotalTime != totalTime())
         emit totalTimeChanged(totalTime());
-    if (prevTrackCount != m_videoPlayer->trackCount())
-        emit availableTitlesChanged(m_videoPlayer->trackCount());
     if (checkForError())
         return;
     if (!m_videoPlayer->isDrmAuthorized())
@@ -339,107 +327,28 @@
     }
 }
 
-#if QT_ALLOW_QUICKTIME
-static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/,
-								 const CVTimeStamp */*inNow*/,
-								 const CVTimeStamp */*inOutputTime*/,
-								 CVOptionFlags /*flagsIn*/,
-								 CVOptionFlags */*flagsOut*/,
-                                 void *userData)
-{
-    MediaObject *mediaObject = static_cast<MediaObject *>(userData);
-    mediaObject->displayLinkEvent();
-    return kCVReturnSuccess;
-}
-
-void MediaObject::displayLinkEvent()
-{
-    // This function is called from a
-    // thread != gui thread. So we post the event.
-    // But we need to make sure that we don't post faster
-    // than the event loop can eat:
-    m_displayLinkMutex.lock();
-    bool pending = m_pendingDisplayLinkEvent;
-    m_pendingDisplayLinkEvent = true;
-    m_displayLinkMutex.unlock();
-
-    if (!pending)
-        qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
-}
-
-void MediaObject::startDisplayLink()
+void MediaObject::updateTimer(int &timer, int interval)
 {
-    if (m_displayLink)
-        return;
-    OSStatus err = CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
-    if (err != noErr)
-        goto fail;
-    err = CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay);
-    if (err != noErr)
-        goto fail;
-    err = CVDisplayLinkSetOutputCallback(m_displayLink, displayLinkCallback, this);
-    if (err != noErr)
-        goto fail;
-    err = CVDisplayLinkStart(m_displayLink);
-    if (err != noErr)
-        goto fail;
-    return;
-fail:
-    stopDisplayLink();
-}
-
-void MediaObject::stopDisplayLink()
-{
-    if (!m_displayLink)
-        return;
-    CVDisplayLinkStop(m_displayLink);
-    CFRelease(m_displayLink);
-    m_displayLink = 0;
-}
-#endif
-
-void MediaObject::restartAudioVideoTimers()
-{
-    if (m_videoTimer)
-        killTimer(m_videoTimer);
-    if (m_audioTimer)
-        killTimer(m_audioTimer);
-
-#if QT_ALLOW_QUICKTIME
-    // We prefer to use a display link as timer if available, since
-    // it is more steady, and results in better and smoother frame drawing:
-    startDisplayLink();
-    if (!m_displayLink){
-        float fps = m_videoPlayer->staticFps();
-        long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
-        m_videoTimer = startTimer(videoUpdateFrequency);
-    }
-#else
-    float fps = m_videoPlayer->staticFps();
-    long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
-    m_videoTimer = startTimer(videoUpdateFrequency);
-#endif
-
-    long audioUpdateFrequency = m_audioPlayer->regularTaskFrequency();
-    m_audioTimer = startTimer(audioUpdateFrequency);
-    updateVideoFrames();
-    updateAudioBuffers();
+    if (timer)
+        killTimer(timer);
+    timer = 0;
+    if (interval >= 0)    
+        timer = startTimer(interval); 
 }
 
 void MediaObject::play_internal()
 {
     // Play main audio/video:
     m_videoPlayer->play();
-    m_audioPlayer->play();
+    m_audioPlayer->play();     
     updateLipSynch(0);
     // Play old audio/video to finish cross-fade:
     if (m_nextVideoPlayer->currentTime() > 0){
         m_nextVideoPlayer->play();
         m_nextAudioPlayer->play();
     }
-    restartAudioVideoTimers();
-    if (!m_rapidTimer)
-        m_rapidTimer = startTimer(100);
+    bufferAudioVideo();
+    updateTimer(m_rapidTimer, 100);
 }
 
 void MediaObject::pause_internal()
@@ -449,15 +358,9 @@
     m_nextAudioPlayer->pause();
     m_videoPlayer->pause();
     m_nextVideoPlayer->pause();
-    killTimer(m_rapidTimer);
-    killTimer(m_videoTimer);
-    killTimer(m_audioTimer);
-    m_rapidTimer = 0;
-    m_videoTimer = 0;
-    m_audioTimer = 0;
-#if QT_ALLOW_QUICKTIME
-    stopDisplayLink();
-#endif
+    updateTimer(m_rapidTimer, -1);
+    updateTimer(m_bufferTimer, -1);
+
     if (m_waitNextSwap)
         m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
 }
@@ -479,7 +382,7 @@
     if (!m_videoPlayer->canPlayMedia())
         return;
     if (!setState(Phonon::PlayingState))
-        return;
+        return;        
     if (m_audioSystem == AS_Graph){
         m_audioGraph->start();
         m_mediaObjectAudioNode->setMute(true);
@@ -520,7 +423,7 @@
     if (!setState(Phonon::StoppedState))
         return;
     m_waitNextSwap = false;
-    m_nextVideoPlayer->unsetCurrentMediaSource();
+    m_nextVideoPlayer->unsetVideo();
     m_nextAudioPlayer->unsetVideoPlayer();
     pause_internal();
     seek(0);
@@ -532,9 +435,9 @@
     IMPLEMENTED;
     if (m_state == Phonon::ErrorState)
         return;
-
+        
     // Stop cross-fade if any:
-    m_nextVideoPlayer->unsetCurrentMediaSource();
+    m_nextVideoPlayer->unsetVideo();
     m_nextAudioPlayer->unsetVideoPlayer();
     m_mediaObjectAudioNode->cancelCrossFade();
 
@@ -543,7 +446,7 @@
     m_videoPlayer->seek(milliseconds);
     m_audioPlayer->seek(m_videoPlayer->currentTime());
     m_mediaObjectAudioNode->setMute(false);
-
+    
     // Update time and cancel pending swap:
     if (m_currentTime < m_videoPlayer->duration())
         m_waitNextSwap = false;
@@ -654,7 +557,7 @@
 qint64 MediaObject::currentTime() const
 {
     IMPLEMENTED_SILENT;
-    const_cast<MediaObject *>(this)->updateCurrentTime();
+    const_cast<MediaObject *>(this)->updateCurrentTime(); 
     return m_currentTime;
 }
 
@@ -664,24 +567,19 @@
     m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
     quint64 total = m_videoPlayer->duration();
 
-    if (m_videoPlayer->currentTrack() < m_videoPlayer->trackCount() - 1){
-        // There are still more tracks to play after the current track.
-        if (m_autoplayTitles) {
-            if (lastUpdateTime < m_currentTime && m_currentTime == total)
-                setCurrentTrack(m_videoPlayer->currentTrack() + 1);
-        }
-    } else if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
-        // There is no more sources or tracks to play after the current source.
-        // Check if it's time to emit aboutToFinish:
-        quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
-        if (lastUpdateTime < mark && mark <= m_currentTime)
-            emit aboutToFinish();
+    // Check if it's time to emit aboutToFinish:
+    quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
+    if (lastUpdateTime < mark && mark <= m_currentTime)
+        emit aboutToFinish();
 
-        // Check if it's time to emit prefinishMarkReached:
-        mark = qMax(quint64(0), total - m_prefinishMark);
-        if (lastUpdateTime < mark && mark <= m_currentTime)
-            emit prefinishMarkReached(total - m_currentTime);
+    // Check if it's time to emit prefinishMarkReached:
+    mark = qMax(quint64(0), total - m_prefinishMark);
+    if (lastUpdateTime < mark && mark <= m_currentTime)
+        emit prefinishMarkReached(total - m_currentTime);
 
+    if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
+        // There is no next source in que.
+        // Check if it's time to emit finished:
         if (lastUpdateTime < m_currentTime && m_currentTime == total){
             emit finished();
             m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
@@ -691,7 +589,7 @@
     } else {
         // We have a next source.
         // Check if it's time to swap to next source:
-        quint32 mark = qMax(quint64(0), total + m_transitionTime);
+        mark = qMax(quint64(0), total + m_transitionTime);
         if (m_waitNextSwap && m_state == Phonon::PlayingState &&
             m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
             swapCurrentWithNext(0);
@@ -794,14 +692,14 @@
 
 void MediaObject::updateCrossFade()
 {
-    m_mediaObjectAudioNode->updateCrossFade(m_currentTime);
+    m_mediaObjectAudioNode->updateCrossFade(m_currentTime);   
     // Clean-up previous movie if done fading:
     if (m_mediaObjectAudioNode->m_fadeDuration == 0){
         if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
-            m_nextVideoPlayer->unsetCurrentMediaSource();
+            m_nextVideoPlayer->unsetVideo();
             m_nextAudioPlayer->unsetVideoPlayer();
         }
-    }
+    }        
 }
 
 void MediaObject::updateBufferStatus()
@@ -830,7 +728,7 @@
     // Draw next frame if awailable:
     if (m_videoPlayer->videoFrameChanged()){
         updateLipSynch(50);
-        VideoFrame frame(m_videoPlayer);
+        VideoFrame frame(m_videoPlayer);           
         if (m_nextVideoPlayer->isPlaying()
             && m_nextVideoPlayer->hasVideo()
             && isCrossFading()){
@@ -838,9 +736,9 @@
             frame.setBackgroundFrame(bgFrame);
             frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
         }
-
+        
         // Send the frame through the graph:
-        updateVideo(frame);
+        updateVideo(frame);    
         checkForError();
     }
 }
@@ -851,7 +749,7 @@
         return;
     if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
         return;
-
+        
     if (m_videoPlayer->hasVideo()){
         qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
         if (-allowedOffset > diff || diff > allowedOffset)
@@ -865,6 +763,16 @@
     }
 }
 
+void MediaObject::bufferAudioVideo()
+{
+    long nextVideoUpdate = m_videoPlayer->hasVideo() ? 30 : INT_MAX;
+    long nextAudioUpdate = m_audioPlayer->regularTaskFrequency();
+    updateAudioBuffers();
+    updateVideoFrames();
+    if (m_state == Phonon::PlayingState)
+        updateTimer(m_bufferTimer, qMin(nextVideoUpdate, nextAudioUpdate));
+}
+
 void MediaObject::updateRapidly()
 {
     updateCurrentTime();
@@ -889,8 +797,8 @@
             synchAudioVideo();
             checkForError();
             m_mediaObjectAudioNode->setMute(false);
-            if (m_state == Phonon::PlayingState)
-                restartAudioVideoTimers();
+             if (m_state == Phonon::PlayingState)
+                bufferAudioVideo();
             break;
         case MediaNodeEvent::AudioGraphCannotPlay:
         case MediaNodeEvent::AudioGraphInitialized:
@@ -901,7 +809,7 @@
                 checkForError();
                 m_mediaObjectAudioNode->setMute(false);
             }
-            break;
+            break; 
         default:
             break;
     }
@@ -910,67 +818,29 @@
 bool MediaObject::event(QEvent *event)
 {
     switch (event->type()){
-#if QT_ALLOW_QUICKTIME
-        case QEvent::User:{
-            m_displayLinkMutex.lock();
-            m_pendingDisplayLinkEvent = false;
-            m_displayLinkMutex.unlock();
-            updateVideoFrames();
-            break; }
-#endif
-        case QEvent::Timer:{
-            int timerId = static_cast<QTimerEvent *>(event)->timerId();
-            if (timerId == m_rapidTimer)
+        case QEvent::Timer: {
+            QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
+            if (timerEvent->timerId() == m_rapidTimer)
                 updateRapidly();
-            else if (timerId == m_tickTimer)
+            else if (timerEvent->timerId() == m_tickTimer)
                 emit tick(currentTime());
-            else if (timerId == m_videoTimer)
-                updateVideoFrames();
-            else if (timerId == m_audioTimer)
-                updateAudioBuffers();
-            break; }
+            else if (timerEvent->timerId() == m_bufferTimer)
+                bufferAudioVideo();
+            }
+            break;
         default:
             break;
     }
     return QObject::event(event);
 }
 
-void MediaObject::setCurrentTrack(int track)
+bool MediaObject::hasInterface(Interface /*interface*/) const
 {
-    if (track == m_videoPlayer->currentTrack() || track < 0 || track >= m_videoPlayer->trackCount())
-        return;
-
-    m_videoPlayer->setCurrentTrack(track);
-    emit titleChanged(track);
-    emit metaDataChanged(m_videoPlayer->metaData());
-}
-
-bool MediaObject::hasInterface(Interface iface) const
-{
-    return iface == AddonInterface::TitleInterface;
+    return false;
 }
 
-QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> &params)
+QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/)
 {
-    switch (iface) {
-        case TitleInterface:
-            switch (command) {
-                case availableTitles:
-                    return m_videoPlayer->trackCount();
-                case title:
-                    return m_videoPlayer->currentTrack();
-                case setTitle:
-                    setCurrentTrack(params.first().toInt());
-                    break;
-                case autoplayTitles:
-                    return m_autoplayTitles;
-                case setAutoplayTitles:
-                    m_autoplayTitles = params.first().toBool();
-                    break;
-            }
-        default:
-            break;
-    }
     return QVariant();
 }