summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-09-07 14:25:41 +0100
committerTim Redfern <tim@eclectronics.org>2013-09-07 14:25:41 +0100
commitfea5bf3ffeac6f7a4c5cccb69c5ce51e4a42dbaf (patch)
tree7b358210b01279ed04e083fd5410d9f508590f88
parent37ca0efe3a3e50c2e7debff5f3f1779377e22ab3 (diff)
render cancelling
-rw-r--r--rotord/src/graph.cpp130
-rw-r--r--rotord/src/rendercontext.cpp23
-rw-r--r--rotord/src/rendercontext.h1
-rwxr-xr-xrotord/src/rotor.cpp128
-rwxr-xr-xrotord/src/rotor.h7
-rwxr-xr-xrotord/src/rotord.cpp3
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;
}