~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/phonon/qt7/mediaobject.mm

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
47
47
    setAudioNode(m_mediaObjectAudioNode);
48
48
 
49
 
    m_metaData = new QuickTimeMetaData();
50
49
    m_audioGraph = new AudioGraph(this);
51
50
 
52
51
    m_tickInterval = 0;
55
54
    m_transitionTime = 0;
56
55
    m_percentageLoaded = 0;
57
56
    m_waitNextSwap = false;
 
57
    m_autoplayTitles = true;
58
58
    m_audioEffectCount = 0;
59
59
    m_audioOutputCount = 0;
60
60
    m_videoEffectCount = 0;
63
63
    m_errorType = Phonon::NoError;
64
64
 
65
65
    m_tickTimer = 0;
66
 
    m_bufferTimer = 0;
 
66
    m_videoTimer = 0;
 
67
    m_audioTimer = 0;
67
68
    m_rapidTimer = 0;
68
69
 
 
70
#if QT_ALLOW_QUICKTIME
 
71
    m_displayLink = 0;
 
72
    m_pendingDisplayLinkEvent = false;
 
73
#endif
 
74
 
69
75
    checkForError();
70
76
}
71
77
 
72
78
MediaObject::~MediaObject()
73
 
{   
74
 
    // m_mediaObjectAudioNode is owned by super class.    
 
79
{
 
80
    // m_mediaObjectAudioNode is owned by super class.
 
81
#if QT_ALLOW_QUICKTIME
 
82
    stopDisplayLink();
 
83
#endif
75
84
    m_audioPlayer->unsetVideoPlayer();
76
85
    m_nextAudioPlayer->unsetVideoPlayer();
77
86
    delete m_videoPlayer;
78
87
    delete m_nextVideoPlayer;
79
 
    delete m_metaData;
80
88
    checkForError();
81
89
}
82
90
 
88
96
        emit stateChanged(m_state, prevState);
89
97
        if (m_state != state){
90
98
            // End-application did something
91
 
            // upon  receiving the signal. 
 
99
            // upon  receiving the signal.
92
100
            return false;
93
101
        }
94
102
    }
122
130
    // Inspect the graph to check wether there are any
123
131
    // effects or outputs connected. This will have
124
132
    // influence on the audio system and video system that ends up beeing used:
125
 
    int prevVideoOutputCount = m_videoOutputCount;      
 
133
    int prevVideoOutputCount = m_videoOutputCount;
126
134
    m_audioEffectCount = 0;
127
135
    m_audioOutputCount = 0;
128
136
    m_videoEffectCount = 0;
134
142
        if (m_videoOutputCount != prevVideoOutputCount){
135
143
            MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
136
144
            notify(&e1);
137
 
        }       
 
145
    }
138
146
}
139
147
 
140
148
void MediaObject::setupAudioSystem()
167
175
 
168
176
    if (newAudioSystem == m_audioSystem)
169
177
        return;
170
 
  
 
178
 
171
179
    // Enable selected audio system:
172
 
    m_audioSystem = newAudioSystem; 
 
180
    m_audioSystem = newAudioSystem;
