Problem with ofMemoryImage and threaded web scraper

Hi all.

Some context:

I’m trying to code a simple app which downloads / draws images from the web using poco for net and events and ofxThread for threads (so that the app doesn’t freeze each time I download).

I’ve written a SimpleWebScraper to request both text and images and an ofMemoryImage to load images from memory (adapting the code from here
http://www.openframeworks.cc/forum/view-…-light=poco
to the latest svn version. 163 I think)

This is how it works with images (where I have the problem):

  • I call getStream passing a url.
  • The web scraper starts a thread and downloads the stream (using the poco code from the link above)
  • when it’s finished, it dispatches an event with the stream data (unsigned char * buff and int bytesToRead) to testApp.
  • on my testApp I receive the data and try to do loadFromData in my memoryImage (with setUseTexture set to false, to avoid uploading to the texture from a thread.)

And the thing is that freeimage_loadfrommemory is not working when the passed data comes from the thread. I think my ofMemoryImage is receiving the data ok because it’s even figuring out the image filetype with FreeImage_GetFileTypeFromMemory, but it doesn’t load the data.

Also, it works if I download the image normally (unthreaded), so the code in the poco downloader and ofMemoryImage must be working ok.

Here’s a simplified app that shows the problem. It has the ofMemoryImage and SimpleWebScraper.

http://jesusgollonet.com/openFrameworks-…-craper.zip

usage:
key 1: gets raw text from the web (works)
key 2: downloads and shows an image blocking the app (works)
key 3: tries to download an image on a thread and get the data into an ofMemoryImage (fails)

It is built over the latest svn version with poco and the new event model
(see http://forum.openframeworks.cc/t/cmake-as-crossplatform-solution-testers/1058/7 )

Any tips at what might be happening? Don’t hesitate to suggest even the silliest things. this is not firm ground for me, so I might be doing several stupid things at once.

Thanks a lot!
good night.

some points about threads - opengl is not multithreaded so any opengl specific action, like uploading data to a texture etc is not going to work not done in the main testApp update, draw etc. that could be your first problem.

also, I remember that I’ve sometimes had this problem with freeImage (using the load from memory) but not sure what it’s about. (actually this was with the canon control stuff we worked on together). can you try outputting the raw data you get to a file (be sure to choose “write binary” when you create the file) and then

(a) seeing if you can view it in an image editor, like photoshop, etc (you might need to give the right file name at the end)

(b) seeing if you can load the saved version of the image into freeImage using ofImage::loadImage (ie, save to disk the raw bytes, then read them into freeImage).

if those things work, then you might have good luck on the freeImage discussion forum also because they might have better ideas about fixes for the loading from memory –

good luck!
zach

Hey jesus

The problem is that in handleStreamRequest:

  
unsigned char buff[bytesToRead];  
  
	memset(buff, 0, bytesToRead);  
  
	for(int i = 0; i < bytesToRead; i++){  
		buff[i] = str[i];  
	}  
	  
	args.buff			= buff;  
	args.bytesToRead	= bytesToRead;  

declaring buff like that you are creating the array in the stack, so when the function ends that memory disappears and when you try to load from the main app it doesn’t exists anymore.

try changing:

  
unsigned char buff[bytesToRead];  

with

  
unsigned char * buff = new unsigned char[bytesToRead];  

And it will work, but then you have a memory leak and need to delete that memory after the image has been loaded.

hey thanks!

@zach: thanks for the tips. I had tried most of what you suggest (after searching a lot on the forums and watching you repeating this things over an over:) ). I could even save to disk and load again, as I remembered that from the canon code, but I wanted to get it from memory as an exercise.

@arturo:yeah that was it! now it works. I’m trying to figure out where/how to delete that memory. Can I abuse your wisdom a little bit more and ask for a way to do it?

At any rate, thanks a lot guys.

You can just delete it once you’ve called the event notify, by then the pixels have already been copied to the free_image structure:

  
delete[] args.buff;  

But it can be a little bit of a problem because you have references to that arguments all over the code, indeed I think they are not used anymore so perhaps the best thing is create the arguments when you need them and delete the buffer when you’ve finished with it. So all the arguments in the .h shouldn’t be there and instead, just create them before notifying the event.

That way you make sure that you’re not going to try to access that memory again.

thanks man, you’re great.
best!

Hey All,

I have been watching this thread with interest:

http://forum.openframeworks.cc/t/loading-ofimage-from-url-using-poco/562/0

