00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "QuicktimeCapture.h"
00047 #include "Image/ByteImage.h"
00048
00049 #include <QuickTime/QuickTimeStreaming.h>
00050
00051
00052
00053
00054
00055
00056
00057 CQuicktimeCapture::CQuicktimeCapture(VideoMode mode, const char *pComponentName) : m_mode(mode)
00058 {
00059 grabber = 0;
00060 videoChannel = 0;
00061 gWorld = 0;
00062 m_pBuffer = 0;
00063 imgDesc = 0;
00064
00065 width = -1;
00066 height = -1;
00067
00068 m_sComponentName = "";
00069
00070 if (pComponentName)
00071 m_sComponentName += pComponentName;
00072
00073 m_bImagePending = false;
00074 }
00075
00076 CQuicktimeCapture::~CQuicktimeCapture()
00077 {
00078 CloseCamera();
00079 }
00080
00081
00082
00083
00084
00085
00086 bool CQuicktimeCapture::OpenCamera()
00087 {
00088 CloseCamera();
00089
00090 switch (m_mode)
00091 {
00092 case e320x240:
00093 width = 320;
00094 height = 240;
00095 break;
00096
00097 case e640x480:
00098 width = 640;
00099 height = 480;
00100 break;
00101
00102 default:
00103 return false;
00104 }
00105
00106 srcRect.left = 0;
00107 srcRect.right = width - 1;
00108 srcRect.top = 0;
00109 srcRect.bottom = height - 1;
00110
00111 Component comp = 0;
00112 Handle grabberName = NewHandle(0);
00113 Handle info = NewHandle(0);
00114 ComponentDescription desc;
00115
00116 desc.componentType = SeqGrabComponentType;
00117 desc.componentSubType = 0;
00118 desc.componentManufacturer = 0;
00119 desc.componentFlags = 0;
00120 desc.componentFlagsMask = 0;
00121
00122
00123 bool bFound = false;
00124 while (comp = FindNextComponent(comp, &desc))
00125 {
00126 if (GetComponentInfo(comp, &desc, grabberName, info, 0) != noErr)
00127 {
00128 printf("error: could not get info on component id = %i\n", comp);
00129 return false;
00130 }
00131
00132 printf("grabber: '%s'\n", *grabberName + 1);
00133
00134 if (m_sComponentName.length() == 0 || strcmp(m_sComponentName.c_str(), *grabberName + 1) == 0)
00135 {
00136 bFound = true;
00137 break;
00138 }
00139 }
00140
00141 if (!bFound)
00142 {
00143 printf("error: could not find a sequence grabber named '%s'\n", m_sComponentName.c_str());
00144 return false;
00145 }
00146
00147
00148 grabber = OpenComponent(comp);
00149
00150 if (!grabber)
00151 {
00152 printf("error: could not open sequence grabber\n");
00153 return false;
00154 }
00155
00156 if (SGInitialize(grabber) != noErr)
00157 {
00158 printf("errror: could not initialize the sequence grabber\n");
00159 return false;
00160 }
00161
00162 if (SGSetDataRef(grabber, 0, 0, seqGrabDontMakeMovie) != noErr)
00163 {
00164 printf("error: could not set data reference on sequence grabber\n");
00165 return false;
00166 }
00167
00168 if (QTNewGWorld(&gWorld, k24RGBPixelFormat, &srcRect, 0, 0, 0) != noErr)
00169 {
00170 printf("error: could not create new gworld\n");
00171 return false;
00172 }
00173
00174 if (!LockPixels(GetPortPixMap(gWorld)))
00175 {
00176 printf("error: could not lock pixels in new gworld\n");
00177 return false;
00178 }
00179
00180 if (SGSetGWorld(grabber, gWorld, 0) != noErr)
00181 {
00182 printf("error: could not set gworld\n");
00183 return false;
00184 }
00185
00186
00187 if (SGNewChannel(grabber, VideoMediaType, &videoChannel) != noErr || !videoChannel)
00188 {
00189 printf("error: could not open video channel\n");
00190 return false;
00191 }
00192
00193 if (SGSetChannelUsage(videoChannel, seqGrabRecord) != noErr)
00194 {
00195 printf("error: could not set channel usage to 'record'\n");
00196 return false;
00197 }
00198
00199 if (SGSetChannelBounds(videoChannel, &srcRect) != noErr)
00200 {
00201 printf("error: could not set channel bounds to %ix%i\n", width, height);
00202 return false;
00203 }
00204
00205 if (SGSetDataProc(grabber, NewSGDataUPP(sDataProc), (long)this) != noErr)
00206 {
00207 printf("error: could not set data proc\n");
00208 return false;
00209 }
00210
00211 SGStartRecord(grabber);
00212
00213 return true;
00214 }
00215
00216 void CQuicktimeCapture::CloseCamera()
00217 {
00218 if (grabber)
00219 {
00220 SGStop(grabber);
00221
00222 if (videoChannel)
00223 {
00224 SGDisposeChannel(grabber, videoChannel);
00225 videoChannel = 0;
00226 }
00227
00228 if (gWorld)
00229 {
00230 DisposeGWorld(gWorld);
00231 gWorld = 0;
00232 }
00233
00234 grabber = 0;
00235 }
00236
00237 m_bImagePending = false;
00238 }
00239
00240 bool CQuicktimeCapture::CaptureImage(CByteImage **ppImages)
00241 {
00242 if (!videoChannel)
00243 return false;
00244
00245 CByteImage *pImage = ppImages[0];
00246 if (pImage->width != width || pImage->height != height || pImage->type != CByteImage::eRGB24)
00247 return false;
00248
00249 while (!m_bImagePending)
00250 SGIdle(grabber);
00251
00252 ImageSequence image_sequence;
00253
00254 if (DecompressSequenceBegin(&image_sequence, imgDesc, gWorld, 0, &srcRect, 0, srcCopy, 0, 0, codecNormalQuality, bestSpeedCodec) != noErr)
00255 {
00256 printf("error: could not begin decompression\n");
00257 return false;
00258 }
00259
00260 CodecFlags ignore;
00261
00262 DecompressSequenceFrameS(image_sequence, m_pBuffer, m_lImageLength, 0, &ignore, NULL);
00263
00264 const int nBytes = 3 * pImage->width * pImage->height;
00265 const unsigned char *input = (unsigned char *) GetPixBaseAddr(GetGWorldPixMap(gWorld));
00266 unsigned char *output = pImage->pixels;
00267 for (int i = 0, offset = 0; i < nBytes; i += 3, offset += 4)
00268 {
00269 output[i] = input[offset + 1];
00270 output[i + 1] = input[offset + 2];
00271 output[i + 2] = input[offset + 3];
00272 }
00273
00274 CDSequenceEnd(image_sequence);
00275
00276 m_bImagePending = false;
00277
00278 return true;
00279 }
00280
00281 pascal OSErr CQuicktimeCapture::sDataProc(SGChannel channel, Ptr p, long length, long *offset, long chRefCon, TimeValue time, short writeType, long refcon)
00282 {
00283 return ((CQuicktimeCapture *) refcon)->dataProc(channel, p, length);
00284 }
00285
00286 OSErr CQuicktimeCapture::dataProc(SGChannel channel, Ptr p, long length)
00287 {
00288 if (!imgDesc)
00289 {
00290 imgDesc = (ImageDescriptionHandle) NewHandle(0);
00291 SGGetChannelSampleDescription(videoChannel, (Handle) imgDesc);
00292 }
00293
00294 m_pBuffer = p;
00295 m_lImageLength = length;
00296 m_bImagePending = true;
00297
00298 return noErr;
00299 }