#include "rotor.h" using namespace Rotor; void Render_context::runTask() { while (!isCancelled()) { int cmd=0; mutex.lock(); if (work_queue.size()){ cmd=work_queue[0]; work_queue.pop_front(); } mutex.unlock(); if(cmd==ANALYSE_AUDIO) { state=ANALYSING_AUDIO; vector processors; processors.push_back(audio_thumb); vector analysers=graph.find_nodes("audio_analysis"); for (auto a: analysers) { processors.push_back(dynamic_cast(a)); } if (load_audio(audio_filename,processors)) { audio_loaded=true; state=IDLE; } else { //an error occurred: TODO have to clean up allocated data. autoptr? audio_loaded=false; state=IDLE; } } if(cmd==RENDER) { state=RENDERING; if(graph.video_render(output_filename,audio_filename,output_framerate,progress)){ state=IDLE; } else { //an error occurred: TODO have to clean up allocated data. autoptr? cerr<<"Rotor: render failed"<& command,xmlIO& XML,HTTPResponse::HTTPStatus& status){ status=HTTPResponse::HTTP_BAD_REQUEST; //error by default if (command[2]=="resolution") { if (command[0]=="PUT") { if (command.size()>2) { if (state==IDLE) { Poco::StringTokenizer t1(command[3],","); if (t1.count()>1){ int w=ofToInt(t1[0]); int h=ofToInt(t1[1]); if (graph.set_resolution(w,h)){ XML.addValue("status","resolution set to "+t1[0]+"x"+t1[1]); status=HTTPResponse::HTTP_OK; } else { XML.addValue("error","invalid resolution request: "+t1[0]+"x"+t1[1]); } } } else { XML.addValue("error","session busy"); } } } } if (command[2]=="audio") { if (command[0]=="PUT") { //get audio file location and initiate analysis if (command.size()>2) { if (state==IDLE) { audio_filename=media_dir+command[3]; //for now, store session variables in memory //check file exists Poco::File f=Poco::File(audio_filename); if (f.exists()) { //pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read?? add_queue(ANALYSE_AUDIO); status=HTTPResponse::HTTP_OK; XML.addValue("status","Starting audio analysis: "+command[3]); } else { status=HTTPResponse::HTTP_NOT_FOUND; XML.addValue("error",command[3]+" not found"); } } else { XML.addValue("error","Session busy"); } } } if (command[0]=="GET") { if (state==ANALYSING_AUDIO) { status=HTTPResponse::HTTP_OK; XML.addValue("status","Analysing audio"); char c[20]; sprintf(c,"%02f",progress); XML.addValue("progress",string(c)); } else if (audio_loaded) { //not sure about this-- should this state be retained? //can the data only be read once? //for now status=HTTPResponse::HTTP_OK; XML.addValue("status","Audio ready"); XML.addValue("audio",audio_thumb->print()); } else { XML.addValue("error","No audio loaded"); } } if (command[0]=="DELETE") { if (state==IDLE) { audio_filename=""; XML.addValue("status","Audio deleted"); status=HTTPResponse::HTTP_OK; } else { XML.addValue("error","Session busy"); } } } if (command[2]=="graph") { if (command[0]=="GET") { if (graph.loaded) { status=HTTPResponse::HTTP_OK; //XML.addValue("patchbay",graph.toString()); XML.loadFromBuffer(graph.toString()); } else { XML.addValue("error","graph not loaded: check XML"); } } if (command[0]=="PUT") { //get new graph from file if (command.size()>2) { //should interrupt whatever is happening? //before begining to load from xml if (state==IDLE) { //eventually not like this if (graph.load(command[3])) { status=HTTPResponse::HTTP_OK; XML.addValue("status","Loaded graph from PUT body"); } else { string graph_filename=graph_dir+command[3]; Poco::File f=Poco::File(graph_filename); if (f.exists()) { if (graph.loadFile(graph_filename)) { status=HTTPResponse::HTTP_OK; //XML.addValue("patchbay",graph.toString()); //XML.loadFromBuffer(graph.toString()); XML=graph.xml; //the graph could actually contain an xml object and we could just print it here? //or could our nodes even be subclassed from xml nodes? //the graph or the audio could load first- have to analyse the audio with vamp after the graph is loaded //for now the graph must load 1st } else { status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; //~/sources/poco-1.4.6-all/Net/include/Poco/Net/HTTPResponse.h XML.addValue("error","graph not loaded: check XML"); } } else { status=HTTPResponse::HTTP_NOT_FOUND; XML.addValue("error",command[3]+" not found"); } } } } } if (command[0]=="DELETE") { //for now graph=Graph(); XML.addValue("status","graph deleted"); status=HTTPResponse::HTTP_OK; } } if (command[2]=="signal") { if (command[0]=="GET") { //generate xml from 1st signal output if (state==IDLE) { //direct call for testing float framerate=25.0f; if (command.size()>2) { framerate=ofToFloat(command[3]); } string signal_xml; if (graph.signal_render(signal_xml,framerate)){ status=HTTPResponse::HTTP_OK; XML.addValue("signal",signal_xml); } else { status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; XML.addValue("error","could not render output signal"); } } else { status=HTTPResponse::HTTP_NOT_FOUND; XML.addValue("error","Signal output not found in graph"); } } else { status=HTTPResponse::HTTP_SERVICE_UNAVAILABLE; XML.addValue("error","Context busy"); } } if (command[2]=="video") { if (command[0]=="PUT") { //get vide file location and initiate analysis if (command.size()>4) { //there should be a filename + a destination node if (state==IDLE) { string video_filename=media_dir+command[4]; //check file exists Poco::File f=Poco::File(video_filename); if (f.exists()) { if (load_video(command[3],video_filename)) { //pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read?? //DUMMY RESPONSE status=HTTPResponse::HTTP_OK; XML.addValue("status","Succesfully loaded "+command[4]+" into video node "+command[3]); } else { status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; XML.addValue("error","could not load "+command[4]+" into video node "+command[3]); } } else { status=HTTPResponse::HTTP_NOT_FOUND; XML.addValue("error",command[4]+" not found"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; XML.addValue("error","Bad request"); } } } if (command[2]=="render") { if (command[0]=="GET") { if(state==RENDERING){ status=HTTPResponse::HTTP_OK; XML.addValue("status","Rendering video"); XML.addValue("progress",ofToString(progress)); } else { XML.addValue("error","Not rendering"); } } if (command[0]=="PUT") { if (command.size()>2) { if (state==IDLE) { output_filename=output_dir+command[3]; if (command.size()>3) { // output_framerate=ofToFloat(command[4]); } add_queue(RENDER); status=HTTPResponse::HTTP_OK; XML.addValue("status","Starting render: "+command[3]); } else { status=HTTPResponse::HTTP_BAD_REQUEST; XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; XML.addValue("error","No output file specified"); } } if (command[0]=="DELETE") { status=HTTPResponse::HTTP_OK; XML.addValue("status","DUMMY RESPONSE: cancelling render"); } } } bool Render_context::load_audio(const string &filename,vector processors){ cerr<<"Rotor: starting audio analysis"<duration)/AV_TIME_BASE; int rate = loader.codecContext->sample_rate; int samples = ((loader.formatContext->duration + 5000)*rate)/AV_TIME_BASE; //why 5000 more? int channels= loader.codecContext->channels; int bits = loader.codecContext->bits_per_raw_sample; for (auto p: processors) { if(!p->init(channels,bits,samples,rate) ){ cerr<<"Plugin failed to initialse"<process_frame(frame->data[0],frame->nb_samples); } sample_processed+=frame->nb_samples; //mutex.lock(); progress=((float)sample_processed)/samples; //mutex.unlock(); frame=loader.get_frame(); } loader.close(); for (auto p: processors) { p->cleanup(); p->print_summary(); } cerr<<"Rotor: finished audio analysis"<type=="video_loader") { if (((Video_loader*)graph.nodes[nodeID])->load(filename)) { return true; } } } return false; }