multithreaded image saver


#1

Here is a simple little class which saves images in a separate thread. Instead of ofImage just use ofxThreadedImageSaver - everything functions like ofImage, but you can call myImage.saveThreaded(“blah.png”) and the encoding and writing to disk is done in a separate thread so as not to block the main app. Note if the data is locked and it cannot save a frame it just skips, does not wait to retry - you can change that from the startThread(false, …) line. Maybe could be useful…

  
#include "ofMain.h"  
#include "ofxThread.h"  
  
class ofxThreadedImageSaver : public ofxThread, public ofImage {  
public:  
	string fileName;  
	  
	void threadedFunction() {  
		if(lock()) {  
			saveImage(fileName);  
			unlock();  
		} else {  
			printf("ofxThreadedImageSaver - cannot save %s cos I'm locked", fileName.c_str());  
		}  
		stopThread();  
	}  
	  
	void saveThreaded(string fileName) {  
		this->fileName = fileName;  
		startThread(false, false);   // blocking, verbose  
	}  
};  
  
  


Screenshot saving slow on Raspberry Pi with ofxRPiCameraVideoGrabber
#2

Just curious,
Have you use this to render out frame sequences for recording video of a real-time app? Seems like this might be useful for this sort of thing…


#3

yup, thats exactly what i use it for, I save out sequence of pngs (along with the FBO saving code at http://forum.openframeworks.cc/t/saveimage-plus-alpha/1145/5).


#4

Here is the ofxPBOTexture code I mentioned.

It is very basic for now - but illustrates how you can work with the PBO data.
A lot of examples use 2 PBOs but this one is using just one for now.

Based off of code from:
http://www.songho.ca/opengl/gl-pbo.html

Here is an example of readback:
http://www.songho.ca/opengl/gl-pbo.html#pack

This seems like a great post regarding using PBOs for fast screencapture:
http://www.opengl.org/discussion-boards-…-304&page=1

Second page has some sample code and tips.

Theo

[attachment=0:1ukfx38d]ofxPBOTexture.zip[/attachment:1ukfx38d]

ofxPBOTexture.zip


#5

I’ve tried using the threaded image saver class and it works very well, however I can’t seem to control the frame numbering issue.

Instead of;
snapshot_001.png
snapshot_002.png
snapshot_003.png…

I’m getting;
snapshot_001.png
snapshot_003.png
snapshot_006.png
snapshot_008.png… and so on

I’m fairly new to C++ and OFX, so perhaps there’s something I’m not doing properly. Any kind of feedback or code commentary is more than welcome!

testApp.h

  
  
#ifndef _TEST_APP  
#define _TEST_APP  
  
#include "ofMain.h"  
#include "ofAddons.h"  
#include "ofxThreadedImageSaver.h"  
  
class testApp : public ofBaseApp{  
	public:  
		void setup();  
		void update();  
		void draw();  
		ofxThreadedImageSaver TIS;  
		ofImage img;  
		int counter;  
};  
  
#endif  
	  
  
  

testApp.cpp

  
  
  
#include "testApp.h"  
void testApp::setup(){  
	ofBackground(255,255,255);  
	counter = 0;  
}  
  
void testApp::update(){  
}  
  
void testApp::draw(){  
	ofSetColor(255,130,0);  
	ofFill();  
	ofRect(mouseX,mouseY,20,20);  
	counter++;  
	img.grabScreen(0,0,640,480);  
	char fileName[255];  
	sprintf(fileName, "snapshot_%0.3i.png", counter);  
	TIS.saveThreaded(fileName,img);  
}  
  

and my slightly modified copy of ofxThreadedImageSaver.h

  
  
#include "ofMain.h"  
#include "ofxThread.h"  
  
class ofxThreadedImageSaver : public ofxThread, public ofImage {  
public:  
	string fileName;  
	ofImage myImage;  
	void threadedFunction() {  
		if(lock()) {  
			myImage.saveImage(fileName);  
			unlock();  
		} else {  
			printf("ofxThreadedImageSaver - cannot save %s cos I'm locked", fileName.c_str());  
		}  
		stopThread();  
	}  
	void saveThreaded(string fileName, ofImage imageToSave) {  
		this->fileName = fileName;  
		this->myImage = imageToSave;  
		startThread(false, false);  
	}  
};  
  

Is this an issue with the way I’m using the ofxThreadedImageSaver class?
I tried fiddling with the “startThread(false, false);” line, but couldn’t seem to get any change in behaviour, lowering the framerate didn’t make much difference.

Such a useful class to have working, I’d love to know if I’m just not using it properly.

setup-
Macbook OS X 10.5.8
Xcode 3.1.3
of_preRelease_v0061_osx_FAT

Thanks!
J


#6

This thread is rather old, but I’m having the same issue using this class. Offloading the image saving into a separate thread has my app performing well now, but even when saving as BMP with blocking set to true I am missing a few frames.

Has anyone had luck troubleshooting this?

-K


#7

Not sure, I didn’t try this. But it seems like your counter is increased in every call of draw. Now because the image saver is threaded, it is not in sync with the calls to the draw function. Let’s say you begin saving at counter value 1, the threaded image saver may take two frames to complete, so the counter now is at 3, when you save the image again.

So instead of

  
void testApp::draw(){    
    ofSetColor(255,130,0);    
    ofFill();    
    ofRect(mouseX,mouseY,20,20);    
    counter++;    
    img.grabScreen(0,0,640,480);    
    char fileName[255];    
    sprintf(fileName, "snapshot_%0.3i.png", counter);    
    TIS.saveThreaded(fileName,img);    
}   

You should probrably do the counter thing somewhere else like (untested):

  
  
#include "ofMain.h"    
#include "ofxThread.h"    
    
class ofxThreadedImageSaver : public ofxThread, public ofImage {    
public:    
  
    int counter;  
    string fileName;    
    ofImage myImage;   
      
    ofxThreadedImageSaver(){  
        counter=0;  
    }  
       
    void threadedFunction() {    
        if(lock()) {    
            myImage.saveImage(fileName);    
            unlock();    
        } else {    
            printf("ofxThreadedImageSaver - cannot save %s cos I'm locked", fileName.c_str());    
        }    
        stopThread();    
    }    
    void saveThreaded(ofImage imageToSave) {  
        string fileName;  
        sprintf(fileName, "snapshot_%0.3i.png", counter);     
        counter++;   
        this->fileName = fileName;    
        this->myImage = imageToSave;    
        startThread(false, false);    
    }    
};  


#8

Thanks underdoeg! I had misunderstood the nature of this threaded image saver code. It provides one additional thread to help with image saving; it does not spawn a new thread for each save call. If the additional thread is busy, it skips saving the frame. Your solution should work well if you don’t mind dropping a frame occasionally and only require sequential numbering (which is actually ok in my case).

I think the best solution might be to create a few threaded savers and cycle through them. Until I understand threading more intuitively, I’m not sure how difficult it would be to spawn a new thread for each save call – it would likely require a lot of memory to instantiate a new threadedImageSaver object each frame (so hopefully there’s a more efficient way).

For now, I have hacked around this a bit and used BMP format for saving because it’s much faster (and less likely to skip a frame). Once I have my BMPs, I use ffmpeg to save a movie to disk which I later interpret.

Hope to update again with some helpful code :slight_smile:


#9

Hi guys,

I took the ideas in this thread, extended them a little bit and created an ofxImageSequenceRecorder:

https://github.com/atduskgreg/ofxImageSequenceRecorder

Instead of stopping and starting the thread, my code maintains an internal queue to ensure things get saved in the order they were added. I also basically store ofPixels objects (with a few extra bits of data) so it can store (and save) from ofImage, ofVideoGrabber, ofVideoPlater, etc.

Take a look and see if there’s any tips or anything I should add.

Thanks!


#10

thanks greg! was actually just going to start on something similar - will give it a shot


#11

I know this is an old post, but this addons crashes when using it on Windows 10.

Here it is the line when it crash:

void threadedFunction() { 		
        while(isThreadRunning()) {			
            if(!q.empty()){												
                QueuedImage i = q.front();        ====> it crashes here
                ofSaveImage(i.image, i.fileName);				
		q.pop();				
            }			
        }		                
    }

I tryed @stephanschulz workaround, no luck though, same problem.

I notice the problem is in the folowing marked line in ofPixels.cpp.

template<typename PixelType>
void ofPixels_<PixelType>::allocate(size_t w, size_t h, ofPixelFormat format){
	if (w == 0 || h == 0 || format == OF_PIXELS_UNKNOWN) {
		return;
	}
       ....................................................
       ....................................................

	pixelsSize = newSize / sizeof(PixelType);
		
	pixels = new PixelType[pixelsSize]; ======> it crashes here, bad allocation memory, pixelSize = 921600
	bAllocated = true;
	pixelsOwner = true;
}

My app is constantly running, and the memory consume increases as the time is passing. It seems there is (are) a sort of memory leak out there that I couldn´t identify properly. Someone posted something in github, but there is no response by its creator, so I take a shot here.

Maybe @arturo could give any hint?

OS: Windows 10 64 bits (running the app int 32 bits though)
oF: 0.10

Thanks in advance


#12

take a look at the threads/threadChannelExample which does something similar but using an ofThreadChannel which makes it much easier to work with threads safely


#13

Gracias @arturo , I am back to the project again, I will try ofThreadChannel then. Best!


#14

BTW I used the ofxImageSequence a while ago and did some modifications.
It runned well for me so if you want to have a look. here it is:


#15

Gracias @Jordi, I will give it a try too. The context of the usage of these addonss is the following: I have to oF apps running simultaneously. One makes screen captures, the another makes gifs/videos with the images the first one produces. I need an architecture that holds a sort of IPC . By now I am making it through OSC messages between them.
Thiis process is related to a this post I did a few time ago: Save frames every X framerate to a GIF file.
The two procceses are meant to be running for a long period.
The main issue I am facing is that if I save the images without communicating with the another process, it works, but as soon as they communicate I get a segmentation fault. Always in the same line.

Btw @Jordi, I read you use ofxVideoPlayer, I had problems using it on Windows 10, did you try it on this OS too?.
Best!