summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon/qt7/mediaobject.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/phonon/qt7/mediaobject.mm')
-rw-r--r--src/3rdparty/phonon/qt7/mediaobject.mm199
1 files changed, 146 insertions, 53 deletions
diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm
index 002c337..6886a3c 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;
@@ -88,7 +97,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;
}
}
@@ -214,28 +223,28 @@ void MediaObject::setSource(const MediaSource &source)
IMPLEMENTED;
PhononAutoReleasePool pool;
setState(Phonon::LoadingState);
-
+
// Save current state for event/signal handling below:
bool prevHasVideo = m_videoPlayer->hasVideo();
qint64 prevTotalTime = totalTime();
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_metaData->setVideo(m_videoPlayer);
- m_audioGraph->updateStreamSpecifications();
+ m_audioGraph->updateStreamSpecifications();
m_nextAudioPlayer->unsetVideoPlayer();
m_nextVideoPlayer->unsetVideo();
m_currentTime = 0;
-
+
// Emit/notify information about the new source:
QRect videoRect = m_videoPlayer->videoRect();
MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
@@ -296,7 +305,7 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime)
m_waitNextSwap = false;
m_currentTime = 0;
-
+
// Emit/notify information about the new source:
QRect videoRect = m_videoPlayer->videoRect();
MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
@@ -306,7 +315,7 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime)
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 (checkForError())
@@ -327,28 +336,107 @@ 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)
+{
+ 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 (timer)
- killTimer(timer);
- timer = 0;
- if (interval >= 0)
- timer = startTimer(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();
}
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();
}
- bufferAudioVideo();
- updateTimer(m_rapidTimer, 100);
+ restartAudioVideoTimers();
+ if (!m_rapidTimer)
+ m_rapidTimer = startTimer(100);
}
void MediaObject::pause_internal()
@@ -358,9 +446,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());
}
@@ -382,7 +476,7 @@ void MediaObject::play()
if (!m_videoPlayer->canPlayMedia())
return;
if (!setState(Phonon::PlayingState))
- return;
+ return;
if (m_audioSystem == AS_Graph){
m_audioGraph->start();
m_mediaObjectAudioNode->setMute(true);
@@ -435,7 +529,7 @@ void MediaObject::seek(qint64 milliseconds)
IMPLEMENTED;
if (m_state == Phonon::ErrorState)
return;
-
+
// Stop cross-fade if any:
m_nextVideoPlayer->unsetVideo();
m_nextAudioPlayer->unsetVideoPlayer();
@@ -446,7 +540,7 @@ void MediaObject::seek(qint64 milliseconds)
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;
@@ -699,7 +793,7 @@ void MediaObject::updateCrossFade()
m_nextVideoPlayer->unsetVideo();
m_nextAudioPlayer->unsetVideoPlayer();
}
- }
+ }
}
void MediaObject::updateBufferStatus()
@@ -728,7 +822,7 @@ void MediaObject::updateVideoFrames()
// 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()){
@@ -736,9 +830,9 @@ void MediaObject::updateVideoFrames()
frame.setBackgroundFrame(bgFrame);
frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
}
-
+
// Send the frame through the graph:
- updateVideo(frame);
+ updateVideo(frame);
checkForError();
}
}
@@ -749,7 +843,7 @@ void MediaObject::updateLipSynch(int allowedOffset)
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)
@@ -763,16 +857,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();
@@ -797,8 +881,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:
@@ -809,7 +893,7 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event)
checkForError();
m_mediaObjectAudioNode->setMute(false);
}
- break;
+ break;
default:
break;
}
@@ -818,16 +902,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;
}