diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-09-07 14:25:41 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-09-07 14:25:41 +0100 |
| commit | fea5bf3ffeac6f7a4c5cccb69c5ce51e4a42dbaf (patch) | |
| tree | 7b358210b01279ed04e083fd5410d9f508590f88 | |
| parent | 37ca0efe3a3e50c2e7debff5f3f1779377e22ab3 (diff) | |
render cancelling
| -rw-r--r-- | rotord/src/graph.cpp | 130 | ||||
| -rw-r--r-- | rotord/src/rendercontext.cpp | 23 | ||||
| -rw-r--r-- | rotord/src/rendercontext.h | 1 | ||||
| -rwxr-xr-x | rotord/src/rotor.cpp | 128 | ||||
| -rwxr-xr-x | rotord/src/rotor.h | 7 | ||||
| -rwxr-xr-x | rotord/src/rotord.cpp | 3 |
6 files changed, 158 insertions, 134 deletions
diff --git a/rotord/src/graph.cpp b/rotord/src/graph.cpp index ef5fd87..7ca8879 100644 --- a/rotord/src/graph.cpp +++ b/rotord/src/graph.cpp @@ -1,6 +1,8 @@ #include "rotor.h" using namespace Rotor; +using Poco::Logger; + const string Graph::toString(){ string xmlgraph; if (loaded) { @@ -90,8 +92,132 @@ bool Graph::video_render(const string &output_filename,const float framerate,flo for (auto f: find_nodes("video_feedback")){ (dynamic_cast<Video_feedback*>(f))->set_feedback(&(video_output->image)); } - return video_output->render(duration,framerate,output_filename,audio_filename,progress,outW,outH); - } + // + //setup defaults + int bitRate=5000000; + AVCodecID codecId=AV_CODEC_ID_H264; //MPEG4; + std::string container ="mp4"; + + //at the moment it crashes if you render before audio is loaded and also on 2nd render + libav::exporter exporter; + + float spct=100.0f/duration; + + if (exporter.setup(outW,outH,bitRate,framerate,container)) { //codecId, + if (exporter.record(output_filename)) { + + libav::audioloader audioloader; + + bool usingaudio=audioloader.setup(audio_filename); + float *avframe=nullptr; + + + Logger& logger = Logger::get("Rotor"); + logger.information("Video_output rendering "+output_filename+": "+ofToString(duration)+" seconds at "+ofToString(framerate)+" fps, audio frame size: "+ofToString(exporter.get_audio_framesize())); + //25fps video and 43.06640625fps audio? hmm + //how to get the timecodes correct for the interleaved files + + struct timeval start, end; + + gettimeofday(&start, NULL); + + uint16_t *audioframe; + int samples_in_frame; + + if (usingaudio){ + //does audioloader output interleaved samples? + samples_in_frame=(audioloader.codecContext->sample_rate)/framerate; + string whether=usingaudio?"Loading":"Cannot load"; + logger.information(whether+" audio file: "+audio_filename+", each frame contains "+ofToString(samples_in_frame)+" samples at "+ofToString(audioloader.codecContext->sample_rate)+" hz"); + audioframe=new uint16_t[(samples_in_frame+exporter.get_audio_framesize())*audioloader.codecContext->channels]; + } + + float vstep=1.0f/framerate; + float v=0.0f; + float vf=0.0f; + float af=0.0f; + int aoffs=0; + int audioend=0; + Audio_frame *a; + while (vf<duration&&!cancelled){ //-vstep) { + uint16_t *audio=nullptr; + if (usingaudio) { + uint16_t *audio=audioloader.get_samples(samples_in_frame); + if (aoffs>0){ + //shift down samples + int s=0; + while ((s+aoffs)<audioend) { + for (int j=0;j<audioloader.codecContext->channels;j++){ + audioframe[s*audioloader.codecContext->channels+j]=audioframe[(s+aoffs)*audioloader.codecContext->channels+j]; + } + s++; + } + aoffs=s; + } + for (int i=0;i<samples_in_frame;i++){ + for (int j=0;j<audioloader.codecContext->channels;j++){ + audioframe[(aoffs+i)*audioloader.codecContext->channels+j]=audio[i*audioloader.codecContext->channels+j]; + } + } + audioend=aoffs+samples_in_frame; + aoffs=0; + //while (fless(vf+vstep,af+exporter.get_audio_step())) { + while (aoffs+exporter.get_audio_framesize()<audioend) { + //insert audio frames until we are only 1 audio frame behind the next video frame + //send audio_framesize() of them through until buffer is used + //pass full buffer within frame_spec for av nodes + exporter.encodeFrame(audioframe+(aoffs*audioloader.codecContext->channels)); + af+=exporter.get_audio_step(); + aoffs+=exporter.get_audio_framesize(); + } + a=new Audio_frame(audio,audioloader.codecContext->channels,samples_in_frame); + } + + + //[mp3 @ 0x7fffe40330e0] max_analyze_duration 5000000 reached at 5015510 microseconds + //[mp3 @ 0x7fffe4033ec0] Insufficient thread locking around avcodec_open/close() + //[mp3 @ 0x7fffe40330e0] Estimating duration from bitrate, this may be inaccurate + //[libx264 @ 0x7fffe8003940] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 + //[libx264 @ 0x7fffe8003940] profile High, level 3.0 + //[libx264 @ 0x7fffe8003940] 264 - core 123 r2189 35cf912 - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=10 keyint_min=1 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=abr mbtree=1 bitrate=400 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 + //Assertion ff_avcodec_locked failed at libavcodec/utils.c:2967 + + //cerr<<"videoloader: "<<vf<<" seconds, vstep "<<vstep<<" ,asking for frame "<<((int)((vf*framerate)+0.5))<<endl + + Image* i; + if (usingaudio) { + i=video_output->get_output(Frame_spec(vf,framerate,duration,outW,outH,a)); + } + else i=video_output->get_output(Frame_spec(vf,framerate,duration,outW,outH)); + if (i) { + exporter.encodeFrame(i->RGBdata); + } + vf+=vstep; + progress=vf/duration; + if (usingaudio) {delete a;}; + } + + exporter.finishRecord(); + + gettimeofday(&end, NULL); + + float mtime = ((end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)/1000000.0) + 0.5; + + logger.information("Video_output: rendered "+output_filename+": in "+ofToString(mtime)+" seconds"); + + if (usingaudio) { + audioloader.close(); + delete[] audioframe; + } + + + + return true; + } + } + + return false; + } cerr<<"Rotor: video output node not found"<<endl; return false; diff --git a/rotord/src/rendercontext.cpp b/rotord/src/rendercontext.cpp index 47113c1..cebe003 100644 --- a/rotord/src/rendercontext.cpp +++ b/rotord/src/rendercontext.cpp @@ -11,6 +11,7 @@ void Render_context::runTask() { if (work_queue.size()){ cmd=work_queue[0]; work_queue.pop_front(); + graph.cancelled=false; } mutex.unlock(); if(cmd.task==ANALYSE_AUDIO) { @@ -37,7 +38,8 @@ void Render_context::runTask() { renders[cmd.uid]=Render_status(RENDERING); if(graph.video_render(output_filename,output_framerate,progress)){ state=IDLE; - renders[cmd.uid].status=RENDER_READY; + 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? @@ -416,6 +418,25 @@ void Render_context::session_command(const Session_command& command,xmlIO& XML,H XML.addValue("status","DUMMY RESPONSE: cancelling render"); } } + if (command.commands[1]=="cancel") { + if (command.method=="PUT") { + if (state==RENDERING||state==ANALYSING_AUDIO){ + graph.cancelled=true; + logger.information("Render cancelled."); + XML.addValue("status","render 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"); + } + } } bool Render_context::load_audio(const string &filename,vector<Audio_processor*> processors){ diff --git a/rotord/src/rendercontext.h b/rotord/src/rendercontext.h index bf7bb11..2d26ec2 100644 --- a/rotord/src/rendercontext.h +++ b/rotord/src/rendercontext.h @@ -16,6 +16,7 @@ namespace Rotor { #define RENDER_READY 6 #define FAILED 7 #define NOT_FOUND 8 + #define CANCELLED 9 #define ANALYSE_AUDIO 1 #define PREVIEW 2 diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp index 87874d8..8905a6e 100755 --- a/rotord/src/rotor.cpp +++ b/rotord/src/rotor.cpp @@ -79,134 +79,6 @@ float Parameter::get(const Time_spec& time){ //gets input and updates variable } return value; } -bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress,int outW,int outH){ - - // - //setup defaults - int bitRate=5000000; - AVCodecID codecId=AV_CODEC_ID_H264; //MPEG4; - std::string container ="mp4"; - - //at the moment it crashes if you render before audio is loaded and also on 2nd render - libav::exporter exporter; - - float spct=100.0f/duration; - - if (exporter.setup(outW,outH,bitRate,framerate,container)) { //codecId, - if (exporter.record(output_filename)) { - - libav::audioloader audioloader; - - bool usingaudio=audioloader.setup(audio_filename); - float *avframe=nullptr; - - - Logger& logger = Logger::get("Rotor"); - logger.information("Video_output rendering "+output_filename+": "+ofToString(duration)+" seconds at "+ofToString(framerate)+" fps, audio frame size: "+ofToString(exporter.get_audio_framesize())); - //25fps video and 43.06640625fps audio? hmm - //how to get the timecodes correct for the interleaved files - - struct timeval start, end; - - gettimeofday(&start, NULL); - - uint16_t *audioframe; - int samples_in_frame; - - if (usingaudio){ - //does audioloader output interleaved samples? - samples_in_frame=(audioloader.codecContext->sample_rate)/framerate; - string whether=usingaudio?"Loading":"Cannot load"; - logger.information(whether+" audio file: "+audio_filename+", each frame contains "+ofToString(samples_in_frame)+" samples at "+ofToString(audioloader.codecContext->sample_rate)+" hz"); - audioframe=new uint16_t[(samples_in_frame+exporter.get_audio_framesize())*audioloader.codecContext->channels]; - } - - float vstep=1.0f/framerate; - float v=0.0f; - float vf=0.0f; - float af=0.0f; - int aoffs=0; - int audioend=0; - Audio_frame *a; - while (vf<duration){ //-vstep) { - uint16_t *audio=nullptr; - if (usingaudio) { - uint16_t *audio=audioloader.get_samples(samples_in_frame); - if (aoffs>0){ - //shift down samples - int s=0; - while ((s+aoffs)<audioend) { - for (int j=0;j<audioloader.codecContext->channels;j++){ - audioframe[s*audioloader.codecContext->channels+j]=audioframe[(s+aoffs)*audioloader.codecContext->channels+j]; - } - s++; - } - aoffs=s; - } - for (int i=0;i<samples_in_frame;i++){ - for (int j=0;j<audioloader.codecContext->channels;j++){ - audioframe[(aoffs+i)*audioloader.codecContext->channels+j]=audio[i*audioloader.codecContext->channels+j]; - } - } - audioend=aoffs+samples_in_frame; - aoffs=0; - //while (fless(vf+vstep,af+exporter.get_audio_step())) { - while (aoffs+exporter.get_audio_framesize()<audioend) { - //insert audio frames until we are only 1 audio frame behind the next video frame - //send audio_framesize() of them through until buffer is used - //pass full buffer within frame_spec for av nodes - exporter.encodeFrame(audioframe+(aoffs*audioloader.codecContext->channels)); - af+=exporter.get_audio_step(); - aoffs+=exporter.get_audio_framesize(); - } - a=new Audio_frame(audio,audioloader.codecContext->channels,samples_in_frame); - } - - - //[mp3 @ 0x7fffe40330e0] max_analyze_duration 5000000 reached at 5015510 microseconds - //[mp3 @ 0x7fffe4033ec0] Insufficient thread locking around avcodec_open/close() - //[mp3 @ 0x7fffe40330e0] Estimating duration from bitrate, this may be inaccurate - //[libx264 @ 0x7fffe8003940] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 - //[libx264 @ 0x7fffe8003940] profile High, level 3.0 - //[libx264 @ 0x7fffe8003940] 264 - core 123 r2189 35cf912 - H.264/MPEG-4 AVC codec - Copyleft 2003-2012 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=10 keyint_min=1 scenecut=40 intra_refresh=0 rc_lookahead=10 rc=abr mbtree=1 bitrate=400 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 - //Assertion ff_avcodec_locked failed at libavcodec/utils.c:2967 - - //cerr<<"videoloader: "<<vf<<" seconds, vstep "<<vstep<<" ,asking for frame "<<((int)((vf*framerate)+0.5))<<endl - - Image* i; - if (usingaudio) { - i=get_output(Frame_spec(vf,framerate,duration,outW,outH,a)); - } - else i=get_output(Frame_spec(vf,framerate,duration,outW,outH)); - if (i) { - exporter.encodeFrame(i->RGBdata); - } - vf+=vstep; - progress=vf/duration; - if (usingaudio) {delete a;}; - } - - exporter.finishRecord(); - - gettimeofday(&end, NULL); - - float mtime = ((end.tv_sec-start.tv_sec) + (end.tv_usec-start.tv_usec)/1000000.0) + 0.5; - - logger.information("Video_output: rendered "+output_filename+": in "+ofToString(mtime)+" seconds"); - - if (usingaudio) { - audioloader.close(); - delete[] audioframe; - } - - - - return true; - } - } - - return false; -} bool Video_loader::load(const string &_filename){ Logger& logger = Logger::get("Rotor"); diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h index 6c030ec..dea3fa0 100755 --- a/rotord/src/rotor.h +++ b/rotord/src/rotor.h @@ -893,7 +893,7 @@ namespace Rotor { Video_output(){ create_image_input("image to output","Image input"); title="Video output"; - description="Outputs to video from here"; + description="Output to video"; }; Video_output(map<string,string> &settings):Video_output() { base_settings(settings); @@ -910,8 +910,7 @@ namespace Rotor { 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,float& progress,int w,int h); - + private: }; @@ -1124,6 +1123,7 @@ namespace Rotor { description=_desc; duration=20.0f; framerate=25.0f; + cancelled=false; }; string uid; //every version of a graph has a UUID, no particular need to actually read its data(?) //?? is it faster than using strings?? @@ -1148,6 +1148,7 @@ namespace Rotor { xmlIO xml; bool audio_loaded; string audio_filename; + bool cancelled; private: Node_factory factory; int outW,outH; diff --git a/rotord/src/rotord.cpp b/rotord/src/rotord.cpp index df1ee6a..57318ed 100755 --- a/rotord/src/rotord.cpp +++ b/rotord/src/rotord.cpp @@ -155,6 +155,9 @@ HTTPRequestHandler* RotorRequestHandlerFactory::createRequestHandler(const HTTPS case NOT_FOUND: XML.addAttribute("render","status","error - not found",i); break; + case CANCELLED: + XML.addAttribute("render","status","render cancelled",i); + break; } context_found=true; } |
