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 Movie myMovie; // movie handle
77 GWorldPtr myGWorld; // we render into an offscreen GWorld
79 CvSize size; // dimensions of the movie
80 TimeValue movie_start_time; // movies can start at arbitrary times
81 long number_of_frames; // duration in frames
83 long next_frame_number;
85 IplImage * image_rgb; // will point to the PixMap of myGWorld
86 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
91 static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename);
92 static int icvClose_QT_Movie (CvCapture_QT_Movie * capture);
93 static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id);
94 static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value);
95 static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture);
96 static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int);
99 static CvCapture_QT_Movie * icvCaptureFromFile_QT (const char * filename)
101 static int did_enter_movies = 0;
102 if (! did_enter_movies)
105 did_enter_movies = 1;
108 CvCapture_QT_Movie * capture = 0;
112 capture = (CvCapture_QT_Movie *) cvAlloc (sizeof (*capture));
113 memset (capture, 0, sizeof(*capture));
115 if (!icvOpenFile_QT_Movie (capture, filename))
125 * convert full path to CFStringRef and open corresponding Movie. Then
126 * step over 'interesting frame times' to count total number of frames
127 * for video material with varying frame durations and create offscreen
128 * GWorld for rendering the movie frames.
130 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
133 static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename)
137 Handle myDataRef = nil;
138 OSType myDataRefType = 0;
142 // no old errors please
143 ClearMoviesStickyError ();
145 // initialize pointers to zero
146 capture->myMovie = 0;
147 capture->myGWorld = nil;
149 // initialize numbers with invalid values
150 capture->next_frame_time = -1;
151 capture->next_frame_number = -1;
152 capture->number_of_frames = -1;
153 capture->movie_start_time = -1;
154 capture->size = cvSize (-1,-1);
157 // we would use CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, filename) on Mac OS X 10.4
158 CFStringRef inPath = CFStringCreateWithCString (kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1);
159 OPENCV_ASSERT ((inPath != nil), "icvOpenFile_QT_Movie", "couldnt create CFString from a string");
161 // create the data reference
162 myErr = QTNewDataReferenceFromFullPathCFString (inPath, kQTPOSIXPathStyle, 0, & myDataRef, & myDataRefType);
165 fprintf (stderr, "Couldn't create QTNewDataReferenceFromFullPathCFString().\n");
170 myErr = NewMovieFromDataRef(& capture->myMovie, newMovieActive | newMovieAsyncOK /* | newMovieIdleImportOK */,
171 & myResID, myDataRef, myDataRefType);
173 // dispose of the data reference handle - we no longer need it
174 DisposeHandle (myDataRef);
176 // if NewMovieFromDataRef failed, we already disposed the DataRef, so just return with an error
179 fprintf (stderr, "Couldn't create a NewMovieFromDataRef() - error is %d.\n", myErr);
183 // count the number of video 'frames' in the movie by stepping through all of the
184 // video 'interesting times', or in other words, the places where the movie displays
185 // a new video sample. The time between these interesting times is not necessarily constant.
187 OSType whichMediaType = VisualMediaCharacteristic;
188 TimeValue theTime = -1;
190 // find out movie start time
191 GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample + nextTimeEdgeOK),
192 1, & whichMediaType, TimeValue (0), 0, & theTime, NULL);
195 fprintf (stderr, "Couldn't inquire first frame time\n");
198 capture->movie_start_time = theTime;
199 capture->next_frame_time = theTime;
200 capture->next_frame_number = 0;
202 // count all 'interesting times' of the movie
203 capture->number_of_frames = 0;
206 GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample),
207 1, & whichMediaType, theTime, 0, & theTime, NULL);
208 capture->number_of_frames++;
212 // get the bounding rectangle of the movie
214 GetMovieBox (capture->myMovie, & myRect);
215 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
217 // create gworld for decompressed image
218 myErr = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat /* k24BGRPixelFormat geht leider nicht */,
219 & myRect, nil, nil, 0);
220 OPENCV_ASSERT (myErr == noErr, "icvOpenFile_QT_Movie", "couldnt create QTNewGWorld() for output image");
221 SetMovieGWorld (capture->myMovie, capture->myGWorld, nil);
223 // build IplImage header that will point to the PixMap of the Movie's GWorld later on
224 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
226 // create IplImage that hold correctly formatted result
227 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
229 // okay, that's it - should we wait until the Movie is playable?
234 * dispose of QuickTime Movie and free memory buffers
236 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
239 static int icvClose_QT_Movie (CvCapture_QT_Movie * capture)
241 OPENCV_ASSERT (capture, "icvClose_QT_Movie", "'capture' is a NULL-pointer");
243 // deallocate and free resources
244 if (capture->myMovie)
246 cvReleaseImage (& capture->image_bgr);
247 cvReleaseImageHeader (& capture->image_rgb);
248 DisposeGWorld (capture->myGWorld);
249 DisposeMovie (capture->myMovie);
257 * get a capture property
259 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
262 static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id)
264 OPENCV_ASSERT (capture, "icvGetProperty_QT_Movie", "'capture' is a NULL-pointer");
265 OPENCV_ASSERT (capture->myMovie, "icvGetProperty_QT_Movie", "invalid Movie handle");
266 OPENCV_ASSERT (capture->number_of_frames > 0, "icvGetProperty_QT_Movie", "movie has invalid number of frames");
267 OPENCV_ASSERT (capture->movie_start_time >= 0, "icvGetProperty_QT_Movie", "movie has invalid start time");
269 // inquire desired property
272 case CV_CAP_PROP_POS_FRAMES:
273 return (capture->next_frame_number);
275 case CV_CAP_PROP_POS_MSEC:
276 case CV_CAP_PROP_POS_AVI_RATIO:
278 TimeValue position = capture->next_frame_time - capture->movie_start_time;
280 if (property_id == CV_CAP_PROP_POS_MSEC)
282 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
283 return (static_cast<double> (position) * 1000.0 / timescale);
287 TimeValue duration = GetMovieDuration (capture->myMovie);
288 return (static_cast<double> (position) / duration);
291 break; // never reached
293 case CV_CAP_PROP_FRAME_WIDTH:
294 return static_cast<double> (capture->size.width);
296 case CV_CAP_PROP_FRAME_HEIGHT:
297 return static_cast<double> (capture->size.height);
299 case CV_CAP_PROP_FPS:
301 TimeValue duration = GetMovieDuration (capture->myMovie);
302 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
304 return (capture->number_of_frames / (static_cast<double> (duration) / timescale));
307 case CV_CAP_PROP_FRAME_COUNT:
308 return static_cast<double> (capture->number_of_frames);
310 case CV_CAP_PROP_FOURCC: // not implemented
311 case CV_CAP_PROP_FORMAT: // not implemented
312 case CV_CAP_PROP_MODE: // not implemented
314 // unhandled or unknown capture property
315 OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
323 * set a capture property. With movie files, it is only possible to set the
324 * position (i.e. jump to a given time or frame number)
326 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
329 static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value)
331 OPENCV_ASSERT (capture, "icvSetProperty_QT_Movie", "'capture' is a NULL-pointer");
332 OPENCV_ASSERT (capture->myMovie, "icvSetProperty_QT_Movie", "invalid Movie handle");
333 OPENCV_ASSERT (capture->number_of_frames > 0, "icvSetProperty_QT_Movie", "movie has invalid number of frames");
334 OPENCV_ASSERT (capture->movie_start_time >= 0, "icvSetProperty_QT_Movie", "movie has invalid start time");
336 // inquire desired property
338 // rework these three points to really work through 'interesting times'.
339 // with the current implementation, they result in wrong times or wrong frame numbers with content that
340 // features varying frame durations
343 case CV_CAP_PROP_POS_MSEC:
344 case CV_CAP_PROP_POS_AVI_RATIO:
346 TimeValue destination;
347 OSType myType = VisualMediaCharacteristic;
350 if (property_id == CV_CAP_PROP_POS_MSEC)
352 TimeScale timescale = GetMovieTimeScale (capture->myMovie);
353 destination = static_cast<TimeValue> (value / 1000.0 * timescale + capture->movie_start_time);
357 TimeValue duration = GetMovieDuration (capture->myMovie);
358 destination = static_cast<TimeValue> (value * duration + capture->movie_start_time);
362 if (capture->next_frame_time == destination)
365 // seek into which direction?
366 if (capture->next_frame_time < destination)
368 while (capture->next_frame_time < destination)
370 capture->next_frame_number++;
371 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
372 1, & capture->next_frame_time, NULL);
373 myErr = GetMoviesError();
376 fprintf (stderr, "Couldn't go on to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
383 while (capture->next_frame_time > destination)
385 capture->next_frame_number--;
386 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
387 -1, & capture->next_frame_time, NULL);
388 myErr = GetMoviesError();
391 fprintf (stderr, "Couldn't go back to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
399 case CV_CAP_PROP_POS_FRAMES:
401 TimeValue destination = static_cast<TimeValue> (value);
402 short direction = (destination > capture->next_frame_number) ? 1 : -1;
403 OSType myType = VisualMediaCharacteristic;
406 while (destination != capture->next_frame_number)
408 capture->next_frame_number += direction;
409 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
410 direction, & capture->next_frame_time, NULL);
411 myErr = GetMoviesError();
414 fprintf (stderr, "Couldn't step to desired frame number in icvGrabFrame_QT.\n");
422 // unhandled or unknown capture property
423 OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
427 // positive result means success
432 * the original meaning of this method is to acquire raw frame data for the next video
433 * frame but not decompress it. With the QuickTime video reader, this is reduced to
434 * advance to the current frame time.
436 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
439 static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture)
441 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Movie", "'capture' is a NULL-pointer");
442 OPENCV_ASSERT (capture->myMovie, "icvGrabFrame_QT_Movie", "invalid Movie handle");
444 TimeValue myCurrTime;
445 OSType myType = VisualMediaCharacteristic;
449 // jump to current video sample
450 SetMovieTimeValue (capture->myMovie, capture->next_frame_time);
451 myErr = GetMoviesError();
454 fprintf (stderr, "Couldn't SetMovieTimeValue() in icvGrabFrame_QT_Movie.\n");
459 myCurrTime = GetMovieTime (capture->myMovie, NULL);
461 // increment counters
462 capture->next_frame_number++;
463 GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, myCurrTime, 1, & capture->next_frame_time, NULL);
464 myErr = GetMoviesError();
467 fprintf (stderr, "Couldn't GetMovieNextInterestingTime() in icvGrabFrame_QT_Movie.\n");
476 * render the current frame into an image buffer and convert to OpenCV IplImage
477 * buffer layout (BGR sampling)
479 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
482 static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int)
484 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Movie", "'capture' is a NULL-pointer");
485 OPENCV_ASSERT (capture->myMovie, "icvRetrieveFrame_QT_Movie", "invalid Movie handle");
486 OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Movie", "invalid source image");
487 OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Movie", "invalid destination image");
489 PixMapHandle myPixMapHandle = nil;
493 // invalidates the movie's display state so that the Movie Toolbox
494 // redraws the movie the next time we call MoviesTask
495 UpdateMovie (capture->myMovie);
496 myErr = GetMoviesError ();
499 fprintf (stderr, "Couldn't UpdateMovie() in icvRetrieveFrame_QT_Movie().\n");
503 // service active movie (= redraw immediately)
504 MoviesTask (capture->myMovie, 0L);
505 myErr = GetMoviesError ();
508 fprintf (stderr, "MoviesTask() didn't succeed in icvRetrieveFrame_QT_Movie().\n");
512 // update IplImage header that points to PixMap of the Movie's GWorld.
513 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
514 // so we pass a modfied address.
515 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
516 myPixMapHandle = GetGWorldPixMap (capture->myGWorld);
517 LockPixels (myPixMapHandle);
518 cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
520 // covert RGB of GWorld to BGR
521 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
523 // allow QuickTime to access the buffer again
524 UnlockPixels (myPixMapHandle);
526 // always return the same image pointer
527 return capture->image_bgr;
531 // ----------------------------------------------------------------------------------------
533 #pragma mark Capturing from Video Cameras
535 #ifdef USE_VDIG_VERSION
537 /// SequenceGrabber state structure for QuickTime
538 typedef struct CvCapture_QT_Cam_vdig
540 ComponentInstance grabber;
546 long number_of_frames;
548 IplImage * image_rgb; // will point to the PixMap of myGWorld
549 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
555 typedef struct CvCapture_QT_Cam_barg
557 SeqGrabComponent grabber;
561 ImageSequence sequence;
563 volatile bool got_frame;
566 IplImage * image_rgb; // will point to the PixMap of myGWorld
567 IplImage * image_bgr; // will be returned by icvRetrieveFrame_QT()
573 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index);
574 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture);
575 static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id);
576 static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value);
577 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture);
578 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int);
582 * Initialize memory structure and call method to open camera
584 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
587 static CvCapture_QT_Cam * icvCaptureFromCam_QT (const int index)
589 if (! did_enter_movies)
592 did_enter_movies = 1;
595 CvCapture_QT_Cam * capture = 0;
599 capture = (CvCapture_QT_Cam *) cvAlloc (sizeof (*capture));
600 memset (capture, 0, sizeof(*capture));
602 if (!icvOpenCamera_QT (capture, index))
609 /// capture properties currently unimplemented for QuickTime camera interface
610 static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id)
616 /// capture properties currently unimplemented for QuickTime camera interface
617 static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value)
623 #ifdef USE_VDIG_VERSION
624 #pragma mark Capturing using VDIG
627 * Open a quicktime video grabber component. This could be an attached
628 * IEEE1394 camera, a web cam, an iSight or digitizer card / video converter.
630 * @author Mark Asbach <asbach@ient.rwth-aachen.de>
633 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
635 OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
636 OPENCV_ASSERT (index >=0, "icvOpenCamera_QT", "camera index is negative");
638 ComponentDescription component_description;
639 Component component = 0;
640 int number_of_inputs = 0;
642 ComponentResult result = noErr;
645 // travers all components and count video digitizer channels
646 component_description.componentType = videoDigitizerComponentType;
647 component_description.componentSubType = 0L;
648 component_description.componentManufacturer = 0L;
649 component_description.componentFlags = 0L;
650 component_description.componentFlagsMask = 0L;
653 // traverse component list
654 component = FindNextComponent (component, & component_description);
656 // found a component?
659 // dump component name
661 ComponentDescription desc;
662 Handle nameHandle = NewHandleClear (200);
663 char nameBuffer [255];
665 result = GetComponentInfo (component, & desc, nameHandle, nil, nil);
666 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt GetComponentInfo()");
667 OPENCV_ASSERT (*nameHandle, "icvOpenCamera_QT", "No name returned by GetComponentInfo()");
668 snprintf (nameBuffer, (**nameHandle) + 1, "%s", (char *) (* nameHandle + 1));
669 printf ("- Videodevice: %s\n", nameBuffer);
670 DisposeHandle (nameHandle);
673 // open component to count number of inputs
674 capture->grabber = OpenComponent (component);
675 if (capture->grabber)
677 result = VDGetNumberOfInputs (capture->grabber, & capture->channel);
679 fprintf (stderr, "Couldnt GetNumberOfInputs: %d\n", (int) result);
683 printf (" Number of inputs: %d\n", (int) capture->channel + 1);
686 // add to overall number of inputs
687 number_of_inputs += capture->channel + 1;
689 // did the user select an input that falls into this device's
690 // range of inputs? Then leave the loop
691 if (number_of_inputs > index)
693 // calculate relative channel index
694 capture->channel = index - number_of_inputs + capture->channel + 1;
695 OPENCV_ASSERT (capture->channel >= 0, "icvOpenCamera_QT", "negative channel number");
702 result = VDGetInputName (capture->grabber, capture->channel, nameBuffer);
703 OPENCV_ASSERT (result == noErr, "ictOpenCamera_QT", "couldnt GetInputName()");
704 snprintf (name, *nameBuffer, "%s", (char *) (nameBuffer + 1));
705 printf (" Choosing input %d - %s\n", (int) capture->channel, name);
713 // obviously no inputs of this device/component were needed
714 CloseComponent (capture->grabber);
720 // did we find the desired input?
723 fprintf(stderr, "Not enough inputs available - can't choose input %d\n", index);
727 // -- Okay now, we selected the digitizer input, lets set up digitizer destination --
729 ClearMoviesStickyError();
731 // Select the desired input
732 result = VDSetInput (capture->grabber, capture->channel);
733 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt select video digitizer input");
735 // get the bounding rectangle of the video digitizer
736 result = VDGetActiveSrcRect (capture->grabber, capture->channel, & myRect);
737 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
738 myRect.right = 640; myRect.bottom = 480;
739 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
740 printf ("Source rect is %d, %d -- %d, %d\n", (int) myRect.left, (int) myRect.top, (int) myRect.right, (int) myRect.bottom);
742 // create offscreen GWorld
743 result = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat, & myRect, nil, nil, 0);
744 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create QTNewGWorld() for output image");
747 capture->pixmap = GetGWorldPixMap (capture->myGWorld);
748 result = GetMoviesError ();
749 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get pixmap");
751 // set digitizer rect
752 result = VDSetDigitizerRect (capture->grabber, & myRect);
753 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
755 // set destination of digitized input
756 result = VDSetPlayThruDestination (capture->grabber, capture->pixmap, & myRect, nil, nil);
757 printf ("QuickTime error: %d\n", (int) result);
758 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video destination");
760 // get destination of digitized images
761 result = VDGetPlayThruDestination (capture->grabber, & capture->pixmap, nil, nil, nil);
762 printf ("QuickTime error: %d\n", (int) result);
763 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get video destination");
764 OPENCV_ASSERT (capture->pixmap != nil, "icvOpenCamera_QT", "empty set video destination");
766 // get the bounding rectangle of the video digitizer
767 GetPixBounds (capture->pixmap, & myRect);
768 capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
770 // build IplImage header that will point to the PixMap of the Movie's GWorld later on
771 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
772 OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
774 // create IplImage that hold correctly formatted result
775 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
776 OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
778 // notify digitizer component, that we well be starting grabbing soon
779 result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureIsForRecord | vdFlagCaptureStarting | vdFlagCaptureLowLatency);
780 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
787 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
789 OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
791 ComponentResult result = noErr;
793 // notify digitizer component, that we well be stopping grabbing soon
794 result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureStopping);
795 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
798 cvReleaseImage (& capture->image_bgr);
799 cvReleaseImageHeader (& capture->image_rgb);
800 DisposeGWorld (capture->myGWorld);
801 CloseComponent (capture->grabber);
807 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
809 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
810 OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
812 ComponentResult result = noErr;
815 result = VDGrabOneFrame (capture->grabber);
818 fprintf (stderr, "VDGrabOneFrame failed\n");
826 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int)
828 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
830 PixMapHandle myPixMapHandle = nil;
832 // update IplImage header that points to PixMap of the Movie's GWorld.
833 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
834 // so we pass a modfied address.
835 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
836 //myPixMapHandle = GetGWorldPixMap (capture->myGWorld);
837 myPixMapHandle = capture->pixmap;
838 LockPixels (myPixMapHandle);
839 cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
841 // covert RGB of GWorld to BGR
842 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
844 // allow QuickTime to access the buffer again
845 UnlockPixels (myPixMapHandle);
847 // always return the same image pointer
848 return capture->image_bgr;
852 #pragma mark Capturing using Sequence Grabber
854 static OSErr icvDataProc_QT_Cam (SGChannel channel, Ptr raw_data, long len, long *, long, TimeValue, short, long refCon)
856 CvCapture_QT_Cam * capture = (CvCapture_QT_Cam *) refCon;
858 ComponentResult err = noErr;
861 // we need valid pointers
862 OPENCV_ASSERT (capture, "icvDataProc_QT_Cam", "'capture' is a NULL-pointer");
863 OPENCV_ASSERT (capture->gworld, "icvDataProc_QT_Cam", "'gworld' is a NULL-pointer");
864 OPENCV_ASSERT (raw_data, "icvDataProc_QT_Cam", "'raw_data' is a NULL-pointer");
866 // create a decompression sequence the first time
867 if (capture->sequence == 0)
869 ImageDescriptionHandle description = (ImageDescriptionHandle) NewHandle(0);
871 // we need a decompression sequence that fits the raw data coming from the camera
872 err = SGGetChannelSampleDescription (channel, (Handle) description);
873 OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt get channel sample description");
874 err = DecompressSequenceBegin (&capture->sequence, description, capture->gworld, 0, &capture->bounds,
875 nil, srcCopy, nil, 0, codecNormalQuality, bestSpeedCodec);
876 OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt begin decompression sequence");
878 DisposeHandle ((Handle) description);
881 // okay, we have a decompression sequence -> decompress!
882 err = DecompressSequenceFrameS (capture->sequence, raw_data, len, 0, &ignore, nil);
885 fprintf (stderr, "icvDataProc_QT_Cam: couldn't decompress frame - %d\n", (int) err);
889 // check if we dropped a frame
891 if (capture->got_frame)
892 fprintf (stderr, "icvDataProc_QT_Cam: frame was dropped\n");
895 // everything worked as expected
896 capture->got_frame = true;
901 static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
903 OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
904 OPENCV_ASSERT (index >= 0, "icvOpenCamera_QT", "camera index is negative");
906 PixMapHandle pixmap = nil;
907 OSErr result = noErr;
909 // open sequence grabber component
910 capture->grabber = OpenDefaultComponent (SeqGrabComponentType, 0);
911 OPENCV_ASSERT (capture->grabber, "icvOpenCamera_QT", "couldnt create image");
913 // initialize sequence grabber component
914 result = SGInitialize (capture->grabber);
915 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt initialize sequence grabber");
916 result = SGSetDataRef (capture->grabber, 0, 0, seqGrabDontMakeMovie);
917 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data reference of sequence grabber");
919 // set up video channel
920 result = SGNewChannel (capture->grabber, VideoMediaType, & (capture->channel));
921 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create new video channel");
923 // select the camera indicated by index
924 SGDeviceList device_list = 0;
925 result = SGGetChannelDeviceList (capture->channel, 0, & device_list);
926 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get channel device list");
927 for (int i = 0, current_index = 1; i < (*device_list)->count; i++)
929 SGDeviceName device = (*device_list)->entry[i];
930 if (device.flags == 0)
932 if (current_index == index)
934 result = SGSetChannelDevice (capture->channel, device.name);
935 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set the channel video device");
941 result = SGDisposeDeviceList (capture->grabber, device_list);
942 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt dispose the channel device list");
944 // query natural camera resolution -- this will be wrong, but will be an upper
945 // bound on the actual resolution -- the actual resolution is set below
946 // after starting the frame grabber
947 result = SGGetSrcVideoBounds (capture->channel, & (capture->bounds));
948 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
950 // create offscreen GWorld
951 result = QTNewGWorld (& (capture->gworld), k32ARGBPixelFormat, & (capture->bounds), 0, 0, 0);
952 result = SGSetGWorld (capture->grabber, capture->gworld, 0);
953 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
954 result = SGSetChannelBounds (capture->channel, & (capture->bounds));
955 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
956 result = SGSetChannelUsage (capture->channel, seqGrabRecord);
957 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set channel usage");
959 // start recording so we can size
960 result = SGStartRecord (capture->grabber);
961 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
963 // don't know *actual* resolution until now
964 ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);
965 result = SGGetChannelSampleDescription(capture->channel, (Handle)imageDesc);
966 OPENCV_ASSERT( result == noErr, "icvOpenCamera_QT", "couldn't get image size");
967 capture->bounds.right = (**imageDesc).width;
968 capture->bounds.bottom = (**imageDesc).height;
969 DisposeHandle ((Handle) imageDesc);
971 // stop grabber so that we can reset the parameters to the right size
972 result = SGStop (capture->grabber);
973 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
975 // reset GWorld to correct image size
977 result = QTNewGWorld( &tmpgworld, k32ARGBPixelFormat, &(capture->bounds), 0, 0, 0);
978 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create offscreen GWorld");
979 result = SGSetGWorld( capture->grabber, tmpgworld, 0);
980 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
981 DisposeGWorld( capture->gworld );
982 capture->gworld = tmpgworld;
984 result = SGSetChannelBounds (capture->channel, & (capture->bounds));
985 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
988 capture->size = cvSize (capture->bounds.right - capture->bounds.left, capture->bounds.bottom - capture->bounds.top);
990 // build IplImage header that points to the PixMap of the Movie's GWorld.
991 // unfortunately, cvCvtColor doesn't know ARGB, the QuickTime pixel format,
992 // so we shift the base address by one byte.
993 // ATTENTION: don't access the last pixel's alpha entry, it's inexistant
994 capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
995 OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
996 pixmap = GetGWorldPixMap (capture->gworld);
997 OPENCV_ASSERT (pixmap, "icvOpenCamera_QT", "didn't get GWorld PixMap handle");
999 cvSetData (capture->image_rgb, GetPixBaseAddr (pixmap) + 1, GetPixRowBytes (pixmap));
1001 // create IplImage that hold correctly formatted result
1002 capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
1003 OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
1006 // tell the sequence grabber to invoke our data proc
1007 result = SGSetDataProc (capture->grabber, NewSGDataUPP (icvDataProc_QT_Cam), (long) capture);
1008 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data proc");
1011 result = SGStartRecord (capture->grabber);
1012 OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
1018 static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
1020 OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
1022 OSErr result = noErr;
1026 result = SGStop (capture->grabber);
1027 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
1029 // close sequence grabber component
1030 result = CloseComponent (capture->grabber);
1031 OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt close sequence grabber component");
1033 // end decompression sequence
1034 CDSequenceEnd (capture->sequence);
1037 cvReleaseImage (& capture->image_bgr);
1038 cvReleaseImageHeader (& capture->image_rgb);
1039 DisposeGWorld (capture->gworld);
1045 static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
1047 OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
1048 OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
1050 ComponentResult result = noErr;
1054 result = SGIdle (capture->grabber);
1055 if (result != noErr)
1057 fprintf (stderr, "SGIdle failed in icvGrabFrame_QT_Cam with error %d\n", (int) result);
1065 static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int)
1067 OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
1068 OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Cam", "invalid source image");
1069 OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Cam", "invalid destination image");
1071 OSErr myErr = noErr;
1074 // service active sequence grabbers (= redraw immediately)
1075 while (! capture->got_frame)
1077 myErr = SGIdle (capture->grabber);
1080 fprintf (stderr, "SGIdle() didn't succeed in icvRetrieveFrame_QT_Cam().\n");
1085 // covert RGB of GWorld to BGR
1086 cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
1088 // reset grabbing status
1089 capture->got_frame = false;
1091 // always return the same image pointer
1092 return capture->image_bgr;
1098 typedef struct CvVideoWriter_QT {
1100 DataHandler data_handler;
1105 ICMCompressionSessionRef compression_session_ref;
1107 TimeValue duration_per_sample;
1111 static TimeScale const TIME_SCALE = 600;
1113 static OSStatus icvEncodedFrameOutputCallback(
1115 ICMCompressionSessionRef compression_session_ref,
1117 ICMEncodedFrameRef encoded_frame_ref,
1121 static void icvSourceTrackingCallback(
1122 void *source_tracking_ref_con,
1123 ICMSourceTrackingFlags source_tracking_flags,
1124 void *source_frame_ref_con,
1128 static int icvWriteFrame_QT(
1129 CvVideoWriter_QT * video_writer,
1130 const IplImage * image
1132 CVPixelBufferRef pixel_buffer_ref = NULL;
1134 CVPixelBufferCreate(
1135 kCFAllocatorDefault,
1136 image->width, image->height, k24RGBPixelFormat,
1137 NULL /* pixel_buffer_attributes */,
1141 // convert BGR IPL image to RGB pixel buffer
1142 IplImage* image_rgb =
1143 cvCreateImageHeader(
1144 cvSize( image->width, image->height ),
1149 retval = CVPixelBufferLockBaseAddress( pixel_buffer_ref, 0 );
1151 void* base_address = CVPixelBufferGetBaseAddress( pixel_buffer_ref );
1152 size_t bytes_per_row = CVPixelBufferGetBytesPerRow( pixel_buffer_ref );
1153 cvSetData( image_rgb, base_address, bytes_per_row );
1155 cvConvertImage( image, image_rgb, CV_CVTIMG_SWAP_RB );
1157 retval = CVPixelBufferUnlockBaseAddress( pixel_buffer_ref, 0 );
1159 cvReleaseImageHeader( &image_rgb );
1161 ICMSourceTrackingCallbackRecord source_tracking_callback_record;
1162 source_tracking_callback_record.sourceTrackingCallback =
1163 icvSourceTrackingCallback;
1164 source_tracking_callback_record.sourceTrackingRefCon = NULL;
1167 ICMCompressionSessionEncodeFrame(
1168 video_writer->compression_session_ref,
1171 video_writer->duration_per_sample,
1172 kICMValidTime_DisplayDurationIsValid,
1174 &source_tracking_callback_record,
1175 static_cast<void*>( &pixel_buffer_ref )
1181 static void icvReleaseVideoWriter_QT( CvVideoWriter_QT ** writer ) {
1182 if ( ( writer != NULL ) && ( *writer != NULL ) ) {
1183 CvVideoWriter_QT* video_writer = *writer;
1185 // force compression session to complete encoding of outstanding source
1187 ICMCompressionSessionCompleteFrames(
1188 video_writer->compression_session_ref, TRUE, 0, 0
1191 EndMediaEdits( video_writer->video );
1193 ICMCompressionSessionRelease( video_writer->compression_session_ref );
1195 InsertMediaIntoTrack(
1196 video_writer->track,
1199 GetMediaDuration( video_writer->video ),
1203 UpdateMovieInStorage( video_writer->movie, video_writer->data_handler );
1205 CloseMovieStorage( video_writer->data_handler );
1210 OSType data_ref_type;
1211 QTNewDataReferenceFromFullPathCFString(
1212 CFSTR( "/Users/seibert/Desktop/test.avi" ), kQTPOSIXPathStyle, 0,
1213 &data_ref, &data_ref_type
1216 ConvertMovieToDataRef( video_writer->movie, NULL, data_ref,
1217 data_ref_type, kQTFileTypeAVI, 'TVOD', 0, NULL );
1219 DisposeHandle( data_ref );
1222 DisposeMovie( video_writer->movie );
1228 static OSStatus icvEncodedFrameOutputCallback(
1230 ICMCompressionSessionRef compression_session_ref,
1232 ICMEncodedFrameRef encoded_frame_ref,
1235 CvVideoWriter_QT* video_writer = static_cast<CvVideoWriter_QT*>( writer );
1237 OSStatus err = AddMediaSampleFromEncodedFrame( video_writer->video,
1238 encoded_frame_ref, NULL );
1243 static void icvSourceTrackingCallback(
1244 void *source_tracking_ref_con,
1245 ICMSourceTrackingFlags source_tracking_flags,
1246 void *source_frame_ref_con,
1249 if ( source_tracking_flags & kICMSourceTracking_ReleasedPixelBuffer ) {
1250 CVPixelBufferRelease(
1251 *static_cast<CVPixelBufferRef*>( source_frame_ref_con )
1257 static CvVideoWriter_QT* icvCreateVideoWriter_QT(
1258 const char * filename,
1264 CV_FUNCNAME( "icvCreateVideoWriter" );
1266 CvVideoWriter_QT* video_writer =
1267 static_cast<CvVideoWriter_QT*>( cvAlloc( sizeof( CvVideoWriter_QT ) ) );
1268 memset( video_writer, 0, sizeof( CvVideoWriter_QT ) );
1270 Handle data_ref = NULL;
1271 OSType data_ref_type;
1272 DataHandler data_handler = NULL;
1274 ICMCompressionSessionOptionsRef options_ref = NULL;
1275 ICMCompressionSessionRef compression_session_ref = NULL;
1276 CFStringRef out_path = nil;
1277 Track video_track = nil;
1283 // validate input arguments
1284 if ( filename == NULL ) {
1285 CV_ERROR( CV_StsBadArg, "Video file name must not be NULL" );
1288 CV_ERROR( CV_StsBadArg, "FPS must be larger than 0.0" );
1290 if ( ( frame_size.width <= 0 ) || ( frame_size.height <= 0 ) ) {
1291 CV_ERROR( CV_StsBadArg,
1292 "Frame width and height must be larger than 0" );
1295 // initialize QuickTime
1296 if ( !did_enter_movies ) {
1297 err = EnterMovies();
1298 if ( err != noErr ) {
1299 CV_ERROR( CV_StsInternal, "Unable to initialize QuickTime" );
1301 did_enter_movies = 1;
1304 // convert the file name into a data reference
1305 out_path = CFStringCreateWithCString( kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1 );
1306 CV_ASSERT( out_path != nil );
1307 err = QTNewDataReferenceFromFullPathCFString( out_path, kQTPOSIXPathStyle,
1308 0, &data_ref, &data_ref_type );
1309 CFRelease( out_path );
1310 if ( err != noErr ) {
1311 CV_ERROR( CV_StsInternal,
1312 "Cannot create data reference from file name" );
1315 // create a new movie on disk
1316 err = CreateMovieStorage( data_ref, data_ref_type, 'TVOD',
1317 smCurrentScript, newMovieActive, &data_handler, &movie );
1319 if ( err != noErr ) {
1320 CV_ERROR( CV_StsInternal, "Cannot create movie storage" );
1323 // create a track with video
1324 video_track = NewMovieTrack (movie,
1325 FixRatio( frame_size.width, 1 ),
1326 FixRatio( frame_size.height, 1 ),
1328 err = GetMoviesError();
1329 if ( err != noErr ) {
1330 CV_ERROR( CV_StsInternal, "Cannot create video track" );
1332 video = NewTrackMedia( video_track, VideoMediaType, TIME_SCALE, nil, 0 );
1333 err = GetMoviesError();
1334 if ( err != noErr ) {
1335 CV_ERROR( CV_StsInternal, "Cannot create video media" );
1338 CodecType codecType;
1340 case CV_FOURCC( 'D', 'I', 'B', ' ' ):
1341 codecType = kRawCodecType;
1344 codecType = kRawCodecType;
1348 // start a compression session
1349 err = ICMCompressionSessionOptionsCreate( kCFAllocatorDefault,
1351 if ( err != noErr ) {
1352 CV_ERROR( CV_StsInternal, "Cannot create compression session options" );
1354 err = ICMCompressionSessionOptionsSetAllowTemporalCompression( options_ref,
1356 if ( err != noErr) {
1357 CV_ERROR( CV_StsInternal, "Cannot enable temporal compression" );
1359 err = ICMCompressionSessionOptionsSetAllowFrameReordering( options_ref,
1361 if ( err != noErr) {
1362 CV_ERROR( CV_StsInternal, "Cannot enable frame reordering" );
1365 ICMEncodedFrameOutputRecord encoded_frame_output_record;
1366 encoded_frame_output_record.encodedFrameOutputCallback =
1367 icvEncodedFrameOutputCallback;
1368 encoded_frame_output_record.encodedFrameOutputRefCon =
1369 static_cast<void*>( video_writer );
1370 encoded_frame_output_record.frameDataAllocator = NULL;
1372 err = ICMCompressionSessionCreate( kCFAllocatorDefault, frame_size.width,
1373 frame_size.height, codecType, TIME_SCALE, options_ref,
1374 NULL /*source_pixel_buffer_attributes*/, &encoded_frame_output_record,
1375 &compression_session_ref );
1376 ICMCompressionSessionOptionsRelease( options_ref );
1377 if ( err != noErr ) {
1378 CV_ERROR( CV_StsInternal, "Cannot create compression session" );
1381 err = BeginMediaEdits( video );
1382 if ( err != noErr ) {
1383 CV_ERROR( CV_StsInternal, "Cannot begin media edits" );
1386 // fill in the video writer structure
1387 video_writer->data_handler = data_handler;
1388 video_writer->movie = movie;
1389 video_writer->track = video_track;
1390 video_writer->video = video;
1391 video_writer->compression_session_ref = compression_session_ref;
1392 video_writer->duration_per_sample =
1393 static_cast<TimeValue>( static_cast<double>( TIME_SCALE ) / fps );
1397 // clean up in case of error (unless error processing mode is
1399 if ( err != noErr ) {
1400 if ( options_ref != NULL ) {
1401 ICMCompressionSessionOptionsRelease( options_ref );
1403 if ( compression_session_ref != NULL ) {
1404 ICMCompressionSessionRelease( compression_session_ref );
1406 if ( data_handler != NULL ) {
1407 CloseMovieStorage( data_handler );
1409 if ( movie != NULL ) {
1410 DisposeMovie( movie );
1412 if ( data_ref != NULL ) {
1413 DeleteMovieStorage( data_ref, data_ref_type );
1414 DisposeHandle( data_ref );
1416 cvFree( reinterpret_cast<void**>( &video_writer ) );
1417 video_writer = NULL;
1420 return video_writer;
1426 * Wrappers for the new C++ CvCapture & CvVideoWriter structures
1430 class CvCapture_QT_Movie_CPP : public CvCapture
1433 CvCapture_QT_Movie_CPP() { captureQT = 0; }
1434 virtual ~CvCapture_QT_Movie_CPP() { close(); }
1436 virtual bool open( const char* filename );
1437 virtual void close();
1439 virtual double getProperty(int);
1440 virtual bool setProperty(int, double);
1441 virtual bool grabFrame();
1442 virtual IplImage* retrieveFrame(int);
1443 virtual int getCaptureDomain() { return CV_CAP_QT; } // Return the type of the capture object: CV_CAP_VFW, etc...
1446 CvCapture_QT_Movie* captureQT;
1449 bool CvCapture_QT_Movie_CPP::open( const char* filename )
1452 captureQT = icvCaptureFromFile_QT( filename );
1453 return captureQT != 0;
1456 void CvCapture_QT_Movie_CPP::close()
1460 icvClose_QT_Movie( captureQT );
1461 cvFree( &captureQT );
1465 bool CvCapture_QT_Movie_CPP::grabFrame()
1467 return captureQT ? icvGrabFrame_QT_Movie( captureQT ) != 0 : false;
1470 IplImage* CvCapture_QT_Movie_CPP::retrieveFrame(int)
1472 return captureQT ? (IplImage*)icvRetrieveFrame_QT_Movie( captureQT, 0 ) : 0;
1475 double CvCapture_QT_Movie_CPP::getProperty( int propId )
1477 return captureQT ? icvGetProperty_QT_Movie( captureQT, propId ) : 0;
1480 bool CvCapture_QT_Movie_CPP::setProperty( int propId, double value )
1482 return captureQT ? icvSetProperty_QT_Movie( captureQT, propId, value ) != 0 : false;
1485 CvCapture* cvCreateFileCapture_QT( const char* filename )
1487 CvCapture_QT_Movie_CPP* capture = new CvCapture_QT_Movie_CPP;
1489 if( capture->open( filename ))
1497 /////////////////////////////////////
1499 class CvCapture_QT_Cam_CPP : public CvCapture
1502 CvCapture_QT_Cam_CPP() { captureQT = 0; }
1503 virtual ~CvCapture_QT_Cam_CPP() { close(); }
1505 virtual bool open( int index );
1506 virtual void close();
1508 virtual double getProperty(int);
1509 virtual bool setProperty(int, double);
1510 virtual bool grabFrame();
1511 virtual IplImage* retrieveFrame(int);
1512 virtual int getCaptureDomain() { return CV_CAP_QT; } // Return the type of the capture object: CV_CAP_VFW, etc...
1515 CvCapture_QT_Cam* captureQT;
1518 bool CvCapture_QT_Cam_CPP::open( int index )
1521 captureQT = icvCaptureFromCam_QT( index );
1522 return captureQT != 0;
1525 void CvCapture_QT_Cam_CPP::close()
1529 icvClose_QT_Cam( captureQT );
1530 cvFree( &captureQT );
1534 bool CvCapture_QT_Cam_CPP::grabFrame()
1536 return captureQT ? icvGrabFrame_QT_Cam( captureQT ) != 0 : false;
1539 IplImage* CvCapture_QT_Cam_CPP::retrieveFrame(int)
1541 return captureQT ? (IplImage*)icvRetrieveFrame_QT_Cam( captureQT, 0 ) : 0;
1544 double CvCapture_QT_Cam_CPP::getProperty( int propId )
1546 return captureQT ? icvGetProperty_QT_Cam( captureQT, propId ) : 0;
1549 bool CvCapture_QT_Cam_CPP::setProperty( int propId, double value )
1551 return captureQT ? icvSetProperty_QT_Cam( captureQT, propId, value ) != 0 : false;
1554 CvCapture* cvCreateCameraCapture_QT( int index )
1556 CvCapture_QT_Cam_CPP* capture = new CvCapture_QT_Cam_CPP;
1558 if( capture->open( index ))
1565 /////////////////////////////////
1567 class CvVideoWriter_QT_CPP : public CvVideoWriter
1570 CvVideoWriter_QT_CPP() { writerQT = 0; }
1571 virtual ~CvVideoWriter_QT_CPP() { close(); }
1573 virtual bool open( const char* filename, int fourcc,
1574 double fps, CvSize frameSize, bool isColor );
1575 virtual void close();
1576 virtual bool writeFrame( const IplImage* );
1579 CvVideoWriter_QT* writerQT;
1582 bool CvVideoWriter_QT_CPP::open( const char* filename, int fourcc,
1583 double fps, CvSize frameSize, bool isColor )
1586 writerQT = icvCreateVideoWriter_QT( filename, fourcc, fps, frameSize, isColor );
1587 return writerQT != 0;
1590 void CvVideoWriter_QT_CPP::close()
1594 icvReleaseVideoWriter_QT( &writerQT );
1599 bool CvVideoWriter_QT_CPP::writeFrame( const IplImage* image )
1601 if( !writerQT || !image )
1603 return icvWriteFrame_QT( writerQT, image ) >= 0;
1606 CvVideoWriter* cvCreateVideoWriter_QT( const char* filename, int fourcc,
1607 double fps, CvSize frameSize, int isColor )
1609 CvVideoWriter_QT_CPP* writer = new CvVideoWriter_QT_CPP;
1610 if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))