LTS Commits

This commit is contained in:
Thulinma 2015-04-05 21:38:36 +02:00
parent f24d97b510
commit 4bdbd82f66
72 changed files with 8245 additions and 105 deletions

View file

@ -96,6 +96,7 @@ namespace Info {
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() );

View file

@ -9,6 +9,7 @@
#include <string.h>
#include <mist/mp4.h>
#include <mist/config.h>
#include <mist/defines.h>
///\brief Holds everything unique to the analysers.
namespace Analysers {
@ -25,9 +26,15 @@ namespace Analysers {
mp4Buffer.erase(mp4Buffer.size() - 1, 1);
MP4::Box mp4Data;
int dataSize = mp4Buffer.size();
int curPos = 0;
while (mp4Data.read(mp4Buffer)){
DEBUG_MSG(DLVL_DEVEL, "Read a box at position %d", curPos);
std::cerr << mp4Data.toPrettyString(0) << std::endl;
curPos += dataSize - mp4Buffer.size();
dataSize = mp4Buffer.size();
}
DEBUG_MSG(DLVL_DEVEL, "Stopped parsing at position %d", curPos);
return 0;
}
}

View file

@ -0,0 +1,209 @@
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <string.h>
#include <vector>
#include <sstream>
#include <mist/socket.h>
#include <mist/config.h>
#include <mist/rtp.h>
#include <mist/http_parser.h>
//rtsp://krabs:1935/vod/gear1.mp4
namespace Analysers {
int analyseRTP(){
Socket::Connection conn("localhost", 554, true);
//Socket::Connection conn("krabs", 1935, true);
HTTP::Parser HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.
int step = 0;
/*1 = sent describe
2 = recd describe
3 = sent setup
4 = received setup
5 = sent play"*/
std::vector<std::string> tracks;
std::vector<Socket::UDPConnection> connections;
unsigned int trackIt = 0;
while (conn.connected()){
// std::cerr << "loopy" << std::endl;
if(step == 0){
HTTP_S.protocol = "RTSP/1.0";
HTTP_S.method = "DESCRIBE";
//rtsp://krabs:1935/vod/gear1.mp4
//rtsp://localhost/g1
HTTP_S.url = "rtsp://localhost/steers";
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("CSeq",1);
HTTP_S.SendRequest(conn);
step++;
}else if(step == 2){
std::cerr <<"setup " << tracks[trackIt] << std::endl;
HTTP_S.method = "SETUP";
HTTP_S.url = "rtsp://localhost/steers/" + tracks[trackIt];
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4/" + tracks[trackIt];
HTTP_S.SetHeader("CSeq",2+trackIt);
std::stringstream ss;
ss << "RTP/steersVP;unicast;client_port="<< 20000 + 2*trackIt<<"-"<< 20001 + 2*trackIt;
HTTP_S.SetHeader("Transport",ss.str());//make client ports, 4200 + 2*offset
trackIt++;
step++;
HTTP_S.SendRequest(conn);
std::cerr << "step " << step << "/\\"<< ss.str()<<std::endl;
}else if(step == 4){
std::cerr << "Play!!!1" << std::endl;
HTTP_S.method = "PLAY";
HTTP_S.url = "rtsp://localhost/steers";
//HTTP_S.url = "rtsp://krabs:1935/vod/steers.mp4";
HTTP_S.SetHeader("Range","npt=0.000-");
HTTP_S.SendRequest(conn);
step++;
std::cerr << "step for play.." << step << std::endl;
}
if (conn.Received().size() || conn.spool()){
if (HTTP_R.Read(conn)){
if(step == 1){
std::cerr << "recvd desc" << std::endl;
for(size_t ml = HTTP_R.body.find("a=control:",HTTP_R.body.find("m=")); ml != std::string::npos; ml = HTTP_R.body.find("a=control:",ml+1)){
std::cerr << "found trekk" << std::endl;
tracks.push_back(HTTP_R.body.substr(ml+10,HTTP_R.body.find_first_of("\r\n",ml)-(ml+10)));
connections.push_back(Socket::UDPConnection());
}
for(unsigned int x = 0; x < connections.size();x++){
connections[x].SetDestination("127.0.0.1",666);
connections[x].bind(20000+2*x);
connections[x].setBlocking(true);
}
step++;
}else if(step == 3){
std::cerr << "recvd setup" << std::endl;
std::cerr << "trackIt: " << trackIt << " size " << tracks.size() << std::endl;
if(trackIt < tracks.size())
step--;
else
step++;
std::cerr << HTTP_R.GetHeader("Transport");
}
HTTP_R.Clean();
}
}//!
if(step == 5){
for(unsigned int cx = 0; cx < connections.size(); cx++){
// std::cerr <<"PLAY MF" << std::endl;
if(connections[cx].Receive()){
RTP::Packet* pakketje = new RTP::Packet(connections[cx].data, connections[cx].data_len);
/*std::cout << "Version = " << pakketje->getVersion() << std::endl;
std::cout << "Padding = " << pakketje->getPadding() << std::endl;
std::cout << "Extension = " << pakketje->getExtension() << std::endl;
std::cout << "Contributing sources = " << pakketje->getContribCount() << std::endl;
std::cout << "Marker = " << pakketje->getMarker() << std::endl;
std::cout << "Payload Type = " << pakketje->getPayloadType() << std::endl;
std::cout << "Sequence = " << pakketje->getSequence() << std::endl;
std::cout << "Timestamp = " << pakketje->getTimeStamp() << std::endl;
std::cout << "SSRC = " << pakketje->getSSRC() << std::endl;
std::cout << "datalen: " << connections[cx].data_len << std::endl;
std::cout << "payload:" << std::endl;*/
if(pakketje->getPayloadType() == 97){
int h264type = (int)(connections[cx].data[12] & 0x1f);
std::cout << h264type << " - ";
if(h264type == 0){
std::cout << "unspecified - ";
}else if(h264type == 1){
std::cout << "Coded slice of a non-IDR picture - ";
}else if(h264type == 2){
std::cout << "Coded slice data partition A - ";
}else if(h264type == 3){
std::cout << "Coded slice data partition B - ";
}else if(h264type == 4){
std::cout << "Coded slice data partition C - ";
}else if(h264type == 5){
std::cout << "Coded slice of an IDR picture - ";
}else if(h264type == 6){
std::cout << "Supplemental enhancement information (SEI) - ";
}else if(h264type == 7){
std::cout << "Sequence parameter set - ";
}else if(h264type == 8){
std::cout << "Picture parameter set - ";
}else if(h264type == 9){
std::cout << "Access unit delimiter - ";
}else if(h264type == 10){
std::cout << "End of sequence - ";
}else if(h264type == 11){
std::cout << "End of stream - ";
}else if(h264type == 12){
std::cout << "Filler data - ";
}else if(h264type == 13){
std::cout << "Sequence parameter set extension - ";
}else if(h264type == 14){
std::cout << "Prefix NAL unit - ";
}else if(h264type == 15){
std::cout << "Subset sequence parameter set - ";
}else if(h264type == 16){
std::cout << "Reserved - ";
}else if(h264type == 17){
std::cout << "Reserved - ";
}else if(h264type == 18){
std::cout << "Reserved - ";
}else if(h264type == 19){
std::cout << "Coded slice of an auxiliary coded picture without partitioning - ";
}else if(h264type == 20){
std::cout << "Coded slice extension - ";
}else if(h264type == 21){
std::cout << "Reserved - ";
}else if(h264type == 22){
std::cout << "Reserved - ";
}else if(h264type == 23){
std::cout << "Reserved - ";
}else if(h264type == 24){
std::cout << "stap a - ";
}else if(h264type == 25){
std::cout << "stap b - ";
}else if(h264type == 26){
std::cout << "mtap16 - ";
}else if(h264type == 27){
std::cout << "mtap24 - ";
}else if(h264type == 28){
std::cout << "fu a - ";
}else if(h264type == 29){
std::cout << "fu b - ";
}else if(h264type == 30){
std::cout << "Unspecified - ";
}else if(h264type == 31){
std::cout << "Unspecified - ";
}
for(unsigned int i = 13 ; i < connections[cx].data_len;i++){
std::cout << std::hex <<std::setw(2) << std::setfill('0') << (int)connections[cx].data[i]<< std::dec;
}
std::cout << std::endl<<std::endl;
}
delete pakketje;
}
}
}
}
return 666;
}
}
int main(int argc, char ** argv){
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
conf.parseArgs(argc, argv);
return Analysers::analyseRTP();
}