I grabbed madparker’s latest code and it worked fine for me too, with OF057 upwards.

What I want to do now is create a threaded version that can load from a URL and not slow the rest of the program.

My attempt is below and builds with the:

00573-Xcode-Fat-YCAM-WithGui

From:

http://www.openframeworks.cc/files/

webImageLoader.h:

  
  
/*  
 *  webImageLoader.h  
 *  openFrameworks  
 *  
 *  Created by Joel Gethin Lewis on 31/10/2008.  
 *  Totally based on:  
 *	[http://forum.openframeworks.cc/t/loading-ofimage-from-url-using-poco/562/0](http://forum.openframeworks.cc/t/loading-ofimage-from-url-using-poco/562/0)  

webImageLoader.cpp:

  
  
/*  
 *  webImageLoader.cpp  
 *  openFrameworks  
 *  
 *  Created by Joel Gethin Lewis on 31/10/2008.  
 *  Totally based on:  
 *	[http://forum.openframeworks.cc/t/loading-ofimage-from-url-using-poco/562/0](http://forum.openframeworks.cc/t/loading-ofimage-from-url-using-poco/562/0)  

testApp.h:

  
  
#ifndef _TEST_APP  
#define _TEST_APP  
  
#include "ofMain.h"  
  
// this h file has the definition for an object that uses the threaded addon:  
  
#include "threadedObject.h"  
  
#include "Poco/URIStreamOpener.h"   
#include "Poco/StreamCopier.h"   
#include "Poco/Path.h"   
#include "Poco/URI.h"   
#include "Poco/Exception.h"   
#include "Poco/Net/HTTPStreamFactory.h"   
#include "Poco/XML/XMLString.h"   
#include "Poco/DOM/DOMParser.h"   
#include "Poco/DOM/Document.h"   
#include "Poco/DOM/NodeIterator.h"   
#include "Poco/DOM/NodeFilter.h"   
#include "Poco/DOM/NamedNodeMap.h"   
#include <memory>  
#include <iostream>  
#include <fstream>  
#include <vector>  
  
using Poco::URIStreamOpener;   
using Poco::StreamCopier;   
using Poco::Path;   
using Poco::URI;   
using Poco::Exception;   
using Poco::Net::HTTPStreamFactory;   
  
static bool factoryLoaded = false;   
  
class testApp : public ofSimpleApp{  
	  
	public:  
		  
		void setup();  
		void update();  
		void draw();  
		  
		void keyPressed  (int key);  
		void mouseMoved(int x, int y );  
		void mouseDragged(int x, int y, int button);  
		void mousePressed(int x, int y, int button);  
		void mouseReleased();  
  
	// callback events ----------------------------------------------------------  
	void onThreadedStreamReceived(const void* pSender, string& response);  
	  
private:  
	  
	threadedObject	TO;  
	  
	int				mainAppsCount;  
	  
};  
  
#endif	  
  

testApp.cpp:

  
  
#include "testApp.h"  
#include "stdio.h"  
  
bool locked = false;  
  
//--------------------------------------------------------------  
void testApp::setup(){	   
	  
	TO.threadedStreamReady		+= Delegate<testApp, string>(this, &testApp::onThreadedStreamReceived);  
	  
	//poco is not happy if we register the factory more than once   
	if(!factoryLoaded){   
		HTTPStreamFactory::registerFactory();   
		factoryLoaded = true;   
	} 	  
	  
	mainAppsCount = 0;  
	TO.start();  
}  
  
//--------------------------------------------------------------  
void testApp::update(){	  
	ofBackground(0,0,0);   // black because threads are EVIL ;)  
	mainAppsCount++;  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofSetColor(0xffffff);  
	//TO.draw();  
  
  
    string str = "I am a the main opengl thread.\nmy current count is: ";  
	str += ofToString(mainAppsCount);  
    ofDrawBitmapString(str, 350, 56);  
      
      
    //ofSetColor(0xff0033);  
	  
	if(TO.webImageLoaded)  
	{  
		cout << "Image loaded!!!!" << endl;  
		TO.theWebImage.draw(0,0);  
	}  
	else  
	{  
		cout << "Image not loaded... yet" << endl;  
	}  
}  
  
//--------------------------------------------------------------  
void testApp::keyPressed  (int key){   
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
	  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
	  
}  
  
//--------------------------------------------------------------  
void testApp::mouseReleased(){  
}  
  
void testApp::onThreadedStreamReceived(const void* pSender, string& response) {  
	cout << "Image loaded" << endl;  
	string resp = response;  
	cout << resp << endl;  
}	  
  

threadedObject.h:

  
  
#ifndef _THREADED_OBJECT  
#define _THREADED_OBJECT  
  
#include "ofMain.h"  
#define OF_ADDON_USING_OFXTHREAD  
#include "ofAddons.h"  
#include "webImageLoader.h"  
  
// event stuff -------------------------------------  
#include "Poco/BasicEvent.h"  
#include "Poco/Delegate.h"  
  
using Poco::BasicEvent;  
using Poco::Delegate;  
  
// this is not a very exciting example yet   
// but ofThread provides the basis for ofNetwork and other   
// operations that require threading.  
//  
// please be careful - threading problems are notoriously hard   
// to debug and working with threads can be quite difficult  
  
  
class threadedObject : public ofxThread{  
  
	public:  
	  
	threadedObject();  
	void start();          
	void stop();  
	void threadedFunction();  
	//void draw();  
	  
	int						count;    
	BasicEvent<string>		threadedStreamReady;  
	bool					webImageLoaded;  
	  
	webImageLoader			theWebImage;  
};  
  
#endif  
  

threadedObject.cpp:

  
  
/*  
 *  threadedObject.cpp  
 *  openFrameworks  
 *  
 *  Created by Joel Gethin Lewis on 02/11/2008.  
 *  Based on the ofxThread example  
 *  
 */  
  
