| PureBasic Forum http://www.purebasic.fr/english/ |
|
| ESCAPI problems http://www.purebasic.fr/english/viewtopic.php?f=7&t=25412 |
Page 1 of 1 |
| Author: | Hi-Toro [ Tue Jan 16, 2007 5:16 pm ] |
| Post subject: | ESCAPI problems |
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] |
|
| Author: | freak [ Tue Jan 16, 2007 8:33 pm ] |
| Post subject: | |
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 |
|
| Author: | Hi-Toro [ Tue Jan 16, 2007 9:00 pm ] |
| Post subject: | |
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! |
|
| Author: | Hi-Toro [ Tue Jan 16, 2007 11:02 pm ] |
| Post subject: | |
I got the Blitz version working too -- thanks again, Freak! http://www.blitzmax.com/Community/posts.php?topic=66505 |
|
| Author: | Hi-Toro [ Wed Jan 17, 2007 10:45 am ] |
| Post subject: | |
Freak, is it OK if Jari (the ESCAPI developer) includes this code in his distribution (basically, as public domain code)? |
|
| Author: | Flype [ Wed Jan 17, 2007 10:57 am ] |
| Post subject: | |
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. |
|
| Author: | Hi-Toro [ Wed Jan 17, 2007 11:13 am ] |
| Post subject: | |
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. |
|
| Author: | Flype [ Wed Jan 17, 2007 12:00 pm ] |
| Post subject: | |
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 ;- |
|
| Author: | freak [ Wed Jan 17, 2007 1:24 pm ] |
| Post subject: | |
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. |
|
| Author: | Hi-Toro [ Wed Jan 17, 2007 4:47 pm ] |
| Post subject: | |
Cool, thanks -- I've let him know. |
|
| Author: | Hi-Toro [ Wed Jan 17, 2007 4:50 pm ] |
| Post subject: | |
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!) |
|
| Page 1 of 1 | All times are UTC + 1 hour |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|