Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm

    r2 r561  
    2121#include "audiodevice.h"
    2222#include "quicktimestreamreader.h"
     23#include "quicktimemetadata.h"
    2324
    2425#include <QtCore/QCoreApplication>
     
    5354    m_state = NoMedia;
    5455    m_mediaSource = MediaSource();
     56    m_metaData = new QuickTimeMetaData(this);
    5557    m_QTMovie = 0;
    5658    m_streamReader = 0;
     
    6264    m_audioEnabled = false;
    6365    m_hasVideo = false;
     66    m_staticFps = 0;
    6467    m_playbackRateSat = false;
    6568    m_isDrmProtected = false;
     
    6871        m_primaryRenderingCIImage = 0;
    6972    m_QImagePixelBuffer = 0;
     73    m_cachedCVTextureRef = 0;
     74    m_folderTracks = 0;
     75    m_currentTrack = 0;
    7076
    7177#ifdef QUICKTIME_C_API_AVAILABLE
     
    7884QuickTimeVideoPlayer::~QuickTimeVideoPlayer()
    7985{
    80     unsetVideo();
     86        PhononAutoReleasePool pool;
     87    unsetCurrentMediaSource();
     88    delete m_metaData;
    8189    [(NSObject*)m_primaryRenderingTarget release];
    8290    m_primaryRenderingTarget = 0;
     
    8593        CFRelease(m_visualContext);
    8694#endif
     95}
     96
     97void QuickTimeVideoPlayer::releaseImageCache()
     98{
     99    if (m_cachedCVTextureRef){
     100        CVOpenGLTextureRelease(m_cachedCVTextureRef);
     101        m_cachedCVTextureRef = 0;
     102    }
     103    m_cachedQImage = QImage();
    87104}
    88105
     
    126143
    127144    QTVisualContextTask(m_visualContext);
    128     return QTVisualContextIsNewImageAvailable(m_visualContext, 0);
     145    bool changed = QTVisualContextIsNewImageAvailable(m_visualContext, 0);
     146    if (changed)
     147        releaseImageCache();
     148    return changed;
    129149
    130150#elif defined(QT_MAC_USE_COCOA)
     
    141161    if (!m_visualContext)
    142162        return 0;
    143     CVOpenGLTextureRef texture = 0;
    144     OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &texture);
    145     BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0)
    146     return texture;
     163    if (!m_cachedCVTextureRef){
     164        OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &m_cachedCVTextureRef);
     165        BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0)
     166    }
     167    return m_cachedCVTextureRef;
    147168
    148169#else
     
    153174QImage QuickTimeVideoPlayer::currentFrameAsQImage()
    154175{
     176    if (!m_cachedQImage.isNull())
     177        return m_cachedQImage;
     178
    155179#ifdef QUICKTIME_C_API_AVAILABLE
    156180    QGLContext *prevContext = const_cast<QGLContext *>(QGLContext::currentContext());
     
    182206    glEnd();
    183207
    184     QImage image = m_QImagePixelBuffer->toImage();
    185     CVOpenGLTextureRelease(texture);
     208    m_cachedQImage = m_QImagePixelBuffer->toImage();
    186209    // Because of QuickTime, m_QImagePixelBuffer->doneCurrent() will fail.
    187210    // So we store, and restore, the context our selves:
    188211    prevContext->makeCurrent();
    189     return image;
     212    return m_cachedQImage;
    190213#else
    191214        CIImage *img = (CIImage *)currentFrameAsCIImage();
     
    196219        CGRect bounds = [img extent];
    197220        QImage qImg([bitmap bitmapData], bounds.size.width, bounds.size.height, QImage::Format_ARGB32);
    198         QImage swapped = qImg.rgbSwapped();
     221        m_cachedQImage = qImg.rgbSwapped();
    199222        [bitmap release];
    200223        [img release];
    201         return swapped;
     224        return m_cachedQImage;
    202225#endif
    203226}
     
    251274        CVOpenGLTextureRef cvImg = currentFrameAsCVTexture();
    252275        CIImage *img = [[CIImage alloc] initWithCVImageBuffer:cvImg];
    253         CVOpenGLTextureRelease(cvImg);
    254         return img;     
     276        return img;
    255277#else
    256278        return 0;
     
    274296    int samplesPerPixel = [bitmap samplesPerPixel];
    275297    if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)){
    276         glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 
     298        glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0,
    277299            samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8,
    278300            [bitmap pixelsWide], [bitmap pixelsHigh],
     
    303325    m_relativeVolume = relativeVolume;
    304326    if (!m_QTMovie || !m_audioEnabled || m_mute)
    305         return;               
     327        return;
    306328    [m_QTMovie setVolume:(m_masterVolume * m_relativeVolume)];
    307329}
     
    314336
    315337    // Work-around bug that happends if you set/unset mute
    316     // before movie is playing, and audio is not played 
     338    // before movie is playing, and audio is not played
    317339    // through graph. Then audio is delayed.
    318340    [m_QTMovie setMuted:mute];
     
    327349
    328350    // Work-around bug that happends if you set/unset mute
    329     // before movie is playing, and audio is not played 
     351    // before movie is playing, and audio is not played
    330352    // through graph. Then audio is delayed.
    331353    [m_QTMovie setMuted:(!enable || m_mute)];
     
    346368    // The following code will not work for some media codecs that
    347369    // typically mingle audio/video frames (e.g mpeg).
    348     CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id));       
     370    CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id));
    349371    QTAudioContextRef context;
    350372    QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, idString, 0, &context);
     
    370392    saturation += 1;
    371393
     394    if (m_brightness == brightness
     395        && m_contrast == contrast
     396        && m_hue == hue
     397        && m_saturation == saturation)
     398        return;
     399
    372400        m_brightness = brightness;
    373401        m_contrast = contrast;
    374402        m_hue = hue;
    375403        m_saturation = saturation;
    376        
    377404#ifdef QUICKTIME_C_API_AVAILABLE
    378405    Float32 value;
     
    386413    SetMovieVisualSaturation([m_QTMovie quickTimeMovie], value, 0);
    387414#endif
     415    releaseImageCache();
    388416}
    389417
     
    398426}
    399427
    400 void QuickTimeVideoPlayer::unsetVideo()
     428void QuickTimeVideoPlayer::unsetCurrentMediaSource()
    401429{
    402430    if (!m_QTMovie)
     
    411439    m_isDrmProtected = false;
    412440    m_isDrmAuthorized = true;
     441    m_hasVideo = false;
     442    m_staticFps = 0;
    413443    m_mediaSource = MediaSource();
     444    m_movieCompactDiscPath.clear();
    414445        [(CIImage *)m_primaryRenderingCIImage release];
    415446        m_primaryRenderingCIImage = 0;
    416447    delete m_QImagePixelBuffer;
    417448    m_QImagePixelBuffer = 0;
     449    releaseImageCache();
     450    [m_folderTracks release];
     451    m_folderTracks = 0;
    418452}
    419453
     
    525559{
    526560    PhononAutoReleasePool pool;
    527     unsetVideo();
     561    unsetCurrentMediaSource();
     562
    528563    m_mediaSource = mediaSource;
    529564    if (mediaSource.type() == MediaSource::Empty || mediaSource.type() == MediaSource::Invalid){
     
    531566        return;
    532567    }
     568
    533569    openMovieFromCurrentMediaSource();
    534570    if (errorOccured()){
    535         unsetVideo();
    536         return;
    537     }
    538 
     571        unsetCurrentMediaSource();
     572        return;
     573    }
     574
     575    prepareCurrentMovieForPlayback();
     576}
     577
     578void QuickTimeVideoPlayer::prepareCurrentMovieForPlayback()
     579{
    539580#ifdef QUICKTIME_C_API_AVAILABLE
    540581    if (m_visualContext)
     
    544585    waitStatePlayable();
    545586    if (errorOccured()){
    546         unsetVideo();
     587        unsetCurrentMediaSource();
    547588        return;
    548589    }
     
    551592    preRollMovie();
    552593    if (errorOccured()){
    553         unsetVideo();
     594        unsetCurrentMediaSource();
    554595        return;
    555596    }
     
    558599        m_playbackRate = prefferedPlaybackRate();
    559600    checkIfVideoAwailable();
     601    calculateStaticFps();
    560602    enableAudio(m_audioEnabled);
    561603    setMute(m_mute);
    562604    setVolume(m_masterVolume, m_relativeVolume);
     605    m_metaData->update();
    563606    pause();
    564607}
     
    574617        break;
    575618    case MediaSource::Disc:
    576         CASE_UNSUPPORTED("Could not open media source.", FATAL_ERROR)
     619        openMovieFromCompactDisc();
    577620        break;
    578621    case MediaSource::Stream:
     
    636679    // codecs *think* they can decode the stream, and crash...
    637680#define TryOpenMovieWithCodec(type) gClearError(); \
    638     openMovieFromData(data, "."type); \
     681    openMovieFromData(data, (char *)"."type); \
    639682    if (m_QTMovie) return;
    640683
     
    676719}
    677720
     721typedef void (*qt_sighandler_t)(int);
     722static void sigtest(int) {
     723    qApp->exit(0);
     724}
     725
     726void 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
     760QString QuickTimeVideoPlayer::movieCompactDiscPath() const
     761{
     762    return m_movieCompactDiscPath;
     763}
     764
    678765MediaSource QuickTimeVideoPlayer::mediaSource() const
    679766{
     
    719806        PhononAutoReleasePool pool;
    720807    return [[m_QTMovie attributeForKey:@"QTMovieTimeScaleAttribute"] longValue];
     808}
     809
     810float QuickTimeVideoPlayer::staticFps()
     811{
     812    return m_staticFps;
     813}
     814
     815void 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
    721846}
    722847
     
    9511076}
    9521077
     1078QMultiMap<QString, QString> QuickTimeVideoPlayer::metaData()
     1079{
     1080    return m_metaData->metaData();
     1081}
     1082
     1083int QuickTimeVideoPlayer::trackCount() const
     1084{
     1085    if (!m_folderTracks)
     1086        return 0;
     1087    return [m_folderTracks count];
     1088}
     1089
     1090int QuickTimeVideoPlayer::currentTrack() const
     1091{
     1092    return m_currentTrack;
     1093}
     1094
     1095QString 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
     1105NSString* 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
     1117bool 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
     1130NSArray* 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
     1144void 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
    9531166}}
    9541167
Note: See TracChangeset for help on using the changeset viewer.