diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llmedia/llmediaimplgstreamer.cpp | 335 |
1 files changed, 244 insertions, 91 deletions
diff --git a/linden/indra/llmedia/llmediaimplgstreamer.cpp b/linden/indra/llmedia/llmediaimplgstreamer.cpp index 30706f1..7ae6b02 100644 --- a/linden/indra/llmedia/llmediaimplgstreamer.cpp +++ b/linden/indra/llmedia/llmediaimplgstreamer.cpp | |||
@@ -30,23 +30,35 @@ | |||
30 | * $/LicenseInfo$ | 30 | * $/LicenseInfo$ |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include "llmediaimplgstreamer.h" | ||
34 | |||
35 | ///#if LL_GSTREAMER_ENABLED | 33 | ///#if LL_GSTREAMER_ENABLED |
36 | 34 | ||
35 | #if LL_WINDOWS | ||
36 | // GStreamer 0.10.22 - gstutils.h - conversion from 'guint64' to 'guint8'. | ||
37 | // This was an intentional change to make GStreamer more threadsafe, and | ||
38 | // is okay. Delete this bit if GStreamer ever gets more VS-friendly -- McCabe | ||
39 | #pragma warning(disable : 4244) | ||
40 | #endif | ||
41 | |||
42 | #include "linden_common.h" | ||
43 | #include "llmediaimplgstreamer.h" | ||
44 | |||
37 | extern "C" { | 45 | extern "C" { |
38 | #include <gst/gst.h> | 46 | #include <gst/gst.h> |
39 | #include <gst/gstelement.h> | 47 | #include <gst/gstelement.h> |
40 | } | 48 | } |
41 | 49 | ||
50 | #if LL_WINDOWS | ||
51 | #pragma warning(default : 4244) | ||
52 | #include <direct.h> | ||
53 | #include <stdlib.h> | ||
54 | #endif | ||
55 | |||
42 | #include "llmediamanager.h" | 56 | #include "llmediamanager.h" |
43 | #include "llmediaimplregister.h" | 57 | #include "llmediaimplregister.h" |
44 | 58 | ||
45 | #include "llmediaimplgstreamervidplug.h" | 59 | #include "llmediaimplgstreamervidplug.h" |
60 | #include "llgstplaythread.h" | ||
46 | 61 | ||
47 | #include "llmediaimplgstreamer_syms.h" | ||
48 | |||
49 | #include "llerror.h" | ||
50 | 62 | ||
51 | // register this impl with media manager factory | 63 | // register this impl with media manager factory |
52 | static LLMediaImplRegister sLLMediaImplGStreamerReg( "LLMediaImplGStreamer", new LLMediaImplGStreamerMaker() ); | 64 | static LLMediaImplRegister sLLMediaImplGStreamerReg( "LLMediaImplGStreamer", new LLMediaImplGStreamerMaker() ); |
@@ -73,7 +85,8 @@ LLMediaImplGStreamer () : | |||
73 | mPump ( NULL ), | 85 | mPump ( NULL ), |
74 | mPlaybin ( NULL ), | 86 | mPlaybin ( NULL ), |
75 | mVideoSink ( NULL ), | 87 | mVideoSink ( NULL ), |
76 | mState( GST_STATE_NULL ) | 88 | mState( GST_STATE_NULL ), |
89 | mPlayThread ( NULL ) | ||
77 | { | 90 | { |
78 | startup( NULL ); // Startup gstreamer if it hasn't been already. | 91 | startup( NULL ); // Startup gstreamer if it hasn't been already. |
79 | 92 | ||
@@ -90,7 +103,7 @@ LLMediaImplGStreamer () : | |||
90 | } | 103 | } |
91 | 104 | ||
92 | // instantiate a playbin element to do the hard work | 105 | // instantiate a playbin element to do the hard work |
93 | mPlaybin = llgst_element_factory_make ("playbin", "play"); | 106 | mPlaybin = gst_element_factory_make ("playbin", "play"); |
94 | if (!mPlaybin) | 107 | if (!mPlaybin) |
95 | { | 108 | { |
96 | // todo: cleanup pump | 109 | // todo: cleanup pump |
@@ -104,7 +117,7 @@ LLMediaImplGStreamer () : | |||
104 | 117 | ||
105 | // Plays inworld instead of in external player | 118 | // Plays inworld instead of in external player |
106 | mVideoSink = | 119 | mVideoSink = |
107 | GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); | 120 | GST_SLVIDEO(gst_element_factory_make ("private-slvideo", "slvideo")); |
108 | if (!mVideoSink) | 121 | if (!mVideoSink) |
109 | { | 122 | { |
110 | LL_WARNS("MediaImpl") << "Could not instantiate private-slvideo element." << LL_ENDL; | 123 | LL_WARNS("MediaImpl") << "Could not instantiate private-slvideo element." << LL_ENDL; |
@@ -148,7 +161,7 @@ LLMediaImplGStreamer:: | |||
148 | std::string LLMediaImplGStreamer::getVersion() | 161 | std::string LLMediaImplGStreamer::getVersion() |
149 | { | 162 | { |
150 | guint major, minor, micro, nano; | 163 | guint major, minor, micro, nano; |
151 | llgst_version(&major, &minor, µ, &nano); | 164 | gst_version(&major, &minor, µ, &nano); |
152 | std::string version = llformat("%d.%d.%d.%d",major,minor,micro,nano); | 165 | std::string version = llformat("%d.%d.%d.%d",major,minor,micro,nano); |
153 | return version; | 166 | return version; |
154 | } | 167 | } |
@@ -165,50 +178,163 @@ bool LLMediaImplGStreamer::startup (LLMediaManagerData* init_data) | |||
165 | // Init the glib type system - we need it. | 178 | // Init the glib type system - we need it. |
166 | g_type_init(); | 179 | g_type_init(); |
167 | 180 | ||
168 | // Get symbols! | 181 | set_gst_plugin_path(); |
169 | #if LL_WINDOWS | ||
170 | if (! grab_gst_syms("libgstreamer-0.10.dll", "libgstvideo-0.10.dll", "libgstaudio-0.10.dll") ) | ||
171 | { | ||
172 | LL_WARNS("MediaImpl") << "Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled." << LL_ENDL; | ||
173 | return false; | ||
174 | } | ||
175 | #else | ||
176 | if (! grab_gst_syms("libgstreamer-0.10.so.0", "libgstvideo-0.10.so.0", "libgstaudio-0.10.so.0") ) | ||
177 | { | ||
178 | LL_WARNS("MediaImpl") << "Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled." << LL_ENDL; | ||
179 | return false; | ||
180 | } | ||
181 | #endif | ||
182 | if (llgst_segtrap_set_enabled) | ||
183 | llgst_segtrap_set_enabled(FALSE); | ||
184 | else | ||
185 | { | ||
186 | LL_WARNS("MediaImpl") << "gst_segtrap_set_enabled() is not available; Automated crash-reporter may cease to function until next restart." << LL_ENDL; | ||
187 | } | ||
188 | 182 | ||
189 | // Protect against GStreamer resetting the locale, yuck. | 183 | // Protect against GStreamer resetting the locale, yuck. |
190 | static std::string saved_locale; | 184 | static std::string saved_locale; |
191 | saved_locale = setlocale(LC_ALL, NULL); | 185 | saved_locale = setlocale(LC_ALL, NULL); |
192 | if (0 == llgst_init_check(NULL, NULL, NULL)) | 186 | if (0 == gst_init_check(NULL, NULL, NULL)) |
193 | { | 187 | { |
194 | LL_WARNS("MediaImpl") << "GStreamer library failed to initialize and load standard plugins." << LL_ENDL; | 188 | LL_WARNS("MediaImpl") << "GStreamer library failed to initialize and load standard plugins." << LL_ENDL; |
195 | setlocale(LC_ALL, saved_locale.c_str() ); | 189 | setlocale(LC_ALL, saved_locale.c_str() ); |
196 | return false; | 190 | return false; |
197 | } | 191 | } |
198 | setlocale(LC_ALL, saved_locale.c_str() ); | 192 | setlocale(LC_ALL, saved_locale.c_str() ); |
199 | 193 | ||
194 | // Set up logging facilities | ||
195 | gst_debug_remove_log_function( gst_debug_log_default ); | ||
196 | gst_debug_add_log_function( gstreamer_log, NULL ); | ||
197 | |||
200 | // Init our custom plugins - only really need do this once. | 198 | // Init our custom plugins - only really need do this once. |
201 | gst_slvideo_init_class(); | 199 | gst_slvideo_init_class(); |
202 | 200 | ||
201 | |||
202 | // List the plugins GStreamer can find | ||
203 | LL_DEBUGS("MediaImpl") << "Found GStreamer plugins:" << LL_ENDL; | ||
204 | GList *list; | ||
205 | GstRegistry *registry = gst_registry_get_default(); | ||
206 | std::string loaded = ""; | ||
207 | for (list = gst_registry_get_plugin_list(registry); | ||
208 | list != NULL; | ||
209 | list = g_list_next(list)) | ||
210 | { | ||
211 | GstPlugin *list_plugin = (GstPlugin *)list->data; | ||
212 | (bool)gst_plugin_is_loaded(list_plugin) ? loaded = "Yes" : loaded = "No"; | ||
213 | LL_DEBUGS("MediaImpl") << gst_plugin_get_name(list_plugin) << ", loaded? " << loaded << LL_ENDL; | ||
214 | } | ||
215 | gst_plugin_list_free(list); | ||
216 | |||
217 | |||
203 | done_init = true; | 218 | done_init = true; |
204 | } | 219 | } |
205 | return true; | 220 | return true; |
206 | } | 221 | } |
207 | 222 | ||
208 | 223 | ||
224 | void LLMediaImplGStreamer::set_gst_plugin_path() | ||
225 | { | ||
226 | // Only needed for Windows. | ||
227 | // Linux sets in wrapper.sh, Mac sets in Info-Imprudence.plist | ||
228 | #ifdef LL_WINDOWS | ||
229 | |||
230 | char* imp_cwd; | ||
231 | |||
232 | // Get the current working directory: | ||
233 | imp_cwd = _getcwd(NULL,0); | ||
234 | |||
235 | if(imp_cwd == NULL) | ||
236 | { | ||
237 | LL_DEBUGS("MediaImpl") << "_getcwd failed, not setting GST_PLUGIN_PATH." | ||
238 | << LL_ENDL; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | LL_DEBUGS("MediaImpl") << "Imprudence is installed at " | ||
243 | << imp_cwd << LL_ENDL; | ||
244 | |||
245 | // Grab the current path, if it's set. | ||
246 | std::string old_plugin_path = ""; | ||
247 | char *old_path = getenv("GST_PLUGIN_PATH"); | ||
248 | if(old_path == NULL) | ||
249 | { | ||
250 | LL_DEBUGS("MediaImpl") << "Did not find user-set GST_PLUGIN_PATH." | ||
251 | << LL_ENDL; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | old_plugin_path = ";" + std::string( old_path ); | ||
256 | } | ||
257 | |||
258 | |||
259 | // Search both Imprudence and Imprudence\lib\gstreamer-plugins. | ||
260 | // If those fail, search the path the user has set, if any. | ||
261 | std::string plugin_path = | ||
262 | "GST_PLUGIN_PATH=" + | ||
263 | std::string(imp_cwd) + "\\lib\\gstreamer-plugins;" + | ||
264 | std::string(imp_cwd) + | ||
265 | old_plugin_path; | ||
266 | |||
267 | // Place GST_PLUGIN_PATH in the environment settings for imprudence.exe | ||
268 | // Returns 0 on success | ||
269 | if(_putenv( (char*)plugin_path.c_str() )) | ||
270 | { | ||
271 | LL_WARNS("MediaImpl") << "Setting environment variable failed!" << LL_ENDL; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | LL_DEBUGS("MediaImpl") << "GST_PLUGIN_PATH set to " | ||
276 | << getenv("GST_PLUGIN_PATH") << LL_ENDL; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | #endif //LL_WINDOWS | ||
281 | } | ||
282 | |||
283 | |||
284 | void LLMediaImplGStreamer::gstreamer_log(GstDebugCategory *category, | ||
285 | GstDebugLevel level, | ||
286 | const gchar *file, | ||
287 | const gchar *function, | ||
288 | gint line, | ||
289 | GObject *object, | ||
290 | GstDebugMessage *message, | ||
291 | gpointer data) | ||
292 | { | ||
293 | std::stringstream log(std::stringstream::out); | ||
294 | |||
295 | // Log format example: | ||
296 | // | ||
297 | // GST_ELEMENT_PADS: removing pad 'sink' (in gstelement.c:757:gst_element_remove_pad) | ||
298 | // | ||
299 | log << gst_debug_category_get_name( category ) << ": " | ||
300 | << gst_debug_message_get(message) << " " | ||
301 | << "(in " << file << ":" << line << ":" << function << ")"; | ||
302 | |||
303 | switch( level ) | ||
304 | { | ||
305 | case GST_LEVEL_ERROR: | ||
306 | LL_ERRS("MediaImpl") << log.str() << LL_ENDL; | ||
307 | break; | ||
308 | case GST_LEVEL_WARNING: | ||
309 | LL_WARNS("MediaImpl") << log.str() << LL_ENDL; | ||
310 | break; | ||
311 | case GST_LEVEL_DEBUG: | ||
312 | LL_DEBUGS("MediaImpl") << log.str() << LL_ENDL; | ||
313 | break; | ||
314 | case GST_LEVEL_INFO: | ||
315 | LL_INFOS("MediaImpl") << log.str() << LL_ENDL; | ||
316 | break; | ||
317 | default: | ||
318 | // Do nothing. | ||
319 | break; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
209 | bool LLMediaImplGStreamer::closedown() | 324 | bool LLMediaImplGStreamer::closedown() |
210 | { | 325 | { |
211 | ungrab_gst_syms(); | 326 | return true; |
327 | } | ||
328 | |||
329 | |||
330 | bool LLMediaImplGStreamer::setDebugLevel( LLMediaBase::EDebugLevel level ) | ||
331 | { | ||
332 | // Do parent class stuff. | ||
333 | LLMediaImplCommon::setDebugLevel(level); | ||
334 | |||
335 | // Set GStreamer verbosity. | ||
336 | gst_debug_set_default_threshold( (GstDebugLevel)level ); | ||
337 | |||
212 | return true; | 338 | return true; |
213 | } | 339 | } |
214 | 340 | ||
@@ -236,7 +362,7 @@ static const char* get_gst_state_name(GstState state) | |||
236 | gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gpointer data) | 362 | gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gpointer data) |
237 | { | 363 | { |
238 | #ifdef LL_GST_REPORT_STATE_CHANGES | 364 | #ifdef LL_GST_REPORT_STATE_CHANGES |
239 | LL_DEBUGS("MediaCallback") << "Got GST message type: " << LLGST_MESSAGE_TYPE_NAME (message) << LL_ENDL; | 365 | LL_DEBUGS("MediaCallback") << "Got GST message type: " << GST_MESSAGE_TYPE_NAME (message) << LL_ENDL; |
240 | #endif | 366 | #endif |
241 | 367 | ||
242 | LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; | 368 | LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; |
@@ -245,17 +371,13 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
245 | { | 371 | { |
246 | case GST_MESSAGE_BUFFERING: | 372 | case GST_MESSAGE_BUFFERING: |
247 | { | 373 | { |
248 | // NEEDS GST 0.10.11+ | 374 | gint percent = 0; |
249 | if (llgst_message_parse_buffering) | 375 | gst_message_parse_buffering(message, &percent); |
250 | { | ||
251 | gint percent = 0; | ||
252 | llgst_message_parse_buffering(message, &percent); | ||
253 | #ifdef LL_GST_REPORT_STATE_CHANGES | 376 | #ifdef LL_GST_REPORT_STATE_CHANGES |
254 | LL_DEBUGS("MediaBuffering") << "GST buffering: " << percent << "%%" << LL_ENDL; | 377 | LL_DEBUGS("MediaBuffering") << "GST buffering: " << percent << "%%" << LL_ENDL; |
255 | #endif | 378 | #endif |
256 | LLMediaEvent event( impl, percent ); | 379 | LLMediaEvent event( impl, percent ); |
257 | impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); | 380 | impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); |
258 | } | ||
259 | } | 381 | } |
260 | break; | 382 | break; |
261 | case GST_MESSAGE_STATE_CHANGED: | 383 | case GST_MESSAGE_STATE_CHANGED: |
@@ -263,7 +385,7 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
263 | GstState old_state; | 385 | GstState old_state; |
264 | GstState new_state; | 386 | GstState new_state; |
265 | GstState pending_state; | 387 | GstState pending_state; |
266 | llgst_message_parse_state_changed(message, | 388 | gst_message_parse_state_changed(message, |
267 | &old_state, | 389 | &old_state, |
268 | &new_state, | 390 | &new_state, |
269 | &pending_state); | 391 | &pending_state); |
@@ -308,7 +430,7 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
308 | GError *err = NULL; | 430 | GError *err = NULL; |
309 | gchar *debug = NULL; | 431 | gchar *debug = NULL; |
310 | 432 | ||
311 | llgst_message_parse_error (message, &err, &debug); | 433 | gst_message_parse_error (message, &err, &debug); |
312 | LL_WARNS("MediaImpl") << "GST Error: " << err->message << LL_ENDL; | 434 | LL_WARNS("MediaImpl") << "GST Error: " << err->message << LL_ENDL; |
313 | g_error_free (err); | 435 | g_error_free (err); |
314 | g_free (debug); | 436 | g_free (debug); |
@@ -320,17 +442,14 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
320 | } | 442 | } |
321 | case GST_MESSAGE_INFO: | 443 | case GST_MESSAGE_INFO: |
322 | { | 444 | { |
323 | if (llgst_message_parse_info) | 445 | GError *err = NULL; |
324 | { | 446 | gchar *debug = NULL; |
325 | GError *err = NULL; | ||
326 | gchar *debug = NULL; | ||
327 | 447 | ||
328 | llgst_message_parse_info (message, &err, &debug); | 448 | gst_message_parse_info (message, &err, &debug); |
329 | LL_INFOS("MediaImpl") << "GST info: " << err->message | 449 | LL_INFOS("MediaImpl") << "GST info: " << err->message |
330 | << LL_ENDL; | 450 | << LL_ENDL; |
331 | g_error_free (err); | 451 | g_error_free (err); |
332 | g_free (debug); | 452 | g_free (debug); |
333 | } | ||
334 | break; | 453 | break; |
335 | } | 454 | } |
336 | case GST_MESSAGE_WARNING: | 455 | case GST_MESSAGE_WARNING: |
@@ -338,7 +457,7 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
338 | GError *err = NULL; | 457 | GError *err = NULL; |
339 | gchar *debug = NULL; | 458 | gchar *debug = NULL; |
340 | 459 | ||
341 | llgst_message_parse_warning (message, &err, &debug); | 460 | gst_message_parse_warning (message, &err, &debug); |
342 | LL_WARNS("MediaImpl") << "GST warning: " << err->message | 461 | LL_WARNS("MediaImpl") << "GST warning: " << err->message |
343 | << LL_ENDL; | 462 | << LL_ENDL; |
344 | g_error_free (err); | 463 | g_error_free (err); |
@@ -351,10 +470,10 @@ gboolean LLMediaImplGStreamer::bus_callback(GstBus *bus, GstMessage *message, gp | |||
351 | GstTagList *tag_list; | 470 | GstTagList *tag_list; |
352 | gchar *title; | 471 | gchar *title; |
353 | gchar *artist; | 472 | gchar *artist; |
354 | llgst_message_parse_tag(message, &tag_list); | 473 | gst_message_parse_tag(message, &tag_list); |
355 | gboolean hazTitle = llgst_tag_list_get_string(tag_list, | 474 | gboolean hazTitle = gst_tag_list_get_string(tag_list, |
356 | GST_TAG_TITLE, &title); | 475 | GST_TAG_TITLE, &title); |
357 | gboolean hazArtist = llgst_tag_list_get_string(tag_list, | 476 | gboolean hazArtist = gst_tag_list_get_string(tag_list, |
358 | GST_TAG_ARTIST, &artist); | 477 | GST_TAG_ARTIST, &artist); |
359 | if(hazTitle) | 478 | if(hazTitle) |
360 | LL_INFOS("MediaInfo") << "Title: " << title << LL_ENDL; | 479 | LL_INFOS("MediaInfo") << "Title: " << title << LL_ENDL; |
@@ -408,13 +527,13 @@ bool LLMediaImplGStreamer::navigateTo (const std::string urlIn) | |||
408 | g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); | 527 | g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); |
409 | 528 | ||
410 | // get playbin's bus - perhaps this can/should be done in ctor | 529 | // get playbin's bus - perhaps this can/should be done in ctor |
411 | GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); | 530 | GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); |
412 | if (!bus) | 531 | if (!bus) |
413 | { | 532 | { |
414 | return false; | 533 | return false; |
415 | } | 534 | } |
416 | llgst_bus_add_watch (bus, bus_callback, this); | 535 | gst_bus_add_watch (bus, bus_callback, this); |
417 | llgst_object_unref (bus); | 536 | gst_object_unref (bus); |
418 | 537 | ||
419 | mState = GST_STATE_READY; | 538 | mState = GST_STATE_READY; |
420 | 539 | ||
@@ -431,9 +550,9 @@ bool LLMediaImplGStreamer::unload() | |||
431 | LL_DEBUGS("MediaImpl") << "unloading media..." << LL_ENDL; | 550 | LL_DEBUGS("MediaImpl") << "unloading media..." << LL_ENDL; |
432 | if (mPlaybin) | 551 | if (mPlaybin) |
433 | { | 552 | { |
434 | llgst_element_set_state (mPlaybin, GST_STATE_NULL); | 553 | gst_element_set_state (mPlaybin, GST_STATE_NULL); |
435 | mState = GST_STATE_NULL; | 554 | mState = GST_STATE_NULL; |
436 | llgst_object_unref (GST_OBJECT (mPlaybin)); | 555 | gst_object_unref (GST_OBJECT (mPlaybin)); |
437 | mPlaybin = NULL; | 556 | mPlaybin = NULL; |
438 | } | 557 | } |
439 | 558 | ||
@@ -591,20 +710,23 @@ bool LLMediaImplGStreamer::stop() | |||
591 | if (!mPlaybin || mState == GST_STATE_NULL) | 710 | if (!mPlaybin || mState == GST_STATE_NULL) |
592 | return true; | 711 | return true; |
593 | 712 | ||
594 | GstElement *pipeline = (GstElement *)llgst_object_ref(GST_OBJECT(mPlaybin)); | 713 | GstStateChangeReturn state_change; |
595 | llgst_object_unref(pipeline); | ||
596 | |||
597 | llgst_element_set_state(pipeline, GST_STATE_READY); | ||
598 | 714 | ||
599 | if (mState == GST_STATE_PLAYING) | 715 | state_change = gst_element_set_state(mPlaybin, GST_STATE_READY); |
600 | mState = GST_STATE_VOID_PENDING; | ||
601 | else | ||
602 | mState = GST_STATE_READY; | ||
603 | 716 | ||
604 | GstStateChangeReturn state_change = llgst_element_get_state(mPlaybin, NULL, NULL, GST_CLOCK_TIME_NONE); | 717 | LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; |
605 | LL_DEBUGS("MediaImpl") << "get_state: " << llgst_element_state_change_return_get_name(state_change) << LL_ENDL; | ||
606 | 718 | ||
607 | return true; | 719 | if (state_change == GST_STATE_CHANGE_FAILURE) |
720 | { | ||
721 | LL_WARNS("MediaImpl") << "could not stop stream!" << LL_ENDL; | ||
722 | return false; | ||
723 | } | ||
724 | else | ||
725 | { | ||
726 | // Going into pending after play keeps dead streams from looping | ||
727 | (mState == GST_STATE_PLAYING) ? (mState = GST_STATE_VOID_PENDING) : (mState = GST_STATE_READY); | ||
728 | return true; | ||
729 | } | ||
608 | } | 730 | } |
609 | 731 | ||
610 | /////////////////////////////////////////////////////////////////////////////// | 732 | /////////////////////////////////////////////////////////////////////////////// |
@@ -616,25 +738,47 @@ bool LLMediaImplGStreamer::play() | |||
616 | if (!mPlaybin || mState == GST_STATE_NULL) | 738 | if (!mPlaybin || mState == GST_STATE_NULL) |
617 | return true; | 739 | return true; |
618 | 740 | ||
619 | GstElement *pipeline = (GstElement *)llgst_object_ref(GST_OBJECT(mPlaybin)); | 741 | // Clean up the existing thread, if any. |
620 | llgst_object_unref(pipeline); | 742 | if( mPlayThread != NULL && mPlayThread->isStopped()) |
743 | { | ||
744 | delete mPlayThread; | ||
745 | mPlayThread = NULL; | ||
746 | } | ||
747 | |||
748 | if( mPlayThread == NULL ) | ||
749 | { | ||
750 | // Make a new thread to start playing. This keeps the viewer | ||
751 | // responsive while the stream is resolved and buffered. | ||
752 | mPlayThread = new LLGstPlayThread( (LLMediaImplCommon *)this, "GstPlayThread", NULL); | ||
753 | mPlayThread->start(); | ||
754 | } | ||
755 | |||
756 | return true; | ||
757 | } | ||
758 | |||
759 | |||
760 | void LLMediaImplGStreamer::startPlay() | ||
761 | { | ||
762 | GstElement *pipeline = (GstElement *)gst_object_ref(GST_OBJECT(mPlaybin)); | ||
763 | gst_object_unref(pipeline); | ||
621 | 764 | ||
622 | llgst_element_set_state(pipeline, GST_STATE_PLAYING); | 765 | GstStateChangeReturn state_change; |
766 | |||
767 | state_change = gst_element_set_state(mPlaybin, GST_STATE_PLAYING); | ||
623 | mState = GST_STATE_PLAYING; | 768 | mState = GST_STATE_PLAYING; |
624 | /*llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); | ||
625 | mState = GST_STATE_PLAYING;*/ | ||
626 | 769 | ||
627 | GstStateChangeReturn state_change = llgst_element_get_state(mPlaybin, NULL, NULL, GST_CLOCK_TIME_NONE); | 770 | LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; |
628 | LL_DEBUGS("MediaImpl") << "get_state: " << llgst_element_state_change_return_get_name(state_change) << LL_ENDL; | ||
629 | 771 | ||
630 | // Check to make sure playing was successful. If not, stop. | 772 | // Check to make sure playing was successful. If not, stop. |
773 | // NOTE: state_change is almost always GST_STATE_CHANGE_ASYNC | ||
631 | if (state_change == GST_STATE_CHANGE_FAILURE) | 774 | if (state_change == GST_STATE_CHANGE_FAILURE) |
632 | { | 775 | { |
633 | setStatus(LLMediaBase::STATUS_STOPPED); | 776 | // If failing from a bad stream, go into an unknown |
777 | // state to stop bus_callback from looping back. | ||
778 | // We also force a stop in case the operations don't sync | ||
779 | setStatus(LLMediaBase::STATUS_UNKNOWN); | ||
634 | stop(); | 780 | stop(); |
635 | } | 781 | } |
636 | |||
637 | return true; | ||
638 | } | 782 | } |
639 | 783 | ||
640 | /////////////////////////////////////////////////////////////////////////////// | 784 | /////////////////////////////////////////////////////////////////////////////// |
@@ -646,13 +790,22 @@ bool LLMediaImplGStreamer::pause() | |||
646 | if (!mPlaybin || mState == GST_STATE_NULL) | 790 | if (!mPlaybin || mState == GST_STATE_NULL) |
647 | return true; | 791 | return true; |
648 | 792 | ||
649 | llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); | 793 | GstStateChangeReturn state_change; |
650 | mState = GST_STATE_PAUSED; | ||
651 | |||
652 | GstStateChangeReturn state_change = llgst_element_get_state(mPlaybin, NULL, NULL, GST_CLOCK_TIME_NONE); | ||
653 | LL_DEBUGS("MediaImpl") << "get_state: " << llgst_element_state_change_return_get_name(state_change) << LL_ENDL; | ||
654 | 794 | ||
655 | return true; | 795 | state_change = gst_element_set_state(mPlaybin, GST_STATE_PAUSED); |
796 | |||
797 | LL_DEBUGS("MediaImpl") << gst_element_state_change_return_get_name(state_change) << LL_ENDL; | ||
798 | |||
799 | if (state_change == GST_STATE_CHANGE_FAILURE) | ||
800 | { | ||
801 | LL_WARNS("MediaImpl") << "could not pause stream!" << LL_ENDL; | ||
802 | return false; | ||
803 | } | ||
804 | else | ||
805 | { | ||
806 | mState = GST_STATE_PAUSED; | ||
807 | return true; | ||
808 | } | ||
656 | }; | 809 | }; |
657 | 810 | ||
658 | 811 | ||
@@ -671,7 +824,7 @@ bool LLMediaImplGStreamer::seek(double time) | |||
671 | bool success = false; | 824 | bool success = false; |
672 | if (mPlaybin) | 825 | if (mPlaybin) |
673 | { | 826 | { |
674 | success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, | 827 | success = gst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, |
675 | GstSeekFlags(GST_SEEK_FLAG_FLUSH | | 828 | GstSeekFlags(GST_SEEK_FLAG_FLUSH | |
676 | GST_SEEK_FLAG_KEY_UNIT), | 829 | GST_SEEK_FLAG_KEY_UNIT), |
677 | GST_SEEK_TYPE_SET, gint64(time*1000000000.0F), | 830 | GST_SEEK_TYPE_SET, gint64(time*1000000000.0F), |