Solved

USB Camera

Posted on 2004-09-03
19
4,500 Views
Last Modified: 2008-03-06
Hi

I have a USB camera from Logitech (QuickCam 8 for Notebooks Pro) and need to write a C/C++ program to capture frames from it. I have no clue how to start.

Anyone heard of ARToolkit? That is what my boss wants me to use but I cannot find any kind of documentation for it.
Should I open system > device manager and look for the addresses used by the cam? isn't that a potential crash?
I have MS Spy++ that can list the PID, name and memory used by any process. I don't think that  to read from some other prgm's mem would be a good idea either.
I have the device driver. if anybody could reverse engineer or hack it, that could be a great help.

thank you.
jaydutt
0
Comment
Question by:jhshukla
  • 8
  • 6
  • 3
  • +2
19 Comments
 

Expert Comment

by:Valadas2
ID: 11978882
I guess there must be some king of interface so different sorfwate can access the camera. I would try to post to the Programming Forum as it is more a programming issues than a hardware issue...
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 11979049
You can use Video Capture functions from Windows Multimedia SDK:

capCreateCaptureWindow
capDriverConnect
capDriverGetCaps
capPreview
etc.

These functions are relatively high-level and allow to get image from any WebCam. Follow these steps:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_using_video_capture.asp

I have MFC application which works with WebCam, I can post here some code fragments if you are interesting.
0
 
LVL 7

Expert Comment

by:aib_42
ID: 11979382
There would be no reason to reverse engineer/debug/hack the device driver unless you wanted to write another one yourself.

The capture functions from the Multimedia SDK seems to be a good idea, but unfortunately it's one I did not have when I needed to write a frame-capture application, so I went the DirectShow way.

Anyway, I have a minimal application (~200 lines) which uses DirectShow (DirectX SDK) to constantly capture frames from a selected capture device. I could also post fragments or the whole code.
0
 
LVL 7

Expert Comment

by:aib_42
ID: 11979428
Actually, I will post the code anyway. Note that it was designed to be a test/trial code, not production code, and I have added the comments for you just two minutes ago. Most of the COM/DirectShow error-checking should be good, but I have some "quick-n-dirty" code for the "dumping the frame" and the loop parts. (Hell, I have an infinite goto-loop!)

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <objbase.h>
#include <dshow.h>
#include <qedit.h>

