TOO SLOW:buffer.BlitFromMemory(image.GetPixelBox());[SOLVED]

CodeKrash

28-12-2010 06:07:18

I was finally able to get my webcam stream to continuously update a material using this, but its slow and causes a nasty FPS jittering effect. Does anyone know a way to do this more efficiently, or correctly if I'm doing it wrong?

public void Replace(string pathRelFile, byte[] imgBytes)
{
if (this.IndexOf(pathRelFile) < 0) throw new ArgumentException("The texture \"" + pathRelFile + "\"doesn't exist");
Mogre.Image image = new Mogre.Image();
MemoryStream ms = new MemoryStream(imgBytes);
DataStreamPtr fs2 = new DataStreamPtr(new ManagedDataStream(ms));
image.Load(fs2);
TexturePtr pTexture = this[pathRelFile];
TextureManager lTextureManager = TextureManager.Singleton;
HardwarePixelBuffer buffer = pTexture.GetBuffer();
unsafe
{
buffer.BlitFromMemory(image.GetPixelBox());
}
image.Dispose();
fs2.Close();
ms.Close();
}


THANKS! :D

CodeKrash

28-12-2010 06:10:20

I'm also getting 00:51:54: D3D9 device: 0x[0AFBBD40] lost. Releasing D3D9 texture: webcapCapture in the log, not sure if that's normal for a "dynamic" texture.

CodeKrash

28-12-2010 06:14:04

I changed the code to this, and I can confirm that it is in fact the call to BlitFromMemory causing the wretched frame per second snags:

public void Replace(string pathRelFile, byte[] imgBytes)
{
if (this.IndexOf(pathRelFile) < 0) throw new ArgumentException("The texture \"" + pathRelFile + "\"doesn't exist");
Mogre.Image image = new Mogre.Image();
MemoryStream ms = new MemoryStream(imgBytes);
DataStreamPtr fs2 = new DataStreamPtr(new ManagedDataStream(ms));
image.Load(fs2);
PixelBox imagBox = image.GetPixelBox();
TexturePtr pTexture = this[pathRelFile];
TextureManager lTextureManager = TextureManager.Singleton;
HardwarePixelBuffer buffer = pTexture.GetBuffer();
//unsafe
//{
// buffer.BlitFromMemory(imagBox);
//}
image.Dispose();
fs2.Close();
ms.Close();
}

CodeKrash

28-12-2010 08:16:20

I matched the texture sizes before doing the blit and it seems to be taking less of a hit now, but the fps interference is still severe ( noticeable jitter once per second, when the blit is performed)

smiley80

28-12-2010 10:35:13

Try:
public unsafe void WriteToTexture(byte[] bytes, string textureName)
{
using (ResourcePtr rpt = TextureManager.Singleton.GetByName(textureName))
{
using (TexturePtr texture = rpt)
{
HardwarePixelBufferSharedPtr texBuffer = texture.GetBuffer();
texBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
PixelBox pb = texBuffer.CurrentLock;

Marshal.Copy(bytes, 0, pb.data, bytes.Length);

texBuffer.Unlock();
texBuffer.Dispose();
}
}
}

Dimensions and pixelformat has to be the same for texture and pixel data ('bytes').

CodeKrash

28-12-2010 22:31:02

thanks! I'll try this out :D

CodeKrash

28-12-2010 23:01:07

This seems to work and is much faster, but there still seems to be a minor twitch every time it's called. The target texture is nothing but black, but with a few lines random noise. I believe it's because I'm sending the raw bytes from a JPG to it. How can i efficiently derive my headerless data? I'm thinking via the pBox after mogre loads the image, but I'm not sure. Thanks again Smiley!

CodeKrash

29-12-2010 00:10:01

I'm almost there! I was able to get the raw rgb values from the jpg, but I think the alignment is off or something. Any ideas?


public byte[] ConvertImageToRgbValues(byte[] inBytes)
{
Mogre.Image image = new Mogre.Image();
MemoryStream ms = new MemoryStream(inBytes);
DataStreamPtr fs2 = new DataStreamPtr(new ManagedDataStream(ms));
image.Load(fs2);
PixelBox imagBox = image.GetPixelBox();
uint bytes = imagBox.GetConsecutiveSize();
byte[] rgbValues = new byte[bytes];
Marshal.Copy( imagBox.data, rgbValues, 0, (int)bytes);
image.Dispose();
fs2.Close();
ms.Close();
return rgbValues;
}
public unsafe void Replace2(byte[] bytes, string textureName)
{
if (this.IndexOf(textureName) < 0) throw new ArgumentException("The texture \"" + textureName + "\"doesn't exist");
TexturePtr pTexture = this[textureName];
HardwarePixelBufferSharedPtr texBuffer = pTexture.GetBuffer();
texBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
PixelBox pb = texBuffer.CurrentLock;
Marshal.Copy(bytes, 0, pb.data, bytes.Length);
texBuffer.Unlock();
texBuffer.Dispose();
}

[attachment=2]Untitled.gif[/attachment][attachment=1]2.jpg[/attachment]

this produces the correct byte[]

public byte[] ConvertImageToRgbValues(Bitmap image)
{
System.Drawing.Imaging.BitmapData bmpData = image.LockBits(
new System.Drawing.Rectangle(0, 0, image.Width, image.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
IntPtr ptr = bmpData.Scan0;
int bytes = System.Math.Abs(bmpData.Stride) * image.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
return rgbValues;
}
[attachment=0]Untitled2.gif[/attachment]

so i guess ill stick with an unserialized System.Drawing.Bitmap for now :D

CodeKrash

29-12-2010 00:19:16

as you can see, it renders nicely!

Cheeto my baaaby[attachment=0]cheeto3.gif[/attachment]

CodeKrash

29-12-2010 01:06:17

[2010/12/28 19:22:59.8003981] [ClientClasses] System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at MogreFramework.OgreWindow.getCap() in C:\Users\Matt\Desktop\extramegablob\trunk\MogreFramework\OgreWindow.cs:line 1048
at MogreFramework.OgreWindow.getCapSerialized(imgFmt fmt) in C:\Users\Matt\Desktop\extramegablob\trunk\MogreFramework\OgreWindow.cs:line 1028
at ExtraMegaBlob.plugin.updateHook()
at ExtraMegaBlob.Client.ClientPlugins.UpdateHooks() in C:\Users\Matt\Desktop\extramegablob\trunk\Client\ClientPlugins.cs:line 130


forgot to unlock the bitmap, here's the corrected function:

public byte[] ConvertImageToRgbValues(Bitmap image)
{
System.Drawing.Imaging.BitmapData bmpData = image.LockBits(
new System.Drawing.Rectangle(0, 0, image.Width, image.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
IntPtr ptr = bmpData.Scan0;
int bytes = System.Math.Abs(bmpData.Stride) * image.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
image.UnlockBits(bmpData);
return rgbValues;
}

nataz

05-01-2011 22:21:56

Heh, yet another Video To Texture snipet? Its funny how many people have recreated this

CodeKrash

06-01-2011 22:45:10

viewtopic.php?f=8&t=11703&start=195#p77899

How many people go a step further to write a full tutorial demonstrating video camera capture -> material