//------------------------------------------------------------------------ unsigned pixel_map::width() const { if(m_pmap == nil) return 0; PixMapHandle pm = GetGWorldPixMap (m_pmap); Rect bounds; GetPixBounds (pm, &bounds); return bounds.right - bounds.left; }
static pascal OSErr DrawCompleteProc (Movie theMovie, long refCon) { long int h; long int w; int y, x; GWorldPtr offWorld = (GWorldPtr) refCon; Rect bounds; Ptr baseAddr; long rowBytes; uint8_t* imbuf; mwSize dims[3]; GetPixBounds(GetGWorldPixMap(offWorld), &bounds); baseAddr = GetPixBaseAddr(GetGWorldPixMap(offWorld)); rowBytes = GetPixRowBytes(GetGWorldPixMap(offWorld)); h = rint(bounds.bottom - bounds.top); w = rint(bounds.right - bounds.left); dims[0] = h; dims[1] = w; dims[2] = 3; framedata = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); imbuf = (uint8_t*) mxGetData(framedata); // Retrieve the pixel data, unpack the RGB values and copy for (y = 0; y < h; ++y) { long *p; p = (long *) (baseAddr + rowBytes * (long) y); for (x = 0; x < w; ++x) { UInt32 color = *(long *)((long) p + 4 * (long) x);; long B = (color & 0xFF000000) >> 24; long G = (color & 0x00FF0000) >> 16; long R = (color & 0x0000FF00) >> 8; imbuf[y + x * h + 0 * (h * w)] = R; imbuf[y + x * h + 1 * (h * w)] = G; imbuf[y + x * h + 2 * (h * w)] = B; } } return noErr; }
// ###################################################################### OSErr QuickTimeGrabber::Impl::grabData(SGChannel c, Ptr p, long len, TimeValue time) { if (itsGotFrame) { LDEBUG("already got a frame on this iteration"); return noErr; } // we only care about the video if (c != itsSGChanVideo.it) { return noErr; } // reset frame and time counters after a stop/start if (time < itsPrevTime) { LDEBUG("resetting frame/time counters (current=%ld, last=%ld)", (long) time, (long) itsPrevTime); itsPrevTime = 0; itsFrameCount = 0; } if (itsTimeScale == 0) { LDEBUG("setting up time scale & timebase"); Fixed framesPerSecond; long milliSecPerFrameIgnore, bytesPerSecondIgnore; // first time here so get the time scale & timebase if (noErr != SGGetChannelTimeScale(c, &itsTimeScale)) { itsErrorMsg = "SGGetChannelTimeScale() failed"; return OSErr(-1); } if (noErr != SGGetTimeBase(itsSeqGrab.it, &itsTimeBase)) { itsErrorMsg = "SGGetTimeBase() failed"; return OSErr(-1); } if (noErr != VDGetDataRate(SGGetVideoDigitizerComponent(c), &milliSecPerFrameIgnore, &framesPerSecond, &bytesPerSecondIgnore)) { itsErrorMsg = "VDGetDataRate() failed"; return OSErr(-1); } } if (itsDrawSeq == 0) { LDEBUG("setting up decompression sequence"); // set up decompression sequence ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); // retrieve a channel's current sample description, the channel // returns a sample description that is appropriate to the type // of data being captured if (noErr != SGGetChannelSampleDescription(c, (Handle)imageDesc)) { itsErrorMsg = "SGGetChannelSampleDescription() failed"; return OSErr(-1); } // make a scaling matrix for the sequence Rect sourceRect = { 0, 0 }; sourceRect.right = (**imageDesc).width; sourceRect.bottom = (**imageDesc).height; Rect scaleRect; GetPixBounds(GetGWorldPixMap(itsGWorld), &scaleRect); // if DV do high quality 720x480 both fields CodecFlags cFlags = (kDVCNTSCCodecType == (**imageDesc).cType) ? codecHighQuality : codecNormalQuality; MatrixRecord scaleMatrix; RectMatrix(&scaleMatrix, &sourceRect, &scaleRect); LINFO("sourceRect = %dx%d, scaleRect = %dx%d", sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, scaleRect.right - scaleRect.left, scaleRect.bottom - scaleRect.top); // begin the process of decompressing a sequence of frames this // is a set-up call and is only called once for the sequence - // the ICM will interrogate different codecs and construct a // suitable decompression chain, as this is a time consuming // process we don't want to do this once per frame (eg. by using // DecompressImage) for more information see Ice Floe #8 // http://developer.apple.com/quicktime/icefloe/dispatch008.html // the destination is specified as the GWorld CGrafPtr dest = itsGWorld; if (noErr != DecompressSequenceBeginS (&itsDrawSeq, // pointer to field to receive unique ID for sequence imageDesc, // handle to image description structure p, // points to the compressed image data len, // size of the data buffer dest, // port for the DESTINATION image NULL, // graphics device handle, if port is set, set to NULL NULL, // decompress the entire source image - no source extraction &scaleMatrix, // transformation matrix srcCopy, // transfer mode specifier (RgnHandle)NULL, // clipping region in dest. coordinate system to use as a mask 0, // flags cFlags, // accuracy in decompression bestSpeedCodec)) // compressor identifier or special identifiers ie. bestSpeedCodec { itsErrorMsg = "DSeqBegin failed"; return OSErr(-1); } DisposeHandle((Handle)imageDesc); } // itsDrawSeq == 0 // get the TimeBase time and figure out the delta between that time // and this frame time const TimeValue timeBaseTime = GetTimeBaseTime(itsTimeBase, itsTimeScale, NULL); const TimeValue timeBaseDelta = timeBaseTime - time; const TimeValue frameTimeDelta = time - itsPrevTime; if (timeBaseDelta < 0) { itsErrorMsg = "bogus timeBaseDelta"; return OSErr(-1); } // if we have more than one queued frame and our capture rate drops // below 10 frames, skip the frame to try and catch up if ((itsQueuedFrameCount > 1) && ((itsTimeScale / frameTimeDelta) < 10) && (itsSkipFrameCount < 15)) { LDEBUG("dropping frame"); ++itsSkipFrameCount; ++itsSkipFrameCountTotal; } else { itsFrameCount++; CodecFlags ignore; // decompress a frame into the window - can queue a frame for async decompression when passed in a completion proc if (noErr != DecompressSequenceFrameS (itsDrawSeq, // sequence ID returned by DecompressSequenceBegin p, // pointer to compressed image data len, // size of the buffer 0, // in flags &ignore, // out flags NULL)) // async completion proc { itsErrorMsg = "DSeqFrameS failed"; return OSErr(-1); } // get the information we need from the GWorld Rect pbound; GetPixBounds(GetGWorldPixMap(itsGWorld), &pbound); char* const baseAddr = GetPixBaseAddr(GetGWorldPixMap(itsGWorld)); const long rowBytes = QTGetPixMapHandleRowBytes(GetGWorldPixMap(itsGWorld)); itsCurrentImage.resize(Dims(pbound.right - pbound.left, pbound.bottom - pbound.top)); Image<PixRGB<byte> >::iterator itr = itsCurrentImage.beginw(); for (int y = pbound.top; y < pbound.bottom; ++y) { char* p = baseAddr + rowBytes * (y-pbound.top); for (int x = pbound.left; x < pbound.right; ++x) { const UInt32 color = *((UInt32*)(p) + x - pbound.left); const UInt32 R = (color & 0x00FF0000) >> 16; const UInt32 G = (color & 0x0000FF00) >> 8; const UInt32 B = (color & 0x000000FF) >> 0; *itr++ = PixRGB<byte>(R,G,B); } } itsSkipFrameCount = 0; itsPrevTime = time; itsGotFrame = true; } // status information const float fps = (float)itsTimeScale / (float)frameTimeDelta; const float averagefps = ((float)itsFrameCount * (float)itsTimeScale) / (float)time; const UInt8 minutes = (time / itsTimeScale) / 60; const UInt8 seconds = (time / itsTimeScale) % 60; const UInt8 frames = (time % itsTimeScale) / frameTimeDelta; LDEBUG("#%06ld t:%ld nq:%u, %02d:%02d.%02d, fps:%5.1f av:%5.1f", itsFrameCount, time, itsQueuedFrameCount, minutes, seconds, frames, fps, averagefps); return noErr; }