Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Edanmo Stream read function query

Status
Not open for further replies.

tedsmith

Programmer
Nov 23, 2000
1,762
AU
How do I read a stream (using Edanmo's OLE) and send the contents to a winsock?
Eg something like Winsock1.Sendata MyStream.read (pv,cb) Is this correct but what do I put in the pv & cbs ?

Background: (thanks to a lot of help from strongm)
I have a network setup working that successfully sends frames from a web camera at each of 16 workstations to a master server and displays 16 small pictures on the server.
A frame is sent whenever there is movement in front of the web camera.
The original web picture is 1 meg but I cut it down to a below 30k JPG to greatly reduce the network traffic. With barely visible degradation of the picture.
I use a stream to accumulate the 8k chunks of picture bytes received by the server winsocks and use GDI to send this to an image box.

My new challenge is to create 2 new remote control workstations to receive a copy of each picture when it changes directly from the server. The network connection to the original pic source is only 100mhz while the link between the server and new remote controls is 1ghz and both are high speed i7's so I don't want to have the original sources sending each pic three times.

So I want to relay only the small data from the server containing the jpg and not the full reconstituted larger picture at the server therefore I need to get a copy of the stream as it is received at the server and resend to the remote controllers.

I could accumulate the pic byte data from the winsock and just resend it but this is too slow.
If I could read the whole stream once it was received I think this would do the trick.
I cant find any info on how to set up the read statement.
The old read stream was simply MStream.Read (No of Bytes) but what do you use with Edanmo's stream and is this in the same form as the original byte data written to the stream?
 
After a bit of fiddling I managed to get read to work
Data is size of data and pic data is received on one of 16 indexed Winsoxks and written to MyStream(Index)
When all chunks of jpg are received -
First use GDI to convert and show JPG on one of 16 Server Indexed Image boxes
myStream(Index).Stat StreamStats, STATFLAG_NONAME
StreamLength = StreamStats.cbSize * 10000
ReDim NewBuffer(StreamLength + 2)
MyResult=MyStream(index).Read(Newbuffer(0),StreamLength) 'puts the stream into a new buffer
WinsockRemote.SendData Index 'tells remote which camera the pic comes from
WinsockRemote.Sendata NewBuffer 'sends copy of the original jpg byte data

Seems to work - have I done anything wrong?
 
Is there some reason you don't just ashcan these streams and simply relay data as it arrives? All you are doing is adding more delay by buffering up the whole JPEG before re-sending it.

As for accumulating the whole JPEG for local use, since GDI won't accept an IStream anyway you can create a faster and probably more effective "stream" class in VB6. It is basically the same logic as common "string builder" classes but using a Byte array as the buffer and CopyMemory to move data around instead of Mid$() or MidB$() statements.

Pretty simple to add methods to extract off things like Long length values from the buffered data or even search for values using InStrB() calls.

Then use WIA 2.0 and you can simply discard 90% to 100% of your GDI code (or is this GDI+ code?) as well as the convoluted stream code. Probably gain a lot of performance back too.

You'll thank me every time you have to do maintenance on the code. But I don't seriously expect you to listen either. [wink]
 
Thanks for your response.
The JPG Stream is created in the original client computer from the webcam 640x480 BMP via the clipboard using among other things - (1meg to <30K)
GdipCreateBitmapFromHBITMAP
Set myStream = CreateStreamOnHGlobal(b(0), True)
GdipSaveImageToStream 'save image as a compressed JPG into a GDI+ stream.

The "stream" of pic data received by Winsock at the server is received in up to 4 separate DataArrival firings per picture. These are generally about 8k each as is usually the case with Winsock.
To accumulate them into one picture, I feed them into an IStream (Endamo type) and use GdipLoadImageFromStream from DSeaman GDI+ library to set the image box in the server. This is similar to using Loadpicture because you cant feed a jpg directly to the imagebox and it is very fast.

I use the same receive method to display the picture in the server and remote.

I though the easiest way to send the pic to the remote controller PC was to re-read this already existing server IStream and send it to the remote Winsock in one Senddata statement.
I thought accumulating the picture twice at the server, once for local and once for remote, would be slower.

If I send the received data direct as each chunk is received, I would have to use four send data statements per picture, receive them and assemble them again at the remote which I thought would be slower.
However
I will experiment further to check.

Incidently without using Stream, how do you combine two byte arrays into one array quickly without adding the second one element by element? And is it quicker anyway? Eg Add the contents of MyArray1(8000) to MyArray2(8000) to get MyArray3(16000)

I thought WIA doesn't work in Windows 7 ?
 
>GdipSaveImageToStream 'save image as a compressed JPG into a GDI+ stream.

BTW, the 'GDI+ stream' is just an IStream

So

1) If it takes '4 separate DataArrival firings' to accumulate the picture at the server, then it will inevitably take a similar '4 separate DataArrival firings' to accumulate the stream at the remote - so, as dilettante suggests, you might as well immediately forward the chunks as they arrive

2) Even if you do prefer the 'accumulate and forward' strategy, I'm not quite sure why you need to create a new stream (newBuffer), copy over the received stream and send it, when you can just as easily send the received stream (myStream) itself
 
