wxBitmap constructor performance Win32 Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Direwolf
In need of some credit
In need of some credit
Posts: 5
Joined: Sat Aug 27, 2005 9:47 pm

wxBitmap constructor performance Win32

Post by Direwolf »

We're trying to display a real-time network video stream in a wxFrame window on MSW. Video frames are decoded, loaded into a wxImage object, and then displayed in the frame. This requires converting the wxImage to a wxBitmap for display. But, the wxBitmap constructor is extraodinarily slow on Win32.

I profiled the app and discovered that the wxBitmap constructor calls the Window's GDI function CreateDIBitmap(). This function is responsible for up to 50% of the runtime of the entire application. Ouch.

Is there a way to display wxImage objects in a wxFrame without creating a new wxBitmap every single time OnPaint() is called?

Here's the OnPaint(), it's pretty basic. The wxBitmap constructor can take up to a couple seconds to complete.

Code: Select all

// ShowFrame inherits wxFrame
void ShowFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
{
        // ShowImage contains the video frame.
	wxBitmap BMP(ShowImage);  // <<<< REALLY, REALLY, SLOW!
	wxBufferedPaintDC DC(this);
	DC.DrawBitmap(BMP,0,0,false);
}
Any ideas?

Thanks!

-- Brian Stone[/code]
ssigala
Earned some good credits
Earned some good credits
Posts: 109
Joined: Fri Sep 03, 2004 9:30 am
Location: Brescia, Italy

Post by ssigala »

Hello,

the wx api graphics routines were not written for real-time data display and I think that no wx-based portable solution exists.

You will find the answer in the Windows DirectDraw family of routines but, yes, that is not portable.
Sandro Sigala - Kynosoft, Brescia
Jorg
Moderator
Moderator
Posts: 3971
Joined: Fri Aug 27, 2004 9:38 pm
Location: Delft, Netherlands

Post by Jorg »

wxOpenGL was portable was it not?

Regards,
- Jorgen
Forensic Software Engineer
Netherlands Forensic Insitute
http://english.forensischinstituut.nl/
-------------------------------------
Jorg's WasteBucket
http://www.xs4all.nl/~jorgb/wb
Direwolf
In need of some credit
In need of some credit
Posts: 5
Joined: Sat Aug 27, 2005 9:47 pm

Post by Direwolf »

I coded a video processor using DirectShow a while back. To display each frame I sent the image to the DC through the SetDIBitsToDevice function. This was also not very efficient, but it was fast enough for 24fps video.

I suspect the problem could be solved, for the most part, by implementing the GDI function SetBitmapBits in the wxBitmap class for MSW. This way, the wxBitmap could be stored as a private global in a class, allocated once, and reused. As opposed to creating a new wxBitmap for every frame.

Any reason why that wouldn't work?

-- Brian
Direwolf
In need of some credit
In need of some credit
Posts: 5
Joined: Sat Aug 27, 2005 9:47 pm

Post by Direwolf »

Well, I've worked on the problem for about a week now with no luck. I've tried just about everything I can think of, and about all I can figure out is that there is something in the conversion from the DIB to the Window's DDB that is just plain slow. I've tried building compatible DC's, reusing bitmap's, calling BitBlt directly, drawing directly to the DC, but there's still something going on inside GDI that I just can't grasp.

So, I'm giving up. I'm going to code a DirectShow source filter to do this job, and that'll be the end of it. But, if someone has a solution that they can share, I'm still interested. I sincerely appreciate your help.

-- Brian Stone
ssigala
Earned some good credits
Earned some good credits
Posts: 109
Joined: Fri Sep 03, 2004 9:30 am
Location: Brescia, Italy

Post by ssigala »

Direwolf wrote: So, I'm giving up. I'm going to code a DirectShow source filter to do this job, and that'll be the end of it. But, if someone has a solution that they can share, I'm still interested. I sincerely appreciate your help.
You might give a try at SDL, IIRC the Windows version interfaces directly to DirectDraw and should be fast (and you don't need to write non-portable unreadable windows-api code).

A wx interface exists at:
http://code.technoplaza.net/wx-sdl/

quote: "wxWidgets is not a good game programming library, but it is an excellent cross-platform widget toolkit. SDL is an excellent cross-platform game programming library." Game programming library means real-time graphics, and that's what you want.
Sandro Sigala - Kynosoft, Brescia
Direwolf
In need of some credit
In need of some credit
Posts: 5
Joined: Sat Aug 27, 2005 9:47 pm

Post by Direwolf »

ssigala wrote:You might give a try at SDL, IIRC the Windows version interfaces directly to DirectDraw and should be fast (and you don't need to write non-portable unreadable windows-api code).
This is fantastic! I'll definitely give this a try and let you know how it turns out.

-- Brian
Direwolf
In need of some credit
In need of some credit
Posts: 5
Joined: Sat Aug 27, 2005 9:47 pm

Post by Direwolf »

After more testing, it turns out that my profiler was lying to me. The display system wasn't slow... it is the HTTP stream that is slow. We're streaming an MJPG stream from an IP camera. The only way to capture each frame is to read the stream character by character, locate the packet boundary, strip the headers, and send the rest of the stream to the JPEG decoder. We were reading one character at a time from the stream via calls to wxInputStream::Read(). Why the profiler didn't pick this up, I don't know, but this is clearly where our speed problem lies.

I modified the program to read in chunks of bytes from the stream, and then write back the unused portion after the header has been stripped. This increased the speed of the video stream by about a factor of 5. There is still much room for improvment. But, at least, I've finally gotten to the root of the problem.

Thanks for the help guys. The tip to use SDL was extreamly helpful, and I've already put it to use in my app.

-- Brian