diff options
Diffstat (limited to 'rotord')
| -rw-r--r-- | rotord/03.xml | 8 | ||||
| -rw-r--r-- | rotord/Makefile | 2 | ||||
| -rw-r--r-- | rotord/ofxMovieExporter.cpp | 302 | ||||
| -rw-r--r-- | rotord/ofxMovieExporter.h | 35 | ||||
| -rwxr-xr-x | rotord/rotor.cpp | 94 | ||||
| -rwxr-xr-x | rotord/rotor.h | 97 |
6 files changed, 256 insertions, 282 deletions
diff --git a/rotord/03.xml b/rotord/03.xml new file mode 100644 index 0000000..f723ee7 --- /dev/null +++ b/rotord/03.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<patchbay ID="0f7aa258-7c2f-11e2-abbd-133252267708">testcard ©Rotor 2013 + <node ID="01" type="testcard" >testcard + </node> + <node ID="02" type="video_output">renders the video + <image_input from="01">video to output</image_input> + </node> +</patchbay> diff --git a/rotord/Makefile b/rotord/Makefile index 6a7f48b..54f5b92 100644 --- a/rotord/Makefile +++ b/rotord/Makefile @@ -4,7 +4,7 @@ MY_CFLAGS = -fpermissive -std=c++11 -Wno-error # -I ../ffmpeg # The linker options. -MY_LIBS = -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lavcodec -lavformat -lavfilter -lavdevice -lavutil +MY_LIBS = -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil #MY_LIBS = ../libavcodec/ffmpeg/libavcodec/libavcodec.a ../libavcodec/ffmpeg/libavutil/libavutil.a ../libavcodec/ffmpeg/libavformat/libavformat.a ../libavcodec/ffmpeg/libavfilter/libavfilter.a ../libavcodec/ffmpeg/libavdevice/libavdevice.a -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk #GAH! HARD! diff --git a/rotord/ofxMovieExporter.cpp b/rotord/ofxMovieExporter.cpp index f7c47de..8b97813 100644 --- a/rotord/ofxMovieExporter.cpp +++ b/rotord/ofxMovieExporter.cpp @@ -32,47 +32,42 @@ #include "ofxMovieExporter.h" //#include "ofThread.h" -namespace itg -{ - const std::string ofxMovieExporter::FILENAME_PREFIX = "capture"; - const std::string ofxMovieExporter::CONTAINER = "mp4"; - - ofxMovieExporter::ofxMovieExporter() { - outputFormat = NULL; - formatCtx = NULL; - videoStream = NULL; - - codec = NULL; - codecCtx = NULL; - convertCtx = NULL; - - inPixels = NULL; - outPixels = NULL; - encodedBuf = NULL; - - inFrame = NULL; - outFrame = NULL; - - posX = 0; - posY = 0; - //inW = ofGetWidth(); - //inH = ofGetHeight(); - //outW = ofGetWidth(); - //outH = ofGetHeight(); - - bool usePixelSource = false; - pixelSource = NULL; - } - - void ofxMovieExporter::setup( - int outW, - int outH, - int bitRate, - int frameRate, - AVCodecID codecId, - std::string container) - { - if (outW % 2 == 1 || outH % 2 == 1) //ofLog(OF_LOG_ERROR, "ofxMovieExporter: Resolution must be a multiple of 2"); + const std::string ofxMovieExporter::FILENAME_PREFIX = "capture"; + const std::string ofxMovieExporter::CONTAINER = "mp4"; + + ofxMovieExporter::ofxMovieExporter() { + outputFormat = NULL; + formatCtx = NULL; + videoStream = NULL; + + codec = NULL; + codecCtx = NULL; + convertCtx = NULL; + + inPixels = NULL; + outPixels = NULL; + encodedBuf = NULL; + + inFrame = NULL; + outFrame = NULL; + + // do one time encoder set up + av_register_all(); + + } + + bool ofxMovieExporter::setup( + int outW, + int outH, + int bitRate, + int frameRate, + AVCodecID codecId, + std::string container) + { + if (outW % 2 == 1 || outH % 2 == 1) { + cerr << "ofxMovieExporter: Resolution must be a multiple of 2" << endl; + return false; + } this->outW = outW; this->outH = outH; @@ -86,15 +81,17 @@ namespace itg // HACK HACK HACK // Time not syncing // probably related to codec ticks_per_frame - frameInterval /= 3.f; + //frameInterval /= 3.f; + recording = false; numCaptures = 0; - // do one time encoder set up - av_register_all(); + convertCtx = sws_getContext(inW, inH, PIX_FMT_RGB24, outW, outH, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); allocateMemory(); + + return true; } ofxMovieExporter::~ofxMovieExporter() @@ -105,14 +102,14 @@ namespace itg clearMemory(); } - void ofxMovieExporter::record(std::string filePrefix, std::string folderPath) + bool ofxMovieExporter::record(std::string filePrefix, std::string folderPath) { initEncoder(); std::ostringstream oss; oss << folderPath; if (folderPath != "" && (folderPath[folderPath.size()-1] != '/' && folderPath[folderPath.size()-1] != '\\')) - oss << "/"; + oss << "/"; oss << filePrefix << numCaptures << "." << container; outFileName = oss.str(); @@ -120,72 +117,36 @@ namespace itg //if (url_fopen(&formatCtx->pb, outFileName.c_str(), 'wb' ) < 0) //url_fopen URL_WRONLY // ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not open file %s", outFileName.c_str()); if (avio_open(&formatCtx->pb, outFileName.c_str(), AVIO_FLAG_WRITE) < 0) { - cerr << "ofxMovieExporter: Could not open file "<< outFileName<<endl; + return false; } //ofAddListener(ofEvents.draw, this, &ofxMovieExporter::checkFrame); AVDictionary *options; //= NULL; causes a forward declaration error!? - options=NULL; + options=NULL; // write the stream header, if any avformat_write_header(formatCtx,&options); lastFrameTime = 0; frameNum = 0; recording = true; -//#ifdef _THREAD_CAPTURE -// startThread(true, false); -//#endif + + return true; } void ofxMovieExporter::stop() { - //ofRemoveListener(ofEvents.draw, this, &ofxMovieExporter::checkFrame); + recording = false; numCaptures++; -//#ifndef _THREAD_CAPTURE -// finishRecord(); -//#endif - } - void ofxMovieExporter::setRecordingArea(int x, int y, int w, int h) - { - posX = x; - posY = y; - inW = w; - inH = h; - } - - void ofxMovieExporter::setRecordingArea(int rect) - { - /* - posX = rect.x; - posY = rect.y; - inW = rect.width; - inH = rect.height; - */ - } - - void ofxMovieExporter::resetRecordingArea() - { - posX = 0; - posY = 0; - //inW = ofGetViewportWidth(); - //inH = ofGetViewportHeight(); - } - - int ofxMovieExporter::getRecordingArea() - { - return 0; //ofRectangle(posX, posY, inW, inH); } void ofxMovieExporter::setPixelSource(unsigned char* pixels, int w, int h) { - if (isRecording()) - stop(); - + if (pixels == NULL) { //ofLog(OF_LOG_ERROR, "ofxMovieExporter: Could not set NULL pixel source"); @@ -200,17 +161,7 @@ namespace itg setup(outW, outH, bitRate, frameRate, codecId, container); } - void ofxMovieExporter::resetPixelSource() - { - usePixelSource = false; - pixelSource = NULL; - //inW = ofGetViewportWidth(); - //inH = ofGetViewportHeight(); - - // resetup encoder etc - setup(outW, outH, bitRate, frameRate, codecId, container); - } - + int ofxMovieExporter::getNumCaptures() { return numCaptures; @@ -220,7 +171,7 @@ namespace itg { numCaptures = 0; } - + // PRIVATE void ofxMovieExporter::finishRecord() @@ -239,105 +190,38 @@ namespace itg //url_fclose(formatCtx->pb); } -/* -#ifdef _THREAD_CAPTURE - void ofxMovieExporter::threadedFunction() + void ofxMovieExporter::encodeFrame() { - while (isThreadRunning()) - { - if (!frameQueue.empty()) - { - float start = ofGetElapsedTimef(); - frameQueueMutex.lock(); - inPixels = frameQueue.front(); - frameQueue.pop_front(); - frameQueueMutex.unlock(); - - encodeFrame(); - - frameMemMutex.lock(); - frameMem.push_back(inPixels); - frameMemMutex.unlock(); - if (ofGetElapsedTimef() - start < frameInterval) ofSleepMillis(1000.f * (frameInterval - (ofGetElapsedTimef() - start))); - } - else if (!recording) - { - finishRecord(); - stopThread(true); - } - } - } -#endif -*/ + + avpicture_fill((AVPicture*)inFrame, inPixels, PIX_FMT_RGB24, inW, inH); + avpicture_fill((AVPicture*)outFrame, outPixels, PIX_FMT_YUV420P, outW, outH); + + //perform the conversion for RGB to YUV and size + sws_scale(convertCtx, inFrame->data, inFrame->linesize, 0, inH, outFrame->data, outFrame->linesize); - void ofxMovieExporter::checkFrame() //ofEventArgs& args) - { - if (1) //ofGetElapsedTimef() - lastFrameTime >= frameInterval) + int outSize = avcodec_encode_video(codecCtx, encodedBuf, ENCODED_FRAME_BUFFER_SIZE, outFrame); + if (outSize > 0) { -/* -#ifdef _THREAD_CAPTURE - unsigned char* pixels; - if (!frameMem.empty()) - { - frameMemMutex.lock(); - pixels = frameMem.back(); - frameMem.pop_back(); - frameMemMutex.unlock(); - } - else - { - pixels = new unsigned char[inW * inH * 3]; - } - - if (!usePixelSource) - { - // this part from ofImage::saveScreen - int screenHeight = ofGetViewportHeight(); // if we are in a FBO or other viewport, this fails: ofGetHeight(); - int screenY = screenHeight - posY; - screenY -= inH; // top, bottom issues - - glReadPixels(posX, screenY, inW, inH, GL_RGB, GL_UNSIGNED_BYTE, pixels); - } - else - { - memcpy(pixels, pixelSource, inW * inH * 3); - } - - frameQueueMutex.lock(); - frameQueue.push_back(pixels); - frameQueueMutex.unlock(); -#else -*/ - if (!usePixelSource) { - // this part from ofImage::saveScreen - //int screenHeight = ofGetViewportHeight(); // if we are in a FBO or other viewport, this fails: ofGetHeight(); - //int screenY = screenHeight - posY; - //screenY -= inH; // top, bottom issues - - //glReadPixels(posX, screenY, inW, inH, GL_RGB, GL_UNSIGNED_BYTE, inPixels); - } - else - { - memcpy(inPixels, pixelSource, inW * inH * 3); - } - encodeFrame(); -//#endif - //lastFrameTime = ofGetElapsedTimef(); + AVPacket pkt; + av_init_packet(&pkt); + //pkt.pts = av_rescale_q(codecCtx->coded_frame->pts, codecCtx->time_base, videoStream->time_base); + //if(codecCtx->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; + pkt.pts = frameNum;//ofGetFrameNum();//codecCtx->coded_frame->pts; + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.dts = pkt.pts; + pkt.stream_index = videoStream->index; + pkt.data = encodedBuf; + pkt.size = outSize; + av_write_frame(formatCtx, &pkt); } + frameNum++; } - void ofxMovieExporter::encodeFrame() + void ofxMovieExporter::encodeFrame(char *pixels) { - avpicture_fill((AVPicture*)inFrame, inPixels, PIX_FMT_RGB24, inW, inH); + avpicture_fill((AVPicture*)inFrame, pixels, PIX_FMT_RGB24, inW, inH); avpicture_fill((AVPicture*)outFrame, outPixels, PIX_FMT_YUV420P, outW, outH); - - // intentionally flip the image to compensate for OF flipping if reading from the screen - if (!usePixelSource) - { - inFrame->data[0] += inFrame->linesize[0] * (inH - 1); - inFrame->linesize[0] = -inFrame->linesize[0]; - } //perform the conversion for RGB to YUV and size sws_scale(convertCtx, inFrame->data, inFrame->linesize, 0, inH, outFrame->data, outFrame->linesize); @@ -365,17 +249,7 @@ namespace itg // clear if we need to reallocate if(inPixels) clearMemory(); -/* - // allocate input stuff -#ifdef _THREAD_CAPTURE - //unsigned char* initFrameMem = new unsigned char[inW * inH * 3 * INIT_QUEUE_SIZE]; - for (int i = 0; i < INIT_QUEUE_SIZE; i++) - { - //frameMem.push_back(initFrameMem + inW * inH * 3 * i); - frameMem.push_back(new unsigned char[inW * inH * 3]); - } -#else -*/ + inPixels = new unsigned char[inW * inH * 3]; //#endif inFrame = avcodec_alloc_frame(); @@ -389,21 +263,7 @@ namespace itg } void ofxMovieExporter::clearMemory() { -/* - // clear input stuff -#ifdef _THREAD_CAPTURE - for (int i = 0; i < frameMem.size(); i++) - { - delete[] frameMem[i]; - } - for (int i = 0; i < frameQueue.size(); i++) - { - delete[] frameQueue[i]; - } -#else -*/ delete[] inPixels; -//#endif inPixels = NULL; @@ -464,11 +324,11 @@ namespace itg /* needed to avoid using macroblocks in which some coeffs overflow this doesnt happen with normal video, it just happens here as the motion of the chroma plane doesnt match the luma plane */ - codecCtx->mb_decision=2; - } + codecCtx->mb_decision=2; + } // some formats want stream headers to be seperate - if(!strcmp(formatCtx->oformat->name, "mp4") || !strcmp(formatCtx->oformat->name, "mov") || !strcmp(formatCtx->oformat->name, "3gp")) - codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; + if(!strcmp(formatCtx->oformat->name, "mp4") || !strcmp(formatCtx->oformat->name, "mov") || !strcmp(formatCtx->oformat->name, "3gp")) + codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; // set the output parameters (must be done even if no parameters). //if ( @@ -485,10 +345,10 @@ namespace itg // < 0) ofLog(OF_LOG_ERROR, "ofxMovieExproter: Could not set format parameters"); AVDictionary *options; //= NULL; causes a forward declaration error!? - options=NULL; + options=NULL; // open codec //if ( avcodec_open2(codecCtx, codec,&options); // < 0) ofLog(OF_LOG_ERROR, "ofxMovieExproter: Could not open codec"); } -} + diff --git a/rotord/ofxMovieExporter.h b/rotord/ofxMovieExporter.h index ae6b306..82c574c 100644 --- a/rotord/ofxMovieExporter.h +++ b/rotord/ofxMovieExporter.h @@ -91,10 +91,7 @@ extern "C" //#include <libavutil/samplefmt.h> //#include <libavutil/timestamp.h> } - -namespace itg -{ - class ofxMovieExporter +class ofxMovieExporter //#ifdef _THREAD_CAPTURE // : public ofThread //#endif @@ -116,31 +113,16 @@ namespace itg // tested so far with... // codecId = CODEC_ID_MPEG4, container = "mp4" // codecId = CODEC_ID_MPEG2VIDEO, container = "mov" - void setup(int outW = OUT_W, int outH = OUT_H, int bitRate = BIT_RATE, int frameRate = FRAME_RATE, AVCodecID codecId = CODEC_ID, std::string container = CONTAINER); - void record(std::string filePrefix=FILENAME_PREFIX, std::string folderPath=""); + bool setup(int outW = OUT_W, int outH = OUT_H, int bitRate = BIT_RATE, int frameRate = FRAME_RATE, AVCodecID codecId = CODEC_ID, std::string container = CONTAINER); + bool record(std::string filePrefix=FILENAME_PREFIX, std::string folderPath=""); + void finishRecord(); void stop(); bool isRecording() const; - // set the recording area - // x, y is the upper left corner of the recording area, default: 0, 0 - // w x h is the area size, default: viewport width x height - void setRecordingArea(int x, int y, int w, int h); - void setRecordingArea(int rect); - - // reset the recording area to the size of the current viewport (screen, FBO, etc) - void resetRecordingArea(); - - // get the recording area as a rectangle - int getRecordingArea(); - // set an external pixel source, assumes 3 Byte RGB // also sets the recording size but does not crop to the recording area void setPixelSource(unsigned char* pixels, int w, int h); - // reset the pixel source and record from the screen - // also resets the recording size to the viewport width - void resetPixelSource(); - // get the number files that have been captured so far int getNumCaptures(); @@ -151,6 +133,8 @@ namespace itg inline int getRecordingWidth() {return outW;} inline int getRecordingHeight() {return outH;} + void encodeFrame(char *pixels); + private: //#ifdef _THREAD_CAPTURE // void threadedFunction(); @@ -163,9 +147,8 @@ namespace itg void allocateMemory(); void clearMemory(); - void checkFrame();//ofEventArgs& args); void encodeFrame(); - void finishRecord(); + std::string container; AVCodecID codecId; @@ -203,7 +186,3 @@ namespace itg unsigned char* pixelSource; }; - inline bool ofxMovieExporter::isRecording() const { return recording; } -} - -namespace Apex = itg; diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index ee170f0..cffb929 100755 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -486,6 +486,19 @@ bool Graph::load(string &filename){ } else cerr << "Rotor: linking input " << i2 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl; } + int n3=xml.getNumTags("image_input"); + for (int i3=0;i3<n3;i3++){ + nodes[nodeID]->create_image_input(xml.getValue("image_input","",i3)); + string fromID=xml.getAttribute("image_input","from","",i2); + if (nodes.find(fromID)!=nodes.end()) { + if (!nodes[nodeID]->inputs[i3]->connect((Image_node*)nodes[fromID])){ + cerr << "Rotor: graph loader cannot connect input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl; + return false; + } + else cerr << "Rotor: linked input " << i3 << " of node '" << nodeID << "' to node '" << fromID << "'" << endl; + } + else cerr << "Rotor: linking input " << i3 << " of node: '" << nodeID << "', cannot find target '" << fromID << "'" << endl; + } xml.popTag(); } } @@ -507,6 +520,7 @@ Node_factory::Node_factory(){ add_type("divide",new Signal_divide()); add_type("bang",new Is_new_integer()); add_type("signal_output",new Signal_output()); + add_type("testcard",new Testcard()); add_type("video_output",new Video_output()); } bool Audio_thumbnailer::init(int _channels,int _bits,int _samples,int _rate) { @@ -742,18 +756,47 @@ bool Video_output::render(const float duration, const float framerate,const stri */ bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename){ + // + //setup defaults + int outW=640; + int outH=480; + int bitRate=4000000; + int frameRate=25; + AVCodecID codecId=AV_CODEC_ID_H264; + std::string container ="mov"; + + + if (exporter->setup(outW,outH,bitRate,frameRate,codecId,container)) { + if (exporter->record(output_filename)) { + + cerr << "Rotor: Video_output rendering " << duration << " seconds at " << framerate << " fps" << endl; + float step=1.0f/framerate; + float v=0.0f; + for (float f=0.0f;f<duration;f+=step) { + exporter->encodeFrame(get_output(Frame_spec(f,framerate,outW,outH))->RGBdata); + } + exporter->finishRecord(); + return true; + } + } + + return false; +} + +//new version from libav examples +/* AVOutputFormat *fmt; AVFormatContext *oc; AVStream *audio_st, *video_st; double audio_pts, video_pts; int i; - /* Initialize libavcodec, and register all codecs and formats. */ + //Initialize libavcodec, and register all codecs and formats. // av_register_all(); //think about this: when to register and unregister? - /* Autodetect the output format from the name. default is MPEG. */ + //Autodetect the output format from the name. default is MPEG. // fmt = av_guess_format(NULL, output_filename.c_str(), NULL); if (!fmt) { printf("Could not deduce output format from file extension: using MPEG.\n"); @@ -764,7 +807,7 @@ bool Video_output::render(const float duration, const float framerate,const stri return false; } - /* Allocate the output media context. */ + //Allocate the output media context. // oc = avformat_alloc_context(); if (!oc) { cerr <<"Rotor: memory error"<< endl; @@ -773,8 +816,8 @@ bool Video_output::render(const float duration, const float framerate,const stri oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filename); - /* Add the audio and video streams using the default format codecs - * and initialize the codecs. */ + //Add the audio and video streams using the default format codecs + * and initialize the codecs. // video_st = NULL; audio_st = NULL; if (fmt->video_codec != AV_CODEC_ID_NONE) { @@ -784,8 +827,8 @@ bool Video_output::render(const float duration, const float framerate,const stri audio_st = add_audio_stream(oc, fmt->audio_codec); } - /* Now that all the parameters are set, we can open the audio and - * video codecs and allocate the necessary encode buffers. */ + //Now that all the parameters are set, we can open the audio and + * video codecs and allocate the necessary encode buffers. // if (video_st) open_video(oc, video_st); if (audio_st) @@ -793,19 +836,19 @@ bool Video_output::render(const float duration, const float framerate,const stri av_dump_format(oc, 0, filename, 1); - /* open the output file, if needed */ + //open the output file, if needed // if (!(fmt->flags & AVFMT_NOFILE)) { if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) { - fprintf(stderr, "Could not open '%s'\n", filename); - return 1; + cerr <<"Could not open "<<output_filename<<endl; + return false; } } - /* Write the stream header, if any. */ + //Write the stream header, if any. // avformat_write_header(oc, NULL); for (;;) { - /* Compute current audio and video time. */ + //Compute current audio and video time. // if (audio_st) audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den; else @@ -821,7 +864,7 @@ bool Video_output::render(const float duration, const float framerate,const stri (!video_st || video_pts >= STREAM_DURATION)) break; - /* write interleaved audio and video frames */ + //write interleaved audio and video frames // if (!video_st || (video_st && audio_st && audio_pts < video_pts)) { write_audio_frame(oc, audio_st); } else { @@ -829,30 +872,33 @@ bool Video_output::render(const float duration, const float framerate,const stri } } - /* Write the trailer, if any. The trailer must be written before you - * close the CodecContexts open when you wrote the header; otherwise - * av_write_trailer() may try to use memory that was freed on - * av_codec_close(). */ - av_write_trailer(oc); + //Write the trailer, if any. The trailer must be written before you + // close the CodecContexts open when you wrote the header; otherwise + // av_write_trailer() may try to use memory that was freed on + // av_codec_close(). // + //av_write_trailer(oc); - /* Close each codec. */ + //Close each codec. // if (video_st) close_video(oc, video_st); if (audio_st) close_audio(oc, audio_st); - /* Free the streams. */ + //Free the streams. // for (i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) - /* Close the output file. */ + //Close the output file. // avio_close(oc->pb); - /* free the stream */ + //free the stream // av_free(oc); - return 0; -}
\ No newline at end of file + return true; + */ + + + diff --git a/rotord/rotor.h b/rotord/rotor.h index 9728909..4a6c8d3 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -153,6 +153,16 @@ namespace Rotor { return Time_spec(seconds-(1.0f/framerate),framerate); } }; + class Frame_spec{ + public: + Frame_spec(float _time,float _framerate,int _w,int _h){ time=_time; framerate=_framerate; w=_w; h=_h;}; + float time; + float framerate; + int h,w; + Frame_spec lastframe(){ + return Frame_spec(time-(1.0f/framerate),framerate,w,h); + } + }; class Render_status{ public: int id; @@ -177,7 +187,8 @@ namespace Rotor { }; class Image_input: public Input{ public: - + bool connect(Image_node* source); + Image_input(const string &_desc): Input(_desc){}; }; class Signal_input: public Input{ public: @@ -205,7 +216,46 @@ namespace Rotor { } }; class Image{ - char* data; + public: + Image(){ + zero(); + }; + Image(int _w,int _h){ + setup(_w,_h); + }; + ~Image() { + free(); + }; + void free(){ + if (RGBdata) delete[] RGBdata; + if (Adata) delete[] Adata; + if (Zdata) delete[] Zdata; + zero(); + } + void zero(){ + RGBdata=nullptr; + Adata=nullptr; + Zdata=nullptr; + w=0; + h=0; + } + bool setup(int _w,int _h){ + if (w!=_w||h!=_h){ + free(); + w=_w; + h=_h; + RGBdata=new uint8_t[w*h*3]; + Adata=new uint8_t[w*h]; + Zdata=new uint16_t[w*h]; + return true; + } + else return false; + } + uint8_t *RGBdata; + uint8_t *Adata; + uint16_t *Zdata; + private: + int h,w; }; class Signal_node: public Node{ public: @@ -214,13 +264,13 @@ namespace Rotor { class Image_node: public Node{ public: vector<Image_input> image_inputs; //image node also has image inputs and outputs - Image* get_output(const Time_spec &time){ //sample implementation + Image *get_output(const Frame_spec &frame){ //sample implementation //do something with the inputs //and then - return ((Image_node*)image_inputs[0].connection)->get_output(time); + return ((Image_node*)image_inputs[0].connection)->get_output(frame); } - void get_preview(const Time_spec &time); - Image* image; //this can be privately allocated or just passed on as the node see fit + Image *get_preview(const Frame_spec &frame); + Image *image; //this can be privately allocated or just passed on as the node see fit private: float image_time; }; @@ -315,14 +365,45 @@ namespace Rotor { else return 0.0f; } }; + class Testcard: public Image_node { + public: + Testcard(){}; + Testcard(map<string,string> &settings) { + base_settings(settings); + }; + Testcard* clone(map<string,string> &_settings) { return new Testcard(_settings);}; + Image *get_output(const Frame_spec &frame){ + if (image->setup(frame.w,frame.h)) { + //create testcard + float ws=(255.0f/frame.w); + float hs=(255.0f/frame.h); + for (int i=0;i<frame.h;i++){ + for (int j=0;j<frame.w;j++){ + image->RGBdata[i*frame.w+j]=(uint8_t)(i*hs); + image->RGBdata[i*frame.w+j+1]=(uint8_t)(j*ws); + image->RGBdata[i*frame.w+j+2]=(uint8_t)(0); + image->Adata[i*frame.w+j]=(uint8_t)255; + image->Zdata[i*frame.w+j]=(uint16_t)512; //1.0 in fixed point 8.8 bits + } + } + } + return image; + } + private: + Image *image; + }; class Video_output: public Image_node { public: Video_output(){}; Video_output(map<string,string> &settings) { base_settings(settings); + exporter=new ofxMovieExporter(); }; 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); + + private: + ofxMovieExporter *exporter; }; //------------------------------------------------------------------- class Node_factory{ @@ -448,6 +529,6 @@ namespace Rotor { /* coding style -Types begin with capitals 'CamelCase' +Types begin with capitals 'New_type' variables/ instances use lower case with underscore as a seperator */ |
