ESCAPI problems

Everything else that doesn't fall into one of the other PB categories.
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

ESCAPI problems

Post by Hi-Toro »

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: Select all

; 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 Boyd
http://www.hi-toro.com/
Death to the Pixies!
freak
PureBasic Team
PureBasic Team
Posts: 5929
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Boy, this one was hard to spot :)

Its actually only your drawing code:

Code: Select all

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: Select all

          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: Select all

;/* 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: Select all

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 :)
quidquid Latine dictum sit altum videtur
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

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 Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

I got the Blitz version working too -- thanks again, Freak!

http://www.blitzmax.com/Community/posts.php?topic=66505
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

Freak, is it OK if Jari (the ESCAPI developer) includes this code in his distribution (basically, as public domain code)?
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

it's very interessant - i tried and it works perfectly.

but i think this part is very slow :

Code: Select all

    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
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

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 Boyd
http://www.hi-toro.com/
Death to the Pixies!
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

thank you for the answer Hi-Toro.

so something like this should be possible :?: ?

Code: Select all

;- 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
freak
PureBasic Team
PureBasic Team
Posts: 5929
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

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.
quidquid Latine dictum sit altum videtur
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

Cool, thanks -- I've let him know.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

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 Boyd
http://www.hi-toro.com/
Death to the Pixies!
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: ESCAPI problems

Post by chris319 »

Please see the post below for an improved ESCAPI webcam program:

http://www.purebasic.fr/english/viewtop ... 44#p391944

The ESCAPI project:

http://sol.gfxile.net/escapi/index.html
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: ESCAPI problems

Post by chris319 »

I have tried escapi.dll from escapi 3 in my own purebasic webcam program and it works OK.

I will look at the blitzmax program but make no promises.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: ESCAPI problems

Post by chris319 »

The existing escapi.pbi code works with escapi version 3.

Code: Select all

;/* 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
Last edited by chris319 on Wed Mar 02, 2016 5:54 pm, edited 1 time in total.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: ESCAPI problems

Post by chris319 »

Please disregard.
Last edited by chris319 on Wed Mar 02, 2016 5:55 pm, edited 1 time in total.
Post Reply