void KMInstance::allocate(size_t nbObs, size_t nbAtt) { _data = RectMatrix(nbObs, nbAtt); _cst = 0; _weights.assign(nbObs, 1); _must = KMConstraints(nbObs); _cannot = KMConstraints(nbObs); }
// ###################################################################### static void setVideoChannelBounds(SGChannel videoChannel, const Rect* scaledSourceBounds, const Rect* scaledVideoBounds) { // Notes: see Q&A 1250 // calculate the matrix to transform the // scaledSourceBounds to the source bounds Rect sourceBounds; SGGetSrcVideoBounds(videoChannel, &sourceBounds); MatrixRecord scaledSourceBoundsToSourceBounds; RectMatrix(&scaledSourceBoundsToSourceBounds, scaledSourceBounds, &sourceBounds); // apply the same transform to the // scaledVideoBounds to get the video bounds Rect videoBounds = *scaledVideoBounds; TransformRect(&scaledSourceBoundsToSourceBounds, &videoBounds, 0); if (noErr != SGSetVideoRect(videoChannel, &videoBounds)) { // some video digitizers may only be able to capture full frame // and will return qtParamErr or possibly digiUnimpErr if they // can't handle working with less than full frame SGSetVideoRect(videoChannel, &sourceBounds); } // the channel bounds is scaledVideoBounds offset to (0, 0) Rect channelBounds = *scaledVideoBounds; OffsetRect(&channelBounds, -channelBounds.left, -channelBounds.top); // Note: SGSetChannelBounds merely allows the client to specify it's // preferred bounds. The actual bounds returned by the vDig in the // image description may be different if (noErr != SGSetChannelBounds(videoChannel, &channelBounds)) LFATAL("SGSetChannelBounds() failed"); }
OSErr CreateDecompSeqForSGChannelData(SGChannel sgChannel, Rect *srcBounds, GWorldPtr imageDestination, ImageSequence *imageSeqID) { OSErr err = noErr; ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription)); if (imageDesc) { err = SGGetChannelSampleDescription(sgChannel,(Handle)imageDesc); // The original version of this code had a bug - it passed in a Crop Rect to DecompressSequenceBegin instead of a scaling matrix // This only worked because of another bug inside QT that reated the crop Rect as a destination rect for DV // the following code does the right thing in all cases. if (err == noErr) { MatrixRecord mr; Rect fromR; fromR.left = 0; fromR.top = 0; fromR.right = (**imageDesc).width; fromR.bottom = (**imageDesc).height; RectMatrix(&mr, &fromR, srcBounds); err = DecompressSequenceBegin(imageSeqID, imageDesc, imageDestination, 0, nil, &mr,srcCopy,nil,0, codecNormalQuality, bestSpeedCodec); } DisposeHandle((Handle)imageDesc); } else { err = MemError(); } return err; }
static GstStateChangeReturn gst_osx_video_src_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn result; GstOSXVideoSrc *self; ComponentResult err; result = GST_STATE_CHANGE_SUCCESS; self = GST_OSX_VIDEO_SRC (element); // ###: prepare_capture in READY->PAUSED? switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { ImageDescriptionHandle imageDesc; Rect sourceRect; MatrixRecord scaleMatrix; if (!prepare_capture (self)) return GST_STATE_CHANGE_FAILURE; // ###: should we start recording /after/ making the decompressionsequence? // CocoaSequenceGrabber does it beforehand, so we do too, but it feels // wrong. err = SGStartRecord (self->seq_grab); if (err != noErr) { /* since we prepare here, we should also unprepare */ SGRelease (self->seq_grab); GST_ERROR_OBJECT (self, "SGStartRecord returned %d", (int) err); return GST_STATE_CHANGE_FAILURE; } imageDesc = (ImageDescriptionHandle) NewHandle (0); err = SGGetChannelSampleDescription (self->video_chan, (Handle) imageDesc); if (err != noErr) { SGStop (self->seq_grab); SGRelease (self->seq_grab); DisposeHandle ((Handle) imageDesc); GST_ERROR_OBJECT (self, "SGGetChannelSampleDescription returned %d", (int) err); return GST_STATE_CHANGE_FAILURE; } GST_DEBUG_OBJECT (self, "actual capture resolution is %dx%d", (int) (**imageDesc).width, (int) (**imageDesc).height); SetRect (&sourceRect, 0, 0, (**imageDesc).width, (**imageDesc).height); RectMatrix (&scaleMatrix, &sourceRect, &self->rect); err = DecompressSequenceBegin (&self->dec_seq, imageDesc, self->world, NULL, NULL, &scaleMatrix, srcCopy, NULL, 0, codecNormalQuality, bestSpeedCodec); if (err != noErr) { SGStop (self->seq_grab); SGRelease (self->seq_grab); DisposeHandle ((Handle) imageDesc); GST_ERROR_OBJECT (self, "DecompressSequenceBegin returned %d", (int) err); return GST_STATE_CHANGE_FAILURE; } DisposeHandle ((Handle) imageDesc); break; } default: break; } result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (result == GST_STATE_CHANGE_FAILURE) return result; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: SGStop (self->seq_grab); err = CDSequenceEnd (self->dec_seq); if (err != noErr) GST_WARNING_OBJECT (self, "CDSequenceEnd returned %d", (int) err); self->dec_seq = 0; SGRelease (self->seq_grab); break; default: break; } return result; }
// ###################################################################### 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; }
pascal OSErr sgdata_callback(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon) { #pragma unused(offset,chRefCon,time,writeType) CodecFlags ignore; V4lState *s=(V4lState *)refCon; ComponentResult err = noErr; if (!s) goto bail; Rect boundsRect = {0, 0, s->vsize.height, s->vsize.width}; /* 240 , 320*/ if (s->pgworld) { if (s->decomseq == 0) { Rect sourceRect = { 0, 0 }; MatrixRecord scaleMatrix; ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); err = SGGetChannelSampleDescription(c,(Handle)imageDesc); BailErr(err); // make a scaling matrix for the sequence sourceRect.right = (**imageDesc).width; sourceRect.bottom = (**imageDesc).height; RectMatrix(&scaleMatrix, &sourceRect, &boundsRect); err = DecompressSequenceBegin(&s->decomseq, // pointer to field to receive unique ID for sequence imageDesc, // handle to image description structure s->pgworld, // port for the DESTINATION image NULL, // graphics device handle, if port is set, set to NULL NULL, // source rectangle defining the portion of the image to decompress &scaleMatrix, // transformation matrix srcCopy, // transfer mode specifier NULL, // clipping region in dest. coordinate system to use as a mask 0, // flags codecNormalQuality, // accuracy in decompression bestSpeedCodec); // compressor identifier or special identifiers ie. bestSpeedCodec BailErr(err); DisposeHandle((Handle)imageDesc); imageDesc = NULL; } // decompress a frame into the GWorld - can queue a frame for async decompression when passed in a completion proc // once the image is in the GWorld it can be manipulated at will err = DecompressSequenceFrameS(s->decomseq, // 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 BailErr(err); { unsigned line; mblk_t *buf; int size = s->vsize.width * s->vsize.height * 3; buf=allocb(size,0); PixMap * pixmap = *GetGWorldPixMap(s->pgworld); uint8_t * data; unsigned rowBytes = pixmap->rowBytes & (((unsigned short) 0xFFFF) >> 2); unsigned pixelSize = pixmap->pixelSize / 8; // Pixel size in bytes unsigned lineOffset = rowBytes - s->vsize.width * pixelSize; data = (uint8_t *) GetPixBaseAddr(GetGWorldPixMap(s->pgworld)); for (line = 0 ; line < s->vsize.height ; line++) { unsigned offset = line * (s->vsize.width * pixelSize + lineOffset); memcpy(buf->b_wptr + ((line * s->vsize.width) * pixelSize), data + offset, (rowBytes - lineOffset)); } if (s->pix_fmt==MS_RGB24) { /* Conversion from top down bottom up (BGR to RGB and flip) */ unsigned long Index,nPixels; unsigned char *blue; unsigned char tmp; short iPixelSize; blue=buf->b_wptr; nPixels=s->vsize.width*s->vsize.height; iPixelSize=24/8; for(Index=0;Index!=nPixels;Index++) // For each pixel { tmp=*blue; *blue=*(blue+2); *(blue+2)=tmp; blue+=iPixelSize; } } buf->b_wptr+=size; ms_mutex_lock(&s->mutex); putq(&s->rq, buf); ms_mutex_unlock(&s->mutex); } } bail: return err; }