173
181
    switch (newAudioSystem){
174
182
        case AS_Silent:
175
183
            m_audioGraph->stop();
176
184
            m_videoPlayer->enableAudio(false);
177
 
            m_nextVideoPlayer->enableAudio(false);    
 
185
            m_nextVideoPlayer->enableAudio(false);
178
186
            m_audioPlayer->enableAudio(false);
179
187
            m_nextAudioPlayer->enableAudio(false);
180
188
        break;
214
222
    IMPLEMENTED;
215
223
        PhononAutoReleasePool pool;
216
224
    setState(Phonon::LoadingState);
217
 
    
 
225
 
218
226
    // Save current state for event/signal handling below:
219
227
    bool prevHasVideo = m_videoPlayer->hasVideo();
220
228
    qint64 prevTotalTime = totalTime();
 
229
    int prevTrackCount = m_videoPlayer->trackCount();
221
230
    m_waitNextSwap = false;
222
 
        
 
231
 
223
232
    // Cancel cross-fade if any:
224
233
    m_nextVideoPlayer->pause();
225
234
    m_nextAudioPlayer->pause();
226
235
    m_mediaObjectAudioNode->cancelCrossFade();
227
 
    
 
236
 
228
237
    // Set new source:
229
238
    m_audioPlayer->unsetVideoPlayer();
230
239
    m_videoPlayer->setMediaSource(source);
231
240
    m_audioPlayer->setVideoPlayer(m_videoPlayer);
232
 
    m_metaData->setVideo(m_videoPlayer);        
233
241
 
234
 
    m_audioGraph->updateStreamSpecifications();        
 
242
    m_audioGraph->updateStreamSpecifications();
235
243
    m_nextAudioPlayer->unsetVideoPlayer();
236
 
    m_nextVideoPlayer->unsetVideo();
 
244
    m_nextVideoPlayer->unsetCurrentMediaSource();
237
245
    m_currentTime = 0;
238
 
        
 
246
 
239
247
    // Emit/notify information about the new source:
240
248
    QRect videoRect = m_videoPlayer->videoRect();
241
249
    MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
246
254
    updateVideo(emptyFrame);
247
255
 
248
256
    emit currentSourceChanged(source);
249
 
    emit metaDataChanged(m_metaData->metaData());
 
257
    emit metaDataChanged(m_videoPlayer->metaData());
250
258
 
251
259
    if (prevHasVideo != m_videoPlayer->hasVideo())
252
 
        emit hasVideoChanged(m_videoPlayer->hasVideo());        
 
260
        emit hasVideoChanged(m_videoPlayer->hasVideo());
253
261
    if (prevTotalTime != totalTime())
254
 
        emit totalTimeChanged(totalTime());        
 
262
        emit totalTimeChanged(totalTime());
 
263
    if (prevTrackCount != m_videoPlayer->trackCount())
 
264
        emit availableTitlesChanged(m_videoPlayer->trackCount());
255
265
    if (checkForError())
256
266
        return;
257
267
    if (!m_videoPlayer->isDrmAuthorized())
260
270
        return;
261
271
    if (!m_videoPlayer->canPlayMedia())
262
272
        SET_ERROR("Cannot play media.", FATAL_ERROR)
263
 
        
 
273
 
264
274
    // The state might have changed from LoadingState
265
275
    // as a response to an error state change. So we
266
276
    // need to check it before stopping: 
287
297
    // Save current state for event/signal handling below:
288
298
    bool prevHasVideo = m_videoPlayer->hasVideo();
289
299
    qint64 prevTotalTime = totalTime();
 
300
    int prevTrackCount = m_videoPlayer->trackCount();
290
301
 
291
302
    qSwap(m_audioPlayer, m_nextAudioPlayer);
292
303
    qSwap(m_videoPlayer, m_nextVideoPlayer);
293
304
    m_mediaObjectAudioNode->startCrossFade(transitionTime);
294
305
    m_audioGraph->updateStreamSpecifications();
295
 
    m_metaData->setVideo(m_videoPlayer);
296
306
 
297
307
    m_waitNextSwap = false;
298
308
    m_currentTime = 0;
299
 
        
 
309
 
300
310
    // Emit/notify information about the new source:
301
311
    QRect videoRect = m_videoPlayer->videoRect();
302
312
    MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
303
313
    notify(&e1);
304
314
 
305
315
    emit currentSourceChanged(m_videoPlayer->mediaSource());
306
 
    emit metaDataChanged(m_metaData->metaData());
 
316
    emit metaDataChanged(m_videoPlayer->metaData());
307
317
 
308
318
    if (prevHasVideo != m_videoPlayer->hasVideo())
309
 
        emit hasVideoChanged(m_videoPlayer->hasVideo());        
 
319
        emit hasVideoChanged(m_videoPlayer->hasVideo());
310
320
    if (prevTotalTime != totalTime())
311
321
        emit totalTimeChanged(totalTime());
 
322
    if (prevTrackCount != m_videoPlayer->trackCount())
 
323
        emit availableTitlesChanged(m_videoPlayer->trackCount());
312
324
    if (checkForError())
313
325
        return;
314
326
    if (!m_videoPlayer->isDrmAuthorized())
327
339
    }
328
340
}
329
341
 
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); 
 
342
#if QT_ALLOW_QUICKTIME
 
343
static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/,
 
344
                                                                 const CVTimeStamp */*inNow*/,
 
345
                                                                 const CVTimeStamp */*inOutputTime*/,
 
346
                                                                 CVOptionFlags /*flagsIn*/,
 
347
                                                                 CVOptionFlags */*flagsOut*/,
 
348
                                 void *userData)
 
349
{
 
350
    MediaObject *mediaObject = static_cast<MediaObject *>(userData);
 
351
    mediaObject->displayLinkEvent();
 
352
    return kCVReturnSuccess;
 
353
}
 
354
 
 
355
void MediaObject::displayLinkEvent()
 
