Merge branch 'development' into LTS_development

# Conflicts:
#	CMakeLists.txt
#	src/analysers/info.cpp
This commit is contained in:
Thulinma 2015-04-16 12:24:37 +02:00
commit cb298c57fd
13 changed files with 84 additions and 2003 deletions

View file

@ -1,109 +0,0 @@
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <mist/json.h>
#include <mist/dtsc.h>
#include <mist/procs.h>
#include <mist/timing.h>
namespace Info {
int getInfo(int argc, char* argv[]) {
if (argc < 2){
fprintf( stderr, "Usage: %s <filename>\n", argv[0] );
return 1;
}
DTSC::File F(argv[1]);
JSON::Value fileSpecs = F.getMeta().toJSON();
if( !fileSpecs ) {
char ** cmd = (char**)malloc(3*sizeof(char*));
cmd[0] = (char*)"ffprobe";
cmd[1] = argv[1];
cmd[2] = NULL;
int outFD = -1;
Util::Procs::StartPiped("FFProbe", cmd, 0, 0, &outFD);
while( Util::Procs::isActive("FFProbe")){ Util::sleep(100); }
FILE * outFile = fdopen( outFD, "r" );
char * fileBuf = 0;
size_t fileBufLen = 0;
while ( !(feof(outFile) || ferror(outFile)) && (getline(&fileBuf, &fileBufLen, outFile) != -1)){
std::string line = fileBuf;
if (line.find("Input") != std::string::npos){
std::string tmp = line.substr(line.find(", ") + 2);
fileSpecs["format"] = tmp.substr(0, tmp.find(","));
}
if (line.find("Duration") != std::string::npos){
std::string tmp = line.substr(line.find(": ", line.find("Duration")) + 2);
tmp = tmp.substr(0, tmp.find(","));
int length = (((atoi(tmp.substr(0,2).c_str()) * 60) + atoi(tmp.substr(3,2).c_str())) * 60) + atoi(tmp.substr(6,2).c_str());
fileSpecs["length"] = length;
length *= 100;
length += atoi(tmp.substr(9,2).c_str());
fileSpecs["lastms"] = length * 10;
}
if (line.find("bitrate") != std::string::npos ){
std::string tmp = line.substr(line.find(": ", line.find("bitrate")) + 2);
fileSpecs["bps"] = atoi(tmp.substr(0, tmp.find(" ")).c_str()) * 128;
}
if (line.find("Stream") != std::string::npos ){
std::string tmp = line.substr(line.find(" ", line.find("Stream")) + 1);
int strmIdx = fileSpecs["streams"].size();
int curPos = 0;
curPos = tmp.find(": ", curPos) + 2;
fileSpecs["streams"][strmIdx]["type"] = tmp.substr(curPos, tmp.find(":", curPos) - curPos);
curPos = tmp.find(":", curPos) + 2;
fileSpecs["streams"][strmIdx]["codec"] = tmp.substr(curPos, tmp.find_first_of(", ", curPos) - curPos);
curPos = tmp.find(",", curPos) + 2;
if (fileSpecs["streams"][strmIdx]["type"] == "Video"){
fileSpecs["streams"][strmIdx]["encoding"] = tmp.substr(curPos, tmp.find(",", curPos) - curPos);
curPos = tmp.find(",", curPos) + 2;
fileSpecs["streams"][strmIdx]["width"] = atoi(tmp.substr(curPos, tmp.find("x", curPos) - curPos).c_str());
curPos = tmp.find("x", curPos) + 1;
fileSpecs["streams"][strmIdx]["height"] = atoi(tmp.substr(curPos, tmp.find(",", curPos) - curPos).c_str());
curPos = tmp.find(",", curPos) + 2;
fileSpecs["streams"][strmIdx]["bps"] = atoi(tmp.substr(curPos, tmp.find(" ", curPos) - curPos).c_str()) * 128;
curPos = tmp.find(",", curPos) + 2;
fileSpecs["streams"][strmIdx]["fpks"] = (int)(atof(tmp.substr(curPos, tmp.find(" ", curPos) - curPos).c_str()) * 1000);
fileSpecs["streams"][strmIdx].removeMember( "type" );
fileSpecs["video"] = fileSpecs["streams"][strmIdx];
}else if (fileSpecs["streams"][strmIdx]["type"] == "Audio"){
fileSpecs["streams"][strmIdx]["samplerate"] = atoi(tmp.substr(curPos, tmp.find(" ", curPos) - curPos).c_str());
curPos = tmp.find(",", curPos) + 2;
if (tmp.substr(curPos, tmp.find(",", curPos) - curPos) == "stereo"){
fileSpecs["streams"][strmIdx]["channels"] = 2;
}else if (tmp.substr(curPos, tmp.find(",", curPos) - curPos) == "mono"){
fileSpecs["streams"][strmIdx]["channels"] = 1;
}else{
fileSpecs["streams"][strmIdx]["channels"] = tmp.substr(curPos, tmp.find(",", curPos) - curPos);
}
curPos = tmp.find(",", curPos) + 2;
fileSpecs["streams"][strmIdx]["samplewidth"] = tmp.substr(curPos, tmp.find(",", curPos) - curPos);
curPos = tmp.find(",", curPos) + 2;
fileSpecs["streams"][strmIdx]["bps"] = atoi(tmp.substr(curPos, tmp.find(" ", curPos) - curPos).c_str()) * 128;
fileSpecs["streams"][strmIdx].removeMember( "type" );
fileSpecs["audio"] = fileSpecs["streams"][strmIdx];
}
}
}
fclose( outFile );
fileSpecs.removeMember( "streams" );
} else {
fileSpecs["format"] = "dtsc";
JSON::Value tracks = fileSpecs["tracks"];
for(JSON::ObjIter trackIt = tracks.ObjBegin(); trackIt != tracks.ObjEnd(); trackIt++){
fileSpecs["tracks"][trackIt->first].removeMember("fragments");
fileSpecs["tracks"][trackIt->first].removeMember("keys");
fileSpecs["tracks"][trackIt->first].removeMember("keysizes");
fileSpecs["tracks"][trackIt->first].removeMember("parts");
fileSpecs["tracks"][trackIt->first].removeMember("ivecs");/*LTS*/
}
}
printf( "%s", fileSpecs.toString().c_str() );
return 0;
}
}
int main(int argc, char* argv[]) {
return Info::getInfo(argc, argv);
}

