QTInternals.c

/*
    File:       QTInternals.c
 
    Contains:   Functions dealing with dumping internal movie information.
 
    Written by: DTS
 
    Copyright:  © 1995 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
       <1>      1/4/95  khs     first file
       
*/
 
 
// INCLUDES
#include "QTInternals.h"
#include "DTSQTUtilities.h"
 
 
// ______________________________________________________________________
// FUNCTIONS
 
 
 
// ______________________________________________________________________
void ShowGlobalMovieInfo(Movie theMovie)
{
    OSErr       anErr = noErr;
    Str255  tmpStr;
    TimeValue   tv, ts;
    Fixed       mr;
    long            movieSize = 0L;
    
    DebugAssert(aMovie != NULL);
    
    GetWTitle(FrontWindow(), tmpStr);
    printf("\nGlobal System Information for %s:\n", p2cstr(tmpStr));
 
    // Memory related information.
    anErr = QTUCalculateMovieMemorySize(theMovie, &movieSize);
    if(anErr == noErr) 
    {
        printf("This movie allocates %ld bytes in the current application heap.\n", movieSize);
        printf("Note that any possible associated movie controllers take each 10k or so.\n\n");
    }
    
    // Global Time Information
    ts = GetMovieTimeScale(theMovie);
    tv = GetMovieDuration(theMovie);
    printf("The time scale for this movie is %ld.\n", ts);
    printf("The movie duration (TimeValue) = %ld\n", tv);
    printf("The movie duration in seconds = %7.2f\n", (float)  tv / ts);
    
    printf("The current movie position (in seconds) = %7.2f\n", (float) GetMovieTime(theMovie, NULL) / ts);
 
    mr = GetMovieRate(theMovie);
    printf("The current movie rate is %7.2f  (0 means movie is not running, < 0 going backwards).\n",  (float) mr /fixed1);
}
 
 
// ______________________________________________________________________
void ShowMovieTrackInfo(Movie theMovie)
{
    OSErr                   anErr  = noErr;
    long                        aTrackCount, index;
    Track                   aTrack;
    long                        aTrackUsage;
    Str255                  tmpStr;
    Fixed                   height, width;
    short                   trackVol;
    MatrixRecord        mr;
    long                        nVideoTracks = 0;
    long                        nSoundTracks = 0;
    long                        nTextTracks = 0;
    long                        nMusicTracks = 0;
    
    GetWTitle(FrontWindow(), tmpStr);
    printf("\nTrack Information for %s:\n", p2cstr(tmpStr));
    
    // TRACK COUNT
    aTrackCount = GetMovieTrackCount(theMovie);
    anErr = GetMoviesError(); DebugAssert(anErr == noErr);
    if(anErr != noErr) return;
    
    if(aTrackCount == 0) 
    {
        printf("The Movie has no tracks.\n");
        return;
    }
    else
        printf("The Movie has %d track(s).\n", aTrackCount);
 
    // Parse through each track and get more information:
    for(index = 1; index <= aTrackCount; index++)
    {
        OSType aTrackType;
        Media aMedia;
        
        printf("\n");
        
        aTrack = GetMovieIndTrack(theMovie, index);
        
        // TRACK TYPE
        aMedia = GetTrackMedia(aTrack);
        GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
        
        switch (aTrackType)
        {
            case SoundMediaType: printf("This is a sound track.\n"); 
                nSoundTracks++;
                break;
                
            case VideoMediaType: printf("This is a video track.\n"); 
                nVideoTracks++;
                break;
                
            case TextMediaType: printf("This is a text track.\n"); 
                nTextTracks++;
                break;
                
            case MPEGMediaType: printf("This is an MPEG track.\n"); 
                break;
                
            case MusicMediaType: printf("This is a music track.\n"); 
                nMusicTracks++;
                break;
                
            case TimeCodeMediaType: printf("This is a time code track.\n"); 
                break;
                
            default: 
            {
                Byte *bp = (Byte *)&aTrackType;
                printf("The track is of type '%c%c%c%c' format.\n", bp[0], bp[1], bp[2], bp[3]);
                break;
            }
        }
        
        // TRACK ID
        printf("Track ID: %d\n", GetTrackID(aTrack));
    
        // TRACK ENABLED
        if(GetTrackEnabled(aTrack))
            printf("Track is enabled.\n");
        else
            printf("Track is disabled.\n");
        
        // TRACK LAYER
        printf("Track Layer: %d\n", GetTrackLayer(aTrack));
        
        // TRACK USAGE
        aTrackUsage = GetTrackUsage(aTrack);
        if(aTrackUsage & trackUsageInMovie)
            printf("Track is used in Movie.\n");
        if(aTrackUsage & trackUsageInPreview)
            printf("Track is used in a preview.\n");
        if(aTrackUsage & trackUsageInPoster)
            printf("Track is used in a poster.\n");
    
        // TRACK DURATION
        printf("Duration of the track = %ld\n", GetTrackDuration(aTrack));
        
        // TRACK DIMENSIONS
        GetTrackDimensions(aTrack, &width, &height);
        printf("Track width = %ld, Track height = %ld\n", Fix2Long(width), Fix2Long(height));
        
        // TRACK MATRIX
        GetTrackMatrix(aTrack, &mr);
        
        printf("Matrix record, row 0 = [%ld], [%ld], [%ld]\n", Fix2Long(*mr.matrix[0,0]), 
                                Fix2Long(*mr.matrix[0,1]), Fix2Long(*mr.matrix[0,2]));
        printf("Matrix record, row 1 = [%ld], [%ld], [%ld]\n", Fix2Long(*mr.matrix[1,0]), 
                                Fix2Long(*mr.matrix[1,1]), Fix2Long(*mr.matrix[1,2]));
        printf("Matrix record, row 2 = [%ld], [%ld], [%ld]\n", Fix2Long(*mr.matrix[2,0]), 
                                Fix2Long(*mr.matrix[2,1]), Fix2Long(*mr.matrix[2,2]));
        
        // TRACK VOLUME
        trackVol = GetTrackVolume(aTrack);
        if(trackVol == 255)
            printf("Track Volume is 1.0\n");
        else
            printf("Track Volume = %d.%d\n", (signed short)(trackVol >> 8) , (trackVol & 0xFF));
    }
    
    // Check how many similar tracks, if too many of same warn (crossplatform issues)
    if(nVideoTracks > 1)
        printf("NOTE! You have more than one video track (%ld tracks), this will be a problem with QuickTime for Windows.\n", nVideoTracks);
 
    if(nSoundTracks > 1)
        printf("NOTE! You have more than one sound track (%ld tracks), you need to enable just one at a time under QuickTime for Windows (2.0.1 forward).\n", nSoundTracks);
 
    if(nTextTracks > 1)
        printf("NOTE! You have more than one text track (%ld tracks), this will be a problem with QuickTime for Windows.\n", nTextTracks);
 
    if(nMusicTracks > 1)
        printf("NOTE! You have more than one music track (%ld tracks), this will be a problem with QuickTime for Windows.\n", nMusicTracks);
}
 
 
// ______________________________________________________________________
void ShowMovieVideoInfo(Movie theMovie)
{
    OSErr       anErr = noErr;
    Str255  tmpStr;
    short       trackCount, index;
    long            nSamples;
    float           nSeconds;
 
    DebugAssert(aMovie != NULL);
    
    GetWTitle(FrontWindow(), tmpStr);
    printf("\nVideo Media Information for %s:\n", p2cstr(tmpStr));
 
    // VIDEO FRAMES/SAMPLES
    nSamples = QTUCountMediaSamples(theMovie, VideoMediaType);
    
    printf("The movie has %ld video frames (samples) ", nSamples);
    printf("of which %ld are key frames\n", QTUCountKeySamples(theMovie, VideoMediaType) );
 
    printf("The duration of the first video sample is %ld\n", QTUGetDurationOfFirstMovieSample(theMovie, VideoMediaType));
    
    nSeconds =  GetMovieDuration(theMovie)/ GetMovieTimeScale(theMovie);
    printf("Frames per second (assuming that each video sample is of the same length) = %7.2f  fps\n", (float) nSamples/nSeconds );
    
    // Get the Image Description Structure and present the values.
    trackCount = GetMovieTrackCount(theMovie);
    
    for(index = 1; index <= trackCount; index++)
    {
        Track       aTrack = NULL;
        Media       aMedia = NULL;
        OSType      aMediaType;
        
        aTrack = GetMovieIndTrack(theMovie, index); DebugAssert(aTrack != NULL);
        aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL);
        anErr = GetMoviesError(); DebugAssert(anErr == noErr);
        if(anErr != noErr)
        {
            printf("Problems with getting trackmedia = %d\n", anErr);
            return;
        }
 
        GetMediaHandlerDescription(aMedia, &aMediaType, 0, 0);
        if(aMediaType == VideoMediaType) // We just want to check the video media samples.
        {
            SampleDescriptionHandle anImageDesc = NULL;
            anImageDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription));
            DebugAssert(GetMemErr == noErr);
 
            GetMediaSampleDescription(aMedia, 1, anImageDesc);
            anErr = GetMoviesError(); DebugAssert(anErr == noErr);
            MoveHHi((Handle)anImageDesc); HLock((Handle)anImageDesc); // Really would not need to, but printf (don't trust that one
                                                                                                          // due to the MetroWerks Sioux environment).
            if(anErr != noErr)
            {
                DisposeHandle((Handle)anImageDesc);
                continue;
            }
 
            // OK, we have the Image Description, now present the values (see IM:QuickTime, page 3-50 for more
            // information about the ImageDescription structure).
            
            printf("The video track has a pixel depth of %d.\n", (*(ImageDescriptionHandle)anImageDesc)->depth);
    
            // Get the image description height and width values, test if these are multiple of 4 (if not there's a performance penalty).
            {
            long rest;
            
            printf("The video track has a source image height of %d.\n", (*(ImageDescriptionHandle)anImageDesc)->height);
        
            rest  = (*(ImageDescriptionHandle)anImageDesc)->height % 4;
            if (rest != 0)
                printf("NOTE! The source image height is not a multiple of 4, this means a performance hit.\n");
 
            printf("The video track has a source image width of %d.\n", (*(ImageDescriptionHandle)anImageDesc)->width);
            
            rest  = (*(ImageDescriptionHandle)anImageDesc)->width % 4;
            if (rest != 0)
                printf("NOTE! The source image width is not a multiple of 4, this means a performance hit.\n");
            }
            
            printf("The video track has a horizontal resolution of %ld.\n", Fix2Long( (*(ImageDescriptionHandle)anImageDesc)->hRes) );
            printf("The video track has a vertical resolution of %ld.\n", Fix2Long( (*(ImageDescriptionHandle)anImageDesc)->vRes) );
            
            printf("The codec used to compress the video samples:  %s\n", p2cstr( (*(ImageDescriptionHandle)anImageDesc)->name) );
            printf("Note that this is the codec for the first video sample, the video samples in the movie might have various codecs used...\n");
            {
                Byte *bp = (Byte *)&(*(ImageDescriptionHandle)anImageDesc)->vendor;
                printf("The video track was compressed by codec provided by '%c%c%c%c'.\n", bp[0], bp[1], bp[2], bp[3]);
            }
            printf("The temporal compression setting is %ld\n",  (*(ImageDescriptionHandle)anImageDesc)->temporalQuality);
            printf("The spatial compression setting is %ld\n",  (*(ImageDescriptionHandle)anImageDesc)->spatialQuality);
            
            
            printf("The image description structure is %ld bytes in size.\n", 
                            (*(ImageDescriptionHandle)anImageDesc)->idSize);
 
            DisposeHandle((Handle)anImageDesc);
        }
    }
}
 
 
// ______________________________________________________________________
void ShowMovieSoundInfo(Movie theMovie)
{
    Str255  tmpStr;
    short       trackCount, index;
    OSErr       anErr = noErr;
    
    DebugAssert(aMovie != NULL);
    
    GetWTitle(FrontWindow(), tmpStr);
    printf("\nSound Media Information for %s:\n", p2cstr(tmpStr));
    
#ifdef THIS_WILL_TAKE_LONG
    printf("The movie has %d sound samples (samples)\n", QTUCountMediaSamples(theMovie, SoundMediaType));
#endif // THIS_WILL_TAKE_LONG
 
    // Get the sound description handle and munch it:
    trackCount = GetMovieTrackCount(theMovie);
    
    for(index = 1; index <= trackCount; index++)
    {
        Track       aTrack = NULL;
        Media       aMedia = NULL;
        OSType  aMediaType;
        
        aTrack = GetMovieIndTrack(theMovie, index); DebugAssert(aTrack != NULL);
        aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL);
        anErr = GetMoviesError(); DebugAssert(anErr == noErr);
        if(anErr != noErr)
        {
            printf("Problems with getting trackmedia = %d\n", anErr);
            return;
        }
        
        GetMediaHandlerDescription(aMedia, &aMediaType, 0, 0);
        if(aMediaType == SoundMediaType)        // We just want to check out the sound description handles.
        {
            SampleDescriptionHandle aDesc = NULL;
            aDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); 
            DebugAssert(GetMemErr() == noErr);
        
            GetMediaSampleDescription(aMedia, 1, aDesc);
            anErr = GetMoviesError(); DebugAssert(anErr == noErr);
            MoveHHi((Handle)aDesc); HLock((Handle)aDesc); // Really would not need to, but printf (don't trust that one
                                                                                     // due to the MetroWerks Sioux environment).
            if(anErr != noErr)
            {
                DisposeHandle((Handle)aDesc);
                continue;
            }
            // OK, we have the sound description handle now, present the values
            printf("The sound track rate is %d Hz.\n", (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16);
            {
            long soundRate =  (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16;
            if (soundRate < 30000)
                if( (soundRate != 22050) && (soundRate != 11025) ) 
                    printf("NOTE! The movie has a sound rate that will maybe cause performance problems with certain PC sound boards. If possible use 22050 or 11025 kHz instead\n");
            }
            
            printf("The sound track size is %d bit.\n", (*(SoundDescriptionHandle)aDesc)->sampleSize);
            
            printf("The sound track has %d channel(s).\n", (*(SoundDescriptionHandle)aDesc)->numChannels);
            {
                Byte *bp = (Byte *)&(*(SoundDescriptionHandle)aDesc)->dataFormat;
                printf("The sound track has the '%c%c%c%c' format.\n", bp[0], bp[1], bp[2], bp[3]);
            }
            
            printf("The sound description structure is %ld bytes in size.\n", 
                            (*(SoundDescriptionHandle)aDesc)->descSize);
        }
    }
}
 
 
// ______________________________________________________________________
// This is a variation function of the QTUCountMediaSamples one, we want to figure out how
// many key frames we have in the movie.
 
pascal long QTUCountKeySamples(Movie theMovie, OSType theMediaType)
{
    long numFrames = 0;
    
    short flags = nextTimeEdgeOK + nextTimeSyncSample;
    TimeValue aDuration = 0;
    TimeValue theTime = 0;
    
    GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
    if(theTime == -1) return numFrames;
 
    flags = nextTimeSyncSample; // Don't include the  nudge after the first interesting time.
    
    while(theTime != -1)  // When the returned time equals -1, then there were no more interesting times.
    {
        numFrames++;
        GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
    }
    
    return numFrames;
}