356
{
 
357
    // This function is called from a
 
358
    // thread != gui thread. So we post the event.
 
359
    // But we need to make sure that we don't post faster
 
360
    // than the event loop can eat:
 
361
    m_displayLinkMutex.lock();
 
362
    bool pending = m_pendingDisplayLinkEvent;
 
363
    m_pendingDisplayLinkEvent = true;
 
364
    m_displayLinkMutex.unlock();
 
365
 
 
366
    if (!pending)
 
367
        qApp->postEvent(this, new QEvent(QEvent::User), Qt::HighEventPriority);
 
368
}
 
369
 
 
370
void MediaObject::startDisplayLink()
 
371
{
 
372
    if (m_displayLink)
 
373
        return;
 
374
    OSStatus err = CVDisplayLinkCreateWithCGDisplay(kCGDirectMainDisplay, &m_displayLink);
 
375
    if (err != noErr)
 
376
        goto fail;
 
377
    err = CVDisplayLinkSetCurrentCGDisplay(m_displayLink, kCGDirectMainDisplay);
 
378
    if (err != noErr)
 
379
        goto fail;
 
380
    err = CVDisplayLinkSetOutputCallback(m_displayLink, displayLinkCallback, this);
 
381
    if (err != noErr)
 
382
        goto fail;
 
383
    err = CVDisplayLinkStart(m_displayLink);
 
384
    if (err != noErr)
 
385
        goto fail;
 
386
    return;
 
387
fail:
 
388
    stopDisplayLink();
 
389
}
 
390
 
 
391
void MediaObject::stopDisplayLink()
 
392
{
 
393
    if (!m_displayLink)
 
394
        return;
 
395
    CVDisplayLinkStop(m_displayLink);
 
396
    CFRelease(m_displayLink);
 
397
    m_displayLink = 0;
 
398
}
 
399
#endif
 
400
 
 
401
void MediaObject::restartAudioVideoTimers()
 
402
{
 
403
    if (m_videoTimer)
 
404
        killTimer(m_videoTimer);
 
405
    if (m_audioTimer)
 
406
        killTimer(m_audioTimer);
 
407
 
 
408
#if QT_ALLOW_QUICKTIME
 
409
    // We prefer to use a display link as timer if available, since
 
410
    // it is more steady, and results in better and smoother frame drawing:
 
411
    startDisplayLink();
 
412
    if (!m_displayLink){
 
413
        float fps = m_videoPlayer->staticFps();
 
414
        long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
 
415
        m_videoTimer = startTimer(videoUpdateFrequency);
 
416
    }
 
417
#else
 
418
    float fps = m_videoPlayer->staticFps();
 
419
    long videoUpdateFrequency = fps ? long(1000.0f / fps) : 0.001;
 
420
    m_videoTimer = startTimer(videoUpdateFrequency);
 
421
#endif
 
422
 
 
423
    long audioUpdateFrequency = m_audioPlayer->regularTaskFrequency();
 
424
    m_audioTimer = startTimer(audioUpdateFrequency);
 
425
    updateVideoFrames();
 
426
    updateAudioBuffers();
337
427
}
338
428
 
339
429
void MediaObject::play_internal()
340
430
{
341
431
    // Play main audio/video:
342
432
    m_videoPlayer->play();
343
 
    m_audioPlayer->play();     
 
433
    m_audioPlayer->play();
344
434
    updateLipSynch(0);
345
435
    // Play old audio/video to finish cross-fade:
346
436
    if (m_nextVideoPlayer->currentTime() > 0){
347
437
        m_nextVideoPlayer->play();
348
438
        m_nextAudioPlayer->play();
349
439
    }
350
 
    bufferAudioVideo();
351
 
    updateTimer(m_rapidTimer, 100);
 
440
    restartAudioVideoTimers();
 
441
    if (!m_rapidTimer)
 
442
        m_rapidTimer = startTimer(100);
352
443
}
353
444
 
354
445
void MediaObject::pause_internal()
358
449
    m_nextAudioPlayer->pause();
359
450
    m_videoPlayer->pause();
360
451
    m_nextVideoPlayer->pause();
361
 
    updateTimer(m_rapidTimer, -1);
362
 
    updateTimer(m_bufferTimer, -1);
363
 
 
 
452
    killTimer(m_rapidTimer);
 
453
    killTimer(m_videoTimer);
 
454
    killTimer(m_audioTimer);
 
455
    m_rapidTimer = 0;
 
456
    m_videoTimer = 0;
 
457
    m_audioTimer = 0;
 
458
#if QT_ALLOW_QUICKTIME
 
459
    stopDisplayLink();
 
460
#endif
364
461
    if (m_waitNextSwap)
