Click to See Complete Forum and Search --> : Displaying jpeg image sequences with ATL only


p_497
August 2nd, 2007, 06:09 AM
Dear ATL C++ / graphics people,

I already searched the forums, but found no answer, just questions to
this topic. So I'll try my luck and post my question:
I am searching for an easy way to load a sequence of jpeg files (which
form a video) into memory and play them like a video. I furthermore
want to react on a keypress by drawing a frame into the current jpeg
in the sequence and saving it to disk/memory (maybe to disk not during
play, but after it, since there should not be delays, performance
does matter!). Is there a simple way to do this with the ATL already?
A little navigation functionality would be great (jumping to specific
frames, having a slider, Play/Stop Button etc.)
Did anyone already do something like that? I want to use pure ATL
and no MFC since I have a guideline to use ATL only.

Would be nice if that would be possible and anyone could help.

Best regards,

Peter.

JVene
August 2nd, 2007, 04:11 PM
Loading a jpg can be done with a call to GDI+. From there you'll end up with a series of bitmaps which you'll blit using standard GDI routines, unless you end up trying something with DirectX.

On most modern machines you can blit around 50 to 100 frames per second where the bitmap is 24 bpp (likely in your case), and around 800 x 600 or smaller (you didn't mention the size).

You said a series of frames, but how many images are you considering?

At what framerate should these be displayed?

Is the timing of the frame delay critical (as would be in synchronized video/audio)?

ATL implies that you're making an ActiveX control, or something along those lines. I think there are articles on using ATL with MFC, but I don't recall.

You might also consider WTL as an alternative to MFC that may be compatible with ATL.

Otherwise, you'll be working with GDI, GDI+ and perhaps other graphics libraries, if you so choose, assuming you reject DirectX for display speed.

That hints that you'd do well to choose object oriented techniques to organize your work, creating a minimal framework that associates with ATL well, giving leverage to your use of bitmaps.

The subject is vast enough that we can only suggest these kinds of general concepts until you have more specific questions about, say, bliting a bitmap in GDI (C style), the notion of DIB vs DDB bitmaps, etc.

p_497
August 7th, 2007, 01:50 PM
Hello JVene,

thank you for your great answer. The images are 640x480 pixels, 24bit
and 30fps (sorry that I forgot to provide this information). I found
the SimpleImage example from Microsoft which uses a FrameWnd and a
ChildView and also do BitBlt, but currently have problems incorpo-
rating it into my ATL project, see

http://www.codeguru.com/forum/showthread.php?t=431038

(maybe you could help me with this, too?).

I wanted to ask whether there is a yet simpler (without the FrameWnd
/ChildView concept) approach in the ATL to directly display jpegs?
Is there a class in ATL (with no MFC, since they are bigger) to do
that? How would ones do that, then?
The requirement to use ATL only isn't that strict but why adding
more dependencies when ATL would suffice? - Only comfort would be an
argument. I am searching for the simplest solution, may it be ATL or
MFC doesn't matter. But if it would be simple AND ATL only, that
would be best.
You are right about that I prefer object oriented techniques, only
if performance issues may force to choose non-OO-approaches like
pure C I would do that.
Yes, timing delay is critical in my project since I want to mark
single frames when the user presses a key.

Thank you for your offer to discuss the graphical part of my problem.
When I reach this stage - after setting up the windows and displaying
the images I will be glad to ask you more specific questions about
that.

Best regards,

Peter.

p_497
August 8th, 2007, 03:19 AM
Hello JVene,

It's just me again ;) I wanted to notify you that I edited my last
answer (see above). Furthermore I invited markiemooster from the
Visual C++ Programming thread

http://www.codeguru.com/forum/showthread.php?p=1609875#post1609875

to join our discussion. Sorry for the crossposting (what you maybe
already noticed), but since my problem touches both areas, ATL, as
well as graphics, I decided to acquaint this problem to both threads,
thinking it could be of interest to the people in both threads.

So I hope you and markiemooster will also benefit a little from this
discussion.

Thank you again for your help so far and I look forward the upcoming
discussion. - Till soon!

Best regards,

Peter.

JVene
August 9th, 2007, 12:41 AM
Let me start with some good news, there's no need to use the FrameWnd/ChildView if you don't want to. A window is a window, frankly - the purpose in placing a child inside a frame has more to do with having a 'difference' between the outer frame of the child and the (generally 4) regions around it for use as status bars, menus, toolbars and other related effects. If your application doesn't require anything to appear 'around' your image display, then all you need to have is the ability to provide a response to a paint message - one one window.

For the image display you have the two basic notions of loading an image, then displaying the image.

For display of an image, ATL implies that you use the otherwise standard win32 features, though some articles discuss how to employ WTL to help with UI while coding in ATL, if your have sufficient need for leverage above win32.

If your code doesn't have much in the way of GUI beyond display of bitmaps, then research on WTL may take as much time and effort as simply using win32 for blitting the bitmaps.

However, WTL has some classes for bitmaps themselves, and perhaps you'll find interest in using them.

The rest of your strategy follows these basic subjects:

- loading the bitmaps. You didn't mention how many bitmaps are involved. Since you're discussing 30 fps 640 x 480, even a few seconds will require some strategy and thought on how to proceed. Fast jpeg decompression is very hard to come by, and I don't think you'll find much that's free which could support ongoing decompression at 30fps at these dimensions from disk. I'll need to understand more about what you're doing, and why you're choosing to produce video from this kind of source material. That choice is unconventional.

GDI+ (available from win32 on the appropriate OS) can load jpeg's. There's also some free C level libraries, and other C++ libraries, that support jpeg loading outside of GDI+. I've not timed which approach is faster (maybe someone here knows).


- once bitmaps are decoded, you'll need a container for them. Managing significant volumes of memory requires a good strategy, and you'll want to consider STL containers among other options. A lot depends, however, and what I learn about the number of images and why you're choosing jpeg's for motion video source - there could be seriously superior choices to be made. It sounds like you may have a queue of frames in a pipeline, but taking that from jpeg only makes sense for short displays that can fit into RAM, I think.



- timing; this gets slightly sticky. Window's isn't a real time OS, so keeping something moving at a steady and strict 30 fps requires some flexibility, and usually that's acceptable. GDI isn't the fastest way to display bitmaps, but it's not beyond it's ability depending on your target hardware. DirectX is faster, and takes you into another direction, still workable within an ActiveX control, I believe. I've witnessed display rates of 150 to 200 fps with bitmaps if these dimensions on typical, modest hardware of recent times (say 1.5Ghz 32bit CPU, AGP graphics card). The trick, though, is how much demand is there on the system for the REST of what must be done to keep the pipeline stuffed and moving. There are multimedia timers and 'standard' timers with resolutions in the 20/30 ms range, and your timer needs to operate at 33.3333 ms, quite close to the tighter tolerances of the 'standard' timer (which typically works no more precisely than 16ms). What that means is that if a timer is 'late' or 'off' - what should have been happening 33.333 ms down the road might not happen until about 50 ms, and as that cascades down the line, you might have to 'skip' a frame to keep things in sync. Something to think about in design. Naive tricks, like raising the priority to 'realtime' do not fix the problem, and may even make it worse. Multimedia timers are of some help, but one must accept the fact that Windows isn't realtime, and that's just the way it is. Still, things move fast enough that you can make applications function acceptably.

p_497
September 8th, 2007, 04:33 PM
Hello JVene,

sorry for my late answer, but I had to do a lot of work in other
projects, but now I will have more time (I hope) for this one.
I now managed, after some elaborate work (windows event loop, ATL
GUI stuff), to adjust the project to display a CWindowImpl<> in
and load jpegs using the CImage class and the StretchImage (I believe,
I write this from at home and haven't the sources here) function in
OnPaint.
Of course it is not fast yet, and it is flickering. What do you think,
would it be possible with this architecture (in OnPaint) to display
the images at reasonable rate without flickering?
To answer your questions:
I have to use ATL for now, and there should be some little GUI for
starting/stopping/pausing the video and jump to a specific frame.
And the material is jpeg because the camera I used delivered it in
this format. But of course I could convert it to an uncompressed
format to get rid of the decoding overhead. But then the files get
bigger so when loading them from disk more data has to be loaded.
Of course it would be great to put all of it into RAM uncompressed. It
could be possible, the videos are ca. 2 minutes in duration, so 3-4 GB
is the estimated amount to keep in RAM (which I could build into the
machine for this short test). But then the system may slow down with
such a great portion of the RAM occupied by the image data. But during
play I could kick out the frames already displayed to stepwise free the
RAM again. STL is a good idea, I already used it (iterators, vectors,
maps) and like it very much.
Do you have a code example how to most efficiently display such a
sequence using OnPaint and the STL? In which datastructure should I
keep the images in the RAM?

Would be great if you could go on helping me, of course you already
did with your very profund answer.

So I once again thank you very much and look forward to your answer.

Best regards and till soon,

Peter.

JVene
September 10th, 2007, 12:15 AM
What do you think,
would it be possible with this architecture (in OnPaint) to display
the images at reasonable rate without flickering?


Depending on hardware, speed is tolerable. In my own machine, images of 800 x 600 can be displayed around 80 frames per second.

Flicker is the result of erasure prior to the blit. You can simply provide your own reponse to WM_ERASEBKGND, and erase nothing. That stops flicker, using the assumption that a complete replacement of one image with the next obviates the need for an erase of the background.

I think jpeg decode is your slowest code. I don't know of any decoders optimized for quick 'video speed' playback of frame sequences. Most cameras can support video for windows, so you may want to look into the various libraries and OS support for it, because it may be what you're really looking for. Is the image data written to disk already (or, I should say, in advance of your application's use of it?). It would be difficult to write a series of jpeg frames to disk quickly enough to get 30fps video, so I wonder if that even happens correctly.

About RAM. In 32bit Windows, you're limited to 2Gbytes per process without throwing some switches. The high bit of all addresses is reserved for the OS (hence 2Gbyte limit), but if you configure your operating system to use PAE, and use the 3big switch, and if you set the compiler to permit it, you can force access to more RAM.

Still, it's not exactly an optimal design. This is what video for windows was designed for, and there are some articles either here or on code project for getting started with it. See if your camera supports it (if it has anything that is actually intended for video recording, I be shocked if it doesn't support it).

Even if you took an uncompressed frame grab (at video speeds) and sent the results to video for windows, you could write that to disk using a codec for compression (depending on hardware, huffy lossless is 2:1 compression at real time speeds, and even DIVX can manage real time on some machines, in the fastest settings).

You might even gain some insight by perusing the source code of Virtual Dub, which you can obtain online. That uses DirectX (I think DirectX 3 or 4) for video display. It otherwise shows video capture and a great many other techniques.

p_497
September 10th, 2007, 01:02 PM
Hello JVene,

thank you for your help. At first, my answer to your question:

> Is the image data written to disk already (or, I should say, in advance of
> your application's use of it?). It would be difficult to write a series of jpeg
> frames to disk quickly enough to get 30fps video, so I wonder if that even
> happens correctly.

Yes, the data is already written to disk (one jpeg per frame) and
my only job is to display the recorded frames (jpegs). No camera is
involved any more. Just loading the frames stored onto hard disk, using
a computer with the follwing configuration:

I got a Pentium D CPU, 3.2 GHz, 1 GB RAM.
The graphics card is a NVIDIA Quadro FX 540.

The tip with WM_ERASEBKGND worked and the frames a replayed faster
than recorded. Of course I have to check whether this suffices when
performing additional background activities and the framerate ad-
justment which I still have to do. - Could you take a look at the
code (see below) what I could improve to get it more efficient
(besides the .jpeg issue)? Is the for loop good or can I improve
it? Is there a way to do this without the m_Img.Destroy()? Before I
inserted it I got an assertion that in atlimage.h, line 503, the ex-
pression m_hBitmap==0 failed. So I inserted it. But is there a more
efficient way without destroying it before the loading of the next
frame and by this getting the flickering and the necessarity of the
WM_ERASEBKGND trick which introduces the additional function call to
my empty OnEraseBkGnd event handler? It would be nice to avoid this
overhead.
And what about the OnPaint, do you think, it is ok like that? Is the
StretchBlt efficient, or are there better ways to do this? My aim is
to display the frames in fullscreen. Since my display resolution is
greater than the frame resolution I have to do some resizing.
Or would it make sense to do the following: Decompress the jpegs,
storing them uncompressed already in the destination resolution (1024x768
pixels, at most 1280x1024)? I would write a little program which
reads them in and stores them, e.g already in the CImage data structure?
So the data can then be taken by the code below directly without jpeg
decompression, just loaded and displayed?
Is the jpeg decoding overhead greater than the overhead when I would
loading the already uncompressed (not jpeg decoded) but therefore
bigger frames from disk, e.g. stored in CImage format already? So is
it faster to load the uncompressed amount of data from disk, having
more disk reading activity compared to when reading the jpeg files
and decompressing them like my code below currently does? Does the
CImage do the decoding completely in software, or does it already use
the graphic card's hardware to do the jpeg decompression (via codecs)?
Does this comparison of the both approaches depend greatly on how fast
my hard disk is, so reading big files without the decoding could be faster
than loading jpeg compressed files but then additionally having to decom-
press them afterwards using CImage?

Would be great if you could answer this, too. I always asked me those
questions and it would be great if you could tell me based on your
experience what the facts are.

Best regards,

Peter.


Here comes the code:


// ImageSample.cpp : Implementation of WinMain

#include "stdafx.h"
#include "resource.h"
#include "mainDialog.h"

class CMyWindow : public CWindowImpl<CMyWindow>
{
public:
// Optionally specify name of the new Windows class
DECLARE_WND_CLASS("MyName")
// If this macro is not specified in your
// class, ATL will generate a class name


BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkGnd)
END_MSG_MAP()

CMyWindow(): CWindowImpl<CMyWindow>() {
m_Img.Load("c:/Temp/black.bmp");
//JVene, do you know a better way to initialize the m_img to
//a black background, without loading a dummy image from disk?

}

LRESULT OnPaint(UINT nMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{

//if ( !m_Img.IsNull() ) { // I try to avoid this if-statement for efficiency reasons.
PAINTSTRUCT ps;
HDC hdc; // device context for painting
hdc = BeginPaint(&ps);

CRect rctWindowSize;
GetClientRect(rctWindowSize);

m_Img.StretchBlt(hdc,0,0,rctWindowSize.Width(), rctWindowSize.Height(), SRCCOPY);
EndPaint(&ps);
//}

return 0;
}


LRESULT OnEraseBkGnd(UINT nMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{
//Do nothing to avoid flicker in video replay.
return 0;
}


void loadImages(){
static ostringstream tmpOStringStream; // For converting other types, e.g. numbers
// (int, float) into strings.
ATL::CString path = "c:/Videos/06/";

ATL::CString fileName = "";

int i = 2;
for ( i = 1; i < 5210; i++ ) {//Don't wonder, 5210 is the number of frames recorded
//in this directory. I hardcoded this here for
//testing only, until I will write the code to count
//the number of files in the directory.
tmpOStringStream << i;
fileName = path + ( tmpOStringStream.str() ).c_str() + ".jpg";
m_Img.Destroy();
HRESULT hr = m_Img.Load( path + ( tmpOStringStream.str() ).c_str()
+ ".jpg");
if ( hr == S_OK ){
this->Invalidate();
this->UpdateWindow();
}
tmpOStringStream.str(""); // To clean up stringstream.
}
}

private:
CImage m_Img;


};



class CSampleModule : public CAtlExeModuleT< CSampleModule >
{
public :
HRESULT PreMessageLoop(int nShowCmd)
{
HRESULT hr = CAtlExeModuleT<CTetCompSampleModule>::PreMessageLoop(nShowCmd);
if (FAILED(hr))
return hr;


return S_OK;
}
};

CSampleModule _AtlModule;

//
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{

CMyWindow myWnd;

myWnd.Create( 0, CWindow::rcDefault, "Image Test",
WS_OVERLAPPEDWINDOW, WS_EX_CLIENTEDGE );

if( !myWnd ) {
return FALSE;
}

myWnd.CenterWindow();
myWnd.ShowWindow( nShowCmd );

myWnd.UpdateWindow();


myWnd.loadImages();


return _AtlModule.WinMain(nShowCmd);

}

JVene
September 10th, 2007, 11:16 PM
You can certainly conduct an interview! :)

I have a 6 year old son - I know I'm in for it - he's going to ask even more questions, but I had to laugh - questions seemed to pour out like rapid machine gun fire!

Ok, a few items in no particular order....


LRESULT OnPaint(UINT nMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{

//if ( !m_Img.IsNull() ) { // I try to avoid this if-statement for efficiency reasons.

>> Don't skip the null test, it takes only a few machine language instructions and goes by 1000 times faster than the getclientrect below, and it adds safety. Skip only if you REALLY don't need it, but from a speed standpoint, it's immeasurable in this context (and on until you reached framerates of 200K per second or more, really).

PAINTSTRUCT ps;
HDC hdc; // device context for painting
hdc = BeginPaint(&ps);

CRect rctWindowSize;
GetClientRect(rctWindowSize);

>> The constructor for CRect could take longer than the null test above, and certainly the getclientrect. Make a CRect window size as a member variable, adjusted it on the WM_SIZE message, so you don't have to repeat it here.



>> Minor (very minor) speed thing here - I think CRect holds left/top/right/bottom, which means Width and Height are always a calculation (and forgive me if I'm actually wrong about that) - anyway, if it IS a calculation, then have a width and height member that's adjusted at WM_SIZE

m_Img.StretchBlt(hdc,0,0,rctWindowSize.Width(), rctWindowSize.Height(), SRCCOPY);

>> BitBlt is much faster, but if you gotta stretch, well....


EndPaint(&ps);
//}

return 0;
}






In 'loadImages':

I'd like to verify you intend to number from 1 instead of zero?

I don't see any way around the image.Destroy(), all other avenues of thought route to the same fact - the existing image would have to be cleared if you're not creating a container of them.


Is there a way to do this without the m_Img.Destroy()? Before I
inserted it I got an assertion that in atlimage.h, line 503, the ex-
pression m_hBitmap==0 failed. So I inserted it. But is there a more
efficient way without destroying it before the loading of the next
frame and by this getting the flickering and the necessarity of the
WM_ERASEBKGND trick which introduces the additional function call to
my empty OnEraseBkGnd event handler?



You can't load a bitmap into a CImage if an image is already there, so Destroy is logically required anyway.

I don't think the destroy has anything to do with flicker. Flicker occurs when a rectangle is drawn over the window just before a paint message is issued (which is basically what the default 'erase background' does). It's widely recognized that double buffering (which is obviated in your case because your source is a bitmap) flickers unless the background erasure is muted.

The calling of the empty function is fairly quick (millionths of a second), and is the only way you can 'take' the messaage and stop the default behavior - Windows is GOING to issue WM_ERASEBKGND IF you use WM_PAINT as the display means (and it does this anyway when a WM_PAINT is issued, which can happen for a number of reasons - user interaction with other applications, popups, etc).

What you CAN do, as an alternative, is to use a ClientDC instead of a paint cycle. For this you can run in a thread, open a client DC, instead of a paint dc, and blit using it - without invoking invalidate OR updatewindow - you just blit to the window "in loop".

Keep in mind this should run in a thread, and it means you don't want WM_PAINT (or erase), which executes in the "main GUI" thread, to interfere in any way with the display (that is, they should do nothing, except the required begin/end paint - just no display work, no erasure).


About stretch vs uncompressed storage...

An uncompressed 24bit 1280 x 1024 image is around 4Mbytes, so you have to take the sustained throughput of your drive under near worse conditions and see if you can sustain that much data at your framerate. Probably not, which means, ironically, the weight of decompression can actually be faster that disk performance.

However, a recompressed enlarged image that lets you blit instead of stretch might be a fair idea - you just have to try it and test.

As for how it decodes - beats me :) It could pull any trick in the book, I'd have to look at the source code. As to which is faster, well, it really depends on the hardware involved - we have such wide ranges around and I've tested a number but certainly not all.

The Pentium D is not as familiar to me, so I can't easily judge it's power at 3.2Ghz, yet I think it's fast enough that I would assume quick decompression facility. I don't think jpeg compression is going to invoke the graphics card, MPEG maybe, but I don't think jpeg (but here I'm working on older information, not researched).

Drives vary widely, too. Sustained read speeds of 40Mbytes per second are common among the 200-300 Gbyte drives, but on the tail end of the disk (when it starts getting full) that can drop to 20Mbytes per second - and fragmentation can drop that below 5Mbytes per second occasionally.

The older 80Gbyte drives could only manage about 30MB/Sec at best, down to about 15, 2 or 3 in fragmentation.

Older drives, those 6Gbytes or so from the turn of the century ( :) ) were a paultry 6MB/Sec.

RAID 1's, Atlas or Raptor - you can see lots of variation on machines designed for video.

For professional work, that would be an adjustable concept - based on some kind of performance analysis - testing which strategy fits best.

Now, if you're telling me that you already see suitable frame speeds with this construction, even at 100% CPU utilization, I'm satisfied.

Now...if you want your application to freeze during playback, you're set. Otherwise, you're going to need to consider threads :)

p_497
September 30th, 2007, 12:39 PM
Hello JVene,

thank you so much for your help. - Yes, I try my best to stay to some
part a child :), concerning the asking and being honest (we always can
learn from them, too). Congratulations to your son, its a great
effort to bring up a child.
Back to our thread:
I made the application multithreaded and it works, it's still re-
sponsive on the user for pausing and stopping the video playback.
Now I'm into another silly problem. It's just making a deep copy of
a CImage. Do you know how to do this? - I already searched the CImage
doc but there seems to be no dedicated copy function. I also searched
the web for examples and looked into my books (which don't deal with
CImage, only with GDI and OpenGL, which is great, but didn't help for
this problem). What I want to do is when the user presses the space
bar, an image is written out to disk with a green frame painted into
it.
So I wanted to do a copy of the image, preferebly on the heap, not
onto the stack - although that would be faster. That is, something
like this:


