diff options
| author | Tim Redfern <tim@herge.(none)> | 2013-04-24 16:42:42 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@herge.(none)> | 2013-04-24 16:42:42 +0100 |
| commit | 7cd6f032cc0e10edcd6bebedfd2e0de38ef2d40a (patch) | |
| tree | 61f13f30ee4bfe40958aaab85a65fd41c6875b0d | |
| parent | a2c6354640f24db3484ccf486c2c0cbd08808e60 (diff) | |
uuencode functionality in place
| -rw-r--r-- | rotord/Pixels.h | 27 | ||||
| -rw-r--r-- | rotord/gstvideoloader.cpp | 619 | ||||
| -rw-r--r-- | rotord/gstvideoloader.h | 12 | ||||
| -rwxr-xr-x | rotord/rotor.cpp | 20 | ||||
| -rwxr-xr-x | rotord/rotor.h | 6 |
5 files changed, 675 insertions, 9 deletions
diff --git a/rotord/Pixels.h b/rotord/Pixels.h new file mode 100644 index 0000000..84942af --- /dev/null +++ b/rotord/Pixels.h @@ -0,0 +1,27 @@ +#include <stdint.h> +#include <algorithm> +//for now always uint8_t* rather than templated + +class Pixels{ + public: + ~Pixels(); + void allocate(int w, int h, int channels); + bool isAllocated() const; + void setFromExternalPixels(uint8_t * newPixels,int w, int h, int channels); + uint8_t * getPixels(); + int getWidth() const; + int getHeight() const; + void clear(); + void swap(Pixels & pix); + int getBytesPerPixel() const; + int getNumChannels() const; + void set(uint8_t val); + private: + uint8_t * pixels; + int width; + int height; + int channels; + bool bAllocated; + bool pixelsOwner; // if set from external data don't delete it +}; + diff --git a/rotord/gstvideoloader.cpp b/rotord/gstvideoloader.cpp index 495181f..0cdc060 100644 --- a/rotord/gstvideoloader.cpp +++ b/rotord/gstvideoloader.cpp @@ -164,4 +164,623 @@ void ofGstUtils::setFrameByFrame(bool _bFrameByFrame){ bool ofGstUtils::isFrameByFrame(){ return bFrameByFrame; +} + +bool ofGstUtils::startPipeline(){ + + bPaused = true; + speed = 1.0f; + + + if(gst_element_set_state (GST_ELEMENT(gstPipeline), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { + cerr<< "GStreamer: unable to set pipeline to ready\n"; + + return false; + } + if(gst_element_get_state (GST_ELEMENT(gstPipeline), NULL, NULL, 10 * GST_SECOND)==GST_STATE_CHANGE_FAILURE){ + cerr<< "GStreamer: unable to get pipeline to ready\n"; + return false; + } + + // pause the pipeline + if(gst_element_set_state(GST_ELEMENT(gstPipeline), GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { + cerr<< "GStreamer: unable to set pipeline to paused\n"; + + return false; + } + + // wait for paused state to query the duration + if(!isStream){ + GstState state = GST_STATE_PAUSED; + if(gst_element_get_state(gstPipeline,&state,NULL,2*GST_SECOND)==GST_STATE_CHANGE_FAILURE){ + cerr<< "GStreamer: unable to get pipeline to paused\n"; + return false; + } + bPlaying = true; + bLoaded = true; + } + + + + if(isAppSink){ + cerr << "attaching callbacks\n"; + // set the appsink to not emit signals, we are using callbacks instead + // and frameByFrame to get buffers by polling instead of callback + g_object_set (G_OBJECT (gstSink), "emit-signals", FALSE, "sync", !bFrameByFrame, (void*)NULL); + + if(!bFrameByFrame){ + GstAppSinkCallbacks gstCallbacks; + gstCallbacks.eos = &on_eos_from_source; + gstCallbacks.new_preroll = &on_new_preroll_from_source; + gstCallbacks.new_buffer = &on_new_buffer_from_source; + + gst_app_sink_set_callbacks(GST_APP_SINK(gstSink), &gstCallbacks, this, NULL); + } + + } + + if(!isStream){ + setSpeed(1.0); + } + + //ofAddListener(ofEvents().update,this,&ofGstUtils::update); + + return true; +} + +void ofGstUtils::play(){ + setPaused(false); + + //this is if we set the speed first but it only can be set when we are playing. + if(!isStream) setSpeed(speed); +} + +void ofGstUtils::setPaused(bool _bPause){ + bPaused = _bPause; + //timeLastIdle = ofGetElapsedTimeMillis(); + if(bLoaded){ + if(bPlaying){ + if(bPaused){ + gst_element_set_state (gstPipeline, GST_STATE_PAUSED); + }else{ + gst_element_set_state (gstPipeline, GST_STATE_PLAYING); + } + }else{ + GstState state = GST_STATE_PAUSED; + gst_element_set_state (gstPipeline, state); + gst_element_get_state(gstPipeline,&state,NULL,2*GST_SECOND); + if(!bPaused){ + gst_element_set_state (gstPipeline, GST_STATE_PLAYING); + } + bPlaying = true; + } + } +} + +void ofGstUtils::stop(){ + if(!bPlaying) return; + GstState state = GST_STATE_PAUSED; + if(!bPaused){ + gst_element_set_state (gstPipeline, state); + gst_element_get_state(gstPipeline,&state,NULL,2*GST_SECOND); + } + state = GST_STATE_READY; + gst_element_set_state (gstPipeline, state); + gst_element_get_state(gstPipeline,&state,NULL,2*GST_SECOND); + bPlaying = false; + bPaused = true; +} + +float ofGstUtils::getPosition(){ + if(gstPipeline){ + gint64 pos=0; + GstFormat format=GST_FORMAT_TIME; + if(!gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos)){ + cerr<<"GStreamer: cannot query position\n"; + return -1; + } + return (float)pos/(float)durationNanos; + }else{ + return -1; + } +} + +float ofGstUtils::getSpeed(){ + return speed; +} + +float ofGstUtils::getDuration(){ + return (float)getDurationNanos()/(float)GST_SECOND; +} + +int64_t ofGstUtils::getDurationNanos(){ + GstFormat format = GST_FORMAT_TIME; + + if(!gst_element_query_duration(getPipeline(),&format,&durationNanos)) + cerr<<"GStreamer: cannot query time duration\n"; + + return durationNanos; + +} +bool ofGstUtils::getIsMovieDone(){ + if(isAppSink){ + return gst_app_sink_is_eos(GST_APP_SINK(gstSink)); + }else{ + return bIsMovieDone; + } +} + +void ofGstUtils::setPosition(float pct){ + //pct = CLAMP(pct, 0,1);// check between 0 and 1; + GstFormat format = GST_FORMAT_TIME; + GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH); + gint64 pos = (guint64)((double)pct*(double)durationNanos); + + /*if(bPaused){ + seek_lock(); + gst_element_set_state (gstPipeline, GST_STATE_PLAYING); + posChangingPaused=true; + seek_unlock(); + }*/ + if(speed>0){ + if(!gst_element_seek(GST_ELEMENT(gstPipeline),speed, format, + flags, + GST_SEEK_TYPE_SET, + pos, + GST_SEEK_TYPE_SET, + -1)) { + cerr<<"GStreamer: unable to seek\n"; + } + }else{ + if(!gst_element_seek(GST_ELEMENT(gstPipeline),speed, format, + flags, + GST_SEEK_TYPE_SET, + 0, + GST_SEEK_TYPE_SET, + pos)) { + cerr<<"GStreamer: unable to seek\n"; + } + } +} + +void ofGstUtils::setVolume(float volume){ + gdouble gvolume = volume; + g_object_set(G_OBJECT(gstPipeline), "volume", gvolume, (void*)NULL); +} + +void ofGstUtils::setLoopState(ofLoopType state){ + loopMode = state; +} + +void ofGstUtils::setSpeed(float _speed){ + GstFormat format = GST_FORMAT_TIME; + GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_SKIP | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH); + gint64 pos; + + if(_speed==0){ + gst_element_set_state (gstPipeline, GST_STATE_PAUSED); + return; + } + + if(!gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos) || pos<0){ + //ofLog(OF_LOG_ERROR,"GStreamer: cannot query position"); + return; + } + + speed = _speed; + //pos = (float)gstData.lastFrame * (float)fps_d / (float)fps_n * GST_SECOND; + + if(!bPaused) + gst_element_set_state (gstPipeline, GST_STATE_PLAYING); + + if(speed>0){ + if(!gst_element_seek(GST_ELEMENT(gstPipeline),speed, format, + flags, + GST_SEEK_TYPE_SET, + pos, + GST_SEEK_TYPE_SET, + -1)) { + cerr<<"GStreamer: unable to change speed\n"; + } + }else{ + if(!gst_element_seek(GST_ELEMENT(gstPipeline),speed, format, + flags, + GST_SEEK_TYPE_SET, + 0, + GST_SEEK_TYPE_SET, + pos)) { + cerr<<"GStreamer: unable to change speed\n"; + } + } + + cerr<<"Gstreamer: speed change to"<< speed<<endl; + +} + +void ofGstUtils::close(){ + if(bPlaying){ + stop(); + } + if(bLoaded){ + gst_element_set_state(GST_ELEMENT(gstPipeline), GST_STATE_NULL); + gst_element_get_state(gstPipeline,NULL,NULL,2*GST_SECOND); + // gst_object_unref(gstSink); this crashes, why?? + + //ofEventArgs args; + //update(args); + + gst_object_unref(gstPipeline); + gstPipeline = NULL; + gstSink = NULL; + } + + bLoaded = false; + //ofRemoveListener(ofEvents().update,this,&ofGstUtils::update); +} + +static string getName(GstState state){ + switch(state){ + case GST_STATE_VOID_PENDING: + return "void pending"; + case GST_STATE_NULL: + return "null"; + case GST_STATE_READY: + return "ready"; + case GST_STATE_PAUSED: + return "paused"; + case GST_STATE_PLAYING: + return "playing"; + default: + return ""; + } +} + +void ofGstUtils::update(){ //ofEventArgs & args){ + gstHandleMessage(); +} + +void ofGstUtils::gstHandleMessage(){ + GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(gstPipeline)); + while(gst_bus_have_pending(bus)) { + GstMessage* msg = gst_bus_pop(bus); + if(appsink && appsink->on_message(msg)) continue; + + cerr << "GStreamer: Got " << GST_MESSAGE_TYPE_NAME(msg) << " message from " << GST_MESSAGE_SRC_NAME(msg)<<endl; + + switch (GST_MESSAGE_TYPE (msg)) { + + case GST_MESSAGE_BUFFERING: + gint pctBuffered; + gst_message_parse_buffering(msg,&pctBuffered); + cerr<<"GStreamer: buffering"<<pctBuffered<<endl; + /*if(pctBuffered<100){ + gst_element_set_state (gstPipeline, GST_STATE_PAUSED); + }else if(!bPaused){ + gst_element_set_state (gstPipeline, GST_STATE_PLAYING); + }*/ + break; + + case GST_MESSAGE_DURATION:{ + GstFormat format=GST_FORMAT_TIME; + gst_element_query_duration(gstPipeline,&format,&durationNanos); + }break; + + case GST_MESSAGE_STATE_CHANGED:{ + GstState oldstate, newstate, pendstate; + gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate); + if(isStream && newstate==GST_STATE_PAUSED && !bPlaying ){ + bLoaded = true; + bPlaying = true; + if(!bPaused){ + cout << "setting stream pipeline to play " << endl; + play(); + } + } + cerr << "GStreamer: " << GST_MESSAGE_SRC_NAME(msg) << " state changed from " << getName(oldstate) + " to " + getName(newstate) + " (" + getName(pendstate) + ")"; + }break; + + case GST_MESSAGE_ASYNC_DONE: + cerr<<"GStreamer: async done"<<endl; + break; + + case GST_MESSAGE_ERROR: { + GError *err; + gchar *debug; + gst_message_parse_error(msg, &err, &debug); + + cerr<<"GStreamer Plugin: Embedded video playback halted; module "<<gst_element_get_name(GST_MESSAGE_SRC (msg))<< "reported: "<<err->message<<endl; + + g_error_free(err); + g_free(debug); + + gst_element_set_state(GST_ELEMENT(gstPipeline), GST_STATE_NULL); + + }break; + + case GST_MESSAGE_EOS: + cerr<<"GStreamer: end of the stream.\n"; + bIsMovieDone = true; + + if(appsink && !isAppSink) appsink->on_eos(); + + switch(loopMode){ + + case OF_LOOP_NORMAL:{ + GstFormat format = GST_FORMAT_TIME; + GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); + gint64 pos; + gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); + + if(!gst_element_seek(GST_ELEMENT(gstPipeline), + speed, + format, + flags, + GST_SEEK_TYPE_SET, + 0, + GST_SEEK_TYPE_SET, + durationNanos)) { + cerr<<"GStreamer: unable to seek\n"; + } + }break; + + case OF_LOOP_PALINDROME:{ + GstFormat format = GST_FORMAT_TIME; + GstSeekFlags flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH |GST_SEEK_FLAG_KEY_UNIT); + gint64 pos; + gst_element_query_position(GST_ELEMENT(gstPipeline),&format,&pos); + float loopSpeed; + if(pos>0) + loopSpeed=-speed; + else + loopSpeed=speed; + if(!gst_element_seek(GST_ELEMENT(gstPipeline), + loopSpeed, + GST_FORMAT_UNDEFINED, + flags, + GST_SEEK_TYPE_NONE, + 0, + GST_SEEK_TYPE_NONE, + 0)) { + cerr<<"GStreamer: unable to seek\n"; + } + }break; + + default: + break; + } + + break; + + default: + cerr << "GStreamer: unhandled message from " << GST_MESSAGE_SRC_NAME(msg)<<endl; + break; + } + gst_message_unref(msg); + } + + gst_object_unref(GST_OBJECT(bus)); +} + +GstElement * ofGstUtils::getPipeline(){ + return gstPipeline; +} + +GstElement * ofGstUtils::getSink(){ + return gstSink; +} + +void ofGstUtils::setSinkListener(ofGstAppSink * appsink_){ + appsink = appsink_; +} + +unsigned long ofGstUtils::getMinLatencyNanos(){ + GstClockTime minlat, maxlat; + GstQuery * q = gst_query_new_latency(); + if (gst_element_query (gstPipeline, q)) { + gboolean live; + gst_query_parse_latency (q, &live, &minlat, &maxlat); + } + gst_query_unref (q); + return minlat; +} + +unsigned long ofGstUtils::getMaxLatencyNanos(){ + GstClockTime minlat, maxlat; + GstQuery * q = gst_query_new_latency(); + if (gst_element_query (gstPipeline, q)) { + gboolean live; + gst_query_parse_latency (q, &live, &minlat, &maxlat); + } + gst_query_unref (q); + return maxlat; +} + + + +//------------------------------------------------- +//----------------------------------------- videoUtils +//------------------------------------------------- + +ofGstVideoUtils::ofGstVideoUtils(){ + bIsFrameNew = false; + bHavePixelsChanged = false; + bBackPixelsChanged = false; + buffer = 0; + prevBuffer = 0; +} + +ofGstVideoUtils::~ofGstVideoUtils(){ + close(); +} + +void ofGstVideoUtils::close(){ + ofGstUtils::close(); + //Poco::ScopedLock<ofMutex> lock(mutex); + pixels.clear(); + backPixels.clear(); + bIsFrameNew = false; + bHavePixelsChanged = false; + bBackPixelsChanged = false; + if(prevBuffer) gst_buffer_unref (prevBuffer); + if(buffer) gst_buffer_unref (buffer); + prevBuffer = 0; + buffer = 0; +} + +bool ofGstVideoUtils::isFrameNew(){ + return bIsFrameNew; +} + +unsigned char * ofGstVideoUtils::getPixels(){ + return pixels.getPixels(); +} + +/* +ofPixelsRef ofGstVideoUtils::getPixelsRef(){ + return pixels; +} +*/ + +void ofGstVideoUtils::update(){ + if (isLoaded()){ + if(!isFrameByFrame()){ + //mutex.lock(); + bHavePixelsChanged = bBackPixelsChanged; + if (bHavePixelsChanged){ + bBackPixelsChanged=false; + pixels.swap(backPixels); + if(prevBuffer) gst_buffer_unref (prevBuffer); + prevBuffer = buffer; + } + + //mutex.unlock(); + }else{ + GstBuffer *buffer; + + //get the buffer from appsink + if(isPaused()) buffer = gst_app_sink_pull_preroll (GST_APP_SINK (getSink())); + else buffer = gst_app_sink_pull_buffer (GST_APP_SINK (getSink())); + + if(buffer){ + if(pixels.isAllocated()){ + if(prevBuffer) gst_buffer_unref (prevBuffer); + //memcpy (pixels.getPixels(), GST_BUFFER_DATA (buffer), size); + pixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); + prevBuffer = buffer; + bHavePixelsChanged=true; + } + } + } + }else{ + cerr<<"ofGstVideoUtils not loaded\n"; + } + bIsFrameNew = bHavePixelsChanged; + bHavePixelsChanged = false; +} + +float ofGstVideoUtils::getHeight(){ + return pixels.getHeight(); +} + +float ofGstVideoUtils::getWidth(){ + return pixels.getWidth(); +} + +bool ofGstVideoUtils::setPipeline(string pipeline, int bpp, bool isStream, int w, int h){ + string caps; + if(bpp==8) + caps="video/x-raw-gray, depth=8, bpp=8"; + else if(bpp==32) + caps="video/x-raw-rgb, depth=24, bpp=32, endianness=4321, red_mask=0xff0000, green_mask=0x00ff00, blue_mask=0x0000ff, alpha_mask=0x000000ff"; + else + caps="video/x-raw-rgb, depth=24, bpp=24, endianness=4321, red_mask=0xff0000, green_mask=0x00ff00, blue_mask=0x0000ff, alpha_mask=0x000000ff"; + + if(w!=-1 && h!=-1){ + caps+=", width=" + ofToString(w) + ", height=" + ofToString(h); + } + + gchar* pipeline_string = + g_strdup((pipeline + " ! appsink name=ofappsink caps=\"" + caps + "\"").c_str()); // caps=video/x-raw-rgb + + if((isStream && (w==-1 || h==-1)) || allocate(w,h,bpp)){ + return setPipelineWithSink(pipeline_string,"ofappsink",isStream); + }else{ + return false; + } +} + +bool ofGstVideoUtils::allocate(int w, int h, int _bpp){ + pixels.allocate(w,h,_bpp/8); + backPixels.allocate(w,h,_bpp/8); + prevBuffer = 0; + pixels.set(0); + + bHavePixelsChanged = pixels.isAllocated(); + return pixels.isAllocated(); +} + +GstFlowReturn ofGstVideoUtils::preroll_cb(GstBuffer * _buffer){ + guint size; + + size = GST_BUFFER_SIZE (_buffer); + if(pixels.isAllocated() && pixels.getWidth()*pixels.getHeight()*pixels.getBytesPerPixel()!=(int)size){ + cerr << "on_preproll: error preroll buffer size: " << size<< "!= init size: " << (pixels.getWidth()*pixels.getHeight()*pixels.getBytesPerPixel()) << endl; + gst_buffer_unref (_buffer); + return GST_FLOW_ERROR; + } + //mutex.lock(); + if(bBackPixelsChanged && buffer) gst_buffer_unref (buffer); + if(pixels.isAllocated()){ + buffer = _buffer; + backPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); + //eventPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); + bBackPixelsChanged=true; + //mutex.unlock(); + //ofNotifyEvent(prerollEvent,eventPixels); + }else{ + if(isStream && appsink){ + appsink->on_stream_prepared(); + }else{ + cerr << "received a preroll without allocation\n"; + } + //mutex.unlock(); + } + return ofGstUtils::preroll_cb(_buffer); +} + +GstFlowReturn ofGstVideoUtils::buffer_cb(GstBuffer * _buffer){ + + guint size; + + size = GST_BUFFER_SIZE (_buffer); + if(pixels.isAllocated() && pixels.getWidth()*pixels.getHeight()*pixels.getBytesPerPixel()!=(int)size){ + cerr<<"on_preproll: error on new buffer, buffer size: " <<size<<"!= init size: "<<(pixels.getWidth()*pixels.getHeight()*pixels.getBytesPerPixel())<<endl; + gst_buffer_unref (_buffer); + return GST_FLOW_ERROR; + } + //mutex.lock(); + if(bBackPixelsChanged && buffer) gst_buffer_unref (buffer); + if(pixels.isAllocated()){ + buffer = _buffer; + backPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); + //eventPixels.setFromExternalPixels(GST_BUFFER_DATA (buffer),pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); + bBackPixelsChanged=true; + //mutex.unlock(); + //ofNotifyEvent(bufferEvent,eventPixels); + }else{ + if(isStream && appsink){ + appsink->on_stream_prepared(); + }else{ + cerr<<"received a preroll without allocation\n"; + } + //mutex.unlock(); + } + + return ofGstUtils::buffer_cb(buffer); +} + +void ofGstVideoUtils::eos_cb(){ + ofGstUtils::eos_cb(); + //ofEventArgs args; + //ofNotifyEvent(eosEvent,args); }
\ No newline at end of file diff --git a/rotord/gstvideoloader.h b/rotord/gstvideoloader.h index a2dc086..66b4c9c 100644 --- a/rotord/gstvideoloader.h +++ b/rotord/gstvideoloader.h @@ -2,6 +2,8 @@ #include <iostream> #include <gst/gstpad.h> +#include "Pixels.h" +#include "ofUtils.h" enum ofLoopType{ OF_LOOP_NONE=0x01, @@ -59,6 +61,8 @@ public: virtual void eos_cb(); static void startGstMainLoop(); + void update(); + protected: ofGstAppSink * appsink; bool isStream; @@ -96,20 +100,23 @@ public: bool isFrameNew(); unsigned char * getPixels(); //ofPixelsRef getPixelsRef(); - void update(); + float getHeight(); float getWidth(); void close(); + void update(); + protected: GstFlowReturn preroll_cb(GstBuffer * buffer); GstFlowReturn buffer_cb(GstBuffer * buffer); void eos_cb(); - + Pixels pixels; + Pixels backPixels; //ofPixels pixels; // 24 bit: rgb //ofPixels backPixels; //ofPixels eventPixels; @@ -119,6 +126,7 @@ private: bool bBackPixelsChanged; //ofMutex mutex; GstBuffer * buffer, *prevBuffer; + }; diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index eb86c27..da8f811 100755 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -572,9 +572,9 @@ int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ if (sample==samples_per_column) { //finished a column //get root-mean double mean=pow(accum/samples,0.5); - if (column==0) { - cerr << "first column total: "<< accum << " in " << samples << " samples, average " << (accum/samples)<<endl; - } + //if (column==0) { + // cerr << "first column total: "<< accum << " in " << samples << " samples, average " << (accum/samples)<<endl; + //} int colheight=height*mean*0.5; int hh=height>>1; for (int i=0;i<height;i++) { @@ -589,14 +589,24 @@ int Audio_thumbnailer::process_frame(uint8_t *_data,int samples_in_frame){ return out_sample; } string Audio_thumbnailer::print(){ - string output; + //base64 encode the image data output it + + stringstream output; + Poco::Base64Encoder *enc=new Poco::Base64Encoder(output); + + enc->write(data,width*height); + //tring output; + /* for (int j=0;j<height;j++) { for (int i=0;i<width;i++) { output+=data[j*width+i]<0x7f?"0":"1"; } output +="\n"; } - return output; + */ + enc->close(); + delete enc; + return output.str(); } bool Audio_analysis::init(int _channels,int _bits,int _samples, int _rate) { //need these to make sense of data diff --git a/rotord/rotor.h b/rotord/rotor.h index 997cd30..6ade885 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -65,6 +65,7 @@ main definitions of libavcodec.h are in utils.c #include "Poco/Random.h" #include "Poco/AutoPtr.h" #include "Poco/File.h" +#include "Poco/Base64Encoder.h" #include <iostream> using Poco::UUID; @@ -483,8 +484,8 @@ namespace Rotor { class Audio_thumbnailer: public Base_audio_processor { public: Audio_thumbnailer(){ - height=32; - width=64; //fit + height=128; + width=512; //fit data=new uint8_t[height*width]; memset(data,0,height*width); }; @@ -530,6 +531,7 @@ namespace Rotor { Poco::Mutex mutex; //lock for access from parent thread std::string audio_filename; std::string output_filename; + Audio_thumbnailer *audio_thumb; vampHost::QMAnalyser audio_analyser; Graph graph; |
