diff options
Diffstat (limited to 'src/3rdparty/phonon/qt7/mediaobject.mm')
-rw-r--r-- | src/3rdparty/phonon/qt7/mediaobject.mm | 306 |
1 files changed, 88 insertions, 218 deletions
diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm index 677640c..002c337 100644 --- a/src/3rdparty/phonon/qt7/mediaobject.mm +++ b/src/3rdparty/phonon/qt7/mediaobject.mm @@ -46,6 +46,7 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, 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 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, 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 @@ MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, 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 @@ 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; } } @@ -130,7 +122,7 @@ void MediaObject::inspectGraph() // 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 @@ void MediaObject::inspectGraph() if (m_videoOutputCount != prevVideoOutputCount){ MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount); notify(&e1); - } + } } void MediaObject::setupAudioSystem() @@ -175,14 +167,14 @@ void MediaObject::setupAudioSystem() 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 @@ 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(); - 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 @@ void MediaObject::setSource(const MediaSource &source) 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 @@ void MediaObject::setSource(const MediaSource &source) 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 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime) // 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 @@ void MediaObject::swapCurrentWithNext(qint32 transitionTime) } } -#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 @@ void MediaObject::pause_internal() 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 @@ 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); @@ -520,7 +423,7 @@ void MediaObject::stop() 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 @@ void MediaObject::seek(qint64 milliseconds) 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 @@ 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; @@ -654,7 +557,7 @@ bool MediaObject::isSeekable() const qint64 MediaObject::currentTime() const { IMPLEMENTED_SILENT; - const_cast<MediaObject *>(this)->updateCurrentTime(); + const_cast<MediaObject *>(this)->updateCurrentTime(); return m_currentTime; } @@ -664,24 +567,19 @@ void MediaObject::updateCurrentTime() 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 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 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); + + 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 @@ void MediaObject::updateCurrentTime() } 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 @@ bool MediaObject::setAudioDeviceOnMovie(int id) 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 @@ 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()){ @@ -838,9 +736,9 @@ void MediaObject::updateVideoFrames() frame.setBackgroundFrame(bgFrame); frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1); } - + // Send the frame through the graph: - updateVideo(frame); + updateVideo(frame); checkForError(); } } @@ -851,7 +749,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) @@ -865,6 +763,16 @@ 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(); @@ -889,8 +797,8 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) 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 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) checkForError(); m_mediaObjectAudioNode->setMute(false); } - break; + break; default: break; } @@ -910,67 +818,29 @@ void MediaObject::mediaNodeEvent(const MediaNodeEvent *event) 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()); + return false; } -bool MediaObject::hasInterface(Interface iface) const +QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/) { - return iface == AddonInterface::TitleInterface; -} - -QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> ¶ms) -{ - 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(); } |