//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int main(void)
{
      IGraphBuilder *filterGraph = NULL;

      ICreateDevEnum *devenum = NULL;
      IEnumMoniker *capenum = NULL;
      IPropertyBag *capdevinfo = NULL;

      IMoniker *capdev = NULL;

      IMediaControl *MAC = NULL;
      IMediaEvent *MAE = NULL;
      ISampleGrabber *samplegrabber = NULL;

      IBaseFilter *capfilter = NULL;
      IBaseFilter *capgrabber = NULL;
      IBaseFilter *capnull = NULL;

      VARIANT v;
      AM_MEDIA_TYPE mt;

      /* Initialize COM */
      if (FAILED(CoInitialize(NULL))) {
            printf("Failed to initialize COM.\n");
            return -1;
      }

      /* Finding and selecting a device */
      
      /* Create enumerator */
      if (FAILED(CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **) &devenum))) {
            printf("Failed to create SystemDeviceEnum instance.\n");
            return -1;
      }

      /* Make it a video enumerator */
      if (FAILED(devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &capenum, 0))) {
            printf("Failed to enumerate video capture devices.\n");
            return -1;
      }

      if (capenum == NULL) {
            printf("There are no video input devices available.\n");
            return 1;
      }

      printf("The devices:\n");

      while(capenum->Next(1, &capdev, NULL) == S_OK) {
            if (FAILED(capdev->BindToStorage(NULL, NULL, IID_IPropertyBag, (void **) &capdevinfo))) {
                  printf("Failed to query capture device.\n");
                  return -1;
            }

            VariantInit(&v);
            capdevinfo->Read(L"FriendlyName", &v, NULL);
            printf("%S\n", v.bstrVal);
            /* find the first device with the name "cam" in it :) */
            if ((wcsstr(v.bstrVal, L"cam")) || (wcsstr(v.bstrVal, L"Cam")) || (wcsstr(v.bstrVal, L"CAM"))) {
                  if (FAILED(capdev->BindToObject(NULL, NULL, IID_IBaseFilter, (void **) &capfilter))) {
                        printf("Failed to bind to capture device.\n");
                        return -1;
                  } else {
                        break;
                  }
            }
            VariantClear(&v);
      }

      capdevinfo->Release();
      capdev->Release();
      capenum->Release();
      devenum->Release();
      /* Finding and selecting a device ends */

      /* Create the Filter Graph - the main thing */
      if (FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &filterGraph))) {
            printf("Unable to create filter graph.\n");
            return -1;
      }

      /* Media Control and Media Event interfaces for running/stopping the graph */
      filterGraph->QueryInterface(IID_IMediaControl, (void **) &MAC);
      if (MAC == NULL) {
            printf("Unable to query media control interface.\n");
            return -1;
      }

      filterGraph->QueryInterface(IID_IMediaEvent, (void **) &MAE);
      if (MAE == NULL) {
            printf("Unable to query media event interface.\n");
            return -1;
      }

      /* Add the video source to graph */
      /* Graph looks like:
            Video Source
      */
      if (filterGraph->AddFilter(capfilter, L"Video Source") != S_OK) {
            printf("Unable to add source filter.\n");
            return -1;
      }

      /* Create the BMP grabber */
      if (FAILED(CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) &capgrabber))) {
            printf("Unable to create video grabber.\n");
            return -1;
      }

      capgrabber->QueryInterface(IID_ISampleGrabber, (void **) &samplegrabber);
      if (samplegrabber == NULL) {
            printf("Unable to query video grabber interface.\n");
            return -1;
      }

      /* Add grabber to graph */
      /* Graph looks like:
            Video Source   Grabber
      */
      if (FAILED(filterGraph->AddFilter(capgrabber, L"Grabber"))) {
            printf("Unable to add grabber filter.\n");
            return -1;
      }

      /* Create the null renderer */
      if (FAILED(CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **) &capnull))) {
            printf("Unable to create null renderer.\n");
            return -1;
      }

      /* Add null renderer to graph */
      /* Graph looks like:
            Video Source   Grabber   Null Renderer
      */
      if (FAILED(filterGraph->AddFilter(capnull, L"Null Renderer"))) {
            printf("Unable to add null renderer filter.\n");
            return -1;
      }

      /* Create and set up the media format for the capture */
      ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
      mt.majortype = MEDIATYPE_Video;
      mt.subtype = MEDIASUBTYPE_RGB32;

      /* Webcam uses RGB32 although it has no alpha channel and thus returns '0'
      every 4th byte in the frame */

      mt.formattype = FORMAT_VideoInfo;

      if (FAILED(samplegrabber->SetMediaType(&mt))) {
            printf("Unable to set media type.\n");
            return -1;
      }

      /* Get all the pins */
      IEnumPins *pinenum;
      IPin *cameraOut;
      IPin *grabberIn;
      IPin *grabberOut;
      IPin *nullIn;
      
      /* Find camera output pin */
      capfilter->EnumPins(&pinenum);
      pinenum->Reset();
      pinenum->Next(1, &cameraOut, NULL);
      pinenum->Release();

      /* Find grabber input/output pins */
      capgrabber->EnumPins(&pinenum);
      pinenum->Reset();
      pinenum->Next(1, &grabberIn, NULL);
      pinenum->Next(1, &grabberOut, NULL);
      pinenum->Release();

      /* Find null renderer input pin */
      capnull->EnumPins(&pinenum);
      pinenum->Reset();
      pinenum->Next(1, &nullIn, NULL);
      pinenum->Release();

      /* Connect all the pins */

      if (FAILED(filterGraph->Connect(cameraOut, grabberIn))) {
            printf("Unable to connect camera output pin.\n");
            return -1;
      } /* Graph looks like:
            Video Source -> Grabber   Null Renderer
      */

      if (FAILED(filterGraph->Connect(grabberOut, nullIn))) {
            printf("Unable to connect grabber output pin.\n");
            return -1;
      } /* Graph looks like:
            Video Source -> Grabber -> Null Renderer
      */

      /* Enable internal buffering (internal frame storage) for the grabber */
      if (FAILED(samplegrabber->SetBufferSamples(TRUE))) {
            printf("Unable to set internal buffering.\n");
            return -1;
      }

      /* We're capturing lots of frames, not 1, comment it out */
