#include "GStreamerImageStream.hpp" #if 0 #define OSGGST_INFO OSG_NOTICE #else #define OSGGST_INFO OSG_INFO #endif namespace osgGStreamer { GStreamerImageStream::GStreamerImageStream(): _loop(0), _pipeline(0), _internal_buffer(0), _width(0), _height(0) { setOrigin(osg::Image::TOP_LEFT); _loop = g_main_loop_new(NULL, FALSE); } GStreamerImageStream::GStreamerImageStream(const GStreamerImageStream & image, const osg::CopyOp & copyop) : osg::ImageStream(image, copyop), OpenThreads::Thread(), _loop(0), _pipeline(0), _internal_buffer(0), _width(0), _height(0) { setOrigin(osg::Image::TOP_LEFT); _loop = g_main_loop_new(NULL, FALSE); if (!getFileName().empty()) { open(getFileName()); } } GStreamerImageStream::~GStreamerImageStream() { gst_element_set_state(_pipeline, GST_STATE_NULL); gst_element_get_state(_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); //wait until the state changed g_main_loop_quit(_loop); g_main_loop_unref(_loop); free(_internal_buffer); } bool GStreamerImageStream::open(const std::string& filename) { setFileName(filename); GError *error = NULL; // get stream info bool has_audio_stream = false; gchar *uri = g_filename_to_uri(filename.c_str(), NULL, NULL); if( uri!=0 && gst_uri_is_valid(uri) ) { GstDiscoverer *item = gst_discoverer_new(1*GST_SECOND, &error); GstDiscovererInfo *info = gst_discoverer_discover_uri(item, uri, &error); GList *audio_list = gst_discoverer_info_get_audio_streams(info); if( g_list_length(audio_list) > 0 ) has_audio_stream = true; gst_discoverer_info_unref(info); g_free(uri); } // build pipeline const gchar *audio_pipe = ""; if( has_audio_stream ) { audio_pipe = "deco. ! queue ! audioconvert ! autoaudiosink"; } gchar *string = g_strdup_printf("filesrc location=%s ! \ decodebin name=deco \ deco. ! queue ! videoconvert ! video/x-raw,format=RGB ! appsink name=sink emit-signals=true \ %s", filename.c_str(), audio_pipe); _pipeline = gst_parse_launch(string, &error); g_free(string); if (error) { g_printerr("Error: %s\n", error->message); g_error_free(error); } if( _pipeline == NULL ) { return false; } // bus GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(_pipeline)); gst_bus_add_watch(bus, (GstBusFunc)on_message, this); gst_object_unref(bus); // sink GstElement *sink = gst_bin_get_by_name(GST_BIN(_pipeline), "sink"); g_signal_connect(sink, "new-sample", G_CALLBACK(on_new_sample), this); g_signal_connect(sink, "new-preroll", G_CALLBACK(on_new_preroll), this); gst_object_unref(sink); gst_element_set_state(_pipeline, GST_STATE_PAUSED); gst_element_get_state(_pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); // wait until the state changed if (_width==0 || _height==0) { // no valid image has been setup by a on_new_preroll() call. return false; } // setLoopingMode(osg::ImageStream::NO_LOOPING); // start the thread to run gstreamer main loop start(); return true; } //** Controls ** void GStreamerImageStream::play() { OSGGST_INFO<<"GStreamerImageStream::play()"<_internal_buffer, info.size); // data has been modified so dirty the image so the texture will updated user_data->dirty(); // clean resources gst_buffer_unmap(buffer, &info); gst_sample_unref(sample); return GST_FLOW_OK; } GstFlowReturn GStreamerImageStream::on_new_preroll(GstAppSink *appsink, GStreamerImageStream *user_data) { // get the sample from appsink GstSample *sample = gst_app_sink_pull_preroll(appsink); // get sample info GstCaps *caps = gst_sample_get_caps(sample); GstStructure *structure = gst_caps_get_structure(caps, 0); int width; int height; gst_structure_get_int(structure, "width", &width); gst_structure_get_int(structure, "height", &height); if (width<=0 || height<=0) { OSG_NOTICE<<"Error: video size invalid width="<getFileName()<<"' finished."<getLoopingMode()==osg::ImageStream::LOOPING) { user_data->rewind(); } } return TRUE; } void GStreamerImageStream::run() { g_main_loop_run(_loop); } } // namespace osgGStreamer