~ubuntu-branches/ubuntu/oneiric/phonon/oneiric-201108111512

« back to all changes in this revision

Viewing changes to qt7/mediaobject.mm

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2011-01-24 10:12:11 UTC
  • mfrom: (0.5.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20110124101211-w9rew7q0dmwbwhqx
Tags: 4:4.7.0really4.4.4-0ubuntu1
* New upstream release
* Xine and GStreamer backends now split out source, remove build-deps and
  binary packages from debian/control
* Remove 02_no_rpath.patch, now upstream
* Disable kubuntu04_no_va_mangle.patch, no longer applies
* Remove kubuntu_05_gst_codec_installer_window_id.diff, kubuntu_06_forward_events.diff,
  kubuntu_07_include_fix.diff, gstreamer now separate

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
30
 
QT_BEGIN_NAMESPACE
31
 
 
32
 
namespace Phonon
33
 
{
34
 
namespace QT7
35
 
{
36
 
 
37
 
MediaObject::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
 
 
72
 
MediaObject::~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
 
 
83
 
bool 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
 
 
98
 
void 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
 
 
109
 
void 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
 
 
120
 
void 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
 
 
140
 
void 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
 
 
212
 
void 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
 
 
274
 
void 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
 
 
283
 
void 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
 
 
330
 
void 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
 
 
339
 
void 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
 
 
354
 
void 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
 
 
368
 
void 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
 
 
400
 
void 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
 
 
418
 
void 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
 
 
433
 
void 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
 
 
460
 
QStringList MediaObject::availableAudioStreams() const
461
 
{
462
 
    NOT_IMPLEMENTED;
463
 
    return QStringList();
464
 
}
465
 
 
466
 
QStringList MediaObject::availableVideoStreams() const
467
 
{
468
 
    NOT_IMPLEMENTED;
469
 
    return QStringList();
470
 
}
471
 
 
472
 
QStringList MediaObject::availableSubtitleStreams() const
473
 
{
474
 
    NOT_IMPLEMENTED;
475
 
    return QStringList();
476
 
}
477
 
 
478
 
QString MediaObject::currentAudioStream(const QObject */*audioPath*/) const
479
 
{
480
 
    NOT_IMPLEMENTED;
481
 
    return QString();
482
 
}
483
 
 
484
 
QString MediaObject::currentVideoStream(const QObject */*videoPath*/) const
485
 
{
486
 
    NOT_IMPLEMENTED;
487
 
    return QString();
488
 
}
489
 
 
490
 
QString MediaObject::currentSubtitleStream(const QObject */*videoPath*/) const
491
 
{
492
 
    NOT_IMPLEMENTED;
493
 
    return QString();
494
 
}
495
 
 
496
 
void MediaObject::setCurrentAudioStream(const QString &/*streamName*/,const QObject */*audioPath*/)
497
 
{
498
 
    NOT_IMPLEMENTED;
499
 
}
500
 
 
501
 
void MediaObject::setCurrentVideoStream(const QString &/*streamName*/,const QObject */*videoPath*/)
502
 
{
503
 
    NOT_IMPLEMENTED;
504
 
}
505
 
 
506
 
void MediaObject::setCurrentSubtitleStream(const QString &/*streamName*/,const QObject */*videoPath*/)
507
 
{
508
 
    NOT_IMPLEMENTED;
509
 
}
510
 
 
511
 
int MediaObject::videoOutputCount()
512
 
{
513
 
        return m_videoOutputCount;
514
 
}
515
 
 
516
 
void 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
 
 
527
 
qint32 MediaObject::tickInterval() const
528
 
{
529
 
    IMPLEMENTED;
530
 
    return m_tickInterval;
531
 
}
532
 
 
533
 
void 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
 
 
545
 
bool MediaObject::hasVideo() const
546
 
{
547
 
    IMPLEMENTED;
548
 
    return m_videoPlayer ? m_videoPlayer->hasVideo() : false;
549
 
}
550
 
 
551
 
bool MediaObject::isSeekable() const
552
 
{
553
 
    IMPLEMENTED;
554
 
    return m_videoPlayer ? m_videoPlayer->isSeekable() : false;
555
 
}
556
 
 
557
 
qint64 MediaObject::currentTime() const
558
 
{
559
 
    IMPLEMENTED_SILENT;
560
 
    const_cast<MediaObject *>(this)->updateCurrentTime(); 
561
 
    return m_currentTime;
562
 
}
563
 
 
564
 
void 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
 
 
608
 
qint64 MediaObject::totalTime() const
609
 
{
610
 
    IMPLEMENTED_SILENT;
611
 
    return m_videoPlayer->duration();
612
 
}
613
 
 
614
 
Phonon::State MediaObject::state() const
615
 
{
616
 
    IMPLEMENTED;
617
 
    return m_state;
618
 
}
619
 
 
620
 
QString MediaObject::errorString() const
621
 
{
622
 
    IMPLEMENTED;
623
 
    return m_errorString;
624
 
}
625
 
 
626
 
Phonon::ErrorType MediaObject::errorType() const
627
 
{
628
 
    IMPLEMENTED;
629
 
    return m_errorType;
630
 
}
631
 
 
632
 
bool 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
 
 
646
 
QuickTimeVideoPlayer* MediaObject::videoPlayer() const
647
 
{
648
 
    return m_videoPlayer;
649
 
}
650
 
 
651
 
MediaSource MediaObject::source() const
652
 
{
653
 
    IMPLEMENTED;
654
 
    return m_videoPlayer->mediaSource();
655
 
}
656
 
 
657
 
qint32 MediaObject::prefinishMark() const
658
 
{
659
 
    IMPLEMENTED;
660
 
    return m_prefinishMark;
661
 
}
662
 
 
663
 
void MediaObject::setPrefinishMark(qint32 mark)
664
 
{
665
 
    IMPLEMENTED;
666
 
    m_prefinishMark = mark;
667
 
}
668
 
 
669
 
qint32 MediaObject::transitionTime() const
670
 
{
671
 
    IMPLEMENTED;
672
 
    return m_transitionTime;
673
 
}
674
 
 
675
 
void MediaObject::setTransitionTime(qint32 transitionTime)
676
 
{
677
 
    IMPLEMENTED;
678
 
    m_transitionTime = transitionTime;
679
 
}
680
 
 
681
 
void MediaObject::setVolumeOnMovie(float volume)
682
 
{
683
 
    m_videoPlayer->setMasterVolume(volume);
684
 
    m_nextVideoPlayer->setMasterVolume(volume);
685
 
}
686
 
 
687
 
bool MediaObject::setAudioDeviceOnMovie(int id)
688
 
{
689
 
    m_nextVideoPlayer->setAudioDevice(id);
690
 
    return m_videoPlayer->setAudioDevice(id);
691
 
}
692
 
 
693
 
void 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
 
 
705
 
void 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
 
 
714
 
void MediaObject::updateAudioBuffers()
715
 
{
716
 
    // Schedule audio slices:
717
 
    m_audioPlayer->scheduleAudioToGraph();
718
 
    m_nextAudioPlayer->scheduleAudioToGraph();
719
 
}
720
 
 
721
 
bool MediaObject::isCrossFading()
722
 
{
723
 
    return m_mediaObjectAudioNode->isCrossFading();
724
 
}
725
 
 
726
 
void 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
 
 
746
 
void 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
 
 
766
 
void 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
 
 
776
 
void MediaObject::updateRapidly()
777
 
{
778
 
    updateCurrentTime();
779
 
    updateCrossFade();
780
 
    updateBufferStatus();
781
 
}
782
 
 
783
 
void MediaObject::setMute(bool mute)
784
 
{
785
 
    m_mediaObjectAudioNode->setMute(mute);
786
 
    m_videoPlayer->setMute(mute);
787
 
    m_nextVideoPlayer->setMute(mute);
788
 
}
789
 
 
790
 
void 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
 
 
818
 
bool 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
 
 
837
 
bool MediaObject::hasInterface(Interface /*interface*/) const
838
 
{
839
 
    return false;
840
 
}
841
 
 
842
 
QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/)
843
 
{
844
 
    return QVariant();
845
 
}
846
 
 
847
 
}} // namespace Phonon::QT7
848
 
 
849
 
QT_END_NAMESPACE
850
 
 
851
 
#include "moc_mediaobject.cpp"
852