1 // CVVidCapture - Video capture interface class
2 // Written by Michael Ellison
3 //-------------------------------------------------------------------------
4 // CodeVis's Free License
5 // www.codevis.com
6 //
7 // Copyright (c) 2003 by Michael Ellison (mike@codevis.com)
8 // All rights reserved.
9 //
10 // You may use this software in source and/or binary form, with or without
11 // modification, for commercial or non-commercial purposes, provided that
12 // you comply with the following conditions:
13 //
14 // * Redistributions of source code must retain the above copyright notice,
15 // this list of conditions and the following disclaimer.
16 //
17 // * Redistributions of modified source must be clearly marked as modified,
18 // and due notice must be placed in the modified source indicating the
19 // type of modification(s) and the name(s) of the person(s) performing
20 // said modification(s).
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 //
34 //---------------------------------------------------------------------------
35 // Modifications:
36 //
37 //---------------------------------------------------------------------------
38 /// \file CVVidCapture.cpp
39 /// \brief Implements common functions between all video capture devices.
40 ///
41 /// CVVidCapture provides the pure interface for derived video capture
42 /// classses, and also provides some basic functionality for all video
43 /// capture classes.
44 ///
45 /// You *must* derive a class from it, and cannot simply instantiate it.
46 ///
47 /// To use any CVVidCapture object, instantiated the desired derived type.
48 ///
49 /// Call Init() to to initialize the capture library as needed.
50 ///
51 /// Successful initialization, you can call EnumDevices() to enumerate
52 /// the available video capture devices.
53 ///
54 /// Once you've decided which capture device to use, call
55 /// Connect() with the desired device name to connect to it. Now
56 /// you can read and modify any of the camera properties and
57 /// video modes.
58 ///
59 /// When you're ready to receive images, either call Grab() for a single-
60 /// shot grab, or setup a callback and call StartImageCap().
61 ///
62 /// If you are using Grab(), be sure to call CVImage::ReleaseImage()
63 /// on the grabbed image when done.
64 ///
65 /// If you are doing a continuous capture, then the images are automatically
66 /// released after the callback returns. However, if you want to keep the
67 /// image around (for example, to place it on a queue for later processing
68 /// outside of the callback), you may call CVImage->AddRef() on the image
69 /// and it will not be deleted. Just make sure to call CVImage::ReleaseImage()
70 /// later when done with that image.
71 ///
72 /// Call Stop() to end a StartImageCap() continuous capture.
73 ///
74 /// When you're done, call Disconnect(), then Uninit() to clean up.
75 ///
76 ///
77 /// $RCSfile: CVVidCapture.cpp,v $
78 /// $Date: 2004/03/01 16:28:15 $
79 /// $Revision: 1.3 $
80 /// $Author: mikeellison $
81
82 #include <string.h> // strncpy
83 #include <memory.h> // memset
84 #include "CVVidCapture.h"
85 #include "CVUtil.h"
86
87 // Version format: xxMMxxmm
88 // xx - currently unused / reserved.
89 // MM - Major version digits (current 00)
90 // mm - minor version digits (current 20)
91 // So, the current version is 00.20, or 0.2
92 const int kVIDCAPTURE_VERSION = 0x00000030;
93
94 /// Property name table string length
95 const int kCVVidCapture_MaxPropNameLen = 32;
96
97 /// Max length of a format name
98 const int kCVVidCapture_MaxFormatNameLen = 32;
99
100 const char *kVIDCAPTURE_STRING =
101 "CodeVis VidCapture Version 0.30\n" \
102 "Copyright (c) 2003-2004 by Michael Ellison\n" \
103 "Documentation and code at http://www.codevis.com\n";
104
105 /// Property name table for translating
106 /// CAMERA_PROPERTY values into user-readable
107 /// strings.
108 ///
109 /// \sa GetPropertyName(), CAMERA_PROPERTY
110 const char kCVVidCapture_Prop_Names
111 [CVVidCapture::CAMERAPROP_NUMPROPS]
112 [kCVVidCapture_MaxPropNameLen] =
113 {
114 "Brightness", // CAMERAPROP_BRIGHT
115 "Contrast", // CAMERAPROP_CONTRAST
116 "Hue", // CAMERAPROP_HUE
117 "Saturation", // CAMERAPROP_SAT
118 "Sharpness", // CAMERAPROP_SHARP
119 "Gamma", // CAMERAPROP_GAMMA
120 "Color Enabled", // CAMERAPROP_COLOR
121 "White Balance", // CAMERAPROP_WHITEBALANCE
122 "Backlight Compensation", // CAMERAPROP_BACKLIGHT
123 "Gain", // CAMERAPROP_GAIN
124 };
125 /// Video format name table - should be kept up to date with
126 /// VIDCAP_FORMAT enumeration
127 const char kVIDCAP_FORMAT_NAMES[VIDCAP_NUM_FORMATS][kCVVidCapture_MaxFormatNameLen] =
128 {
129 "Unknown", // VIDCAP_FORMAT_UNKNOWN
130 "YVU9", // VIDCAP_FORMAT_YVU9
131 "Y411", // VIDCAP_FORMAT_Y411
132 "Y41P", // VIDCAP_FORMAT_Y41P
133 "YUY2", // VIDCAP_FORMAT_YUY2
134 "YVYU", // VIDCAP_FORMAT_YVYU
135 "UYVY", // VIDCAP_FORMAT_UYVY
136 "Y211", // VIDCAP_FORMAT_Y211
137 "CLJR", // VIDCAP_FORMAT_CLJR
138 "IF09", // VIDCAP_FORMAT_IF09
139 "CPLA", // VIDCAP_FORMAT_CPLA
140 "MJPG", // VIDCAP_FORMAT_MJPG
141 "TVMJ", // VIDCAP_FORMAT_TVMJ
142 "WAKE", // VIDCAP_FORMAT_WAKE
143 "CFCC", // VIDCAP_FORMAT_CFCC
144 "IJPG", // VIDCAP_FORMAT_IJPG
145 "Plum", // VIDCAP_FORMAT_Plum
146 "RGB1", // VIDCAP_FORMAT_RGB1
147 "RGB4", // VIDCAP_FORMAT_RGB4
148 "RGB8", // VIDCAP_FORMAT_RGB8
149 "RGB565", // VIDCAP_FORMAT_RGB565
150 "RGB555", // VIDCAP_FORMAT_RGB555
151 "RGB24", // VIDCAP_FORMAT_RGB24
152 "RGB32", // VIDCAP_FORMAT_RGB32
153 "ARGB32", // VIDCAP_FORMAT_ARGB32
154 "Overlay", // VIDCAP_FORMAT_Overlay
155 "QTMovie", // VIDCAP_FORMAT_QTMovie
156 "QTRpza", // VIDCAP_FORMAT_QTRpza
157 "QTSmc", // VIDCAP_FORMAT_QTSmc
158 "QTRle", // VIDCAP_FORMAT_QTRle
159 "QTJpeg", // VIDCAP_FORMAT_QTJpeg
160 "dvsd", // VIDCAP_FORMAT_dvsd
161 "dvhd", // VIDCAP_FORMAT_dvhd
162 "dvsl", // VIDCAP_FORMAT_dvsl
163 "MPEG1Packet", // VIDCAP_FORMAT_MPEG1Packet
164 "MPEG1Payload", // VIDCAP_FORMAT_MPEG1Payload
165 "VPVideo", // VIDCAP_FORMAT_VPVideo
166 "MPEG1 Video", // VIDCAP_FORMAT_MPEG1Video
167
168 "I420", // VIDCAP_FORMAT_I420
169 "IYUV", // VIDCAP_FORMAT_IYUV
170
171 "Y444", // VIDCAP_FORMAT_Y444
172 "Y800", // VIDCAP_FORMAT_Y800
173 "Y422", // VIDCAP_FORMAT_Y422
174 };
175
176 //---------------------------------------------------------------------------
CVVidCapture()177 CVVidCapture::CVVidCapture()
178 {
179 fInitialized = false;
180 fConnected = false;
181 fStarted = false;
182 fDeviceName = 0;
183 fModeList = 0;
184
185 fNumDevices = 0;
186 fDeviceList = 0;
187 memset(&fCurMode,0,sizeof(fCurMode));
188
189 fLastState = VIDCAP_UNCONNECTED;
190 }
191
192 //---------------------------------------------------------------------------
~CVVidCapture()193 CVVidCapture::~CVVidCapture()
194 {
195 // Sanity check - caller should stop, disconnect, and
196 // uninitialize in that order prior to deleting
197 // the object.
198
199 if (fStarted)
200 {
201 CVTrace("Capture device deleted while running!");
202 Stop();
203 }
204
205 if (fConnected)
206 {
207 CVTrace("Capture device deleted while connected!");
208 Disconnect();
209 }
210
211 if (fInitialized)
212 {
213 CVTrace("Capture device deleted while initialized!");
214 Uninit();
215 }
216
217 ClearDeviceList();
218
219 fModeList = 0;
220 }
221
222 //---------------------------------------------------------------------------
223 // ClearDeviceList
224 // Clears the list of available devices, if any.
225 //---------------------------------------------------------------------------
ClearDeviceList()226 void CVVidCapture::ClearDeviceList()
227 {
228 if (fDeviceList != 0)
229 {
230 VIDCAP_DEVICE* curDevice = fDeviceList;
231 VIDCAP_DEVICE* prevDevice = 0;
232
233 while (curDevice != 0)
234 {
235 prevDevice = curDevice;
236 curDevice = curDevice->NextDevice;
237 delete [] prevDevice->DeviceString;
238 delete prevDevice;
239 }
240 fDeviceList = 0;
241 }
242 fNumDevices = 0;
243 }
244
245 //---------------------------------------------------------------------------
246 // GetNumDevices() returns the number of devices available.
247 //---------------------------------------------------------------------------
GetNumDevices(int & numDevices)248 CVRES CVVidCapture::GetNumDevices(int& numDevices)
249 {
250 if (fInitialized != true)
251 {
252 return CVRES_VIDCAP_NOT_INITIALIZED;
253 }
254 numDevices = fNumDevices;
255
256 return CVRES_SUCCESS;
257 }
258
259 //---------------------------------------------------------------------------
260 // GetDeviceInfo()
261 // index is the index into the list (max from GetNumDevices)
262 // fills devInfo if index is valid.
263 //---------------------------------------------------------------------------
GetDeviceInfo(int index,VIDCAP_DEVICE & devInfo)264 CVRES CVVidCapture::GetDeviceInfo( int index,
265 VIDCAP_DEVICE& devInfo)
266 {
267 if (fInitialized != true)
268 {
269 return CVRES_VIDCAP_NOT_INITIALIZED;
270 }
271 if (fDeviceList == 0)
272 {
273 return CVRES_VIDCAP_NO_DEVICES;
274 }
275
276 if ((index < 0) || (index >= this->fNumDevices))
277 {
278 return CVRES_VIDCAP_INVALID_DEVICE_INDEX;
279 }
280
281
282 int devNum = 0;
283 VIDCAP_DEVICE* curDevice = fDeviceList;
284 while ((curDevice != 0) && (devNum != index))
285 {
286 devNum++;
287 curDevice = curDevice->NextDevice;
288 }
289
290 if (curDevice != 0)
291 {
292 devInfo = *curDevice;
293 return CVRES_SUCCESS;
294 }
295
296 return CVRES_VIDCAP_INVALID_DEVICE_INDEX;
297 }
298
299 //---------------------------------------------------------------------------
300 // Stop
301 // Child classes should override. This should stop what
302 // StartImageCap() and any other continuous grabs start.
303 //---------------------------------------------------------------------------
Stop()304 CVRES CVVidCapture::Stop()
305 {
306 if (fStarted != true)
307 {
308 return CVRES_VIDCAP_ALREADY_STOPPED;
309 }
310 fStarted = false;
311 return CVRES_SUCCESS;
312 }
313
314 //---------------------------------------------------------------------------
315 // Disconnect
316 // Child classes should override.
317 // This should release anything allocated by Connect().
318 //---------------------------------------------------------------------------
Disconnect()319 CVRES CVVidCapture::Disconnect()
320 {
321 if (fConnected != true)
322 {
323 return CVRES_VIDCAP_NOT_CONNECTED;
324 }
325
326 fLastState = VIDCAP_UNCONNECTED;
327 fConnected = false;
328
329 return CVRES_SUCCESS;
330 }
331
332 //---------------------------------------------------------------------------
333 // Uninit
334 // Child classes should override.
335 // This should release anything allocated by Init()
336 //---------------------------------------------------------------------------
Uninit()337 CVRES CVVidCapture::Uninit()
338 {
339 if (fInitialized != true)
340 {
341 return CVRES_VIDCAP_NOT_INITIALIZED;
342 }
343 fInitialized = false;
344 return CVRES_SUCCESS;
345 }
346
347 //---------------------------------------------------------------------------
348 // GetPropertyInfo()
349 // Retrieves the information for the specified camera property.
350 // If you receive CVRES_VIDCAP_PROPERTY_NOT_SUPPORTED, then either your camera
351 // or the derived video capture class does not support the property.
352 //---------------------------------------------------------------------------
GetPropertyInfo(CAMERA_PROPERTY property,long * curVal,long * defVal,long * minVal,long * maxVal,long * step)353 CVRES CVVidCapture::GetPropertyInfo ( CAMERA_PROPERTY property,
354 long* curVal,
355 long* defVal,
356 long* minVal,
357 long* maxVal,
358 long* step)
359 {
360 return CVRES_VIDCAP_PROPERTY_NOT_SUPPORTED;
361 }
362
363 //---------------------------------------------------------------------------
364 // SetProperty
365 // Sets a property if it is available and the specified value is within
366 // range. Use GetPropertyInfo to get the property min/max and step.
367 //---------------------------------------------------------------------------
SetProperty(CAMERA_PROPERTY property,long value)368 CVRES CVVidCapture::SetProperty ( CAMERA_PROPERTY property,
369 long value)
370 {
371 return CVRES_VIDCAP_PROPERTY_NOT_SUPPORTED;
372 }
373
374 //---------------------------------------------------------------------------
375 // GetPropertyName()
376 // Retrieve the property name for a specified property
377 //---------------------------------------------------------------------------
GetPropertyName(CAMERA_PROPERTY property,char * nameBuffer,int maxLength)378 CVRES CVVidCapture::GetPropertyName ( CAMERA_PROPERTY property,
379 char* nameBuffer,
380 int maxLength)
381 {
382 if ((property < 0) || (property >= CAMERAPROP_NUMPROPS))
383 {
384 return CVRES_INVALID_PARAMETER;
385 }
386 if ((nameBuffer == 0) || (maxLength < 2))
387 {
388 return CVRES_INVALID_PARAMETER;
389 }
390
391 memset(nameBuffer,0,maxLength);
392 strncpy(nameBuffer,kCVVidCapture_Prop_Names[property],maxLength-1);
393
394 return CVRES_SUCCESS;
395 }
396
397 //---------------------------------------------------------------------------
398 // GetNumSupportedModes
399 // Retrieves the number of supported modes by
400 // walking the mode list. Mode list should be
401 // created inside Connect().
402 //---------------------------------------------------------------------------
GetNumSupportedModes(int & numModes)403 CVRES CVVidCapture::GetNumSupportedModes( int& numModes )
404 {
405 if (fConnected != true)
406 {
407 return CVRES_VIDCAP_NOT_CONNECTED;
408 }
409 numModes = 0;
410
411 VIDCAP_MODE* curMode = fModeList;
412
413 // Count modes
414 while (curMode != 0)
415 {
416 numModes++;
417 curMode = curMode->NextMode;
418 }
419
420 return CVRES_SUCCESS;
421 }
422
423 //---------------------------------------------------------------------------
424 // GetModeInfo()
425 // index is the index into the list (max from GetNumSupportedModes)
426 // fills modeInfo if index is valid.
427 //---------------------------------------------------------------------------
GetModeInfo(int index,VIDCAP_MODE & modeInfo)428 CVRES CVVidCapture::GetModeInfo( int index,
429 VIDCAP_MODE& modeInfo)
430 {
431 if (fConnected != true)
432 {
433 return CVRES_VIDCAP_NOT_CONNECTED;
434 }
435
436 int modeNum = 0;
437 VIDCAP_MODE* curMode = fModeList;
438 while ((curMode != 0) && (modeNum != index))
439 {
440 modeNum++;
441 curMode = curMode->NextMode;
442 }
443
444 if (curMode != 0)
445 {
446 modeInfo = *curMode;
447 return CVRES_SUCCESS;
448 }
449
450 return CVRES_VIDCAP_MODE_NOT_SUPPORTED;
451 }
452
453 //---------------------------------------------------------------------------
454 // SetMode()
455 // index is the index into the list (max from GetNumSupportedModes)
456 // sets the capture mode.
457 //---------------------------------------------------------------------------
SetMode(int index,bool rawYUY2)458 CVRES CVVidCapture::SetMode( int index,
459 bool rawYUY2 )
460 {
461 if (fConnected != true)
462 {
463 return CVRES_VIDCAP_NOT_CONNECTED;
464 }
465
466 VIDCAP_MODE* curMode = fModeList;
467 int modeNum = 0;
468 while ((curMode != 0) && (modeNum != index))
469 {
470 modeNum++;
471 curMode = curMode->NextMode;
472 }
473
474 if (curMode != 0)
475 {
476 return SetMode(*curMode, rawYUY2);
477 }
478
479 return CVRES_VIDCAP_MODE_NOT_SUPPORTED;
480 }
481
482
483 //---------------------------------------------------------------------------
484 // GetCurrentMode()
485 // Retrieve the current mode
486 //---------------------------------------------------------------------------
GetCurrentMode(VIDCAP_MODE & curMode)487 CVRES CVVidCapture::GetCurrentMode( VIDCAP_MODE& curMode )
488 {
489 if (fConnected != true)
490 {
491 return CVRES_VIDCAP_NOT_CONNECTED;
492 }
493
494 curMode = fCurMode;
495 return CVRES_SUCCESS;
496 }
497
498 //---------------------------------------------------------------------------
499 // SetMode()
500 // Set the mode to a specific mode.
501 // Override in child classes!
502 //---------------------------------------------------------------------------
SetMode(VIDCAP_MODE & curMode,bool rawYUY2)503 CVRES CVVidCapture::SetMode( VIDCAP_MODE& curMode,
504 bool rawYUY2 )
505 {
506 return CVRES_VIDCAP_MODE_NOT_SUPPORTED;
507 }
508
509
510 //---------------------------------------------------------------------------
511 // ClearModes()
512 // Clear out the mode list
513 // Probably need to override this in child classes if internal
514 // void* is used.
515 //---------------------------------------------------------------------------
ClearModes()516 void CVVidCapture::ClearModes()
517 {
518 VIDCAP_MODE* curMode = fModeList;
519 VIDCAP_MODE* prevMode = 0;
520
521 while (curMode != 0)
522 {
523 prevMode = curMode;
524 curMode = curMode->NextMode;
525 delete prevMode;
526 }
527
528 fModeList = 0;
529 }
530
531 //---------------------------------------------------------------------------
532 // AddMode()
533 // Adds a mode to the mode list.
534 //---------------------------------------------------------------------------
AddMode(VIDCAP_MODE & addMode)535 CVRES CVVidCapture::AddMode( VIDCAP_MODE& addMode )
536 {
537 VIDCAP_MODE* newMode = new VIDCAP_MODE;
538 if (newMode == 0)
539 {
540 return CVRES_OUT_OF_MEMORY;
541 }
542
543 // Copy mode information
544 *newMode = addMode;
545
546 // Prepend to list
547 newMode->NextMode = fModeList;
548 fModeList = newMode;
549
550 return CVRES_SUCCESS;
551 }
552
553
554 //---------------------------------------------------------------------------
555 // IsInitialized()
556 // Returns true if the capture object is initialized
557 //---------------------------------------------------------------------------
IsInitialized()558 bool CVVidCapture::IsInitialized()
559 {
560 return this->fInitialized;
561 }
562
563 //---------------------------------------------------------------------------
564 // IsStarted()
565 // Returns true if a capture has been started
566 //---------------------------------------------------------------------------
IsStarted()567 bool CVVidCapture::IsStarted()
568 {
569 return this->fStarted;
570 }
571
572 //---------------------------------------------------------------------------
573 // IsConnected()
574 // Returns true if we're connected to a camera
575 //---------------------------------------------------------------------------
IsConnected()576 bool CVVidCapture::IsConnected()
577 {
578 return this->fConnected;
579 }
580
581 //---------------------------------------------------------------------------
582 // GetFormatModeName() retrieves the video format mode name
583 // from the enumeration value.
584 //
585 // vidcapFormat - video format of camera
586 // const char* - ptr to const string describing video format
587 //---------------------------------------------------------------------------
GetFormatModeName(VIDCAP_FORMAT format)588 const char* CVVidCapture::GetFormatModeName( VIDCAP_FORMAT format)
589 {
590 if ((format >= VIDCAP_NUM_FORMATS) || (format < 0))
591 {
592 return kVIDCAP_FORMAT_NAMES[0];
593 }
594
595 return kVIDCAP_FORMAT_NAMES[format];
596 }
597
598 //---------------------------------------------------------------------------
599 // GetDeviceName() retrieve the device name into a buffer/
600 // The buffer must already be created.
601 // You may call it with a null buffer to receive the length of the string
602 // in maxLength.
603 //---------------------------------------------------------------------------
GetDeviceName(char * nameBuffer,int & maxLength)604 CVRES CVVidCapture::GetDeviceName ( char* nameBuffer,
605 int& maxLength )
606 {
607 int copyLen = maxLength;
608 maxLength = strlen(this->fDeviceName);
609
610 if ((nameBuffer == 0) || (copyLen == 0))
611 {
612 return CVRES_VIDCAP_NAME_BUFFER_TOO_SMALL;
613 }
614
615 strncpy(nameBuffer,fDeviceName,copyLen);
616 if (copyLen < maxLength)
617 {
618 // ensure null termination
619 nameBuffer[copyLen-1] = 0;
620 return CVRES_VIDCAP_NAME_BUFFER_TOO_SMALL;
621 }
622 return CVRES_SUCCESS;
623 }
624