diff options
| author | Tim Redfern <tim@herge.(none)> | 2013-05-03 18:25:26 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@herge.(none)> | 2013-05-03 18:25:26 +0100 |
| commit | ff59340614ec150e4bd84d3554081e666970aef2 (patch) | |
| tree | b32689f18b0457580ecf1c7934edd69142a9e005 | |
| parent | 4aa8f7c20c5e8bbe1ed9b007a1193ced8b019f4d (diff) | |
elusive hang while rendering
| -rwxr-xr-x | rotord/01.xml | 15 | ||||
| -rw-r--r-- | rotord/04.xml | 17 | ||||
| -rw-r--r-- | rotord/graph.cpp | 4 | ||||
| -rw-r--r-- | rotord/libavaudioloader.cpp | 52 | ||||
| -rw-r--r-- | rotord/libavaudioloader.h | 1 | ||||
| -rw-r--r-- | rotord/rendercontext.cpp | 25 | ||||
| -rwxr-xr-x | rotord/rotor.cpp | 14 | ||||
| -rwxr-xr-x | rotord/rotor.h | 85 | ||||
| -rw-r--r-- | rotord/utils.cpp | 19 | ||||
| -rw-r--r-- | rotord/utils.h | 6 |
10 files changed, 173 insertions, 65 deletions
diff --git a/rotord/01.xml b/rotord/01.xml index 7a7315d..29d709e 100755 --- a/rotord/01.xml +++ b/rotord/01.xml @@ -2,15 +2,16 @@ <patchbay ID="0f7aa258-7c2f-11e2-abbd-133252267708">Sample template ©Rotor 2013 <node ID="01" type="audio_analysis" soname="qm-vamp-plugins" id="qm-tempotracker" output="signal">beats </node> - <node ID="03" type="divide" amount="2.0" output="signal">signal divide - <signal_input from="01">signal 1 to divide</signal_input> + <node ID="02" type="on_off" output="signal">on off + <signal_input from="01">signal 1 to make on off</signal_input> </node> - <node ID="04" type="bang" output="signal">outputs a single 1 every time signal enters a new number - <signal_input from="03">signal to analyse</signal_input> + <node ID="03" type="video_input" output="image">performance video </node> - <node ID="05" type="video_input" output="image">performance video + <node ID="04" type="invert" output="image">invert video + <signal_input from="02">invert signal</signal_input> + <image_input from="03">image to invert</image_input> </node> - <node ID="06" type="video_output">video output - <image_input from="05">image to output</image_input> + <node ID="05" type="video_output">video output + <image_input from="04">image to output</image_input> </node> </patchbay> diff --git a/rotord/04.xml b/rotord/04.xml new file mode 100644 index 0000000..fe5c3e1 --- /dev/null +++ b/rotord/04.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<patchbay ID="0f7aa258-7c2f-11e2-abbd-133252267708">Sample template ©Rotor 2013 + <node ID="01" type="audio_analysis" soname="qm-vamp-plugins" id="qm-tempotracker" output="signal">beats + </node> + <node ID="02" type="video_input" output="image">performance video + </node> + <node ID="03" type="video_input" output="image">performance video + </node> + <node ID="04" type="video_cycler" output="image">video cycler + <signal_input from="01">switching signal</signal_input> + <image_input from="02">image to switch</image_input> + <image_input from="03">image to switch</image_input> + </node> + <node ID="05" type="video_output">video output + <image_input from="04">image to output</image_input> + </node> +</patchbay> diff --git a/rotord/graph.cpp b/rotord/graph.cpp index fc9a129..2139f6c 100644 --- a/rotord/graph.cpp +++ b/rotord/graph.cpp @@ -29,10 +29,10 @@ bool Graph::signal_render(string &signal_xml,const float framerate) { } else return false; } -bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate) { +bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress) { if (find_node("video_output")) { Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output")); - return video_output->render(duration,framerate,output_filename,audio_filename); + return video_output->render(duration,framerate,output_filename,audio_filename,progress); } else return false; } diff --git a/rotord/libavaudioloader.cpp b/rotord/libavaudioloader.cpp index 03919f0..ef84560 100644 --- a/rotord/libavaudioloader.cpp +++ b/rotord/libavaudioloader.cpp @@ -152,42 +152,50 @@ uint16_t* libav::Audioloader::get_samples(int num){ //presumes 16bpc here //std::cerr << "request "<<num<<" samples: "<<(ready?"ready":"not ready")<<std::endl; if(!ready) return nullptr; //shuffle down samples + if (sample_start>0){ for (int i=0;i<sample_end-sample_start;i++){ - for (int j=0;j<av_frame_get_channels(frame);j++) { - buffer[(i*av_frame_get_channels(frame))+j]=buffer[((sample_start+i)*av_frame_get_channels(frame))+j]; + for (int j=0;j<channels;j++) { + buffer[(i*channels)+j]=buffer[((sample_start+i)*channels)+j]; } } sample_start=sample_end-sample_start; } + sample_end=sample_start; while (sample_end<num) { - frame=get_frame(); - if (((sample_end+std::max(num,frame->nb_samples))*av_frame_get_channels(frame))>buffer.size()){ - int m=buffer.size(); - int s=((sample_end+std::max(num,frame->nb_samples))*av_frame_get_channels(frame)); - buffer.reserve(s); - std::cerr << "audioloader reserved buffer to " << s << std::endl; - for (int i=m;i<s;i++) buffer.push_back(0); + frame=get_frame(); + if (frame) { + channels=av_frame_get_channels(frame); //will always reach here 1st + if (((sample_end+std::max(num,frame->nb_samples))*channels)>buffer.size()){ + int m=buffer.size(); + int s=((sample_end+std::max(num,frame->nb_samples))*channels); + buffer.reserve(s); + std::cerr << "audioloader reserved buffer to " << s << std::endl; + for (int i=m;i<s;i++) buffer.push_back(0); + } + for (int i=0;i<frame->nb_samples;i++) { + for (int j=0;j<channels;j++) { + buffer[((sample_end+i)*frame->channels)+j]= ((uint16_t*) frame->buf[j]->data)[i]; + //temporarily disabled audio as its is SIGSEV with audio from delorentos + + + //buffer[(j*frame->channels)+(sample_end+i)]= ((uint16_t*) frame->buf[j]->data)[i]; ??planar?? nope + } + } + sample_end+=frame->nb_samples; } - if (!frame) { - for (int i=0;i<num*av_frame_get_channels(frame);i++){ - buffer[sample_end+i]=0; + else { + for (int i=sample_end;i<num;i++){ + for (int j=0;j<channels;j++) { + buffer[(channels*i)+j]=0; + } } } //std::cerr<<"filling buffer to "<<((sample_end+frame->nb_samples)*frame->channels)<<std::endl; - for (int i=0;i<frame->nb_samples;i++) { - for (int j=0;j<av_frame_get_channels(frame);j++) { - buffer[((sample_end+i)*frame->channels)+j]= ((uint16_t*) frame->buf[j]->data)[i]; - //temporarily disabled audio as its is SIGSEV with audio from delorentos - - - //buffer[(j*frame->channels)+(sample_end+i)]= ((uint16_t*) frame->buf[j]->data)[i]; ??planar?? nope - } - } - sample_end+=frame->nb_samples; + //avcodec_free_frame(&frame); } if (sample_end>num) { diff --git a/rotord/libavaudioloader.h b/rotord/libavaudioloader.h index aca6bd0..1197fbb 100644 --- a/rotord/libavaudioloader.h +++ b/rotord/libavaudioloader.h @@ -31,6 +31,7 @@ namespace libav { AVPacket packet; int sample_end; int sample_start; + int channels; //necessary to handle final packet }; diff --git a/rotord/rendercontext.cpp b/rotord/rendercontext.cpp index d6469bd..d0fa5bd 100644 --- a/rotord/rendercontext.cpp +++ b/rotord/rendercontext.cpp @@ -19,17 +19,19 @@ void Render_context::runTask() { processors.push_back(dynamic_cast<Base_audio_processor*>(a)); } if (load_audio(audio_filename,processors)) { - state=AUDIO_READY; + 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)){ - state=RENDER_READY; + 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? @@ -88,7 +90,7 @@ Command_response Render_context::session_command(const std::vector<std::string>& sprintf(c,"%02f",progress); response.description+="<progress>"+string(c)+"</progress>\n"; } - if (state==AUDIO_READY) { + else if (audio_loaded) { //not sure about this-- should this state be retained? //can the data only be read once? //for now @@ -97,7 +99,10 @@ Command_response Render_context::session_command(const std::vector<std::string>& response.description+="<audio>\n"; response.description+=audio_thumb->print(); response.description+="</audio>"; - state=IDLE; + } + else { + response.status=HTTPResponse::HTTP_BAD_REQUEST; + response.description="<status context='"+command[1]+"'>Rotor: no audio loaded</status>\n"; } } if (command[0]=="DELETE") { @@ -230,8 +235,8 @@ Command_response Render_context::session_command(const std::vector<std::string>& if (command[0]=="GET") { //DUMMY RESPONSE response.status=HTTPResponse::HTTP_OK; - response.description="<status context='"+command[1]+"'>DUMMY RESPONSE Rotor: rendering video</status>\n"; - response.description+="<progress>25.2</progress>\n"; + response.description="<status context='"+command[1]+"'>Rotor: rendering video</status>\n"; + response.description+="<progress>"+ofToString(progress)+"</progress>\n"; } if (command[0]=="PUT") { if (command.size()>2) { @@ -383,9 +388,9 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process p->process_frame(frame->data[0],frame->nb_samples); } sample_processed+=frame->nb_samples; - mutex.lock(); - progress=((double)sample_processed)/samples; - mutex.unlock(); + //mutex.lock(); + progress=((float)sample_processed)/samples; + //mutex.unlock(); } } // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index b0bf8ab..4c79fc1 100755 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -13,6 +13,9 @@ Node_factory::Node_factory(){ add_type("testcard",new Testcard()); add_type("video_output",new Video_output()); add_type("video_input",new Video_input()); + add_type("on_off",new On_off()); + add_type("invert",new Invert()); + add_type("video_cycler",new Video_cycler()); } bool Signal_input::connect(Signal_node* source) { @@ -151,7 +154,7 @@ void Audio_analysis::print_features(){ } } -bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename){ +bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress){ // //setup defaults @@ -188,8 +191,15 @@ bool Video_output::render(const float duration, const float framerate,const stri af+=exporter->get_audio_step(); } Image* i=get_output(Frame_spec(vf,framerate,outW,outH)); - exporter->encodeFrame(i->RGBdata); + if (i) { + exporter->encodeFrame(i->RGBdata); + } vf+=vstep; + progress=vf/duration; + if (progress>0.99) { + //stop here + //seems that the last frame of samples causes std::max to have <error reading variables> + } /* if (!exporter->encodeFrame(i->RGBdata)){ //if (!exporter->encodeFrame(get_output(Frame_spec(f,framerate,outW,outH))->RGBdata,audioloader.get_packet())){ diff --git a/rotord/rotor.h b/rotord/rotor.h index 441be2f..ea4d758 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -62,6 +62,7 @@ extern "C" { #include "libavaudioloader.h" #include "libavexporter.h" #include "gstvideoloader.h" +#include "utils.h" //fequal namespace Rotor { #define IDLE 0 @@ -76,19 +77,7 @@ namespace Rotor { #define PREVIEW 2 #define RENDER 3 -#ifndef FEQUAL -//float equality -bool fequal(const float u,const float v){ - if (abs(u-v)<.001) return true; - else return false; -}; -bool flessorequal(const float u,const float v){ - //v is less or equal to u - if (u-v>-.001) return true; - else return false; -}; -#define FEQUAL -#endif + //forward declaration class Node; @@ -344,6 +333,21 @@ bool flessorequal(const float u,const float v){ return 0.0f; } }; + class On_off: public Signal_node { + public: + On_off(){}; + On_off(map<string,string> &settings) { + base_settings(settings); + }; + On_off* clone(map<string,string> &_settings) { return new On_off(_settings);}; + const float get_output(const Time_spec &time) { + if (inputs[0]->connection) { + float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time)); + if ((int)s1%2) return 1.0f; + } + return 0.0f; + } + }; class Signal_output: public Signal_node { public: Signal_output(){}; @@ -400,12 +404,22 @@ bool flessorequal(const float u,const float v){ Invert* clone(map<string,string> &_settings) { return new Invert(_settings);}; Image *get_output(const Frame_spec &frame){ if (inputs.size()) { - if (inputs[0]->connection) { - Time_spec requested=Time_spec(frame.time,frame.framerate); - if (fequal((((Signal_node*)inputs[0]->connection)->get_output(requested)),1.0f)) { - //invert=!invert; - } - } + if (image_inputs[0]->connection){ + if (inputs[0]->connection) { + Time_spec requested=Time_spec(frame.time,frame.framerate); + if (fmoreorequal(1.0f,(((Signal_node*)inputs[0]->connection)->get_output(requested)))) { + Image *in=(((Image_node*)image_inputs[0]->connection)->get_output(frame)); + image->setup(frame.w,frame.h); + for (int i=0;i<in->w*in->h*3;i++) { + image->RGBdata[i]=255-in->RGBdata[i]; + } + return image; + + } + } + return (((Image_node*)image_inputs[0]->connection)->get_output(frame)); + } + return nullptr; } if (image_inputs[0]->connection) { @@ -431,7 +445,7 @@ bool flessorequal(const float u,const float v){ else return nullptr; }; Video_output* clone(map<string,string> &_settings) { return new Video_output(_settings);}; - bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename); + bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress); private: //ofxMovieExporter *exporter; @@ -454,6 +468,31 @@ bool flessorequal(const float u,const float v){ ofGstVideoPlayer *player; Image *image; }; + class Video_cycler: public Image_node { + //cycles through video inputs in order + public: + Video_cycler(){}; + Video_cycler(map<string,string> &settings) { + base_settings(settings); + }; + ~Video_cycler(){}; + bool load(const string &filename); + Image *get_output(const Frame_spec &frame){ + int which_input=0; + Time_spec requested=Time_spec(frame.time,frame.framerate); + if (inputs[0]->connection) { + which_input=((int)((Signal_node*)inputs[0]->connection)->get_output(requested))%image_inputs.size(); + } + if (image_inputs.size()) { + if (image_inputs[which_input]->connection){ + return (((Image_node*)image_inputs[which_input]->connection)->get_output(frame)); + } + } + return nullptr; + } + Video_cycler* clone(map<string,string> &_settings) { return new Video_cycler(_settings);}; + private: + }; //------------------------------------------------------------------- class Node_factory{ public: @@ -484,7 +523,7 @@ bool flessorequal(const float u,const float v){ vector<Node*> find_nodes(const string &type); Node* find_node(const string &type); bool signal_render(string &signal_xml,const float framerate); - bool video_render(const string &output_filename,const string &audio_filename,const float framerate); + bool video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress); int load(Poco::UUID uid); bool load(string &graph_filename); UUID save(); //save to DB, returns UUID of saved graph @@ -526,6 +565,7 @@ bool flessorequal(const float u,const float v){ audio_thumb=new Audio_thumbnailer(); state=IDLE; output_framerate=25.0f; + audio_loaded=false; }; void runTask(); void add_queue(int item); @@ -538,7 +578,7 @@ bool flessorequal(const float u,const float v){ bool load_video(const string &nodeID,const string &filename);//can be performance or clip private: int state; - double progress; //for a locking process: audio analysis or rendering + float progress; //for a locking process: audio analysis or rendering //thread only does one thing at once std::deque<int> work_queue; Poco::Mutex mutex; //lock for access from parent thread @@ -550,6 +590,7 @@ bool flessorequal(const float u,const float v){ Graph graph; Node_factory factory; float output_framerate; + bool audio_loaded; }; } diff --git a/rotord/utils.cpp b/rotord/utils.cpp new file mode 100644 index 0000000..d357319 --- /dev/null +++ b/rotord/utils.cpp @@ -0,0 +1,19 @@ +#include "utils.h" + +using namespace std; + +//float equality +bool fequal(const float u,const float v){ + if (abs(u-v)<.001) return true; + else return false; +}; +bool flessorequal(const float u,const float v){ + //v is less or equal to u + if (u-v>-.001) return true; + else return false; +}; +bool fmoreorequal(const float u,const float v){ + //v is more or equal to u + if (v-u>-.001) return true; + else return false; +}; diff --git a/rotord/utils.h b/rotord/utils.h new file mode 100644 index 0000000..e9084ff --- /dev/null +++ b/rotord/utils.h @@ -0,0 +1,6 @@ +#include <cmath> + +//float equality +bool fequal(const float u,const float v); +bool flessorequal(const float u,const float v); +bool fmoreorequal(const float u,const float v); |
