summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rotord/gstvideoloader.cpp1142
-rw-r--r--rotord/gstvideoloader.h235
2 files changed, 0 insertions, 1377 deletions
diff --git a/rotord/gstvideoloader.cpp b/rotord/gstvideoloader.cpp
deleted file mode 100644
index 9d04daa..0000000
--- a/rotord/gstvideoloader.cpp
+++ /dev/null
@@ -1,1142 +0,0 @@
-#include "gstvideoloader.h"
-
-
-
-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", "gstvideoloader", "Rotor",
- "http://rotored.com/");
- 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;
-}
-
-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);
-}
-
-ofGstVideoPlayer::ofGstVideoPlayer(){
- nFrames = 0;
- //internalPixelFormat = OF_PIXELS_RGB;
- bIsStream = false;
- bIsAllocated = false;
- threadAppSink = false;
- videoUtils.setSinkListener(this);
-}
-
-ofGstVideoPlayer::~ofGstVideoPlayer(){
- close();
-}
-
-bool ofGstVideoPlayer::loadMovie(string name){
- close();
- /*
- if( name.find( "file://",0 ) != string::npos){
- bIsStream = false;
- }else if( name.find( "://",0 ) == string::npos){
- name = "file://"+ofToDataPath(name,true);
- bIsStream = false;
- }else{
- bIsStream = true;
- }
- */
- cerr<<"loading "<<name<<endl;
-
- ofGstUtils::startGstMainLoop();
-
-#if GST_VERSION_MAJOR==0
- GstElement * gstPipeline = gst_element_factory_make("playbin2","player");
-#else
- GstElement * gstPipeline = gst_element_factory_make("playbin","player");
-#endif
- g_object_set(G_OBJECT(gstPipeline), "uri", name.c_str(), (void*)NULL);
-
- // create the oF appsink for video rgb without sync to clock
- GstElement * gstSink = gst_element_factory_make("appsink", "app_sink");
-
- gst_base_sink_set_sync(GST_BASE_SINK(gstSink), true);
- gst_app_sink_set_max_buffers(GST_APP_SINK(gstSink), 8);
- gst_app_sink_set_drop (GST_APP_SINK(gstSink),true);
- gst_base_sink_set_max_lateness (GST_BASE_SINK(gstSink), -1);
-
-#if GST_VERSION_MAJOR==0
- int bpp;
- string mime;
- /*
- switch(internalPixelFormat){
- case OF_PIXELS_MONO:
- mime = "video/x-raw-gray";
- bpp = 8;
- break;
- case OF_PIXELS_RGB:
- mime = "video/x-raw-rgb";
- bpp = 24;
- break;
- case OF_PIXELS_RGBA:
- case OF_PIXELS_BGRA:
- mime = "video/x-raw-rgb";
- bpp = 32;
- break;
- default:
- mime = "video/x-raw-rgb";
- bpp=24;
- break;
- }
- */
- mime = "video/x-raw-rgb";
- bpp=24;
-
-
- GstCaps *caps = gst_caps_new_simple(mime.c_str(),
- "bpp", G_TYPE_INT, bpp,
- "depth", G_TYPE_INT, 24,
- "endianness",G_TYPE_INT,4321,
- "red_mask",G_TYPE_INT,0xff0000,
- "green_mask",G_TYPE_INT,0x00ff00,
- "blue_mask",G_TYPE_INT,0x0000ff,
- "alpha_mask",G_TYPE_INT,0x000000ff,
- NULL);
-#else
- int bpp;
- string mime="video/x-raw";
- string format;
- /*
- switch(internalPixelFormat){
- case OF_PIXELS_MONO:
- format = "GRAY8";
- bpp = 8;
- break;
- case OF_PIXELS_RGB:
- format = "RGB";
- bpp = 24;
- break;
- case OF_PIXELS_RGBA:
- format = "RGBA";
- bpp = 32;
- break;
- case OF_PIXELS_BGRA:
- format = "BGRA";
- bpp = 32;
- break;
- default:
- format = "RGB";
- bpp=24;
- break;
- }
- */
- format = "RGB";
- bpp=24;
-
- GstCaps *caps = gst_caps_new_simple(mime.c_str(),
- "format", G_TYPE_STRING, format.c_str(),
- /*"bpp", G_TYPE_INT, bpp,
- "depth", G_TYPE_INT, 24,
- "endianness",G_TYPE_INT,4321,
- "red_mask",G_TYPE_INT,0xff0000,
- "green_mask",G_TYPE_INT,0x00ff00,
- "blue_mask",G_TYPE_INT,0x0000ff,
- "alpha_mask",G_TYPE_INT,0x000000ff,*/
- NULL);
-#endif
-
-
- gst_app_sink_set_caps(GST_APP_SINK(gstSink), caps);
- gst_caps_unref(caps);
-
- if(threadAppSink){
- GstElement * appQueue = gst_element_factory_make("queue","appsink_queue");
- g_object_set(G_OBJECT(appQueue), "leaky", 0, "silent", 1, (void*)NULL);
- GstElement* appBin = gst_bin_new("app_bin");
- gst_bin_add(GST_BIN(appBin), appQueue);
- GstPad* appQueuePad = gst_element_get_static_pad(appQueue, "sink");
- GstPad* ghostPad = gst_ghost_pad_new("app_bin_sink", appQueuePad);
- gst_object_unref(appQueuePad);
- gst_element_add_pad(appBin, ghostPad);
-
- gst_bin_add_many(GST_BIN(appBin), gstSink, NULL);
- gst_element_link_many(appQueue, gstSink, NULL);
-
- g_object_set (G_OBJECT(gstPipeline),"video-sink",appBin,(void*)NULL);
- }else{
- g_object_set (G_OBJECT(gstPipeline),"video-sink",gstSink,(void*)NULL);
- }
-
-
- videoUtils.setPipelineWithSink(gstPipeline,gstSink,bIsStream);
- if(!bIsStream) return allocate(bpp);
- else return true;
-}
-
-void ofGstVideoPlayer::setThreadAppSink(bool threaded){
- threadAppSink = threaded;
-}
-
-
-bool ofGstVideoPlayer::allocate(int bpp){
- if(bIsAllocated) return true;
-
- guint64 durationNanos = videoUtils.getDurationNanos();
-
- nFrames = 0;
- if(GstPad* pad = gst_element_get_static_pad(videoUtils.getSink(), "sink")){
-#if GST_VERSION_MAJOR==0
- int width,height;
- if(gst_video_get_size(GST_PAD(pad), &width, &height)){
- if(!videoUtils.allocate(width,height,bpp)) return false;
- }else{
- cerr<<"GStreamer: cannot query width and height"<<endl;
- return false;
- }
-
- const GValue *framerate = gst_video_frame_rate(pad);
- fps_n=0;
- fps_d=0;
- if(framerate && GST_VALUE_HOLDS_FRACTION (framerate)){
- fps_n = gst_value_get_fraction_numerator (framerate);
- fps_d = gst_value_get_fraction_denominator (framerate);
- nFrames = (float)(durationNanos / GST_SECOND) * (float)fps_n/(float)fps_d;
- cerr<<"ofGstUtils: framerate:"<<fps_n<<"/"<<fps_d<<endl;
- }else{
- cerr<<"Gstreamer: cannot get framerate, frame seek won't work"<<endl;
- }
- bIsAllocated = true;
-#else
- if(GstCaps *caps = gst_pad_get_current_caps (GST_PAD (pad))){
- GstVideoInfo info;
- gst_video_info_init (&info);
- if (gst_video_info_from_caps (&info, caps)){
- if(!videoUtils.allocate(info.width,info.height,bpp)) return false;
- }else{
- cerr<<"GStreamer: cannot query width and height"<<endl;
- return false;
- }
-
- fps_n = info.fps_n;
- fps_d = info.fps_d;
- nFrames = (float)(durationNanos / GST_SECOND) * (float)fps_n/(float)fps_d;
- gst_caps_unref(caps);
- bIsAllocated = true;
- }else{
- cerr<<"GStreamer: cannot get pipeline caps"<<endl;
- bIsAllocated = false;
- }
-#endif
- gst_object_unref(GST_OBJECT(pad));
- }else{
- cerr<<"GStreamer: cannot get sink pad"<<endl;
- bIsAllocated = false;
- }
-
- return bIsAllocated;
-}
-
-void ofGstVideoPlayer::on_stream_prepared(){
- if(!bIsAllocated) allocate(24);
-}
-
-int ofGstVideoPlayer::getCurrentFrame(){
- int frame = 0;
-
- // zach I think this may fail on variable length frames...
- float pos = getPosition();
- if(pos == -1) return -1;
-
-
- float framePosInFloat = ((float)getTotalNumFrames() * pos);
- int framePosInInt = (int)framePosInFloat;
- float floatRemainder = (framePosInFloat - framePosInInt);
- if (floatRemainder > 0.5f) framePosInInt = framePosInInt + 1;
- //frame = (int)ceil((getTotalNumFrames() * getPosition()));
- frame = framePosInInt;
-
- return frame;
-}
-
-int ofGstVideoPlayer::getTotalNumFrames(){
- return nFrames;
-}
-
-void ofGstVideoPlayer::firstFrame(){
- setFrame(0);
-}
-
-void ofGstVideoPlayer::nextFrame(){
- gint64 currentFrame = getCurrentFrame();
- if(currentFrame!=-1) setFrame(currentFrame + 1);
-}
-
-void ofGstVideoPlayer::previousFrame(){
- gint64 currentFrame = getCurrentFrame();
- if(currentFrame!=-1) setFrame(currentFrame - 1);
-}
-
-void ofGstVideoPlayer::setFrame(int frame){ // frame 0 = first frame...
- float pct = (float)frame / (float)nFrames;
- setPosition(pct);
-}
-
-bool ofGstVideoPlayer::isStream(){
- return bIsStream;
-}
-
-void ofGstVideoPlayer::update(){
- videoUtils.update();
-}
-
-void ofGstVideoPlayer::play(){
- videoUtils.play();
-}
-
-void ofGstVideoPlayer::stop(){
- videoUtils.stop();
-}
-
-void ofGstVideoPlayer::setPaused(bool bPause){
- videoUtils.setPaused(bPause);
-}
-
-bool ofGstVideoPlayer::isPaused(){
- return videoUtils.isPaused();
-}
-
-bool ofGstVideoPlayer::isLoaded(){
- return videoUtils.isLoaded();
-}
-
-bool ofGstVideoPlayer::isPlaying(){
- return videoUtils.isPlaying();
-}
-
-float ofGstVideoPlayer::getPosition(){
- return videoUtils.getPosition();
-}
-
-float ofGstVideoPlayer::getSpeed(){
- return videoUtils.getSpeed();
-}
-
-float ofGstVideoPlayer::getDuration(){
- return videoUtils.getDuration();
-}
-
-bool ofGstVideoPlayer::getIsMovieDone(){
- return videoUtils.getIsMovieDone();
-}
-
-void ofGstVideoPlayer::setPosition(float pct){
- videoUtils.setPosition(pct);
-}
-
-void ofGstVideoPlayer::setVolume(float volume){
- videoUtils.setVolume(volume);
-}
-
-void ofGstVideoPlayer::setLoopState(ofLoopType state){
- videoUtils.setLoopState(state);
-}
-
-ofLoopType ofGstVideoPlayer::getLoopState(){
- return videoUtils.getLoopState();
-}
-
-void ofGstVideoPlayer::setSpeed(float speed){
- videoUtils.setSpeed(speed);
-}
-
-void ofGstVideoPlayer::close(){
- bIsAllocated = false;
- videoUtils.close();
-}
-
-bool ofGstVideoPlayer::isFrameNew(){
- return videoUtils.isFrameNew();
-}
-
-unsigned char * ofGstVideoPlayer::getPixels(){
- return videoUtils.getPixels();
-}
-/*
-ofPixelsRef ofGstVideoPlayer::getPixelsRef(){
- return videoUtils.getPixelsRef();
-}
-*/
-float ofGstVideoPlayer::getHeight(){
- return videoUtils.getHeight();
-}
-
-float ofGstVideoPlayer::getWidth(){
- return videoUtils.getWidth();
-}
-
-ofGstVideoUtils * ofGstVideoPlayer::getGstVideoUtils(){
- return &videoUtils;
-}
-
-void ofGstVideoPlayer::setFrameByFrame(bool frameByFrame){
- videoUtils.setFrameByFrame(frameByFrame);
-}
-
diff --git a/rotord/gstvideoloader.h b/rotord/gstvideoloader.h
deleted file mode 100644
index b354fa7..0000000
--- a/rotord/gstvideoloader.h
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <string>
-#include <iostream>
-
-#include <gst/gst.h>
-#include <gst/app/gstappsink.h>
-#include <gst/video/video.h>
-#include <gst/audio/multichannel.h>
-
-#include <glib-object.h>
-#include <glib.h>
-#include <algorithm>
-
-#define GST_DISABLE_DEPRECATED
-#include <gst/gstpad.h>
-#include "Pixels.h"
-#include "ofUtils.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();
- void update();
-
-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();
-
-
- 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;
-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(){};
-};
-
-class ofGstVideoPlayer: public ofGstAppSink{
-public:
-
- ofGstVideoPlayer();
- ~ofGstVideoPlayer();
-
- /// needs to be called before loadMovie
- //bool setPixelFormat(ofPixelFormat pixelFormat);
- //ofPixelFormat getPixelFormat();
-
- bool loadMovie(string uri);
-
- void update();
-
- int getCurrentFrame();
- int getTotalNumFrames();
-
- void firstFrame();
- void nextFrame();
- void previousFrame();
- void setFrame(int frame); // frame 0 = first frame...
-
- bool isStream();
-
- void play();
- void stop();
- void setPaused(bool bPause);
- bool isPaused();
- bool isLoaded();
- bool isPlaying();
-
- float getPosition();
- float getSpeed();
- float getDuration();
- bool getIsMovieDone();
-
- void setPosition(float pct);
- void setVolume(float volume);
- void setLoopState(ofLoopType state);
- ofLoopType getLoopState();
- void setSpeed(float speed);
- void close();
-
- bool isFrameNew();
-
- unsigned char * getPixels();
- //ofPixelsRef getPixelsRef();
-
- float getHeight();
- float getWidth();
-
- void setFrameByFrame(bool frameByFrame);
- void setThreadAppSink(bool threaded);
-
- ofGstVideoUtils * getGstVideoUtils();
-
-protected:
- bool allocate(int bpp);
- void on_stream_prepared();
-
- // return true to set the message as attended so upstream doesn't try to process it
- virtual bool on_message(GstMessage* msg){return false;};
-
-private:
- //ofPixelFormat internalPixelFormat;
- guint64 nFrames;
- int fps_n, fps_d;
- bool bIsStream;
- bool bIsAllocated;
- bool threadAppSink;
- ofGstVideoUtils videoUtils;
-};