diff options
| -rw-r--r-- | rotord/Makefile | 10 | ||||
| -rw-r--r-- | rotord/gstvideoloader.cpp | 167 | ||||
| -rw-r--r-- | rotord/gstvideoloader.h | 147 |
3 files changed, 320 insertions, 4 deletions
diff --git a/rotord/Makefile b/rotord/Makefile index 0895ed9..0f8e736 100644 --- a/rotord/Makefile +++ b/rotord/Makefile @@ -1,10 +1,14 @@ # The pre-processor and compiler options. + +#http://docs.gstreamer.com/display/GstSDK/Installing+on+Linux + MY_CFLAGS = -fpermissive -std=c++11 -Wno-error -I /opt/gstreamer-sdk/include/gstreamer-0.10/ -I /opt/gstreamer-sdk/include/glib-2.0 -I /opt/gstreamer-sdk/lib/glib-2.0/include -I /opt/gstreamer-sdk/include/libxml2 # -I ../ffmpeg -# The linker options. -MY_LIBS = -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil +# The linker options.libgstaasinklibgstaasink.so + +MY_LIBS = -lPocoNet -lPocoXML -lPocoUtil -lPocoFoundation -lvamp-hostsdk -lsndfile -L /usr/local/lib -lswscale -lavcodec -lavformat -lavfilter -lavdevice -lavutil -lgstreamer-0.10 -lglib-2.0 -lgstapp-0.10 #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! @@ -47,7 +51,7 @@ CXXFLAGS= #CC = $(CXX) # The command used to delete file. -#RM = rm -f +RM = rm -f ETAGS = etags ETAGSFLAGS = diff --git a/rotord/gstvideoloader.cpp b/rotord/gstvideoloader.cpp index e69de29..495181f 100644 --- a/rotord/gstvideoloader.cpp +++ b/rotord/gstvideoloader.cpp @@ -0,0 +1,167 @@ +#include "gstvideoloader.h" + +#include <gst/gst.h> +#include <gst/app/gstappsink.h> +#include <gst/video/video.h> + +#include <glib-object.h> +#include <glib.h> +#include <algorithm> + +using namespace std; + + + +void ofGstUtils::startGstMainLoop(){ + static bool initialized = false; + if(!initialized){ + g_main_loop_new (NULL, FALSE); + initialized=true; + } +} + +//------------------------------------------------- +//----------------------------------------- gstUtils +//------------------------------------------------- + +static bool plugin_registered = false; +static bool gst_inited = false; + + +// called when the appsink notifies us that there is a new buffer ready for +// processing + +static GstFlowReturn on_new_buffer_from_source (GstAppSink * elt, void * data){ + GstBuffer *buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt)); + return ((ofGstUtils*)data)->buffer_cb(buffer); +} + +static GstFlowReturn on_new_preroll_from_source (GstAppSink * elt, void * data){ + GstBuffer *buffer = gst_app_sink_pull_preroll(GST_APP_SINK (elt)); + return ((ofGstUtils*)data)->preroll_cb(buffer); +} + +static void on_eos_from_source (GstAppSink * elt, void * data){ + ((ofGstUtils*)data)->eos_cb(); +} + +static gboolean appsink_plugin_init (GstPlugin * plugin) +{ + gst_element_register (plugin, "appsink", GST_RANK_NONE, GST_TYPE_APP_SINK); + + return TRUE; +} + + +ofGstUtils::ofGstUtils() { + bLoaded = false; + speed = 1; + bPaused = false; + bIsMovieDone = false; + bPlaying = false; + loopMode = OF_LOOP_NONE; + bFrameByFrame = false; + + gstPipeline = NULL; + gstSink = NULL; + + durationNanos = 0; + + isAppSink = false; + isStream = false; + + appsink = NULL; + + if(!g_thread_supported()){ + g_thread_init(NULL); + } + if(!gst_inited){ + gst_init (NULL, NULL); + gst_inited=true; + cerr <<"ofGstUtils: gstreamer inited"<<endl; + } + if(!plugin_registered){ + gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, + "appsink", (char*)"Element application sink", + appsink_plugin_init, "0.1", "LGPL", "ofVideoPlayer", "openFrameworks", + "http://openframeworks.cc/"); + plugin_registered=true; + } + +} + +ofGstUtils::~ofGstUtils() { + close(); +} + +GstFlowReturn ofGstUtils::preroll_cb(GstBuffer * buffer){ + bIsMovieDone = false; + if(appsink) return appsink->on_preroll(buffer); + else return GST_FLOW_OK; +} + +GstFlowReturn ofGstUtils::buffer_cb(GstBuffer * buffer){ + bIsMovieDone = false; + if(appsink) return appsink->on_buffer(buffer); + else return GST_FLOW_OK; +} + +void ofGstUtils::eos_cb(){ + bIsMovieDone = true; + if(appsink) appsink->on_eos(); +} + +bool ofGstUtils::setPipelineWithSink(string pipeline, string sinkname, bool isStream){ + ofGstUtils::startGstMainLoop(); + + gchar* pipeline_string = + g_strdup((pipeline).c_str()); + + GError * error = NULL; + gstPipeline = gst_parse_launch (pipeline_string, &error); + + cerr << "gstreamer pipeline: " <<pipeline_string<<endl; + if(error!=NULL){ + cerr <<"couldnt create pipeline: " << string(error->message)<<endl; + return false; + } + + gstSink = gst_bin_get_by_name(GST_BIN(gstPipeline),sinkname.c_str()); + + if(!gstSink){ + cerr << "couldn't get sink from string pipeline"<<endl; + } + + return setPipelineWithSink(gstPipeline,gstSink,isStream); +} + +bool ofGstUtils::setPipelineWithSink(GstElement * pipeline, GstElement * sink, bool isStream_){ + ofGstUtils::startGstMainLoop(); + + gstPipeline = pipeline; + gstSink = sink; + isStream = isStream_; + + if(gstSink){ + gst_base_sink_set_sync(GST_BASE_SINK(gstSink), true); + } + + if(gstSink && string(gst_plugin_feature_get_name( GST_PLUGIN_FEATURE(gst_element_get_factory(gstSink))))=="appsink"){ + isAppSink = true; + }else{ + isAppSink = false; + } + + return startPipeline(); +} + +void ofGstUtils::setFrameByFrame(bool _bFrameByFrame){ + bFrameByFrame = _bFrameByFrame; + if(gstSink){ + g_object_set (G_OBJECT (gstSink), "sync", !bFrameByFrame, (void*)NULL); + } +} + +bool ofGstUtils::isFrameByFrame(){ + return bFrameByFrame; +}
\ No newline at end of file diff --git a/rotord/gstvideoloader.h b/rotord/gstvideoloader.h index 411fe6e..a2dc086 100644 --- a/rotord/gstvideoloader.h +++ b/rotord/gstvideoloader.h @@ -1 +1,146 @@ -#include <gst/gstpad.h>
\ No newline at end of file +#include <string> +#include <iostream> + +#include <gst/gstpad.h> + +enum ofLoopType{ + OF_LOOP_NONE=0x01, + OF_LOOP_PALINDROME=0x02, + OF_LOOP_NORMAL=0x03 +}; + +class ofGstAppSink; +typedef struct _GstElement GstElement; +typedef struct _GstBuffer GstBuffer; +typedef struct _GstMessage GstMessage; + +class ofGstUtils{ +public: + ofGstUtils(); + virtual ~ofGstUtils(); + + bool setPipelineWithSink(std::string pipeline, std::string sinkname="sink", bool isStream=false); + bool setPipelineWithSink(GstElement * pipeline, GstElement * sink, bool isStream=false); + + void play(); + void stop(); + void setPaused(bool bPause); + bool isPaused(){return bPaused;} + bool isLoaded(){return bLoaded;} + bool isPlaying(){return bPlaying;} + + float getPosition(); + float getSpeed(); + float getDuration(); + int64_t getDurationNanos(); + bool getIsMovieDone(); + + void setPosition(float pct); + void setVolume(float volume); + void setLoopState(ofLoopType state); + ofLoopType getLoopState(){return loopMode;} + void setSpeed(float speed); + + void setFrameByFrame(bool bFrameByFrame); + bool isFrameByFrame(); + + GstElement * getPipeline(); + GstElement * getSink(); + unsigned long getMinLatencyNanos(); + unsigned long getMaxLatencyNanos(); + + virtual void close(); + + void setSinkListener(ofGstAppSink * appsink); + + // callbacks to get called from gstreamer + virtual GstFlowReturn preroll_cb(GstBuffer * buffer); + virtual GstFlowReturn buffer_cb(GstBuffer * buffer); + virtual void eos_cb(); + + static void startGstMainLoop(); +protected: + ofGstAppSink * appsink; + bool isStream; + +private: + void gstHandleMessage(); + //void update(ofEventArgs & args); + bool startPipeline(); + + bool bPlaying; + bool bPaused; + bool bIsMovieDone; + bool bLoaded; + bool bFrameByFrame; + ofLoopType loopMode; + + GstElement * gstSink; + GstElement * gstPipeline; + + float speed; + int64_t durationNanos; + bool isAppSink; +}; + +class ofGstVideoUtils: public ofGstUtils{ +public: + + ofGstVideoUtils(); + virtual ~ofGstVideoUtils(); + + bool setPipeline(std::string pipeline, int bpp=24, bool isStream=false, int w=-1, int h=-1); + + bool allocate(int w, int h, int bpp); + + bool isFrameNew(); + unsigned char * getPixels(); + //ofPixelsRef getPixelsRef(); + void update(); + + float getHeight(); + float getWidth(); + + void close(); + + +protected: + GstFlowReturn preroll_cb(GstBuffer * buffer); + GstFlowReturn buffer_cb(GstBuffer * buffer); + void eos_cb(); + + + //ofPixels pixels; // 24 bit: rgb + //ofPixels backPixels; + //ofPixels eventPixels; +private: + bool bIsFrameNew; // if we are new + bool bHavePixelsChanged; + bool bBackPixelsChanged; + //ofMutex mutex; + GstBuffer * buffer, *prevBuffer; +}; + + +//------------------------------------------------- +//----------------------------------------- appsink listener +//------------------------------------------------- + +class ofGstAppSink{ +public: + virtual GstFlowReturn on_preroll(GstBuffer * buffer){ + return GST_FLOW_OK; + } + virtual GstFlowReturn on_buffer(GstBuffer * buffer){ + return GST_FLOW_OK; + } + virtual void on_eos(){} + + // return true to set the message as attended so upstream doesn't try to process it + virtual bool on_message(GstMessage* msg){return false;}; + + // pings when enough data has arrived to be able to get sink properties + virtual void on_stream_prepared(){}; +}; + + |
