It is currently Thu Jul 29, 2010 5:40 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: ESCAPI problems
PostPosted: Tue Jan 16, 2007 5:16 pm 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
Anyone had any luck with ESCAPI 2.0 for easy webcam capture on Windows?

http://sol.gfxile.net/code.html

I wrote this code (just place it in the same folder as escapi.dll from the escapi20.zip archive and make sure your camera is plugged in!), and all the function calls seem to work, but I just get black data (all zeroes) from the webcam after capture:

Code:
; PB4...

Structure SimpleCapParams
   mTargetBuf.l   ; Must be at least mWidth * mHeight * SizeOf(int) of size!
   mWidth.l
   mHeight.l
EndStructure

camnum = 0 ; First device found; adjust to suit...

esc = OpenLibrary (#PB_Any, "escapi.dll")

If esc
   
   initCOM = GetFunction (esc, "initCOM")
   countCaptureDevices = GetFunction (esc, "countCaptureDevices")
   initCapture = GetFunction (esc, "initCapture")
   deinitCapture = GetFunction (esc, "deinitCapture")
   doCapture = GetFunction (esc, "doCapture")
   isCaptureDone = GetFunction (esc, "isCaptureDone")
   getCaptureDeviceName = GetFunction (esc, "getCaptureDeviceName")
   ESCAPIDLLVersion = GetFunction (esc, "ESCAPIDLLVersion")

   CallFunctionFast (initCOM)

   Debug "ESCAPIDLLVersion:"
   Debug "$" + Hex (CallFunctionFast (ESCAPIDLLVersion))
   Debug ""
   
   Debug "countCaptureDevices:"
   Debug CallFunctionFast (countCaptureDevices)
   Debug ""

   cam$ = Space (#MAX_PATH)
   CallFunctionFast (getCaptureDeviceName, camnum, @cam$, #MAX_PATH)
   Debug cam$
   Debug ""

   scp.SimpleCapParams
   scp\mWidth = 320
   scp\mHeight = 240
   scp\mTargetBuf = AllocateMemory (scp\mWidth * scp\mHeight * 4)
   
   Debug "initCapture:"
   Debug CallFunctionFast (initCapture, camnum, @scp)
   Debug ""

   For a = 1 To 10
      CallFunctionFast (doCapture, camnum)
      Repeat
         Delay (1)
      Until CallFunctionFast (isCaptureDone, camnum)
   Next

   Debug "Size:"
   Debug scp\mWidth
   Debug scp\mHeight
   
   image = CreateImage (#PB_Any, scp\mWidth, scp\mHeight)
   StartDrawing (ImageOutput (image))
   
   For y = 0 To scp\mHeight - 1
      For x = 0 To scp\mWidth - 1
         Plot (x, y, scp\mTargetBuf + count)
         count = count + 1
      Next
   Next
   
   StopDrawing ()

   CallFunctionFast (deinitCapture, camnum)

   CloseLibrary (esc)
   
EndIf

window = OpenWindow (#PB_Any, 320, 200, 320, 200, "ESCAPI 2")

CreateGadgetList (WindowID (window))
ImageGadget (#PB_Any, 0, 0, 320, 200, ImageID (image))

Repeat

Until WaitWindowEvent () = #PB_Event_CloseWindow


I used the setupESCAPI() function from escapi.cpp in the archive as a guide to setting things up, as well as using the "simplest" example as a guide to capturing. The only thing I can imagine is that something's going wrong with the initCOM call... I'll never understand COM stuff as long as I live.

This also fails in BlitzMax (see my post here: http://www.blitzmax.com/Community/posts.php?topic=66505), yet the provided binary examples work fine, and it's just a simple C-style API.

Anyone got any ideas as to what might be wrong?

(Heh, spot the forum bug with ? in URLs!)
[/url]

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 16, 2007 8:33 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 5:21 pm
Posts: 4516
Location: Germany
Boy, this one was hard to spot :)

Its actually only your drawing code:
Code:
Plot (x, y, scp\mTargetBuf + count)

What you do here is calculate the position of the pixel in memory, and then use the
memory location as the pixel value.
You have to PeekL() the value from the address.
Also the calculation is wrong. Each pixel is 4 bytes wide, so you have to increase the count by 4 each time.
Also the pixel order is different, it is stored in BGR, so this needs to be reversed too.

Something like this:
Code:
          pixel = PeekL(scp\mTargetBuf + (y*scp\mWidth + x) * 4)
          rgb   = RGB((pixel >> 16) & $FF, (pixel >> 8) & $FF, pixel & $FF)
          Plot(x, y, rgb)


Another note:
The dll functions are in the cdecl calling convention (the definitions have no _stdcall or macro that stands for it)
So you have to use CallCFunctionFast() or you will get trouble in procedures etc because the stack is wrong.

As i did not get your code to run at all at first, i wrote my own.
It uses prototypes, which is much cleaner than Call(C)FunctionFast.

escapi.pb includefile
Code:
;/* Extremely Simple Capture API */

Structure SimpleCapParams
   *mTargetBuf ; Must be at least mWidth * mHeight * SizeOf(int) of size!
   mWidth.l
   mHeight.l
EndStructure

;/* Return the number of capture devices found */
PrototypeC countCaptureDevicesProc()

; /* initCapture tries To open the video capture device.
;  * Returns 0 on failure, 1 on success.
;  * Note: Capture parameter values must Not change While capture device
;  *       is in use (i.e. between initCapture And deinitCapture).
;  *       Do *Not* free the target buffer, Or change its pointer!
;  */
PrototypeC initCaptureProc(deviceno, *aParams.SimpleCapParams)

;/* deinitCapture closes the video capture device. */
PrototypeC deinitCaptureProc(deviceno)

;/* doCapture requests video frame To be captured. */
PrototypeC doCaptureProc(deviceno)

;/* isCaptureDone returns 1 when the requested frame has been captured.*/
PrototypeC isCaptureDoneProc(deviceno)


;/* Get the user-friendly name of a capture device. */
PrototypeC getCaptureDeviceNameProc(deviceno, *namebuffer, bufferlength)


;/* Returns the ESCAPI DLL version. 0x200 For 2.0 */
PrototypeC ESCAPIDLLVersionProc()

; marked as "internal" in the example
PrototypeC initCOMProc()

Global countCaptureDevices.countCaptureDevicesProc
Global initCapture.initCaptureProc
Global deinitCapture.deinitCaptureProc
Global doCapture.doCaptureProc
Global isCaptureDone.isCaptureDoneProc
Global getCaptureDeviceName.getCaptureDeviceNameProc
Global ESCAPIDLLVersion.ESCAPIDLLVersionProc


Procedure setupESCAPI()
   
  ; load library
  capdll = OpenLibrary(#PB_Any, "escapi.dll")
  If capdll = 0
    ProcedureReturn 0
  EndIf
 
   ;/* Fetch function entry points */
   countCaptureDevices  = GetFunction(capdll, "countCaptureDevices")
   initCapture          = GetFunction(capdll, "initCapture")
   deinitCapture        = GetFunction(capdll, "deinitCapture")
   doCapture            = GetFunction(capdll, "doCapture")
   isCaptureDone        = GetFunction(capdll, "isCaptureDone")
   initCOM.initCOMProc  = GetFunction(capdll, "initCOM")
   getCaptureDeviceName = GetFunction(capdll, "getCaptureDeviceName")
   ESCAPIDLLVersion     = GetFunction(capdll, "ESCAPIDLLVersion")
   
   If countCaptureDevices = 0 Or initCapture = 0 Or deinitCapture = 0 Or doCapture = 0 Or isCaptureDone = 0 Or initCOM = 0 Or getCaptureDeviceName = 0 Or ESCAPIDLLVersion = 0
     ProcedureReturn 0
   EndIf
   
   ;/* Verify DLL version */
   If ESCAPIDLLVersion() < $200
     ProcedureReturn 0
   EndIf
 
   ;/* Initialize COM.. */
   initCOM(); 
 
  ; returns number of devices found
  ProcedureReturn countCaptureDevices()
EndProcedure




test code
Code:
XIncludeFile "escapi.pb"

device = 0

count = setupESCAPI()
Debug "init: " + Str(count)

If count = 0
  End
EndIf

name$ = Space(1000)
getCaptureDeviceName(device, @name$, 1000)
Debug "name: " + name$

scp.SimpleCapParams
scp\mWidth = 320
scp\mHeight = 240
scp\mTargetBuf = AllocateMemory (scp\mWidth * scp\mHeight * 4)

If initCapture(device, @scp)
  Debug "cap init successful" 
 
  image = CreateImage(#PB_Any, 320, 240)
 
  OpenWindow(0, 0, 0, 320, 240, name$, #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  CreateGadgetList(WindowID(0))
  ImageGadget(0, 0, 0, 320, 240, ImageID(image))
 
  Quit = 0
  Repeat
 
    doCapture(device)
    While isCaptureDone(device) = 0
      If WaitWindowEvent(1) = #PB_Event_CloseWindow
        Quit = 1
        Break
      EndIf       
    Wend
   
    If StartDrawing(ImageOutput(image))   
      For y = 0 To scp\mHeight - 1
        For x = 0 To scp\mWidth - 1
          pixel = PeekL(scp\mTargetBuf + (y*scp\mWidth + x) * 4)
          rgb   = RGB((pixel >> 16) & $FF, (pixel >> 8) & $FF, pixel & $FF)
          Plot(x, y, rgb)
        Next
      Next
     
      StopDrawing()
      SetGadgetState(0, ImageID(image))
    EndIf
     
 
  Until Quit

  deinitCapture(device)
Else
  Debug "init capture failed!"
EndIf

End


I can watch my TV-cards input now from PB :)

_________________
Good judgement comes from experience, and experience comes from bad judgement.
-- Fred Brooks, Jr


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 16, 2007 9:00 pm 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
Ah, brilliant, thanks Freak. I pretty much knew my drawing code would be completely wrong but was desperately trying to get *anything* out of it to start with...

Prototypes look interesting -- haven't tried those yet. I would never have noticed the problem with the calling convention...

Thanks again!

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 16, 2007 11:02 pm 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
I got the Blitz version working too -- thanks again, Freak!

http://www.blitzmax.com/Community/posts.php?topic=66505

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 10:45 am 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
Freak, is it OK if Jari (the ESCAPI developer) includes this code in his distribution (basically, as public domain code)?

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 10:57 am 
Offline
Addict
Addict
User avatar

Joined: Tue Jul 22, 2003 5:02 pm
Posts: 1490
Location: Nantes, France
it's very interessant - i tried and it works perfectly.

but i think this part is very slow :

Code:
    If StartDrawing(ImageOutput(image))   
      For y = 0 To scp\mHeight - 1
        For x = 0 To scp\mWidth - 1
          pixel = PeekL(scp\mTargetBuf + (y*scp\mWidth + x) * 4)
          rgb   = RGB((pixel >> 16) & $FF, (pixel >> 8) & $FF, pixel & $FF)
          Plot(x, y, rgb)
        Next
      Next
      StopDrawing()
      SetGadgetState(0, ImageID(image))
    EndIf


320x240 is acceptable but highest resolution are just too slow.

is this image-format a BMP format without the header ?

No way to catch the buffer and draw the entire image in one or two function (CatchImage/DrawImage) ?

Ok, this way, I understand that it is handy for sharing the imagedata via networks / differents operating systems. It allow many perspectives.

In all cases it's a very handy lib.

_________________
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 11:13 am 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
It should be perfectly possible to grab directly to a buffer and display more directly. Freak was just showing me how to extract and draw the raw data.

I found I can grab directly to a 'PixMap' in BlitzMax for a large speedup in the drawing process. The data is in what BlitzMax calls "PF_BGRA8888" format, ie. four bytes per pixel, ordered as blue, green, red and alpha components, with 8 bits per component. I think this is the same as BMP with no header, as you suggest.

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 12:00 pm 
Offline
Addict
Addict
User avatar

Joined: Tue Jul 22, 2003 5:02 pm
Posts: 1490
Location: Nantes, France
thank you for the answer Hi-Toro.

so something like this should be possible :?: ?

Code:
;- initialization.

w = 320
h = 240

ImageHdrLen.l = 128 ; don't know this one - to be modified.
ImageBufLen.l = (w * h * 4)
ImageMemLen.l = ImageHdrLen + ImageBufLen
ImageMemPtr.l = AllocateMemory(ImageMemLen)
ImageBufPtr.l = ImageMemPtr + ImageHdrLen

scp.SimpleCapParams
scp\mWidth     = w
scp\mHeight    = h
scp\mTargetBuf = ImageBufPtr

;- inside the loop.

If CatchImage(0, ImageMemPtr, ImageMemLen, #PB_Image_DisplayFormat)
  DrawImage(0, 0, 0, w, h)
EndIf

;-

_________________
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 1:24 pm 
Offline
PureBasic Team
PureBasic Team
User avatar

Joined: Fri Apr 25, 2003 5:21 pm
Posts: 4516
Location: Germany
Hi-Toro wrote:
Freak, is it OK if Jari (the ESCAPI developer) includes this code in his distribution (basically, as public domain code)?


Sure, why not.

_________________
Good judgement comes from experience, and experience comes from bad judgement.
-- Fred Brooks, Jr


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 4:47 pm 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
Cool, thanks -- I've let him know.

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 17, 2007 4:50 pm 
Offline
Enthusiast
Enthusiast

Joined: Sat Apr 26, 2003 3:23 pm
Posts: 224
Oops, sorry Flype... I think that looks about right, but I haven't played with graphical stuff much in PB. You'll have to experiment here, sorry. (Unless someone else knows!)

_________________
James L Boyd
http://www.hi-toro.com/
Death to the Pixies!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 0 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye