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