LRESULT CMyWindow::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled)
{
switch (wParam) {
case VK_SPACE://User stroke space bar.
{
CImage currFrameCpy = new CImage();
CSingleLock lock_Img( &prot_Img );
//try lock
lock_Img.Lock();
if (lock_Img.IsLocked()) {
DWORD dwFlags;
if ( m_pImg.???hasAlphaChannel()???) {//How to find out?
dwFlags = createAlphaChannel;
} else {
dwFlags = ???NULL???;
}
currFrameCpy.Create( m_pImg.GetWidth(),
m_pImg.GetHeight(), m_pImg.GetBPP(), DWORD dwFlags )
(*currFrameCpy) = (*m_pImg);
lock_Img.Unlock();
} else {
cerr << "didn't get any lock in CMyWindow::OnKeyDown" <<
endl;
}
writeToDisk( currFrameCpy );
}
}
return 0;
}



m_pImg is a CImage* and is used by the window to display the image.
It is also written by the thread loading the images from the disk, so
synchronization via the CMutex prot_Img is done.
currFrameCpy is the CImage on the heap which should hold the copy of
m_pImg for writing it out to disk. But doing the copy like this (using the
simple assignment) only does a shallow copy of m_pImg, all references
of it still point to the same data in currFrameCpy. So there must be
another solution to get a really deep copy, also to avoid thread sync
problems when the same data is acessed by the shallow copy and
the loading thread, overwriting this data while currFrameCpy is written
to disk.
I wanted not to write m_pImg directly to disk and use the copy instead to
not block m_pImg during the whole disk write acess, so the thread loading
the images then had to wait until the disk write access is finished. But like
this he can go on paralelly loading the next frame while the previous frame
is written (using the copy into currFrameCpy).

