Page 1 of 2

Displaying a png frame sequence.

Posted: Fri Nov 05, 2010 2:02 pm
by neil_123
I want to display a series of png images in order to simulate a video play. Here is what I am doing,

Code: Select all


ITexture       *images;
char            file_name[128];
int                num_frms, frm;

  frm = 0;
  
  while(device->run() && driver)
  {
     
    if(++frm >= num_frms)
      frm = 0;

    strcpy(file_name, SEQ_DIR);
    strcat(file_name, seq[frm]);

    images = driver->getTexture(file_name);
    
    driver->beginScene(true, true, SColor(255, 120, 102, 136) );

    driver->draw2DImage(images, position2d<s32>(0, 0), rect<s32>(0, 0, 448, 640), 0, SColor(255, 255, 255, 255), true);


    usleep(20*1000);
                                                    
    driver->endScene();

    
    device->yield();
  }


Posted: Fri Nov 05, 2010 2:10 pm
by neil_123
I am sorry, the above message got posted pre-maturely.

This program works,

But my question is, in this approach, shouldn't we be de-allocating memory for the texture generated from each png file? Other wise it seems to me, there is memory leak here, and there will be maximum limit on the number of frames that can be displayed in the sequence.

In SDL, you call SDL_FreeSurface after each "blit", is there a parellel method in irrlicht?

Any pointers will be appreciated.

Posted: Fri Nov 05, 2010 4:01 pm
by hybrid
Two things, no three: First of all put your usleep after endScene. Otherwise you get an off by one glitch, as the first image is rendered after the first wait (endScene is what makes the rendering appear on the screen).
Then, you should check the texture cache in Irrlicht. Since you use a method with 'add', you cannot drop that pointer. Instead, you can ask the texture cache to remove the texture in question.
Third, point two will introduce a heavy lag in your application. Simply because you ask the GPU to remove all the stuff and reallocate new textures each frame. It's better to lock the texture and render the image into the texture manually. This at least avoids all this overhead. A slight complication could occur because Irrlicht does not support 'write-only' textures. Hence, the old texture is also downloaded each time from GPU to CPU. You could check which method is faster for you.

Posted: Fri Nov 05, 2010 6:07 pm
by neil_123
Thanks hybrid,

I am afraid you over-estimated my knowledge of Irrlicht,

I didnt get what you meant by "Since you use a method with 'add', "

I am using draw2DImage() method.

Is this better to use IImage class in this kind of situations, since all I want is just load an image file and display it on screen, seems fairly simple operation.

Posted: Fri Nov 05, 2010 9:25 pm
by hybrid
Oh sorry, I thought you create the texture with addTexture. But getTexture basically does the same. The point is that a hardware texture is created each time this method is called with a new name. So you have to clean up afterwards.
You cannot render an image to the screen, it has to become a texture at some point (which is simply an image usable on the GPU).

Posted: Fri Nov 05, 2010 9:37 pm
by Bate
Why not convert the sequence to a real video format? Then you can use this video player. If you don't wanna do that, you can still have a look into the source to get an idea of how to access and copy image data.

Posted: Mon Nov 08, 2010 4:18 pm
by neil_123
Thanks Bate,

Does this player work only on Windows or it can work on Linux also?

Posted: Mon Nov 08, 2010 4:25 pm
by neil_123
hybrid wrote:Oh sorry, I thought you create the texture with addTexture. But getTexture basically does the same. The point is that a hardware texture is created each time this method is called with a new name. So you have to clean up afterwards.
You cannot render an image to the screen, it has to become a texture at some point (which is simply an image usable on the GPU).

So Hybrid,

What you are saying is, there is no way I can display an image on the screen without first creating a texture out of it, and when I create a texture out of image, I will run into all kind of limitations.

Isnt there a way to display an image without involving textures and GPU? So that a series of images can be displayed in quick succession.

Posted: Mon Nov 08, 2010 10:10 pm
by hybrid
No, of course not. Rendering happens on the GPU. If you want to draw an image pixel by pixel, each pixel goes from CPU to GPU. So it's much better to put the whole image to the GPU at once, and then draw the texture on the GPU.
The problem is that you want to reduce the amount of texture being used. You must optimize this in order to get a responsive app.

Posted: Mon Nov 08, 2010 10:21 pm
by slavik262
Last year for a robotics team I was in, I created an application that streamed video using TCP from the robot to an Irrlicht program on a laptop. Instead of creating a new texture for every frame, just lock the texture and memcpy the image onto the texture. You have to do it row-by-row in case the texture isn't the same size as the image (e.g. due to power of two limitations), but even then it's extremely fast and works like a charm.

Posted: Tue Nov 09, 2010 4:07 pm
by neil_123
Aha,

Thanks slavik262 & hybrid for helpful response. I will try these approaches and report back.

Regards

Posted: Wed Nov 10, 2010 2:13 pm
by neil_123
Hi slavik262,

This idea of copying pixels directly onto texture sounds interesting and promising. But I need some help in how to actually do it. I looked into the member data fields of ITexture class, but couldnt find any member where I can copy pixel data into.

I would appreciate if you could give me some further pointers as to how to actually do it.

Regards

Posted: Wed Nov 10, 2010 2:31 pm
by slavik262
No problem. I'll post the code later today when I get back from classes

Posted: Fri Nov 12, 2010 1:34 am
by slavik262
Enjoy:

Code: Select all

bool TextureManipulator::copyImgToTexture(IImage* img, ITexture* txt)
{
	//We have to be the same color format
	if(img->getColorFormat() != txt->getColorFormat())
	{
		return false;
	}

	//compare dimensions
	dimension2d<u32> tDim = txt->getSize();
	dimension2d<u32> iDim = img->getDimension();

	if(tDim.Width < iDim.Width || tDim.Height < iDim.Height)
		return false;

	//Otherwise start copying
	u32 imgPitch = img->getBytesPerPixel() * iDim.Width;
	u32 txtPitch = txt->getPitch();
	char* txtPtr = (char*)txt->lock();
	char* imgPtr = (char*)img->lock();

	for(u32 c = 0; c < iDim.Height; c++)
	{
		memcpy(txtPtr, imgPtr, imgPitch);

		txtPtr += txtPitch;
		imgPtr += imgPitch;
	}

	txt->unlock();
	img->unlock();

	return true;
}

Posted: Fri Nov 12, 2010 1:40 pm
by neil_123
Thanks slavik262,
Looks like a good instructional material. I am hoping to learn quite a few things from this.