src/3rdparty/phonon/qt7/quicktimevideoplayer.mm
changeset 30 5dc02b23752f
parent 0 1918ee327afb
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    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
   140 		return true;
   123 		return true;
   141     if (!m_visualContext)
   124     if (!m_visualContext)
   142 		return false;
   125 		return false;
   143 
   126 
   144     QTVisualContextTask(m_visualContext);
   127     QTVisualContextTask(m_visualContext);
   145     bool changed = QTVisualContextIsNewImageAvailable(m_visualContext, 0);
   128     return QTVisualContextIsNewImageAvailable(m_visualContext, 0);
   146     if (changed)
       
   147         releaseImageCache();
       
   148     return changed;
       
   149 
   129 
   150 #elif defined(QT_MAC_USE_COCOA)
   130 #elif defined(QT_MAC_USE_COCOA)
   151     return true;
   131     return true;
   152 
   132 
   153 #else
   133 #else
   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 {
   271 #endif
   248 #endif
   272 
   249 
   273 #ifdef QUICKTIME_C_API_AVAILABLE
   250 #ifdef QUICKTIME_C_API_AVAILABLE
   274 	CVOpenGLTextureRef cvImg = currentFrameAsCVTexture();
   251 	CVOpenGLTextureRef cvImg = currentFrameAsCVTexture();
   275 	CIImage *img = [[CIImage alloc] initWithCVImageBuffer:cvImg];
   252 	CIImage *img = [[CIImage alloc] initWithCVImageBuffer:cvImg];
   276 	return img;
   253 	CVOpenGLTextureRelease(cvImg);
       
   254 	return img;	
   277 #else
   255 #else
   278 	return 0;
   256 	return 0;
   279 #endif
   257 #endif
   280 }
   258 }
   281 
   259 
   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;
   410     value = hue;
   383     value = hue;
   411     SetMovieVisualHue([m_QTMovie quickTimeMovie], value, 0);
   384     SetMovieVisualHue([m_QTMovie quickTimeMovie], value, 0);
   412     value = saturation;
   385     value = saturation;
   413     SetMovieVisualSaturation([m_QTMovie quickTimeMovie], value, 0);
   386     SetMovieVisualSaturation([m_QTMovie quickTimeMovie], value, 0);
   414 #endif
   387 #endif
   415     releaseImageCache();
       
   416 }
   388 }
   417 
   389 
   418 QRect QuickTimeVideoPlayer::videoRect() const
   390 QRect QuickTimeVideoPlayer::videoRect() const
   419 {
   391 {
   420     if (!m_QTMovie)
   392     if (!m_QTMovie)
   423 	PhononAutoReleasePool pool;
   395 	PhononAutoReleasePool pool;
   424     NSSize size = [[m_QTMovie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue];
   396     NSSize size = [[m_QTMovie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue];
   425     return QRect(0, 0, size.width, size.height);
   397     return QRect(0, 0, size.width, size.height);
   426 }
   398 }
   427 
   399 
   428 void QuickTimeVideoPlayer::unsetCurrentMediaSource()
   400 void QuickTimeVideoPlayer::unsetVideo()
   429 {
   401 {
   430     if (!m_QTMovie)
   402     if (!m_QTMovie)
   431         return;
   403         return;
   432 
   404 
   433     [m_QTMovie release];
   405     [m_QTMovie release];
   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