44 m_nextVideoPlayer = new QuickTimeVideoPlayer(); |
44 m_nextVideoPlayer = new QuickTimeVideoPlayer(); |
45 m_nextAudioPlayer = new QuickTimeAudioPlayer(); |
45 m_nextAudioPlayer = new QuickTimeAudioPlayer(); |
46 m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer); |
46 m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer); |
47 setAudioNode(m_mediaObjectAudioNode); |
47 setAudioNode(m_mediaObjectAudioNode); |
48 |
48 |
|
49 m_metaData = new QuickTimeMetaData(); |
49 m_audioGraph = new AudioGraph(this); |
50 m_audioGraph = new AudioGraph(this); |
50 |
51 |
51 m_tickInterval = 0; |
52 m_tickInterval = 0; |
52 m_prefinishMark = 0; |
53 m_prefinishMark = 0; |
53 m_currentTime = 0; |
54 m_currentTime = 0; |
54 m_transitionTime = 0; |
55 m_transitionTime = 0; |
55 m_percentageLoaded = 0; |
56 m_percentageLoaded = 0; |
56 m_waitNextSwap = false; |
57 m_waitNextSwap = false; |
57 m_autoplayTitles = true; |
|
58 m_audioEffectCount = 0; |
58 m_audioEffectCount = 0; |
59 m_audioOutputCount = 0; |
59 m_audioOutputCount = 0; |
60 m_videoEffectCount = 0; |
60 m_videoEffectCount = 0; |
61 m_videoOutputCount = 0; |
61 m_videoOutputCount = 0; |
62 m_audioSystem = AS_Unset; |
62 m_audioSystem = AS_Unset; |
63 m_errorType = Phonon::NoError; |
63 m_errorType = Phonon::NoError; |
64 |
64 |
65 m_tickTimer = 0; |
65 m_tickTimer = 0; |
66 m_videoTimer = 0; |
66 m_bufferTimer = 0; |
67 m_audioTimer = 0; |
|
68 m_rapidTimer = 0; |
67 m_rapidTimer = 0; |
69 |
68 |
70 #if QT_ALLOW_QUICKTIME |
|
71 m_displayLink = 0; |
|
72 m_pendingDisplayLinkEvent = false; |
|
73 #endif |
|
74 |
|
75 checkForError(); |
69 checkForError(); |
76 } |
70 } |
77 |
71 |
78 MediaObject::~MediaObject() |
72 MediaObject::~MediaObject() |
79 { |
73 { |
80 // m_mediaObjectAudioNode is owned by super class. |
74 // m_mediaObjectAudioNode is owned by super class. |
81 #if QT_ALLOW_QUICKTIME |
|
82 stopDisplayLink(); |
|
83 #endif |
|
84 m_audioPlayer->unsetVideoPlayer(); |
75 m_audioPlayer->unsetVideoPlayer(); |
85 m_nextAudioPlayer->unsetVideoPlayer(); |
76 m_nextAudioPlayer->unsetVideoPlayer(); |
86 delete m_videoPlayer; |
77 delete m_videoPlayer; |
87 delete m_nextVideoPlayer; |
78 delete m_nextVideoPlayer; |
|
79 delete m_metaData; |
88 checkForError(); |
80 checkForError(); |
89 } |
81 } |
90 |
82 |
91 bool MediaObject::setState(Phonon::State state) |
83 bool MediaObject::setState(Phonon::State state) |
92 { |
84 { |
128 void MediaObject::inspectGraph() |
120 void MediaObject::inspectGraph() |
129 { |
121 { |
130 // Inspect the graph to check wether there are any |
122 // Inspect the graph to check wether there are any |
131 // effects or outputs connected. This will have |
123 // effects or outputs connected. This will have |
132 // influence on the audio system and video system that ends up beeing used: |
124 // influence on the audio system and video system that ends up beeing used: |
133 int prevVideoOutputCount = m_videoOutputCount; |
125 int prevVideoOutputCount = m_videoOutputCount; |
134 m_audioEffectCount = 0; |
126 m_audioEffectCount = 0; |
135 m_audioOutputCount = 0; |
127 m_audioOutputCount = 0; |
136 m_videoEffectCount = 0; |
128 m_videoEffectCount = 0; |
137 m_videoOutputCount = 0; |
129 m_videoOutputCount = 0; |
138 AudioConnection rootConnection(this); |
130 AudioConnection rootConnection(this); |
173 } |
165 } |
174 #endif |
166 #endif |
175 |
167 |
176 if (newAudioSystem == m_audioSystem) |
168 if (newAudioSystem == m_audioSystem) |
177 return; |
169 return; |
178 |
170 |
179 // Enable selected audio system: |
171 // Enable selected audio system: |
180 m_audioSystem = newAudioSystem; |
172 m_audioSystem = newAudioSystem; |
181 switch (newAudioSystem){ |
173 switch (newAudioSystem){ |
182 case AS_Silent: |
174 case AS_Silent: |
183 m_audioGraph->stop(); |
175 m_audioGraph->stop(); |
184 m_videoPlayer->enableAudio(false); |
176 m_videoPlayer->enableAudio(false); |
185 m_nextVideoPlayer->enableAudio(false); |
177 m_nextVideoPlayer->enableAudio(false); |
186 m_audioPlayer->enableAudio(false); |
178 m_audioPlayer->enableAudio(false); |
187 m_nextAudioPlayer->enableAudio(false); |
179 m_nextAudioPlayer->enableAudio(false); |
188 break; |
180 break; |
189 case AS_Graph: |
181 case AS_Graph: |
190 if (m_state == Phonon::PausedState) |
182 if (m_state == Phonon::PausedState) |
220 void MediaObject::setSource(const MediaSource &source) |
212 void MediaObject::setSource(const MediaSource &source) |
221 { |
213 { |
222 IMPLEMENTED; |
214 IMPLEMENTED; |
223 PhononAutoReleasePool pool; |
215 PhononAutoReleasePool pool; |
224 setState(Phonon::LoadingState); |
216 setState(Phonon::LoadingState); |
225 |
217 |
226 // Save current state for event/signal handling below: |
218 // Save current state for event/signal handling below: |
227 bool prevHasVideo = m_videoPlayer->hasVideo(); |
219 bool prevHasVideo = m_videoPlayer->hasVideo(); |
228 qint64 prevTotalTime = totalTime(); |
220 qint64 prevTotalTime = totalTime(); |
229 int prevTrackCount = m_videoPlayer->trackCount(); |
|
230 m_waitNextSwap = false; |
221 m_waitNextSwap = false; |
231 |
222 |
232 // Cancel cross-fade if any: |
223 // Cancel cross-fade if any: |
233 m_nextVideoPlayer->pause(); |
224 m_nextVideoPlayer->pause(); |
234 m_nextAudioPlayer->pause(); |
225 m_nextAudioPlayer->pause(); |
235 m_mediaObjectAudioNode->cancelCrossFade(); |
226 m_mediaObjectAudioNode->cancelCrossFade(); |
236 |
227 |
237 // Set new source: |
228 // Set new source: |
238 m_audioPlayer->unsetVideoPlayer(); |
229 m_audioPlayer->unsetVideoPlayer(); |
239 m_videoPlayer->setMediaSource(source); |
230 m_videoPlayer->setMediaSource(source); |
240 m_audioPlayer->setVideoPlayer(m_videoPlayer); |
231 m_audioPlayer->setVideoPlayer(m_videoPlayer); |
241 |
232 m_metaData->setVideo(m_videoPlayer); |
242 m_audioGraph->updateStreamSpecifications(); |
233 |
|
234 m_audioGraph->updateStreamSpecifications(); |
243 m_nextAudioPlayer->unsetVideoPlayer(); |
235 m_nextAudioPlayer->unsetVideoPlayer(); |
244 m_nextVideoPlayer->unsetCurrentMediaSource(); |
236 m_nextVideoPlayer->unsetVideo(); |
245 m_currentTime = 0; |
237 m_currentTime = 0; |
246 |
238 |
247 // Emit/notify information about the new source: |
239 // Emit/notify information about the new source: |
248 QRect videoRect = m_videoPlayer->videoRect(); |
240 QRect videoRect = m_videoPlayer->videoRect(); |
249 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); |
241 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); |
250 notify(&e1); |
242 notify(&e1); |
251 |
243 |
252 // Clear video widgets: |
244 // Clear video widgets: |
253 VideoFrame emptyFrame; |
245 VideoFrame emptyFrame; |
254 updateVideo(emptyFrame); |
246 updateVideo(emptyFrame); |
255 |
247 |
256 emit currentSourceChanged(source); |
248 emit currentSourceChanged(source); |
257 emit metaDataChanged(m_videoPlayer->metaData()); |
249 emit metaDataChanged(m_metaData->metaData()); |
258 |
250 |
259 if (prevHasVideo != m_videoPlayer->hasVideo()) |
251 if (prevHasVideo != m_videoPlayer->hasVideo()) |
260 emit hasVideoChanged(m_videoPlayer->hasVideo()); |
252 emit hasVideoChanged(m_videoPlayer->hasVideo()); |
261 if (prevTotalTime != totalTime()) |
253 if (prevTotalTime != totalTime()) |
262 emit totalTimeChanged(totalTime()); |
254 emit totalTimeChanged(totalTime()); |
263 if (prevTrackCount != m_videoPlayer->trackCount()) |
|
264 emit availableTitlesChanged(m_videoPlayer->trackCount()); |
|
265 if (checkForError()) |
255 if (checkForError()) |
266 return; |
256 return; |
267 if (!m_videoPlayer->isDrmAuthorized()) |
257 if (!m_videoPlayer->isDrmAuthorized()) |
268 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR) |
258 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR) |
269 if (checkForError()) |
259 if (checkForError()) |
270 return; |
260 return; |
271 if (!m_videoPlayer->canPlayMedia()) |
261 if (!m_videoPlayer->canPlayMedia()) |
272 SET_ERROR("Cannot play media.", FATAL_ERROR) |
262 SET_ERROR("Cannot play media.", FATAL_ERROR) |
273 |
263 |
274 // The state might have changed from LoadingState |
264 // The state might have changed from LoadingState |
275 // as a response to an error state change. So we |
265 // as a response to an error state change. So we |
276 // need to check it before stopping: |
266 // need to check it before stopping: |
277 if (m_state == Phonon::LoadingState) |
267 if (m_state == Phonon::LoadingState) |
278 stop(); |
268 stop(); |
295 PhononAutoReleasePool pool; |
285 PhononAutoReleasePool pool; |
296 setState(Phonon::LoadingState); |
286 setState(Phonon::LoadingState); |
297 // Save current state for event/signal handling below: |
287 // Save current state for event/signal handling below: |
298 bool prevHasVideo = m_videoPlayer->hasVideo(); |
288 bool prevHasVideo = m_videoPlayer->hasVideo(); |
299 qint64 prevTotalTime = totalTime(); |
289 qint64 prevTotalTime = totalTime(); |
300 int prevTrackCount = m_videoPlayer->trackCount(); |
|
301 |
290 |
302 qSwap(m_audioPlayer, m_nextAudioPlayer); |
291 qSwap(m_audioPlayer, m_nextAudioPlayer); |
303 qSwap(m_videoPlayer, m_nextVideoPlayer); |
292 qSwap(m_videoPlayer, m_nextVideoPlayer); |
304 m_mediaObjectAudioNode->startCrossFade(transitionTime); |
293 m_mediaObjectAudioNode->startCrossFade(transitionTime); |
305 m_audioGraph->updateStreamSpecifications(); |
294 m_audioGraph->updateStreamSpecifications(); |
|
295 m_metaData->setVideo(m_videoPlayer); |
306 |
296 |
307 m_waitNextSwap = false; |
297 m_waitNextSwap = false; |
308 m_currentTime = 0; |
298 m_currentTime = 0; |
309 |
299 |
310 // Emit/notify information about the new source: |
300 // Emit/notify information about the new source: |
311 QRect videoRect = m_videoPlayer->videoRect(); |
301 QRect videoRect = m_videoPlayer->videoRect(); |
312 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); |
302 MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect); |
313 notify(&e1); |
303 notify(&e1); |
314 |
304 |
315 emit currentSourceChanged(m_videoPlayer->mediaSource()); |
305 emit currentSourceChanged(m_videoPlayer->mediaSource()); |
316 emit metaDataChanged(m_videoPlayer->metaData()); |
306 emit metaDataChanged(m_metaData->metaData()); |
317 |
307 |
318 if (prevHasVideo != m_videoPlayer->hasVideo()) |
308 if (prevHasVideo != m_videoPlayer->hasVideo()) |
319 emit hasVideoChanged(m_videoPlayer->hasVideo()); |
309 emit hasVideoChanged(m_videoPlayer->hasVideo()); |
320 if (prevTotalTime != totalTime()) |
310 if (prevTotalTime != totalTime()) |
321 emit totalTimeChanged(totalTime()); |
311 emit totalTimeChanged(totalTime()); |
322 if (prevTrackCount != m_videoPlayer->trackCount()) |
|
323 emit availableTitlesChanged(m_videoPlayer->trackCount()); |
|
324 if (checkForError()) |
312 if (checkForError()) |
325 return; |
313 return; |
326 if (!m_videoPlayer->isDrmAuthorized()) |
314 if (!m_videoPlayer->isDrmAuthorized()) |
327 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR) |
315 SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR) |
328 if (checkForError()) |
316 if (checkForError()) |
337 play_internal(); |
325 play_internal(); |
338 checkForError(); |
326 checkForError(); |
339 } |
327 } |
340 } |
328 } |
341 |
329 |
342 #if QT_ALLOW_QUICKTIME |
330 void MediaObject::updateTimer(int &timer, int interval) |
343 static CVReturn displayLinkCallback(CVDisplayLinkRef /*displayLink*/, |
331 { |
344 const CVTimeStamp */*inNow*/, |
332 if (timer) |
345 const CVTimeStamp */*inOutputTime*/, |
333 killTimer(timer); |
346 CVOptionFlags /*flagsIn*/, |
334 timer = 0; |
347 CVOptionFlags */*flagsOut*/, |
335 if (interval >= 0) |
348 void *userData) |
336 timer = startTimer(interval); |
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(); |
|
427 } |
337 } |
428 |
338 |
429 void MediaObject::play_internal() |
339 void MediaObject::play_internal() |
430 { |
340 { |
431 // Play main audio/video: |
341 // Play main audio/video: |
432 m_videoPlayer->play(); |
342 m_videoPlayer->play(); |
433 m_audioPlayer->play(); |
343 m_audioPlayer->play(); |
434 updateLipSynch(0); |
344 updateLipSynch(0); |
435 // Play old audio/video to finish cross-fade: |
345 // Play old audio/video to finish cross-fade: |
436 if (m_nextVideoPlayer->currentTime() > 0){ |
346 if (m_nextVideoPlayer->currentTime() > 0){ |
437 m_nextVideoPlayer->play(); |
347 m_nextVideoPlayer->play(); |
438 m_nextAudioPlayer->play(); |
348 m_nextAudioPlayer->play(); |
439 } |
349 } |
440 restartAudioVideoTimers(); |
350 bufferAudioVideo(); |
441 if (!m_rapidTimer) |
351 updateTimer(m_rapidTimer, 100); |
442 m_rapidTimer = startTimer(100); |
|
443 } |
352 } |
444 |
353 |
445 void MediaObject::pause_internal() |
354 void MediaObject::pause_internal() |
446 { |
355 { |
447 m_audioGraph->stop(); |
356 m_audioGraph->stop(); |
448 m_audioPlayer->pause(); |
357 m_audioPlayer->pause(); |
449 m_nextAudioPlayer->pause(); |
358 m_nextAudioPlayer->pause(); |
450 m_videoPlayer->pause(); |
359 m_videoPlayer->pause(); |
451 m_nextVideoPlayer->pause(); |
360 m_nextVideoPlayer->pause(); |
452 killTimer(m_rapidTimer); |
361 updateTimer(m_rapidTimer, -1); |
453 killTimer(m_videoTimer); |
362 updateTimer(m_bufferTimer, -1); |
454 killTimer(m_audioTimer); |
363 |
455 m_rapidTimer = 0; |
|
456 m_videoTimer = 0; |
|
457 m_audioTimer = 0; |
|
458 #if QT_ALLOW_QUICKTIME |
|
459 stopDisplayLink(); |
|
460 #endif |
|
461 if (m_waitNextSwap) |
364 if (m_waitNextSwap) |
462 m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime()); |
365 m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime()); |
463 } |
366 } |
464 |
367 |
465 void MediaObject::play() |
368 void MediaObject::play() |
530 void MediaObject::seek(qint64 milliseconds) |
433 void MediaObject::seek(qint64 milliseconds) |
531 { |
434 { |
532 IMPLEMENTED; |
435 IMPLEMENTED; |
533 if (m_state == Phonon::ErrorState) |
436 if (m_state == Phonon::ErrorState) |
534 return; |
437 return; |
535 |
438 |
536 // Stop cross-fade if any: |
439 // Stop cross-fade if any: |
537 m_nextVideoPlayer->unsetCurrentMediaSource(); |
440 m_nextVideoPlayer->unsetVideo(); |
538 m_nextAudioPlayer->unsetVideoPlayer(); |
441 m_nextAudioPlayer->unsetVideoPlayer(); |
539 m_mediaObjectAudioNode->cancelCrossFade(); |
442 m_mediaObjectAudioNode->cancelCrossFade(); |
540 |
443 |
541 // Seek to new position: |
444 // Seek to new position: |
542 m_mediaObjectAudioNode->setMute(true); |
445 m_mediaObjectAudioNode->setMute(true); |
543 m_videoPlayer->seek(milliseconds); |
446 m_videoPlayer->seek(milliseconds); |
544 m_audioPlayer->seek(m_videoPlayer->currentTime()); |
447 m_audioPlayer->seek(m_videoPlayer->currentTime()); |
545 m_mediaObjectAudioNode->setMute(false); |
448 m_mediaObjectAudioNode->setMute(false); |
546 |
449 |
547 // Update time and cancel pending swap: |
450 // Update time and cancel pending swap: |
548 if (m_currentTime < m_videoPlayer->duration()) |
451 if (m_currentTime < m_videoPlayer->duration()) |
549 m_waitNextSwap = false; |
452 m_waitNextSwap = false; |
550 |
453 |
551 updateCurrentTime(); |
454 updateCurrentTime(); |
652 } |
555 } |
653 |
556 |
654 qint64 MediaObject::currentTime() const |
557 qint64 MediaObject::currentTime() const |
655 { |
558 { |
656 IMPLEMENTED_SILENT; |
559 IMPLEMENTED_SILENT; |
657 const_cast<MediaObject *>(this)->updateCurrentTime(); |
560 const_cast<MediaObject *>(this)->updateCurrentTime(); |
658 return m_currentTime; |
561 return m_currentTime; |
659 } |
562 } |
660 |
563 |
661 void MediaObject::updateCurrentTime() |
564 void MediaObject::updateCurrentTime() |
662 { |
565 { |
663 quint64 lastUpdateTime = m_currentTime; |
566 quint64 lastUpdateTime = m_currentTime; |
664 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); |
567 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); |
665 quint64 total = m_videoPlayer->duration(); |
568 quint64 total = m_videoPlayer->duration(); |
666 |
569 |
667 if (m_videoPlayer->currentTrack() < m_videoPlayer->trackCount() - 1){ |
570 // Check if it's time to emit aboutToFinish: |
668 // There are still more tracks to play after the current track. |
571 quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000)); |
669 if (m_autoplayTitles) { |
572 if (lastUpdateTime < mark && mark <= m_currentTime) |
670 if (lastUpdateTime < m_currentTime && m_currentTime == total) |
573 emit aboutToFinish(); |
671 setCurrentTrack(m_videoPlayer->currentTrack() + 1); |
574 |
672 } |
575 // Check if it's time to emit prefinishMarkReached: |
673 } else if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){ |
576 mark = qMax(quint64(0), total - m_prefinishMark); |
674 // There is no more sources or tracks to play after the current source. |
577 if (lastUpdateTime < mark && mark <= m_currentTime) |
675 // Check if it's time to emit aboutToFinish: |
578 emit prefinishMarkReached(total - m_currentTime); |
676 quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000)); |
579 |
677 if (lastUpdateTime < mark && mark <= m_currentTime) |
580 if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){ |
678 emit aboutToFinish(); |
581 // There is no next source in que. |
679 |
582 // Check if it's time to emit finished: |
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 |
|
685 if (lastUpdateTime < m_currentTime && m_currentTime == total){ |
583 if (lastUpdateTime < m_currentTime && m_currentTime == total){ |
686 emit finished(); |
584 emit finished(); |
687 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); |
585 m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime(); |
688 if (m_state == Phonon::PlayingState && m_currentTime == total) |
586 if (m_state == Phonon::PlayingState && m_currentTime == total) |
689 pause(); |
587 pause(); |
690 } |
588 } |
691 } else { |
589 } else { |
692 // We have a next source. |
590 // We have a next source. |
693 // Check if it's time to swap to next source: |
591 // Check if it's time to swap to next source: |
694 quint32 mark = qMax(quint64(0), total + m_transitionTime); |
592 mark = qMax(quint64(0), total + m_transitionTime); |
695 if (m_waitNextSwap && m_state == Phonon::PlayingState && |
593 if (m_waitNextSwap && m_state == Phonon::PlayingState && |
696 m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){ |
594 m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){ |
697 swapCurrentWithNext(0); |
595 swapCurrentWithNext(0); |
698 } else if (mark >= total){ |
596 } else if (mark >= total){ |
699 if (lastUpdateTime < total && total == m_currentTime){ |
597 if (lastUpdateTime < total && total == m_currentTime){ |
792 return m_videoPlayer->setAudioDevice(id); |
690 return m_videoPlayer->setAudioDevice(id); |
793 } |
691 } |
794 |
692 |
795 void MediaObject::updateCrossFade() |
693 void MediaObject::updateCrossFade() |
796 { |
694 { |
797 m_mediaObjectAudioNode->updateCrossFade(m_currentTime); |
695 m_mediaObjectAudioNode->updateCrossFade(m_currentTime); |
798 // Clean-up previous movie if done fading: |
696 // Clean-up previous movie if done fading: |
799 if (m_mediaObjectAudioNode->m_fadeDuration == 0){ |
697 if (m_mediaObjectAudioNode->m_fadeDuration == 0){ |
800 if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){ |
698 if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){ |
801 m_nextVideoPlayer->unsetCurrentMediaSource(); |
699 m_nextVideoPlayer->unsetVideo(); |
802 m_nextAudioPlayer->unsetVideoPlayer(); |
700 m_nextAudioPlayer->unsetVideoPlayer(); |
803 } |
701 } |
804 } |
702 } |
805 } |
703 } |
806 |
704 |
807 void MediaObject::updateBufferStatus() |
705 void MediaObject::updateBufferStatus() |
808 { |
706 { |
809 float percent = m_videoPlayer->percentageLoaded(); |
707 float percent = m_videoPlayer->percentageLoaded(); |
828 void MediaObject::updateVideoFrames() |
726 void MediaObject::updateVideoFrames() |
829 { |
727 { |
830 // Draw next frame if awailable: |
728 // Draw next frame if awailable: |
831 if (m_videoPlayer->videoFrameChanged()){ |
729 if (m_videoPlayer->videoFrameChanged()){ |
832 updateLipSynch(50); |
730 updateLipSynch(50); |
833 VideoFrame frame(m_videoPlayer); |
731 VideoFrame frame(m_videoPlayer); |
834 if (m_nextVideoPlayer->isPlaying() |
732 if (m_nextVideoPlayer->isPlaying() |
835 && m_nextVideoPlayer->hasVideo() |
733 && m_nextVideoPlayer->hasVideo() |
836 && isCrossFading()){ |
734 && isCrossFading()){ |
837 VideoFrame bgFrame(m_nextVideoPlayer); |
735 VideoFrame bgFrame(m_nextVideoPlayer); |
838 frame.setBackgroundFrame(bgFrame); |
736 frame.setBackgroundFrame(bgFrame); |
839 frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1); |
737 frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1); |
840 } |
738 } |
841 |
739 |
842 // Send the frame through the graph: |
740 // Send the frame through the graph: |
843 updateVideo(frame); |
741 updateVideo(frame); |
844 checkForError(); |
742 checkForError(); |
845 } |
743 } |
846 } |
744 } |
847 |
745 |
848 void MediaObject::updateLipSynch(int allowedOffset) |
746 void MediaObject::updateLipSynch(int allowedOffset) |
849 { |
747 { |
850 if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning()) |
748 if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning()) |
851 return; |
749 return; |
852 if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty()) |
750 if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty()) |
853 return; |
751 return; |
854 |
752 |
855 if (m_videoPlayer->hasVideo()){ |
753 if (m_videoPlayer->hasVideo()){ |
856 qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime(); |
754 qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime(); |
857 if (-allowedOffset > diff || diff > allowedOffset) |
755 if (-allowedOffset > diff || diff > allowedOffset) |
858 m_audioPlayer->seek(m_videoPlayer->currentTime()); |
756 m_audioPlayer->seek(m_videoPlayer->currentTime()); |
859 } |
757 } |
861 if (isCrossFading() && m_nextVideoPlayer->hasVideo()){ |
759 if (isCrossFading() && m_nextVideoPlayer->hasVideo()){ |
862 qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime(); |
760 qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime(); |
863 if (-(allowedOffset*2) > diff || diff > (allowedOffset*2)) |
761 if (-(allowedOffset*2) > diff || diff > (allowedOffset*2)) |
864 m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime()); |
762 m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime()); |
865 } |
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)); |
866 } |
774 } |
867 |
775 |
868 void MediaObject::updateRapidly() |
776 void MediaObject::updateRapidly() |
869 { |
777 { |
870 updateCurrentTime(); |
778 updateCurrentTime(); |
887 inspectGraph(); |
795 inspectGraph(); |
888 setupAudioSystem(); |
796 setupAudioSystem(); |
889 synchAudioVideo(); |
797 synchAudioVideo(); |
890 checkForError(); |
798 checkForError(); |
891 m_mediaObjectAudioNode->setMute(false); |
799 m_mediaObjectAudioNode->setMute(false); |
892 if (m_state == Phonon::PlayingState) |
800 if (m_state == Phonon::PlayingState) |
893 restartAudioVideoTimers(); |
801 bufferAudioVideo(); |
894 break; |
802 break; |
895 case MediaNodeEvent::AudioGraphCannotPlay: |
803 case MediaNodeEvent::AudioGraphCannotPlay: |
896 case MediaNodeEvent::AudioGraphInitialized: |
804 case MediaNodeEvent::AudioGraphInitialized: |
897 if (m_state != Phonon::LoadingState){ |
805 if (m_state != Phonon::LoadingState){ |
898 m_mediaObjectAudioNode->setMute(true); |
806 m_mediaObjectAudioNode->setMute(true); |
899 setupAudioSystem(); |
807 setupAudioSystem(); |
900 updateLipSynch(0); |
808 updateLipSynch(0); |
901 checkForError(); |
809 checkForError(); |
902 m_mediaObjectAudioNode->setMute(false); |
810 m_mediaObjectAudioNode->setMute(false); |
903 } |
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 } |
904 break; |
830 break; |
905 default: |
831 default: |
906 break; |
832 break; |
907 } |
833 } |
908 } |
|
909 |
|
910 bool MediaObject::event(QEvent *event) |
|
911 { |
|
912 switch (event->type()){ |
|
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) |
|
924 updateRapidly(); |
|
925 else if (timerId == m_tickTimer) |
|
926 emit tick(currentTime()); |
|
927 else if (timerId == m_videoTimer) |
|
928 updateVideoFrames(); |
|
929 else if (timerId == m_audioTimer) |
|
930 updateAudioBuffers(); |
|
931 break; } |
|
932 default: |
|
933 break; |
|
934 } |
|
935 return QObject::event(event); |
834 return QObject::event(event); |
936 } |
835 } |
937 |
836 |
938 void MediaObject::setCurrentTrack(int track) |
837 bool MediaObject::hasInterface(Interface /*interface*/) const |
939 { |
838 { |
940 if (track == m_videoPlayer->currentTrack() || track < 0 || track >= m_videoPlayer->trackCount()) |
839 return false; |
941 return; |
840 } |
942 |
841 |
943 m_videoPlayer->setCurrentTrack(track); |
842 QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/) |
944 emit titleChanged(track); |
843 { |
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> ¶ms) |
|
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 } |
|
974 return QVariant(); |
844 return QVariant(); |
975 } |
845 } |
976 |
846 |
977 }} // namespace Phonon::QT7 |
847 }} // namespace Phonon::QT7 |
978 |
848 |