System() starting and killing a process within a thread

Hi everybody,

I was wondering how I can kill a process started with system(cmd) within a thread.

For example I start a new process (another c++ program fi) from a thread like this:

class SystemThread: public ofThread{

 public:
   string cmd;

   void setup(string _cmd){
       this->cmd = _cmd;
   }
 
 void threadedFunction(){
    if (isThreadRunning()){
       system(cmd.c_str());
    }
};

in main.h
#include "SystemThread.h"
...
SystemThread systhread;

in main.cpp
void ofApp::setup(){
     
    string execpath = ofToDataPath("ThisIsAnotherProgram_FFMPEG_FI");
    string cmd="bash --login -c '";
    cmd += execpath;
    cmd += "'";

    systhread.setup(cmd);
    systhread.startThread();
    
    //continue with other stuff here
}

What I have now is a simple program that is running in the shell. (this could be ffmpeg fi coverting some files)

What I would like to know is, how to kill this running process when I stop the thread. I have tried to use popen en pclose but using pclose freezes everything…

I know it works when I look at the multiple ffmpeg video recorders out there (fi https://github.com/timscaffidi/ofxVideoRecorder), but I don’t understand quite well how they manage to start/stop the ffmpeg process.
Maybe it has something to do with opening/closing the pipe that makes ffmpeg stop? I am not sure what is going on exactly.

I am looking for a general solution to do this, not only ffmpeg related, but I am a bit in the dark here.

Thank you for your help in advance,

HI,

under unix-based systems you can use the kill command,
This allows you to kill a running process, the most common form is:

kill -9 (job number)

you can retrieve the PID of the process in this way:

ps aux | grep Process_Name | grep -v grep | awk ‘{print $ 2}’

so maybe it can be useful to do a:

exec: to retrieve the PID of the process that you want to kill.
and then another exec to run the command kill -9 number_pid.

Ciao,
Dario

There may be an easier way but I would probably try

  • writing a script that either exits/kills itself once it is finished
  • write 2 scripts, one that starts the process and one that you call on the thread closing. the start script could have some logic to look if it is already running and kill any processes necessary.

Hi Dario, Jason,

Thanks for the input.!
I guess for me the best way to handle this situation is the second option that you gave Jason.

  1. use a script that opens the proces: system(“myprocess”) in a thread

  2. On stopping the thread use a script to get the pid of the process as Dario described.
    Something like this:
    File *myfile = popen(“ps aux | grep Process_Name | grep -v grep | awk ‘{print $ 2}’”,r)
    read the output from myfile (it should contain the pid address, could be multiple)

  3. With the output from 2 use another script to kill the process.
    Something like:
    system(‘kill -9 (12345)’)

However when I look at the implementation of ofxVideoRecorder fi, none of these things are happening and yet ffmpeg gets killed and restarted together with the threads that sprung it.
I am starting to think that ffmpeg closes itself once you close the pipe it is reading from (or writing to). I am no expert in threading or ffmpeg, so I am not sure.
I think I will have to strip down the code bit by bit and build it back up again piece by piece, to grasp what is going on :wink:

In regards to how ofxVideoRecorder works, the calls to ffmpeg will return when ffmpeg closes. ofxVideoRecorder does nothing to ensure that this happens. Luckily, it turns out that when there is nothing left in the video/audio pipes and they are closed by ofxVideoRecorder, ffmpeg will recognize this as being the end of input and will finish up the encode and close itself.

Hi Tim,

Thanks for your reply! I am working on a windows version based on the one by @DomAmato which is based on yours.

The problem is that when working with h264 video it leaks tremendously.
I solved that already and I can real time convert 1080p30 in h264.

What I am trying to do now is converting multiple videos at the same time.

This works when I spawn multiple instances of the videorecorder within the same process (meaning in the same app).
This however slows down the framerate too much.

So I was thinking to have different process each spawning only one instance of the videowriter (different exe’s each converting one video).
This however crashes. First I thought it had something to do with threads stealing memory from each other but in fact that’s not possible. The problem seems to be somewhere in the usage of the pipes in Windows…

I am trying to figure this out.

another idea would be to use multiple apps/processes. Try spout (https://github.com/elliotwoods/ofxSpout), its like syphon for windows and very fast (gpu texture sharing). Receive the texture(s) in a other OF apps for recording (however you want to record), thus the sender isn’t slowed down by this. You can use osc to give commands to the recording app(s).
Do make sure to have the latest video drivers, old nvidea drivers have a memory leak.

Hey Kj1,
Thanks for the reply. How are you man? We should get together again soon!

I am already using Spout to do this (with the bug fixed, sort of) :wink:
The problem is not in receiving textures. The problem seems to be in the recording with ffmpeg through pipes

For real time encoding with ffmpeg I use named PipeServers.

Every update (in a thread) the raw ofPixels are written to this named server with the method WriteFile.
The ffmpeg exec which runs in another thread has the named pipe server as input.

This all works very well when using only one process. (one exe).
If I run two exe’s (with each a different name server and each a different ffmpeg process) then the problems arise.
At that point the one started last is unable to process all the data which results in a crash due to memory insufficiency.

It seems like even though there are two named pipes (i checked this with the Proces Explorer) and two ffmpeg instances, somewhere along the road writing to a pipe gets tangled up or something.
I am not quite sure what is going on.

Can you say how you fixed the memory leak with h264 encoding so that it can be fixed on my end for others who are using the addon.

Piping on windows was… a process, there is a non named piping method but its incredibly slower than the named pipe. Also unlike the single pipe method usable in Tim’s version Windows named pipes would only take one instance at a time so theres actually two pipes, one for video, and one for audio and then something to sew up the files at the end.

Can I ask what you are doing with the files? if you are just trying to batch convert files you can really skip a ton of the process and do it from the ffmpeg command file and it might be better to do it that way than to leverage the ofxVideoRecorder methodology. In fact I would argue the only reason you would want to use ofxVideorecorder is for live video or recording the screen of the app you are making in openframeworks. The process of encoding and decoding videos will be way slower and prone to problems as you have pointed out

https://ffmpeg.org/ffmpeg.html#Stream-copy

Hi wim, indeed, we should get a drink soon! Cant really help you; seems like a very complex situation for just recording video. But encoding several highres video’s is very memory-intensive, which might actually be the cause of the issue?

Another way to go is to try touchdesigner: it has native video recording & spout support. Touchdesigner also has native accelerated nvidea gpu h264 encoding, so there would be less need for memroy intensive operations .

good luck!

Hi guys, thanks!

@DomAmato @Kj1 I really am suspecting it is indeed just a question of not enough memory.

@Kj1 I’ll take a look at touchdesigner. Thx. Maybe I can have it communicate with oF over OSC or something?

Dom in regards to fixing the memory in ofxVideoPlayer regarding h264.
The problem was not memory leaking but ffmpeg being so slow in writing, that frames were not cleared fast enough and kept on stacking in memory until it reached the 1,7Gb (on my machine) limit and crashes.

By using this line ffmpeg works much faster and so this keeps up with the thread (good enough) and runs smooth at 30fps. This is in a setup with video coming in from a Blackmagic Declink card over Blackspout in oF, hence the rgba pixel format.

ffmpegLocation << " -loglevel debug -y -video_size " << width << “x” << height << " -r " << fps << " -pix_fmt rgba -f rawvideo -i " << convertWideToNarrow(vPipename) << " -c:v libx264 -r " << fps << " -preset ultrafast -qp 22 -pix_fmt yuv420p " << outputString << movFileExt;

Regarding the stuff I’m working on it is indeed the case that I would like to use oF for previewing the video and then record and encode in real-time. I have a setup in wich I use a Blackmagic decklink card to capture the streams. With ffmpeg you can directly capture this (with directshow) and encode it like this:

ffmpeg -y -video_size 1920x1080 -r 50 -f dshow -i video=“Decklink Video Capture” -c:v libx264 -preset fast -crf 28 out.mp4

You can even use ffplay for preview but then you do not have an extra interface to control other stuff, so I would really like to get this working in oF with more than one stream at the same time.
I have no evidence to support this, but I still believe there has to be way encoding at least two stream at the same time using the named pipeSystem…

i don’t remember exactly how it works but i think you probably just need to give the different named piepes, different names. the name is probably hardcoded in ofxVideoRecorder and when you use more than one all of them use the same pipe.

The pipes should have a unique name, though right now the convention isn’t particularly elegant.

int num = ofRandom(1024);
sprintf(apip, "\\\\.\\pipe\\videoPipe%d", num);

they should also probably be titled differently as both the audio pipe and video pipe use this same convention… I think I tested multiple instances running simultaneously which prompted me to add in the random numbering on the end though its been awhile. Ill give it a test with encoding a prerecorded video and live video and see what happens

Not sure about @DomAmato’s fork, but ofxVideoRecorder should handle uniquely naming pipes for you. If you need multiple videos then you just create multiple recorder objects. The pipe numbers are handled by these functions:

int ofxVideoRecorder::requestPipeNumber(){
    int n = 0;
    while (openPipes.find(n) != openPipes.end()) {
        n++;
    }
    openPipes.insert(n);
    return n;
}

//--------------------------------------------------------------
void ofxVideoRecorder::retirePipeNumber(int num){
    if(!openPipes.erase(num)){
        ofLogNotice() << "ofxVideoRecorder::retirePipeNumber(): trying to retire a pipe number that is not being tracked: " << num << endl;
    }
}

where openPipes is a static set of integers.

Hi guys,

Thank you so much for looking into this.
Instead of typing everything out, I made a movie of where I am at, at the moment.
I know it’s pretty long (10min) and very amateur like :wink: but I hope it can shed some light on what is going on.


password: ofrules

I guess the question right now is? “Is there something going on with the pipes, or is just that I do not have enough RAM memory and just increasing RAM would that solve the case?”

Thank you so much in advance!

Hi everybody,

I just used the same version of the program, except for recording/encoding in HD (1920x1080) I changed it to 1280/720. Now everything runs smooth without any problems.

I just created a new video that shows recording and encoding real-time at 30fps with 3 processes at the same time.
In the video I only do this for a short amount of time, but in the meantime I have this setup running for more than 45 minutes without any problems.


pswd: ofrules

What would be a solution to get this working in HD? Is it a question of not enough memory, and would adding RAM help? Or is it a question of speed where the frames are not processed fast enough?

Thanks a lot!

Mostly guessing (and may have missed some details already explained) but I would see these as potential bottlenecks:

Are you able to run multiple instances of ffmpeg outside of OF? Maybe your situation requires multiple binaries of ffmpeg?

What happens if you turn off drawing while it is recording? Could narrow down potential GPU bottlenecks

Have you messed with the Affinity of the process? It’s been a while since I used Windows but you used to be able to assign a physical process to an executable by right clicking it in Windows Task Manager>Set Affinity. There is probably a way to do this programatically.