So how to efficiently do this deep copy from m_pImg to currFrameCpy,
since there unfortunately is no CImage.copy() function and no copy
constructor? In the above example, there's also still unclear how to
find out the right value for the dwFlags.
Maybe ones also could BitBlt the m_pImg into the currFrameCpy after
some preparation (reserving the right amount of memory, using Create()
like above, or something other)? How could that be done and what
preparation of currFrameCpy is necessary to reserve the right amount
of memory to not overwrite wrong portions of the working memory?

I hope there is a best practice and most efficient solution for this?

Would be great if you could help me with this.

One more question: CImage can be used everywhere CBitmap can be used,
since it only encapsulates a handle to a CBitmap and has the
operator HBITMAP to allow implicit conversion to CBitmap?

I also wanted to display an icon/bitmap onto the play button and
change it when it is in "pause" mode. I tried something like this:


this->GetDlgItem( IDC_BUTTON_START_REPLAY ).SetIcon( LoadIcon(
(HINSTANCE) _AtlModule, "ico_mmcndmgr0033.bmp") );

I get an error that he can not convert _AtlModule to HINSTANCE.
Do you know how to set up a bitmap/icon for a button in ATL?
I added the file "ico_mmcndmgr0033.bmp") to the application resources
and my problem now is how to use it. Is the "name" of the icon the
one displayed in the properties when selecting it in the resource
view? In my case this seems to be simply the name of the file.
Would be great if you also knew this, but it is not that important
like the copy problem.