/*      if (FAILED(samplegrabber->SetOneShot(TRUE))) {
            printf("Unable to set one-shot grabbing.\n");
            return -1;
      }*/

hede:
      if (FAILED(MAC->Run())) {
            printf("Error running graph.\n");
            return -1;
      }

      Sleep(3000);

      /* This is needed for 1-frame capture too, comment it out */
/*      long eventCode = 0;
      if (FAILED(MAE->WaitForCompletion(INFINITE, &eventCode))) {
            printf("Error waiting for completion.\n");
            return -1;
      }*/

      long bufsize = 0;
      char *buffer;
      /* Get current frame from the internal buffer */
      samplegrabber->GetCurrentBuffer(&bufsize, NULL);

      if (bufsize == 0) {
            printf("Sample grabber does not have a buffer.\n");
            return -1;
      } else {
            buffer = (char *) malloc(bufsize); /* VS.NET does not like uncasted mallocs, WTF?!? */
            if (buffer == NULL) {
                  printf("Unable to allocate %u bytes of memory.\n", (unsigned) bufsize);
                  return -1;
            }
      }

      samplegrabber->GetCurrentBuffer(&bufsize, (long *) buffer);

      /* Dump the frame into a temporary file */

      FILE *of;

      if ((of = fopen("C:\\TEMP\\test.bin", "wb")) == NULL) return -2;
      fwrite(buffer, bufsize, 1, of);
      fclose(of);
      free(buffer);

goto hede;

      capgrabber->Release();
      capfilter->Release();
      capnull->Release();
      filterGraph->Release();

      CoUninitialize();

      return 0;
}
0
 
LVL 5

Expert Comment

by:Hammadian2
ID: 11979806
no need for all these things
if ur camera supports TWAIN (and probably it is)
you can use one of many activex controls available on the internet

here u are 3 controls availble to try:

http://www.download.com/3120-20-0.html?qt=webcam&tg=dl-2026

if you're looking for a free/fast solution
install yahoo messenger
and u'll find a control used for video capture installed with it :)

Anyway, no need for reverse engineering, direct communication with the port, or even API calls...

never re-invent the wheels
0
 
LVL 9

Author Comment

by:jhshukla
ID: 11981357
I have posted a link to this question is C/C++ forums as suggested by valadas2.
and i will try out the things suggested by all of you. i have to go to work now so i will post the further development tomorrow.

thx for help so far and if possible please try to locate ARToolkit documentation for me. (Google: ARToolkit Download)

thx again.
jaydutt
0
 
LVL 7

Expert Comment

by:aib_42
ID: 11984990
Note that most of the TWAIN-compatible cameras pop up a camera driver-supplied "capture" dialog which ruins the "capture frames without intervention from the user" aspect of such projects.
0
 
LVL 9

Author Comment

by:jhshukla
ID: 11996290
Ok I tried out everything that was suggested here and would prefer to follow Alex's suggestions.

@Alex (but everyone is welcome!)
I was going through SDK Documentation and found this variable called DeviceDriverIndex/DriverIndex/wIndex etc that can range from 0-9.
How can I find the index of the driver I want to use?

