summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Redfern <tim@herge.(none)>2013-04-24 16:42:42 +0100
committerTim Redfern <tim@herge.(none)>2013-04-24 16:42:42 +0100
commit7cd6f032cc0e10edcd6bebedfd2e0de38ef2d40a (patch)
tree61f13f30ee4bfe40958aaab85a65fd41c6875b0d
parenta2c6354640f24db3484ccf486c2c0cbd08808e60 (diff)
uuencode functionality in place
-rw-r--r--rotord/Pixels.h27
-rw-r--r--rotord/gstvideoloader.cpp619
-rw-r--r--rotord/gstvideoloader.h12
-rwxr-xr-xrotord/rotor.cpp20
-rwxr-xr-xrotord/rotor.h6
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;