source: trunk/src/3rdparty/phonon/qt7/mediaobject.mm

Last change on this file was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 24.2 KB
Line 
1/* This file is part of the KDE project.
2
3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5 This library is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 2.1 or 3 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this library. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <QtCore/QEvent>
19#include "mediaobject.h"
20#include "backendheader.h"
21#include "videowidget.h"
22#include "videoframe.h"
23#include "audiooutput.h"
24#include "quicktimevideoplayer.h"
25#include "quicktimemetadata.h"
26#include "audiograph.h"
27#include "mediaobjectaudionode.h"
28#include "quicktimeaudioplayer.h"
29
30QT_BEGIN_NAMESPACE
31
32namespace Phonon
33{
34namespace QT7
35{
36
37MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, parent)
38{
39 m_owningMediaObject = this;
40 m_state = Phonon::LoadingState;
41
42 m_videoPlayer = new QuickTimeVideoPlayer();
43 m_audioPlayer = new QuickTimeAudioPlayer();
44 m_nextVideoPlayer = new QuickTimeVideoPlayer();
45 m_nextAudioPlayer = new QuickTimeAudioPlayer();
46 m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
47 setAudioNode(m_mediaObjectAudioNode);
48
49 m_metaData = new QuickTimeMetaData();
50 m_audioGraph = new AudioGraph(this);
51
52 m_tickInterval = 0;
53 m_prefinishMark = 0;
54 m_currentTime = 0;
55 m_transitionTime = 0;
56 m_percentageLoaded = 0;
57 m_waitNextSwap = false;
58 m_audioEffectCount = 0;
59 m_audioOutputCount = 0;
60 m_videoEffectCount = 0;
61 m_videoOutputCount = 0;
62 m_audioSystem = AS_Unset;
63 m_errorType = Phonon::NoError;
64
65 m_tickTimer = 0;
66 m_bufferTimer = 0;
67 m_rapidTimer = 0;
68
69 checkForError();
70}
71
72MediaObject::~MediaObject()
73{
74 // m_mediaObjectAudioNode is owned by super class.
75 m_audioPlayer->unsetVideoPlayer();
76 m_nextAudioPlayer->unsetVideoPlayer();
77 delete m_videoPlayer;
78 delete m_nextVideoPlayer;
79 delete m_metaData;
80 checkForError();
81}
82
83bool MediaObject::setState(Phonon::State state)
84{
85 Phonon::State prevState = m_state;
86 m_state = state;
87 if (prevState != m_state){
88 emit stateChanged(m_state, prevState);
89 if (m_state != state){
90 // End-application did something
91 // upon receiving the signal.
92 return false;
93 }
94 }
95 return true;
96}
97
98void MediaObject::inspectAudioGraphRecursive(AudioConnection *connection, int &effectCount, int &outputCount)
99{
100 if ((connection->m_sink->m_description & (AudioSource | AudioSink)) == (AudioSource | AudioSink))
101 ++effectCount;
102 else if (connection->m_sink->m_description & AudioSink)
103 ++outputCount;
104
105 for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i)
106 inspectAudioGraphRecursive(connection->m_sink->m_audioSinkList[i], effectCount, outputCount);
107}
108
109void MediaObject::inspectVideoGraphRecursive(MediaNode *node, int &effectCount, int &outputCount)
110{
111 if ((node->m_description & (VideoSource | VideoSink)) == (VideoSource | VideoSink))
112 ++effectCount;
113 else if (node->m_description & VideoSink)
114 ++outputCount;
115
116 for (int i=0; i<node->m_videoSinkList.size(); ++i)
117 inspectVideoGraphRecursive(node->m_videoSinkList[i], effectCount, outputCount);
118}
119
120void MediaObject::inspectGraph()
121{
122 // Inspect the graph to check wether there are any
123 // effects or outputs connected. This will have
124 // influence on the audio system and video system that ends up beeing used:
125 int prevVideoOutputCount = m_videoOutputCount;
126 m_audioEffectCount = 0;
127 m_audioOutputCount = 0;
128 m_videoEffectCount = 0;
129 m_videoOutputCount = 0;
130 AudioConnection rootConnection(this);
131 inspectAudioGraphRecursive(&rootConnection, m_audioEffectCount, m_audioOutputCount);
132 inspectVideoGraphRecursive(this, m_videoEffectCount, m_videoOutputCount);
133
134 if (m_videoOutputCount != prevVideoOutputCount){
135 MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
136 notify(&e1);
137 }
138}
139
140void MediaObject::setupAudioSystem()
141{
142 // Select which audio system to use:
143 AudioSystem newAudioSystem = AS_Unset;
144 if (!m_audioOutputCount || !m_videoPlayer->canPlayMedia()){
145 newAudioSystem = AS_Silent;
146 } else if (m_audioEffectCount == 0){
147 newAudioSystem = AS_Video;
148 } else if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_4){
149 newAudioSystem = AS_Video;
150 SET_ERROR("Audio effects are not supported for Mac OS 10.3 and below", NORMAL_ERROR);
151 } else if (m_videoPlayer->isDrmProtected()){
152 newAudioSystem = AS_Video;
153 SET_ERROR("Audio effects are not supported for DRM protected media", NORMAL_ERROR);
154 } else if (m_audioGraph->graphCannotPlay()){
155 newAudioSystem = AS_Video;
156 SET_ERROR("Audio effects are not supported for the current codec", NORMAL_ERROR);
157#ifdef QUICKTIME_C_API_AVAILABLE
158 } else {
159 newAudioSystem = AS_Graph;
160 }
161#else
162 } else {
163 newAudioSystem = AS_Video;
164 SET_ERROR("Audio effects are not supported for the 64-bit version of the Phonon QT7 backend", NORMAL_ERROR);
165 }
166#endif
167
168 if (newAudioSystem == m_audioSystem)
169 return;
170
171 // Enable selected audio system:
172 m_audioSystem = newAudioSystem;
173 switch (newAudioSystem){
174 case AS_Silent:
175 m_audioGraph->stop();
176 m_videoPlayer->enableAudio(false);
177 m_nextVideoPlayer->enableAudio(false);
178 m_audioPlayer->enableAudio(false);
179 m_nextAudioPlayer->enableAudio(false);
180 break;
181 case AS_Graph:
182 if (m_state == Phonon::PausedState)
183 m_audioGraph->prepare();
184 else
185 m_audioGraph->start();
186 // Starting the graph can lead to a recursive call
187 // telling us that we must direct audio through
188 // video. If that has happened, we must not proceed:
189 if (m_audioSystem != AS_Graph)
190 return;
191 m_videoPlayer->enableAudio(false);
192 m_nextVideoPlayer->enableAudio(false);
193 m_audioPlayer->enableAudio(true);
194 m_audioPlayer->seek(m_videoPlayer->currentTime());
195 m_nextAudioPlayer->enableAudio(true);
196 m_audioPlayer->seek(m_videoPlayer->currentTime());
197 m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
198 break;
199 case AS_Video:
200 case AS_Unset:
201 m_audioGraph->stop();
202 m_videoPlayer->enableAudio(true);
203 m_nextVideoPlayer->enableAudio(true);
204 m_audioPlayer->enableAudio(false);
205 m_nextAudioPlayer->enableAudio(false);
206 m_videoPlayer->seek(m_audioPlayer->currentTime());
207 m_nextVideoPlayer->seek(m_nextAudioPlayer->currentTime());
208 break;
209 }
210}
211
212void MediaObject::setSource(const MediaSource &source)
213{
214 IMPLEMENTED;
215 PhononAutoReleasePool pool;
216 setState(Phonon::LoadingState);
217
218 // Save current state for event/signal handling below:
219 bool prevHasVideo = m_videoPlayer->hasVideo();
220 qint64 prevTotalTime = totalTime();
221 m_waitNextSwap = false;
222
223 // Cancel cross-fade if any:
224 m_nextVideoPlayer->pause();
225 m_nextAudioPlayer->pause();
226 m_mediaObjectAudioNode->cancelCrossFade();
227
228 // Set new source:
229 m_audioPlayer->unsetVideoPlayer();
230 m_videoPlayer->setMediaSource(source);
231 m_audioPlayer->setVideoPlayer(m_videoPlayer);
232 m_metaData->setVideo(m_videoPlayer);
233
234 m_audioGraph->updateStreamSpecifications();
235 m_nextAudioPlayer->unsetVideoPlayer();
236 m_nextVideoPlayer->unsetVideo();
237 m_currentTime = 0;
238
239 // Emit/notify information about the new source:
240 QRect videoRect = m_videoPlayer->videoRect();
241 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
242 notify(&e1);
243
244 // Clear video widgets:
245 VideoFrame emptyFrame;
246 updateVideo(emptyFrame);
247
248 emit currentSourceChanged(source);
249 emit metaDataChanged(m_metaData->metaData());
250
251 if (prevHasVideo != m_videoPlayer->hasVideo())
252 emit hasVideoChanged(m_videoPlayer->hasVideo());
253 if (prevTotalTime != totalTime())
254 emit totalTimeChanged(totalTime());
255 if (checkForError())
256 return;
257 if (!m_videoPlayer->isDrmAuthorized())
258 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
259 if (checkForError())
260 return;
261 if (!m_videoPlayer->canPlayMedia())
262 SET_ERROR("Cannot play media.", FATAL_ERROR)
263
264 // The state might have changed from LoadingState
265 // as a response to an error state change. So we
266 // need to check it before stopping:
267 if (m_state == Phonon::LoadingState)
268 stop();
269
270 setupAudioSystem();
271 checkForError();
272}
273
274void MediaObject::setNextSource(const MediaSource &source)
275{
276 IMPLEMENTED;
277 m_nextAudioPlayer->unsetVideoPlayer();
278 m_nextVideoPlayer->setMediaSource(source);
279 m_nextAudioPlayer->setVideoPlayer(m_nextVideoPlayer);
280 checkForError();
281}
282
283void MediaObject::swapCurrentWithNext(qint32 transitionTime)
284{
285 PhononAutoReleasePool pool;
286 setState(Phonon::LoadingState);
287 // Save current state for event/signal handling below:
288 bool prevHasVideo = m_videoPlayer->hasVideo();
289 qint64 prevTotalTime = totalTime();
290
291 qSwap(m_audioPlayer, m_nextAudioPlayer);
292 qSwap(m_videoPlayer, m_nextVideoPlayer);
293 m_mediaObjectAudioNode->startCrossFade(transitionTime);
294 m_audioGraph->updateStreamSpecifications();
295 m_metaData->setVideo(m_videoPlayer);
296
297 m_waitNextSwap = false;
298 m_currentTime = 0;
299
300 // Emit/notify information about the new source:
301 QRect videoRect = m_videoPlayer->videoRect();
302 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
303 notify(&e1);
304
305 emit currentSourceChanged(m_videoPlayer->mediaSource());
306 emit metaDataChanged(m_metaData->metaData());
307
308 if (prevHasVideo != m_videoPlayer->hasVideo())
309 emit hasVideoChanged(m_videoPlayer->hasVideo());
310 if (prevTotalTime != totalTime())
311 emit totalTimeChanged(totalTime());
312 if (checkForError())
313 return;
314 if (!m_videoPlayer->isDrmAuthorized())
315 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
316 if (checkForError())
317 return;
318 if (!m_videoPlayer->canPlayMedia())
319 SET_ERROR("Cannot play next media.", FATAL_ERROR)
320
321 setupAudioSystem();
322 checkForError();
323 if (m_state == Phonon::LoadingState){
324 if (setState(Phonon::PlayingState))
325 play_internal();
326 checkForError();
327 }
328}
329
330void MediaObject::updateTimer(int &timer, int interval)
331{
332 if (timer)
333 killTimer(timer);
334 timer = 0;
335 if (interval >= 0)
336 timer = startTimer(interval);
337}
338
339void MediaObject::play_internal()
340{
341 // Play main audio/video:
342 m_videoPlayer->play();
343 m_audioPlayer->play();
344 updateLipSynch(0);
345 // Play old audio/video to finish cross-fade:
346 if (m_nextVideoPlayer->currentTime() > 0){
347 m_nextVideoPlayer->play();
348 m_nextAudioPlayer->play();
349 }
350 bufferAudioVideo();
351 updateTimer(m_rapidTimer, 100);
352}
353
354void MediaObject::pause_internal()
355{
356 m_audioGraph->stop();
357 m_audioPlayer->pause();
358 m_nextAudioPlayer->pause();
359 m_videoPlayer->pause();
360 m_nextVideoPlayer->pause();
361 updateTimer(m_rapidTimer, -1);
362 updateTimer(m_bufferTimer, -1);
363
364 if (m_waitNextSwap)
365 m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
366}
367
368void MediaObject::play()
369{
370 IMPLEMENTED;
371 if (m_state == Phonon::PlayingState)
372 return;
373 if (m_waitNextSwap){
374 // update swap time after pause:
375 m_swapTime = QTime::currentTime();
376 m_swapTime.addMSecs(m_swapTimeLeft);
377 setState(Phonon::PlayingState);
378 return;
379 }
380 if (m_currentTime == m_videoPlayer->duration())
381 return;
382 if (!m_videoPlayer->canPlayMedia())
383 return;
384 if (!setState(Phonon::PlayingState))
385 return;
386 if (m_audioSystem == AS_Graph){
387 m_audioGraph->start();
388 m_mediaObjectAudioNode->setMute(true);
389 }
390 // Inform the graph that we are about to play:
391 bool playing = true;
392 MediaNodeEvent e1(MediaNodeEvent::MediaPlaying, &playing);
393 notify(&e1);
394 // Start to play:
395 play_internal();
396 m_mediaObjectAudioNode->setMute(false);
397 checkForError();
398}
399
400void MediaObject::pause()
401{
402 IMPLEMENTED;
403 if (m_state == Phonon::PausedState)
404 return;
405 if (!setState(Phonon::PausedState))
406 return;
407 pause_internal();
408 // Inform the graph that we are no longer playing:
409 bool playing = false;
410 MediaNodeEvent e1(MediaNodeEvent::MediaPlaying, &playing);
411 notify(&e1);
412 // But be prepared:
413 if (m_audioSystem == AS_Graph)
414 m_audioGraph->prepare();
415 checkForError();
416}
417
418void MediaObject::stop()
419{
420 IMPLEMENTED;
421 if (m_state == Phonon::StoppedState)
422 return;
423 if (!setState(Phonon::StoppedState))
424 return;
425 m_waitNextSwap = false;
426 m_nextVideoPlayer->unsetVideo();
427 m_nextAudioPlayer->unsetVideoPlayer();
428 pause_internal();
429 seek(0);
430 checkForError();
431}
432
433void MediaObject::seek(qint64 milliseconds)
434{
435 IMPLEMENTED;
436 if (m_state == Phonon::ErrorState)
437 return;
438
439 // Stop cross-fade if any:
440 m_nextVideoPlayer->unsetVideo();
441 m_nextAudioPlayer->unsetVideoPlayer();
442 m_mediaObjectAudioNode->cancelCrossFade();
443
444 // Seek to new position:
445 m_mediaObjectAudioNode->setMute(true);
446 m_videoPlayer->seek(milliseconds);
447 m_audioPlayer->seek(m_videoPlayer->currentTime());
448 m_mediaObjectAudioNode->setMute(false);
449
450 // Update time and cancel pending swap:
451 if (m_currentTime < m_videoPlayer->duration())
452 m_waitNextSwap = false;
453
454 updateCurrentTime();
455 if (m_state != Phonon::PlayingState)
456 updateVideoFrames();
457 checkForError();
458}
459
460QStringList MediaObject::availableAudioStreams() const
461{
462 NOT_IMPLEMENTED;
463 return QStringList();
464}
465
466QStringList MediaObject::availableVideoStreams() const
467{
468 NOT_IMPLEMENTED;
469 return QStringList();
470}
471
472QStringList MediaObject::availableSubtitleStreams() const
473{
474 NOT_IMPLEMENTED;
475 return QStringList();
476}
477
478QString MediaObject::currentAudioStream(const QObject */*audioPath*/) const
479{
480 NOT_IMPLEMENTED;
481 return QString();
482}
483
484QString MediaObject::currentVideoStream(const QObject */*videoPath*/) const
485{
486 NOT_IMPLEMENTED;
487 return QString();
488}
489
490QString MediaObject::currentSubtitleStream(const QObject */*videoPath*/) const
491{
492 NOT_IMPLEMENTED;
493 return QString();
494}
495
496void MediaObject::setCurrentAudioStream(const QString &/*streamName*/,const QObject */*audioPath*/)
497{
498 NOT_IMPLEMENTED;
499}
500
501void MediaObject::setCurrentVideoStream(const QString &/*streamName*/,const QObject */*videoPath*/)
502{
503 NOT_IMPLEMENTED;
504}
505
506void MediaObject::setCurrentSubtitleStream(const QString &/*streamName*/,const QObject */*videoPath*/)
507{
508 NOT_IMPLEMENTED;
509}
510
511int MediaObject::videoOutputCount()
512{
513 return m_videoOutputCount;
514}
515
516void MediaObject::synchAudioVideo()
517{
518 if (m_state != Phonon::PlayingState)
519 return;
520 if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
521 return;
522
523 seek(m_currentTime);
524 checkForError();
525}
526
527qint32 MediaObject::tickInterval() const
528{
529 IMPLEMENTED;
530 return m_tickInterval;
531}
532
533void MediaObject::setTickInterval(qint32 interval)
534{
535 IMPLEMENTED;
536 m_tickInterval = interval;
537 if (m_tickInterval > 0)
538 m_tickTimer = startTimer(m_tickInterval);
539 else{
540 killTimer(m_tickTimer);
541 m_tickTimer = 0;
542 }
543}
544
545bool MediaObject::hasVideo() const
546{
547 IMPLEMENTED;
548 return m_videoPlayer ? m_videoPlayer->hasVideo() : false;
549}
550
551bool MediaObject::isSeekable() const
552{
553 IMPLEMENTED;
554 return m_videoPlayer ? m_videoPlayer->isSeekable() : false;
555}
556
557qint64 MediaObject::currentTime() const
558{
559 IMPLEMENTED_SILENT;
560 const_cast<MediaObject *>(this)->updateCurrentTime();
561 return m_currentTime;
562}
563
564void MediaObject::updateCurrentTime()
565{
566 quint64 lastUpdateTime = m_currentTime;
567 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
568 quint64 total = m_videoPlayer->duration();
569
570 // Check if it's time to emit aboutToFinish:
571 quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
572 if (lastUpdateTime < mark && mark <= m_currentTime)
573 emit aboutToFinish();
574
575 // Check if it's time to emit prefinishMarkReached:
576 mark = qMax(quint64(0), total - m_prefinishMark);
577 if (lastUpdateTime < mark && mark <= m_currentTime)
578 emit prefinishMarkReached(total - m_currentTime);
579
580 if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
581 // There is no next source in que.
582 // Check if it's time to emit finished:
583 if (lastUpdateTime < m_currentTime && m_currentTime == total){
584 emit finished();
585 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
586 if (m_state == Phonon::PlayingState && m_currentTime == total)
587 pause();
588 }
589 } else {
590 // We have a next source.
591 // Check if it's time to swap to next source:
592 mark = qMax(quint64(0), total + m_transitionTime);
593 if (m_waitNextSwap && m_state == Phonon::PlayingState &&
594 m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
595 swapCurrentWithNext(0);
596 } else if (mark >= total){
597 if (lastUpdateTime < total && total == m_currentTime){
598 m_swapTime = QTime::currentTime();
599 m_swapTime.addMSecs(mark - total);
600 m_waitNextSwap = true;
601 }
602 } else if (lastUpdateTime < mark && mark <= m_currentTime){
603 swapCurrentWithNext(total - m_currentTime);
604 }
605 }
606}
607
608qint64 MediaObject::totalTime() const
609{
610 IMPLEMENTED_SILENT;
611 return m_videoPlayer->duration();
612}
613
614Phonon::State MediaObject::state() const
615{
616 IMPLEMENTED;
617 return m_state;
618}
619
620QString MediaObject::errorString() const
621{
622 IMPLEMENTED;
623 return m_errorString;
624}
625
626Phonon::ErrorType MediaObject::errorType() const
627{
628 IMPLEMENTED;
629 return m_errorType;
630}
631
632bool MediaObject::checkForError()
633{
634 int type = gGetErrorType();
635 if (type == NO_ERROR)
636 return false;
637
638 m_errorType = (type == NORMAL_ERROR) ? Phonon::NormalError : Phonon::FatalError;
639 m_errorString = gGetErrorString();
640 pause_internal();
641 gClearError();
642 setState(Phonon::ErrorState);
643 return true;
644}
645
646QuickTimeVideoPlayer* MediaObject::videoPlayer() const
647{
648 return m_videoPlayer;
649}
650
651MediaSource MediaObject::source() const
652{
653 IMPLEMENTED;
654 return m_videoPlayer->mediaSource();
655}
656
657qint32 MediaObject::prefinishMark() const
658{
659 IMPLEMENTED;
660 return m_prefinishMark;
661}
662
663void MediaObject::setPrefinishMark(qint32 mark)
664{
665 IMPLEMENTED;
666 m_prefinishMark = mark;
667}
668
669qint32 MediaObject::transitionTime() const
670{
671 IMPLEMENTED;
672 return m_transitionTime;
673}
674
675void MediaObject::setTransitionTime(qint32 transitionTime)
676{
677 IMPLEMENTED;
678 m_transitionTime = transitionTime;
679}
680
681void MediaObject::setVolumeOnMovie(float volume)
682{
683 m_videoPlayer->setMasterVolume(volume);
684 m_nextVideoPlayer->setMasterVolume(volume);
685}
686
687bool MediaObject::setAudioDeviceOnMovie(int id)
688{
689 m_nextVideoPlayer->setAudioDevice(id);
690 return m_videoPlayer->setAudioDevice(id);
691}
692
693void MediaObject::updateCrossFade()
694{
695 m_mediaObjectAudioNode->updateCrossFade(m_currentTime);
696 // Clean-up previous movie if done fading:
697 if (m_mediaObjectAudioNode->m_fadeDuration == 0){
698 if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
699 m_nextVideoPlayer->unsetVideo();
700 m_nextAudioPlayer->unsetVideoPlayer();
701 }
702 }
703}
704
705void MediaObject::updateBufferStatus()
706{
707 float percent = m_videoPlayer->percentageLoaded();
708 if (percent != m_percentageLoaded){
709 m_percentageLoaded = percent;
710 emit bufferStatus(m_percentageLoaded * 100);
711 }
712}
713
714void MediaObject::updateAudioBuffers()
715{
716 // Schedule audio slices:
717 m_audioPlayer->scheduleAudioToGraph();
718 m_nextAudioPlayer->scheduleAudioToGraph();
719}
720
721bool MediaObject::isCrossFading()
722{
723 return m_mediaObjectAudioNode->isCrossFading();
724}
725
726void MediaObject::updateVideoFrames()
727{
728 // Draw next frame if awailable:
729 if (m_videoPlayer->videoFrameChanged()){
730 updateLipSynch(50);
731 VideoFrame frame(m_videoPlayer);
732 if (m_nextVideoPlayer->isPlaying()
733 && m_nextVideoPlayer->hasVideo()
734 && isCrossFading()){
735 VideoFrame bgFrame(m_nextVideoPlayer);
736 frame.setBackgroundFrame(bgFrame);
737 frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
738 }
739
740 // Send the frame through the graph:
741 updateVideo(frame);
742 checkForError();
743 }
744}
745
746void MediaObject::updateLipSynch(int allowedOffset)
747{
748 if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning())
749 return;
750 if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
751 return;
752
753 if (m_videoPlayer->hasVideo()){
754 qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
755 if (-allowedOffset > diff || diff > allowedOffset)
756 m_audioPlayer->seek(m_videoPlayer->currentTime());
757 }
758
759 if (isCrossFading() && m_nextVideoPlayer->hasVideo()){
760 qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime();
761 if (-(allowedOffset*2) > diff || diff > (allowedOffset*2))
762 m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
763 }
764}
765
766void 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));
774}
775
776void MediaObject::updateRapidly()
777{
778 updateCurrentTime();
779 updateCrossFade();
780 updateBufferStatus();
781}
782
783void MediaObject::setMute(bool mute)
784{
785 m_mediaObjectAudioNode->setMute(mute);
786 m_videoPlayer->setMute(mute);
787 m_nextVideoPlayer->setMute(mute);
788}
789
790void MediaObject::mediaNodeEvent(const MediaNodeEvent *event)
791{
792 switch (event->type()){
793 case MediaNodeEvent::EndConnectionChange:
794 m_mediaObjectAudioNode->setMute(true);
795 inspectGraph();
796 setupAudioSystem();
797 synchAudioVideo();
798 checkForError();
799 m_mediaObjectAudioNode->setMute(false);
800 if (m_state == Phonon::PlayingState)
801 bufferAudioVideo();
802 break;
803 case MediaNodeEvent::AudioGraphCannotPlay:
804 case MediaNodeEvent::AudioGraphInitialized:
805 if (m_state != Phonon::LoadingState){
806 m_mediaObjectAudioNode->setMute(true);
807 setupAudioSystem();
808 updateLipSynch(0);
809 checkForError();
810 m_mediaObjectAudioNode->setMute(false);
811 }
812 break;
813 default:
814 break;
815 }
816}
817
818bool 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 }
830 break;
831 default:
832 break;
833 }
834 return QObject::event(event);
835}
836
837bool MediaObject::hasInterface(Interface /*interface*/) const
838{
839 return false;
840}
841
842QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/)
843{
844 return QVariant();
845}
846
847}} // namespace Phonon::QT7
848
849QT_END_NAMESPACE
850
851#include "moc_mediaobject.cpp"
852
Note: See TracBrowser for help on using the repository browser.