How to access the content of BITBLT ?

Blitz3D Forums/Blitz3D Userlibs/How to access the content of BITBLT ?

jfk EO-11110(Posted 2005) [#1]
Hi
I am using a BITBLT Operation that was added by a userlib (fast Get Desktop example). It works nicely, there is only one problem: I cannot access the Pixels delivered by BITBLT. The image is on my blitz window, but when I use CopyRect (both, backbuffer and frontbuffer), all I get is an empty image. It seems like BITBLT is only sticking a canvas onto the blitzwindow, but doesn not really paint into the blitz buffer.

How could this be solved? (Currently I am using GetPixel, but it's WAY to slow, I urgently need something better.) Is there a way to make BitBLT draw directly into Blitz's Backbuffer? Or even better, into a Blitz Image Buffer?


Apocalypse(Posted 2005) [#2]
Here is some code from a function which uses BitBlt to capture bits into a DIB...


    pBITMAP.bmiHeader.biSize = SIZEOF(pBITMAP.bmiHeader)
    pBITMAP.bmiHeader.biBitCount = 24
    pBITMAP.bmiHeader.biCompression = %BI_RGB
    pBITMAP.bmiHeader.biWidth = iWidth
    pBITMAP.bmiHeader.biHeight = -iHeight
    pBITMAP.bmiHeader.biClrUsed = 0
    pBITMAP.bmiHeader.biSizeImage = 0
    pBITMAP.bmiHeader.biPlanes = 1

    hDIBDC = CreateCompatibleDC(hDC)
    hDIB = CreateDIBSection(hDIBDC, pBITMAP, %DIB_RGB_COLORS, hImage, 0, 0)

    IF NOT (SelectObject(hDIBDC, hDIB)=%NULL) THEN

        Rtn = BitBlt(hDIBDC, 0, 0, iWidth, iHeight, hDC, 0, 0, %SRCCOPY)
        BuffSize = iWidth * iHeight * 3
        Rtn = MoveMemory(pRGB, hImage, buffsize)
        FUNCTION = BuffSize

    END IF

    Rtn = DeleteDC (hDIBDC)
    Rtn = DeleteObject (hDIB)    



Hope this helps...


jfk EO-11110(Posted 2005) [#3]
thanks, but it didn't really help me. What is hImage, and how do I implement this in Blitz?
Although I already did a CreateCompatibleDC, plus a CreateCompatibleBitmap, and was able to Bitblit to it, I have no idea how to access the image created outside Blitz.

I need this to play a movie frame by frame. Unfortunately the Blitzes built in Movie Command is doing realtime correcture at all costs, so it is impossible to pause a movie. Using userlibs with the mciSendString Commmands at the other hand forces me to use BITBLT that results in the problems I described initially.


Apocalypse(Posted 2005) [#4]
hImage is NULL

The image data is available via the memory pointer pRGB.


jfk EO-11110(Posted 2005) [#5]
pRGB? Is that some kind of a win constant or function? I'm really bad when it comes to windows system programming.

What do you think, if I give you what I got so far, could you give it a try and implement it? I rarely ask other people so directly, but I am stuck with this issue since several days now.


Tom(Posted 2005) [#6]
Are you ok with compiling a DLL? If not lemme know and I'll whip one up.

This code will blit from any HWND direct to a BB Image

BBDECL int BBCALL BitBlitHWND2Image(HWND hnd, unsigned int buffer, int sx, int sy, int sw, int sh, int dx, int dy)
{
	HRESULT hr;
	int srcFrame=0;
	buffer = (unsigned int) *((int*)(buffer+4));
	buffer = (unsigned int) *((int*)(buffer+(4 * srcFrame)));

	IDirectDrawSurface7 *destTex=NULL;
	destTex = (IDirectDrawSurface7*) *((int*)(buffer+12));

	HDC sDC=0;
	HDC dDC=0;

	sDC=GetDC(hnd);
	if(!sDC) return 0;

	hr=destTex->GetDC(&dDC);
	if(FAILED(hr))
	{
		ReleaseDC(hnd,sDC);
		return hr;
	}

	BOOL result=BitBlt(dDC,sx,sy,sw,sh,sDC,dx,dy,SRCCOPY);
	destTex->ReleaseDC(dDC);
	ReleaseDC(hnd,sDC);
	return result;
}

Note that I've left out the source frame from the parameters, you can just add it in if you wish (does work:)


Here's an example of calling it, I'm using GetDesktopWindow() so you'll need to have that setup in your user32.decls for this test:

Graphics 800,600,32,2

image=CreateImage(512,512)
srcHWND=api_GetDesktopWindow()


While Not KeyDown(1)
	BitBlitHWND2Image(srcHWND,image,0,0,512,512,0,0)
	DrawImage image,MouseX(),MouseY()

	Flip
Wend
End


Cya!
Tom


Apocalypse(Posted 2005) [#7]
From your example code you are not blitting pixel data to the DirectX Surface, but sending pixels to the target window of the DirectX Clipper. I would try locking the DirectX surface and copying the pixel data directly using RTLMovememory or some similar copy method.


Tom(Posted 2005) [#8]
I'm getting a device context from a legal DX surface:

destTex->GetDC(&dDC);

The API blit does any neccessary color conversion.

You can't lock the surface else it won't work, which is beside the point because... it works :O)

Does it not work for you?

Tom


Apocalypse(Posted 2005) [#9]
Would a function that lets you Blt to a Blitz Image object be useful? I am considering it as one of the functions for my Userlib.


jfk EO-11110(Posted 2005) [#10]
Thanks a lot for your help. Tom, unfortunately I am not familar with making DLLs. Apocalypse - yes, this would be very useful.


jfk EO-11110(Posted 2005) [#11]
I got it kind of working. I found Toms old article about how to access imagebuffers the quick'n'dirty way, using a redirected Bank that points to an Imagebuffer, then use CreateComaptibleDC etc to make Bitblit writing to it. I tried to use GetDIBits, but it refused to work (I only get a black rectangle), maybe I made something wrong with the BitmapInfo Struct. Anyway, I used GetBitmapBits like in your example, although MS says it's obsolete (using 16 Bit) and you should use GetDIBits instead. A least it worked.

Now my problem is: I get approx 0.7 frames per second when I use it together with an open Movie that plays frame by frame, using mciSendstring Step...

So the whole task is:
Play an Aviframe
blitblit this to the Comptible Image
Move the Bits to the Blitz Imagebuffer

I can't believe that this is so slow. I made some tests with RTLMoveMemory and it moves 720*576*4Bytes (my frame size) a thousand times in 14 milisecs.
If I play the Avi Frame by Frame without to copy or blit anything, then I get decent framereates, maybe 15 or 25 per second. Maybe there is some kind of Data collision on the bus since the Bitblit and Movie playing commands may be parallel threads on the system level ?

The most efficent way would be to redirect MCI to draw the movie directly into the blitz image buffer. I just made some more tests and it seems, bitblt is the worst brake here.
If I could use MoveMemory instead, that would be cool.
will this Odysee ever end :/


Apocalypse(Posted 2005) [#12]
Check over in the Worklogs and see if any of the functions I've made so far would help you...

http://www.blitzbasic.com/logs/userlog.php?user=7138&log=440


sswift(Posted 2005) [#13]
"I can't believe that this is so slow. I made some tests with RTLMoveMemory and it moves 720*576*4Bytes (my frame size) a thousand times in 14 milisecs."

Is that copying from video memory though? Copying from video memory is generally slow. I don't know if Windows buffers the screen in main memory or not, but I doubt they do.


Tom(Posted 2005) [#14]
JFK: Try this

http://www.tomspeed.com/blit.zip

Put both files in the zip into blitz3d\userlibs\

As I said before, you'll need the GetDesktopWindow() User32 API decls if you want to try my test code a few posts back, or supply your own Hwnd var

Here's my GetDesktopWindow declaration from User32.decls
.lib "user32.dll"
api_GetDesktopWindow%():"GetDesktopWindow"


Tom


jfk EO-11110(Posted 2005) [#15]
Apocalypse - this sounds very good, especially the DIB Memory Pointer thing, since it would allow to use TRLMoveMemory to move the whole frame in one step. This should be extremly fast. At least if the Image buffer is not stored in VRam, as Sswift mentioned (yes, it's a Bitmap, not the Desktop). BTW. is the VRam mapped linearly in the 32 Bit adress space?

Tom - thanks, I'll try that right now!


Apocalypse(Posted 2005) [#16]
JFK:
I do not believe the VRAM is linearly mapped in your apps address space. The VRAM is only accessible via the video driver and calls made through the video driver and the DMA controller. However, if you create a DIB and Blit to the DC of the DIB, you can directly copy the pixel data via the DIB's pBits pointer using RTLMoveMemory.

My userlib currently only supports 24bit and 32bit RGB DIBs.


jfk EO-11110(Posted 2005) [#17]
Tom I tried the dll exactly as you described, but for some reason it didn't have an impact on the image. DX9a WinME, Radeon 9200se, Blitz3D 1.88.


jfk EO-11110(Posted 2005) [#18]
Apocalypse - if it isn't the regular adress space, how can you copy data with RTLMovememory then?


Apocalypse(Posted 2005) [#19]
You asked if VRAM is mapped to an apps linear address space, not if the frame of your AVI was stored there. If you Blt an image to the DIB's device context, the pixel data will be stored in your apps linear address space.

Are you trying to capture an image from the screen?


jfk EO-11110(Posted 2005) [#20]
I'd like to capture a Frame of the MCI Avi player directly, but whatever I do, it writes to the screen. If I minimize the mci objects HWND, blitblit delivers trash, it really seems like i HAVE to capture it on the screen, although I'd prevere to do so "offscreen".


Apocalypse(Posted 2005) [#21]
It sounds like the MCI driver is writing to a video overlay which is outside of your apps ability to capture. You need to either force MCI to use Windows GDI functions to draw the image to the screen or you need to decode the AVI using a different method other than the MCI interface.

I guess the best solution will be to open the AVI using the AVI library instead. This gives you 100% control over when and where each frame is stored. I will look into adding some AVI functions to my DLL.


Apocalypse(Posted 2005) [#22]
JFK:

I finished adding the AVI functions to my helper DLL project. Check it out and see if it does what you need.


jfk EO-11110(Posted 2005) [#23]
Ok, I'll try this asap, thanks!


jfk EO-11110(Posted 2005) [#24]
Currently I am kinda busy with non-blitz related work (job), I got to finish some stuff, writing docs etc. I'm pretty late already. i hope I can continue this project this weekend.


jfk EO-11110(Posted 2005) [#25]
As I explained earlier, I needed this Bitblit access to grab the frames of a movie quickly that was played using the MciSendString commands of the Win Api.

I have made it work, although the long way over a compatible bitmap made the whole thing very slow, in the end it was almost as slow as using GetPixel to grab the frames (more than a second for one frame in PAV DV Format, that's 720*576 pixies)

The problem was, Mci didn't play the movie in the blitz window (altough I told it to do so, using the window parent feature of mci aviplay), instead it played it on some kind of overlay. This resulted not only in continous Z-Fighting and flashing of the Blitzwindow and the Overlay, it was also impossible to grab the movie frames in the blitzwindow, using copyrect or readpixelfast. That's why I introduced Bitblit, hoping this would at least let me access the pixels. But Bitblit still blitted only to some kind of canvas (that's why I asked this question, how to access the content of blitblit) and this was driving me crazy. As I said, in the enf^d it worked, but very slowly.

Well, the good news is, it works now without to use Blitblit at all. Only problem: it works only in fulscreen mode. If I use mci to draw the movie onto the blitz window in fullscreen mode, I CAN grab it on the frontbuffer, using copyrect. And it's blitzning fast. All I have to do after a Step Command, that will show the next frame of the movie, is wait a few millisecs to let windows draw the frame before I can grab it (to prevent dropouts). But, depending on the machine speed, this is only a dozen or so millisecs. I Still have to optimize the dropout detection, but basicly it works very well.

Of course, I wanted to use a windowed Mode since it's gonna be a tool, but hey - probably I am gonna grab the desktop as an image und use the bottom bar ON the fullscreen window to create the fake impression of a windowed app, and as soon as the user clicks the bottom bar, I'll minimize the fullscreen app. Not sure of this right now.


jfk EO-11110(Posted 2005) [#26]
Of course, there is yet another problem :) Now grabing frames in fullscreen mode works ok, but since I want to mix etc. multiple movies and then save them immediately to a destination Avi, I need to use BlitzAvi. BlitzAvi works perfectly in windowed mode (thanks to the author, BTW), but in Fullscreen Mode the App pauses after the overwrite-file-dialog as well as after the Codec Selection Dialog. It pauses until I minimize the Blitz Fullscreen App using Alt-Tab, and then maximize it again manually. I tried a lot of automatic Minimizing, Maximizing etc. using SetWindowPos, but nothing seemed to work. The problem is, when I minimize a Blitz Fullscreen App, it will be kind of frozen until somebody clicks its icon. Probably I sould run a second task that will watch the main app and forces it to be maximized a few seconds after losing focus - but that's real messy. Any better ideas?


jfk EO-11110(Posted 2005) [#27]
Finally I got it working. It's all a bit more complicated than it should be, but who cares, as long as the result is ok.

What I do is:
Right after the "CreateAviFile" Command (that usually asks if it should overwrite a file and then pauses Blitz) I run a little Exe, using ExecFile. The Exe is a simple app that is doing the following:

receiving the HWND of the calling Blitz App on the commandline.
ShowWindow said HWND, SHOWNORMAL
(Now Blitz is maximized again, but still paused, it still needs a Mouseclick for some reason, even setFocus didn't do the job, so I simulate a Mouseclick:)
delay 10
mouse_event($2,0,0,0,0) ; left mouse down
delay 10
mouse_event($4,0,0,0,0) ; left mouse up
delay 10
end

I also run this second Exe one time after the very first call of WriteImageToAviFile(), for the same reason (because this opens the Codec Selection when it's called the very first time, that pauses Blitz as well as described earlier).

mouse_event and ShowWindow are declared in user32.decls. So running the second Exe kicks the Main Fullscreen window down to the tray, where it resides paused, frozen. It will not be able to regain focus by itself. So the second app will reactivate it. It seems like this little Pause is exactly what BlitzAvi needs. Of course, it looks ugly when the Fullscreen App flashes out and back in 2 times when it starts rendering, but hey, it's still better than ad popup windows :P

Currently this is the only way for me to
-Open multiple Avis using MciSendString and play them Frame by Frame simultanously
-Mix Frames (transparent areas etc.), add particles etc.
-Save the resulting frames to a destination Avi.