View file

@ -0,0 +1,197 @@
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <vector>
#include <mist/config.h>
#include <mist/rtp.h>
#include <mist/socket.h>
#include <mist/http_parser.h>
#include <sstream>
namespace RtspRtp{
int analyseRtspRtp(std::string rtspUrl){
/*//parse hostname
std::string hostname = rtspUrl.substr(7);
hostname = hostname.substr(0,hostname.find('/'));
std::cout << hostname << std::endl;
HTTP::Parser HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.
Socket::Connection conn(hostname,554,false);//setting rtsp connection
bool optionsSent = false;
bool optionsRecvd = false;
bool descSent = false;
bool descRecvd = false;
bool setupComplete = false;
bool playSent = false;
int CSeq = 1;
while(conn.connected()){
if(!optionsSent){
HTTP_R.protocol="RTSP/1.0";
HTTP_R.method = "OPTIONS";
HTTP_R.url = rtspUrl;
HTTP_R.SetHeader("CSeq",CSeq);
CSeq++;
HTTP_R.SetHeader("User-Agent","mistANALyser");
HTTP_R.SendRequest(conn);
optionsSent = true;
}
if (optionsSent&& !optionsRecvd && (conn.Received().size() || conn.spool() )){
if(HTTP_S.Read(conn)){
std::cout << "recv opts" << std::endl;
std::cout << HTTP_S.BuildResponse(HTTP_S.method,HTTP_S.url);
optionsRecvd = true;
}
}
if(optionsRecvd && !descSent){
HTTP_S.Clean();
HTTP_R.protocol="RTSP/1.0";
HTTP_R.method = "DESCRIBE";
HTTP_R.url = rtspUrl;
HTTP_R.SetHeader("CSeq",CSeq);
CSeq++;
HTTP_R.SetHeader("User-Agent","mistANALyser");
HTTP_R.SendRequest(conn);
descSent = true;
}
std::vector<std::string> trackIds;
if (descSent&&!descRecvd && (conn.Received().size() || conn.spool() )){
if(HTTP_S.Read(conn)){
std::cout << "recv desc2" << std::endl;
std::cout << HTTP_S.BuildResponse(HTTP_S.method,HTTP_S.url);
size_t pos = HTTP_S.body.find("m=");
do{
//finding all track IDs
pos = HTTP_S.body.find("a=control:",pos);
if(pos !=std::string::npos){
trackIds.push_back(HTTP_S.body.substr(pos+10,HTTP_S.body.find("\r\n",pos)-pos-10 ) );//setting track IDs;
pos++;
}
}while(pos != std::string::npos);
//we have all the tracks
descRecvd = true;
}
}
unsigned int setupsSent = 0;
unsigned int setupsRecvd = 0;
Socket::UDPConnection connectors[trackIds.size()];
unsigned int setports[trackIds.size()];
uint32_t bport = 10000;
std::string sessionID = "";
std::stringstream setup;
if(descRecvd && !setupComplete){
//time to setup.
for(std::vector<std::string>::iterator it = trackIds.begin();it!=trackIds.end();it++){
std::cout << "setup " << setupsSent<< std::endl;
while(!connectors[setupsSent].SetConnection( bport,false) ){
bport +=2;//finding an available port
}
std::cout << "setup" << bport<< std::endl;
setports[setupsSent] = bport;
bport +=2;
if(setupsSent == setupsRecvd){
//send only one setup
HTTP_S.Clean();
HTTP_R.protocol="RTSP/1.0";
HTTP_R.method = "SETUP";
HTTP_R.url = rtspUrl+ '/' + *(it);
setup << "RTP/AVP/UDP;unicast;client_port="<< setports[setupsSent] <<"-" <<setports[setupsSent]+1 ;
HTTP_R.SetHeader("Transport",setup.str() );
std:: cout << setup.str()<<std::endl;
setup.str(std::string());
setup.clear();
HTTP_R.SetHeader("CSeq",CSeq);
CSeq++;
if(sessionID != ""){
HTTP_R.SetHeader("Session",sessionID);
}
HTTP_R.SetHeader("User-Agent","mistANALyser");
HTTP_R.SendRequest(conn);
setupsSent ++;
}
while(setupsSent == setupsRecvd+1){
//lets Assume we assume we always receive a response
if ( (conn.Received().size() || conn.spool() )){
if(HTTP_S.Read(conn)){
std::cout << "recv setup" << std::endl;
std::cout << HTTP_S.BuildResponse(HTTP_S.method,HTTP_S.url);
optionsRecvd = true;
sessionID = HTTP_S.GetHeader("Session");
setupsRecvd++;
}
}
}
//set up all parameters, and then after the for loop we have to listen to setups and all. sent if both are equal, and recv if one is sent
}
setupComplete = true;
}
if(setupComplete && !playSent){
//time to play
HTTP_S.Clean();
HTTP_R.protocol="RTSP/1.0";
HTTP_R.method = "PLAY";
HTTP_R.url = rtspUrl;
HTTP_R.SetHeader("CSeq",CSeq);
CSeq++;
HTTP_R.SetHeader("User-Agent","mistANALyser");
HTTP_R.SetHeader("Session",sessionID);
HTTP_R.SendRequest(conn);
playSent = true;
std::cout << "sent play" << std::endl;
char buffer[2000];
while(!connectors[0].iread((void*)buffer,2000)) {
std::cout << "buffer";
}
std::cout <<"buffer is not empty" << std::endl;
}
//streams set up
//time to read some packets
if(descRecvd){
conn.close();
}
}
conn.close();*/
return 0;
}
}
int main(int argc, char ** argv){
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
conf.addOption("url",JSON::fromString("{\"arg\":\"string\",\"short\":\"u\",\"long\":\"url\",\"help\":\"URL To get.\", \"default\":\"rtsp://localhost/s1k\"}"));
conf.parseArgs(argc, argv);
return RtspRtp::analyseRtspRtp(conf.getString("url"));
}

