From dce6d4b0303aadf398d3b8defe8e3c6a281886f0 Mon Sep 17 00:00:00 2001 From: Erik Zandvliet Date: Thu, 7 Mar 2013 12:19:15 +0100 Subject: [PATCH] Updates to StartPiped (added std::string version and a 2-process variant), also updated conversion to allow for status checks (not fully functional yet) --- lib/converter.cpp | 44 +++++++++++++++++++++++++++++++++++++-- lib/procs.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++++++ lib/procs.h | 2 ++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/lib/converter.cpp b/lib/converter.cpp index 5c6a5974..425a4a76 100644 --- a/lib/converter.cpp +++ b/lib/converter.cpp @@ -161,7 +161,9 @@ namespace Converter { } encoderCommand << "-f flv -"; } - Util::Procs::Start(name,encoderCommand.str(),Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString()); + int statusFD = -1; + Util::Procs::StartPiped2(name,encoderCommand.str(),Util::getMyPath() + "MistFLV2DTSC -o " + parameters["output"].asString(),0,0,&statusFD,0); + parameters["statusFD"] = statusFD; allConversions[name] = parameters; } @@ -200,12 +202,50 @@ namespace Converter { } } + JSON::Value parseFFMpegStatus(std::string statusLine){ + JSON::Value result; + int curOffset = statusLine.find("frame=") + 6; + result["frame"] = atoi(statusLine.substr(curOffset, statusLine.find("fps=") - curOffset).c_str() ); + curOffset = statusLine.find("time=") + 5; + int myTime = 0; + myTime += atoi(statusLine.substr(curOffset, 2).c_str()) * 60 * 60 * 1000; + myTime += atoi(statusLine.substr(curOffset+3, 2).c_str()) * 60 * 1000; + myTime += atoi(statusLine.substr(curOffset+6, 2).c_str()) *1000; + myTime += atoi(statusLine.substr(curOffset+9, 2).c_str()) * 10; + result["time"] = myTime; + return result; + } + JSON::Value Converter::getStatus(){ updateStatus(); JSON::Value result; if (allConversions.size()){ for (std::map::iterator cIt = allConversions.begin(); cIt != allConversions.end(); cIt++){ - result[cIt->first] = "Converting"; + int statusFD = dup(cIt->second["statusFD"].asInt()); + fsync( statusFD ); + FILE* statusFile = fdopen( statusFD, "r" ); + char * fileBuf = 0; + size_t fileBufLen = 0; + fseek(statusFile,0,SEEK_END); + std::string line; + int totalTime = 0; + do{ + getdelim(&fileBuf, &fileBufLen, '\r', statusFile); + line = fileBuf; + if (line.find("Duration") != std::string::npos){ + int curOffset = line.find("Duration: ") + 10; + totalTime += atoi(line.substr(curOffset, 2).c_str()) * 60 * 60 * 1000; + totalTime += atoi(line.substr(curOffset+3, 2).c_str()) * 60 * 1000; + totalTime += atoi(line.substr(curOffset+6, 2).c_str()) *1000; + totalTime += atoi(line.substr(curOffset+9, 2).c_str()) * 10; + cIt->second["duration"] = totalTime; + } + }while(line.find("frame") != 0);//"frame" is the fist word on an actual status line of ffmpeg + result[cIt->first] = parseFFMpegStatus( line ); + result[cIt->first]["duration"] = cIt->second["duration"]; + result[cIt->first]["progress"] = (result[cIt->first]["time"].asInt() * 100) / cIt->second["duration"].asInt(); + free(fileBuf); + fclose(statusFile); } } if (statusHistory.size()){ diff --git a/lib/procs.cpp b/lib/procs.cpp index 810161b6..f0a07913 100644 --- a/lib/procs.cpp +++ b/lib/procs.cpp @@ -528,6 +528,59 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int * return pid; } +/// Starts a new process with given fds if the name is not already active. +/// \return 0 if process was not started, process PID otherwise. +/// \arg name Name for this process - only used internally. +/// \arg cmd Command for this process. +/// \arg fdin Standard input file descriptor. If null, /dev/null is assumed. Otherwise, if arg contains -1, a new fd is automatically allocated and written into this arg. Then the arg will be used as fd. +/// \arg fdout Same as fdin, but for stdout. +/// \arg fdout Same as fdin, but for stderr. +pid_t Util::Procs::StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr){ + //Convert the given command to a char * [] + char * tmp = (char*)cmd.c_str(); + char * tmp2 = 0; + char * args[21]; + int i = 0; + tmp2 = strtok(tmp, " "); + args[0] = tmp2; + while (tmp2 != 0 && (i < 20)){ + tmp2 = strtok(0, " "); + ++i; + args[i] = tmp2; + } + if (i == 20){ + args[20] = 0; + } + return StartPiped(name,args,fdin,fdout,fderr); +} + + +pid_t Util::Procs::StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2){ + int pfildes[2]; + if (pipe(pfildes) == -1){ +#if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl; +#endif + return 0; + } + pid_t res1 = StartPiped(name, cmd1, fdin, &pfildes[1], fderr1); + if ( !res1){ + close(pfildes[1]); + close(pfildes[0]); + return 0; + } + pid_t res2 = StartPiped(name+"receiving", cmd2, &pfildes[0], fdout, fderr2); + if ( !res2){ + Stop(res1); + close(pfildes[1]); + close(pfildes[0]); + return 0; + } + //we can close these because the fork in StartPiped() copies them. + close(pfildes[1]); + close(pfildes[0]); + return res1; +} /// Stops the named process, if running. /// \arg name (Internal) name of process to stop void Util::Procs::Stop(std::string name){ diff --git a/lib/procs.h b/lib/procs.h index 32fdd46d..4f24ff5c 100644 --- a/lib/procs.h +++ b/lib/procs.h @@ -27,6 +27,8 @@ namespace Util { static pid_t Start(std::string name, std::string cmd, std::string cmd2); static pid_t Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3); static pid_t StartPiped(std::string name, char * argv[], int * fdin, int * fdout, int * fderr); + static pid_t StartPiped(std::string name, std::string cmd, int * fdin, int * fdout, int * fderr); + static pid_t StartPiped2(std::string name, std::string cmd1, std::string cmd2, int * fdin, int * fdout, int * fderr1, int * fderr2); static void Stop(std::string name); static void Stop(pid_t name); static void StopAll();