Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Q&As > QuickTime > Compression & Decompression >

How can I verify that a Movie can actually draw into a non-RGB GWorld?


Q: Is it possible to verify that a movie can actually draw into a non-RGB GWorld? For example, if I create a GWorld with a '2vuy' (k2vuyPixelFormat) pixel format, it appears that only certain movies will render to that format while others just render empty frames.

A: There are a couple of different approaches you can take to verify that a movie can be rendered to a non-RGB GWorld.

Not all image decompressors support non-RGB output. Complicated movies with multiple video tracks, effects, multiple codec types, transformation matrices and so on, require kinds of composition that QuickTime cannot perform in non-RGB colorspaces.

The first approach checks the simplicity of a movie making sure no composition or complex matrices are involved, the movie contains only one video track with a single image description and the video format supports the specified non-RGB destination pixel format. See Listing 1.

Note:
This approach may reject some movies which are capable of being rendered to the non-RGB pixel format.


Listing 1. Can a movie render to the specified pixel format.

Boolean CanRenderMovieToPixelFormat(Movie  inMovie,
                                    OSType inPixelFormat)
{
  Track videoTrack, secondVisualTrack;
  ImageDescriptionHandle imageDesc = NULL;
  Boolean canRenderNonRGB = false;
  MatrixRecord matrix;
  Media videoMedia;
  OSType codecType;
  ComponentDescription cd = { decompressorComponentType, 0, 0, 0,
                              cmpIsMissing };
  Component decompressor = 0;

  // values of 1, 2, 4, 8, 16, 24 and 32 specify standard RGB
  // pixel formats while values of 33, 34, 36 and 40 specify
  // standard gray-scale pixel formats -- don't use this
  // approach for these pixel formats 
  if (inPixelFormat <= 40) return true;

  // check that the Movie matrix is no worse than scale+translate
  GetMovieMatrix(inMovie, &matrix);
  if (GetMatrixType(&matrix) > scaleTranslateMatrixType) goto nope;

  // get the first video track
  videoTrack = GetMovieIndTrackType(inMovie, 1, VideoMediaType,
                                    movieTrackMediaType);
  if (!videoTrack) goto nope;

  // make sure there are no other visual tracks
  // (video tracks are always visual)
  secondVisualTrack = GetMovieIndTrackType(inMovie, 2,
                                        VisualMediaCharacteristic,
                                        movieTrackCharacteristic);
  if (secondVisualTrack) goto nope;

  // check that the video track matrix is no worse than
  // scale+translate
  GetTrackMatrix(videoTrack, &matrix);
  if (GetMatrixType(&matrix) > scaleTranslateMatrixType) goto nope;

  // check that there's only one sample description
  videoMedia = GetTrackMedia(videoTrack);
  if (1 != GetMediaSampleDescriptionCount(videoMedia)) goto nope;

  // get the codec type out of that sample description
  imageDesc = (ImageDescriptionHandle)NewHandle(0);
  GetMediaSampleDescription(videoMedia, 1,
                            (SampleDescriptionHandle)imageDesc);
  if (noErr != GetMoviesError()) goto nope;
  codecType = (*imageDesc)->cType;

  // find decompressors for this codec type -- we'll need to find
  // at least one that lists a matching pixel format in its
  // cpix public resource
  cd.componentSubType = codecType;
  decompressor = FindNextComponent(0, &cd);
  if (!decompressor) goto nope;

  do {
    Handle cpix = NULL;
    // 'cpix' resources are used by codecs to list their
    // supported non-RGB pixel formats
    if (noErr == GetComponentPublicResource(decompressor,
                         FOUR_CHAR_CODE('cpix'), 1, &cpix)) {
      int i;
      int cpixFormatCount = GetHandleSize(cpix) / sizeof(OSType);
      for (i = 0; i < cpixFormatCount; i++) {
        if (inPixelformat == (*(OSType**)cpix)[i]) {
          canRenderNonRGB = true;
        }
      }
      DisposeHandle( cpix );
    }
    decompressor = FindNextComponent(decompressor, &cd);
  } while (decompressor && false == canRenderNonRGB);

nope:
  if (imageDesc) DisposeHandle((Handle)imageDesc);

  return canRenderNonRGB;
}

The second approach tries rendering to the specified pixel format and checks to see whether it succeeded. See Listing 2.

WARNING:
This approach should not be used before QuickTime 6 as it could fail by crashing.


Listing 2. Try and render a movie to the specified pixel format.
OSErr TryToRenderMovieToPixelFormat(Movie inMovie, 
                                    OSType inPixelFormat)
{
  OSErr err;
  Rect bounds;
  CGrafPtr savePort;
  GDHandle saveDevice;
  GWorldPtr gworld = NULL;

  GetMovieGWorld(inMovie, &savePort, &saveDevice);

  GetMovieBox(inMovie, &bounds);
  err = QTNewGWorld(&gworld, inPixelFormat, &bounds, NULL, NULL, 0);
  if (err) goto bail;
  LockPixels(GetGWorldPixMap(gworld));

  SetMovieGWorld(inMovie, gworld, NULL);
  MoviesTask(inMovie, 0);
  err = GetMovieStatus(inMovie, NULL);

bail:
  SetMovieGWorld(inMovie, savePort, saveDevice);
  if (gworld) DisposeGWorld(gworld);

  return err;
}

Using both techniques together is the recommended approach when trying to verify that a movie can be drawn to a specific non-RGB GWorld. First check to see if the movie is likely to support rendering to the destination pixel format, then actually try to render it. If either step fails, fall back to a 32ARGB (k32ARGBPixelFormat) GWorld.


[Mar 05, 2003]