// decode a frame static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){ OSErr result = 1; CodecFlags ignore; if(len<=0) return NULL; // skipped frame #if defined(WIN32_LOADER) && !defined(CONFIG_QUICKTIME) Setup_FS_Segment(); #endif result = DecompressSequenceFrameS(imageSeq, data, len, 0, &ignore, NULL); if(result) { mp_msg(MSGT_DECVIDEO,MSGL_ERR,"DecompressSequenceFrameS result=0x%d\n",result); return NULL; } if((int)sh->context==0x73797639){ // Sorenson 16-bit YUV -> std YVU9 int i; PixMap dstPixMap = **GetGWorldPixMap(OutBufferGWorld); short *src0=(short *)((char*)dstPixMap.baseAddr+0x20); for(i=0;i<mpi->h;i++){ int x; unsigned char* dst=mpi->planes[0]+i*mpi->stride[0]; unsigned short* src=src0+i*((mpi->w+15)&(~15)); for(x=0;x<mpi->w;x++) dst[x]=src[x]; } src0+=((mpi->w+15)&(~15))*((mpi->h+15)&(~15)); for(i=0;i<mpi->h/4;i++){ int x; unsigned char* dst=mpi->planes[1]+i*mpi->stride[1]; unsigned short* src=src0+i*(((mpi->w+63)&(~63))/4); for(x=0;x<mpi->w/4;x++) dst[x]=src[x]; src+=((mpi->w+63)&(~63))/4; } src0+=(((mpi->w+63)&(~63))/4)*(((mpi->h+63)&(~63))/4); for(i=0;i<mpi->h/4;i++){ int x; unsigned char* dst=mpi->planes[2]+i*mpi->stride[2]; unsigned short* src=src0+i*(((mpi->w+63)&(~63))/4); for(x=0;x<mpi->w/4;x++) dst[x]=src[x]; src+=((mpi->w+63)&(~63))/4; } } return mpi; }
static OSErr data_proc (SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon) { GstOSXVideoSrc *self; gint fps_n, fps_d; GstClockTime duration, timestamp, latency; CodecFlags flags; ComponentResult err; PixMapHandle hPixMap; Rect portRect; int pix_rowBytes; void *pix_ptr; int pix_height; int pix_size; self = GST_OSX_VIDEO_SRC (refCon); if (self->buffer != NULL) { gst_buffer_unref (self->buffer); self->buffer = NULL; } err = DecompressSequenceFrameS (self->dec_seq, p, len, 0, &flags, NULL); if (err != noErr) { GST_ERROR_OBJECT (self, "DecompressSequenceFrameS returned %d", (int) err); return err; } hPixMap = GetGWorldPixMap (self->world); LockPixels (hPixMap); GetPortBounds (self->world, &portRect); pix_rowBytes = (int) GetPixRowBytes (hPixMap); pix_ptr = GetPixBaseAddr (hPixMap); pix_height = (portRect.bottom - portRect.top); pix_size = pix_rowBytes * pix_height; GST_DEBUG_OBJECT (self, "num=%5d, height=%d, rowBytes=%d, size=%d", self->seq_num, pix_height, pix_rowBytes, pix_size); fps_n = FRAMERATE; fps_d = 1; duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); latency = duration; timestamp = gst_clock_get_time (GST_ELEMENT_CAST (self)->clock); timestamp -= gst_element_get_base_time (GST_ELEMENT_CAST (self)); if (timestamp > latency) timestamp -= latency; else timestamp = 0; self->buffer = gst_buffer_new_and_alloc (pix_size); GST_BUFFER_OFFSET (self->buffer) = self->seq_num; GST_BUFFER_TIMESTAMP (self->buffer) = timestamp; memcpy (GST_BUFFER_DATA (self->buffer), pix_ptr, pix_size); self->seq_num++; UnlockPixels (hPixMap); 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; }
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; }