Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Q&As > QuickTime > Movie Basics >

How do I decompress individual frames into an offscreen?


Q: How can you scale and decompress individual frames of a video track into an offscreen RGB buffer so the pixels can be further manipulated?

A: The code snippets below show how a single frame can be drawn into a GWorld. Once the GWorld is created, use SetMovieGWorld() to specify the GWorld you would like the movie to draw into. Use GetMovieNextInterestingTime() to find the places where the movie will display a new video sample (frame), then set the movie position using SetMovieTimeValue(). The time value passed to SetMovieTimeValue() is returned by GetMovieNextInterestingTime(). Finally, task the movie using MovieTask(), which performs the actual drawing into your GWorld. You will end up with the GWorld containing the frame pixels ready for manipulation.

GWorlds are very flexible and can contain pixel formats other than RGB. For more information regarding GWorlds and drawing, refer to the following technical documentation:

The full sample application called VideoFrameToGWorld can be found on the QuickTime Sample Code page:




    /* Globals */

GWorldPtr gSrcGWorld = NULL;
Movie gMovie = NULL;

    /* set current time value to beginning of the movie */
TimeValue gMovieTime = 0;
UInt32 gFrameCount = -1;
UInt32 gFrameNumber = 0;



    /* CountThemFrames
    Count the number of video "frames" in the movie by stepping
    through all of the video "interesting times", or in other words,
    the places where the movie displays a new video sample. The time
    between these interesting times is not necessarily constant. */

void CountThemFrames( void ) {
    OSType whichMediaType = VIDEO_TYPE;
    short flags = nextTimeMediaSample + nextTimeEdgeOK;
    TimeValue duration;
    TimeValue theTime = 0;

    while (theTime >= 0) {
        gFrameCount++;
        GetMovieNextInterestingTime(gMovie,
                            flags,
                            1,
                            &whichMediaType,
                            theTime,
                            0,
                            &theTime,
                            &duration);

        /* after the first interesting time, don't include
        the time we are currently at. */

        flags = nextTimeMediaSample;
    }
}



    /* MakeGWorld
    Get the bounding rectangle of the movie and create a
    32-bit gworld with those dimensions.  This GWorld will
    be used for rendering movie frames into. */

void MakeGWorld( void ) {
    Rect srcRect;
    Rect portRect;
    OSErr err = noErr;

        /* get the movies dimensions */
    GetMovieBox(gMovie,&srcRect);

    err = NewGWorld(&gSrcGWorld,
                k32ARGBPixelFormat,
                &srcRect,
                NULL,
                NULL,
                0);
    BailError(err);

        /* make sure to lock the PixMap */
    LockPixels(GetGWorldPixMap(gSrcGWorld));

        /* erase */
    SetGWorld(gSrcGWorld,NULL);
    GetPortBounds(gSrcGWorld, &portRect);
    EraseRect(&portRect);

        /* tell the movie to draw into the GWorld */
    SetMovieGWorld(gMovie, gSrcGWorld,  GetGWorldDevice(gSrcGWorld));

bail:
    return;
}




    /* NextFrame
    Get the next frame of the movie, set the movie time
    for that frame, then task the movie which will draw
    the frame to the GWorld.  Modify the movie matrix so
    the next frame will be rotated just for fun, and
    finally, draw the frame number on top of the image
    and inval the window rect. */

void NextFrame( void ) {
    if ( gFrameNumber < gFrameCount ) {

        TimeValue duration;

            /* get the next frame of the source movie */
        short   flags = nextTimeMediaSample;
        OSType  whichMediaType = VIDEO_TYPE;

            /* if this is the first frame, include the
            frame we are currently on */
        if (gFrameNumber == 0)
            flags |= nextTimeEdgeOK;

            /* skip to the next interesting time and
            get the duration for that frame */
        GetMovieNextInterestingTime(gMovie,
                            flags,
                            1,
                            &whichMediaType,
                            gMovieTime,
                            0,
                            &gMovieTime,
                            &duration);

            /* set the time for the frame and give
            time to the movie toolbox */
        SetMovieTimeValue(gMovie,gMovieTime);

            /* tasking the movie does the actual draw */
        MoviesTask(gMovie,0);
    }

    /* You now have pixels you can
    play with in the GWorld! */
}


[Apr 24 2000]