View file

@ -0,0 +1,84 @@
/// \file stats_analyser.cpp
/// Will emulate a given amount of clients in the statistics.
#include <stdlib.h>
#include <mist/dtsc.h>
#include <mist/json.h>
#include <mist/shared_memory.h>
#include <mist/config.h>
#include <mist/defines.h>
/// Will emulate a given amount of clients in the statistics.
int main(int argc, char ** argv){
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
conf.addOption("clients", JSON::fromString("{\"arg\":\"num\", \"short\":\"c\", \"long\":\"clients\", \"default\":1000, \"help\":\"Amount of clients to emulate.\"}"));
conf.addOption("stream", JSON::fromString("{\"arg\":\"string\", \"short\":\"s\", \"long\":\"stream\", \"default\":\"test\", \"help\":\"Streamname to pretend to request.\"}"));
conf.addOption("up", JSON::fromString("{\"arg\":\"string\", \"short\":\"u\", \"long\":\"up\", \"default\":131072, \"help\":\"Bytes per second upstream.\"}"));
conf.addOption("down", JSON::fromString("{\"arg\":\"string\", \"short\":\"d\", \"long\":\"down\", \"default\":13000, \"help\":\"Bytes per second downstream.\"}"));
conf.addOption("sine", JSON::fromString("{\"arg\":\"string\", \"short\":\"S\", \"long\":\"sine\", \"default\":0, \"help\":\"Bytes per second variance in a sine pattern.\"}"));
conf.addOption("userscale", JSON::fromString("{\"arg\":\"string\", \"short\":\"U\", \"long\":\"userscale\", \"default\":0, \"help\":\"If != 0, scales users from 0% to 100% bandwidth.\"}"));
conf.parseArgs(argc, argv);
std::string streamName = conf.getString("stream");
long long clientCount = conf.getInteger("clients");
long long up = conf.getInteger("up");
long long down = conf.getInteger("down");
long long sine = conf.getInteger("sine");
long long scale = conf.getInteger("userscale");
long long currsine = sine;
long long goingUp = 0;
IPC::sharedClient ** clients = (IPC::sharedClient **)malloc(sizeof(IPC::sharedClient *)*clientCount);
for (long long i = 0; i < clientCount; i++){
clients[i] = new IPC::sharedClient("statistics", STAT_EX_SIZE, true);
}
unsigned long long int counter = 0;
conf.activate();
while (conf.is_active){
unsigned long long int now = Util::epoch();
counter++;
if (sine){
currsine += goingUp;
if (currsine < -down || currsine < -up){
currsine = std::max(-down, -up);
}
if (currsine > 0){
goingUp -= sine/100 + 1;
}else{
goingUp += sine/100 + 1;
}
}
for (long long i = 0; i < clientCount; i++){
if (clients[i]->getData()){
IPC::statExchange tmpEx(clients[i]->getData());
tmpEx.now(now);
tmpEx.host("::42");
tmpEx.crc(i);
tmpEx.streamName(streamName);
tmpEx.connector("TEST");
if (scale){
tmpEx.up(tmpEx.up() + (up+currsine)*i/clientCount);
tmpEx.down(tmpEx.down() + (down+currsine)*i/clientCount);
}else{
tmpEx.up(tmpEx.up()+up+currsine);
tmpEx.down(tmpEx.down()+down+currsine);
}
tmpEx.time(counter);
tmpEx.lastSecond(counter * 1000);
clients[i]->keepAlive();
}
}
Util::wait(1000);
}
for (long long i = 0; i < clientCount; i++){
clients[i]->finish();
delete clients[i];
}
free(clients);
return 0;
}

