diff options
Diffstat (limited to 'src/3rdparty/phonon/qt7/mediaobject.mm')
-rw-r--r-- | src/3rdparty/phonon/qt7/mediaobject.mm | 163 |
1 files changed, 128 insertions, 35 deletions
diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm index 95859ef..677640c 100644 --- a/src/3rdparty/phonon/qt7/mediaobject.mm +++ b/src/3rdparty/phonon/qt7/mediaobject.mm @@ -63,15 +63,24 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, m_errorType = Phonon::NoError; m_tickTimer = 0; - m_bufferTimer = 0; + m_videoTimer = 0; + m_audioTimer = 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. + // m_mediaObjectAudioNode is owned by super class. +#if QT_ALLOW_QUICKTIME + stopDisplayLink(); +#endif m_audioPlayer->unsetVideoPlayer(); m_nextAudioPlayer->unsetVideoPlayer(); delete m_videoPlayer; @@ -87,7 +96,7 @@ bool MediaObject::setState(Phonon::State state) emit stateChanged(m_state, prevState); if (m_state != state){ // End-application did something - // upon receiving the signal. + // upon receiving the signal. return false; } } @@ -330,13 +339,91 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime) } } -void MediaObject::updateTimer(int &timer, int interval) +#if QT_ALLOW_QUICKTIME +static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/, + const CVTimeStamp */*inNow*/, + const CVTimeStamp */*inOutputTime*/, + CVOptionFlags /*flagsIn*/, + CVOptionFlags */*flagsOut*/, + void *userData) { - if (timer) - killTimer(timer); - timer = 0; - if (interval >= 0) - timer = startTimer(interval); + 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() +{ + 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(); } void MediaObject::play_internal() @@ -350,8 +437,9 @@ void MediaObject::play_internal() m_nextVideoPlayer->play(); m_nextAudioPlayer->play(); } - bufferAudioVideo(); - updateTimer(m_rapidTimer, 100); + restartAudioVideoTimers(); + if (!m_rapidTimer) + m_rapidTimer = startTimer(100); } void MediaObject::pause_internal() @@ -361,9 +449,15 @@ void MediaObject::pause_internal() m_nextAudioPlayer->pause(); m_videoPlayer->pause(); m_nextVideoPlayer->pause(); - updateTimer(m_rapidTimer, -1); - updateTimer(m_bufferTimer, -1); - + killTimer(m_rapidTimer); + killTimer(m_videoTimer); + killTimer(m_audioTimer); + m_rapidTimer = 0; + m_videoTimer = 0; + m_audioTimer = 0; +#if QT_ALLOW_QUICKTIME + stopDisplayLink(); +#endif if (m_waitNextSwap) m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime()); } @@ -771,16 +865,6 @@ void MediaObject::updateLipSynch(int allowedOffset) } } -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(); @@ -805,8 +889,8 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) synchAudioVideo(); checkForError(); m_mediaObjectAudioNode->setMute(false); - if (m_state == Phonon::PlayingState) - bufferAudioVideo(); + if (m_state == Phonon::PlayingState) + restartAudioVideoTimers(); break; case MediaNodeEvent::AudioGraphCannotPlay: case MediaNodeEvent::AudioGraphInitialized: @@ -817,7 +901,7 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) checkForError(); m_mediaObjectAudioNode->setMute(false); } - break; + break; default: break; } @@ -826,16 +910,25 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) bool MediaObject::event(QEvent *event) { switch (event->type()){ - case QEvent::Timer: { - QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event); - if (timerEvent->timerId() == m_rapidTimer) +#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) updateRapidly(); - else if (timerEvent->timerId() == m_tickTimer) + else if (timerId == m_tickTimer) emit tick(currentTime()); - else if (timerEvent->timerId() == m_bufferTimer) - bufferAudioVideo(); - } - break; + else if (timerId == m_videoTimer) + updateVideoFrames(); + else if (timerId == m_audioTimer) + updateAudioBuffers(); + break; } default: break; } |