aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewermedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llviewermedia.cpp')
-rw-r--r--linden/indra/newview/llviewermedia.cpp1451
1 files changed, 985 insertions, 466 deletions
diff --git a/linden/indra/newview/llviewermedia.cpp b/linden/indra/newview/llviewermedia.cpp
index 6bcf8ce..5c01b25 100644
--- a/linden/indra/newview/llviewermedia.cpp
+++ b/linden/indra/newview/llviewermedia.cpp
@@ -33,687 +33,1206 @@
33#include "llviewerprecompiledheaders.h" 33#include "llviewerprecompiledheaders.h"
34 34
35#include "llviewermedia.h" 35#include "llviewermedia.h"
36 36#include "llviewermediafocus.h"
37#include "llhoverview.h"
37#include "llmimetypes.h" 38#include "llmimetypes.h"
38#include "llviewercontrol.h" 39#include "llviewercontrol.h"
39#include "llviewerimage.h" 40#include "llviewerimage.h"
40#include "llviewerwindow.h" 41#include "llviewerwindow.h"
41#include "llviewerimagelist.h" 42#include "llviewerimagelist.h"
42#include "viewerversion.h" 43//#include "viewerversion.h"
44
45#include "llpluginclassmedia.h"
43 46
44#include "llevent.h" // LLSimpleListener 47#include "llevent.h" // LLSimpleListener
45#include "llmediamanager.h"
46#include "lluuid.h" 48#include "lluuid.h"
49#include "llkeyboard.h"
47 50
48#include <boost/bind.hpp> // for SkinFolder listener
49#include <boost/signal.hpp>
50 51
52// Merov: Temporary definitions while porting the new viewer media code to Snowglobe
53const int LEFT_BUTTON = 0;
54const int RIGHT_BUTTON = 1;
51 55
52// Implementation functions not exported into header file 56// Move this to its own file.
53class LLViewerMediaImpl 57
54 : public LLMediaObserver 58LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter()
55{ 59{
56 public: 60 observerListType::iterator iter = mObservers.begin();
57 LLViewerMediaImpl()
58 : mMediaSource( NULL ),
59 mMovieImageID(),
60 mMovieImageHasMips(false)
61 { }
62
63 void destroyMediaSource();
64
65 void play(const std::string& media_url,
66 const std::string& mime_type,
67 const LLUUID& placeholder_texture_id,
68 S32 media_width, S32 media_height, U8 media_auto_scale,
69 U8 media_loop);
70
71 void stop();
72 void pause();
73 void start();
74 void seek(F32 time);
75 void setVolume(F32 volume);
76 LLMediaBase::EStatus getStatus();
77
78 /*virtual*/ void onMediaSizeChange(const EventType& event_in);
79 /*virtual*/ void onMediaContentsChange(const EventType& event_in);
80
81 void updateMovieImage(const LLUUID& image_id, BOOL active);
82 void updateImagesMediaStreams();
83 LLUUID getMediaTextureID();
84
85 // Internally set our desired browser user agent string, including
86 // the Second Life version and skin name. Used because we can
87 // switch skins without restarting the app.
88 static void updateBrowserUserAgent();
89
90 // Callback for when the SkinCurrent control is changed to
91 // switch the user agent string to indicate the new skin.
92 static bool handleSkinCurrentChanged(const LLSD& newvalue);
93 61
94 public: 62 while( iter != mObservers.end() )
63 {
64 LLViewerMediaObserver *self = *iter;
65 iter++;
66 remObserver(self);
67 }
68}
95 69
96 // a single media url with some data and an impl. 70///////////////////////////////////////////////////////////////////////////////
97 LLMediaBase* mMediaSource; 71//
98 LLUUID mMovieImageID; 72bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer )
99 bool mMovieImageHasMips; 73{
100 std::string mMediaURL; 74 if ( ! observer )
101 std::string mMimeType; 75 return false;
102 private:
103 void initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source);
104};
105 76
106static LLViewerMediaImpl sViewerMediaImpl; 77 if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() )
78 return false;
107 79
108////////////////////////////////////////////////////////////////////////////////////////// 80 mObservers.push_back( observer );
81 observer->mEmitters.push_back( this );
109 82
110void LLViewerMediaImpl::destroyMediaSource() 83 return true;
84}
85
86///////////////////////////////////////////////////////////////////////////////
87//
88bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer )
89{
90 if ( ! observer )
91 return false;
92
93 mObservers.remove( observer );
94 observer->mEmitters.remove(this);
95
96 return true;
97}
98
99///////////////////////////////////////////////////////////////////////////////
100//
101void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event )
111{ 102{
112 LLMediaManager* mgr = LLMediaManager::getInstance(); 103 observerListType::iterator iter = mObservers.begin();
113 if ( mMediaSource ) 104
105 while( iter != mObservers.end() )
114 { 106 {
115 bool was_playing = LLViewerMedia::isMediaPlaying(); 107 LLViewerMediaObserver *self = *iter;
116 mMediaSource->remObserver(this); 108 ++iter;
117 mgr->destroySource( mMediaSource ); 109 self->handleMediaEvent( media, event );
110 }
111}
118 112
119 // Restore the texture 113// Move this to its own file.
120 updateMovieImage(LLUUID::null, was_playing); 114LLViewerMediaObserver::~LLViewerMediaObserver()
115{
116 std::list<LLViewerMediaEventEmitter *>::iterator iter = mEmitters.begin();
121 117
118 while( iter != mEmitters.end() )
119 {
120 LLViewerMediaEventEmitter *self = *iter;
121 iter++;
122 self->remObserver( this );
122 } 123 }
123 mMediaSource = NULL;
124} 124}
125 125
126void LLViewerMediaImpl::play(const std::string& media_url, 126
127 const std::string& mime_type, 127// Move this to its own file.
128 const LLUUID& placeholder_texture_id, 128// helper class that tries to download a URL from a web site and calls a method
129 S32 media_width, S32 media_height, U8 media_auto_scale, 129// on the Panel Land Media and to discover the MIME type
130 U8 media_loop) 130class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
131{ 131{
132 // first stop any previously playing media 132LOG_CLASS(LLMimeDiscoveryResponder);
133 stop(); 133public:
134 LLMimeDiscoveryResponder( viewer_media_t media_impl)
135 : mMediaImpl(media_impl),
136 mInitialized(false)
137 {}
138
134 139
135 // Save this first, as init/load below may fire events
136 mMovieImageID = placeholder_texture_id;
137 140
138 // If the mime_type passed in is different than the cached one, and 141 virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
139 // Auto-discovery is turned OFF, replace the cached mime_type with the new one. 142 {
140 if(mime_type != mMimeType && 143 std::string media_type = content["content-type"].asString();
141 ! gSavedSettings.getBOOL("AutoMimeDiscovery")) 144 std::string::size_type idx1 = media_type.find_first_of(";");
145 std::string mime_type = media_type.substr(0, idx1);
146 completeAny(status, mime_type);
147 }
148
149 virtual void error( U32 status, const std::string& reason )
142 { 150 {
143 mMimeType = mime_type; 151 // completeAny(status, "none/none");
144 } 152 }
145 LLURI url(media_url);
146 std::string scheme = url.scheme() != "" ? url.scheme() : "http";
147 153
148 LLMediaManager* mgr = LLMediaManager::getInstance(); 154 void completeAny(U32 status, const std::string& mime_type)
149 mMediaSource = mgr->createSourceFromMimeType(scheme, mMimeType );
150 if ( !mMediaSource )
151 { 155 {
152 if (mMimeType != "none/none") 156 if(!mInitialized && ! mime_type.empty())
153 { 157 {
154 llwarns << "media source create failed " << media_url 158 if (mMediaImpl->initializeMedia(mime_type))
155 << " type " << mMimeType 159 {
156 << llendl; 160 mInitialized = true;
161 mMediaImpl->play();
162 }
157 } 163 }
158 return;
159 } 164 }
160 165
161 // Store the URL and Mime Type 166 public:
162 mMediaURL = media_url; 167 viewer_media_t mMediaImpl;
168 bool mInitialized;
169};
170typedef std::list<LLViewerMediaImpl*> impl_list;
171static impl_list sViewerMediaImplList;
172
173//////////////////////////////////////////////////////////////////////////////////////////
174// LLViewerMedia
163 175
164 if ((media_width != 0) && (media_height != 0)) 176//////////////////////////////////////////////////////////////////////////////////////////
177// static
178viewer_media_t LLViewerMedia::newMediaImpl(const std::string& media_url,
179 const LLUUID& texture_id,
180 S32 media_width, S32 media_height, U8 media_auto_scale,
181 U8 media_loop,
182 std::string mime_type)
183{
184 LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id);
185 if(media_impl == NULL || texture_id.isNull())
165 { 186 {
166 mMediaSource->setRequestedMediaSize(media_width, media_height); 187 // Create the media impl
188 media_impl = new LLViewerMediaImpl(media_url, texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type);
189 sViewerMediaImplList.push_back(media_impl);
167 } 190 }
168 191 else
169 mMediaSource->setLooping(media_loop); 192 {
170 mMediaSource->setAutoScaled(media_auto_scale); 193 media_impl->stop();
171 mMediaSource->addObserver( this ); 194 media_impl->mTextureId = texture_id;
172 mMediaSource->navigateTo( media_url ); 195 media_impl->mMediaURL = media_url;
173 mMediaSource->addCommand(LLMediaBase::COMMAND_START); 196 media_impl->mMediaWidth = media_width;
197 media_impl->mMediaHeight = media_height;
198 media_impl->mMediaAutoScale = media_auto_scale;
199 media_impl->mMediaLoop = media_loop;
200 if(! media_url.empty())
201 media_impl->navigateTo(media_url, mime_type, true);
202 }
203 return media_impl;
174} 204}
175 205
176void LLViewerMediaImpl::stop() 206//////////////////////////////////////////////////////////////////////////////////////////
207// static
208void LLViewerMedia::removeMedia(LLViewerMediaImpl* media)
177{ 209{
178 destroyMediaSource(); 210 impl_list::iterator iter = sViewerMediaImplList.begin();
211 impl_list::iterator end = sViewerMediaImplList.end();
212
213 for(; iter != end; iter++)
214 {
215 if(media == *iter)
216 {
217 sViewerMediaImplList.erase(iter);
218 return;
219 }
220 }
179} 221}
180 222
181void LLViewerMediaImpl::pause() 223//////////////////////////////////////////////////////////////////////////////////////////
224// static
225LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id)
182{ 226{
183 if(mMediaSource) 227 impl_list::iterator iter = sViewerMediaImplList.begin();
228 impl_list::iterator end = sViewerMediaImplList.end();
229
230 for(; iter != end; iter++)
184 { 231 {
185 mMediaSource->addCommand(LLMediaBase::COMMAND_PAUSE); 232 LLViewerMediaImpl* media_impl = *iter;
233 if(media_impl->getMediaTextureID() == texture_id)
234 {
235 return media_impl;
236 }
186 } 237 }
238 return NULL;
187} 239}
188 240
189void LLViewerMediaImpl::start() 241//////////////////////////////////////////////////////////////////////////////////////////
242// static
243std::string LLViewerMedia::getCurrentUserAgent()
190{ 244{
191 if(mMediaSource) 245 // Don't include version, channel, or skin -- MC
246
247 // Don't use user-visible string to avoid
248 // punctuation and strange characters.
249 //std::string skin_name = gSavedSettings.getString("SkinCurrent");
250
251 // Just in case we need to check browser differences in A/B test
252 // builds.
253 //std::string channel = gSavedSettings.getString("VersionChannelName");
254
255 // append our magic version number string to the browser user agent id
256 // See the HTTP 1.0 and 1.1 specifications for allowed formats:
257 // http://www.ietf.org/rfc/rfc1945.txt section 10.15
258 // http://www.ietf.org/rfc/rfc2068.txt section 3.8
259 // This was also helpful:
260 // http://www.mozilla.org/build/revised-user-agent-strings.html
261 std::ostringstream codec;
262 codec << "SecondLife/";
263 codec << "C64 Basic V2";
264 //codec << ViewerVersion::getImpMajorVersion() << "." << ViewerVersion::getImpMinorVersion() << "." << ViewerVersion::getImpPatchVersion() << " " << ViewerVersion::getImpTestVersion();
265 //codec << " (" << channel << "; " << skin_name << " skin)";
266// llinfos << codec.str() << llendl;
267
268 return codec.str();
269}
270
271//////////////////////////////////////////////////////////////////////////////////////////
272// static
273void LLViewerMedia::updateBrowserUserAgent()
274{
275 std::string user_agent = getCurrentUserAgent();
276
277 impl_list::iterator iter = sViewerMediaImplList.begin();
278 impl_list::iterator end = sViewerMediaImplList.end();
279
280 for(; iter != end; iter++)
192 { 281 {
193 mMediaSource->addCommand(LLMediaBase::COMMAND_START); 282 LLViewerMediaImpl* pimpl = *iter;
283 if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser())
284 {
285 pimpl->mMediaSource->setBrowserUserAgent(user_agent);
286 }
194 } 287 }
288
195} 289}
196 290
197void LLViewerMediaImpl::seek(F32 time) 291//////////////////////////////////////////////////////////////////////////////////////////
292// static
293bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/)
198{ 294{
199 if(mMediaSource) 295 // gSavedSettings is already updated when this function is called.
296 updateBrowserUserAgent();
297 return true;
298}
299
300//////////////////////////////////////////////////////////////////////////////////////////
301// static
302bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id)
303{
304 impl_list::iterator iter = sViewerMediaImplList.begin();
305 impl_list::iterator end = sViewerMediaImplList.end();
306
307 for(; iter != end; iter++)
200 { 308 {
201 mMediaSource->seek(time); 309 LLViewerMediaImpl* pimpl = *iter;
310 if(pimpl->getMediaTextureID() == texture_id)
311 {
312 return true;
313 }
202 } 314 }
315 return false;
203} 316}
204 317
205void LLViewerMediaImpl::setVolume(F32 volume) 318//////////////////////////////////////////////////////////////////////////////////////////
319// static
320void LLViewerMedia::setVolume(F32 volume)
206{ 321{
207 if(mMediaSource) 322 impl_list::iterator iter = sViewerMediaImplList.begin();
323 impl_list::iterator end = sViewerMediaImplList.end();
324
325 for(; iter != end; iter++)
208 { 326 {
209 mMediaSource->setVolume( volume); 327 LLViewerMediaImpl* pimpl = *iter;
328 pimpl->setVolume(volume);
210 } 329 }
211} 330}
212 331
213LLMediaBase::EStatus LLViewerMediaImpl::getStatus() 332//////////////////////////////////////////////////////////////////////////////////////////
333// static
334void LLViewerMedia::updateMedia()
214{ 335{
215 if (mMediaSource) 336 impl_list::iterator iter = sViewerMediaImplList.begin();
337 impl_list::iterator end = sViewerMediaImplList.end();
338
339 for(; iter != end; iter++)
216 { 340 {
217 return mMediaSource->getStatus(); 341 LLViewerMediaImpl* pimpl = *iter;
342 pimpl->update();
218 } 343 }
219 else 344}
345
346//////////////////////////////////////////////////////////////////////////////////////////
347// static
348void LLViewerMedia::cleanupClass()
349{
350 // This is no longer necessary, since the list is no longer smart pointers.
351#if 0
352 while(!sViewerMediaImplList.empty())
220 { 353 {
221 return LLMediaBase::STATUS_UNKNOWN; 354 sViewerMediaImplList.pop_back();
222 } 355 }
356#endif
223} 357}
224 358
225////////////////////////////////////////////////////////////////////////////////////////// 359//////////////////////////////////////////////////////////////////////////////////////////
226// static 360// LLViewerMediaImpl
227void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) 361//////////////////////////////////////////////////////////////////////////////////////////
362LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url,
363 const LLUUID& texture_id,
364 S32 media_width,
365 S32 media_height,
366 U8 media_auto_scale,
367 U8 media_loop,
368 const std::string& mime_type)
369:
370 mMediaSource( NULL ),
371 mMovieImageHasMips(false),
372 mTextureId(texture_id),
373 mMediaWidth(media_width),
374 mMediaHeight(media_height),
375 mMediaAutoScale(media_auto_scale),
376 mMediaLoop(media_loop),
377 mMediaURL(media_url),
378 mMimeType(mime_type),
379 mNeedsNewTexture(true),
380 mSuspendUpdates(false),
381 mVisible(true)
382{
383 createMediaSource();
384}
385
386//////////////////////////////////////////////////////////////////////////////////////////
387LLViewerMediaImpl::~LLViewerMediaImpl()
228{ 388{
229 // IF the media image hasn't changed, do nothing 389 if( gEditMenuHandler == this )
230 if (mMovieImageID == uuid)
231 { 390 {
232 return; 391 gEditMenuHandler = NULL;
233 } 392 }
234 // If we have changed media uuid, restore the old one 393
235 if (!mMovieImageID.isNull()) 394 destroyMediaSource();
395 LLViewerMedia::removeMedia(this);
396}
397
398//////////////////////////////////////////////////////////////////////////////////////////
399bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
400{
401 if((mMediaSource == NULL) || (mMimeType != mime_type))
236 { 402 {
237 LLViewerImage* oldImage = LLViewerImage::getImage( mMovieImageID ); 403 if(! initializePlugin(mime_type))
238 if (oldImage)
239 { 404 {
240 oldImage->reinit(mMovieImageHasMips); 405 LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL;
241 oldImage->mIsMediaTexture = FALSE; 406 LLSD args;
407 args["MIME_TYPE"] = mime_type;
408 LLNotifications::instance().add("NoPlugin", args);
409
410 return false;
242 } 411 }
243 mMovieImageID.setNull();
244 } 412 }
245 // If the movie is playing, set the new media image 413
246 if (active && !uuid.isNull()) 414 // play();
415 return (mMediaSource != NULL);
416}
417
418//////////////////////////////////////////////////////////////////////////////////////////
419void LLViewerMediaImpl::createMediaSource()
420{
421 if(! mMediaURL.empty())
247 { 422 {
248 LLViewerImage* viewerImage = LLViewerImage::getImage( uuid ); 423 navigateTo(mMediaURL, mMimeType, true);
249 if( viewerImage ) 424 }
250 { 425 else if(! mMimeType.empty())
251 mMovieImageID = uuid; 426 {
252 // Can't use mipmaps for movies because they don't update the full image 427 initializeMedia(mMimeType);
253 mMovieImageHasMips = viewerImage->getUseMipMaps();
254 viewerImage->reinit(FALSE);
255 viewerImage->mIsMediaTexture = TRUE;
256 }
257 } 428 }
429
258} 430}
259 431
432//////////////////////////////////////////////////////////////////////////////////////////
433void LLViewerMediaImpl::destroyMediaSource()
434{
435 mNeedsNewTexture = true;
436 if(! mMediaSource)
437 {
438 return;
439 }
440 // Restore the texture
441 updateMovieImage(LLUUID::null, false);
442 delete mMediaSource;
443 mMediaSource = NULL;
444}
260 445
261////////////////////////////////////////////////////////////////////////////////////////// 446//////////////////////////////////////////////////////////////////////////////////////////
262// static 447void LLViewerMediaImpl::setMediaType(const std::string& media_type)
263void LLViewerMediaImpl::updateImagesMediaStreams()
264{ 448{
265 LLMediaManager::updateClass(); 449 mMimeType = media_type;
266} 450}
267 451
268void LLViewerMediaImpl::initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source) 452//////////////////////////////////////////////////////////////////////////////////////////
453/*static*/
454LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height)
269{ 455{
270 int media_width = media_source->getMediaWidth(); 456 std::string plugin_basename = LLMIMETypes::implType(media_type);
271 int media_height = media_source->getMediaHeight();
272 //int media_rowspan = media_source->getMediaRowSpan();
273 457
274 // if width & height are invalid, don't bother doing anything 458 if(plugin_basename.empty())
275 if ( media_width < 1 || media_height < 1 ) 459 {
276 return; 460 LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL;
461 }
462 else
463 {
464 std::string launcher_name = gDirUtilp->getLLPluginLauncher();
465 std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename);
466 std::string user_data_path = gDirUtilp->getOSUserAppDir();
467 user_data_path += gDirUtilp->getDirDelimiter();
468
469 // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.)
470 // If the linden username returned is blank, that can only mean we are
471 // at the login page displaying login Web page or Web browser test via Develop menu.
472 // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this
473 // is what we always used before this change)
474 std::string linden_user_dir = gDirUtilp->getLindenUserDir(true);
475 if ( ! linden_user_dir.empty() )
476 {
477 // gDirUtilp->getLindenUserDir() is whole path, not just Linden name
478 user_data_path = linden_user_dir;
479 user_data_path += gDirUtilp->getDirDelimiter();
480 }
277 481
278 llinfos << "initializing media placeholder" << llendl; 482 // See if the plugin executable exists
279 llinfos << "movie image id " << mMovieImageID << llendl; 483 llstat s;
484 if(LLFile::stat(launcher_name, &s))
485 {
486 LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL;
487 }
488 else if(LLFile::stat(plugin_name, &s))
489 {
490 LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL;
491 }
492 else
493 {
494 LLPluginClassMedia* media_source = new LLPluginClassMedia(owner);
495 media_source->setSize(default_width, default_height);
496 media_source->setUserDataPath(user_data_path);
497 media_source->setLanguageCode(LLUI::getLanguage());
280 498
281 int texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); 499 // collect 'cookies enabled' setting from prefs and send to embedded browser
282 int texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height ); 500 bool cookies_enabled = gSavedSettings.getBOOL( "BrowserCookiesEnabled" );
283 int texture_depth = media_source->getMediaDepth(); 501 media_source->enable_cookies( cookies_enabled );
284 502
285 // MEDIAOPT: check to see if size actually changed before doing work 503 // collect 'plugins enabled' setting from prefs and send to embedded browser
286 placeholder_image->destroyGLTexture(); 504 bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
287 // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? 505 media_source->setPluginsEnabled( plugins_enabled );
288 placeholder_image->reinit(FALSE); // probably not needed
289 506
290 // MEDIAOPT: seems insane that we actually have to make an imageraw then 507 // collect 'javascript enabled' setting from prefs and send to embedded browser
291 // immediately discard it 508 bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
292 LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); 509 media_source->setJavascriptEnabled( javascript_enabled );
293 raw->clear(0x0f, 0x0f, 0x0f, 0xff);
294 int discard_level = 0;
295 510
296 // ask media source for correct GL image format constants 511 if (media_source->init(launcher_name, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
297 placeholder_image->setExplicitFormat(media_source->getTextureFormatInternal(), 512 {
298 media_source->getTextureFormatPrimary(), 513 return media_source;
299 media_source->getTextureFormatType()); 514 }
515 else
516 {
517 LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL;
518 delete media_source;
519 }
520 }
521 }
300 522
301 placeholder_image->createGLTexture(discard_level, raw); 523 LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL;
524 LLSD args;
525 args["MIME_TYPE"] = media_type;
526 LLNotifications::instance().add("NoPlugin", args);
302 527
303 // placeholder_image->setExplicitFormat() 528 return NULL;
304 placeholder_image->setUseMipMaps(FALSE); 529}
305 530
306 // MEDIAOPT: set this dynamically on play/stop 531//////////////////////////////////////////////////////////////////////////////////////////
307 placeholder_image->mIsMediaTexture = true; 532bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
308} 533{
534 if(mMediaSource)
535 {
536 // Save the previous media source's last set size before destroying it.
537 mMediaWidth = mMediaSource->getSetWidth();
538 mMediaHeight = mMediaSource->getSetHeight();
539 }
540
541 // Always delete the old media impl first.
542 destroyMediaSource();
543
544 // and unconditionally set the mime type
545 mMimeType = media_type;
309 546
547 LLPluginClassMedia* media_source = newSourceFromMediaType(media_type, this, mMediaWidth, mMediaHeight);
548
549 if (media_source)
550 {
551 media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout"));
552 media_source->setLoop(mMediaLoop);
553 media_source->setAutoScale(mMediaAutoScale);
554 media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
555
556 mMediaSource = media_source;
557 return true;
558 }
310 559
560 return false;
561}
311 562
312// virtual 563void LLViewerMediaImpl::setSize(int width, int height)
313void LLViewerMediaImpl::onMediaContentsChange(const EventType& event_in) 564{
565 mMediaWidth = width;
566 mMediaHeight = height;
567 if(mMediaSource)
568 {
569 mMediaSource->setSize(width, height);
570 }
571}
572
573//////////////////////////////////////////////////////////////////////////////////////////
574void LLViewerMediaImpl::play()
314{ 575{
315 LLMediaBase* media_source = event_in.getSubject(); 576 // first stop any previously playing media
316 LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID ); 577 // stop();
317 if ((placeholder_image) && (placeholder_image->getHasGLTexture())) 578
579 // mMediaSource->addObserver( this );
580 if(mMediaSource == NULL)
318 { 581 {
319 if (placeholder_image->getUseMipMaps()) 582 if(!initializePlugin(mMimeType))
320 { 583 {
321 // bad image! NO MIPMAPS! 584 // Plugin failed initialization... should assert or something
322 initializePlaceholderImage(placeholder_image, media_source); 585 return;
323 } 586 }
587 }
588
589 // updateMovieImage(mTextureId, true);
324 590
325 U8* data = media_source->getMediaData(); 591 mMediaSource->loadURI( mMediaURL );
326 S32 x_pos = 0; 592 if(/*mMediaSource->pluginSupportsMediaTime()*/ true)
327 S32 y_pos = 0; 593 {
328 S32 width = media_source->getMediaWidth(); 594 start();
329 S32 height = media_source->getMediaHeight();
330 S32 data_width = media_source->getMediaDataWidth();
331 S32 data_height = media_source->getMediaDataHeight();
332 placeholder_image->setSubImage(data, data_width, data_height,
333 x_pos, y_pos, width, height);
334 } 595 }
335} 596}
336 597
598//////////////////////////////////////////////////////////////////////////////////////////
599void LLViewerMediaImpl::stop()
600{
601 if(mMediaSource)
602 {
603 mMediaSource->stop();
604 // destroyMediaSource();
605 }
606}
337 607
338// virtual 608//////////////////////////////////////////////////////////////////////////////////////////
339void LLViewerMediaImpl::onMediaSizeChange(const EventType& event_in) 609void LLViewerMediaImpl::pause()
340{ 610{
341 LLMediaBase* media_source = event_in.getSubject(); 611 if(mMediaSource)
342 LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID );
343 if (placeholder_image)
344 { 612 {
345 initializePlaceholderImage(placeholder_image, media_source); 613 mMediaSource->pause();
346 } 614 }
347 else 615}
616
617//////////////////////////////////////////////////////////////////////////////////////////
618void LLViewerMediaImpl::start()
619{
620 if(mMediaSource)
348 { 621 {
349 llinfos << "no placeholder image" << llendl; 622 mMediaSource->start();
350 } 623 }
351} 624}
352 625
626//////////////////////////////////////////////////////////////////////////////////////////
627void LLViewerMediaImpl::seek(F32 time)
628{
629 if(mMediaSource)
630 {
631 mMediaSource->seek(time);
632 }
633}
353 634
354 // Get the image we're using 635//////////////////////////////////////////////////////////////////////////////////////////
636void LLViewerMediaImpl::setVolume(F32 volume)
637{
638 if(mMediaSource)
639 {
640 mMediaSource->setVolume(volume);
641 }
642}
355 643
356 /* 644//////////////////////////////////////////////////////////////////////////////////////////
357 // update media stream if required 645void LLViewerMediaImpl::focus(bool focus)
358 LLMediaEngine* media_engine = LLMediaEngine::getInstance(); 646{
359 if (media_engine) 647 if (mMediaSource)
360 { 648 {
361 if ( media_engine->update() ) 649 // call focus just for the hell of it, even though this apopears to be a nop
362 { 650 mMediaSource->focus(focus);
363 LLUUID media_uuid = media_engine->getImageUUID(); 651 if (focus)
364 updateMovieImage(media_uuid, TRUE);
365 if (!media_uuid.isNull())
366 {
367 LLViewerImage* viewerImage = getImage( media_uuid );
368 if( viewerImage )
369 {
370 LLMediaBase* renderer = media_engine->getMediaRenderer();
371 if ((renderer->getTextureWidth() != viewerImage->getWidth()) ||
372 (renderer->getTextureHeight() != viewerImage->getHeight()) ||
373 (renderer->getTextureDepth() != viewerImage->getComponents()) ||
374 (viewerImage->getHasGLTexture() == FALSE))
375 {
376 // destroy existing GL image
377 viewerImage->destroyGLTexture();
378
379 // set new size
380 viewerImage->setSize( renderer->getTextureWidth(),
381 renderer->getTextureHeight(),
382 renderer->getTextureDepth() );
383
384 LLPointer<LLImageRaw> raw = new LLImageRaw(renderer->getTextureWidth(),
385 renderer->getTextureHeight(),
386 renderer->getTextureDepth());
387 raw->clear(0x7f,0x7f,0x7f,0xff);
388 viewerImage->createGLTexture(0, raw);
389 }
390
391 // Set the explicit format the instance wants
392 viewerImage->setExplicitFormat(renderer->getTextureFormatInternal(),
393 renderer->getTextureFormatPrimary(),
394 renderer->getTextureFormatType(),
395 renderer->getTextureFormatSwapBytes());
396 // This should be redundant, but just in case:
397 viewerImage->setUseMipMaps(FALSE);
398
399 LLImageRaw* rawImage = media_engine->getImageRaw();
400 if ( rawImage )
401 {
402 viewerImage->setSubImage(rawImage, 0, 0,
403 renderer->getMediaWidth(),
404 renderer->getMediaHeight());
405 }
406 }
407 else
408 {
409 llwarns << "MediaEngine update unable to get viewer image for GL texture" << llendl;
410 }
411 }
412 }
413 else
414 { 652 {
415 LLUUID media_uuid = media_engine->getImageUUID(); 653 // spoof a mouse click to *actually* pass focus
416 updateMovieImage(media_uuid, FALSE); 654 // Don't do this anymore -- it actually clicks through now.
655// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0);
656// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0);
417 } 657 }
418 } 658 }
419 */ 659}
420
421 660
422LLUUID LLViewerMediaImpl::getMediaTextureID() 661//////////////////////////////////////////////////////////////////////////////////////////
662void LLViewerMediaImpl::mouseDown(S32 x, S32 y)
423{ 663{
424 return mMovieImageID; 664 scaleMouse(&x, &y);
665 mLastMouseX = x;
666 mLastMouseY = y;
667 if (mMediaSource)
668 {
669 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, LEFT_BUTTON, x, y, 0);
670 }
425} 671}
426 672
427// static 673//////////////////////////////////////////////////////////////////////////////////////////
428void LLViewerMediaImpl::updateBrowserUserAgent() 674void LLViewerMediaImpl::mouseUp(S32 x, S32 y)
429{ 675{
430 // Don't use user-visible string to avoid 676 scaleMouse(&x, &y);
431 // punctuation and strange characters. 677 mLastMouseX = x;
432 std::string skin_name = gSavedSettings.getString("SkinCurrent"); 678 mLastMouseY = y;
433 679 if (mMediaSource)
434 // Just in case we need to check browser differences in A/B test 680 {
435 // builds. 681 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, x, y, 0);
436 std::string channel = gSavedSettings.getString("VersionChannelName"); 682 }
437
438 // append our magic version number string to the browser user agent id
439 // See the HTTP 1.0 and 1.1 specifications for allowed formats:
440 // http://www.ietf.org/rfc/rfc1945.txt section 10.15
441 // http://www.ietf.org/rfc/rfc2068.txt section 3.8
442 // This was also helpful:
443 // http://www.mozilla.org/build/revised-user-agent-strings.html
444 std::ostringstream codec;
445 codec << "SecondLife/";
446 codec << ViewerVersion::getLLMajorVersion() << "." << ViewerVersion::getLLMinorVersion() << "." << ViewerVersion::getLLPatchVersion() << "." << ViewerVersion::getLLBuildVersion();
447 codec << " (" << channel << "; " << skin_name << " skin)";
448 llinfos << codec.str() << llendl;
449 LLMediaManager::setBrowserUserAgent( codec.str() );
450} 683}
451 684
452// static 685//////////////////////////////////////////////////////////////////////////////////////////
453bool LLViewerMediaImpl::handleSkinCurrentChanged(const LLSD& /*newvalue*/) 686void LLViewerMediaImpl::mouseMove(S32 x, S32 y)
454{ 687{
455 // gSavedSettings is already updated when this function is called. 688 scaleMouse(&x, &y);
456 updateBrowserUserAgent(); 689 mLastMouseX = x;
457 return true; 690 mLastMouseY = y;
691 if (mMediaSource)
692 {
693 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, LEFT_BUTTON, x, y, 0);
694 }
458} 695}
459 696
460////////////////////////////////////////////////////////////////////////////////////////// 697//////////////////////////////////////////////////////////////////////////////////////////
461// Wrapper class 698void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y)
699{
700 scaleMouse(&x, &y);
701 mLastMouseX = x;
702 mLastMouseY = y;
703 if (mMediaSource)
704 {
705 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, LEFT_BUTTON, x, y, 0);
706 }
707}
708
462////////////////////////////////////////////////////////////////////////////////////////// 709//////////////////////////////////////////////////////////////////////////////////////////
710void LLViewerMediaImpl::onMouseCaptureLost()
711{
712 if (mMediaSource)
713 {
714 mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, LEFT_BUTTON, mLastMouseX, mLastMouseY, 0);
715 }
716}
463 717
718//////////////////////////////////////////////////////////////////////////////////////////
719BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
720{
721 // NOTE: this is called when the mouse is released when we have capture.
722 // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event.
723
724 if(hasMouseCapture())
725 {
726 // Release the mouse -- this will also send a mouseup to the media
727 gFocusMgr.setMouseCapture( FALSE );
728 }
464 729
730 return TRUE;
731}
465////////////////////////////////////////////////////////////////////////////////////////// 732//////////////////////////////////////////////////////////////////////////////////////////
466// The viewer takes a long time to load the start screen. Part of the problem 733void LLViewerMediaImpl::navigateHome()
467// is media initialization -- in particular, QuickTime loads many DLLs and
468// hits the disk heavily. So we initialize only the browser component before
469// the login screen, then do the rest later when we have a progress bar. JC
470// static
471void LLViewerMedia::initBrowser()
472{ 734{
473 LLMediaManagerData* init_data = new LLMediaManagerData; 735 if(mMediaSource)
474 buildMediaManagerData( init_data ); 736 {
475 LLMediaManager::initBrowser( init_data ); 737 mMediaSource->loadURI( mHomeURL );
476 delete init_data; 738 }
477
478 // We use a custom user agent with viewer version and skin name.
479 LLViewerMediaImpl::updateBrowserUserAgent();
480} 739}
481 740
482////////////////////////////////////////////////////////////////////////////////////////// 741//////////////////////////////////////////////////////////////////////////////////////////
483// static 742void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type)
484void LLViewerMedia::initClass()
485{ 743{
486 // *TODO: This looks like a memory leak to me. JC 744 if(rediscover_type)
487 LLMediaManagerData* init_data = new LLMediaManagerData; 745 {
488 buildMediaManagerData( init_data );
489 LLMediaManager::initClass( init_data );
490 delete init_data;
491 746
492 LLMediaManager* mm = LLMediaManager::getInstance(); 747 LLURI uri(url);
493 LLMIMETypes::mime_info_map_t::const_iterator it; 748 std::string scheme = uri.scheme();
494 for (it = LLMIMETypes::sMap.begin(); it != LLMIMETypes::sMap.end(); ++it) 749
750 if(scheme.empty() || "http" == scheme || "https" == scheme)
751 {
752 LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this));
753 }
754 else if("data" == scheme || "file" == scheme || "about" == scheme)
755 {
756 // FIXME: figure out how to really discover the type for these schemes
757 // We use "data" internally for a text/html url for loading the login screen
758 if(initializeMedia("text/html"))
759 {
760 mMediaSource->loadURI( url );
761 }
762 }
763 else
764 {
765 // This catches 'rtsp://' urls
766 if(initializeMedia(scheme))
767 {
768 mMediaSource->loadURI( url );
769 }
770 }
771 }
772 else if (mMediaSource)
495 { 773 {
496 const std::string& mime_type = it->first; 774 mMediaSource->loadURI( url );
497 const LLMIMETypes::LLMIMEInfo& info = it->second;
498 mm->addMimeTypeImplNameMap( mime_type, info.mImpl );
499 } 775 }
500 776 else if(initializeMedia(mime_type) && mMediaSource)
501 LLMediaBase *impl = mm->createSourceFromMimeType("http", "audio/mpeg"); 777 {
502 if (impl) 778 mMediaSource->loadURI( url );
779 }
780 else
503 { 781 {
504 U32 level = gSavedSettings.getU32("MediaDebugLevel"); 782 LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL;
505 impl->setDebugLevel( (LLMediaBase::EDebugLevel)level ); 783 return;
506 } 784 }
785 mMediaURL = url;
786
507} 787}
508 788
509////////////////////////////////////////////////////////////////////////////////////////// 789//////////////////////////////////////////////////////////////////////////////////////////
510// static 790void LLViewerMediaImpl::navigateStop()
511void LLViewerMedia::buildMediaManagerData( LLMediaManagerData* init_data ) 791{
512{ 792 if(mMediaSource)
513// std::string executable_dir = std::string( arg0 ).substr( 0, std::string( arg0 ).find_last_of("\\/") ); 793 {
514// std::string component_dir = std::string( executable_dir ).substr( 0, std::string( executable_dir ).find_last_of("\\/") ); 794 mMediaSource->browse_stop();
515// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); 795 }
516// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") );
517// component_dir += "\\newview\\app_settings\\mozilla";
518
519
520#if LL_DARWIN
521 // For Mac OS, we store both the shared libraries and the runtime files (chrome/, plugins/, etc) in
522 // Second Life.app/Contents/MacOS/. This matches the way Firefox is distributed on the Mac.
523 std::string component_dir(gDirUtilp->getExecutableDir());
524#elif LL_WINDOWS
525 std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) );
526 component_dir += gDirUtilp->getDirDelimiter();
527 #ifdef LL_DEBUG
528 component_dir += "mozilla_debug";
529 #else // LL_DEBUG
530 component_dir += "mozilla";
531 #endif // LL_DEBUG
532#elif LL_LINUX
533 std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) );
534 component_dir += gDirUtilp->getDirDelimiter();
535
536 #if LINUX64
537 component_dir += "mozilla-runtime-linux-x86_64";
538 #else
539 component_dir += "mozilla-runtime-linux-i686";
540 #endif
541
542#elif LL_SOLARIS
543 std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) );
544 component_dir += gDirUtilp->getDirDelimiter();
545 #ifdef __sparc
546 component_dir += "mozilla-solaris-sparc";
547 #else
548 component_dir += "mozilla-solaris-i686";
549 #endif
550#else
551 std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) );
552 component_dir += gDirUtilp->getDirDelimiter();
553 component_dir += "mozilla";
554#endif
555
556 std::string application_dir = gDirUtilp->getExecutableDir();
557 796
558 init_data->setBrowserApplicationDir( application_dir ); 797}
559 std::string profile_dir = gDirUtilp->getExpandedFilename( LL_PATH_MOZILLA_PROFILE, "" );
560 init_data->setBrowserProfileDir( profile_dir );
561 init_data->setBrowserComponentDir( component_dir );
562 std::string profile_name("Second Life");
563 init_data->setBrowserProfileName( profile_name );
564 init_data->setBrowserParentWindow( gViewerWindow->getMediaWindow() );
565 798
566 // Users can change skins while client is running, so make sure 799//////////////////////////////////////////////////////////////////////////////////////////
567 // we pick up on changes. 800bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
568 gSavedSettings.getControl("SkinCurrent")->getSignal()->connect( 801{
569 boost::bind( LLViewerMediaImpl::handleSkinCurrentChanged, _1 ) ); 802 bool result = false;
803
804 if (mMediaSource)
805 {
806 // FIXME: THIS IS SO WRONG.
807 // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
808 if( MASK_CONTROL & mask )
809 {
810 if( 'C' == key )
811 {
812 mMediaSource->copy();
813 result = true;
814 }
815 else
816 if( 'V' == key )
817 {
818 mMediaSource->paste();
819 result = true;
820 }
821 else
822 if( 'X' == key )
823 {
824 mMediaSource->cut();
825 result = true;
826 }
827 }
828
829 if(!result)
830 {
831
832 LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
833
834 result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data);
835 // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here.
836 (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data);
837 }
838 }
839
840 return result;
841}
570 842
843//////////////////////////////////////////////////////////////////////////////////////////
844bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
845{
846 bool result = false;
847
848 if (mMediaSource)
849 {
850 // only accept 'printable' characters, sigh...
851 if (uni_char >= 32 // discard 'control' characters
852 && uni_char != 127) // SDL thinks this is 'delete' - yuck.
853 {
854 LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
855
856 mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data);
857 }
858 }
859
860 return result;
571} 861}
572 862
573////////////////////////////////////////////////////////////////////////////////////////// 863//////////////////////////////////////////////////////////////////////////////////////////
574// static 864bool LLViewerMediaImpl::canNavigateForward()
575void LLViewerMedia::cleanupClass()
576{ 865{
577 stop() ; 866 BOOL result = FALSE;
578 LLMediaManager::cleanupClass(); 867 if (mMediaSource)
868 {
869 result = mMediaSource->getHistoryForwardAvailable();
870 }
871 return result;
579} 872}
580 873
581// static 874//////////////////////////////////////////////////////////////////////////////////////////
582void LLViewerMedia::play(const std::string& media_url, 875bool LLViewerMediaImpl::canNavigateBack()
583 const std::string& mime_type,
584 const LLUUID& placeholder_texture_id,
585 S32 media_width, S32 media_height, U8 media_auto_scale,
586 U8 media_loop)
587{ 876{
588 sViewerMediaImpl.play(media_url, mime_type, placeholder_texture_id, 877 BOOL result = FALSE;
589 media_width, media_height, media_auto_scale, media_loop); 878 if (mMediaSource)
879 {
880 result = mMediaSource->getHistoryBackAvailable();
881 }
882 return result;
590} 883}
591 884
592// static 885
593void LLViewerMedia::stop() 886//////////////////////////////////////////////////////////////////////////////////////////
887void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active)
594{ 888{
595 sViewerMediaImpl.stop(); 889 // IF the media image hasn't changed, do nothing
890 if (mTextureId == uuid)
891 {
892 return;
893 }
894 // If we have changed media uuid, restore the old one
895 if (!mTextureId.isNull())
896 {
897 LLViewerImage* oldImage = LLViewerImage::getImage( mTextureId );
898 if (oldImage)
899 {
900 oldImage->reinit(mMovieImageHasMips);
901 oldImage->mIsMediaTexture = FALSE;
902 }
903 }
904 // If the movie is playing, set the new media image
905 if (active && !uuid.isNull())
906 {
907 LLViewerImage* viewerImage = LLViewerImage::getImage( uuid );
908 if( viewerImage )
909 {
910 mTextureId = uuid;
911 // Can't use mipmaps for movies because they don't update the full image
912 mMovieImageHasMips = viewerImage->getUseMipMaps();
913 viewerImage->reinit(FALSE);
914 viewerImage->mIsMediaTexture = TRUE;
915 }
916 }
596} 917}
597 918
598// static 919//////////////////////////////////////////////////////////////////////////////////////////
599void LLViewerMedia::pause() 920void LLViewerMediaImpl::update()
600{ 921{
601 sViewerMediaImpl.pause(); 922 if(mMediaSource == NULL)
923 {
924 return;
925 }
926
927 mMediaSource->idle();
928
929 if(mMediaSource->isPluginExited())
930 {
931 destroyMediaSource();
932 return;
933 }
934
935 if(!mMediaSource->textureValid())
936 {
937 return;
938 }
939
940 if(mSuspendUpdates || !mVisible)
941 {
942 return;
943 }
944
945 LLViewerImage* placeholder_image = updatePlaceholderImage();
946
947 if(placeholder_image)
948 {
949 LLRect dirty_rect;
950 if(mMediaSource->getDirty(&dirty_rect))
951 {
952 // Constrain the dirty rect to be inside the texture
953 S32 x_pos = llmax(dirty_rect.mLeft, 0);
954 S32 y_pos = llmax(dirty_rect.mBottom, 0);
955 S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
956 S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
957
958 if(width > 0 && height > 0)
959 {
960
961 U8* data = mMediaSource->getBitsData();
962
963 // Offset the pixels pointer to match x_pos and y_pos
964 data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
965 data += ( y_pos * mMediaSource->getTextureDepth() );
966
967 placeholder_image->setSubImage(
968 data,
969 mMediaSource->getBitsWidth(),
970 mMediaSource->getBitsHeight(),
971 x_pos,
972 y_pos,
973 width,
974 height,
975 TRUE); // force a fast update (i.e. don't call analyzeAlpha, etc.)
976
977 }
978
979 mMediaSource->resetDirty();
980 }
981 }
602} 982}
603 983
604// static 984
605void LLViewerMedia::start() 985//////////////////////////////////////////////////////////////////////////////////////////
986void LLViewerMediaImpl::updateImagesMediaStreams()
606{ 987{
607 sViewerMediaImpl.start();
608} 988}
609 989
610// static 990
611void LLViewerMedia::seek(F32 time) 991//////////////////////////////////////////////////////////////////////////////////////////
992LLViewerImage* LLViewerMediaImpl::updatePlaceholderImage()
612{ 993{
613 sViewerMediaImpl.seek(time); 994 if(mTextureId.isNull())
995 {
996 // The code that created this instance will read from the plugin's bits.
997 return NULL;
998 }
999
1000 LLViewerImage* placeholder_image = gImageList.getImage( mTextureId );
1001
1002 if (mNeedsNewTexture
1003 || placeholder_image->getUseMipMaps()
1004 || ! placeholder_image->mIsMediaTexture
1005 || placeholder_image->getWidth() != mMediaSource->getTextureWidth()
1006 || placeholder_image->getHeight() != mMediaSource->getTextureHeight())
1007 {
1008 llinfos << "initializing media placeholder" << llendl;
1009 llinfos << "movie image id " << mTextureId << llendl;
1010
1011 int texture_width = mMediaSource->getTextureWidth();
1012 int texture_height = mMediaSource->getTextureHeight();
1013 int texture_depth = mMediaSource->getTextureDepth();
1014
1015 // MEDIAOPT: check to see if size actually changed before doing work
1016 placeholder_image->destroyGLTexture();
1017 // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
1018 placeholder_image->reinit(FALSE); // probably not needed
1019
1020 // MEDIAOPT: seems insane that we actually have to make an imageraw then
1021 // immediately discard it
1022 LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
1023 raw->clear(0x0f, 0x0f, 0x0f, 0xff);
1024 int discard_level = 0;
1025
1026 // ask media source for correct GL image format constants
1027 placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
1028 mMediaSource->getTextureFormatPrimary(),
1029 mMediaSource->getTextureFormatType(),
1030 mMediaSource->getTextureFormatSwapBytes());
1031
1032 placeholder_image->createGLTexture(discard_level, raw);
1033
1034 // placeholder_image->setExplicitFormat()
1035 placeholder_image->setUseMipMaps(FALSE);
1036
1037 // MEDIAOPT: set this dynamically on play/stop
1038 placeholder_image->mIsMediaTexture = true;
1039 mNeedsNewTexture = false;
1040 }
1041
1042 return placeholder_image;
614} 1043}
615 1044
616// static 1045
617void LLViewerMedia::setVolume(F32 volume) 1046//////////////////////////////////////////////////////////////////////////////////////////
1047LLUUID LLViewerMediaImpl::getMediaTextureID()
618{ 1048{
619 sViewerMediaImpl.setVolume(volume); 1049 return mTextureId;
620} 1050}
621 1051
622// static 1052//////////////////////////////////////////////////////////////////////////////////////////
623LLMediaBase::EStatus LLViewerMedia::getStatus() 1053void LLViewerMediaImpl::setVisible(bool visible)
624{ 1054{
625 return sViewerMediaImpl.getStatus(); 1055 mVisible = visible;
1056
1057 if(mVisible)
1058 {
1059 if(mMediaSource && mMediaSource->isPluginExited())
1060 {
1061 destroyMediaSource();
1062 }
1063
1064 if(!mMediaSource)
1065 {
1066 createMediaSource();
1067 }
1068 }
1069
1070 if(mMediaSource)
1071 {
1072 mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN);
1073 }
626} 1074}
627 1075
628////////////////////////////////////////////////////////////////////////////////////////// 1076//////////////////////////////////////////////////////////////////////////////////////////
629// static 1077void LLViewerMediaImpl::mouseCapture()
630LLUUID LLViewerMedia::getMediaTextureID()
631{ 1078{
632 return sViewerMediaImpl.getMediaTextureID(); 1079 gFocusMgr.setMouseCapture(this);
633} 1080}
634 1081
635////////////////////////////////////////////////////////////////////////////////////////// 1082//////////////////////////////////////////////////////////////////////////////////////////
636// static 1083void LLViewerMediaImpl::getTextureSize(S32 *texture_width, S32 *texture_height)
637bool LLViewerMedia::getMediaSize(S32 *media_width, S32 *media_height)
638{ 1084{
639 // make sure we're valid 1085 if(mMediaSource && mMediaSource->textureValid())
1086 {
1087 S32 real_texture_width = mMediaSource->getBitsWidth();
1088 S32 real_texture_height = mMediaSource->getBitsHeight();
640 1089
641 if ( sViewerMediaImpl.mMediaSource != NULL ) 1090 {
1091 // The "texture width" coming back from the plugin may not be a power of two (thanks to webkit).
1092 // It will be the correct "data width" to pass to setSubImage
1093 int i;
1094
1095 for(i = 1; i < real_texture_width; i <<= 1)
1096 ;
1097 *texture_width = i;
1098
1099 for(i = 1; i < real_texture_height; i <<= 1)
1100 ;
1101 *texture_height = i;
1102 }
1103
1104 }
1105 else
642 { 1106 {
643 *media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); 1107 *texture_width = 0;
644 *media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); 1108 *texture_height = 0;
645 return true;
646 } 1109 }
647 return false; 1110}
1111//////////////////////////////////////////////////////////////////////////////////////////
1112void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y)
1113{
1114#if 0
1115 S32 media_width, media_height;
1116 S32 texture_width, texture_height;
1117 getMediaSize( &media_width, &media_height );
1118 getTextureSize( &texture_width, &texture_height );
1119 S32 y_delta = texture_height - media_height;
1120
1121 *mouse_y -= y_delta;
1122#endif
648} 1123}
649 1124
650////////////////////////////////////////////////////////////////////////////////////////// 1125//////////////////////////////////////////////////////////////////////////////////////////
651// static 1126bool LLViewerMediaImpl::isMediaPlaying()
652bool LLViewerMedia::getTextureSize(S32 *texture_width, S32 *texture_height)
653{ 1127{
654 if ( sViewerMediaImpl.mMediaSource != NULL ) 1128 bool result = false;
1129
1130 if(mMediaSource)
655 { 1131 {
656 S32 media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); 1132 EMediaStatus status = mMediaSource->getStatus();
657 S32 media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); 1133 if(status == MEDIA_PLAYING || status == MEDIA_LOADING)
658 *texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); 1134 result = true;
659 *texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height );
660 return true;
661 } 1135 }
662 return false; 1136
1137 return result;
663} 1138}
1139//////////////////////////////////////////////////////////////////////////////////////////
1140bool LLViewerMediaImpl::isMediaPaused()
1141{
1142 bool result = false;
664 1143
1144 if(mMediaSource)
1145 {
1146 if(mMediaSource->getStatus() == MEDIA_PAUSED)
1147 result = true;
1148 }
1149
1150 return result;
1151}
665 1152
666////////////////////////////////////////////////////////////////////////////////////////// 1153//////////////////////////////////////////////////////////////////////////////////////////
667// static 1154//
668void LLViewerMedia::updateImagesMediaStreams() 1155bool LLViewerMediaImpl::hasMedia()
669{ 1156{
670 sViewerMediaImpl.updateImagesMediaStreams(); 1157 return mMediaSource != NULL;
671} 1158}
1159
672////////////////////////////////////////////////////////////////////////////////////////// 1160//////////////////////////////////////////////////////////////////////////////////////////
673// static 1161void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event)
674bool LLViewerMedia::isMediaPlaying()
675{ 1162{
676 LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); 1163 switch(event)
677 return (status == LLMediaBase::STATUS_STARTED ); 1164 {
1165 case MEDIA_EVENT_PLUGIN_FAILED:
1166 {
1167 LLSD args;
1168 args["PLUGIN"] = LLMIMETypes::implType(mMimeType);
1169 LLNotifications::instance().add("MediaPluginFailed", args);
1170 }
1171 break;
1172 default:
1173 break;
1174 }
1175 // Just chain the event to observers.
1176 emitEvent(self, event);
678} 1177}
679////////////////////////////////////////////////////////////////////////////////////////// 1178
680// static 1179////////////////////////////////////////////////////////////////////////////////
681bool LLViewerMedia::isMediaPaused() 1180// virtual
1181void
1182LLViewerMediaImpl::cut()
682{ 1183{
683 LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); 1184 if (mMediaSource)
684 return (status == LLMediaBase::STATUS_PAUSED); 1185 mMediaSource->cut();
685} 1186}
686////////////////////////////////////////////////////////////////////////////////////////// 1187
687// static 1188////////////////////////////////////////////////////////////////////////////////
688bool LLViewerMedia::hasMedia() 1189// virtual
1190BOOL
1191LLViewerMediaImpl::canCut() const
689{ 1192{
690 return sViewerMediaImpl.mMediaSource != NULL; 1193 if (mMediaSource)
1194 return mMediaSource->canCut();
1195 else
1196 return FALSE;
691} 1197}
692 1198
693////////////////////////////////////////////////////////////////////////////////////////// 1199////////////////////////////////////////////////////////////////////////////////
694//static 1200// virtual
695bool LLViewerMedia::isActiveMediaTexture(const LLUUID& id) 1201void
1202LLViewerMediaImpl::copy()
696{ 1203{
697 return (id.notNull() 1204 if (mMediaSource)
698 && id == getMediaTextureID() 1205 mMediaSource->copy();
699 && isMediaPlaying());
700} 1206}
701 1207
702////////////////////////////////////////////////////////////////////////////////////////// 1208////////////////////////////////////////////////////////////////////////////////
703// static 1209// virtual
704std::string LLViewerMedia::getMediaURL() 1210BOOL
1211LLViewerMediaImpl::canCopy() const
705{ 1212{
706 return sViewerMediaImpl.mMediaURL; 1213 if (mMediaSource)
1214 return mMediaSource->canCopy();
1215 else
1216 return FALSE;
707} 1217}
708////////////////////////////////////////////////////////////////////////////////////////// 1218
709// static 1219////////////////////////////////////////////////////////////////////////////////
710std::string LLViewerMedia::getMimeType() 1220// virtual
1221void
1222LLViewerMediaImpl::paste()
711{ 1223{
712 return sViewerMediaImpl.mMimeType; 1224 if (mMediaSource)
1225 mMediaSource->paste();
713} 1226}
714////////////////////////////////////////////////////////////////////////////////////////// 1227
715// static 1228////////////////////////////////////////////////////////////////////////////////
716void LLViewerMedia::setMimeType(std::string mime_type) 1229// virtual
1230BOOL
1231LLViewerMediaImpl::canPaste() const
717{ 1232{
718 sViewerMediaImpl.mMimeType = mime_type; 1233 if (mMediaSource)
1234 return mMediaSource->canPaste();
1235 else
1236 return FALSE;
719} 1237}
1238