189
src/analysers/ts_analyser.cpp Executable file
View file

@ -0,0 +1,189 @@
#include <fcntl.h>
#include <iostream>
#include <map>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <string.h>
#include <fstream>
#include <unistd.h>
#include <sstream>
#include <signal.h>
#include <mist/ts_packet.h>
#include <mist/config.h>
namespace Analysers {
std::string printPES(const std::string & d, unsigned long PID, int detailLevel){
unsigned int headSize = 0;
std::stringstream res;
bool known = false;
res << "[PES " << PID << "]";
if ((d[3] & 0xF0) == 0xE0){
res << " [Video " << (int)(d[3] & 0xF) << "]";
known = true;
}
if (!known && (d[3] & 0xE0) == 0xC0){
res << " [Audio " << (int)(d[3] & 0x1F) << "]";
known = true;
}
if (!known){
res << " [Unknown stream ID]";
}
if (d[0] != 0 || d[1] != 0 || d[2] != 1){
res << " [!INVALID START CODE!]";
}
if (known){
if ((d[6] & 0xC0) != 0x80){
res << " [!INVALID FIRST BITS!]";
}
if (d[6] & 0x30){
res << " [SCRAMBLED]";
}
if (d[6] & 0x08){
res << " [Priority]";
}
if (d[6] & 0x04){
res << " [Aligned]";
}
if (d[6] & 0x02){
res << " [Copyrighted]";
}
if (d[6] & 0x01){
res << " [Original]";
}else{
res << " [Copy]";
}
if (d[7] & 0x20){
res << " [ESCR present, not decoded!]";
headSize += 6;
}
if (d[7] & 0x10){
res << " [ESR present, not decoded!]";
headSize += 3;
}
if (d[7] & 0x08){
res << " [Trick mode present, not decoded!]";
headSize += 1;
}
if (d[7] & 0x04){
res << " [Add. copy present, not decoded!]";
headSize += 1;
}
if (d[7] & 0x02){
res << " [CRC present, not decoded!]";
headSize += 2;
}
if (d[7] & 0x01){
res << " [Extension present, not decoded!]";
headSize += 0; /// \todo Implement this. Complicated field, bah.
}
int timeFlags = ((d[7] & 0xC0) >> 6);
if (timeFlags == 2){
headSize += 5;
}
if (timeFlags == 3){
headSize += 10;
}
if (d[8] != headSize){
res << " [Padding: " << ((int)d[8] - headSize) << "b]";
}
if (timeFlags & 0x02){
long long unsigned int time = (((unsigned int)d[9] & 0xE) >> 1);
time <<= 15;
time |= ((unsigned int)d[10] << 7) | (((unsigned int)d[11] >> 1) & 0x7F);
time <<= 15;
time |= ((unsigned int)d[12] << 7) | (((unsigned int)d[13] >> 1) & 0x7F);
res << " [PTS " << ((double)time / 90000) << "s]";
}
if (timeFlags & 0x01){
long long unsigned int time = ((d[14] >> 1) & 0x07);
time <<= 15;
time |= ((int)d[15] << 7) | (d[16] >> 1);
time <<= 15;
time |= ((int)d[17] << 7) | (d[18] >> 1);
res << " [DTS " << ((double)time/90000) << "s]";
}
}
if ((((int)d[4]) << 8 | d[5]) != (d.size() - 6)){
res << " [Size " << (((int)d[4]) << 8 | d[5]) << " => " << (d.size() - 6) << "]";
}
res << std::endl;
if(detailLevel==1){
unsigned int counter = 0;
for (unsigned int i = 9+headSize; i<d.size(); ++i){
if ((i < d.size() - 4) && d[i] == 0 && d[i+1] == 0 && d[i+2] == 0 && d[i+3] == 1){res << std::endl; counter = 0;}
res << std::hex << std::setw(2) << std::setfill('0') << (int)(d[i]&0xff) << " ";
counter++;
if ((counter) % 32 == 31){res << std::endl;}
}
res << std::endl;
}
return res.str();
}
/// Debugging tool for TS data.
/// Expects TS data through stdin, outputs human-readable information to stderr.
/// \return The return code of the analyser.
int analyseTS(bool validate, bool analyse, int detailLevel){
std::map<unsigned long long, std::string> payloads;
TS::Packet packet;
long long int upTime = Util::bootSecs();
int64_t pcr = 0;
unsigned int bytes = 0;
char packetPtr[188];
while (std::cin.good()){
std::cin.read(packetPtr,188);
if(std::cin.gcount() != 188){break;}
bytes += 188;
if(packet.FromPointer(packetPtr)){
if(analyse){
if (packet.getUnitStart() && payloads[packet.getPID()] != ""){
std::cout << printPES(payloads[packet.getPID()], packet.getPID(), detailLevel);
payloads.erase(packet.getPID());
}
if (detailLevel < 2){
std::stringstream nul;
nul << packet.toPrettyString(0, detailLevel);
}else{
std::cout << packet.toPrettyString(0, detailLevel);
}
if (packet.getPID() && !packet.isPMT()){
payloads[packet.getPID()].append(packet.getPayload(), packet.getPayloadLength());
}
}
if(packet && packet.getAdaptationField() > 1 && packet.hasPCR()){pcr = packet.getPCR();}
}
if(bytes > 1024){
long long int tTime = Util::bootSecs();
if(validate && tTime - upTime > 5 && tTime - upTime > pcr/27000000){
std::cerr << "data received too slowly" << std::endl;
return 1;
}
bytes = 0;
}
}
for (std::map<unsigned long long, std::string>::iterator it = payloads.begin(); it != payloads.end(); it++){
if (!it->first || it->first == 4096){ continue; }
std::cout << printPES(it->second, it->first, detailLevel);
}
long long int finTime = Util::bootSecs();
if(validate){
fprintf(stdout,"time since boot,time at completion,real time duration of data receival,video duration\n");
fprintf(stdout, "%lli000,%lli000,%lli000,%li \n",upTime,finTime,finTime-upTime,pcr/27000);
}
return 0;
}
}
int main(int argc, char ** argv){
Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
conf.addOption("analyse", JSON::fromString("{\"long\":\"analyse\", \"short\":\"a\", \"default\":1, \"long_off\":\"notanalyse\", \"short_off\":\"b\", \"help\":\"Analyse a file's contents (-a), or don't (-b) returning false on error. Default is analyse.\"}"));
conf.addOption("validate", JSON::fromString("{\"long\":\"validate\", \"short\":\"V\", \"default\":0, \"long_off\":\"notvalidate\", \"short_off\":\"X\", \"help\":\"Validate (-V) the file contents or don't validate (-X) its integrity, returning false on error. Default is don't validate.\"}"));
conf.addOption("detail", JSON::fromString("{\"long\":\"detail\", \"short\":\"D\", \"arg\":\"num\", \"default\":3, \"help\":\"Detail level of analysis.\"}"));
conf.parseArgs(argc, argv);
return Analysers::analyseTS(conf.getBool("validate"),conf.getBool("analyse"),conf.getInteger("detail"));
}