• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
4  * Copyright (C) 2009 Andrey Nechypurenko <andreynech@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #include <gst/gl/gl.h>
23 #include "../gl-compat-defines.h"
24 #include "pipeline.h"
25 
Pipeline(GstGLDisplay * display,GstGLContext * context,const QString & videoLocation,QObject * parent)26 Pipeline::Pipeline (GstGLDisplay *display,
27     GstGLContext * context, const QString & videoLocation, QObject * parent)
28     :
29 QObject (parent),
30 m_videoLocation (videoLocation),
31 m_loop (NULL),
32 m_bus (NULL),
33 m_pipeline (NULL)
34 {
35   this->display = display;
36   this->context = context;
37   this->configure ();
38 }
39 
~Pipeline()40 Pipeline::~Pipeline ()
41 {
42 }
43 
44 void
configure()45 Pipeline::configure ()
46 {
47 
48 #ifdef Q_WS_WIN
49   m_loop = g_main_loop_new (NULL, FALSE);
50 #endif
51 
52   if (m_videoLocation.isEmpty ()) {
53     qDebug ("No video file specified. Using video test source.");
54     m_pipeline =
55         GST_PIPELINE (gst_parse_launch
56         ("videotestsrc ! "
57             "video/x-raw, width=640, height=480, "
58             "framerate=(fraction)30/1 ! "
59             "glupload ! gleffects effect=5 ! fakesink sync=1", NULL));
60   } else {
61     QByteArray ba = m_videoLocation.toLocal8Bit ();
62     qDebug ("Loading video: %s", ba.data ());
63     gchar *pipeline = g_strdup_printf ("filesrc name=f ! "
64         "decodebin ! gleffects effect=5 ! " "fakesink sync=1");
65     m_pipeline = GST_PIPELINE (gst_parse_launch (pipeline, NULL));
66     GstElement *f = gst_bin_get_by_name (GST_BIN (m_pipeline), "f");
67     g_object_set (G_OBJECT (f), "location", ba.data (), NULL);
68     gst_object_unref (GST_OBJECT (f));
69     g_free (pipeline);
70   }
71 
72   m_bus = gst_pipeline_get_bus (GST_PIPELINE (m_pipeline));
73   gst_bus_add_watch (m_bus, (GstBusFunc) bus_call, this);
74   gst_bus_enable_sync_message_emission (m_bus);
75   g_signal_connect (m_bus, "sync-message", G_CALLBACK (sync_bus_call), this);
76   gst_object_unref (m_bus);
77 
78   gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PAUSED);
79   GstState state = GST_STATE_PAUSED;
80   if (gst_element_get_state (GST_ELEMENT (this->m_pipeline),
81           &state, NULL, GST_CLOCK_TIME_NONE)
82       != GST_STATE_CHANGE_SUCCESS) {
83     qDebug ("failed to pause pipeline");
84     return;
85   }
86 }
87 
88 void
start()89 Pipeline::start ()
90 {
91   // set a callback to retrieve the gst gl textures
92   GstElement *fakesink = gst_bin_get_by_name (GST_BIN (this->m_pipeline),
93       "fakesink0");
94   g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
95   g_signal_connect (fakesink, "handoff", G_CALLBACK (on_gst_buffer), this);
96   gst_object_unref (fakesink);
97 
98   GstStateChangeReturn ret =
99       gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PLAYING);
100   if (ret == GST_STATE_CHANGE_FAILURE) {
101     qDebug ("Failed to start up pipeline!");
102 
103     /* check if there is an error message with details on the bus */
104     GstMessage *msg = gst_bus_poll (this->m_bus, GST_MESSAGE_ERROR, 0);
105     if (msg) {
106       GError *err = NULL;
107       gst_message_parse_error (msg, &err, NULL);
108       qDebug ("ERROR: %s", err->message);
109       g_error_free (err);
110       gst_message_unref (msg);
111     }
112     return;
113   }
114 #ifdef Q_WS_WIN
115   g_main_loop_run (m_loop);
116 #endif
117 }
118 
119 /* fakesink handoff callback */
120 void
on_gst_buffer(GstElement * element,GstBuffer * buf,GstPad * pad,Pipeline * p)121 Pipeline::on_gst_buffer (GstElement * element,
122     GstBuffer * buf, GstPad * pad, Pipeline * p)
123 {
124   Q_UNUSED (pad)
125       Q_UNUSED (element)
126 
127       /* ref then push buffer to use it in qt */
128       gst_buffer_ref (buf);
129   p->queue_input_buf.put (buf);
130 
131   if (p->queue_input_buf.size () > 3)
132     p->notifyNewFrame ();
133 
134   /* pop then unref buffer we have finished to use in qt */
135   if (p->queue_output_buf.size () > 3) {
136     GstBuffer *buf_old = (p->queue_output_buf.get ());
137     if (buf_old)
138       gst_buffer_unref (buf_old);
139   }
140 }
141 
142 void
stop()143 Pipeline::stop ()
144 {
145 #ifdef Q_WS_WIN
146   g_main_loop_quit (m_loop);
147 #else
148   emit stopRequested ();
149 #endif
150 }
151 
152 void
unconfigure()153 Pipeline::unconfigure ()
154 {
155   gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_NULL);
156 
157   GstBuffer *buf;
158   while (this->queue_input_buf.size ()) {
159     buf = (GstBuffer *) (this->queue_input_buf.get ());
160     gst_buffer_unref (buf);
161   }
162   while (this->queue_output_buf.size ()) {
163     buf = (GstBuffer *) (this->queue_output_buf.get ());
164     gst_buffer_unref (buf);
165   }
166 
167   gst_object_unref (m_pipeline);
168 }
169 
bus_call(GstBus * bus,GstMessage * msg,Pipeline * p)170 gboolean Pipeline::bus_call (GstBus * bus, GstMessage * msg, Pipeline * p)
171 {
172   Q_UNUSED (bus)
173 
174       switch (GST_MESSAGE_TYPE (msg)) {
175     case GST_MESSAGE_EOS:
176       qDebug ("End-of-stream received. Stopping.");
177       p->stop ();
178       break;
179 
180     case GST_MESSAGE_ERROR:
181     {
182       gchar *
183           debug = NULL;
184       GError *
185           err = NULL;
186       gst_message_parse_error (msg, &err, &debug);
187       qDebug ("Error: %s", err->message);
188       g_error_free (err);
189       if (debug) {
190         qDebug ("Debug deails: %s", debug);
191         g_free (debug);
192       }
193       p->stop ();
194       break;
195     }
196 
197     default:
198       break;
199   }
200 
201   return TRUE;
202 }
203 
sync_bus_call(GstBus * bus,GstMessage * msg,Pipeline * p)204 gboolean Pipeline::sync_bus_call (GstBus * bus, GstMessage * msg, Pipeline * p)
205 {
206   switch (GST_MESSAGE_TYPE (msg)) {
207     case GST_MESSAGE_NEED_CONTEXT:
208     {
209       const gchar *
210           context_type;
211 
212       gst_message_parse_context_type (msg, &context_type);
213       g_print ("got need context %s\n", context_type);
214 
215       if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
216         GstContext *display_context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
217         gst_context_set_gl_display (display_context, p->display);
218         gst_element_set_context (GST_ELEMENT (msg->src), display_context);
219       } else if (g_strcmp0 (context_type, "gst.gl.app_context") == 0) {
220         GstContext *app_context = gst_context_new ("gst.gl.app_context", TRUE);
221         GstStructure *s = gst_context_writable_structure (app_context);
222         gst_structure_set (s, "context", GST_TYPE_GL_CONTEXT, p->context, NULL);
223         gst_element_set_context (GST_ELEMENT (msg->src), app_context);
224       }
225       break;
226     }
227     default:
228       break;
229   }
230   return FALSE;
231 }
232