Documentation Archive Developer
Search

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

Extracting DV Fields using QTNewGWorldFromPtr


Q: I'm working with a 30 fps 720x480 DV movie and I'd like to extract each field of each frame into something I can add to a new file. Any ideas how to do this?

A: Each field can be extracted by using MoviesTask to draw each frame into a GWorld with movie play hints high quality turned on. Both fields will be rendered in the same GWorld, and alternate lines may then be extracted from the source GWorld allowing access to each field.

A quick way to extract alternate lines from a GWorld is to use QTNewGWorldFromPtr.

Using the technique outlined in Technical Q&A 1014 Creating Sub GWorlds, create a 720x480 source GWorld in which to draw the DV movie, then use QTNewGWorldFromPtr to create two new 'field' GWorlds which address alternate lines of the source GWorld.

QTNewGWorldFromPtr allows you to create an offscreen graphics world, which may have a non-Macintosh pixel format, where you define the base address and row bytes. Because the application is responsible for passing a pointer that isn't going to change during the lifetime of the GWorld, it should ensure the source GWorld pixels are locked. The application is also responsible for disposing of the pixel data when done.

High quality play hints can be turned on by using the SetMoviePlayHints API.

SetMoviePlayHints(theMovie, hintsHighQuality, hintsHighQuality);

Listing 1 demonstrates one way of creating the 'field' GWorlds.

Listing 1. MakeDVFieldGWorlds

 /*
    MakeDVFieldGWorlds

    This function returns two new GWorlds which point to
    alternate lines of a main source GWorld. The QuickTime
    DV codec draws both fields of a DV source in the same
    GWorld when Movie Play Hints High Quality is turned on.
    You can use this function to return two GWorlds which
    will give you access to both separate fields.

    In  inGWorld - source GWorld

    Out outTopFieldGW - GWorld containing the top field
                        of a DV frame
        outBottomFieldGW  - GWorld containing the
                            bottom field of a DV frame
*/
OSErr MakeDVFieldGWorlds(GWorldPtr inGWorld,
                         GWorldPtr *outTopFieldGW,
                         GWorldPtr *outBottomFieldGW)
{
    PixMapHandle hPixMap = NULL;
    long theRowBytes = 0L;
    Ptr theBaseAddr = NULL;
    OSType thePixelFormat;
    Rect theBounds;
    OSErr err = noErr;

    if (NULL == inSrcGWorld || NULL == outTopFieldGW ||
        NULL == outBottomFieldGW) return paramErr;

    // get what we need from the source GWorld
    hPixMap = GetGWorldPixMap(inGWorld);
        /* must be locked as we are making two new GWorlds
        that point to the pixels in this source GWorld */
    if (!(GetPixelsState(hPixMap) && pixelsLocked))
        LockPixels(hPixMap);

    theBaseAddr = GetPixBaseAddr(hPixMap);
    theRowBytes = QTGetPixMapHandleRowBytes(hPixMap);
    thePixelFormat = GETPIXMAPPIXELFORMAT(*hPixMap);
    theBounds = (**hPixMap).bounds;

    // should end up as 240 for NTSC DV
    theBounds.bottom = theBounds.bottom / 2;

    // create a new GWorld for the top field
    // we use rowBytes * 2 because we want every other line
    err = QTNewGWorldFromPtr(
        outTopFieldGW,  // returned GWorld
        thePixelFormat, // pixel format for new GWorld
        &theBounds, // boundary rectangle
        (**hPixMap).pmTable, // color table
        0, // GDevice handle
        0, // flags
        theBaseAddr, // address of the pixel data
        theRowBytes * 2); // number of bytes per row
     if (err) goto bail;

    // create a new GWorld for the bottom field
    err = QTNewGWorldFromPtr(
        outBottomFieldGW,
        thePixelFormat,
        &bounds,
        (**hPixMap).pmTable,
        0,
        0,
        (void *)(theBaseAddr + theRowBytes),
        theRowBytes * 2);
bail:
    return err;
}


After MoviesTask is used to draw into the main GWorld, the individual fields can be accessed using the sub-GWorlds and drawn with CopyBits.

Depending on the source, the fields may or may not be spatially coherent. If they are not, a filter should be applied to move the top field down half a pixel and the bottom field up half a pixel. Differences in the two fields will only be noticeable if something in the source is moving fast.

References:

Technical Q&A QA1014, "Creating Sub GWorlds using QTNewGWorldFromPtr"
Technical Q&A QA1007, "LockPixels and DisposeGWorld with QTNewGWorldFromPtr"


[Mar 20 2001]