365
462
        m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
366
463
}
382
479
    if (!m_videoPlayer->canPlayMedia())
383
480
        return;
384
481
    if (!setState(Phonon::PlayingState))
385
 
        return;        
 
482
        return;
386
483
    if (m_audioSystem == AS_Graph){
387
484
        m_audioGraph->start();
388
485
        m_mediaObjectAudioNode->setMute(true);
423
520
    if (!setState(Phonon::StoppedState))
424
521
        return;
425
522
    m_waitNextSwap = false;
426
 
    m_nextVideoPlayer->unsetVideo();
 
523
    m_nextVideoPlayer->unsetCurrentMediaSource();
427
524
    m_nextAudioPlayer->unsetVideoPlayer();
428
525
    pause_internal();
429
526
    seek(0);
435
532
    IMPLEMENTED;
436
533
    if (m_state == Phonon::ErrorState)
437
534
        return;
438
 
        
 
535
 
439
536
    // Stop cross-fade if any:
440
 
    m_nextVideoPlayer->unsetVideo();
 
537
    m_nextVideoPlayer->unsetCurrentMediaSource();
441
538
    m_nextAudioPlayer->unsetVideoPlayer();
442
539
    m_mediaObjectAudioNode->cancelCrossFade();
443
540
 
446
543
    m_videoPlayer->seek(milliseconds);
447
544
    m_audioPlayer->seek(m_videoPlayer->currentTime());
448
545
    m_mediaObjectAudioNode->setMute(false);
449
 
    
 
546
 
450
547
    // Update time and cancel pending swap:
451
548
    if (m_currentTime < m_videoPlayer->duration())
452
549
        m_waitNextSwap = false;
557
654
qint64 MediaObject::currentTime() const
558
655
{
559
656
    IMPLEMENTED_SILENT;
560
 
    const_cast<MediaObject *>(this)->updateCurrentTime(); 
 
657
    const_cast<MediaObject *>(this)->updateCurrentTime();
561
658
    return m_currentTime;
562
659
}
563
660
 
567
664
    m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
568
665
    quint64 total = m_videoPlayer->duration();
569
666
 
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:
 
667
    if (m_videoPlayer->currentTrack() < m_videoPlayer->trackCount() - 1){
 
668
        // There are still more tracks to play after the current track.
 
669
        if (m_autoplayTitles) {
 
670
            if (lastUpdateTime < m_currentTime && m_currentTime == total)
 
671
                setCurrentTrack(m_videoPlayer->currentTrack() + 1);
 
672
        }
 
673
    } else if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
 
674
        // There is no more sources or tracks to play after the current source.
 
675
        // Check if it's time to emit aboutToFinish:
 
676
        quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
 
677
        if (lastUpdateTime < mark && mark <= m_currentTime)
 
678
            emit aboutToFinish();
 
679
 
 
680
        // Check if it's time to emit prefinishMarkReached:
 
681
        mark = qMax(quint64(0), total - m_prefinishMark);
 
682
        if (lastUpdateTime < mark && mark <= m_currentTime)
 
683
            emit prefinishMarkReached(total - m_currentTime);
 
684
 
583
685
        if (lastUpdateTime < m_currentTime && m_currentTime == total){
584
686
            emit finished();
585
687
            m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
589
691
    } else {
590
692
        // We have a next source.
591
693
        // Check if it's time to swap to next source:
592
 
        mark = qMax(quint64(0), total + m_transitionTime);
 
694
        quint32 mark = qMax(quint64(0), total + m_transitionTime);
593
695
        if (m_waitNextSwap && m_state == Phonon::PlayingState &&
594
696
            m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
595
697
            swapCurrentWithNext(0);
692
794
 
693
795
void MediaObject::updateCrossFade()
694
796
{
695
 
    m_mediaObjectAudioNode->updateCrossFade(m_currentTime);   
 
797
    m_mediaObjectAudioNode->updateCrossFade(m_currentTime);
696
798
    // Clean-up previous movie if done fading:
697
799
    if (m_mediaObjectAudioNode->m_fadeDuration == 0){
698
800
        if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
699
 
            m_nextVideoPlayer->unsetVideo();
 
801
            m_nextVideoPlayer->unsetCurrentMediaSource();
700
802
            m_nextAudioPlayer->unsetVideoPlayer();
701
803
        }
702
 
    }        
 
804
    }
703
805
}
704
806
 
705
807
void MediaObject::updateBufferStatus()
728
830
    // Draw next frame if awailable:
729
831
    if (m_videoPlayer->videoFrameChanged()){
730
832
        updateLipSynch(50);
731
 
        VideoFrame frame(m_videoPlayer);           
 
833
        VideoFrame frame(m_videoPlayer);
732
834
        if (m_nextVideoPlayer->isPlaying()
733
835
            && m_nextVideoPlayer->hasVideo()
734
836
            && isCrossFading()){
736
838
            frame.setBackgroundFrame(bgFrame);
737
839
            frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
738
840
        }
739
 
        
 
841
 
740
842
        // Send the frame through the graph:
741
 
        updateVideo(frame);    
 
843
        updateVideo(frame);
742
844
        checkForError();
743
845
    }
744
846
}
749
851
        return;
