#include "rendercontext.h" using namespace Rotor; using Poco::Net::HTTPResponse; using Poco::Logger; void Render_context::runTask() { while (!isCancelled()) { Session_task cmd; mutex.lock(); if (work_queue.size()){ cmd=work_queue[0]; work_queue.pop_front(); graph.cancelled=false; } mutex.unlock(); if(cmd.task==ANALYSE_AUDIO) { state=ANALYSING_AUDIO; vector processors; processors.push_back(graph.audio_thumb); for (auto a: graph.nodes) { if (dynamic_cast(a.second)){ processors.push_back(dynamic_cast(a.second)); } } if (graph.load_audio(graph.audio_filename,processors)) { state=IDLE; } else { //an error occurred: TODO have to clean up allocated data. autoptr? graph.audio_loaded=false; state=IDLE; } } if(cmd.task==RENDER) { state=RENDERING; renders[cmd.uid]=Render_status(RENDERING); if(graph.video_render(output_filename,output_framerate,start,stop)){ state=IDLE; if (graph.cancelled) renders[cmd.uid].status=CANCELLED; else renders[cmd.uid].status=RENDER_READY; } else { //an error occurred: TODO have to clean up allocated data. autoptr? cerr<<"Rotor: render failed"<& command void Render_context::session_command(const Session_command& command,xmlIO& XML,HTTPResponse::HTTPStatus& status){ string s; for (auto c:command.commands){ s+=c; s+=" "; } //cerr<<"uid:"<1){ int w=toInt(t1[0]); int h=toInt(t1[1]); if (graph.set_resolution(w,h)){ logger.information("resolution set to "+t1[0]+"x"+t1[1]); XML.addValue("status","resolution set to "+t1[0]+"x"+t1[1]); status=HTTPResponse::HTTP_OK; } else { logger.error("ERROR: invalid resolution request: "+t1[0]+"x"+t1[1]); XML.addValue("error","invalid resolution request: "+t1[0]+"x"+t1[1]); } } } else { XML.addValue("error","session busy"); } } } } if (command.commands[1]=="bitrate") { if (command.method=="PUT") { int b=toInt(command.body); if (graph.set_bitrate(b)){ logger.information("bitrate set to "+command.body); XML.addValue("status","bitrate set to "+command.body); status=HTTPResponse::HTTP_OK; } else { logger.error("ERROR: Could not set bitrate set to "+command.body); XML.addValue("error","Could not set bitrate set to "+command.body); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } if (command.commands[1]=="fragmentation") { if (command.method=="PUT") { bool f=(toInt(command.body)!=0); if (graph.set_fragmentation(f)){ string fs=f?"on":"off"; logger.information("MP4 fragmentation "+fs); XML.addValue("status","MP4 fragmentation "+fs); status=HTTPResponse::HTTP_OK; } else { logger.error("ERROR: Could not set MP4 fragmentation"); XML.addValue("error","Could not set MP4 fragmentation"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } if (command.commands[1]=="audio") { if (command.method=="PUT") { //get audio file location and initiate analysis if (command.body!="") { if (state==IDLE) { graph.audio_filename=media_dir+command.body; //for now, store session variables in memory //check file exists Poco::File f=Poco::File(graph.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(Session_task(command.uid,ANALYSE_AUDIO)); status=HTTPResponse::HTTP_OK; logger.information("Audio analysis: "+command.body); XML.addValue("status","Starting audio analysis: "+command.body); } else { status=HTTPResponse::HTTP_NOT_FOUND; logger.error("ERROR: audio file "+command.body+" not found"); XML.addValue("error",command.body+" not found"); } } else { logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } } if (command.method=="GET") { if (state==ANALYSING_AUDIO) { status=HTTPResponse::HTTP_OK; XML.addValue("status","Analysing audio"); char c[20]; sprintf(c,"%02f",graph.progress); XML.addValue("progress",string(c)); } else if (graph.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"); graph.audio_thumb->print_vector(XML); //XML.addValue("audio",audio_thumb->print()); } else { logger.error("ERROR: audio thumbnail requested but no audio loaded"); XML.addValue("error","No audio loaded"); } } if (command.method=="DELETE") { if (state==IDLE) { graph.audio_filename=""; graph.audio_loaded=false; logger.information("Audio deleted"); XML.addValue("status","Audio deleted"); status=HTTPResponse::HTTP_OK; } else { logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } } if (command.commands[1]=="graph") { if (command.method=="GET") { if (state!=LOADING_GRAPH) { if (graph.loaded) { status=HTTPResponse::HTTP_OK; //XML.addValue("patchbay",graph.toString()); logger.information("Graph loaded"); //XML.loadFromBuffer(graph.graphToString()); XML.addValue("status","Graph loaded"); } else { logger.error("ERROR: graph not loaded"); XML.addValue("error","graph not loaded"); } } else { logger.error("ERROR: Graph loading"); XML.addValue("error","Graph loading"); } } if (command.method=="PUT") { //get new graph from file if (command.body!="") { //should interrupt whatever is happening? //before begining to load from xml if (state==IDLE) { //eventually not like this if (command.body!="") { graph_filename=""; graph_body=""; if (Poco::File(graph_dir+command.body).exists()) { graph_filename=graph_dir+command.body; add_queue(Session_task(command.uid,LOAD_GRAPH)); status=HTTPResponse::HTTP_OK; logger.information("Loading graph from file: "+command.body); XML.addValue("status","Loading graph from file: "+command.body); //XML.addValue("render_id",command.uid); process ID? } else { xmlIO xml; bool readable=true; if (!xml.loadFromBuffer(command.body)){ Json::Value root; // will contains the root value after parsing. Json::Reader reader; if ( !reader.parse( command.body, root ) ) { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Could not load graph"); XML.addValue("error","Could not load graph"); readable=false; } } if (readable) { graph_body=command.body; add_queue(Session_task(command.uid,LOAD_GRAPH)); status=HTTPResponse::HTTP_OK; logger.information("Loading graph from body request"); XML.addValue("status","Loading graph from body request"); } } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Empty request"); XML.addValue("error","Empty request"); } } else { logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } } if (command.method=="DELETE") { //for now graph.clear(); logger.information("graph deleted"); XML.addValue("status","graph deleted"); status=HTTPResponse::HTTP_OK; } } if (command.commands[1]=="signal") { if (command.method=="GET") { //generate xml from 1st signal output if (state==IDLE) { //direct call for testing float framerate=25.0f; //if (command.size()>2) { // framerate=toFloat(command.id); //} //string signal_xml; if (graph.signal_render(XML,framerate)){ status=HTTPResponse::HTTP_OK; logger.information("rendering signal to xml"); //XML.addValue("signal",signal_xml); //this doesn't work >> pseudo xml } else { status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; logger.error("ERROR: could not render output signal"); 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; logger.error("ERROR: context busy"); XML.addValue("error","Context busy"); } } } if (command.commands[1]=="video") { if (command.method=="PUT") { //get vide file location and initiate analysis if (command.body!="") { //there should be a filename + a destination node if (state!=RENDERING) { if (command.commands.size()>2) { string video_filename=media_dir+command.body; //check file exists Poco::File f=Poco::File(video_filename); if (f.exists()) { if (graph.load_video(command.commands[2],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; logger.information("Succesfully loaded "+command.body+" into video node "+command.commands[2]); XML.addValue("status","Succesfully loaded "+command.body+" into video node "+command.commands[2]); } else { status=HTTPResponse::HTTP_INTERNAL_SERVER_ERROR; logger.error("ERROR: could not load "+command.body+" into video node "+command.commands[2]); XML.addValue("error","could not load "+command.body+" into video node "+command.commands[2]); } } else { status=HTTPResponse::HTTP_NOT_FOUND; logger.error("ERROR: "+command.body+" not found"); XML.addValue("error",command.body+" not found"); } } else { status=HTTPResponse::HTTP_NOT_FOUND; logger.error("ERROR: video loader node not specified"); XML.addValue("error","video loader node not specified"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } if (command.commands[1]=="preview") { if (command.method=="GET") { if(state==IDLE){ //parse json to get preview spec, return XML? this is a mess string preview_node=command.commands[2]; Json::Value root; // will contains the root value after parsing. Json::Reader reader; if (reader.parse( command.body, root )) { int frame=root["frame"].asInt(); int width=root["width"].asInt(); int height=root["height"].asInt(); string format=root["format"].asString(); if (graph.preview(XML,preview_node,format,frame,width,height)) { status=HTTPResponse::HTTP_OK; } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Could not create preview"); XML.addValue("error","Could not preview node '"+preview_node+"', frame "+toString(frame)+" at "+toString(width)+"x"+toString(height)); } } else { std::cout << "Failed to parse preview request\n" << reader.getFormattedErrorMessages(); status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad preview request"); XML.addValue("error","Bad preview request"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } if (command.commands[1]=="features") { if (command.method=="GET") { if(state==IDLE){ //parse json to get preview spec, return XML? this is a mess string features_node=command.commands[2]; if (graph.print_features(XML,features_node)) { status=HTTPResponse::HTTP_OK; } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Could not print features for node "+features_node); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } if (command.commands[1]=="render") { if (command.method=="GET") { if(state==RENDERING){ //graph.mutex.lock(); status=HTTPResponse::HTTP_OK; XML.addValue("status","Rendering video"); XML.addValue("progress",toString(graph.progress)); //graph.mutex.unlock(); } else { logger.error("ERROR: Render progress requested but not rendering"); XML.addValue("error","Not rendering"); } } if (command.method=="PUT") { if (command.body!="") { if (state==IDLE) { Poco::StringTokenizer t1(command.body,","); if (t1.count()>1){ output_filename=output_dir+t1[0]; start=toInt(t1[1]); if (t1.count()>2){ stop=toInt(t1[2]); if (t1.count()>3){ float framerate=toFloat(t1[3]); if (framerate>0.0f) { output_framerate=framerate; } } } } else { start=0; stop=999999; output_filename=output_dir+command.body; } add_queue(Session_task(command.uid,RENDER)); status=HTTPResponse::HTTP_OK; logger.information("Starting render: "+command.body); XML.addValue("status","Starting render: "+command.body); XML.addValue("render_id",command.uid); XML.addValue("path",output_filename); } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Session busy"); XML.addValue("error","Session busy"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: No output file specified"); XML.addValue("error","No output file specified"); } } if (command.method=="DELETE") { status=HTTPResponse::HTTP_OK; logger.error("ERROR: Not implemented"); XML.addValue("status","DUMMY RESPONSE: cancelling render"); } } if (command.commands[1]=="cancel") { if (command.method=="PUT") { if (state==RENDERING){ graph.cancelled=true; logger.information("Render cancelled."); XML.addValue("status","render cancelled"); } else if (state==ANALYSING_AUDIO){ graph.cancelled=true; logger.information("Audio analysis cancelled."); XML.addValue("status","audio analysis cancelled"); } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: no process to cancel"); XML.addValue("error","No process to cancel"); } } else { status=HTTPResponse::HTTP_BAD_REQUEST; logger.error("ERROR: Bad request"); XML.addValue("error","Bad request"); } } }