18 #include "quicktimevideoplayer.h" |
18 #include "quicktimevideoplayer.h" |
19 #include "mediaobject.h" |
19 #include "mediaobject.h" |
20 #include "videowidget.h" |
20 #include "videowidget.h" |
21 #include "audiodevice.h" |
21 #include "audiodevice.h" |
22 #include "quicktimestreamreader.h" |
22 #include "quicktimestreamreader.h" |
23 #include "quicktimemetadata.h" |
|
24 |
23 |
25 #include <QtCore/QCoreApplication> |
24 #include <QtCore/QCoreApplication> |
26 #include <QtCore/QEventLoop> |
25 #include <QtCore/QEventLoop> |
27 #include <QtCore/QFileInfo> |
26 #include <QtCore/QFileInfo> |
28 #include <QtCore/QUrl> |
27 #include <QtCore/QUrl> |
51 |
50 |
52 QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0) |
51 QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0) |
53 { |
52 { |
54 m_state = NoMedia; |
53 m_state = NoMedia; |
55 m_mediaSource = MediaSource(); |
54 m_mediaSource = MediaSource(); |
56 m_metaData = new QuickTimeMetaData(this); |
|
57 m_QTMovie = 0; |
55 m_QTMovie = 0; |
58 m_streamReader = 0; |
56 m_streamReader = 0; |
59 m_playbackRate = 1.0f; |
57 m_playbackRate = 1.0f; |
60 m_masterVolume = 1.0f; |
58 m_masterVolume = 1.0f; |
61 m_relativeVolume = 1.0f; |
59 m_relativeVolume = 1.0f; |
62 m_currentTime = 0; |
60 m_currentTime = 0; |
63 m_mute = false; |
61 m_mute = false; |
64 m_audioEnabled = false; |
62 m_audioEnabled = false; |
65 m_hasVideo = false; |
63 m_hasVideo = false; |
66 m_staticFps = 0; |
|
67 m_playbackRateSat = false; |
64 m_playbackRateSat = false; |
68 m_isDrmProtected = false; |
65 m_isDrmProtected = false; |
69 m_isDrmAuthorized = true; |
66 m_isDrmAuthorized = true; |
70 m_primaryRenderingTarget = 0; |
67 m_primaryRenderingTarget = 0; |
71 m_primaryRenderingCIImage = 0; |
68 m_primaryRenderingCIImage = 0; |
72 m_QImagePixelBuffer = 0; |
69 m_QImagePixelBuffer = 0; |
73 m_cachedCVTextureRef = 0; |
|
74 m_folderTracks = 0; |
|
75 m_currentTrack = 0; |
|
76 |
70 |
77 #ifdef QUICKTIME_C_API_AVAILABLE |
71 #ifdef QUICKTIME_C_API_AVAILABLE |
78 OSStatus err = EnterMovies(); |
72 OSStatus err = EnterMovies(); |
79 BACKEND_ASSERT2(err == noErr, "Could not initialize QuickTime", FATAL_ERROR) |
73 BACKEND_ASSERT2(err == noErr, "Could not initialize QuickTime", FATAL_ERROR) |
80 createVisualContext(); |
74 createVisualContext(); |
81 #endif |
75 #endif |
82 } |
76 } |
83 |
77 |
84 QuickTimeVideoPlayer::~QuickTimeVideoPlayer() |
78 QuickTimeVideoPlayer::~QuickTimeVideoPlayer() |
85 { |
79 { |
86 PhononAutoReleasePool pool; |
80 unsetVideo(); |
87 unsetCurrentMediaSource(); |
|
88 delete m_metaData; |
|
89 [(NSObject*)m_primaryRenderingTarget release]; |
81 [(NSObject*)m_primaryRenderingTarget release]; |
90 m_primaryRenderingTarget = 0; |
82 m_primaryRenderingTarget = 0; |
91 #ifdef QUICKTIME_C_API_AVAILABLE |
83 #ifdef QUICKTIME_C_API_AVAILABLE |
92 if (m_visualContext) |
84 if (m_visualContext) |
93 CFRelease(m_visualContext); |
85 CFRelease(m_visualContext); |
94 #endif |
86 #endif |
95 } |
|
96 |
|
97 void QuickTimeVideoPlayer::releaseImageCache() |
|
98 { |
|
99 if (m_cachedCVTextureRef){ |
|
100 CVOpenGLTextureRelease(m_cachedCVTextureRef); |
|
101 m_cachedCVTextureRef = 0; |
|
102 } |
|
103 m_cachedQImage = QImage(); |
|
104 } |
87 } |
105 |
88 |
106 void QuickTimeVideoPlayer::createVisualContext() |
89 void QuickTimeVideoPlayer::createVisualContext() |
107 { |
90 { |
108 #ifdef QUICKTIME_C_API_AVAILABLE |
91 #ifdef QUICKTIME_C_API_AVAILABLE |
158 CVOpenGLTextureRef QuickTimeVideoPlayer::currentFrameAsCVTexture() |
138 CVOpenGLTextureRef QuickTimeVideoPlayer::currentFrameAsCVTexture() |
159 { |
139 { |
160 #ifdef QUICKTIME_C_API_AVAILABLE |
140 #ifdef QUICKTIME_C_API_AVAILABLE |
161 if (!m_visualContext) |
141 if (!m_visualContext) |
162 return 0; |
142 return 0; |
163 if (!m_cachedCVTextureRef){ |
143 CVOpenGLTextureRef texture = 0; |
164 OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &m_cachedCVTextureRef); |
144 OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &texture); |
165 BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0) |
145 BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0) |
166 } |
146 return texture; |
167 return m_cachedCVTextureRef; |
|
168 |
147 |
169 #else |
148 #else |
170 return 0; |
149 return 0; |
171 #endif |
150 #endif |
172 } |
151 } |
173 |
152 |
174 QImage QuickTimeVideoPlayer::currentFrameAsQImage() |
153 QImage QuickTimeVideoPlayer::currentFrameAsQImage() |
175 { |
154 { |
176 if (!m_cachedQImage.isNull()) |
|
177 return m_cachedQImage; |
|
178 |
|
179 #ifdef QUICKTIME_C_API_AVAILABLE |
155 #ifdef QUICKTIME_C_API_AVAILABLE |
180 QGLContext *prevContext = const_cast<QGLContext *>(QGLContext::currentContext()); |
156 QGLContext *prevContext = const_cast<QGLContext *>(QGLContext::currentContext()); |
181 CVOpenGLTextureRef texture = currentFrameAsCVTexture(); |
157 CVOpenGLTextureRef texture = currentFrameAsCVTexture(); |
182 GLenum target = CVOpenGLTextureGetTarget(texture); |
158 GLenum target = CVOpenGLTextureGetTarget(texture); |
183 GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2]; |
159 GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2]; |
203 glVertex2i(1, -1); |
179 glVertex2i(1, -1); |
204 glTexCoord2f(upperLeft[0], upperLeft[1]); |
180 glTexCoord2f(upperLeft[0], upperLeft[1]); |
205 glVertex2i(-1, -1); |
181 glVertex2i(-1, -1); |
206 glEnd(); |
182 glEnd(); |
207 |
183 |
208 m_cachedQImage = m_QImagePixelBuffer->toImage(); |
184 QImage image = m_QImagePixelBuffer->toImage(); |
|
185 CVOpenGLTextureRelease(texture); |
209 // Because of QuickTime, m_QImagePixelBuffer->doneCurrent() will fail. |
186 // Because of QuickTime, m_QImagePixelBuffer->doneCurrent() will fail. |
210 // So we store, and restore, the context our selves: |
187 // So we store, and restore, the context our selves: |
211 prevContext->makeCurrent(); |
188 prevContext->makeCurrent(); |
212 return m_cachedQImage; |
189 return image; |
213 #else |
190 #else |
214 CIImage *img = (CIImage *)currentFrameAsCIImage(); |
191 CIImage *img = (CIImage *)currentFrameAsCIImage(); |
215 if (!img) |
192 if (!img) |
216 return QImage(); |
193 return QImage(); |
217 |
194 |
218 NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; |
195 NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img]; |
219 CGRect bounds = [img extent]; |
196 CGRect bounds = [img extent]; |
220 QImage qImg([bitmap bitmapData], bounds.size.width, bounds.size.height, QImage::Format_ARGB32); |
197 QImage qImg([bitmap bitmapData], bounds.size.width, bounds.size.height, QImage::Format_ARGB32); |
221 m_cachedQImage = qImg.rgbSwapped(); |
198 QImage swapped = qImg.rgbSwapped(); |
222 [bitmap release]; |
199 [bitmap release]; |
223 [img release]; |
200 [img release]; |
224 return m_cachedQImage; |
201 return swapped; |
225 #endif |
202 #endif |
226 } |
203 } |
227 |
204 |
228 void QuickTimeVideoPlayer::setPrimaryRenderingCIImage(void *ciImage) |
205 void QuickTimeVideoPlayer::setPrimaryRenderingCIImage(void *ciImage) |
229 { |
206 { |
293 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texName); |
271 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texName); |
294 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
272 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
295 |
273 |
296 int samplesPerPixel = [bitmap samplesPerPixel]; |
274 int samplesPerPixel = [bitmap samplesPerPixel]; |
297 if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)){ |
275 if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)){ |
298 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, |
276 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, |
299 samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8, |
277 samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8, |
300 [bitmap pixelsWide], [bitmap pixelsHigh], |
278 [bitmap pixelsWide], [bitmap pixelsHigh], |
301 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB, |
279 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB, |
302 GL_UNSIGNED_BYTE, [bitmap bitmapData]); |
280 GL_UNSIGNED_BYTE, [bitmap bitmapData]); |
303 } else { |
281 } else { |
322 void QuickTimeVideoPlayer::setVolume(float masterVolume, float relativeVolume) |
300 void QuickTimeVideoPlayer::setVolume(float masterVolume, float relativeVolume) |
323 { |
301 { |
324 m_masterVolume = masterVolume; |
302 m_masterVolume = masterVolume; |
325 m_relativeVolume = relativeVolume; |
303 m_relativeVolume = relativeVolume; |
326 if (!m_QTMovie || !m_audioEnabled || m_mute) |
304 if (!m_QTMovie || !m_audioEnabled || m_mute) |
327 return; |
305 return; |
328 [m_QTMovie setVolume:(m_masterVolume * m_relativeVolume)]; |
306 [m_QTMovie setVolume:(m_masterVolume * m_relativeVolume)]; |
329 } |
307 } |
330 |
308 |
331 void QuickTimeVideoPlayer::setMute(bool mute) |
309 void QuickTimeVideoPlayer::setMute(bool mute) |
332 { |
310 { |
333 m_mute = mute; |
311 m_mute = mute; |
334 if (!m_QTMovie || m_state != Playing || !m_audioEnabled) |
312 if (!m_QTMovie || m_state != Playing || !m_audioEnabled) |
335 return; |
313 return; |
336 |
314 |
337 // Work-around bug that happends if you set/unset mute |
315 // Work-around bug that happends if you set/unset mute |
338 // before movie is playing, and audio is not played |
316 // before movie is playing, and audio is not played |
339 // through graph. Then audio is delayed. |
317 // through graph. Then audio is delayed. |
340 [m_QTMovie setMuted:mute]; |
318 [m_QTMovie setMuted:mute]; |
341 [m_QTMovie setVolume:(mute ? 0 : m_masterVolume * m_relativeVolume)]; |
319 [m_QTMovie setVolume:(mute ? 0 : m_masterVolume * m_relativeVolume)]; |
342 } |
320 } |
343 |
321 |
346 m_audioEnabled = enable; |
324 m_audioEnabled = enable; |
347 if (!m_QTMovie || m_state != Playing) |
325 if (!m_QTMovie || m_state != Playing) |
348 return; |
326 return; |
349 |
327 |
350 // Work-around bug that happends if you set/unset mute |
328 // Work-around bug that happends if you set/unset mute |
351 // before movie is playing, and audio is not played |
329 // before movie is playing, and audio is not played |
352 // through graph. Then audio is delayed. |
330 // through graph. Then audio is delayed. |
353 [m_QTMovie setMuted:(!enable || m_mute)]; |
331 [m_QTMovie setMuted:(!enable || m_mute)]; |
354 [m_QTMovie setVolume:((!enable || m_mute) ? 0 : m_masterVolume * m_relativeVolume)]; |
332 [m_QTMovie setVolume:((!enable || m_mute) ? 0 : m_masterVolume * m_relativeVolume)]; |
355 } |
333 } |
356 |
334 |
365 return false; |
343 return false; |
366 |
344 |
367 #ifdef QUICKTIME_C_API_AVAILABLE |
345 #ifdef QUICKTIME_C_API_AVAILABLE |
368 // The following code will not work for some media codecs that |
346 // The following code will not work for some media codecs that |
369 // typically mingle audio/video frames (e.g mpeg). |
347 // typically mingle audio/video frames (e.g mpeg). |
370 CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id)); |
348 CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id)); |
371 QTAudioContextRef context; |
349 QTAudioContextRef context; |
372 QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, idString, 0, &context); |
350 QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, idString, 0, &context); |
373 OSStatus err = SetMovieAudioContext([m_QTMovie quickTimeMovie], context); |
351 OSStatus err = SetMovieAudioContext([m_QTMovie quickTimeMovie], context); |
374 CFRelease(context); |
352 CFRelease(context); |
375 if (err != noErr) |
353 if (err != noErr) |
389 // 0 is default value for the colors |
367 // 0 is default value for the colors |
390 // in phonon, so adjust scale: |
368 // in phonon, so adjust scale: |
391 contrast += 1; |
369 contrast += 1; |
392 saturation += 1; |
370 saturation += 1; |
393 |
371 |
394 if (m_brightness == brightness |
|
395 && m_contrast == contrast |
|
396 && m_hue == hue |
|
397 && m_saturation == saturation) |
|
398 return; |
|
399 |
|
400 m_brightness = brightness; |
372 m_brightness = brightness; |
401 m_contrast = contrast; |
373 m_contrast = contrast; |
402 m_hue = hue; |
374 m_hue = hue; |
403 m_saturation = saturation; |
375 m_saturation = saturation; |
|
376 |
404 #ifdef QUICKTIME_C_API_AVAILABLE |
377 #ifdef QUICKTIME_C_API_AVAILABLE |
405 Float32 value; |
378 Float32 value; |
406 value = brightness; |
379 value = brightness; |
407 SetMovieVisualBrightness([m_QTMovie quickTimeMovie], value, 0); |
380 SetMovieVisualBrightness([m_QTMovie quickTimeMovie], value, 0); |
408 value = contrast; |
381 value = contrast; |
436 m_streamReader = 0; |
408 m_streamReader = 0; |
437 m_currentTime = 0; |
409 m_currentTime = 0; |
438 m_state = NoMedia; |
410 m_state = NoMedia; |
439 m_isDrmProtected = false; |
411 m_isDrmProtected = false; |
440 m_isDrmAuthorized = true; |
412 m_isDrmAuthorized = true; |
441 m_hasVideo = false; |
|
442 m_staticFps = 0; |
|
443 m_mediaSource = MediaSource(); |
413 m_mediaSource = MediaSource(); |
444 m_movieCompactDiscPath.clear(); |
|
445 [(CIImage *)m_primaryRenderingCIImage release]; |
414 [(CIImage *)m_primaryRenderingCIImage release]; |
446 m_primaryRenderingCIImage = 0; |
415 m_primaryRenderingCIImage = 0; |
447 delete m_QImagePixelBuffer; |
416 delete m_QImagePixelBuffer; |
448 m_QImagePixelBuffer = 0; |
417 m_QImagePixelBuffer = 0; |
449 releaseImageCache(); |
|
450 [m_folderTracks release]; |
|
451 m_folderTracks = 0; |
|
452 } |
418 } |
453 |
419 |
454 QuickTimeVideoPlayer::State QuickTimeVideoPlayer::state() const |
420 QuickTimeVideoPlayer::State QuickTimeVideoPlayer::state() const |
455 { |
421 { |
456 return m_state; |
422 return m_state; |
556 } |
522 } |
557 |
523 |
558 void QuickTimeVideoPlayer::setMediaSource(const MediaSource &mediaSource) |
524 void QuickTimeVideoPlayer::setMediaSource(const MediaSource &mediaSource) |
559 { |
525 { |
560 PhononAutoReleasePool pool; |
526 PhononAutoReleasePool pool; |
561 unsetCurrentMediaSource(); |
527 unsetVideo(); |
562 |
|
563 m_mediaSource = mediaSource; |
528 m_mediaSource = mediaSource; |
564 if (mediaSource.type() == MediaSource::Empty || mediaSource.type() == MediaSource::Invalid){ |
529 if (mediaSource.type() == MediaSource::Empty || mediaSource.type() == MediaSource::Invalid){ |
565 m_state = NoMedia; |
530 m_state = NoMedia; |
566 return; |
531 return; |
567 } |
532 } |
568 |
|
569 openMovieFromCurrentMediaSource(); |
533 openMovieFromCurrentMediaSource(); |
570 if (errorOccured()){ |
534 if (errorOccured()){ |
571 unsetCurrentMediaSource(); |
535 unsetVideo(); |
572 return; |
536 return; |
573 } |
537 } |
574 |
538 |
575 prepareCurrentMovieForPlayback(); |
|
576 } |
|
577 |
|
578 void QuickTimeVideoPlayer::prepareCurrentMovieForPlayback() |
|
579 { |
|
580 #ifdef QUICKTIME_C_API_AVAILABLE |
539 #ifdef QUICKTIME_C_API_AVAILABLE |
581 if (m_visualContext) |
540 if (m_visualContext) |
582 SetMovieVisualContext([m_QTMovie quickTimeMovie], m_visualContext); |
541 SetMovieVisualContext([m_QTMovie quickTimeMovie], m_visualContext); |
583 #endif |
542 #endif |
584 |
543 |
585 waitStatePlayable(); |
544 waitStatePlayable(); |
586 if (errorOccured()){ |
545 if (errorOccured()){ |
587 unsetCurrentMediaSource(); |
546 unsetVideo(); |
588 return; |
547 return; |
589 } |
548 } |
590 |
549 |
591 readProtection(); |
550 readProtection(); |
592 preRollMovie(); |
551 preRollMovie(); |
593 if (errorOccured()){ |
552 if (errorOccured()){ |
594 unsetCurrentMediaSource(); |
553 unsetVideo(); |
595 return; |
554 return; |
596 } |
555 } |
597 |
556 |
598 if (!m_playbackRateSat) |
557 if (!m_playbackRateSat) |
599 m_playbackRate = prefferedPlaybackRate(); |
558 m_playbackRate = prefferedPlaybackRate(); |
600 checkIfVideoAwailable(); |
559 checkIfVideoAwailable(); |
601 calculateStaticFps(); |
|
602 enableAudio(m_audioEnabled); |
560 enableAudio(m_audioEnabled); |
603 setMute(m_mute); |
561 setMute(m_mute); |
604 setVolume(m_masterVolume, m_relativeVolume); |
562 setVolume(m_masterVolume, m_relativeVolume); |
605 m_metaData->update(); |
|
606 pause(); |
563 pause(); |
607 } |
564 } |
608 |
565 |
609 void QuickTimeVideoPlayer::openMovieFromCurrentMediaSource() |
566 void QuickTimeVideoPlayer::openMovieFromCurrentMediaSource() |
610 { |
567 { |
614 break; |
571 break; |
615 case MediaSource::Url: |
572 case MediaSource::Url: |
616 openMovieFromUrl(); |
573 openMovieFromUrl(); |
617 break; |
574 break; |
618 case MediaSource::Disc: |
575 case MediaSource::Disc: |
619 openMovieFromCompactDisc(); |
576 CASE_UNSUPPORTED("Could not open media source.", FATAL_ERROR) |
620 break; |
577 break; |
621 case MediaSource::Stream: |
578 case MediaSource::Stream: |
622 openMovieFromStream(); |
579 openMovieFromStream(); |
623 break; |
580 break; |
624 case MediaSource::Empty: |
581 case MediaSource::Empty: |
676 { |
633 { |
677 // It turns out to be better to just try the standard file types rather |
634 // It turns out to be better to just try the standard file types rather |
678 // than using e.g [QTMovie movieFileTypes:QTIncludeCommonTypes]. Some |
635 // than using e.g [QTMovie movieFileTypes:QTIncludeCommonTypes]. Some |
679 // codecs *think* they can decode the stream, and crash... |
636 // codecs *think* they can decode the stream, and crash... |
680 #define TryOpenMovieWithCodec(type) gClearError(); \ |
637 #define TryOpenMovieWithCodec(type) gClearError(); \ |
681 openMovieFromData(data, (char *)"."type); \ |
638 openMovieFromData(data, "."type); \ |
682 if (m_QTMovie) return; |
639 if (m_QTMovie) return; |
683 |
640 |
684 TryOpenMovieWithCodec("avi"); |
641 TryOpenMovieWithCodec("avi"); |
685 TryOpenMovieWithCodec("mp4"); |
642 TryOpenMovieWithCodec("mp4"); |
686 TryOpenMovieWithCodec("m4p"); |
643 TryOpenMovieWithCodec("m4p"); |
716 if (!m_streamReader->readAllData()) |
673 if (!m_streamReader->readAllData()) |
717 return; |
674 return; |
718 openMovieFromDataGuessType(m_streamReader->pointerToData()); |
675 openMovieFromDataGuessType(m_streamReader->pointerToData()); |
719 } |
676 } |
720 |
677 |
721 typedef void (*qt_sighandler_t)(int); |
|
722 static void sigtest(int) { |
|
723 qApp->exit(0); |
|
724 } |
|
725 |
|
726 void QuickTimeVideoPlayer::openMovieFromCompactDisc() |
|
727 { |
|
728 // Interrupting the application while the device is open |
|
729 // causes the application to hang. So we need to handle |
|
730 // this in a more graceful way: |
|
731 qt_sighandler_t hndl = signal(SIGINT, sigtest); |
|
732 if (hndl) |
|
733 signal(SIGINT, hndl); |
|
734 |
|
735 PhononAutoReleasePool pool; |
|
736 NSString *cd = 0; |
|
737 QString devName = m_mediaSource.deviceName(); |
|
738 if (devName.isEmpty()) { |
|
739 cd = pathToCompactDisc(); |
|
740 if (!cd) { |
|
741 SET_ERROR("Could not open media source.", NORMAL_ERROR) |
|
742 return; |
|
743 } |
|
744 m_movieCompactDiscPath = PhononCFString::toQString(reinterpret_cast<CFStringRef>(cd)); |
|
745 } else { |
|
746 if (!QFileInfo(devName).isAbsolute()) |
|
747 devName = QLatin1String("/Volumes/") + devName; |
|
748 cd = [reinterpret_cast<const NSString *>(PhononCFString::toCFStringRef(devName)) autorelease]; |
|
749 if (!isCompactDisc(cd)) { |
|
750 SET_ERROR("Could not open media source.", NORMAL_ERROR) |
|
751 return; |
|
752 } |
|
753 m_movieCompactDiscPath = devName; |
|
754 } |
|
755 |
|
756 m_folderTracks = [scanFolder(cd) retain]; |
|
757 setCurrentTrack(0); |
|
758 } |
|
759 |
|
760 QString QuickTimeVideoPlayer::movieCompactDiscPath() const |
|
761 { |
|
762 return m_movieCompactDiscPath; |
|
763 } |
|
764 |
|
765 MediaSource QuickTimeVideoPlayer::mediaSource() const |
678 MediaSource QuickTimeVideoPlayer::mediaSource() const |
766 { |
679 { |
767 return m_mediaSource; |
680 return m_mediaSource; |
768 } |
681 } |
769 |
682 |
803 if (!m_QTMovie) |
716 if (!m_QTMovie) |
804 return 0; |
717 return 0; |
805 |
718 |
806 PhononAutoReleasePool pool; |
719 PhononAutoReleasePool pool; |
807 return [[m_QTMovie attributeForKey:@"QTMovieTimeScaleAttribute"] longValue]; |
720 return [[m_QTMovie attributeForKey:@"QTMovieTimeScaleAttribute"] longValue]; |
808 } |
|
809 |
|
810 float QuickTimeVideoPlayer::staticFps() |
|
811 { |
|
812 return m_staticFps; |
|
813 } |
|
814 |
|
815 void QuickTimeVideoPlayer::calculateStaticFps() |
|
816 { |
|
817 if (!m_hasVideo){ |
|
818 m_staticFps = 0; |
|
819 return; |
|
820 } |
|
821 |
|
822 #ifdef QT_ALLOW_QUICKTIME |
|
823 Boolean isMpeg = false; |
|
824 Track videoTrack = GetMovieIndTrackType([m_QTMovie quickTimeMovie], 1, |
|
825 FOUR_CHAR_CODE('vfrr'), // 'vfrr' means: has frame rate |
|
826 movieTrackCharacteristic | movieTrackEnabledOnly); |
|
827 Media media = GetTrackMedia(videoTrack); |
|
828 MediaHandler mediaH = GetMediaHandler(media); |
|
829 MediaHasCharacteristic(mediaH, FOUR_CHAR_CODE('mpeg'), &isMpeg); |
|
830 |
|
831 if (isMpeg){ |
|
832 MHInfoEncodedFrameRateRecord frameRate; |
|
833 Size frameRateSize = sizeof(frameRate); |
|
834 MediaGetPublicInfo(mediaH, kMHInfoEncodedFrameRate, &frameRate, &frameRateSize); |
|
835 m_staticFps = float(Fix2X(frameRate.encodedFrameRate)); |
|
836 } else { |
|
837 Media media = GetTrackMedia(videoTrack); |
|
838 long sampleCount = GetMediaSampleCount(media); |
|
839 TimeValue64 duration = GetMediaDisplayDuration(media); |
|
840 TimeValue64 timeScale = GetMediaTimeScale(media); |
|
841 m_staticFps = float((double)sampleCount * (double)timeScale / (double)duration); |
|
842 } |
|
843 #else |
|
844 m_staticFps = 30.0f; |
|
845 #endif |
|
846 } |
721 } |
847 |
722 |
848 QString QuickTimeVideoPlayer::timeToString(quint64 ms) |
723 QString QuickTimeVideoPlayer::timeToString(quint64 ms) |
849 { |
724 { |
850 int sec = ms/1000; |
725 int sec = ms/1000; |
1073 if (!isDrmAuthorized) |
948 if (!isDrmAuthorized) |
1074 m_isDrmAuthorized = false; |
949 m_isDrmAuthorized = false; |
1075 } |
950 } |
1076 } |
951 } |
1077 |
952 |
1078 QMultiMap<QString, QString> QuickTimeVideoPlayer::metaData() |
|
1079 { |
|
1080 return m_metaData->metaData(); |
|
1081 } |
|
1082 |
|
1083 int QuickTimeVideoPlayer::trackCount() const |
|
1084 { |
|
1085 if (!m_folderTracks) |
|
1086 return 0; |
|
1087 return [m_folderTracks count]; |
|
1088 } |
|
1089 |
|
1090 int QuickTimeVideoPlayer::currentTrack() const |
|
1091 { |
|
1092 return m_currentTrack; |
|
1093 } |
|
1094 |
|
1095 QString QuickTimeVideoPlayer::currentTrackPath() const |
|
1096 { |
|
1097 if (!m_folderTracks) |
|
1098 return QString(); |
|
1099 |
|
1100 PhononAutoReleasePool pool; |
|
1101 NSString *trackPath = [m_folderTracks objectAtIndex:m_currentTrack]; |
|
1102 return PhononCFString::toQString(reinterpret_cast<CFStringRef>(trackPath)); |
|
1103 } |
|
1104 |
|
1105 NSString* QuickTimeVideoPlayer::pathToCompactDisc() |
|
1106 { |
|
1107 PhononAutoReleasePool pool; |
|
1108 NSArray *devices = [[NSWorkspace sharedWorkspace] mountedRemovableMedia]; |
|
1109 for (unsigned int i=0; i<[devices count]; ++i) { |
|
1110 NSString *dev = [devices objectAtIndex:i]; |
|
1111 if (isCompactDisc(dev)) |
|
1112 return [dev retain]; |
|
1113 } |
|
1114 return 0; |
|
1115 } |
|
1116 |
|
1117 bool QuickTimeVideoPlayer::isCompactDisc(NSString *path) |
|
1118 { |
|
1119 PhononAutoReleasePool pool; |
|
1120 NSString *type = [NSString string]; |
|
1121 [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:path |
|
1122 isRemovable:0 |
|
1123 isWritable:0 |
|
1124 isUnmountable:0 |
|
1125 description:0 |
|
1126 type:&type]; |
|
1127 return [type hasPrefix:@"cdd"]; |
|
1128 } |
|
1129 |
|
1130 NSArray* QuickTimeVideoPlayer::scanFolder(NSString *path) |
|
1131 { |
|
1132 NSMutableArray *tracks = [NSMutableArray arrayWithCapacity:20]; |
|
1133 if (!path) |
|
1134 return tracks; |
|
1135 |
|
1136 NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:path]; |
|
1137 while (NSString *track = [enumerator nextObject]) { |
|
1138 if (![track hasPrefix:@"."]) |
|
1139 [tracks addObject:[path stringByAppendingPathComponent:track]]; |
|
1140 } |
|
1141 return tracks; |
|
1142 } |
|
1143 |
|
1144 void QuickTimeVideoPlayer::setCurrentTrack(int track) |
|
1145 { |
|
1146 PhononAutoReleasePool pool; |
|
1147 [m_QTMovie release]; |
|
1148 m_QTMovie = 0; |
|
1149 m_currentTime = 0; |
|
1150 m_currentTrack = track; |
|
1151 |
|
1152 if (!m_folderTracks) |
|
1153 return; |
|
1154 if (track < 0 || track >= (int)[m_folderTracks count]) |
|
1155 return; |
|
1156 |
|
1157 NSString *trackPath = [m_folderTracks objectAtIndex:track]; |
|
1158 QTDataReference *dataRef = [QTDataReference dataReferenceWithReferenceToFile:trackPath]; |
|
1159 State currentState = m_state; |
|
1160 openMovieFromDataRef(dataRef); |
|
1161 prepareCurrentMovieForPlayback(); |
|
1162 if (currentState == Playing) |
|
1163 play(); |
|
1164 } |
|
1165 |
|
1166 }} |
953 }} |
1167 |
954 |
1168 QT_END_NAMESPACE |
955 QT_END_NAMESPACE |