750
852
    if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
751
853
        return;
752
 
        
 
854
 
753
855
    if (m_videoPlayer->hasVideo()){
754
856
        qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
755
857
        if (-allowedOffset > diff || diff > allowedOffset)
763
865
    }
764
866
}
765
867
 
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
868
void MediaObject::updateRapidly()
777
869
{
778
870
    updateCurrentTime();
797
889
            synchAudioVideo();
798
890
            checkForError();
799
891
            m_mediaObjectAudioNode->setMute(false);
800
 
             if (m_state == Phonon::PlayingState)
801
 
                bufferAudioVideo();
 
892
            if (m_state == Phonon::PlayingState)
 
893
                restartAudioVideoTimers();
802
894
            break;
803
895
        case MediaNodeEvent::AudioGraphCannotPlay:
804
896
        case MediaNodeEvent::AudioGraphInitialized:
809
901
                checkForError();
810
902
                m_mediaObjectAudioNode->setMute(false);
811
903
            }
812
 
            break; 
 
904
            break;
813
905
        default:
814
906
            break;
815
907
    }
818
910
bool MediaObject::event(QEvent *event)
819
911
{
820
912
    switch (event->type()){
821
 
        case QEvent::Timer: {
822
 
            QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
823
 
            if (timerEvent->timerId() == m_rapidTimer)
 
913
#if QT_ALLOW_QUICKTIME
 
914
        case QEvent::User:{
 
915
            m_displayLinkMutex.lock();
 
916
            m_pendingDisplayLinkEvent = false;
 
917
            m_displayLinkMutex.unlock();
 
918
            updateVideoFrames();
 
919
            break; }
 
920
#endif
 
921
        case QEvent::Timer:{
 
922
            int timerId = static_cast<QTimerEvent *>(event)->timerId();
 
923
            if (timerId == m_rapidTimer)
824
924
                updateRapidly();
825
 
            else if (timerEvent->timerId() == m_tickTimer)
 
925
            else if (timerId == m_tickTimer)
826
926
                emit tick(currentTime());
827
 
            else if (timerEvent->timerId() == m_bufferTimer)
828
 
                bufferAudioVideo();
829
 
            }
830
 
            break;
 
927
            else if (timerId == m_videoTimer)
 
928
                updateVideoFrames();
 
929
            else if (timerId == m_audioTimer)
 
930
                updateAudioBuffers();
 
931
            break; }
831
932
        default:
832
933
            break;
833
934
    }
834
935
    return QObject::event(event);
835
936
}
836
937
 
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
 
{
 
938
void MediaObject::setCurrentTrack(int track)
 
939
{
 
940
    if (track == m_videoPlayer->currentTrack() || track < 0 || track >= m_videoPlayer->trackCount())
 
941
        return;
 
942
 
 
943
    m_videoPlayer->setCurrentTrack(track);
 
944
    emit titleChanged(track);
 
945
    emit metaDataChanged(m_videoPlayer->metaData());
 
946
}
 
947
 
 
948
bool MediaObject::hasInterface(Interface iface) const
 
949
{
 
950
    return iface == AddonInterface::TitleInterface;
 
951
}
 
952
 
 
953
QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> &params)
 
954
{
 
955
    switch (iface) {
 
956
        case TitleInterface:
 
957
            switch (command) {
 
958
                case availableTitles:
 
959
                    return m_videoPlayer->trackCount();
 
960
                case title:
 
961
                    return m_videoPlayer->currentTrack();
 
962
                case setTitle:
 
963
                    setCurrentTrack(params.first().toInt());
 
964
                    break;
 
965
                case autoplayTitles:
 
966
                    return m_autoplayTitles;
 
967
                case setAutoplayTitles:
 
968
                    m_autoplayTitles = params.first().toBool();
 
969
                    break;
 
970
            }
 
971
        default:
 
972
            break;
 
973
    }
844
974
    return QVariant();
845
975
}
846
976