#include "threadedObject.h"  
  
//--------------------------  
threadedObject::threadedObject(){  
	count = 0;  
	webImageLoaded = false;  
}  
  
void threadedObject::start(){  
	  
	if (isThreadRunning() == false){  
        printf("thread started\n");  
        startThread(true,false);  
    }	  
}  
  
void threadedObject::stop(){  
	stopThread();   
}  
  
//--------------------------  
void threadedObject::threadedFunction(){  
	  
	while(isThreadRunning())  
	{  
		webImageLoaded = false;  
	  
		theWebImage.loadFromUrl("[http://cache.gawker.com/assets/images/io9/2008/11/ironman1.jpg");](http://cache.gawker.com/assets/images/io9/2008/11/ironman1.jpg");)  
		  
		string response = "Image loaded";  
		  
		threadedStreamReady.notify(this, response);  
		webImageLoaded = true;  
		  
		stop();  
	}  
}  
  

Ideally, I’d like to be able to display progress of the load, or at least monitor it - but a system that notifies when the load is complete and the image is available to view for now is fine.

I have been reading some other posts about threading:

“threaded image loader”
http://forum.openframeworks.cc/t/threaded-image-loader/816/0

Do I have the classic “OpenGL is not thread safe” problem because I am trying to save to a texture in the threaded part of the code?

Jesus, did you get any closer? It seems we have very similar aims in mind.

Jesus, did you get any closer? It seems we have very similar aims in mind.

Yep, as far as I remember I got it working. let me clean the code and I’ll post it.

cheers.

Hey Jesus,

That’s great - look forward to seeing it. Out of interest - does anyone know if it is the OpenGL non thread safe issue that is stopping me? I have a sneaking suspicion that by thread code is at fault in general - rather than the OpenGL classic.

The event isn’t even getting notified via Poco, which makes me very suspicious.

I haven’t had to play with threads in years - my old Java hacking from my Maths and Computer science days are being dredged from memory. (-;

I’ll be writing this all up for the Wiki after - I have seen several requests for better documentation on Threads on it.

Cheers,

JGL

ok, no time to clean. here it is in all its rawness.

http://jesusgollonet.com/openFrameworks-…-dersrc.zip

press ‘1’, ‘2’, ‘3’, and ‘4’ to get 4 different images, and see the dancing square blocking test moving endlesly :slight_smile:

Hey Jesus,

Great! Thanks for posting that. I have dropped it into a build and I keep getting back:

  
The Debugger Debugger is attaching to process  
[Session started at 2008-11-03 12:02:50 -0500.]  
terminate called after throwing an instance of 'Poco::SystemException  
[Session started at 2008-11-03 12:02:51 -0500.]  
'  
  what():  System exception  

Does it run cleanly on your system?

Cheers,

JGL

Sorry for the exception stuff. I just had to clean my build!

All looks good now! This is very helpful.

The final hurdle would be to work out how to monitor the download in progress - would it be best to use sessions a la the Mail addon? I am going to be fiddling for the rest of the day.

Best,

JGL