So sorry for this again lengthy mail, but I hope you could help me.
Thank you once again for your already great help,

Best regards, and till soon,

Peter.

JVene
October 4th, 2007, 06:28 PM
Sorry, had to handle much in these past few days. I've limited myself to simpler, shorter posts on the boards lately.

As you've discovered (and I'm only 90% certain of this, I use wxWidgets more than MFC), CImage uses a reference counted containment design such that two CImage objects actually point to one image. If the bitmap is really a DDB, the bits are 'owned' by the OS - you can't 'have' them directly. If it's a DIB, you have access to the bits, but you have to create a NEW CImage of the matching size and transport those bits yourself. If your destination is going to be larger, that's not a simple memcpy, but it could be a simple memcpy if all other parameters of the image remain identical to the original.

It can be safer, though slower, to consider using a memoryDC to 'draw' the source bitmap onto the destination (and that's ALL you can do if it's a DDB, to my knowledge).

Generally, you know there's an alpha channel if the GetBPP tells you 32 bits. 24bits is 'true color' without the alpha channel, and 32bits is true color with one.

Obviously this class doesn't consider 16 BPP or other more advanced formats.

Bottom line, you're only going to get a deep copy from an object perspective if you derived from CImage and explicitly manage the details, or, which may do as well, perform the creation of the new destination bitmap and copy the bits.