1. One reason was to simplify the identification of which original picture. At the server this is accomplished by using the index of the receiving windsock. Also the pictures never get mixed up if more than 2 send at the same time as the streams are indexed to follow the source index. When sending to the remote I have to send this index number to tell the remote whiter the picture originated.
2. I actually had to use Clone.Read for the send to the server otherwise for some reason Read wipes out the bottom half of the server picture image that has just been created! Maybe the endamos process is a bit slow and the image box picture has not been fully completed?
However
I tried it connecting up a third computer but can't get any picture even though the required number of bytes is being received at the remote and fed to an identical display routine to the server.
I wondered if I am doing the right thing anyway in sending a read stream that has been assembled or am I mixing up pictures and bytes?

I'll try sending the chunks method to confirm if my remote setup is correct.
 
>the streams are indexed

Might have been better if you used separate (indexed) sockets for each connection, which I'm sure we must have suggested all those years ago when you first started playing around with this. Ah well, guess you have to live with what you have got.

>the endamos process
Erm - no such thing. Edanmo's olelib is simply a type library. To put that at it's simplest, all it does is provide declarations for existing Windows code that VB6 would not normally be able to use (because the underlying API calls use types and calling conventions not understood by VB). So it unlikely that Edanmo is responsible for any issue, since it does not contain any code.

What is more likely (without seeing all your code) is that you are, without realising it, retaining locks on areas of memory.
 
Thanks.
I do indeed use separate indexed sockets for easy connection, the index matching the id of the source. I Load them during startup.
The reason I also indexed the streams was I was worried that if two sources a and b sent at almost exactly the same time. I might get the chunks received like a1,b1,a2,b2,c1,c2 so the top half of the first source could mix with the bottom half of the second. Also they all have to have a different port anyway.

What is the real difference between an adobe stream and an IStream?
 
> I was worried that if two sources a and b sent at almost exactly the same time. I might get the chunks received like a1,b1,a2,b2,c1,c2

Er ... if you have your sockets set up correctly that just can't happen, since chunks a1 and a2 can only arrive on a specific socket. Likewise chunks b1 and b2, and chunks c1 and c2

>Also they all have to have a different port anyway

Nope

This is all encapsulated by the winsock control already.

The ADODB stream is a subclass of an IStream - it implements all the properties and methods of an Istream, and then adds a few more.
 
But when I have indexed winsocks, I have only one Dataarrival sub. Until I also indexed the stream I actually saw the effect of the top half of one camera and a section of another camera combined on the one picture. This now never happens with indexed streams.
I could only see this effect the day I installed it in front of my client with the 16 cameras as my office setup only had two to test with (much to my embarrassment) and it quickly became obvious that indexed streams were needed.
I suggest that Dataarrival has no way to tell which camera chunk from another except by it's index. With using one stream it seems to accumulate whatever comes next if they all arrive within millisecond of each other.
I understand if they arrive exactly at the same time, one chunk is read completely before another without problems and they never get mixed up.
I am experimenting further.
What I meant with streams is how do I find out what exactly is in a "stream" in terms of start bytes data bytes and all the other bits and pieces that make up the streams and what they are all for. Eg a propertybag architecture is easy to examine by simply printing the asc value of each byte. Any attempt to do with a stream gives an data type error.

Also- Is there a reference of how to use the huge number of properties and functions you see revealed when you type in an Endamo function or examine the properties? I wonder how you found this out?
I downloaded some stuff from the site but it doesn't quite 'compute' with me!
 
>I downloaded some stuff from the site but it doesn't quite 'compute' with me!

It's certainly true that the Edanmo library isn't really documented very well for VB programmers, apart from the example code on his site.

>Is there a reference of how to use the huge number of properties and functions

How to use them? Not exactly. There's comprehensive documentation on MSDN for all the interfaces made available via the olelib library. But it isn't written with the VB programmer in mind ...

For example, here's what it says about the Read method, which seems straightforward enough:

MSDN said:
Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
(Inherited from ISequentialStream)

but, more specifically, this, which is more opaque. I find it easy to understand and can mentally map it to the Edanmo declarations, but I suspect (given my recollection of trying to explain wParam and lParam in API calls to you some years ago) that you might find it harder.

 
Actually I can understand your link we'll now that I know how to format the read statement.
My original problem in this thread was so simple I wonder why I was so stupid.
I just didn't realise the buffer to be read to has to go inside the brackets, thinking it was a read function until I saw a plain example in someone else's project. I assumed it was buffer = read( something, somethingelse) and not simply
Read(buffer, bytestotal) or Result = Read(buffer,bytestotal) which none of the documentation said.

This is a problem with a lot of documentation. When you already know the answer it is handy for reminding you but often hopeless if entirely new.

A good example is road signs on freeways designed by people who already know how to get there but can't visually imagine what it is like for a first time visitor.
 
By the way I also index the counter that counts the bytes received and sets the image box when all chunks are received otherwise they get confused too.
 
>By the way I also index the counter

Don't worry Ted, I'm not going to argue with you about your implementation details
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top