summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/Makefile10
-rw-r--r--rotord/gstvideoloader.cpp167
-rw-r--r--rotord/gstvideoloader.h147
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(){};
+};
+
+