View file

@ -18,21 +18,16 @@
///\brief Holds everything unique to the controller.
namespace Controller {
static std::map<long long, std::string> currentConnectors; ///<The currently running connectors.
static inline std::string toConn(long long i){
return std::string("Conn") + JSON::Value(i).asString();
}
static std::map<std::string, pid_t> currentConnectors; ///<The currently running connectors.
///\brief Checks if the binary mentioned in the protocol argument is currently active, if so, restarts it.
///\param protocol The protocol to check.
void UpdateProtocol(std::string protocol){
std::map<long long, std::string>::iterator iter;
std::map<std::string, pid_t>::iterator iter;
for (iter = currentConnectors.begin(); iter != currentConnectors.end(); iter++){
if (iter->second.substr(0, protocol.size()) == protocol){
Log("CONF", "Killing connector for update: " + iter->second);
Util::Procs::Stop(toConn(iter->first));
if (iter->first.substr(0, protocol.size()) == protocol){
Log("CONF", "Killing connector for update: " + iter->first);
Util::Procs::Stop(iter->second);
}
}
}
@ -65,7 +60,8 @@ namespace Controller {
}
}
static inline void buildPipedArguments(JSON::Value & p, char * argarr[], JSON::Value & capabilities){
static inline void buildPipedArguments(const std::string & proto, char * argarr[], JSON::Value & capabilities){
JSON::Value p = JSON::fromString(proto);
int argnum = 0;
static std::string tmparg;
tmparg = Util::getMyPath() + std::string("MistOut") + p["connector"].asStringRef();
@ -82,12 +78,11 @@ namespace Controller {
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
}
///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary.
///\brief Checks current protocol configuration, updates state of enabled connectors if neccessary.
///\param p An object containing all protocols.
///\param capabilities An object containing the detected capabilities.
void CheckProtocols(JSON::Value & p, JSON::Value & capabilities){
std::map<long long, std::string> new_connectors;
std::map<long long, std::string>::iterator iter;
std::set<std::string> runningConns;
// used for building args
int zero = 0;
@ -102,12 +97,13 @@ namespace Controller {
for (JSON::ArrIter ait = p.ArrBegin(); ait != p.ArrEnd(); ait++){
counter = ait - p.ArrBegin();
std::string prevOnline = ( *ait)["online"].asString();
#define connName (*ait)["connector"].asStringRef()
const std::string & connName = (*ait)["connector"].asStringRef();
//do not further parse if there's no connector name
if ( !(*ait).isMember("connector") || connName == ""){
( *ait)["online"] = "Missing connector name";
continue;
}
//ignore connectors that are not installed
if ( !capabilities["connectors"].isMember(connName)){
( *ait)["online"] = "Not installed";
if (( *ait)["online"].asString() != prevOnline){
@ -115,14 +111,13 @@ namespace Controller {
}
continue;
}
#define connCapa capabilities["connectors"][connName]
//list connectors that go through HTTP as 'enabled' without actually running them.
JSON::Value & connCapa = capabilities["connectors"][connName];
if (connCapa.isMember("socket") || (connCapa.isMember("deps") && connCapa["deps"].asStringRef() == "HTTP")){
( *ait)["online"] = "Enabled";
continue;
}
//check required parameters, skip if anything is missing
if (connCapa.isMember("required")){
bool gotAll = true;
for (JSON::ObjIter it = connCapa["required"].ObjBegin(); it != connCapa["required"].ObjEnd(); ++it){
@ -137,12 +132,13 @@ namespace Controller {
}
if (!gotAll){continue;}
}
//remove current online status
( *ait).removeMember("online");
/// \todo Check dependencies?
new_connectors[counter] = (*ait).toString();
if (Util::Procs::isActive(toConn(counter))){
//set current online status
std::string myCmd = (*ait).toString();
runningConns.insert(myCmd);
if (currentConnectors.count(myCmd) && Util::Procs::isActive(currentConnectors[myCmd])){
( *ait)["online"] = 1;
}else{
( *ait)["online"] = 0;
@ -150,28 +146,28 @@ namespace Controller {
}
//shut down deleted/changed connectors
for (iter = currentConnectors.begin(); iter != currentConnectors.end(); iter++){
if (new_connectors.count(iter->first) != 1 || new_connectors[iter->first] != iter->second){
Log("CONF", "Stopping connector " + iter->second);
Util::Procs::Stop(toConn(iter->first));
std::map<std::string, pid_t>::iterator it;
for (it = currentConnectors.begin(); it != currentConnectors.end(); it++){
if (!runningConns.count(it->first)){
Log("CONF", "Stopping connector " + it->first);
Util::Procs::Stop(it->second);
}
}
//start up new/changed connectors
for (iter = new_connectors.begin(); iter != new_connectors.end(); iter++){
if (currentConnectors.count(iter->first) != 1 || currentConnectors[iter->first] != iter->second || !Util::Procs::isActive(toConn(iter->first))){
Log("CONF", "Starting connector: " + iter->second);
while (runningConns.size() && conf.is_active){
if (!currentConnectors.count(*runningConns.begin()) || !Util::Procs::isActive(currentConnectors[*runningConns.begin()])){
Log("CONF", "Starting connector: " + *runningConns.begin());
// clear out old args
for (i=0; i<15; i++){argarr[i] = 0;}
// get args for this connector
buildPipedArguments(p[(long long unsigned)iter->first], (char **)&argarr, capabilities);
buildPipedArguments(*runningConns.begin(), (char **)&argarr, capabilities);
// start piped w/ generated args
Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err);//redirects output to out. Must make a new pipe, redirect std err
currentConnectors[*runningConns.begin()] = Util::Procs::StartPiped(argarr, &zero, &out, &err);
}
runningConns.erase(runningConns.begin());
}
//store new state
currentConnectors = new_connectors;
}
}

View file

@ -130,60 +130,35 @@ namespace Controller {
// if the file isn't dtsc and there's no dtsh file, run getStream on it
// this guarantees that if the stream is playable, it now has a valid header.
DEBUG_MSG(DLVL_INSANE, "(re)loading metadata for stream %s", name.c_str());
if ((URL.substr(URL.size() - 5) != ".dtsc") && (stat((URL+".dtsh").c_str(), &fileinfo) != 0)){
DEBUG_MSG(DLVL_INSANE, "Stream %s is non-DTSC file without DTSH. Opening stream to generate DTSH...", name.c_str());
Util::startInput(name);
DEBUG_MSG(DLVL_INSANE, "Waiting for stream %s to open...", name.c_str());
//wait for the stream
{
char streamPageName[NAME_BUFFER_SIZE];
snprintf(streamPageName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, name.c_str());
IPC::sharedPage streamIndex(streamPageName, DEFAULT_META_PAGE_SIZE, false, false);
if (!streamIndex.mapped){
DEBUG_MSG(DLVL_INSANE, "Stream %s opening failed! Cancelling and marking as corrupt.", name.c_str());
data["meta"].null();
data["meta"]["tracks"].null();
data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
}
data["online"] = 0;
return;
Util::startInput(name);
DEBUG_MSG(DLVL_INSANE, "Waiting for stream %s to open...", name.c_str());
//wait for the stream
{
char streamPageName[NAME_BUFFER_SIZE];
snprintf(streamPageName, NAME_BUFFER_SIZE, SHM_STREAM_INDEX, name.c_str());
IPC::sharedPage streamIndex(streamPageName, DEFAULT_META_PAGE_SIZE, false, false);
if (!streamIndex.mapped){
DEBUG_MSG(DLVL_INSANE, "Stream %s opening failed! Cancelling and marking as corrupt.", name.c_str());
data["meta"].null();
data["meta"]["tracks"].null();
data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
}
unsigned int i = 0;
JSON::fromDTMI((const unsigned char*)streamIndex.mapped + 8, streamIndex.len - 8, i, data["meta"]);
if (data["meta"].isMember("tracks") && data["meta"]["tracks"].size()){
for(JSON::ObjIter trackIt = data["meta"]["tracks"].ObjBegin(); trackIt != data["meta"]["tracks"].ObjEnd(); trackIt++){
trackIt->second.removeMember("fragments");
trackIt->second.removeMember("keys");
trackIt->second.removeMember("keysizes");
trackIt->second.removeMember("parts");
trackIt->second.removeMember("ivecs");/*LTS*/
}
}
if ( !data["meta"] || !data["meta"].isMember("tracks") || !data["meta"]["tracks"]){
data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
}
data["online"] = 0;
return;
}
DEBUG_MSG(DLVL_INSANE, "Metadata for stream %s (re)loaded", name.c_str());
data["online"] = 0;
return;
}
DEBUG_MSG(DLVL_INSANE, "Stream %s opened", name.c_str());
}else{
//now, run mistinfo on the source - or on the accompanying dtsh file, if it exists
if (stat((URL+".dtsh").c_str(), &fileinfo) == 0){
DEBUG_MSG(DLVL_INSANE, "Stream %s has a DTSH - opening DTSH instead of main stream file", name.c_str());
URL += ".dtsh";
unsigned int i = 0;
JSON::fromDTMI((const unsigned char*)streamIndex.mapped + 8, streamIndex.len - 8, i, data["meta"]);
if (data["meta"].isMember("tracks") && data["meta"]["tracks"].size()){
for(JSON::ObjIter trackIt = data["meta"]["tracks"].ObjBegin(); trackIt != data["meta"]["tracks"].ObjEnd(); trackIt++){
trackIt->second.removeMember("fragments");
trackIt->second.removeMember("keys");
trackIt->second.removeMember("keysizes");
trackIt->second.removeMember("parts");
trackIt->second.removeMember("ivecs");
}
}
char * tmp_cmd[3] = {0, 0, 0};
std::string mistinfo = Util::getMyPath() + "MistInfo";
tmp_cmd[0] = (char*)mistinfo.c_str();
tmp_cmd[1] = (char*)URL.c_str();
DEBUG_MSG(DLVL_INSANE, "Running MistInfo for stream %s on file %s", name.c_str(), tmp_cmd[1]);
data["meta"] = JSON::fromString(Util::Procs::getOutputOf(tmp_cmd));
if ( !data["meta"] || !data["meta"].isMember("tracks") || !data["meta"]["tracks"]){
data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
@ -192,8 +167,9 @@ namespace Controller {
data["online"] = 0;
return;
}
DEBUG_MSG(DLVL_INSANE, "Metadata for stream %s succesfully (re)loaded", name.c_str());
DEBUG_MSG(DLVL_INSANE, "Metadata for stream %s (re)loaded", name.c_str());
}
DEBUG_MSG(DLVL_INSANE, "Stream %s opened", name.c_str());
}
if (!hasViewers(name)){
if ( !data.isMember("error")){