This would be fast enough that you can let the primary drawing thread move onto it's next frame, and take what time you like for the writing of the 'snapped' frame. A word of caution in design here....

What happens if the 'snap frame' command is issued by the user before the frame being written has completed?

What happens if multiple 'snap frame' commands have been issued such that writing demand (which is heavier than reading) slows down READING in the other thread, such that performance is scuttled?

These issues have compromise solutions; as in refuse to accept a snap command until the previous one is finished - or tag the frame, holding it so it's not deleted even with the display thread is theoretically done with it (I'd use smart pointers for this myself), with some care to avoid memory starvation due to pile up.


....operator HBITMAP to allow implicit conversion to CBitmap?


I'd have to check the CImage source (like I said, I use wxWidgets more often these days), but I don't think CImage uses a CBitmap internally, I think it uses the HBITMAP internally, and there's a conversion available for the compiler to wrap CBitmap's around HBITMAPs - either that, or there's actually an HBITMAP used everywhere, CBitmap automatically provides that, so does CImage, and everyone's happy with that.



Sorry, I haven't dealt with GetDlgItem in years, I'll have to pass there. In my own work I have classes that do these things for me (well, I wrote them years ago, but it means the same thing) - so I don't even worry about it.

p_497
November 20th, 2007, 10:59 AM
Hello JVene,

sorry for my late answer, but now my program is finished so far. Thank
you for your great help, the image copy now works (using BitBlt) and
decided to address the problem with the bitmaps on the buttons later.
Currently I am trying to make the program more efficient since my
image loading thread still poses 50% CPU load in its idle loop.
Here's the (forum-;)) thread I posted this problem in:

http://www.codeguru.com/forum/showthread.php?p=1652131#post1652131

If you could help with this, too, that would be great, but I would
fully understand if you hadn't the time.
Many thanks again for your help, would be great to hear from you
how you are.

Best regards,

Peter.