diff options
author | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:34 -0500 |
commit | cd17687f01420952712a500107e0f93e7ab8d5f8 (patch) | |
tree | ce48c2b706f2c1176290e39fb555fbdf6648ce01 /linden/indra/llmedia/llmediaimplgstreamer.cpp | |
parent | Second Life viewer sources 1.19.0.5 (diff) | |
download | meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.zip meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.gz meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.bz2 meta-impy-cd17687f01420952712a500107e0f93e7ab8d5f8.tar.xz |
Second Life viewer sources 1.19.1.0
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llmedia/llmediaimplgstreamer.cpp | 652 |
1 files changed, 277 insertions, 375 deletions
diff --git a/linden/indra/llmedia/llmediaimplgstreamer.cpp b/linden/indra/llmedia/llmediaimplgstreamer.cpp index 50dc052..b54d088 100644 --- a/linden/indra/llmedia/llmediaimplgstreamer.cpp +++ b/linden/indra/llmedia/llmediaimplgstreamer.cpp | |||
@@ -1,5 +1,6 @@ | |||
1 | /** | 1 | /** |
2 | * @file llmediaimplgstreamer.cpp | 2 | * @file llmediaimplgstreamer.cpp |
3 | * @author Tofu Linden | ||
3 | * @brief implementation that supports various media through GStreamer. | 4 | * @brief implementation that supports various media through GStreamer. |
4 | * | 5 | * |
5 | * $LicenseInfo:firstyear=2007&license=viewergpl$ | 6 | * $LicenseInfo:firstyear=2007&license=viewergpl$ |
@@ -29,7 +30,7 @@ | |||
29 | * $/LicenseInfo$ | 30 | * $/LicenseInfo$ |
30 | */ | 31 | */ |
31 | 32 | ||
32 | #include "linden_common.h" | 33 | #include "llmediaimplgstreamer.h" |
33 | 34 | ||
34 | #if LL_GSTREAMER_ENABLED | 35 | #if LL_GSTREAMER_ENABLED |
35 | 36 | ||
@@ -37,7 +38,8 @@ extern "C" { | |||
37 | #include <gst/gst.h> | 38 | #include <gst/gst.h> |
38 | } | 39 | } |
39 | 40 | ||
40 | #include "llmediaimplgstreamer.h" | 41 | #include "llmediamanager.h" |
42 | #include "llmediaimplregister.h" | ||
41 | 43 | ||
42 | #include "llmediaimplgstreamervidplug.h" | 44 | #include "llmediaimplgstreamervidplug.h" |
43 | 45 | ||
@@ -47,17 +49,28 @@ extern "C" { | |||
47 | 49 | ||
48 | #include "llmediaimplgstreamer_syms.h" | 50 | #include "llmediaimplgstreamer_syms.h" |
49 | 51 | ||
50 | #include "llgl.h" | 52 | // register this impl with media manager factory |
51 | #include "llglheaders.h" // For gl texture modes | 53 | static LLMediaImplRegister sLLMediaImplGStreamerReg( "LLMediaImplGStreamer", new LLMediaImplGStreamerMaker() ); |
54 | |||
55 | LLMediaImplGStreamerMaker::LLMediaImplGStreamerMaker() | ||
56 | { | ||
57 | // Register to handle the scheme | ||
58 | mSchema.push_back( "rtsp" ); | ||
59 | mSchema.push_back( "rtmp" ); | ||
60 | |||
61 | // Register to handle the category | ||
62 | mMimeTypeCategories.push_back( "video" ); | ||
63 | mMimeTypeCategories.push_back( "audio" ); | ||
64 | } | ||
52 | 65 | ||
53 | /////////////////////////////////////////////////////////////////////////////// | 66 | /////////////////////////////////////////////////////////////////////////////// |
54 | // | 67 | // |
55 | LLMediaImplGStreamer:: | 68 | LLMediaImplGStreamer:: |
56 | LLMediaImplGStreamer () : | 69 | LLMediaImplGStreamer () : |
57 | mediaData ( NULL ), | 70 | mediaData ( NULL ), |
58 | ownBuffer ( TRUE ), | 71 | mMediaRowbytes ( 1 ), |
59 | mVolume ( 1.0f ), | 72 | mTextureFormatPrimary ( LL_MEDIA_BGRA ), |
60 | currentMode ( ModeIdle ), | 73 | mTextureFormatType ( LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV ), |
61 | mPump ( NULL ), | 74 | mPump ( NULL ), |
62 | mPlaybin ( NULL ), | 75 | mPlaybin ( NULL ), |
63 | mVideoSink ( NULL ) | 76 | mVideoSink ( NULL ) |
@@ -65,80 +78,95 @@ LLMediaImplGStreamer () : | |||
65 | ,mAudioSink ( NULL ) | 78 | ,mAudioSink ( NULL ) |
66 | #endif // LL_GST_SOUNDSINK | 79 | #endif // LL_GST_SOUNDSINK |
67 | { | 80 | { |
68 | mMediaDepthBytes = 4; | 81 | DEBUGMSG("constructing media..."); |
69 | mTextureDepth = 4; | 82 | |
70 | mTextureFormatInternal = GL_RGB8; | 83 | setMediaDepth(4); |
71 | mTextureFormatPrimary = GL_BGRA; | 84 | |
72 | mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; | 85 | // Create a pumpable main-loop for this media |
86 | mPump = g_main_loop_new (NULL, FALSE); | ||
87 | if (!mPump) | ||
88 | { | ||
89 | return; // error | ||
90 | } | ||
91 | |||
92 | // instantiate a playbin element to do the hard work | ||
93 | mPlaybin = llgst_element_factory_make ("playbin", "play"); | ||
94 | if (!mPlaybin) | ||
95 | { | ||
96 | // todo: cleanup pump | ||
97 | return; // error | ||
98 | } | ||
99 | |||
100 | if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { | ||
101 | // instantiate and connect a custom video sink | ||
102 | mVideoSink = | ||
103 | GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); | ||
104 | if (!mVideoSink) | ||
105 | { | ||
106 | WARNMSG("Could not instantiate private-slvideo element."); | ||
107 | // todo: cleanup. | ||
108 | return; // error | ||
109 | } | ||
110 | |||
111 | g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); | ||
112 | |||
113 | #ifdef LL_GST_SOUNDSINK | ||
114 | // instantiate and connect a custom audio sink | ||
115 | mAudioSink = | ||
116 | GST_SLSOUND(llgst_element_factory_make ("private-slsound", "slsound")); | ||
117 | if (!mAudioSink) | ||
118 | { | ||
119 | WARNMSG("Could not instantiate private-slsound element."); | ||
120 | // todo: cleanup. | ||
121 | return; // error | ||
122 | } | ||
123 | |||
124 | g_object_set(mPlaybin, "audio-sink", mAudioSink, NULL); | ||
125 | #endif | ||
126 | } | ||
73 | } | 127 | } |
74 | 128 | ||
75 | /////////////////////////////////////////////////////////////////////////////// | 129 | // virtual |
76 | // | 130 | int LLMediaImplGStreamer::getTextureFormatPrimary() const |
77 | LLMediaImplGStreamer:: | ||
78 | ~LLMediaImplGStreamer () | ||
79 | { | 131 | { |
80 | unload(); | 132 | return mTextureFormatPrimary; |
81 | } | 133 | } |
82 | 134 | ||
83 | void UnloadGStreamer() | 135 | // virtual |
136 | int LLMediaImplGStreamer::getTextureFormatType() const | ||
84 | { | 137 | { |
85 | ungrab_gst_syms(); | 138 | return mTextureFormatType; |
86 | } | 139 | } |
87 | 140 | ||
141 | // virtual | ||
142 | int LLMediaImplGStreamer::getTextureFormatInternal() const | ||
143 | { | ||
144 | return LL_MEDIA_RGB8; | ||
145 | } | ||
88 | 146 | ||
89 | /////////////////////////////////////////////////////////////////////////////// | 147 | /////////////////////////////////////////////////////////////////////////////// |
90 | // | 148 | // |
91 | BOOL | ||
92 | LLMediaImplGStreamer:: | 149 | LLMediaImplGStreamer:: |
93 | setBuffer ( U8* bufferIn ) | 150 | ~LLMediaImplGStreamer () |
94 | { | 151 | { |
95 | // Since we've pointed GStreamer at the old media data buffer | 152 | DEBUGMSG("dtor of media..."); |
96 | // directly, we need to be somewhat careful deleting it... | 153 | unload(); |
97 | U8* oldMediaData = mediaData; | 154 | } |
98 | BOOL ownedMediaData = ownBuffer; | ||
99 | |||
100 | if(bufferIn == NULL) | ||
101 | { | ||
102 | // Passing NULL to this function requests that the object | ||
103 | // allocate its own buffer. | ||
104 | mediaData = new unsigned char[ mMediaHeight * mMediaRowbytes ]; | ||
105 | ownBuffer = TRUE; | ||
106 | } | ||
107 | else | ||
108 | { | ||
109 | // Use the supplied buffer. | ||
110 | mediaData = bufferIn; | ||
111 | ownBuffer = FALSE; | ||
112 | } | ||
113 | |||
114 | if(mediaData == NULL) | ||
115 | { | ||
116 | // This is bad - probably out of memory. | ||
117 | llerrs << "LLMediaImplGStreamer::setBuffer: mediaData is NULL" << llendl; | ||
118 | // NOTE: This case doesn't clean up properly. This assert is fatal, so this isn't a huge problem, | ||
119 | // but if this assert is ever removed the code should be fixed to clean up correctly. | ||
120 | return FALSE; | ||
121 | } | ||
122 | |||
123 | // [..] | ||
124 | 155 | ||
125 | // Delete the old media data buffer iff we owned it. | 156 | //////////////////////////////////////////////////////////////////////////////// |
126 | if ( ownedMediaData ) | 157 | // virtual |
127 | { | 158 | std::string LLMediaImplGStreamer::getVersion() |
128 | if ( oldMediaData ) | 159 | { |
129 | { | 160 | std::string rtn; |
130 | delete [] oldMediaData; | 161 | rtn = "[" + sLLMediaImplGStreamerReg.getImplName() + "] - GStreamer 0.10.x"; |
131 | } | 162 | return rtn; |
132 | } | ||
133 | |||
134 | return TRUE; | ||
135 | } | 163 | } |
136 | 164 | ||
137 | /////////////////////////////////////////////////////////////////////////////// | 165 | /////////////////////////////////////////////////////////////////////////////// |
138 | // | 166 | // (static) super-initialization - called once at application startup |
139 | BOOL | 167 | bool |
140 | LLMediaImplGStreamer:: | 168 | LLMediaImplGStreamer:: |
141 | init () | 169 | startup ( LLMediaManagerData* init_data ) |
142 | { | 170 | { |
143 | static bool done_init = false; | 171 | static bool done_init = false; |
144 | if (!done_init) | 172 | if (!done_init) |
@@ -148,19 +176,19 @@ init () | |||
148 | "libgstvideo-0.10.so.0", | 176 | "libgstvideo-0.10.so.0", |
149 | "libgstaudio-0.10.so.0") ) | 177 | "libgstaudio-0.10.so.0") ) |
150 | { | 178 | { |
151 | llwarns << "Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled." << llendl; | 179 | WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); |
152 | return FALSE; | 180 | return false; |
153 | } | 181 | } |
154 | 182 | ||
155 | if (llgst_segtrap_set_enabled) | 183 | if (llgst_segtrap_set_enabled) |
156 | llgst_segtrap_set_enabled(FALSE); | 184 | llgst_segtrap_set_enabled(FALSE); |
157 | else | 185 | else |
158 | llwarns << "gst_segtrap_set_enabled() is not available; Second Life automated crash-reporter may cease to function until next restart." << llendl; | 186 | WARNMSG("gst_segtrap_set_enabled() is not available; Automated crash-reporter may cease to function until next restart."); |
159 | 187 | ||
160 | if (0 == llgst_init_check(NULL, NULL, NULL)) | 188 | if (0 == llgst_init_check(NULL, NULL, NULL)) |
161 | { | 189 | { |
162 | llwarns << "GST init failed for unspecified reason." << llendl; | 190 | WARNMSG("GST init failed for unspecified reason."); |
163 | return FALSE; | 191 | return false; |
164 | } | 192 | } |
165 | 193 | ||
166 | // Init our custom plugins - only really need do this once. | 194 | // Init our custom plugins - only really need do this once. |
@@ -172,52 +200,16 @@ init () | |||
172 | done_init = true; | 200 | done_init = true; |
173 | } | 201 | } |
174 | 202 | ||
175 | // Create a pumpable main-loop for this media | 203 | return true; |
176 | mPump = g_main_loop_new (NULL, FALSE); | 204 | } |
177 | if (!mPump) | ||
178 | { | ||
179 | return FALSE; | ||
180 | } | ||
181 | |||
182 | // instantiate a playbin element to do the hard work | ||
183 | mPlaybin = llgst_element_factory_make ("playbin", "play"); | ||
184 | if (!mPlaybin) | ||
185 | { | ||
186 | // todo: cleanup pump | ||
187 | return FALSE; | ||
188 | } | ||
189 | |||
190 | if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { | ||
191 | // instantiate and connect a custom video sink | ||
192 | mVideoSink = | ||
193 | GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); | ||
194 | if (!mVideoSink) | ||
195 | { | ||
196 | llwarns << "Could not instantiate private-slvideo element." | ||
197 | << llendl; | ||
198 | // todo: cleanup. | ||
199 | return FALSE; | ||
200 | } | ||
201 | |||
202 | g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); | ||
203 | 205 | ||
204 | #ifdef LL_GST_SOUNDSINK | ||
205 | // instantiate and connect a custom audio sink | ||
206 | mAudioSink = | ||
207 | GST_SLSOUND(llgst_element_factory_make ("private-slsound", "slsound")); | ||
208 | if (!mAudioSink) | ||
209 | { | ||
210 | llwarns << "Could not instantiate private-slsound element." | ||
211 | << llendl; | ||
212 | // todo: cleanup. | ||
213 | return FALSE; | ||
214 | } | ||
215 | 206 | ||
216 | g_object_set(mPlaybin, "audio-sink", mAudioSink, NULL); | 207 | bool LLMediaImplGStreamer:: |
217 | #endif | 208 | closedown() |
218 | } | 209 | { |
210 | ungrab_gst_syms(); | ||
219 | 211 | ||
220 | return LLMediaMovieBase::init(); | 212 | return true; |
221 | } | 213 | } |
222 | 214 | ||
223 | 215 | ||
@@ -239,22 +231,20 @@ static char* get_gst_state_name(GstState state) | |||
239 | #endif // LL_GST_REPORT_STATE_CHANGES | 231 | #endif // LL_GST_REPORT_STATE_CHANGES |
240 | 232 | ||
241 | static gboolean | 233 | static gboolean |
242 | my_bus_callback (GstBus *bus, | 234 | bus_callback (GstBus *bus, |
243 | GstMessage *message, | 235 | GstMessage *message, |
244 | gpointer data) | 236 | gpointer data) |
245 | { | 237 | { |
246 | if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && | 238 | if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && |
247 | GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) | 239 | GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) |
248 | { | 240 | { |
249 | llinfos << "Got GST message type: " | 241 | DEBUGMSG("Got GST message type: %s", |
250 | << LLGST_MESSAGE_TYPE_NAME (message) | 242 | LLGST_MESSAGE_TYPE_NAME (message)); |
251 | << llendl; | ||
252 | } | 243 | } |
253 | else | 244 | else |
254 | { | 245 | { |
255 | lldebugs << "Got GST message type: " | 246 | DEBUGMSG("Got GST message type: %s", |
256 | << LLGST_MESSAGE_TYPE_NAME (message) | 247 | LLGST_MESSAGE_TYPE_NAME (message)); |
257 | << llendl; | ||
258 | } | 248 | } |
259 | 249 | ||
260 | LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; | 250 | LLMediaImplGStreamer *impl = (LLMediaImplGStreamer*)data; |
@@ -266,11 +256,10 @@ my_bus_callback (GstBus *bus, | |||
266 | { | 256 | { |
267 | gint percent = 0; | 257 | gint percent = 0; |
268 | llgst_message_parse_buffering(message, &percent); | 258 | llgst_message_parse_buffering(message, &percent); |
269 | llinfos << "GST buffering: " << percent | 259 | DEBUGMSG("GST buffering: %d%%", percent); |
270 | << "%" << llendl; | 260 | LLMediaEvent event( impl, percent ); |
271 | // ModeBuffering seems to do nothing except make | 261 | impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); |
272 | // the UI worse | 262 | |
273 | /*if (percent < 100) impl->setCurrentMode(LLMediaImplGStreamer::ModeBuffering);*/ | ||
274 | } | 263 | } |
275 | break; | 264 | break; |
276 | } | 265 | } |
@@ -284,66 +273,63 @@ my_bus_callback (GstBus *bus, | |||
284 | &pending_state); | 273 | &pending_state); |
285 | #ifdef LL_GST_REPORT_STATE_CHANGES | 274 | #ifdef LL_GST_REPORT_STATE_CHANGES |
286 | // not generally very useful, and rather spammy. | 275 | // not generally very useful, and rather spammy. |
287 | llinfos << "state change (old,<new>,pending): " | 276 | DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s", |
288 | << get_gst_state_name(old_state) << ", <" | 277 | get_gst_state_name(old_state), |
289 | << get_gst_state_name(new_state) << ">, " | 278 | get_gst_state_name(new_state), |
290 | << get_gst_state_name(pending_state) << | 279 | get_gst_state_name(pending_state)); |
291 | llendl; | ||
292 | #endif // LL_GST_REPORT_STATE_CHANGES | 280 | #endif // LL_GST_REPORT_STATE_CHANGES |
293 | 281 | ||
294 | switch (new_state) { | 282 | switch (new_state) { |
295 | case GST_STATE_VOID_PENDING: | 283 | case GST_STATE_VOID_PENDING: |
296 | impl->setCurrentMode(LLMediaImplGStreamer::ModeNone); | ||
297 | break; | 284 | break; |
298 | case GST_STATE_NULL: | 285 | case GST_STATE_NULL: |
299 | impl->setCurrentMode(LLMediaImplGStreamer::ModeNone); | ||
300 | break; | 286 | break; |
301 | case GST_STATE_READY: | 287 | case GST_STATE_READY: |
302 | impl->setCurrentMode(LLMediaImplGStreamer::ModeStopped); | ||
303 | break; | 288 | break; |
304 | case GST_STATE_PAUSED: | 289 | case GST_STATE_PAUSED: |
305 | impl->setCurrentMode(LLMediaImplGStreamer::ModePaused); | ||
306 | break; | 290 | break; |
307 | case GST_STATE_PLAYING: | 291 | case GST_STATE_PLAYING: |
308 | impl->setCurrentMode(LLMediaImplGStreamer::ModePlaying); | 292 | LLMediaEvent event( impl, 100 ); |
293 | impl->getEventEmitter().update( &LLMediaObserver::onUpdateProgress, event ); | ||
294 | // emit an event to say that a media source was loaded | ||
295 | LLMediaEvent event2( impl ); | ||
296 | impl->getEventEmitter().update( &LLMediaObserver::onMediaLoaded, event2 ); | ||
309 | break; | 297 | break; |
310 | } | 298 | } |
311 | break; | 299 | break; |
312 | } | 300 | } |
313 | case GST_MESSAGE_ERROR: { | 301 | case GST_MESSAGE_ERROR: { |
314 | GError *err; | 302 | GError *err = NULL; |
315 | gchar *debug; | 303 | gchar *debug = NULL; |
316 | 304 | ||
317 | llgst_message_parse_error (message, &err, &debug); | 305 | llgst_message_parse_error (message, &err, &debug); |
318 | llinfos << "GST error: " << err->message << llendl; | 306 | WARNMSG("GST error: %s", err->message); |
319 | g_error_free (err); | 307 | g_error_free (err); |
320 | g_free (debug); | 308 | g_free (debug); |
321 | 309 | ||
322 | impl->setCurrentMode(LLMediaImplGStreamer::ModeError); | 310 | impl->addCommand(LLMediaBase::COMMAND_STOP); |
323 | |||
324 | impl->stop(); | ||
325 | 311 | ||
326 | break; | 312 | break; |
327 | } | 313 | } |
328 | case GST_MESSAGE_INFO: { | 314 | case GST_MESSAGE_INFO: { |
329 | if (llgst_message_parse_info) | 315 | if (llgst_message_parse_info) |
330 | { | 316 | { |
331 | GError *err; | 317 | GError *err = NULL; |
332 | gchar *debug; | 318 | gchar *debug = NULL; |
333 | 319 | ||
334 | llgst_message_parse_info (message, &err, &debug); | 320 | llgst_message_parse_info (message, &err, &debug); |
335 | llinfos << "GST info: " << err->message << llendl; | 321 | INFOMSG("GST info: %s", err->message); |
336 | g_error_free (err); | 322 | g_error_free (err); |
337 | g_free (debug); | 323 | g_free (debug); |
338 | } | 324 | } |
339 | break; | 325 | break; |
340 | } | 326 | } |
341 | case GST_MESSAGE_WARNING: { | 327 | case GST_MESSAGE_WARNING: { |
342 | GError *err; | 328 | GError *err = NULL; |
343 | gchar *debug; | 329 | gchar *debug = NULL; |
344 | 330 | ||
345 | llgst_message_parse_warning (message, &err, &debug); | 331 | llgst_message_parse_warning (message, &err, &debug); |
346 | llinfos << "GST warning: " << err->message << llendl; | 332 | WARNMSG("GST warning: %s", err->message); |
347 | g_error_free (err); | 333 | g_error_free (err); |
348 | g_free (debug); | 334 | g_free (debug); |
349 | 335 | ||
@@ -351,9 +337,18 @@ my_bus_callback (GstBus *bus, | |||
351 | } | 337 | } |
352 | case GST_MESSAGE_EOS: | 338 | case GST_MESSAGE_EOS: |
353 | /* end-of-stream */ | 339 | /* end-of-stream */ |
354 | llinfos << "GST EOS." << llendl; | 340 | DEBUGMSG("GST end-of-stream."); |
355 | impl->setCurrentMode(LLMediaImplGStreamer::ModeStopped);//? | 341 | if (impl->isLooping()) |
356 | impl->stop(); | 342 | { |
343 | DEBUGMSG("looping media..."); | ||
344 | impl->stop(); | ||
345 | impl->play(); | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | // inject a COMMAND_STOP | ||
350 | impl->addCommand(LLMediaBase::COMMAND_STOP); | ||
351 | } | ||
357 | break; | 352 | break; |
358 | default: | 353 | default: |
359 | /* unhandled message */ | 354 | /* unhandled message */ |
@@ -361,52 +356,57 @@ my_bus_callback (GstBus *bus, | |||
361 | } | 356 | } |
362 | 357 | ||
363 | /* we want to be notified again the next time there is a message | 358 | /* we want to be notified again the next time there is a message |
364 | * on the bus, so returning TRUE (FALSE means we want to stop watching | 359 | * on the bus, so return true (false means we want to stop watching |
365 | * for messages on the bus and our callback should not be called again) | 360 | * for messages on the bus and our callback should not be called again) |
366 | */ | 361 | */ |
367 | return TRUE; | 362 | return TRUE; |
368 | } | 363 | } |
369 | 364 | ||
370 | BOOL | 365 | /////////////////////////////////////////////////////////// |
366 | // virtual | ||
367 | bool | ||
371 | LLMediaImplGStreamer:: | 368 | LLMediaImplGStreamer:: |
372 | load ( const LLString& urlIn ) | 369 | navigateTo ( const std::string urlIn ) |
373 | { | 370 | { |
374 | llinfos << "Setting media URI: " << urlIn << llendl; | 371 | DEBUGMSG("Setting media URI: %s", urlIn.c_str()); |
372 | |||
373 | if (NULL == mPump | ||
374 | #ifdef LL_GST_SOUNDSINK | ||
375 | || NULL == mAudioSink | ||
376 | #endif | ||
377 | || NULL == mPlaybin) | ||
378 | { | ||
379 | return false; | ||
380 | } | ||
381 | |||
382 | setStatus( LLMediaBase::STATUS_NAVIGATING ); | ||
375 | 383 | ||
376 | // set URI | 384 | // set URI |
377 | g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); | 385 | g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); |
378 | //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); | 386 | //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); |
379 | 387 | ||
380 | // get playbin's bus - perhaps this can/should be done at init() | 388 | // get playbin's bus - perhaps this can/should be done in ctor |
381 | GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); | 389 | GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); |
382 | if (!bus) | 390 | if (!bus) |
383 | { | 391 | { |
384 | return FALSE; | 392 | return false; |
385 | } | 393 | } |
386 | llgst_bus_add_watch (bus, my_bus_callback, this); | 394 | llgst_bus_add_watch (bus, bus_callback, this); |
387 | llgst_object_unref (bus); | 395 | llgst_object_unref (bus); |
388 | 396 | ||
389 | if (true) // dummy values | 397 | // navigateTo implicitly plays, too. |
390 | { | 398 | play(); |
391 | const int fixedsize = 2; | ||
392 | mMediaRowbytes = mMediaDepthBytes * fixedsize; | ||
393 | mMediaWidth = fixedsize; | ||
394 | mMediaHeight = fixedsize; | ||
395 | mTextureWidth = fixedsize; | ||
396 | mTextureHeight = fixedsize; | ||
397 | } | ||
398 | 399 | ||
399 | BOOL rtn = LLMediaMovieBase::load(urlIn); | 400 | return true; |
400 | llinfos << "load returns " << int(rtn) << llendl; | ||
401 | return rtn; | ||
402 | } | 401 | } |
403 | 402 | ||
404 | /////////////////////////////////////////////////////////////////////////////// | 403 | /////////////////////////////////////////////////////////////////////////////// |
405 | // | 404 | // |
406 | BOOL | 405 | bool |
407 | LLMediaImplGStreamer:: | 406 | LLMediaImplGStreamer:: |
408 | unload () | 407 | unload () |
409 | { | 408 | { |
409 | DEBUGMSG("unloading media..."); | ||
410 | if (mPlaybin) | 410 | if (mPlaybin) |
411 | { | 411 | { |
412 | llgst_element_set_state (mPlaybin, GST_STATE_NULL); | 412 | llgst_element_set_state (mPlaybin, GST_STATE_NULL); |
@@ -422,25 +422,75 @@ unload () | |||
422 | 422 | ||
423 | if (mediaData) | 423 | if (mediaData) |
424 | { | 424 | { |
425 | if (ownBuffer) | 425 | delete mediaData; |
426 | { | 426 | mediaData = NULL; |
427 | delete mediaData; | ||
428 | mediaData = NULL; | ||
429 | } | ||
430 | } | 427 | } |
431 | 428 | ||
432 | mVideoSink = NULL; | 429 | mVideoSink = NULL; |
433 | 430 | ||
434 | return TRUE; | 431 | return true; |
435 | } | 432 | } |
436 | 433 | ||
437 | /////////////////////////////////////////////////////////////////////////////// | 434 | /////////////////////////////////////////////////////////////////////////////// |
438 | // | 435 | // virtual |
439 | S32 | 436 | bool |
440 | LLMediaImplGStreamer:: | 437 | LLMediaImplGStreamer:: |
441 | updateMedia () | 438 | updateMedia () |
442 | { | 439 | { |
443 | //llinfos << "updating media..." << llendl; | 440 | DEBUGMSG("updating media..."); |
441 | |||
442 | // sanity check | ||
443 | if (NULL == mPump | ||
444 | #ifdef LL_GST_SOUNDSINK | ||
445 | || NULL == mAudioSink | ||
446 | #endif | ||
447 | || NULL == mPlaybin) | ||
448 | { | ||
449 | DEBUGMSG("dead media..."); | ||
450 | return false; | ||
451 | } | ||
452 | |||
453 | // process next outstanding command | ||
454 | switch (nextCommand()) | ||
455 | { | ||
456 | case LLMediaBase::COMMAND_START: | ||
457 | DEBUGMSG("COMMAND_START"); | ||
458 | if (getStatus() == LLMediaBase::STATUS_PAUSED || | ||
459 | getStatus() == LLMediaBase::STATUS_NAVIGATING || | ||
460 | getStatus() == LLMediaBase::STATUS_STOPPED) | ||
461 | { | ||
462 | DEBUGMSG("doing COMMAND_START"); | ||
463 | play(); | ||
464 | setStatus(LLMediaBase::STATUS_STARTED); | ||
465 | clearCommand(); | ||
466 | } | ||
467 | break; | ||
468 | case LLMediaBase::COMMAND_STOP: | ||
469 | DEBUGMSG("COMMAND_STOP"); | ||
470 | DEBUGMSG("doing COMMAND_STOP"); | ||
471 | stop(); | ||
472 | setStatus(LLMediaBase::STATUS_STOPPED); | ||
473 | clearCommand(); | ||
474 | break; | ||
475 | case LLMediaBase::COMMAND_PAUSE: | ||
476 | DEBUGMSG("COMMAND_PAUSE"); | ||
477 | if (getStatus() == LLMediaBase::STATUS_STARTED) | ||
478 | { | ||
479 | DEBUGMSG("doing COMMAND_PAUSE"); | ||
480 | pause(); | ||
481 | setStatus(LLMediaBase::STATUS_PAUSED); | ||
482 | clearCommand(); | ||
483 | } | ||
484 | break; | ||
485 | default: | ||
486 | DEBUGMSG("COMMAND_?"); | ||
487 | clearCommand(); | ||
488 | break; | ||
489 | case LLMediaBase::COMMAND_NONE: | ||
490 | break; | ||
491 | } | ||
492 | |||
493 | // deal with results | ||
444 | if (g_main_context_pending(g_main_loop_get_context(mPump))) | 494 | if (g_main_context_pending(g_main_loop_get_context(mPump))) |
445 | { | 495 | { |
446 | g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); | 496 | g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); |
@@ -451,269 +501,121 @@ updateMedia () | |||
451 | GST_OBJECT_LOCK(mVideoSink); | 501 | GST_OBJECT_LOCK(mVideoSink); |
452 | if (mVideoSink->retained_frame_ready) | 502 | if (mVideoSink->retained_frame_ready) |
453 | { | 503 | { |
454 | //llinfos << "NEW FRAME " << llendl; | 504 | DEBUGMSG("NEW FRAME "); |
455 | if (mVideoSink->retained_frame_width != mMediaWidth || | 505 | if (mVideoSink->retained_frame_width != getMediaWidth() || |
456 | mVideoSink->retained_frame_height != mMediaHeight) | 506 | mVideoSink->retained_frame_height != getMediaHeight()) |
457 | // *TODO: also check for change in format | 507 | // *TODO: also check for change in format |
458 | { | 508 | { |
459 | // just resize container | 509 | // just resize containe |
460 | mMediaWidth = mVideoSink->retained_frame_width; | 510 | int neww = mVideoSink->retained_frame_width; |
461 | mMediaHeight = mVideoSink->retained_frame_height; | 511 | int newh = mVideoSink->retained_frame_height; |
462 | mTextureWidth = mMediaWidth; | 512 | int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; |
463 | mTextureHeight = mMediaHeight; | ||
464 | mMediaDepthBytes = mTextureDepth = | ||
465 | SLVPixelFormatBytes[mVideoSink->retained_frame_format]; | ||
466 | if (SLV_PF_RGBX == mVideoSink->retained_frame_format) | 513 | if (SLV_PF_RGBX == mVideoSink->retained_frame_format) |
467 | { | 514 | { |
468 | mTextureFormatPrimary = GL_RGBA; | 515 | mTextureFormatPrimary = LL_MEDIA_RGBA; |
469 | mTextureFormatType=GL_UNSIGNED_INT_8_8_8_8_REV; | 516 | mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; |
470 | } | 517 | } |
471 | else | 518 | else |
472 | { | 519 | { |
473 | mTextureFormatPrimary = GL_BGRA; | 520 | mTextureFormatPrimary = LL_MEDIA_BGRA; |
474 | mTextureFormatType=GL_UNSIGNED_INT_8_8_8_8_REV; | 521 | mTextureFormatType = LL_MEDIA_UNSIGNED_INT_8_8_8_8_REV; |
475 | } | 522 | } |
476 | mMediaRowbytes = mMediaWidth * mMediaDepthBytes; | 523 | mMediaRowbytes = neww * newd; |
477 | llinfos << "video container resized to " << | 524 | DEBUGMSG("video container resized to %dx%d", |
478 | mMediaWidth << "x" << mMediaHeight << llendl; | 525 | neww, newh); |
479 | 526 | ||
480 | if (ownBuffer) | 527 | delete[] mediaData; |
481 | { | 528 | mediaData = new unsigned char[mMediaRowbytes * |
482 | // we manage the buffer, so we need to realloc | 529 | newh]; |
483 | delete[] mediaData; | ||
484 | mediaData = new U8[mMediaRowbytes * | ||
485 | mMediaHeight]; | ||
486 | } | ||
487 | 530 | ||
488 | GST_OBJECT_UNLOCK(mVideoSink); | 531 | GST_OBJECT_UNLOCK(mVideoSink); |
489 | return updateMediaNeedsSizeChange; | 532 | |
533 | setMediaDepth(newd); | ||
534 | setMediaSize(neww, newh); | ||
535 | return true; | ||
490 | } | 536 | } |
491 | 537 | ||
492 | // we're gonna totally consume this frame - reset 'ready' flag | 538 | // we're gonna totally consume this frame - reset 'ready' flag |
493 | mVideoSink->retained_frame_ready = FALSE; | 539 | mVideoSink->retained_frame_ready = FALSE; |
494 | memcpy(mediaData, mVideoSink->retained_frame_data, | 540 | memcpy(mediaData, mVideoSink->retained_frame_data, |
495 | mMediaRowbytes * mMediaHeight); | 541 | mMediaRowbytes * getMediaHeight()); |
496 | 542 | ||
497 | GST_OBJECT_UNLOCK(mVideoSink); | 543 | GST_OBJECT_UNLOCK(mVideoSink); |
498 | return updateMediaNeedsUpdate; | 544 | LLMediaEvent event( this ); |
545 | mEventEmitter.update( &LLMediaObserver::onMediaContentsChange, event ); | ||
546 | return true; | ||
499 | } | 547 | } |
500 | else | 548 | else |
501 | { | 549 | { |
502 | // nothing to do yet. | 550 | // nothing to do yet. |
503 | GST_OBJECT_UNLOCK(mVideoSink); | 551 | GST_OBJECT_UNLOCK(mVideoSink); |
504 | return updateMediaNoChanges; | 552 | return true; |
505 | } | 553 | } |
506 | } | 554 | } |
507 | 555 | ||
508 | return updateMediaNoChanges; | 556 | return true; |
509 | } | ||
510 | |||
511 | /////////////////////////////////////////////////////////////////////////////// | ||
512 | // | ||
513 | void | ||
514 | LLMediaImplGStreamer:: | ||
515 | setAutoScaled ( BOOL autoScaledIn ) | ||
516 | { | ||
517 | autoScaled = autoScaledIn; | ||
518 | } | 557 | } |
519 | 558 | ||
520 | /////////////////////////////////////////////////////////////////////////////// | 559 | /////////////////////////////////////////////////////////////////////////////// |
521 | // | 560 | // |
522 | BOOL | 561 | bool |
523 | LLMediaImplGStreamer:: | 562 | LLMediaImplGStreamer:: |
524 | stop () | 563 | stop () |
525 | { | 564 | { |
526 | llinfos << "stopping media..." << llendl; | 565 | DEBUGMSG("stopping media..."); |
527 | // todo: error-check this? | 566 | // todo: error-check this? |
528 | llgst_element_set_state(mPlaybin, GST_STATE_READY); | 567 | llgst_element_set_state(mPlaybin, GST_STATE_READY); |
529 | 568 | return true; | |
530 | BOOL rtn = LLMediaMovieBase::stop(); | ||
531 | setCurrentMode(LLMediaImplGStreamer::ModeStopped);//? | ||
532 | return rtn; | ||
533 | } | 569 | } |
534 | 570 | ||
535 | /////////////////////////////////////////////////////////////////////////////// | 571 | /////////////////////////////////////////////////////////////////////////////// |
536 | // | 572 | // |
537 | BOOL | 573 | bool |
538 | LLMediaImplGStreamer:: | 574 | LLMediaImplGStreamer:: |
539 | play () | 575 | play () |
540 | { | 576 | { |
541 | llinfos << "playing media..." << llendl; | 577 | DEBUGMSG("playing media..."); |
542 | // todo: error-check this? | 578 | // todo: error-check this? |
543 | llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); | 579 | llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); |
544 | 580 | return true; | |
545 | return LLMediaMovieBase::play(); | ||
546 | } | 581 | } |
547 | 582 | ||
548 | /////////////////////////////////////////////////////////////////////////////// | 583 | /////////////////////////////////////////////////////////////////////////////// |
549 | // | 584 | // |
550 | BOOL | 585 | bool |
551 | LLMediaImplGStreamer:: | ||
552 | loop ( S32 howMany ) | ||
553 | { | ||
554 | llinfos << "looping media... " << howMany << llendl; | ||
555 | // todo: implement this | ||
556 | if (!play()) | ||
557 | return FALSE; | ||
558 | |||
559 | return LLMediaMovieBase::loop(howMany); | ||
560 | }; | ||
561 | |||
562 | /////////////////////////////////////////////////////////////////////////////// | ||
563 | // | ||
564 | BOOL | ||
565 | LLMediaImplGStreamer:: | 586 | LLMediaImplGStreamer:: |
566 | pause () | 587 | pause () |
567 | { | 588 | { |
568 | llinfos << "pausing media..." << llendl; | 589 | DEBUGMSG("pausing media..."); |
569 | // todo: error-check this? | 590 | // todo: error-check this? |
570 | llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); | 591 | llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); |
571 | 592 | return true; | |
572 | return LLMediaMovieBase::pause(); | ||
573 | }; | 593 | }; |
574 | 594 | ||
575 | /////////////////////////////////////////////////////////////////////////////// | ||
576 | // | ||
577 | BOOL | ||
578 | LLMediaImplGStreamer:: | ||
579 | setVolume ( F32 volumeIn ) | ||
580 | { | ||
581 | mVolume = volumeIn; | ||
582 | g_object_set(mPlaybin, "volume", mVolume, NULL); | ||
583 | return TRUE; | ||
584 | } | ||
585 | 595 | ||
586 | /////////////////////////////////////////////////////////////////////////////// | 596 | /////////////////////////////////////////////////////////////////////////////// |
587 | // | 597 | // virtual |
588 | F32 | 598 | unsigned char* |
589 | LLMediaImplGStreamer:: | ||
590 | getVolume () | ||
591 | { | ||
592 | return mVolume; | ||
593 | } | ||
594 | |||
595 | /////////////////////////////////////////////////////////////////////////////// | ||
596 | // | ||
597 | BOOL | ||
598 | LLMediaImplGStreamer:: | ||
599 | isIdle () const | ||
600 | { | ||
601 | // todo: probably semantically decouple from currentMode | ||
602 | return currentMode == ModeIdle; | ||
603 | } | ||
604 | |||
605 | /////////////////////////////////////////////////////////////////////////////// | ||
606 | // | ||
607 | BOOL | ||
608 | LLMediaImplGStreamer:: | ||
609 | isError () const | ||
610 | { | ||
611 | // todo: probably semantically decouple from currentMode | ||
612 | return currentMode == ModeError; | ||
613 | } | ||
614 | |||
615 | /////////////////////////////////////////////////////////////////////////////// | ||
616 | // | ||
617 | BOOL | ||
618 | LLMediaImplGStreamer:: | ||
619 | isBuffering () const | ||
620 | { | ||
621 | // todo: probably semantically decouple from currentMode | ||
622 | return currentMode == ModeBuffering; | ||
623 | } | ||
624 | |||
625 | /////////////////////////////////////////////////////////////////////////////// | ||
626 | // | ||
627 | BOOL | ||
628 | LLMediaImplGStreamer:: | ||
629 | isLoaded () const | ||
630 | { | ||
631 | // todo: probably semantically decouple from currentMode | ||
632 | //return currentMode == ModeLoaded; | ||
633 | return (mPump != NULL); | ||
634 | } | ||
635 | |||
636 | /////////////////////////////////////////////////////////////////////////////// | ||
637 | // | ||
638 | BOOL | ||
639 | LLMediaImplGStreamer:: | ||
640 | isPlaying () const | ||
641 | { | ||
642 | // todo: probably semantically decouple from currentMode | ||
643 | return currentMode == ModePlaying; | ||
644 | } | ||
645 | |||
646 | /////////////////////////////////////////////////////////////////////////////// | ||
647 | // | ||
648 | BOOL | ||
649 | LLMediaImplGStreamer:: | ||
650 | isLooping () const | ||
651 | { | ||
652 | // todo: probably semantically decouple from currentMode | ||
653 | return currentMode == ModeLooping; | ||
654 | } | ||
655 | |||
656 | /////////////////////////////////////////////////////////////////////////////// | ||
657 | // | ||
658 | BOOL | ||
659 | LLMediaImplGStreamer:: | ||
660 | isPaused () const | ||
661 | { | ||
662 | // todo: probably semantically decouple from currentMode | ||
663 | return currentMode == ModePaused; | ||
664 | } | ||
665 | |||
666 | /////////////////////////////////////////////////////////////////////////////// | ||
667 | // | ||
668 | BOOL | ||
669 | LLMediaImplGStreamer:: | ||
670 | isStopped () const | ||
671 | { | ||
672 | // todo: probably semantically decouple from currentMode | ||
673 | return currentMode == ModeStopped; | ||
674 | } | ||
675 | |||
676 | /////////////////////////////////////////////////////////////////////////////// | ||
677 | // | ||
678 | U8* | ||
679 | LLMediaImplGStreamer:: | 599 | LLMediaImplGStreamer:: |
680 | getMediaData () | 600 | getMediaData () |
681 | { | 601 | { |
682 | return mediaData; | 602 | return mediaData; |
683 | } | 603 | } |
684 | 604 | ||
685 | /////////////////////////////////////////////////////////////////////////////// | ||
686 | // | ||
687 | BOOL | ||
688 | LLMediaImplGStreamer:: | ||
689 | seek ( F64 time ) | ||
690 | { | ||
691 | // todo: implement this | ||
692 | llinfos << "Tried to seek to time " << time | ||
693 | << " - faking it" << llendl; | ||
694 | return TRUE; | ||
695 | } | ||
696 | |||
697 | /////////////////////////////////////////////////////////////////////////////// | ||
698 | // | ||
699 | F64 | ||
700 | LLMediaImplGStreamer:: | ||
701 | getTime () const | ||
702 | { | ||
703 | // todo: implement this | ||
704 | F64 result = 0; | ||
705 | return result; | ||
706 | } | ||
707 | 605 | ||
708 | /////////////////////////////////////////////////////////////////////////////// | 606 | /////////////////////////////////////////////////////////////////////////////// |
709 | // | 607 | // virtual |
710 | F64 | 608 | bool |
711 | LLMediaImplGStreamer:: | 609 | LLMediaImplGStreamer:: |
712 | getMediaDuration () const | 610 | setVolume(float volume) |
713 | { | 611 | { |
714 | // todo: implement this | 612 | mVolume = volume; |
715 | F64 result = 0; | 613 | if (mPlaybin) |
716 | return result; | 614 | { |
615 | g_object_set(mPlaybin, "volume", mVolume, NULL); | ||
616 | return true; | ||
617 | } | ||
618 | return false; | ||
717 | } | 619 | } |
718 | 620 | ||
719 | #endif // LL_GSTREAMER_ENABLED | 621 | #endif // LL_GSTREAMER_ENABLED |