thx
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 11996450
Use 0. Usually there is one USB driver on the computer. SDK allows to select one of available drivers, but by default you can use first of them.
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 9

Author Comment

by:jhshukla
ID: 12002286
I tried using capCreateCaptureWindow but it gives me "unresolved external" error. Apparently, it is replaced by _capCreateCaptureWindowA in compiler-generated symbol table. I included the header file that contains the prototype but that does not help. Am I missing something?

Jaydutt
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 12003588
Add Vfw32.lib to the list of libraries for linker: Project - Settings - Link - Library modules.
0
 
LVL 9

Author Comment

by:jhshukla
ID: 12005871
thx
0
 
LVL 9

Author Comment

by:jhshukla
ID: 12006077
I can now create a CaptureWindow (i haven't tried connecting to the driver yet) but the window thus created is 100% transparent except for the titleBar and border. It does no close on Alt+F4 nor does it have Minimize/Maximixe/Close buttons. I know that I have to modify the window class for doing so but how can I do so?
The prototype for capCreateCaptureWindow is:
capCreateCaptureWindow(LPCTSTR, DWORD dwStyle, int, int, int, int, HWND Parent, int ID)

also how do I specify the WindowProcedure. Through window class?

thx
jaydutt
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 12006350
CaptureWindow should be child window. Create it as dialog or frame window child.
Check out CapTest and VidCap samples which are available in MSDN Library.
0
 
LVL 9

Author Comment

by:jhshukla
ID: 12006777
can't we specify wndProc for a child window?
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 12006950
This is code fragment from the CapTest sample:

// MainWndProc: Application Main Window Procedure
//
LONG FAR PASCAL MainWndProc(HWND hWnd, UINT Message, UINT wParam, LONG lParam)
{

    switch (Message) {
        case WM_CREATE:
        {
            // First create the capture window
            ghWndCap = capCreateCaptureWindow((LPTSTR)TEXT("Capture Window"),
                                              WS_CHILD | WS_VISIBLE,
                                              0, 0, 160, 120,
                                              (HWND) hWnd, (int) 0) ;

Don't care about WndProc for the capture window. Video Capture library manages this window showing image in it. You only need to call Video Capture functions for this.

You can download CapTest sample from here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample98/html/vcsmpcaptest.asp
But if you have MSDN Library, it is better to get this sample from it: just type CapTest in the Library index.
0
 
LVL 9

Author Comment

by:jhshukla
ID: 12035440
thanks for all the help. I finally figured out how to use ARtoolkit. I found a tutorial for it. It's very easy to use provided you read the source code carefully. It is open source and is actually a partial wrapper for Windows Multimedia and IO. thx anyways.

now i have this question about Visual Studio. As you told me earlier,
> Add Vfw32.lib to the list of libraries for linker: Project - Settings - Link - Library modules.
I added libarvideo.lib to my proj. It compiles and links perfectly but when I try to run the exe it complains about missing "libarvideo.dll". how do i go about solving this problem?

thanks
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 300 total points
ID: 12037222
lib file is required at link time, and dll is required at run time. libarvideo.dll should be placed in one of the following places:
1) Current directory;
2) The same directory where executable file is placed;
3) Windows system directory;
4) Directories available through PATH environment variable.

When executable starts, it tries to find all Dll it needs. If at least one of libraries is not found, it shows error message and exits.
0
 
LVL 9

Author Comment

by:jhshukla
ID: 12041214
thanks. I learned a lot.
0

Featured Post

Backup Your Microsoft Windows Server®

Backup all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

Join & Write a Comment

Suggested Solutions

In this article we have discussed the manual scenarios to recover data from Windows 10 through some backup and recovery tools which are offered by it.
Great sound, comfort and fit, excellent build quality, versatility, compatibility. These are just some of the many reasons for choosing a headset from Sennheiser.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now