00001
00033 #include "llmediaimplgstreamer.h"
00034
00035 #if LL_GSTREAMER_ENABLED
00036
00037 extern "C" {
00038 #include <gst/gst.h>
00039 }
00040
00041 #include "llmediamanager.h"
00042 #include "llmediaimplregister.h"
00043
00044 #include "llmediaimplgstreamervidplug.h"
00045
00046 #ifdef LL_GST_SOUNDSINK
00047 #include "llmediaimplgstreamersndplug.h"
00048 #endif // LL_GST_SOUNDSINK
00049
00050 #include "llmediaimplgstreamer_syms.h"
00051
00052
00053 static LLMediaImplRegister sLLMediaImplGStreamerReg( "LLMediaImplGStreamer", new LLMediaImplGStreamerMaker() );
00054
00055 LLMediaImplGStreamerMaker::LLMediaImplGStreamerMaker()
00056 {
00057
00058 mSchema.push_back( "rtsp" );
00059 mSchema.push_back( "rtmp" );
00060
00061
00062 mMimeTypeCategories.push_back( "video" );
00063 mMimeTypeCategories.push_back( "audio" );
00064 }
00065
00067
00068 LLMediaImplGStreamer::
00069 LLMediaImplGStreamer () :
00070 mediaData ( NULL ),
00071 mMediaRowbytes ( 1 ),
00072 mTextureFormatPrimary ( LL_MEDIA_BGRA ),
00073 mTextureFormatType ( LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV ),
00074 mPump ( NULL ),
00075 mPlaybin ( NULL ),
00076 mVideoSink ( NULL )
00077 #ifdef LL_GST_SOUNDSINK
00078 ,mAudioSink ( NULL )
00079 #endif
00080 {
00081 DEBUGMSG("constructing media...");
00082
00083 setMediaDepth(4);
00084
00085
00086 mPump = g_main_loop_new (NULL, FALSE);
00087 if (!mPump)
00088 {
00089 return;
00090 }
00091
00092
00093 mPlaybin = llgst_element_factory_make ("playbin", "play");
00094 if (!mPlaybin)
00095 {
00096
00097 return;
00098 }
00099
00100 if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) {
00101
00102 mVideoSink =
00103 GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo"));
00104 if (!mVideoSink)
00105 {
00106 WARNMSG("Could not instantiate private-slvideo element.");
00107
00108 return;
00109 }
00110
00111 g_object_set(mPlaybin, "video-sink", mVideoSink, NULL);
00112
00113 #ifdef LL_GST_SOUNDSINK
00114
00115 mAudioSink =
00116 GST_SLSOUND(llgst_element_factory_make ("private-slsound", "slsound"));
00117 if (!mAudioSink)
00118 {
00119 WARNMSG("Could not instantiate private-slsound element.");
00120
00121 return;
00122 }
00123
00124 g_object_set(mPlaybin, "audio-sink", mAudioSink, NULL);
00125 #endif
00126 }
00127 }
00128
00129
00130 int LLMediaImplGStreamer::getTextureFormatPrimary() const
00131 {
00132 return mTextureFormatPrimary;
00133 }
00134
00135
00136 int LLMediaImplGStreamer::getTextureFormatType() const
00137 {
00138 return mTextureFormatType;
00139 }
00140
00141
00142 int LLMediaImplGStreamer::getTextureFormatInternal() const
00143 {
00144 return LL_MEDIA_RGB8;
00145 }
00146
00148
00149 LLMediaImplGStreamer::
00150 ~LLMediaImplGStreamer ()
00151 {
00152 DEBUGMSG("dtor of media...");
00153 unload();
00154 }
00155
00157
00158 std::string LLMediaImplGStreamer::getVersion()
00159 {
00160 std::string rtn;
00161 rtn = "[" + sLLMediaImplGStreamerReg.getImplName() + "] - GStreamer 0.10.x";
00162 return rtn;
00163 }
00164
00166
00167 bool
00168 LLMediaImplGStreamer::
00169 startup ( LLMediaManagerData* init_data )
00170 {
00171 static bool done_init = false;
00172 if (!done_init)
00173 {
00174
00175 if (! grab_gst_syms("libgstreamer-0.10.so.0",
00176 "libgstvideo-0.10.so.0",
00177 "libgstaudio-0.10.so.0") )
00178 {
00179 WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled.");
00180 return false;
00181 }
00182
00183 if (llgst_segtrap_set_enabled)
00184 llgst_segtrap_set_enabled(FALSE);
00185 else
00186 WARNMSG("gst_segtrap_set_enabled() is not available; Automated crash-reporter may cease to function until next restart.");
00187
00188
00189 static std::string saved_locale;
00190 saved_locale = setlocale(LC_ALL, NULL);
00191 if (0 == llgst_init_check(NULL, NULL, NULL))
00192 {
00193 WARNMSG("GST init failed for unspecified reason.");
00194 setlocale(LC_ALL, saved_locale.c_str() );
00195 return false;
00196 }
00197 setlocale(LC_ALL, saved_locale.c_str() );
00198
00199
00200 gst_slvideo_init_class();
00201 #if 0
00202 gst_slsound_init_class();
00203 #endif
00204
00205 done_init = true;
00206 }
00207
00208 return true;
00209 }
00210
00211
00212 bool LLMediaImplGStreamer::
00213 closedown()
00214 {
00215 ungrab_gst_syms();
00216
00217 return true;
00218 }
00219
00220
00222
00223
00224 #ifdef LL_GST_REPORT_STATE_CHANGES
00225 static char* get_gst_state_name(GstState state)
00226 {
00227 switch (state) {
00228 case GST_STATE_VOID_PENDING: return "VOID_PENDING";
00229 case GST_STATE_NULL: return "NULL";
00230 case GST_STATE_READY: return "READY";
00231 case GST_STATE_PAUSED: return "PAUSED";
00232 case GST_STATE_PLAYING: return "PLAYING";
00233 }
00234 return "(unknown)";
00235 }
00236 #endif // LL_GST_REPORT_STATE_CHANGES
00237
00238 static gboolean
00239 bus_callback (GstBus *bus,
00240 GstMessage *message,
00241 gpointer data)
00242 {
00243 if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED &&
00244 GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING)
00245 {
00246 DEBUGMSG("Got GST message type: %s",
00247 LLGST_MESSAGE_TYPE_NAME (message));
00248 }
00249 else
00250 {
00251 DEBUGMSG("Got GST message type: %s",
00252 LLGST_MESSAGE_TYPE_NAME (message));
00253 }
00254
00255 LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data;
00256
00257 switch (GST_MESSAGE_TYPE (message)) {
00258 case GST_MESSAGE_BUFFERING: {
00259
00260 if (llgst_message_parse_buffering)
00261 {
00262 gint percent = 0;
00263 llgst_message_parse_buffering(message, &percent);
00264 DEBUGMSG("GST buffering: %d%%", percent);
00265 LLMediaEvent event( impl, percent );
00266 impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event );
00267
00268 }
00269 break;
00270 }
00271 case GST_MESSAGE_STATE_CHANGED: {
00272 GstState old_state;
00273 GstState new_state;
00274 GstState pending_state;
00275 llgst_message_parse_state_changed(message,
00276 &old_state,
00277 &new_state,
00278 &pending_state);
00279 #ifdef LL_GST_REPORT_STATE_CHANGES
00280
00281 DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s",
00282 get_gst_state_name(old_state),
00283 get_gst_state_name(new_state),
00284 get_gst_state_name(pending_state));
00285 #endif // LL_GST_REPORT_STATE_CHANGES
00286
00287 switch (new_state) {
00288 case GST_STATE_VOID_PENDING:
00289 break;
00290 case GST_STATE_NULL:
00291 break;
00292 case GST_STATE_READY:
00293 break;
00294 case GST_STATE_PAUSED:
00295 break;
00296 case GST_STATE_PLAYING:
00297 LLMediaEvent event( impl, 100 );
00298 impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event );
00299
00300 LLMediaEvent event2( impl );
00301 impl->getEventEmitter().update( &LLMediaObserver::onMediaLoaded, event2 );
00302 break;
00303 }
00304 break;
00305 }
00306 case GST_MESSAGE_ERROR: {
00307 GError *err = NULL;
00308 gchar *debug = NULL;
00309
00310 llgst_message_parse_error (message, &err, &debug);
00311 WARNMSG("GST error: %s", err->message);
00312 g_error_free (err);
00313 g_free (debug);
00314
00315 impl->addCommand(LLMediaBase::COMMAND_STOP);
00316
00317 break;
00318 }
00319 case GST_MESSAGE_INFO: {
00320 if (llgst_message_parse_info)
00321 {
00322 GError *err = NULL;
00323 gchar *debug = NULL;
00324
00325 llgst_message_parse_info (message, &err, &debug);
00326 INFOMSG("GST info: %s", err->message);
00327 g_error_free (err);
00328 g_free (debug);
00329 }
00330 break;
00331 }
00332 case GST_MESSAGE_WARNING: {
00333 GError *err = NULL;
00334 gchar *debug = NULL;
00335
00336 llgst_message_parse_warning (message, &err, &debug);
00337 WARNMSG("GST warning: %s", err->message);
00338 g_error_free (err);
00339 g_free (debug);
00340
00341 break;
00342 }
00343 case GST_MESSAGE_EOS:
00344
00345 DEBUGMSG("GST end-of-stream.");
00346 if (impl->isLooping())
00347 {
00348 DEBUGMSG("looping media...");
00349 impl->stop();
00350 impl->play();
00351 }
00352 else
00353 {
00354
00355 impl->addCommand(LLMediaBase::COMMAND_STOP);
00356 }
00357 break;
00358 default:
00359
00360 break;
00361 }
00362
00363
00364
00365
00366
00367 return TRUE;
00368 }
00369
00371
00372 bool
00373 LLMediaImplGStreamer::
00374 navigateTo ( const std::string urlIn )
00375 {
00376 DEBUGMSG("Setting media URI: %s", urlIn.c_str());
00377
00378 if (NULL == mPump
00379 #ifdef LL_GST_SOUNDSINK
00380 || NULL == mAudioSink
00381 #endif
00382 || NULL == mPlaybin)
00383 {
00384 return false;
00385 }
00386
00387 setStatus( LLMediaBase::STATUS_NAVIGATING );
00388
00389
00390 g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL);
00391
00392
00393
00394 GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
00395 if (!bus)
00396 {
00397 return false;
00398 }
00399 llgst_bus_add_watch (bus, bus_callback, this);
00400 llgst_object_unref (bus);
00401
00402
00403 play();
00404
00405 return true;
00406 }
00407
00409
00410 bool
00411 LLMediaImplGStreamer::
00412 unload ()
00413 {
00414 DEBUGMSG("unloading media...");
00415 if (mPlaybin)
00416 {
00417 llgst_element_set_state (mPlaybin, GST_STATE_NULL);
00418 llgst_object_unref (GST_OBJECT (mPlaybin));
00419 mPlaybin = NULL;
00420 }
00421
00422 if (mPump)
00423 {
00424 g_main_loop_quit(mPump);
00425 mPump = NULL;
00426 }
00427
00428 if (mediaData)
00429 {
00430 delete mediaData;
00431 mediaData = NULL;
00432 }
00433
00434 mVideoSink = NULL;
00435
00436 return true;
00437 }
00438
00440
00441 bool
00442 LLMediaImplGStreamer::
00443 updateMedia ()
00444 {
00445 DEBUGMSG("updating media...");
00446
00447
00448 if (NULL == mPump
00449 #ifdef LL_GST_SOUNDSINK
00450 || NULL == mAudioSink
00451 #endif
00452 || NULL == mPlaybin)
00453 {
00454 DEBUGMSG("dead media...");
00455 return false;
00456 }
00457
00458
00459 switch (nextCommand())
00460 {
00461 case LLMediaBase::COMMAND_START:
00462 DEBUGMSG("COMMAND_START");
00463 if (getStatus() == LLMediaBase::STATUS_PAUSED ||
00464 getStatus() == LLMediaBase::STATUS_NAVIGATING ||
00465 getStatus() == LLMediaBase::STATUS_STOPPED)
00466 {
00467 DEBUGMSG("doing COMMAND_START");
00468 play();
00469 setStatus(LLMediaBase::STATUS_STARTED);
00470 clearCommand();
00471 }
00472 break;
00473 case LLMediaBase::COMMAND_STOP:
00474 DEBUGMSG("COMMAND_STOP");
00475 DEBUGMSG("doing COMMAND_STOP");
00476 stop();
00477 setStatus(LLMediaBase::STATUS_STOPPED);
00478 clearCommand();
00479 break;
00480 case LLMediaBase::COMMAND_PAUSE:
00481 DEBUGMSG("COMMAND_PAUSE");
00482 if (getStatus() == LLMediaBase::STATUS_STARTED)
00483 {
00484 DEBUGMSG("doing COMMAND_PAUSE");
00485 pause();
00486 setStatus(LLMediaBase::STATUS_PAUSED);
00487 clearCommand();
00488 }
00489 break;
00490 default:
00491 DEBUGMSG("COMMAND_?");
00492 clearCommand();
00493 break;
00494 case LLMediaBase::COMMAND_NONE:
00495 break;
00496 }
00497
00498
00499 if (g_main_context_pending(g_main_loop_get_context(mPump)))
00500 {
00501 g_main_context_iteration(g_main_loop_get_context(mPump), FALSE);
00502 }
00503
00504 if (mVideoSink)
00505 {
00506 GST_OBJECT_LOCK(mVideoSink);
00507 if (mVideoSink->retained_frame_ready)
00508 {
00509 DEBUGMSG("NEW FRAME ");
00510 if (mVideoSink->retained_frame_width != getMediaWidth() ||
00511 mVideoSink->retained_frame_height != getMediaHeight())
00512
00513 {
00514
00515 int neww = mVideoSink->retained_frame_width;
00516 int newh = mVideoSink->retained_frame_height;
00517 int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format];
00518 if (SLV_PF_RGBX == mVideoSink->retained_frame_format)
00519 {
00520 mTextureFormatPrimary = LL_MEDIA_RGBA;
00521 mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV;
00522 }
00523 else
00524 {
00525 mTextureFormatPrimary = LL_MEDIA_BGRA;
00526 mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV;
00527 }
00528 mMediaRowbytes = neww * newd;
00529 DEBUGMSG("video container resized to %dx%d",
00530 neww, newh);
00531
00532 delete[] mediaData;
00533 mediaData = new unsigned char[mMediaRowbytes *
00534 newh];
00535
00536 GST_OBJECT_UNLOCK(mVideoSink);
00537
00538 setMediaDepth(newd);
00539 setMediaSize(neww, newh);
00540 return true;
00541 }
00542
00543
00544 mVideoSink->retained_frame_ready = FALSE;
00545 memcpy(mediaData, mVideoSink->retained_frame_data,
00546 mMediaRowbytes * getMediaHeight());
00547
00548 GST_OBJECT_UNLOCK(mVideoSink);
00549 LLMediaEvent event( this );
00550 mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event );
00551 return true;
00552 }
00553 else
00554 {
00555
00556 GST_OBJECT_UNLOCK(mVideoSink);
00557 return true;
00558 }
00559 }
00560
00561 return true;
00562 }
00563
00565
00566 bool
00567 LLMediaImplGStreamer::
00568 stop ()
00569 {
00570 DEBUGMSG("stopping media...");
00571
00572 llgst_element_set_state(mPlaybin, GST_STATE_READY);
00573 return true;
00574 }
00575
00577
00578 bool
00579 LLMediaImplGStreamer::
00580 play ()
00581 {
00582 DEBUGMSG("playing media...");
00583
00584 llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
00585 return true;
00586 }
00587
00589
00590 bool
00591 LLMediaImplGStreamer::
00592 pause ()
00593 {
00594 DEBUGMSG("pausing media...");
00595
00596 llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
00597 return true;
00598 };
00599
00600
00602
00603 unsigned char*
00604 LLMediaImplGStreamer::
00605 getMediaData ()
00606 {
00607 return mediaData;
00608 }
00609
00610
00612
00613 bool
00614 LLMediaImplGStreamer::
00615 setVolume(float volume)
00616 {
00617 mVolume = volume;
00618 if (mPlaybin)
00619 {
00620 g_object_set(mPlaybin, "volume", mVolume, NULL);
00621 return true;
00622 }
00623 return false;
00624 }
00625
00626 #endif // LL_GSTREAMER_ENABLED