This source file includes following definitions.
- icvCaptureFromFile_QT
- icvOpenFile_QT_Movie
- icvClose_QT_Movie
- icvGetProperty_QT_Movie
- icvSetProperty_QT_Movie
- icvGrabFrame_QT_Movie
- icvRetrieveFrame_QT_Movie
- icvCaptureFromCam_QT
- icvGetProperty_QT_Cam
- icvSetProperty_QT_Cam
- icvOpenCamera_QT
- icvClose_QT_Cam
- icvGrabFrame_QT_Cam
- icvRetrieveFrame_QT_Cam
- icvDataProc_QT_Cam
- icvOpenCamera_QT
- icvClose_QT_Cam
- icvGrabFrame_QT_Cam
- icvRetrieveFrame_QT_Cam
- icvWriteFrame_QT
- icvReleaseVideoWriter_QT
- icvEncodedFrameOutputCallback
- icvSourceTrackingCallback
- icvCreateVideoWriter_QT
- getCaptureDomain
- open
- close
- grabFrame
- retrieveFrame
- getProperty
- setProperty
- cvCreateFileCapture_QT
- getCaptureDomain
- open
- close
- grabFrame
- retrieveFrame
- getProperty
- setProperty
- cvCreateCameraCapture_QT
- open
- close
- writeFrame
- cvCreateVideoWriter_QT
#include "precomp.hpp"
#include <cstdio>
#include <cassert>
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <QuickTime/QuickTime.h>
static int did_enter_movies = 0;
#pragma mark Reading Video Files
typedef struct CvCapture_QT_Movie
{
Movie myMovie;
GWorldPtr myGWorld;
CvSize size;
TimeValue movie_start_time;
long number_of_frames;
long next_frame_time;
long next_frame_number;
IplImage * image_rgb;
IplImage * image_bgr;
} CvCapture_QT_Movie;
static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename);
static int icvClose_QT_Movie (CvCapture_QT_Movie * capture);
static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id);
static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value);
static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture);
static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int);
static CvCapture_QT_Movie * icvCaptureFromFile_QT (const char * filename)
{
static int did_enter_movies = 0;
if (! did_enter_movies)
{
EnterMovies();
did_enter_movies = 1;
}
CvCapture_QT_Movie * capture = 0;
if (filename)
{
capture = (CvCapture_QT_Movie *) cvAlloc (sizeof (*capture));
memset (capture, 0, sizeof(*capture));
if (!icvOpenFile_QT_Movie (capture, filename))
cvFree( &capture );
}
return capture;
}
static int icvOpenFile_QT_Movie (CvCapture_QT_Movie * capture, const char * filename)
{
Rect myRect;
short myResID = 0;
Handle myDataRef = nil;
OSType myDataRefType = 0;
OSErr myErr = noErr;
ClearMoviesStickyError ();
capture->myMovie = 0;
capture->myGWorld = nil;
capture->next_frame_time = -1;
capture->next_frame_number = -1;
capture->number_of_frames = -1;
capture->movie_start_time = -1;
capture->size = cvSize (-1,-1);
CFStringRef inPath = CFStringCreateWithCString (kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1);
OPENCV_ASSERT ((inPath != nil), "icvOpenFile_QT_Movie", "couldnt create CFString from a string");
myErr = QTNewDataReferenceFromFullPathCFString (inPath, kQTPOSIXPathStyle, 0, & myDataRef, & myDataRefType);
if (myErr != noErr)
{
fprintf (stderr, "Couldn't create QTNewDataReferenceFromFullPathCFString().\n");
return 0;
}
myErr = NewMovieFromDataRef(& capture->myMovie, newMovieActive | newMovieAsyncOK ,
& myResID, myDataRef, myDataRefType);
DisposeHandle (myDataRef);
if (myErr != noErr)
{
fprintf (stderr, "Couldn't create a NewMovieFromDataRef() - error is %d.\n", myErr);
return 0;
}
{
OSType whichMediaType = VisualMediaCharacteristic;
TimeValue theTime = -1;
GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample + nextTimeEdgeOK),
1, & whichMediaType, TimeValue (0), 0, & theTime, NULL);
if (theTime == -1)
{
fprintf (stderr, "Couldn't inquire first frame time\n");
return 0;
}
capture->movie_start_time = theTime;
capture->next_frame_time = theTime;
capture->next_frame_number = 0;
capture->number_of_frames = 0;
while (theTime >= 0)
{
GetMovieNextInterestingTime (capture->myMovie, short (nextTimeMediaSample),
1, & whichMediaType, theTime, 0, & theTime, NULL);
capture->number_of_frames++;
}
}
GetMoviesError ();
GetMovieBox (capture->myMovie, & myRect);
capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
myErr = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat ,
& myRect, nil, nil, 0);
OPENCV_ASSERT (myErr == noErr, "icvOpenFile_QT_Movie", "couldnt create QTNewGWorld() for output image");
SetMovieGWorld (capture->myMovie, capture->myGWorld, nil);
capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
return 1;
}
static int icvClose_QT_Movie (CvCapture_QT_Movie * capture)
{
OPENCV_ASSERT (capture, "icvClose_QT_Movie", "'capture' is a NULL-pointer");
if (capture->myMovie)
{
cvReleaseImage (& capture->image_bgr);
cvReleaseImageHeader (& capture->image_rgb);
DisposeGWorld (capture->myGWorld);
DisposeMovie (capture->myMovie);
}
return 1;
}
static double icvGetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id)
{
OPENCV_ASSERT (capture, "icvGetProperty_QT_Movie", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->myMovie, "icvGetProperty_QT_Movie", "invalid Movie handle");
OPENCV_ASSERT (capture->number_of_frames > 0, "icvGetProperty_QT_Movie", "movie has invalid number of frames");
OPENCV_ASSERT (capture->movie_start_time >= 0, "icvGetProperty_QT_Movie", "movie has invalid start time");
switch (property_id)
{
case CV_CAP_PROP_POS_FRAMES:
return (capture->next_frame_number);
case CV_CAP_PROP_POS_MSEC:
case CV_CAP_PROP_POS_AVI_RATIO:
{
TimeValue position = capture->next_frame_time - capture->movie_start_time;
if (property_id == CV_CAP_PROP_POS_MSEC)
{
TimeScale timescale = GetMovieTimeScale (capture->myMovie);
return (static_cast<double> (position) * 1000.0 / timescale);
}
else
{
TimeValue duration = GetMovieDuration (capture->myMovie);
return (static_cast<double> (position) / duration);
}
}
break;
case CV_CAP_PROP_FRAME_WIDTH:
return static_cast<double> (capture->size.width);
case CV_CAP_PROP_FRAME_HEIGHT:
return static_cast<double> (capture->size.height);
case CV_CAP_PROP_FPS:
{
TimeValue duration = GetMovieDuration (capture->myMovie);
TimeScale timescale = GetMovieTimeScale (capture->myMovie);
return (capture->number_of_frames / (static_cast<double> (duration) / timescale));
}
case CV_CAP_PROP_FRAME_COUNT:
return static_cast<double> (capture->number_of_frames);
case CV_CAP_PROP_FOURCC:
case CV_CAP_PROP_FORMAT:
case CV_CAP_PROP_MODE:
default:
OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
return CV_StsBadArg;
}
return 0;
}
static int icvSetProperty_QT_Movie (CvCapture_QT_Movie * capture, int property_id, double value)
{
OPENCV_ASSERT (capture, "icvSetProperty_QT_Movie", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->myMovie, "icvSetProperty_QT_Movie", "invalid Movie handle");
OPENCV_ASSERT (capture->number_of_frames > 0, "icvSetProperty_QT_Movie", "movie has invalid number of frames");
OPENCV_ASSERT (capture->movie_start_time >= 0, "icvSetProperty_QT_Movie", "movie has invalid start time");
switch (property_id)
{
case CV_CAP_PROP_POS_MSEC:
case CV_CAP_PROP_POS_AVI_RATIO:
{
TimeValue destination;
OSType myType = VisualMediaCharacteristic;
OSErr myErr = noErr;
if (property_id == CV_CAP_PROP_POS_MSEC)
{
TimeScale timescale = GetMovieTimeScale (capture->myMovie);
destination = static_cast<TimeValue> (value / 1000.0 * timescale + capture->movie_start_time);
}
else
{
TimeValue duration = GetMovieDuration (capture->myMovie);
destination = static_cast<TimeValue> (value * duration + capture->movie_start_time);
}
if (capture->next_frame_time == destination)
break;
if (capture->next_frame_time < destination)
{
while (capture->next_frame_time < destination)
{
capture->next_frame_number++;
GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
1, & capture->next_frame_time, NULL);
myErr = GetMoviesError();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't go on to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
return 0;
}
}
}
else
{
while (capture->next_frame_time > destination)
{
capture->next_frame_number--;
GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
-1, & capture->next_frame_time, NULL);
myErr = GetMoviesError();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't go back to GetMovieNextInterestingTime() in icvGrabFrame_QT.\n");
return 0;
}
}
}
}
break;
case CV_CAP_PROP_POS_FRAMES:
{
TimeValue destination = static_cast<TimeValue> (value);
short direction = (destination > capture->next_frame_number) ? 1 : -1;
OSType myType = VisualMediaCharacteristic;
OSErr myErr = noErr;
while (destination != capture->next_frame_number)
{
capture->next_frame_number += direction;
GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, capture->next_frame_time,
direction, & capture->next_frame_time, NULL);
myErr = GetMoviesError();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't step to desired frame number in icvGrabFrame_QT.\n");
return 0;
}
}
}
break;
default:
OPENCV_ERROR (CV_StsBadArg, "icvSetProperty_QT_Movie", "unknown or unhandled property_id");
return 0;
}
return 1;
}
static int icvGrabFrame_QT_Movie (CvCapture_QT_Movie * capture)
{
OPENCV_ASSERT (capture, "icvGrabFrame_QT_Movie", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->myMovie, "icvGrabFrame_QT_Movie", "invalid Movie handle");
TimeValue myCurrTime;
OSType myType = VisualMediaCharacteristic;
OSErr myErr = noErr;
SetMovieTimeValue (capture->myMovie, capture->next_frame_time);
myErr = GetMoviesError();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't SetMovieTimeValue() in icvGrabFrame_QT_Movie.\n");
return 0;
}
myCurrTime = GetMovieTime (capture->myMovie, NULL);
capture->next_frame_number++;
GetMovieNextInterestingTime (capture->myMovie, nextTimeStep, 1, & myType, myCurrTime, 1, & capture->next_frame_time, NULL);
myErr = GetMoviesError();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't GetMovieNextInterestingTime() in icvGrabFrame_QT_Movie.\n");
return 0;
}
return 1;
}
static const void * icvRetrieveFrame_QT_Movie (CvCapture_QT_Movie * capture, int)
{
OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Movie", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->myMovie, "icvRetrieveFrame_QT_Movie", "invalid Movie handle");
OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Movie", "invalid source image");
OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Movie", "invalid destination image");
PixMapHandle myPixMapHandle = nil;
OSErr myErr = noErr;
UpdateMovie (capture->myMovie);
myErr = GetMoviesError ();
if (myErr != noErr)
{
fprintf (stderr, "Couldn't UpdateMovie() in icvRetrieveFrame_QT_Movie().\n");
return 0;
}
MoviesTask (capture->myMovie, 0L);
myErr = GetMoviesError ();
if (myErr != noErr)
{
fprintf (stderr, "MoviesTask() didn't succeed in icvRetrieveFrame_QT_Movie().\n");
return 0;
}
myPixMapHandle = GetGWorldPixMap (capture->myGWorld);
LockPixels (myPixMapHandle);
cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
UnlockPixels (myPixMapHandle);
return capture->image_bgr;
}
#pragma mark -
#pragma mark Capturing from Video Cameras
#ifdef USE_VDIG_VERSION
typedef struct CvCapture_QT_Cam_vdig
{
ComponentInstance grabber;
short channel;
GWorldPtr myGWorld;
PixMapHandle pixmap;
CvSize size;
long number_of_frames;
IplImage * image_rgb;
IplImage * image_bgr;
} CvCapture_QT_Cam;
#else
typedef struct CvCapture_QT_Cam_barg
{
SeqGrabComponent grabber;
SGChannel channel;
GWorldPtr gworld;
Rect bounds;
ImageSequence sequence;
volatile bool got_frame;
CvSize size;
IplImage * image_rgb;
IplImage * image_bgr;
} CvCapture_QT_Cam;
#endif
static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index);
static int icvClose_QT_Cam (CvCapture_QT_Cam * capture);
static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id);
static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value);
static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture);
static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int);
static CvCapture_QT_Cam * icvCaptureFromCam_QT (const int index)
{
if (! did_enter_movies)
{
EnterMovies();
did_enter_movies = 1;
}
CvCapture_QT_Cam * capture = 0;
if (index >= 0)
{
capture = (CvCapture_QT_Cam *) cvAlloc (sizeof (*capture));
memset (capture, 0, sizeof(*capture));
if (!icvOpenCamera_QT (capture, index))
cvFree (&capture);
}
return capture;
}
static double icvGetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id)
{
assert (0);
return 0;
}
static int icvSetProperty_QT_Cam (CvCapture_QT_Cam * capture, int property_id, double value)
{
assert (0);
return 0;
}
#ifdef USE_VDIG_VERSION
#pragma mark Capturing using VDIG
static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
{
OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
OPENCV_ASSERT (index >=0, "icvOpenCamera_QT", "camera index is negative");
ComponentDescription component_description;
Component component = 0;
int number_of_inputs = 0;
Rect myRect;
ComponentResult result = noErr;
component_description.componentType = videoDigitizerComponentType;
component_description.componentSubType = 0L;
component_description.componentManufacturer = 0L;
component_description.componentFlags = 0L;
component_description.componentFlagsMask = 0L;
do
{
component = FindNextComponent (component, & component_description);
if (component)
{
#ifndef NDEBUG
ComponentDescription desc;
Handle nameHandle = NewHandleClear (200);
char nameBuffer [255];
result = GetComponentInfo (component, & desc, nameHandle, nil, nil);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt GetComponentInfo()");
OPENCV_ASSERT (*nameHandle, "icvOpenCamera_QT", "No name returned by GetComponentInfo()");
snprintf (nameBuffer, (**nameHandle) + 1, "%s", (char *) (* nameHandle + 1));
printf ("- Videodevice: %s\n", nameBuffer);
DisposeHandle (nameHandle);
#endif
capture->grabber = OpenComponent (component);
if (capture->grabber)
{
result = VDGetNumberOfInputs (capture->grabber, & capture->channel);
if (result != noErr)
fprintf (stderr, "Couldnt GetNumberOfInputs: %d\n", (int) result);
else
{
#ifndef NDEBUG
printf (" Number of inputs: %d\n", (int) capture->channel + 1);
#endif
number_of_inputs += capture->channel + 1;
if (number_of_inputs > index)
{
capture->channel = index - number_of_inputs + capture->channel + 1;
OPENCV_ASSERT (capture->channel >= 0, "icvOpenCamera_QT", "negative channel number");
#ifndef NDEBUG
char name[256];
Str255 nameBuffer;
result = VDGetInputName (capture->grabber, capture->channel, nameBuffer);
OPENCV_ASSERT (result == noErr, "ictOpenCamera_QT", "couldnt GetInputName()");
snprintf (name, *nameBuffer, "%s", (char *) (nameBuffer + 1));
printf (" Choosing input %d - %s\n", (int) capture->channel, name);
#endif
break;
}
}
CloseComponent (capture->grabber);
}
}
}
while (component);
if (! component)
{
fprintf(stderr, "Not enough inputs available - can't choose input %d\n", index);
return 0;
}
ClearMoviesStickyError();
result = VDSetInput (capture->grabber, capture->channel);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt select video digitizer input");
result = VDGetActiveSrcRect (capture->grabber, capture->channel, & myRect);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
myRect.right = 640; myRect.bottom = 480;
capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
printf ("Source rect is %d, %d -- %d, %d\n", (int) myRect.left, (int) myRect.top, (int) myRect.right, (int) myRect.bottom);
result = QTNewGWorld (& capture->myGWorld, k32ARGBPixelFormat, & myRect, nil, nil, 0);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create QTNewGWorld() for output image");
capture->pixmap = GetGWorldPixMap (capture->myGWorld);
result = GetMoviesError ();
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get pixmap");
result = VDSetDigitizerRect (capture->grabber, & myRect);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create VDGetActiveSrcRect from digitizer");
result = VDSetPlayThruDestination (capture->grabber, capture->pixmap, & myRect, nil, nil);
printf ("QuickTime error: %d\n", (int) result);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video destination");
result = VDGetPlayThruDestination (capture->grabber, & capture->pixmap, nil, nil, nil);
printf ("QuickTime error: %d\n", (int) result);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get video destination");
OPENCV_ASSERT (capture->pixmap != nil, "icvOpenCamera_QT", "empty set video destination");
GetPixBounds (capture->pixmap, & myRect);
capture->size = cvSize (myRect.right - myRect.left, myRect.bottom - myRect.top);
capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureIsForRecord | vdFlagCaptureStarting | vdFlagCaptureLowLatency);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
return 1;
}
static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
{
OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
ComponentResult result = noErr;
result = VDCaptureStateChanging (capture->grabber, vdFlagCaptureStopping);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set capture state");
cvReleaseImage (& capture->image_bgr);
cvReleaseImageHeader (& capture->image_rgb);
DisposeGWorld (capture->myGWorld);
CloseComponent (capture->grabber);
return 1;
}
static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
{
OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
ComponentResult result = noErr;
result = VDGrabOneFrame (capture->grabber);
if (result != noErr)
{
fprintf (stderr, "VDGrabOneFrame failed\n");
return 0;
}
return 1;
}
static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int)
{
OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
PixMapHandle myPixMapHandle = nil;
myPixMapHandle = capture->pixmap;
LockPixels (myPixMapHandle);
cvSetData (capture->image_rgb, GetPixBaseAddr (myPixMapHandle) + 1, GetPixRowBytes (myPixMapHandle));
cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
UnlockPixels (myPixMapHandle);
return capture->image_bgr;
}
#else
#pragma mark Capturing using Sequence Grabber
static OSErr icvDataProc_QT_Cam (SGChannel channel, Ptr raw_data, long len, long *, long, TimeValue, short, long refCon)
{
CvCapture_QT_Cam * capture = (CvCapture_QT_Cam *) refCon;
CodecFlags ignore;
ComponentResult err = noErr;
OPENCV_ASSERT (capture, "icvDataProc_QT_Cam", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->gworld, "icvDataProc_QT_Cam", "'gworld' is a NULL-pointer");
OPENCV_ASSERT (raw_data, "icvDataProc_QT_Cam", "'raw_data' is a NULL-pointer");
if (capture->sequence == 0)
{
ImageDescriptionHandle description = (ImageDescriptionHandle) NewHandle(0);
err = SGGetChannelSampleDescription (channel, (Handle) description);
OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt get channel sample description");
Rect sourceRect;
sourceRect.top = 0;
sourceRect.left = 0;
sourceRect.right = (**description).width;
sourceRect.bottom = (**description).height;
MatrixRecord scaleMatrix;
RectMatrix(&scaleMatrix,&sourceRect,&capture->bounds);
err = DecompressSequenceBegin (&capture->sequence, description, capture->gworld, 0,&capture->bounds,&scaleMatrix, srcCopy, NULL, 0, codecNormalQuality, bestSpeedCodec);
OPENCV_ASSERT (err == noErr, "icvDataProc_QT_Cam", "couldnt begin decompression sequence");
DisposeHandle ((Handle) description);
}
err = DecompressSequenceFrameS (capture->sequence, raw_data, len, 0, &ignore, nil);
if (err != noErr)
{
fprintf (stderr, "icvDataProc_QT_Cam: couldn't decompress frame - %d\n", (int) err);
return err;
}
capture->got_frame = true;
return noErr;
}
static int icvOpenCamera_QT (CvCapture_QT_Cam * capture, const int index)
{
OPENCV_ASSERT (capture, "icvOpenCamera_QT", "'capture' is a NULL-pointer");
OPENCV_ASSERT (index >= 0, "icvOpenCamera_QT", "camera index is negative");
PixMapHandle pixmap = nil;
OSErr result = noErr;
capture->grabber = OpenDefaultComponent (SeqGrabComponentType, 0);
OPENCV_ASSERT (capture->grabber, "icvOpenCamera_QT", "couldnt create image");
result = SGInitialize (capture->grabber);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt initialize sequence grabber");
result = SGSetDataRef (capture->grabber, 0, 0, seqGrabDontMakeMovie);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data reference of sequence grabber");
result = SGNewChannel (capture->grabber, VideoMediaType, & (capture->channel));
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create new video channel");
SGDeviceList device_list = 0;
result = SGGetChannelDeviceList (capture->channel, 0, & device_list);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt get channel device list");
for (int i = 0, current_index = 1; i < (*device_list)->count; i++)
{
SGDeviceName device = (*device_list)->entry[i];
if (device.flags == 0)
{
if (current_index == index)
{
result = SGSetChannelDevice (capture->channel, device.name);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set the channel video device");
break;
}
current_index++;
}
}
result = SGDisposeDeviceList (capture->grabber, device_list);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt dispose the channel device list");
result = SGGetSrcVideoBounds (capture->channel, & (capture->bounds));
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
result = QTNewGWorld (& (capture->gworld), k32ARGBPixelFormat, & (capture->bounds), 0, 0, 0);
result = SGSetGWorld (capture->grabber, capture->gworld, 0);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
result = SGSetChannelBounds (capture->channel, & (capture->bounds));
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
result = SGSetChannelUsage (capture->channel, seqGrabRecord);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set channel usage");
result = SGStartRecord (capture->grabber);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);
result = SGGetChannelSampleDescription(capture->channel, (Handle)imageDesc);
OPENCV_ASSERT( result == noErr, "icvOpenCamera_QT", "couldn't get image size");
capture->bounds.right = (**imageDesc).width;
capture->bounds.bottom = (**imageDesc).height;
DisposeHandle ((Handle) imageDesc);
result = SGStop (capture->grabber);
OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
GWorldPtr tmpgworld;
result = QTNewGWorld( &tmpgworld, k32ARGBPixelFormat, &(capture->bounds), 0, 0, 0);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt create offscreen GWorld");
result = SGSetGWorld( capture->grabber, tmpgworld, 0);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set GWorld for sequence grabber");
DisposeGWorld( capture->gworld );
capture->gworld = tmpgworld;
result = SGSetChannelBounds (capture->channel, & (capture->bounds));
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set video channel bounds");
capture->size = cvSize (capture->bounds.right - capture->bounds.left, capture->bounds.bottom - capture->bounds.top);
capture->image_rgb = cvCreateImageHeader (capture->size, IPL_DEPTH_8U, 4);
OPENCV_ASSERT (capture->image_rgb, "icvOpenCamera_QT", "couldnt create image header");
pixmap = GetGWorldPixMap (capture->gworld);
OPENCV_ASSERT (pixmap, "icvOpenCamera_QT", "didn't get GWorld PixMap handle");
LockPixels (pixmap);
cvSetData (capture->image_rgb, GetPixBaseAddr (pixmap) + 1, GetPixRowBytes (pixmap));
capture->image_bgr = cvCreateImage (capture->size, IPL_DEPTH_8U, 3);
OPENCV_ASSERT (capture->image_bgr, "icvOpenCamera_QT", "couldnt create image");
result = SGSetDataProc (capture->grabber, NewSGDataUPP (icvDataProc_QT_Cam), (long) capture);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt set data proc");
result = SGStartRecord (capture->grabber);
OPENCV_ASSERT (result == noErr, "icvOpenCamera_QT", "couldnt start recording");
return 1;
}
static int icvClose_QT_Cam (CvCapture_QT_Cam * capture)
{
OPENCV_ASSERT (capture, "icvClose_QT_Cam", "'capture' is a NULL-pointer");
OSErr result = noErr;
result = SGStop (capture->grabber);
OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt stop recording");
result = CloseComponent (capture->grabber);
OPENCV_ASSERT (result == noErr, "icveClose_QT_Cam", "couldnt close sequence grabber component");
CDSequenceEnd (capture->sequence);
cvReleaseImage (& capture->image_bgr);
cvReleaseImageHeader (& capture->image_rgb);
DisposeGWorld (capture->gworld);
return 1;
}
static int icvGrabFrame_QT_Cam (CvCapture_QT_Cam * capture)
{
OPENCV_ASSERT (capture, "icvGrabFrame_QT_Cam", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->grabber, "icvGrabFrame_QT_Cam", "'grabber' is a NULL-pointer");
ComponentResult result = noErr;
result = SGIdle (capture->grabber);
if (result != noErr)
{
fprintf (stderr, "SGIdle failed in icvGrabFrame_QT_Cam with error %d\n", (int) result);
return 0;
}
return 1;
}
static const void * icvRetrieveFrame_QT_Cam (CvCapture_QT_Cam * capture, int)
{
OPENCV_ASSERT (capture, "icvRetrieveFrame_QT_Cam", "'capture' is a NULL-pointer");
OPENCV_ASSERT (capture->image_rgb, "icvRetrieveFrame_QT_Cam", "invalid source image");
OPENCV_ASSERT (capture->image_bgr, "icvRetrieveFrame_QT_Cam", "invalid destination image");
OSErr myErr = noErr;
while (! capture->got_frame)
{
myErr = SGIdle (capture->grabber);
if (myErr != noErr)
{
fprintf (stderr, "SGIdle() didn't succeed in icvRetrieveFrame_QT_Cam().\n");
return 0;
}
}
cvCvtColor (capture->image_rgb, capture->image_bgr, CV_RGBA2BGR);
capture->got_frame = false;
return capture->image_bgr;
}
#endif
typedef struct CvVideoWriter_QT {
DataHandler data_handler;
Movie movie;
Track track;
Media video;
ICMCompressionSessionRef compression_session_ref;
TimeValue duration_per_sample;
} CvVideoWriter_QT;
static TimeScale const TIME_SCALE = 600;
static OSStatus icvEncodedFrameOutputCallback(
void* writer,
ICMCompressionSessionRef compression_session_ref,
OSStatus error,
ICMEncodedFrameRef encoded_frame_ref,
void* reserved
);
static void icvSourceTrackingCallback(
void *source_tracking_ref_con,
ICMSourceTrackingFlags source_tracking_flags,
void *source_frame_ref_con,
void *reserved
);
static int icvWriteFrame_QT(
CvVideoWriter_QT * video_writer,
const IplImage * image
) {
CVPixelBufferRef pixel_buffer_ref = NULL;
CVReturn retval =
CVPixelBufferCreate(
kCFAllocatorDefault,
image->width, image->height, k24RGBPixelFormat,
NULL ,
&pixel_buffer_ref
);
IplImage* image_rgb =
cvCreateImageHeader(
cvSize( image->width, image->height ),
IPL_DEPTH_8U,
3
);
retval = CVPixelBufferLockBaseAddress( pixel_buffer_ref, 0 );
void* base_address = CVPixelBufferGetBaseAddress( pixel_buffer_ref );
size_t bytes_per_row = CVPixelBufferGetBytesPerRow( pixel_buffer_ref );
cvSetData( image_rgb, base_address, bytes_per_row );
cvConvertImage( image, image_rgb, CV_CVTIMG_SWAP_RB );
retval = CVPixelBufferUnlockBaseAddress( pixel_buffer_ref, 0 );
cvReleaseImageHeader( &image_rgb );
ICMSourceTrackingCallbackRecord source_tracking_callback_record;
source_tracking_callback_record.sourceTrackingCallback =
icvSourceTrackingCallback;
source_tracking_callback_record.sourceTrackingRefCon = NULL;
OSStatus status =
ICMCompressionSessionEncodeFrame(
video_writer->compression_session_ref,
pixel_buffer_ref,
0,
video_writer->duration_per_sample,
kICMValidTime_DisplayDurationIsValid,
NULL,
&source_tracking_callback_record,
static_cast<void*>( &pixel_buffer_ref )
);
return 0;
}
static void icvReleaseVideoWriter_QT( CvVideoWriter_QT ** writer ) {
if ( ( writer != NULL ) && ( *writer != NULL ) ) {
CvVideoWriter_QT* video_writer = *writer;
ICMCompressionSessionCompleteFrames(
video_writer->compression_session_ref, 1, 0, 0
);
EndMediaEdits( video_writer->video );
ICMCompressionSessionRelease( video_writer->compression_session_ref );
InsertMediaIntoTrack(
video_writer->track,
0,
0,
GetMediaDuration( video_writer->video ),
FixRatio( 1, 1 )
);
UpdateMovieInStorage( video_writer->movie, video_writer->data_handler );
CloseMovieStorage( video_writer->data_handler );
DisposeMovie( video_writer->movie );
cvFree( writer );
}
}
static OSStatus icvEncodedFrameOutputCallback(
void* writer,
ICMCompressionSessionRef compression_session_ref,
OSStatus error,
ICMEncodedFrameRef encoded_frame_ref,
void* reserved
) {
CvVideoWriter_QT* video_writer = static_cast<CvVideoWriter_QT*>( writer );
OSStatus err = AddMediaSampleFromEncodedFrame( video_writer->video,
encoded_frame_ref, NULL );
return err;
}
static void icvSourceTrackingCallback(
void *source_tracking_ref_con,
ICMSourceTrackingFlags source_tracking_flags,
void *source_frame_ref_con,
void *reserved
) {
if ( source_tracking_flags & kICMSourceTracking_ReleasedPixelBuffer ) {
CVPixelBufferRelease(
*static_cast<CVPixelBufferRef*>( source_frame_ref_con )
);
}
}
static CvVideoWriter_QT* icvCreateVideoWriter_QT(
const char * filename,
int fourcc,
double fps,
CvSize frame_size,
int is_color
) {
CV_FUNCNAME( "icvCreateVideoWriter" );
CvVideoWriter_QT* video_writer =
static_cast<CvVideoWriter_QT*>( cvAlloc( sizeof( CvVideoWriter_QT ) ) );
memset( video_writer, 0, sizeof( CvVideoWriter_QT ) );
Handle data_ref = NULL;
OSType data_ref_type;
DataHandler data_handler = NULL;
Movie movie = NULL;
ICMCompressionSessionOptionsRef options_ref = NULL;
ICMCompressionSessionRef compression_session_ref = NULL;
CFStringRef out_path = nil;
Track video_track = nil;
Media video = nil;
OSErr err = noErr;
CodecType codecType = kRawCodecType;
__BEGIN__
if ( filename == NULL ) {
CV_ERROR( CV_StsBadArg, "Video file name must not be NULL" );
}
if ( fps <= 0.0 ) {
CV_ERROR( CV_StsBadArg, "FPS must be larger than 0.0" );
}
if ( ( frame_size.width <= 0 ) || ( frame_size.height <= 0 ) ) {
CV_ERROR( CV_StsBadArg,
"Frame width and height must be larger than 0" );
}
if ( !did_enter_movies ) {
err = EnterMovies();
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Unable to initialize QuickTime" );
}
did_enter_movies = 1;
}
out_path = CFStringCreateWithCString( kCFAllocatorDefault, filename, kCFStringEncodingISOLatin1 );
CV_ASSERT( out_path != nil );
err = QTNewDataReferenceFromFullPathCFString( out_path, kQTPOSIXPathStyle,
0, &data_ref, &data_ref_type );
CFRelease( out_path );
if ( err != noErr ) {
CV_ERROR( CV_StsInternal,
"Cannot create data reference from file name" );
}
err = CreateMovieStorage( data_ref, data_ref_type, 'TVOD',
smCurrentScript, newMovieActive, &data_handler, &movie );
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot create movie storage" );
}
video_track = NewMovieTrack (movie,
FixRatio( frame_size.width, 1 ),
FixRatio( frame_size.height, 1 ),
kNoVolume);
err = GetMoviesError();
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot create video track" );
}
video = NewTrackMedia( video_track, VideoMediaType, TIME_SCALE, nil, 0 );
err = GetMoviesError();
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot create video media" );
}
err = ICMCompressionSessionOptionsCreate( kCFAllocatorDefault,
&options_ref );
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot create compression session options" );
}
err = ICMCompressionSessionOptionsSetAllowTemporalCompression( options_ref,
true );
if ( err != noErr) {
CV_ERROR( CV_StsInternal, "Cannot enable temporal compression" );
}
err = ICMCompressionSessionOptionsSetAllowFrameReordering( options_ref,
true );
if ( err != noErr) {
CV_ERROR( CV_StsInternal, "Cannot enable frame reordering" );
}
ICMEncodedFrameOutputRecord encoded_frame_output_record;
encoded_frame_output_record.encodedFrameOutputCallback =
icvEncodedFrameOutputCallback;
encoded_frame_output_record.encodedFrameOutputRefCon =
static_cast<void*>( video_writer );
encoded_frame_output_record.frameDataAllocator = NULL;
err = ICMCompressionSessionCreate( kCFAllocatorDefault, frame_size.width,
frame_size.height, codecType, TIME_SCALE, options_ref,
NULL , &encoded_frame_output_record,
&compression_session_ref );
ICMCompressionSessionOptionsRelease( options_ref );
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot create compression session" );
}
err = BeginMediaEdits( video );
if ( err != noErr ) {
CV_ERROR( CV_StsInternal, "Cannot begin media edits" );
}
video_writer->data_handler = data_handler;
video_writer->movie = movie;
video_writer->track = video_track;
video_writer->video = video;
video_writer->compression_session_ref = compression_session_ref;
video_writer->duration_per_sample =
static_cast<TimeValue>( static_cast<double>( TIME_SCALE ) / fps );
__END__
if ( err != noErr ) {
if ( options_ref != NULL ) {
ICMCompressionSessionOptionsRelease( options_ref );
}
if ( compression_session_ref != NULL ) {
ICMCompressionSessionRelease( compression_session_ref );
}
if ( data_handler != NULL ) {
CloseMovieStorage( data_handler );
}
if ( movie != NULL ) {
DisposeMovie( movie );
}
if ( data_ref != NULL ) {
DeleteMovieStorage( data_ref, data_ref_type );
DisposeHandle( data_ref );
}
cvFree( reinterpret_cast<void**>( &video_writer ) );
video_writer = NULL;
}
return video_writer;
}
class CvCapture_QT_Movie_CPP : public CvCapture
{
public:
CvCapture_QT_Movie_CPP() { captureQT = 0; }
virtual ~CvCapture_QT_Movie_CPP() { close(); }
virtual bool open( const char* filename );
virtual void close();
virtual double getProperty(int) const;
virtual bool setProperty(int, double);
virtual bool grabFrame();
virtual IplImage* retrieveFrame(int);
virtual int getCaptureDomain() { return CV_CAP_QT; }
protected:
CvCapture_QT_Movie* captureQT;
};
bool CvCapture_QT_Movie_CPP::open( const char* filename )
{
close();
captureQT = icvCaptureFromFile_QT( filename );
return captureQT != 0;
}
void CvCapture_QT_Movie_CPP::close()
{
if( captureQT )
{
icvClose_QT_Movie( captureQT );
cvFree( &captureQT );
}
}
bool CvCapture_QT_Movie_CPP::grabFrame()
{
return captureQT ? icvGrabFrame_QT_Movie( captureQT ) != 0 : false;
}
IplImage* CvCapture_QT_Movie_CPP::retrieveFrame(int)
{
return captureQT ? (IplImage*)icvRetrieveFrame_QT_Movie( captureQT, 0 ) : 0;
}
double CvCapture_QT_Movie_CPP::getProperty( int propId ) const
{
return captureQT ? icvGetProperty_QT_Movie( captureQT, propId ) : 0;
}
bool CvCapture_QT_Movie_CPP::setProperty( int propId, double value )
{
return captureQT ? icvSetProperty_QT_Movie( captureQT, propId, value ) != 0 : false;
}
CvCapture* cvCreateFileCapture_QT( const char* filename )
{
CvCapture_QT_Movie_CPP* capture = new CvCapture_QT_Movie_CPP;
if( capture->open( filename ))
return capture;
delete capture;
return 0;
}
class CvCapture_QT_Cam_CPP : public CvCapture
{
public:
CvCapture_QT_Cam_CPP() { captureQT = 0; }
virtual ~CvCapture_QT_Cam_CPP() { close(); }
virtual bool open( int index );
virtual void close();
virtual double getProperty(int) const;
virtual bool setProperty(int, double);
virtual bool grabFrame();
virtual IplImage* retrieveFrame(int);
virtual int getCaptureDomain() { return CV_CAP_QT; }
protected:
CvCapture_QT_Cam* captureQT;
};
bool CvCapture_QT_Cam_CPP::open( int index )
{
close();
captureQT = icvCaptureFromCam_QT( index );
return captureQT != 0;
}
void CvCapture_QT_Cam_CPP::close()
{
if( captureQT )
{
icvClose_QT_Cam( captureQT );
cvFree( &captureQT );
}
}
bool CvCapture_QT_Cam_CPP::grabFrame()
{
return captureQT ? icvGrabFrame_QT_Cam( captureQT ) != 0 : false;
}
IplImage* CvCapture_QT_Cam_CPP::retrieveFrame(int)
{
return captureQT ? (IplImage*)icvRetrieveFrame_QT_Cam( captureQT, 0 ) : 0;
}
double CvCapture_QT_Cam_CPP::getProperty( int propId ) const
{
return captureQT ? icvGetProperty_QT_Cam( captureQT, propId ) : 0;
}
bool CvCapture_QT_Cam_CPP::setProperty( int propId, double value )
{
return captureQT ? icvSetProperty_QT_Cam( captureQT, propId, value ) != 0 : false;
}
CvCapture* cvCreateCameraCapture_QT( int index )
{
CvCapture_QT_Cam_CPP* capture = new CvCapture_QT_Cam_CPP;
if( capture->open( index ))
return capture;
delete capture;
return 0;
}
class CvVideoWriter_QT_CPP : public CvVideoWriter
{
public:
CvVideoWriter_QT_CPP() { writerQT = 0; }
virtual ~CvVideoWriter_QT_CPP() { close(); }
virtual bool open( const char* filename, int fourcc,
double fps, CvSize frameSize, bool isColor );
virtual void close();
virtual bool writeFrame( const IplImage* );
protected:
CvVideoWriter_QT* writerQT;
};
bool CvVideoWriter_QT_CPP::open( const char* filename, int fourcc,
double fps, CvSize frameSize, bool isColor )
{
close();
writerQT = icvCreateVideoWriter_QT( filename, fourcc, fps, frameSize, isColor );
return writerQT != 0;
}
void CvVideoWriter_QT_CPP::close()
{
if( writerQT )
{
icvReleaseVideoWriter_QT( &writerQT );
writerQT = 0;
}
}
bool CvVideoWriter_QT_CPP::writeFrame( const IplImage* image )
{
if( !writerQT || !image )
return false;
return icvWriteFrame_QT( writerQT, image ) >= 0;
}
CvVideoWriter* cvCreateVideoWriter_QT( const char* filename, int fourcc,
double fps, CvSize frameSize, int isColor )
{
CvVideoWriter_QT_CPP* writer = new CvVideoWriter_QT_CPP;
if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
return writer;
delete writer;
return 0;
}