<commit_before>#pragma once

#include "ofMain.h"
#include <queue>
#include "FreeImage.h"

FI_STRUCT (FIMEMORYHEADER)
{
    /// remember to delete the buffer
    bool delete_me;
    /// file length
    long filelen;
    /// buffer size
    long datalen;
    /// current position
    long curpos;
    /// start buffer address
    void *data;
};

class ofxVideoRecorder : public ofThread
{
public:
    ofxVideoRecorder()
    {
        bIsInitialized = false;
    }
    bool setup(string fname, int w, int h, int fps)
    {
        if(bIsInitialized)
        {
            close();
        }

        width = w;
        height = h;
        frameRate = fps;
        fileName = fname;
        bIsInitialized = videoFile.open(fileName+".mjpg",ofFile::WriteOnly,true);
        if(!isThreadRunning())
            startThread(true, false);
        return bIsInitialized;
    }

    void addFrame(const ofPixels pixels)
    {
        if(bIsInitialized)
        {
            ofPixels * buffer = new ofPixels(pixels);

            lock();
            frames.push(buffer);
            unlock();
            condition.signal();
        }
    }

    void close()
    {
        bIsInitialized = false;
        waitForThread(false);
        if(videoFile.is_open())
        {
            videoFile.close();
        }
    }
    int encodeVideo()
    {
        if(bIsInitialized) close();
        char cmd[256];
        sprintf(cmd,"ffmpeg -y -r %2$d -i data/%1$s.mjpg -r %2$d -vcodec copy data/%1$s; rm data/%1$s.mjpg",fileName.c_str(), frameRate);
        return system(cmd);
    }

    void threadedFunction()
    {
        while(isThreadRunning())
        {
            ofPixels * frame = NULL;
			lock();
			if(!frames.empty()) {
				frame = frames.front();
				frames.pop();
			}
			unlock();

			if(frame){
				frame->swapRgb();

				FIBITMAP * bmp = FreeImage_ConvertFromRawBits(frame->getPixels(), width, height, width*3, 24, FI_RGBA_RED_MASK,FI_RGBA_GREEN_MASK,FI_RGBA_BLUE_MASK, true);
				FIMEMORY *hmem = FreeImage_OpenMemory();

				FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, 100);


				long file_size = FreeImage_TellMemory(hmem);
				videoFile.write((char *)(((FIMEMORYHEADER*)(hmem->data))->data), file_size);
				FreeImage_Unload(bmp);
				FreeImage_CloseMemory(hmem);

				delete frame;
			} else {
				if(bIsInitialized){
					//ofSleepMillis(1.0/(float)frameRate);
					condition.wait(conditionMutex);
				}else{
					break;
				}
			}
        }
    }

    int getNumFramesInQueue()
    {
        return frames.size();
    }
    bool isInitialized()
    {
        return bIsInitialized;
    }

private:
    string fileName;
    ofFile videoFile;<commit_msg>fixed infinite wait on empty queue when close() is called<commit_after>#pragma once

#include "ofMain.h"
#include <queue>
#include "FreeImage.h"

FI_STRUCT (FIMEMORYHEADER)
{
    /// remember to delete the buffer
    bool delete_me;
    /// file length
    long filelen;
    /// buffer size
    long datalen;
    /// current position
    long curpos;
    /// start buffer address
    void *data;
};

class ofxVideoRecorder : public ofThread
{
public:
    ofxVideoRecorder()
    {
        bIsInitialized = false;
    }
    bool setup(string fname, int w, int h, int fps)
    {
        if(bIsInitialized)
        {
            close();
        }

        width = w;
        height = h;
        frameRate = fps;
        fileName = fname;
        bIsInitialized = videoFile.open(fileName+".mjpg",ofFile::WriteOnly,true);
        if(!isThreadRunning())
            startThread(true, false);
        return bIsInitialized;
    }

    void addFrame(const ofPixels pixels)
    {
        if(bIsInitialized)
        {
            ofPixels * buffer = new ofPixels(pixels);

            lock();
            frames.push(buffer);
            unlock();
            condition.signal();
        }
    }

    void close()
    {

        condition.signal();
        while(frames.size() > 0) ofSleepMillis(100);

        bIsInitialized = false;
        condition.signal();

        stopThread();


        if(videoFile.is_open())
        {
            videoFile.close();
        }
    }
    int encodeVideo()
    {
        if(bIsInitialized) close();
        char cmd[256];
        sprintf(cmd,"ffmpeg -y -r %2$d -i data/%1$s.mjpg -r %2$d -vcodec copy data/%1$s; rm data/%1$s.mjpg",fileName.c_str(), frameRate);
        return system(cmd);
    }

    void threadedFunction()
    {
        while(isThreadRunning())
        {
            ofPixels * frame = NULL;
			lock();
			if(!frames.empty()) {
				frame = frames.front();
				frames.pop();
			}
			unlock();

			if(frame){
			    if(frame->getBytesPerPixel() >=3)
                    frame->swapRgb();

				FIBITMAP * bmp = FreeImage_ConvertFromRawBits(frame->getPixels(), width, height, width*frame->getBytesPerPixel(), frame->getBitsPerPixel(), FI_RGBA_RED_MASK,FI_RGBA_GREEN_MASK,FI_RGBA_BLUE_MASK, true);
				FIMEMORY *hmem = FreeImage_OpenMemory();

				FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, 100);


				long file_size = FreeImage_TellMemory(hmem);
				videoFile.write((char *)(((FIMEMORYHEADER*)(hmem->data))->data), file_size);
				FreeImage_Unload(bmp);
				FreeImage_CloseMemory(hmem);

				delete frame;
			} else {
				if(bIsInitialized){
				    ofLog(OF_LOG_VERBOSE, "ofxVideoRecorder: threaded function: waiting for mutex condition");
					condition.wait(conditionMutex);
				}else{
				    ofLog(OF_LOG_VERBOSE, "ofxVideoRecorder: threaded function: exiting");
					break;
				}
			}
        }
    }

    int getNumFramesInQueue()
    {
        return frames.size();
    }
    bool isInitialized()
    {
        return bIsInitialized;
    }

private:
    string fileName;
    ofFile videoFile;
{'fraction_non_alphanumeric': 0.1240581741720694, 'fraction_numerical': 0.005607149115121781, 'mean_word_length': 2.162326869806094, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7211944', 'n_tokens_mistral': 2003, 'n_tokens_neox': 1853, 'n_words': 365}