1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
46 // Original implementation by Mark Asbach
47 // Institute of Communications Engineering
48 // RWTH Aachen University
50 // For implementation details and background see:
51 // http://developer.apple.com/samplecode/qtframestepper.win/listing1.html
53 // Please note that timing will only be correct for videos that contain a visual track
54 // that has full length (compared to other tracks)
62 #include <Carbon/Carbon.h>
63 #include <CoreFoundation/CoreFoundation.h>
64 #include <QuickTime/QuickTime.h>
67 // Global state (did we call EnterMovies?)
68 static int did_enter_movies = 0;
70 // ----------------------------------------------------------------------------------------
71 #pragma mark Reading Video Files
73 /// Movie state structure for QuickTime movies
74 typedef struct CvCapture_QT_Movie
76 CvCaptureVTable * vtable;
78 Movie myMovie; // movie handle
79 GWorldPtr myGWorld; // we render into an offscreen GWorld
81 CvSize size; // dimensions of the movie
82 TimeValue movie_start_time; // movies can start at arbitrary times
83 long number_of_frames; // duration in frames
85 long next_frame_number;
87 IplImage * image_rgb; // will point to the PixMap of myGWorld
88 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
94 static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename);
95 static int icvClose_QT_Movie (CvCapture_QT_Movie * capture);
96 static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id);
97 static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value);
98 static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture);
99 static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture);
102 static CvCaptureVTable capture_QT_Movie_vtable =
105 (CvCaptureCloseFunc) icvClose_QT_Movie,
106 (CvCaptureGrabFrameFunc) icvGrabFrame_QT_Movie,
107 (CvCaptureRetrieveFrameFunc) icvRetrieveFrame_QT_Movie,
108 (CvCaptureGetPropertyFunc) icvGetProperty_QT_Movie,
109 (CvCaptureSetPropertyFunc) icvSetProperty_QT_Movie,
110 (CvCaptureGetDescriptionFunc) 0
114 CvCapture * cvCaptureFromFile_QT (const char * filename)
116 static int did_enter_movies = 0;
117 if (! did_enter_movies)
120 did_enter_movies = 1;
123 CvCapture_QT_Movie * capture = 0;
127 capture = (CvCapture_QT_Movie *) cvAlloc (sizeof (*capture));
128 memset (capture, 0, sizeof(*capture));
130 capture->vtable = &capture_QT_Movie_vtable;
132 if (!icvOpenFile_QT_Movie (capture, filename))
133 cvReleaseCapture ((CvCapture**) & capture);
136 return (CvCapture*)capture;
142 * convert full path to CFStringRef and open corresponding Movie. Then
143 * step over 'interesting frame times' to count total number of frames
144 * for video material with varying frame durations and create offscreen
145 * GWorld for rendering the movie frames.
147 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
150 static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename)
154 Handle myDataRef = nil;
155 OSType myDataRefType = 0;
159 // no old errors please
160 ClearMoviesStickyError ();
162 // initialize pointers to zero
163 capture->myMovie = 0;
164 capture->myGWorld = nil;
166 // initialize numbers with invalid values
167 capture->next_frame_time = -1;
168 capture->next_frame_number = -1;
169 capture->number_of_frames = -1;
170 capture->movie_start_time = -1;
171 capture->size = cvSize (-1,-1);
174 // we would use CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, filename) on Mac OS X 10.4
175 CFStringRef inPath = CFStringCreateWithCString (kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1);
176 OPENCV_ASSERT ((inPath != nil), "icvOpenFile_QT_Movie", "couldnt create CFString from a string");
178 // create the data reference
179 myErr = QTNewDataReferenceFromFullPathCFString (inPath, kQTPOSIXPathStyle, 0, & myDataRef, & myDataRefType);
182 fprintf (stderr, "Couldn't create QTNewDataReferenceFromFullPathCFString().\n");
187 myErr = NewMovieFromDataRef(& capture->myMovie, newMovieActive | newMovieAsyncOK /* | newMovieIdleImportOK */,
188 & myResID, myDataRef, myDataRefType);
190 // dispose of the data reference handle - we no longer need it
191 DisposeHandle (myDataRef);
193 // if NewMovieFromDataRef failed, we already disposed the DataRef, so just return with an error
196 fprintf (stderr, "Couldn't create a NewMovieFromDataRef() - error is %d.\n", myErr);
200 // count the number of video 'frames' in the movie by stepping through all of the
201 // video 'interesting times', or in other words, the places where the movie displays
202 // a new video sample. The time between these interesting times is not necessarily constant.
204 OSType whichMediaType = VisualMediaCharacteristic;
205 TimeValue theTime = -1;
207 // find out movie start time
208 GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample + nextTimeEdgeOK),
209 1, & whichMediaType, TimeValue (0), 0, & theTime, NULL);
212 fprintf (stderr, "Couldn't inquire first frame time\n");
215 capture->movie_start_time = theTime;
216 capture->next_frame_time = theTime;
217 capture->next_frame_number = 0;
219 // count all 'interesting times' of the movie
220 capture->number_of_frames = 0;
223 GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample),
224 1, & whichMediaType, theTime, 0, & theTime, NULL);
225 capture->number_of_frames++;
229 // get the bounding rectangle of the movie
231 GetMovieBox (capture->myMovie, & myRect);
232 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
234 // create gworld for decompressed image
235 myErr = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat /* k24BGRPixelFormat geht leider nicht */,
236 & myRect, nil, nil, 0);
237 OPENCV_ASSERT (myErr == noErr, "icvOpenFile_QT_Movie", "couldnt create QTNewGWorld() for output image");
238 SetMovieGWorld (capture->myMovie, capture->myGWorld, nil);
240 // build IplImage header that will point to the PixMap of the Movie's GWorld later on
241 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
243 // create IplImage that hold correctly formatted result
244 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
246 // okay, that's it - should we wait until the Movie is playable?
251 * dispose of QuickTime Movie and free memory buffers
253 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
256 static int icvClose_QT_Movie (CvCapture_QT_Movie * capture)
258 OPENCV_ASSERT (capture, "icvClose_QT_Movie", "'capture' is a NULL-pointer");
260 // deallocate and free resources
261 if (capture->myMovie)
263 cvReleaseImage (& capture->image_bgr);
264 cvReleaseImageHeader (& capture->image_rgb);
265 DisposeGWorld (capture->myGWorld);
266 DisposeMovie (capture->myMovie);
274 * get a capture property
276 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
279 static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id)
281 OPENCV_ASSERT (capture, "icvGetProperty_QT_Movie", "'capture' is a NULL-pointer");
282 OPENCV_ASSERT (capture->myMovie, "icvGetProperty_QT_Movie", "invalid Movie handle");
283 OPENCV_ASSERT (capture->number_of_frames > 0, "icvGetProperty_QT_Movie", "movie has invalid number of frames");
284 OPENCV_ASSERT (capture->movie_start_time >= 0, "icvGetProperty_QT_Movie", "movie has invalid start time");
286 // inquire desired property
289 case CV_CAP_PROP_POS_FRAMES:
290 return (capture->next_frame_number);
292 case CV_CAP_PROP_POS_MSEC:
293 case CV_CAP_PROP_POS_AVI_RATIO:
295 TimeValue position = capture->next_frame_time - capture->movie_start_time;
297 if (property_id == CV_CAP_PROP_POS_MSEC)
299 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
300 return (static_cast<double> (position) * 1000.0 / timescale);
304 TimeValue duration = GetMovieDuration (capture->myMovie);
305 return (static_cast<double> (position) / duration);
308 break; // never reached
310 case CV_CAP_PROP_FRAME_WIDTH:
311 return static_cast<double> (capture->size.width);
313 case CV_CAP_PROP_FRAME_HEIGHT:
314 return static_cast<double> (capture->size.height);
316 case CV_CAP_PROP_FPS:
318 TimeValue duration = GetMovieDuration (capture->myMovie);
319 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
321 return (capture->number_of_frames / (static_cast<double> (duration) / timescale));
324 case CV_CAP_PROP_FRAME_COUNT:
325 return static_cast<double> (capture->number_of_frames);
327 case CV_CAP_PROP_FOURCC: // not implemented
328 case CV_CAP_PROP_FORMAT: // not implemented
329 case CV_CAP_PROP_MODE: // not implemented
331 // unhandled or unknown capture property
332 OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
340 * set a capture property. With movie files, it is only possible to set the
341 * position (i.e. jump to a given time or frame number)
343 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
346 static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value)
348 OPENCV_ASSERT (capture, "icvSetProperty_QT_Movie", "'capture' is a NULL-pointer");
349 OPENCV_ASSERT (capture->myMovie, "icvSetProperty_QT_Movie", "invalid Movie handle");
350 OPENCV_ASSERT (capture->number_of_frames > 0, "icvSetProperty_QT_Movie", "movie has invalid number of frames");
351 OPENCV_ASSERT (capture->movie_start_time >= 0, "icvSetProperty_QT_Movie", "movie has invalid start time");
353 // inquire desired property
355 // rework these three points to really work through 'interesting times'.
356 // with the current implementation, they result in wrong times or wrong frame numbers with content that
357 // features varying frame durations
360 case CV_CAP_PROP_POS_MSEC:
361 case CV_CAP_PROP_POS_AVI_RATIO:
363 TimeValue destination;
364 OSType myType = VisualMediaCharacteristic;
367 if (property_id == CV_CAP_PROP_POS_MSEC)
369 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
370 destination = static_cast<TimeValue> (value / 1000.0 * timescale + capture->movie_start_time);
374 TimeValue duration = GetMovieDuration (capture->myMovie);
375 destination = static_cast<TimeValue> (value * duration + capture->movie_start_time);
379 if (capture->next_frame_time == destination)
382 // seek into which direction?
383 if (capture->next_frame_time < destination)
385 while (capture->next_frame_time < destination)
387 capture->next_frame_number++;
388 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
389 1, & capture->next_frame_time, NULL);
390 myErr = GetMoviesError();
393 fprintf (stderr, "Couldn't go on to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
400 while (capture->next_frame_time > destination)
402 capture->next_frame_number--;
403 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
404 -1, & capture->next_frame_time, NULL);
405 myErr = GetMoviesError();
408 fprintf (stderr, "Couldn't go back to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
416 case CV_CAP_PROP_POS_FRAMES:
418 TimeValue destination = static_cast<TimeValue> (value);
419 short direction = (destination > capture->next_frame_number) ? 1 : -1;
420 OSType myType = VisualMediaCharacteristic;
423 while (destination != capture->next_frame_number)
425 capture->next_frame_number += direction;
426 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
427 direction, & capture->next_frame_time, NULL);
428 myErr = GetMoviesError();
431 fprintf (stderr, "Couldn't step to desired frame number in icvGrabFrame_QT.\n");
439 // unhandled or unknown capture property
440 OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
444 // positive result means success
449 * the original meaning of this method is to acquire raw frame data for the next video
450 * frame but not decompress it. With the QuickTime video reader, this is reduced to
451 * advance to the current frame time.
453 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
456 static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture)
458 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Movie", "'capture' is a NULL-pointer");
459 OPENCV_ASSERT (capture->myMovie, "icvGrabFrame_QT_Movie", "invalid Movie handle");
461 TimeValue myCurrTime;
462 OSType myType = VisualMediaCharacteristic;
466 // jump to current video sample
467 SetMovieTimeValue (capture->myMovie, capture->next_frame_time);
468 myErr = GetMoviesError();
471 fprintf (stderr, "Couldn't SetMovieTimeValue() in icvGrabFrame_QT_Movie.\n");
476 myCurrTime = GetMovieTime (capture->myMovie, NULL);
478 // increment counters
479 capture->next_frame_number++;
480 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, myCurrTime, 1, & capture->next_frame_time, NULL);
481 myErr = GetMoviesError();
484 fprintf (stderr, "Couldn't GetMovieNextInterestingTime() in icvGrabFrame_QT_Movie.\n");
493 * render the current frame into an image buffer and convert to OpenCV IplImage
494 * buffer layout (BGR sampling)
496 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
499 static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture)
501 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Movie", "'capture' is a NULL-pointer");
502 OPENCV_ASSERT (capture->myMovie, "icvRetrieveFrame_QT_Movie", "invalid Movie handle");
503 OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Movie", "invalid source image");
504 OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Movie", "invalid destination image");
506 PixMapHandle myPixMapHandle = nil;
510 // invalidates the movie's display state so that the Movie Toolbox
511 // redraws the movie the next time we call MoviesTask
512 UpdateMovie (capture->myMovie);
513 myErr = GetMoviesError ();
516 fprintf (stderr, "Couldn't UpdateMovie() in icvRetrieveFrame_QT_Movie().\n");
520 // service active movie (= redraw immediately)
521 MoviesTask (capture->myMovie, 0L);
522 myErr = GetMoviesError ();
525 fprintf (stderr, "MoviesTask() didn't succeed in icvRetrieveFrame_QT_Movie().\n");
529 // update IplImage header that points to PixMap of the Movie's GWorld.
530 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
531 // so we pass a modfied address.
532 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
533 myPixMapHandle = GetGWorldPixMap (capture->myGWorld);
534 LockPixels (myPixMapHandle);
535 cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
537 // covert RGB of GWorld to BGR
538 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
540 // allow QuickTime to access the buffer again
541 UnlockPixels (myPixMapHandle);
543 // always return the same image pointer
544 return capture->image_bgr;
548 // ----------------------------------------------------------------------------------------
550 #pragma mark Capturing from Video Cameras
552 #ifdef USE_VDIG_VERSION
554 /// SequenceGrabber state structure for QuickTime
555 typedef struct CvCapture_QT_Cam_vdig
557 CvCaptureVTable * vtable;
559 ComponentInstance grabber;
565 long number_of_frames;
567 IplImage * image_rgb; // will point to the PixMap of myGWorld
568 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
574 typedef struct CvCapture_QT_Cam_barg
576 CvCaptureVTable * vtable;
578 SeqGrabComponent grabber;
582 ImageSequence sequence;
584 volatile bool got_frame;
587 IplImage * image_rgb; // will point to the PixMap of myGWorld
588 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
594 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index);
595 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture);
596 static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id);
597 static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value);
598 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture);
599 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture);
602 static CvCaptureVTable capture_QT_Cam_vtable =
605 (CvCaptureCloseFunc) icvClose_QT_Cam,
606 (CvCaptureGrabFrameFunc) icvGrabFrame_QT_Cam,
607 (CvCaptureRetrieveFrameFunc) icvRetrieveFrame_QT_Cam,
608 (CvCaptureGetPropertyFunc) icvGetProperty_QT_Cam,
609 (CvCaptureSetPropertyFunc) icvSetProperty_QT_Cam,
610 (CvCaptureGetDescriptionFunc) 0
615 * Initialize memory structure and call method to open camera
617 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
620 CvCapture * cvCaptureFromCAM_QT (const int index)
622 if (! did_enter_movies)
625 did_enter_movies = 1;
628 CvCapture_QT_Cam * capture = 0;
632 capture = (CvCapture_QT_Cam *) cvAlloc (sizeof (*capture));
633 memset (capture, 0, sizeof(*capture));
635 capture->vtable = &capture_QT_Cam_vtable;
637 if (!icvOpenCamera_QT (capture, index))
638 cvReleaseCapture ((CvCapture**) & capture);
641 return (CvCapture *) capture;
644 /// capture properties currently unimplemented for QuickTime camera interface
645 static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id)
651 /// capture properties currently unimplemented for QuickTime camera interface
652 static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value)
658 #ifdef USE_VDIG_VERSION
659 #pragma mark Capturing using VDIG
662 * Open a quicktime video grabber component. This could be an attached
663 * IEEE1394 camera, a web cam, an iSight or digitizer card / video converter.
665 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
668 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
670 OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
671 OPENCV_ASSERT (index >=0, "icvOpenCamera_QT", "camera index is negative");
673 ComponentDescription component_description;
674 Component component = 0;
675 int number_of_inputs = 0;
677 ComponentResult result = noErr;
680 // travers all components and count video digitizer channels
681 component_description.componentType = videoDigitizerComponentType;
682 component_description.componentSubType = 0L;
683 component_description.componentManufacturer = 0L;
684 component_description.componentFlags = 0L;
685 component_description.componentFlagsMask = 0L;
688 // traverse component list
689 component = FindNextComponent (component, & component_description);
691 // found a component?
694 // dump component name
696 ComponentDescription desc;
697 Handle nameHandle = NewHandleClear (200);
698 char nameBuffer [255];
700 result = GetComponentInfo (component, & desc, nameHandle, nil, nil);
701 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt GetComponentInfo()");
702 OPENCV_ASSERT (*nameHandle, "icvOpenCamera_QT", "No name returned by GetComponentInfo()");
703 snprintf (nameBuffer, (**nameHandle) + 1, "%s", (char *) (* nameHandle + 1));
704 printf ("- Videodevice: %s\n", nameBuffer);
705 DisposeHandle (nameHandle);
708 // open component to count number of inputs
709 capture->grabber = OpenComponent (component);
710 if (capture->grabber)
712 result = VDGetNumberOfInputs (capture->grabber, & capture->channel);
714 fprintf (stderr, "Couldnt GetNumberOfInputs: %d\n", (int) result);
718 printf (" Number of inputs: %d\n", (int) capture->channel + 1);
721 // add to overall number of inputs
722 number_of_inputs += capture->channel + 1;
724 // did the user select an input that falls into this device's
725 // range of inputs? Then leave the loop
726 if (number_of_inputs > index)
728 // calculate relative channel index
729 capture->channel = index - number_of_inputs + capture->channel + 1;
730 OPENCV_ASSERT (capture->channel >= 0, "icvOpenCamera_QT", "negative channel number");
737 result = VDGetInputName (capture->grabber, capture->channel, nameBuffer);
738 OPENCV_ASSERT (result == noErr, "ictOpenCamera_QT", "couldnt GetInputName()");
739 snprintf (name, *nameBuffer, "%s", (char *) (nameBuffer + 1));
740 printf (" Choosing input %d - %s\n", (int) capture->channel, name);
748 // obviously no inputs of this device/component were needed
749 CloseComponent (capture->grabber);
755 // did we find the desired input?
758 fprintf(stderr, "Not enough inputs available - can't choose input %d\n", index);
762 // -- Okay now, we selected the digitizer input, lets set up digitizer destination --
764 ClearMoviesStickyError();
766 // Select the desired input
767 result = VDSetInput (capture->grabber, capture->channel);
768 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt select video digitizer input");
770 // get the bounding rectangle of the video digitizer
771 result = VDGetActiveSrcRect (capture->grabber, capture->channel, & myRect);
772 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
773 myRect.right = 640; myRect.bottom = 480;
774 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
775 printf ("Source rect is %d, %d -- %d, %d\n", (int) myRect.left, (int) myRect.top, (int) myRect.right, (int) myRect.bottom);
777 // create offscreen GWorld
778 result = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat, & myRect, nil, nil, 0);
779 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create QTNewGWorld() for output image");
782 capture->pixmap = GetGWorldPixMap (capture->myGWorld);
783 result = GetMoviesError ();
784 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get pixmap");
786 // set digitizer rect
787 result = VDSetDigitizerRect (capture->grabber, & myRect);
788 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
790 // set destination of digitized input
791 result = VDSetPlayThruDestination (capture->grabber, capture->pixmap, & myRect, nil, nil);
792 printf ("QuickTime error: %d\n", (int) result);
793 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video destination");
795 // get destination of digitized images
796 result = VDGetPlayThruDestination (capture->grabber, & capture->pixmap, nil, nil, nil);
797 printf ("QuickTime error: %d\n", (int) result);
798 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get video destination");
799 OPENCV_ASSERT (capture->pixmap != nil, "icvOpenCamera_QT", "empty set video destination");
801 // get the bounding rectangle of the video digitizer
802 GetPixBounds (capture->pixmap, & myRect);
803 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
805 // build IplImage header that will point to the PixMap of the Movie's GWorld later on
806 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
807 OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
809 // create IplImage that hold correctly formatted result
810 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
811 OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
813 // notify digitizer component, that we well be starting grabbing soon
814 result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureIsForRecord | vdFlagCaptureStarting | vdFlagCaptureLowLatency);
815 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
822 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
824 OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
826 ComponentResult result = noErr;
828 // notify digitizer component, that we well be stopping grabbing soon
829 result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureStopping);
830 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
833 cvReleaseImage (& capture->image_bgr);
834 cvReleaseImageHeader (& capture->image_rgb);
835 DisposeGWorld (capture->myGWorld);
836 CloseComponent (capture->grabber);
842 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
844 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
845 OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
847 ComponentResult result = noErr;
850 result = VDGrabOneFrame (capture->grabber);
853 fprintf (stderr, "VDGrabOneFrame failed\n");
861 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture)
863 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
865 PixMapHandle myPixMapHandle = nil;
867 // update IplImage header that points to PixMap of the Movie's GWorld.
868 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
869 // so we pass a modfied address.
870 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
871 //myPixMapHandle = GetGWorldPixMap (capture->myGWorld);
872 myPixMapHandle = capture->pixmap;
873 LockPixels (myPixMapHandle);
874 cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
876 // covert RGB of GWorld to BGR
877 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
879 // allow QuickTime to access the buffer again
880 UnlockPixels (myPixMapHandle);
882 // always return the same image pointer
883 return capture->image_bgr;
887 #pragma mark Capturing using Sequence Grabber
889 static OSErr icvDataProc_QT_Cam (SGChannel channel, Ptr raw_data, long len, long *, long, TimeValue, short, long refCon)
891 CvCapture_QT_Cam * capture = (CvCapture_QT_Cam *) refCon;
893 ComponentResult err = noErr;
896 // we need valid pointers
897 OPENCV_ASSERT (capture, "icvDataProc_QT_Cam", "'capture' is a NULL-pointer");
898 OPENCV_ASSERT (capture->gworld, "icvDataProc_QT_Cam", "'gworld' is a NULL-pointer");
899 OPENCV_ASSERT (raw_data, "icvDataProc_QT_Cam", "'raw_data' is a NULL-pointer");
901 // create a decompression sequence the first time
902 if (capture->sequence == 0)
904 ImageDescriptionHandle description = (ImageDescriptionHandle) NewHandle(0);
906 // we need a decompression sequence that fits the raw data coming from the camera
907 err = SGGetChannelSampleDescription (channel, (Handle) description);
908 OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt get channel sample description");
909 err = DecompressSequenceBegin (&capture->sequence, description, capture->gworld, 0, &capture->bounds,
910 nil, srcCopy, nil, 0, codecNormalQuality, bestSpeedCodec);
911 OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt begin decompression sequence");
913 DisposeHandle ((Handle) description);
916 // okay, we have a decompression sequence -> decompress!
917 err = DecompressSequenceFrameS (capture->sequence, raw_data, len, 0, &ignore, nil);
920 fprintf (stderr, "icvDataProc_QT_Cam: couldn't decompress frame - %d\n", (int) err);
924 // check if we dropped a frame
926 if (capture->got_frame)
927 fprintf (stderr, "icvDataProc_QT_Cam: frame was dropped\n");
930 // everything worked as expected
931 capture->got_frame = true;
936 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
938 OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
939 OPENCV_ASSERT (index >= 0, "icvOpenCamera_QT", "camera index is negative");
941 PixMapHandle pixmap = nil;
942 OSErr result = noErr;
944 // open sequence grabber component
945 capture->grabber = OpenDefaultComponent (SeqGrabComponentType, 0);
946 OPENCV_ASSERT (capture->grabber, "icvOpenCamera_QT", "couldnt create image");
948 // initialize sequence grabber component
949 result = SGInitialize (capture->grabber);
950 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt initialize sequence grabber");
951 result = SGSetDataRef (capture->grabber, 0, 0, seqGrabDontMakeMovie);
952 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data reference of sequence grabber");
954 // set up video channel
955 result = SGNewChannel (capture->grabber, VideoMediaType, & (capture->channel));
956 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create new video channel");
958 // query natural camera resolution -- this will be wrong, but will be an upper
959 // bound on the actual resolution -- the actual resolution is set below
960 // after starting the frame grabber
961 result = SGGetSrcVideoBounds (capture->channel, & (capture->bounds));
962 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
964 // create offscreen GWorld
965 result = QTNewGWorld (& (capture->gworld), k32ARGBPixelFormat, & (capture->bounds), 0, 0, 0);
966 result = SGSetGWorld (capture->grabber, capture->gworld, 0);
967 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
968 result = SGSetChannelBounds (capture->channel, & (capture->bounds));
969 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
970 result = SGSetChannelUsage (capture->channel, seqGrabRecord);
971 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set channel usage");
973 // start recording so we can size
974 result = SGStartRecord (capture->grabber);
975 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
977 // don't know *actual* resolution until now
978 ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);
979 result = SGGetChannelSampleDescription(capture->channel, (Handle)imageDesc);
980 OPENCV_ASSERT( result == noErr, "icvOpenCamera_QT", "couldn't get image size");
981 capture->bounds.right = (**imageDesc).width;
982 capture->bounds.bottom = (**imageDesc).height;
983 DisposeHandle ((Handle) imageDesc);
985 // stop grabber so that we can reset the parameters to the right size
986 result = SGStop (capture->grabber);
987 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
989 // reset GWorld to correct image size
991 result = QTNewGWorld( &tmpgworld, k32ARGBPixelFormat, &(capture->bounds), 0, 0, 0);
992 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create offscreen GWorld");
993 result = SGSetGWorld( capture->grabber, tmpgworld, 0);
994 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
995 DisposeGWorld( capture->gworld );
996 capture->gworld = tmpgworld;
998 result = SGSetChannelBounds (capture->channel, & (capture->bounds));
999 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
1002 capture->size = cvSize (capture->bounds.right - capture->bounds.left, capture->bounds.bottom - capture->bounds.top);
1004 // build IplImage header that points to the PixMap of the Movie's GWorld.
1005 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
1006 // so we shift the base address by one byte.
1007 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
1008 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
1009 OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
1010 pixmap = GetGWorldPixMap (capture->gworld);
1011 OPENCV_ASSERT (pixmap, "icvOpenCamera_QT", "didn't get GWorld PixMap handle");
1012 LockPixels (pixmap);
1013 cvSetData (capture->image_rgb, GetPixBaseAddr (pixmap) + 1, GetPixRowBytes (pixmap));
1015 // create IplImage that hold correctly formatted result
1016 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
1017 OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
1020 // tell the sequence grabber to invoke our data proc
1021 result = SGSetDataProc (capture->grabber, NewSGDataUPP (icvDataProc_QT_Cam), (long) capture);
1022 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data proc");
1025 result = SGStartRecord (capture->grabber);
1026 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
1032 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
1034 OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
1036 OSErr result = noErr;
1040 result = SGStop (capture->grabber);
1041 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
1043 // close sequence grabber component
1044 result = CloseComponent (capture->grabber);
1045 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt close sequence grabber component");
1047 // end decompression sequence
1048 CDSequenceEnd (capture->sequence);
1051 cvReleaseImage (& capture->image_bgr);
1052 cvReleaseImageHeader (& capture->image_rgb);
1053 DisposeGWorld (capture->gworld);
1059 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
1061 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
1062 OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
1064 ComponentResult result = noErr;
1068 result = SGIdle (capture->grabber);
1069 if (result != noErr)
1071 fprintf (stderr, "SGIdle failed in icvGrabFrame_QT_Cam with error %d\n", (int) result);
1079 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture)
1081 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
1082 OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Cam", "invalid source image");
1083 OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Cam", "invalid destination image");
1085 OSErr myErr = noErr;
1088 // service active sequence grabbers (= redraw immediately)
1089 while (! capture->got_frame)
1091 myErr = SGIdle (capture->grabber);
1094 fprintf (stderr, "SGIdle() didn't succeed in icvRetrieveFrame_QT_Cam().\n");
1099 // covert RGB of GWorld to BGR
1100 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
1102 // reset grabbing status
1103 capture->got_frame = false;
1105 // always return the same image pointer
1106 return capture->image_bgr;
1112 typedef struct CvVideoWriter_QT {
1113 DataHandler data_handler;
1118 ICMCompressionSessionRef compression_session_ref;
1120 TimeValue duration_per_sample;
1123 static TimeScale const TIME_SCALE = 600;
1125 OSStatus icvEncodedFrameOutputCallback(
1127 ICMCompressionSessionRef compression_session_ref,
1129 ICMEncodedFrameRef encoded_frame_ref,
1133 void icvSourceTrackingCallback(
1134 void *source_tracking_ref_con,
1135 ICMSourceTrackingFlags source_tracking_flags,
1136 void *source_frame_ref_con,
1140 CV_IMPL CvVideoWriter* cvCreateVideoWriter(
1141 const char * filename,
1147 CV_FUNCNAME( "cvCreateVideoWriter" );
1149 CvVideoWriter_QT* video_writer =
1150 static_cast<CvVideoWriter_QT*>( cvAlloc( sizeof( CvVideoWriter_QT ) ) );
1151 memset( video_writer, 0, sizeof( CvVideoWriter_QT ) );
1153 Handle data_ref = NULL;
1154 OSType data_ref_type;
1155 DataHandler data_handler = NULL;
1157 ICMCompressionSessionOptionsRef options_ref = NULL;
1158 ICMCompressionSessionRef compression_session_ref = NULL;
1164 // validate input arguments
1165 if ( filename == NULL ) {
1166 CV_ERROR( CV_StsBadArg, "Video file name must not be NULL" );
1169 CV_ERROR( CV_StsBadArg, "FPS must be larger than 0.0" );
1171 if ( ( frame_size.width <= 0 ) || ( frame_size.height <= 0 ) ) {
1172 CV_ERROR( CV_StsBadArg,
1173 "Frame width and height must be larger than 0" );
1176 // initialize QuickTime
1177 if ( !did_enter_movies ) {
1178 err = EnterMovies();
1179 if ( err != noErr ) {
1180 CV_ERROR( CV_StsInternal, "Unable to initialize QuickTime" );
1182 did_enter_movies = 1;
1185 // convert the file name into a data reference
1186 CFStringRef out_path = CFStringCreateWithCString( kCFAllocatorDefault,
1187 filename, kCFStringEncodingISOLatin1 );
1188 CV_ASSERT( out_path != nil );
1189 err = QTNewDataReferenceFromFullPathCFString( out_path, kQTPOSIXPathStyle,
1190 0, &data_ref, &data_ref_type );
1191 CFRelease( out_path );
1192 if ( err != noErr ) {
1193 CV_ERROR( CV_StsInternal,
1194 "Cannot create data reference from file name" );
1197 // create a new movie on disk
1198 err = CreateMovieStorage( data_ref, data_ref_type, 'TVOD',
1199 smCurrentScript, newMovieActive, &data_handler, &movie );
1201 if ( err != noErr ) {
1202 CV_ERROR( CV_StsInternal, "Cannot create movie storage" );
1205 // create a track with video
1209 FixRatio( frame_size.width, 1 ),
1210 FixRatio( frame_size.height, 1 ),
1213 err = GetMoviesError();
1214 if ( err != noErr ) {
1215 CV_ERROR( CV_StsInternal, "Cannot create video track" );
1218 NewTrackMedia( video_track, VideoMediaType, TIME_SCALE, nil, 0 );
1219 err = GetMoviesError();
1220 if ( err != noErr ) {
1221 CV_ERROR( CV_StsInternal, "Cannot create video media" );
1224 CodecType codecType;
1226 case CV_FOURCC( 'D', 'I', 'B', ' ' ):
1227 codecType = kRawCodecType;
1230 codecType = kRawCodecType;
1234 // start a compression session
1235 err = ICMCompressionSessionOptionsCreate( kCFAllocatorDefault,
1237 if ( err != noErr ) {
1238 CV_ERROR( CV_StsInternal, "Cannot create compression session options" );
1240 err = ICMCompressionSessionOptionsSetAllowTemporalCompression( options_ref,
1242 if ( err != noErr) {
1243 CV_ERROR( CV_StsInternal, "Cannot enable temporal compression" );
1245 err = ICMCompressionSessionOptionsSetAllowFrameReordering( options_ref,
1247 if ( err != noErr) {
1248 CV_ERROR( CV_StsInternal, "Cannot enable frame reordering" );
1251 ICMEncodedFrameOutputRecord encoded_frame_output_record;
1252 encoded_frame_output_record.encodedFrameOutputCallback =
1253 icvEncodedFrameOutputCallback;
1254 encoded_frame_output_record.encodedFrameOutputRefCon =
1255 static_cast<void*>( video_writer );
1256 encoded_frame_output_record.frameDataAllocator = NULL;
1258 err = ICMCompressionSessionCreate( kCFAllocatorDefault, frame_size.width,
1259 frame_size.height, codecType, TIME_SCALE, options_ref,
1260 NULL /*source_pixel_buffer_attributes*/, &encoded_frame_output_record,
1261 &compression_session_ref );
1262 ICMCompressionSessionOptionsRelease( options_ref );
1263 if ( err != noErr ) {
1264 CV_ERROR( CV_StsInternal, "Cannot create compression session" );
1267 err = BeginMediaEdits( video );
1268 if ( err != noErr ) {
1269 CV_ERROR( CV_StsInternal, "Cannot begin media edits" );
1272 // fill in the video writer structure
1273 video_writer->data_handler = data_handler;
1274 video_writer->movie = movie;
1275 video_writer->track = video_track;
1276 video_writer->video = video;
1277 video_writer->compression_session_ref = compression_session_ref;
1278 video_writer->duration_per_sample =
1279 static_cast<TimeValue>( static_cast<double>( TIME_SCALE ) / fps );
1283 // clean up in case of error (unless error processing mode is
1285 if ( err != noErr ) {
1286 if ( options_ref != NULL ) {
1287 ICMCompressionSessionOptionsRelease( options_ref );
1289 if ( compression_session_ref != NULL ) {
1290 ICMCompressionSessionRelease( compression_session_ref );
1292 if ( data_handler != NULL ) {
1293 CloseMovieStorage( data_handler );
1295 if ( movie != NULL ) {
1296 DisposeMovie( movie );
1298 if ( data_ref != NULL ) {
1299 DeleteMovieStorage( data_ref, data_ref_type );
1300 DisposeHandle( data_ref );
1302 cvFree( reinterpret_cast<void**>( &video_writer ) );
1303 video_writer = NULL;
1306 return reinterpret_cast<CvVideoWriter*>( video_writer );
1309 CV_IMPL int cvWriteFrame(
1310 CvVideoWriter * writer,
1311 const IplImage * image
1313 CvVideoWriter_QT* video_writer =
1314 reinterpret_cast<CvVideoWriter_QT*>( writer );
1316 CVPixelBufferRef pixel_buffer_ref = NULL;
1318 CVPixelBufferCreate(
1319 kCFAllocatorDefault,
1320 image->width, image->height, k24RGBPixelFormat,
1321 NULL /* pixel_buffer_attributes */,
1325 // convert BGR IPL image to RGB pixel buffer
1326 IplImage* image_rgb =
1327 cvCreateImageHeader(
1328 cvSize( image->width, image->height ),
1333 retval = CVPixelBufferLockBaseAddress( pixel_buffer_ref, 0 );
1335 void* base_address = CVPixelBufferGetBaseAddress( pixel_buffer_ref );
1336 size_t bytes_per_row = CVPixelBufferGetBytesPerRow( pixel_buffer_ref );
1337 cvSetData( image_rgb, base_address, bytes_per_row );
1339 cvConvertImage( image, image_rgb, CV_CVTIMG_SWAP_RB );
1341 retval = CVPixelBufferUnlockBaseAddress( pixel_buffer_ref, 0 );
1343 cvReleaseImageHeader( &image_rgb );
1345 ICMSourceTrackingCallbackRecord source_tracking_callback_record;
1346 source_tracking_callback_record.sourceTrackingCallback =
1347 icvSourceTrackingCallback;
1348 source_tracking_callback_record.sourceTrackingRefCon = NULL;
1351 ICMCompressionSessionEncodeFrame(
1352 video_writer->compression_session_ref,
1355 video_writer->duration_per_sample,
1356 kICMValidTime_DisplayDurationIsValid,
1358 &source_tracking_callback_record,
1359 static_cast<void*>( &pixel_buffer_ref )
1365 CV_IMPL void cvReleaseVideoWriter( CvVideoWriter ** writer ) {
1366 if ( ( writer != NULL ) && ( *writer != NULL ) ) {
1367 CvVideoWriter_QT* video_writer =
1368 reinterpret_cast<CvVideoWriter_QT*>( *writer );
1370 // force compression session to complete encoding of outstanding source
1372 ICMCompressionSessionCompleteFrames(
1373 video_writer->compression_session_ref, TRUE, 0, 0
1376 EndMediaEdits( video_writer->video );
1378 ICMCompressionSessionRelease( video_writer->compression_session_ref );
1380 InsertMediaIntoTrack(
1381 video_writer->track,
1384 GetMediaDuration( video_writer->video ),
1388 UpdateMovieInStorage( video_writer->movie, video_writer->data_handler );
1390 CloseMovieStorage( video_writer->data_handler );
1395 OSType data_ref_type;
1396 QTNewDataReferenceFromFullPathCFString(
1397 CFSTR( "/Users/seibert/Desktop/test.avi" ), kQTPOSIXPathStyle, 0,
1398 &data_ref, &data_ref_type
1401 ConvertMovieToDataRef( video_writer->movie, NULL, data_ref,
1402 data_ref_type, kQTFileTypeAVI, 'TVOD', 0, NULL );
1404 DisposeHandle( data_ref );
1407 DisposeMovie( video_writer->movie );
1409 cvFree( reinterpret_cast<void**>( &video_writer ) );
1414 OSStatus icvEncodedFrameOutputCallback(
1416 ICMCompressionSessionRef compression_session_ref,
1418 ICMEncodedFrameRef encoded_frame_ref,
1421 CvVideoWriter_QT* video_writer = static_cast<CvVideoWriter_QT*>( writer );
1423 OSStatus err = AddMediaSampleFromEncodedFrame( video_writer->video,
1424 encoded_frame_ref, NULL );
1429 void icvSourceTrackingCallback(
1430 void *source_tracking_ref_con,
1431 ICMSourceTrackingFlags source_tracking_flags,
1432 void *source_frame_ref_con,
1435 if ( source_tracking_flags & kICMSourceTracking_ReleasedPixelBuffer ) {
1436 CVPixelBufferRelease(
1437 *static_cast<CVPixelBufferRef*>( source_frame_ref_con )