summaryrefslogtreecommitdiff
path: root/indra/media_plugins
diff options
context:
space:
mode:
Diffstat (limited to 'indra/media_plugins')
-rw-r--r--indra/media_plugins/base/media_plugin_base.cpp154
-rw-r--r--indra/media_plugins/base/media_plugin_base.h118
-rw-r--r--indra/media_plugins/cef/mac_volume_catcher.cpp550
-rw-r--r--indra/media_plugins/cef/mac_volume_catcher_null.cpp50
-rw-r--r--indra/media_plugins/cef/media_plugin_cef.cpp2294
-rw-r--r--indra/media_plugins/cef/volume_catcher.h30
-rw-r--r--indra/media_plugins/cef/windows_volume_catcher.cpp62
-rw-r--r--indra/media_plugins/example/media_plugin_example.cpp618
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamer.h14
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp176
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h12
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h8
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp708
-rw-r--r--indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h66
-rw-r--r--indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp1976
-rw-r--r--indra/media_plugins/libvlc/media_plugin_libvlc.cpp906
16 files changed, 3871 insertions, 3871 deletions
diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp
index 37c498664a..545eee25a9 100644
--- a/indra/media_plugins/base/media_plugin_base.cpp
+++ b/indra/media_plugins/base/media_plugin_base.cpp
@@ -1,28 +1,28 @@
-/**
+/**
* @file media_plugin_base.cpp
* @brief Media plugin base class for LLMedia API plugin system
*
- * All plugins should be a subclass of MediaPluginBase.
+ * All plugins should be a subclass of MediaPluginBase.
*
* @cond
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -40,102 +40,102 @@
/// @param[in] host_user_data Message data for messages from plugin to plugin loader shell
MediaPluginBase::MediaPluginBase(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data )
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data )
{
- mHostSendFunction = host_send_func;
- mHostUserData = host_user_data;
- mDeleteMe = false;
- mPixels = 0;
- mWidth = 0;
- mHeight = 0;
- mTextureWidth = 0;
- mTextureHeight = 0;
- mDepth = 0;
- mStatus = STATUS_NONE;
+ mHostSendFunction = host_send_func;
+ mHostUserData = host_user_data;
+ mDeleteMe = false;
+ mPixels = 0;
+ mWidth = 0;
+ mHeight = 0;
+ mTextureWidth = 0;
+ mTextureHeight = 0;
+ mDepth = 0;
+ mStatus = STATUS_NONE;
}
/**
* Converts current media status enum value into string (STATUS_LOADING into "loading", etc.)
- *
+ *
* @return Media status string ("loading", "playing", "paused", etc)
*
*/
std::string MediaPluginBase::statusString()
{
- std::string result;
-
- switch(mStatus)
- {
- case STATUS_LOADING: result = "loading"; break;
- case STATUS_LOADED: result = "loaded"; break;
- case STATUS_ERROR: result = "error"; break;
- case STATUS_PLAYING: result = "playing"; break;
- case STATUS_PAUSED: result = "paused"; break;
- case STATUS_DONE: result = "done"; break;
- default:
- // keep the empty string
- break;
- }
-
- return result;
+ std::string result;
+
+ switch(mStatus)
+ {
+ case STATUS_LOADING: result = "loading"; break;
+ case STATUS_LOADED: result = "loaded"; break;
+ case STATUS_ERROR: result = "error"; break;
+ case STATUS_PLAYING: result = "playing"; break;
+ case STATUS_PAUSED: result = "paused"; break;
+ case STATUS_DONE: result = "done"; break;
+ default:
+ // keep the empty string
+ break;
+ }
+
+ return result;
}
-
+
/**
* Set media status.
- *
+ *
* @param[in] status Media status (STATUS_LOADING, STATUS_PLAYING, STATUS_PAUSED, etc)
*
*/
void MediaPluginBase::setStatus(EStatus status)
{
- if(mStatus != status)
- {
- mStatus = status;
- sendStatus();
- }
+ if(mStatus != status)
+ {
+ mStatus = status;
+ sendStatus();
+ }
}
/**
* Receive message from plugin loader shell.
- *
+ *
* @param[in] message_string Message string
* @param[in] user_data Message data
*
*/
void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data)
{
- MediaPluginBase *self = (MediaPluginBase*)*user_data;
-
- if(self != NULL)
- {
- self->receiveMessage(message_string);
-
- // If the plugin has processed the delete message, delete it.
- if(self->mDeleteMe)
- {
- delete self;
- *user_data = NULL;
- }
- }
+ MediaPluginBase *self = (MediaPluginBase*)*user_data;
+
+ if(self != NULL)
+ {
+ self->receiveMessage(message_string);
+
+ // If the plugin has processed the delete message, delete it.
+ if(self->mDeleteMe)
+ {
+ delete self;
+ *user_data = NULL;
+ }
+ }
}
/**
* Send message to plugin loader shell.
- *
+ *
* @param[in] message Message data being sent to plugin loader shell
*
*/
void MediaPluginBase::sendMessage(const LLPluginMessage &message)
{
- std::string output = message.generate();
- mHostSendFunction(output.c_str(), &mHostUserData);
+ std::string output = message.generate();
+ mHostSendFunction(output.c_str(), &mHostUserData);
}
/**
* Notifies plugin loader shell that part of display area needs to be redrawn.
- *
+ *
* @param[in] left Left X coordinate of area to redraw (0,0 is at top left corner)
* @param[in] top Top Y coordinate of area to redraw (0,0 is at top left corner)
* @param[in] right Right X-coordinate of area to redraw (0,0 is at top left corner)
@@ -144,27 +144,27 @@ void MediaPluginBase::sendMessage(const LLPluginMessage &message)
*/
void MediaPluginBase::setDirty(int left, int top, int right, int bottom)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
-
- message.setValueS32("left", left);
- message.setValueS32("top", top);
- message.setValueS32("right", right);
- message.setValueS32("bottom", bottom);
-
- sendMessage(message);
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+
+ message.setValueS32("left", left);
+ message.setValueS32("top", top);
+ message.setValueS32("right", right);
+ message.setValueS32("bottom", bottom);
+
+ sendMessage(message);
}
/**
* Sends "media_status" message to plugin loader shell ("loading", "playing", "paused", etc.)
- *
+ *
*/
void MediaPluginBase::sendStatus()
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status");
- message.setValue("status", statusString());
-
- sendMessage(message);
+ message.setValue("status", statusString());
+
+ sendMessage(message);
}
@@ -178,12 +178,12 @@ void MediaPluginBase::sendStatus()
extern "C"
{
- LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
+ LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data);
}
/**
* Plugin initialization and entry point. Establishes communication channel for messages between plugin and plugin loader shell. TODO:DOC - Please check!
- *
+ *
* @param[in] host_send_func Function for sending messages from plugin to plugin loader shell
* @param[in] host_user_data Message data for messages from plugin to plugin loader shell
* @param[out] plugin_send_func Function for plugin to receive messages from plugin loader shell
@@ -195,12 +195,12 @@ extern "C"
LLSYMEXPORT int
LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
{
- return init_media_plugin(host_send_func, host_user_data, plugin_send_func, plugin_user_data);
+ return init_media_plugin(host_send_func, host_user_data, plugin_send_func, plugin_user_data);
}
#ifdef WIN32
int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params )
{
- return 1;
+ return 1;
}
#endif
diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h
index 38b8226bb3..f65c712a66 100644
--- a/indra/media_plugins/base/media_plugin_base.h
+++ b/indra/media_plugins/base/media_plugin_base.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file media_plugin_base.h
* @brief Media plugin base class for LLMedia API plugin system
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -36,94 +36,94 @@
class MediaPluginBase
{
public:
- MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
/** Media plugin destructor. */
- virtual ~MediaPluginBase() {}
+ virtual ~MediaPluginBase() {}
/** Handle received message from plugin loader shell. */
- virtual void receiveMessage(const char *message_string) = 0;
-
- static void staticReceiveMessage(const char *message_string, void **user_data);
+ virtual void receiveMessage(const char *message_string) = 0;
+
+ static void staticReceiveMessage(const char *message_string, void **user_data);
protected:
/** Plugin status. */
- typedef enum
- {
- STATUS_NONE,
- STATUS_LOADING,
- STATUS_LOADED,
- STATUS_ERROR,
- STATUS_PLAYING,
- STATUS_PAUSED,
- STATUS_DONE
- } EStatus;
+ typedef enum
+ {
+ STATUS_NONE,
+ STATUS_LOADING,
+ STATUS_LOADED,
+ STATUS_ERROR,
+ STATUS_PLAYING,
+ STATUS_PAUSED,
+ STATUS_DONE
+ } EStatus;
/** Plugin shared memory. */
- class SharedSegmentInfo
- {
- public:
+ class SharedSegmentInfo
+ {
+ public:
/** Shared memory address. */
- void *mAddress;
+ void *mAddress;
/** Shared memory size. */
- size_t mSize;
- };
+ size_t mSize;
+ };
+
+ void sendMessage(const LLPluginMessage &message);
+ void sendStatus();
+ std::string statusString();
+ void setStatus(EStatus status);
- void sendMessage(const LLPluginMessage &message);
- void sendStatus();
- std::string statusString();
- void setStatus(EStatus status);
-
- /// Note: The quicktime plugin overrides this to add current time and duration to the message.
- virtual void setDirty(int left, int top, int right, int bottom);
+ /// Note: The quicktime plugin overrides this to add current time and duration to the message.
+ virtual void setDirty(int left, int top, int right, int bottom);
/** Map of shared memory names to shared memory. */
- typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap;
+ typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap;
+
-
/** Function to send message from plugin to plugin loader shell. */
- LLPluginInstance::sendMessageFunction mHostSendFunction;
+ LLPluginInstance::sendMessageFunction mHostSendFunction;
/** Message data being sent to plugin loader shell by mHostSendFunction. */
- void *mHostUserData;
+ void *mHostUserData;
/** Flag to delete plugin instance (self). */
- bool mDeleteMe;
+ bool mDeleteMe;
/** Pixel array to display. TODO:DOC are pixels always 24-bit RGB format, aligned on 32-bit boundary? Also: calling this a pixel array may be misleading since 1 pixel > 1 char. */
- unsigned char* mPixels;
+ unsigned char* mPixels;
/** TODO:DOC what's this for -- does a texture have its own piece of shared memory? updated on size_change_request, cleared on shm_remove */
- std::string mTextureSegmentName;
+ std::string mTextureSegmentName;
/** Width of plugin display in pixels. */
- int mWidth;
+ int mWidth;
/** Height of plugin display in pixels. */
- int mHeight;
+ int mHeight;
/** Width of plugin texture. */
- int mTextureWidth;
+ int mTextureWidth;
/** Height of plugin texture. */
- int mTextureHeight;
+ int mTextureHeight;
/** Pixel depth (pixel size in bytes). */
- int mDepth;
+ int mDepth;
/** Current status of plugin. */
- EStatus mStatus;
+ EStatus mStatus;
/** Map of shared memory segments. */
- SharedSegmentMap mSharedSegments;
+ SharedSegmentMap mSharedSegments;
};
/** The plugin <b>must</b> define this function to create its instance.
- * It should look something like this:
+ * It should look something like this:
* @code
- * {
- * MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data);
- * *plugin_send_func = MediaPluginFoo::staticReceiveMessage;
- * *plugin_user_data = (void*)self;
- *
- * return 0;
- * }
+ * {
+ * MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data);
+ * *plugin_send_func = MediaPluginFoo::staticReceiveMessage;
+ * *plugin_user_data = (void*)self;
+ *
+ * return 0;
+ * }
* @endcode
*/
int init_media_plugin(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data,
- LLPluginInstance::sendMessageFunction *plugin_send_func,
- void **plugin_user_data);
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data,
+ LLPluginInstance::sendMessageFunction *plugin_send_func,
+ void **plugin_user_data);
diff --git a/indra/media_plugins/cef/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp
index dafe545d09..26b1977e55 100644
--- a/indra/media_plugins/cef/mac_volume_catcher.cpp
+++ b/indra/media_plugins/cef/mac_volume_catcher.cpp
@@ -1,275 +1,275 @@
-/**
- * @file mac_volume_catcher.cpp
- * @brief A macOS specific hack to control the volume level of all audio channels opened by a process.
- *
- * @cond
- * $LicenseInfo:firstyear=2010&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- * @endcond
- */
-
-/**************************************************************************************************************
- This code works by using CaptureComponent to capture the "Default Output" audio component
- (kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput) and delegating all calls to the original component.
- It does this just to keep track of all instances of the default output component, so that it can set the
- kHALOutputParam_Volume parameter on all of them to adjust the output volume.
-**************************************************************************************************************/
-
-#include "volume_catcher.h"
-
-#include <QuickTime/QuickTime.h>
-#include <AudioUnit/AudioUnit.h>
-#include <list>
-
-#if LL_DARWIN
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-struct VolumeCatcherStorage;
-
-class VolumeCatcherImpl
-{
-public:
-
- void setVolume(F32 volume);
- void setPan(F32 pan);
-
- void setInstanceVolume(VolumeCatcherStorage *instance);
-
- std::list<VolumeCatcherStorage*> mComponentInstances;
- Component mOriginalDefaultOutput;
- Component mVolumeAdjuster;
-
- static VolumeCatcherImpl *getInstance();
-private:
- // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
- VolumeCatcherImpl();
- static VolumeCatcherImpl *sInstance;
-
- // The singlar instance of this class is expected to last until the process exits.
- // To ensure this, we declare the destructor here but never define it, so any code which attempts to destroy the instance will not link.
- ~VolumeCatcherImpl();
-
- F32 mVolume;
- F32 mPan;
-};
-
-VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;;
-
-struct VolumeCatcherStorage
-{
- ComponentInstance self;
- ComponentInstance delegate;
-};
-
-static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage);
-static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self);
-static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self);
-
-VolumeCatcherImpl *VolumeCatcherImpl::getInstance()
-{
- if(!sInstance)
- {
- sInstance = new VolumeCatcherImpl;
- }
-
- return sInstance;
-}
-
-VolumeCatcherImpl::VolumeCatcherImpl()
-{
- mVolume = 1.0; // default to full volume
- mPan = 0.0; // and center pan
-
- ComponentDescription desc;
- desc.componentType = kAudioUnitType_Output;
- desc.componentSubType = kAudioUnitSubType_DefaultOutput;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- desc.componentFlags = 0;
- desc.componentFlagsMask = 0;
-
- // Find the original default output component
- mOriginalDefaultOutput = FindNextComponent(NULL, &desc);
-
- // Register our own output component with the same parameters
- mVolumeAdjuster = RegisterComponent(&desc, NewComponentRoutineUPP(volume_catcher_component_entry), 0, NULL, NULL, NULL);
-
- // Capture the original component, so we always get found instead.
- CaptureComponent(mOriginalDefaultOutput, mVolumeAdjuster);
-
-}
-
-static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage)
-{
- ComponentResult result = badComponentSelector;
- VolumeCatcherStorage *storage = (VolumeCatcherStorage*)componentStorage;
-
- switch(cp->what)
- {
- case kComponentOpenSelect:
-// std::cerr << "kComponentOpenSelect" << std::endl;
- result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_open, uppCallComponentOpenProcInfo);
- break;
-
- case kComponentCloseSelect:
-// std::cerr << "kComponentCloseSelect" << std::endl;
- result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_close, uppCallComponentCloseProcInfo);
- // CallComponentFunctionWithStorageProcInfo
- break;
-
- default:
-// std::cerr << "Delegating selector: " << cp->what << " to component instance " << storage->delegate << std::endl;
- result = DelegateComponentCall(cp, storage->delegate);
- break;
- }
-
- return result;
-}
-
-static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self)
-{
- ComponentResult result = noErr;
- VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
-
- storage = new VolumeCatcherStorage;
-
- storage->self = self;
- storage->delegate = NULL;
-
- result = OpenAComponent(impl->mOriginalDefaultOutput, &(storage->delegate));
-
- if(result != noErr)
- {
-// std::cerr << "OpenAComponent result = " << result << ", component ref = " << storage->delegate << std::endl;
-
- // If we failed to open the delagate component, our open is going to fail. Clean things up.
- delete storage;
- }
- else
- {
- // Success -- set up this component's storage
- SetComponentInstanceStorage(self, (Handle)storage);
-
- // add this instance to the global list
- impl->mComponentInstances.push_back(storage);
-
- // and set up the initial volume
- impl->setInstanceVolume(storage);
- }
-
- return result;
-}
-
-static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self)
-{
- ComponentResult result = noErr;
-
- if(storage)
- {
- if(storage->delegate)
- {
- CloseComponent(storage->delegate);
- storage->delegate = NULL;
- }
-
- VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
- impl->mComponentInstances.remove(storage);
- delete[] storage;
- }
-
- return result;
-}
-
-void VolumeCatcherImpl::setVolume(F32 volume)
-{
- VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
- impl->mVolume = volume;
-
- // Iterate through all known instances, setting the volume on each.
- for(std::list<VolumeCatcherStorage*>::iterator iter = mComponentInstances.begin(); iter != mComponentInstances.end(); ++iter)
- {
- impl->setInstanceVolume(*iter);
- }
-}
-
-void VolumeCatcherImpl::setPan(F32 pan)
-{
- VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
- impl->mPan = pan;
-
- // TODO: implement this.
- // This will probably require adding a "panner" audio unit to the chain somehow.
- // There's also a "3d mixer" component that we might be able to use...
-}
-
-void VolumeCatcherImpl::setInstanceVolume(VolumeCatcherStorage *instance)
-{
-// std::cerr << "Setting volume on component instance: " << (instance->delegate) << " to " << mVolume << std::endl;
-
- OSStatus err = noErr;
-
- if(instance && instance->delegate)
- {
- err = AudioUnitSetParameter(
- instance->delegate,
- kHALOutputParam_Volume,
- kAudioUnitScope_Global,
- 0,
- mVolume,
- 0);
- }
-
- if(err)
- {
-// std::cerr << " AudioUnitSetParameter returned " << err << std::endl;
- }
-}
-
-/////////////////////////////////////////////////////
-
-VolumeCatcher::VolumeCatcher()
-{
- pimpl = VolumeCatcherImpl::getInstance();
-}
-
-VolumeCatcher::~VolumeCatcher()
-{
- // Let the instance persist until exit.
-}
-
-void VolumeCatcher::setVolume(F32 volume)
-{
- pimpl->setVolume(volume);
-}
-
-void VolumeCatcher::setPan(F32 pan)
-{
- pimpl->setPan(pan);
-}
-
-void VolumeCatcher::pump()
-{
- // No periodic tasks are necessary for this implementation.
-}
-
-#if LL_DARWIN
-#pragma GCC diagnostic warning "-Wdeprecated-declarations"
-#endif
+/**
+ * @file mac_volume_catcher.cpp
+ * @brief A macOS specific hack to control the volume level of all audio channels opened by a process.
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+/**************************************************************************************************************
+ This code works by using CaptureComponent to capture the "Default Output" audio component
+ (kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput) and delegating all calls to the original component.
+ It does this just to keep track of all instances of the default output component, so that it can set the
+ kHALOutputParam_Volume parameter on all of them to adjust the output volume.
+**************************************************************************************************************/
+
+#include "volume_catcher.h"
+
+#include <QuickTime/QuickTime.h>
+#include <AudioUnit/AudioUnit.h>
+#include <list>
+
+#if LL_DARWIN
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+struct VolumeCatcherStorage;
+
+class VolumeCatcherImpl
+{
+public:
+
+ void setVolume(F32 volume);
+ void setPan(F32 pan);
+
+ void setInstanceVolume(VolumeCatcherStorage *instance);
+
+ std::list<VolumeCatcherStorage*> mComponentInstances;
+ Component mOriginalDefaultOutput;
+ Component mVolumeAdjuster;
+
+ static VolumeCatcherImpl *getInstance();
+private:
+ // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
+ VolumeCatcherImpl();
+ static VolumeCatcherImpl *sInstance;
+
+ // The singlar instance of this class is expected to last until the process exits.
+ // To ensure this, we declare the destructor here but never define it, so any code which attempts to destroy the instance will not link.
+ ~VolumeCatcherImpl();
+
+ F32 mVolume;
+ F32 mPan;
+};
+
+VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;;
+
+struct VolumeCatcherStorage
+{
+ ComponentInstance self;
+ ComponentInstance delegate;
+};
+
+static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage);
+static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self);
+static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self);
+
+VolumeCatcherImpl *VolumeCatcherImpl::getInstance()
+{
+ if(!sInstance)
+ {
+ sInstance = new VolumeCatcherImpl;
+ }
+
+ return sInstance;
+}
+
+VolumeCatcherImpl::VolumeCatcherImpl()
+{
+ mVolume = 1.0; // default to full volume
+ mPan = 0.0; // and center pan
+
+ ComponentDescription desc;
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ // Find the original default output component
+ mOriginalDefaultOutput = FindNextComponent(NULL, &desc);
+
+ // Register our own output component with the same parameters
+ mVolumeAdjuster = RegisterComponent(&desc, NewComponentRoutineUPP(volume_catcher_component_entry), 0, NULL, NULL, NULL);
+
+ // Capture the original component, so we always get found instead.
+ CaptureComponent(mOriginalDefaultOutput, mVolumeAdjuster);
+
+}
+
+static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage)
+{
+ ComponentResult result = badComponentSelector;
+ VolumeCatcherStorage *storage = (VolumeCatcherStorage*)componentStorage;
+
+ switch(cp->what)
+ {
+ case kComponentOpenSelect:
+// std::cerr << "kComponentOpenSelect" << std::endl;
+ result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_open, uppCallComponentOpenProcInfo);
+ break;
+
+ case kComponentCloseSelect:
+// std::cerr << "kComponentCloseSelect" << std::endl;
+ result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_close, uppCallComponentCloseProcInfo);
+ // CallComponentFunctionWithStorageProcInfo
+ break;
+
+ default:
+// std::cerr << "Delegating selector: " << cp->what << " to component instance " << storage->delegate << std::endl;
+ result = DelegateComponentCall(cp, storage->delegate);
+ break;
+ }
+
+ return result;
+}
+
+static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self)
+{
+ ComponentResult result = noErr;
+ VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
+
+ storage = new VolumeCatcherStorage;
+
+ storage->self = self;
+ storage->delegate = NULL;
+
+ result = OpenAComponent(impl->mOriginalDefaultOutput, &(storage->delegate));
+
+ if(result != noErr)
+ {
+// std::cerr << "OpenAComponent result = " << result << ", component ref = " << storage->delegate << std::endl;
+
+ // If we failed to open the delagate component, our open is going to fail. Clean things up.
+ delete storage;
+ }
+ else
+ {
+ // Success -- set up this component's storage
+ SetComponentInstanceStorage(self, (Handle)storage);
+
+ // add this instance to the global list
+ impl->mComponentInstances.push_back(storage);
+
+ // and set up the initial volume
+ impl->setInstanceVolume(storage);
+ }
+
+ return result;
+}
+
+static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self)
+{
+ ComponentResult result = noErr;
+
+ if(storage)
+ {
+ if(storage->delegate)
+ {
+ CloseComponent(storage->delegate);
+ storage->delegate = NULL;
+ }
+
+ VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
+ impl->mComponentInstances.remove(storage);
+ delete[] storage;
+ }
+
+ return result;
+}
+
+void VolumeCatcherImpl::setVolume(F32 volume)
+{
+ VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
+ impl->mVolume = volume;
+
+ // Iterate through all known instances, setting the volume on each.
+ for(std::list<VolumeCatcherStorage*>::iterator iter = mComponentInstances.begin(); iter != mComponentInstances.end(); ++iter)
+ {
+ impl->setInstanceVolume(*iter);
+ }
+}
+
+void VolumeCatcherImpl::setPan(F32 pan)
+{
+ VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
+ impl->mPan = pan;
+
+ // TODO: implement this.
+ // This will probably require adding a "panner" audio unit to the chain somehow.
+ // There's also a "3d mixer" component that we might be able to use...
+}
+
+void VolumeCatcherImpl::setInstanceVolume(VolumeCatcherStorage *instance)
+{
+// std::cerr << "Setting volume on component instance: " << (instance->delegate) << " to " << mVolume << std::endl;
+
+ OSStatus err = noErr;
+
+ if(instance && instance->delegate)
+ {
+ err = AudioUnitSetParameter(
+ instance->delegate,
+ kHALOutputParam_Volume,
+ kAudioUnitScope_Global,
+ 0,
+ mVolume,
+ 0);
+ }
+
+ if(err)
+ {
+// std::cerr << " AudioUnitSetParameter returned " << err << std::endl;
+ }
+}
+
+/////////////////////////////////////////////////////
+
+VolumeCatcher::VolumeCatcher()
+{
+ pimpl = VolumeCatcherImpl::getInstance();
+}
+
+VolumeCatcher::~VolumeCatcher()
+{
+ // Let the instance persist until exit.
+}
+
+void VolumeCatcher::setVolume(F32 volume)
+{
+ pimpl->setVolume(volume);
+}
+
+void VolumeCatcher::setPan(F32 pan)
+{
+ pimpl->setPan(pan);
+}
+
+void VolumeCatcher::pump()
+{
+ // No periodic tasks are necessary for this implementation.
+}
+
+#if LL_DARWIN
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
+#endif
diff --git a/indra/media_plugins/cef/mac_volume_catcher_null.cpp b/indra/media_plugins/cef/mac_volume_catcher_null.cpp
index f4fcef71aa..c479e24a95 100644
--- a/indra/media_plugins/cef/mac_volume_catcher_null.cpp
+++ b/indra/media_plugins/cef/mac_volume_catcher_null.cpp
@@ -1,28 +1,28 @@
-/**
+/**
* @file windows_volume_catcher.cpp
* @brief A null implementation of volume level control of all audio channels opened by a process.
- * We are using this for the macOS version for now until we can understand how to make the
+ * We are using this for the macOS version for now until we can understand how to make the
* exitising mac_volume_catcher.cpp work without the (now, non-existant) QuickTime dependency
*
* @cond
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -32,24 +32,24 @@
#include "llsingleton.h"
class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
{
- LLSINGLETON(VolumeCatcherImpl);
- // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
- ~VolumeCatcherImpl();
+ LLSINGLETON(VolumeCatcherImpl);
+ // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
+ ~VolumeCatcherImpl();
public:
- void setVolume(F32 volume);
- void setPan(F32 pan);
-
+ void setVolume(F32 volume);
+ void setPan(F32 pan);
+
private:
- F32 mVolume;
- F32 mPan;
- bool mSystemIsVistaOrHigher;
+ F32 mVolume;
+ F32 mPan;
+ bool mSystemIsVistaOrHigher;
};
VolumeCatcherImpl::VolumeCatcherImpl()
-: mVolume(1.0f), // default volume is max
- mPan(0.f) // default pan is centered
+: mVolume(1.0f), // default volume is max
+ mPan(0.f) // default pan is centered
{
}
@@ -59,37 +59,37 @@ VolumeCatcherImpl::~VolumeCatcherImpl()
void VolumeCatcherImpl::setVolume(F32 volume)
{
- mVolume = volume;
+ mVolume = volume;
}
void VolumeCatcherImpl::setPan(F32 pan)
-{ // remember pan for calculating individual channel levels later
- mPan = pan;
+{ // remember pan for calculating individual channel levels later
+ mPan = pan;
}
/////////////////////////////////////////////////////
VolumeCatcher::VolumeCatcher()
{
- pimpl = VolumeCatcherImpl::getInstance();
+ pimpl = VolumeCatcherImpl::getInstance();
}
VolumeCatcher::~VolumeCatcher()
{
- // Let the instance persist until exit.
+ // Let the instance persist until exit.
}
void VolumeCatcher::setVolume(F32 volume)
{
- pimpl->setVolume(volume);
+ pimpl->setVolume(volume);
}
void VolumeCatcher::setPan(F32 pan)
{
- pimpl->setPan(pan);
+ pimpl->setPan(pan);
}
void VolumeCatcher::pump()
{
- // No periodic tasks are necessary for this implementation.
+ // No periodic tasks are necessary for this implementation.
}
diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp
index d5e17ba536..3aa73ed9a2 100644
--- a/indra/media_plugins/cef/media_plugin_cef.cpp
+++ b/indra/media_plugins/cef/media_plugin_cef.cpp
@@ -1,1147 +1,1147 @@
-/**
-* @file media_plugin_cef.cpp
-* @brief CEF (Chromium Embedding Framework) plugin for LLMedia API plugin system
-*
-* @cond
-* $LicenseInfo:firstyear=2008&license=viewerlgpl$
-* Second Life Viewer Source Code
-* Copyright (C) 2010, Linden Research, Inc.
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU Lesser General Public
-* License as published by the Free Software Foundation;
-* version 2.1 of the License only.
-*
-* This library is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this library; if not, write to the Free Software
-* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*
-* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
-* $/LicenseInfo$
-* @endcond
-*/
-
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "llglheaders.h" // for GL_* constants
-#include "llsdutil.h"
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "llstring.h"
-#include "volume_catcher.h"
-#include "media_plugin_base.h"
-
-#include "dullahan.h"
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginCEF :
- public MediaPluginBase
-{
-public:
- MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginCEF();
-
- /*virtual*/
- void receiveMessage(const char* message_string);
-
-private:
- bool init();
-
- void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height);
- void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect);
- void onConsoleMessageCallback(std::string message, std::string source, int line);
- void onStatusMessageCallback(std::string value);
- void onTitleChangeCallback(std::string title);
- void onTooltipCallback(std::string text);
- void onLoadStartCallback();
- void onRequestExitCallback();
- void onLoadEndCallback(int httpStatusCode, std::string url);
- void onLoadError(int status, const std::string error_text);
- void onAddressChangeCallback(std::string url);
- void onOpenPopupCallback(std::string url, std::string target);
- bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password);
- void onCursorChangedCallback(dullahan::ECursorType type);
- const std::vector<std::string> onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default);
- bool onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text);
- bool onJSBeforeUnloadCallback();
-
- void postDebugMessage(const std::string& msg);
- void authResponse(LLPluginMessage &message);
-
- void keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data);
- void unicodeInput(std::string event, LLSD native_key_data);
-
- void checkEditState();
- void setVolume();
-
- bool mEnableMediaPluginDebugging;
- std::string mHostLanguage;
- bool mCookiesEnabled;
- bool mPluginsEnabled;
- bool mJavascriptEnabled;
- bool mProxyEnabled;
- std::string mProxyHost;
- int mProxyPort;
- bool mDisableGPU;
- bool mDisableNetworkService;
- bool mUseMockKeyChain;
- bool mDisableWebSecurity;
- bool mFileAccessFromFileUrls;
- std::string mUserAgentSubtring;
- std::string mAuthUsername;
- std::string mAuthPassword;
- bool mAuthOK;
- bool mCanCut;
- bool mCanCopy;
- bool mCanPaste;
- std::string mRootCachePath;
- std::string mCachePath;
- std::string mContextCachePath;
- std::string mCefLogFile;
- bool mCefLogVerbose;
- std::vector<std::string> mPickedFiles;
- VolumeCatcher mVolumeCatcher;
- F32 mCurVolume;
- dullahan* mCEFLib;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-MediaPluginCEF::MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
-MediaPluginBase(host_send_func, host_user_data)
-{
- mWidth = 0;
- mHeight = 0;
- mDepth = 4;
- mPixels = 0;
- mEnableMediaPluginDebugging = true;
- mHostLanguage = "en";
- mCookiesEnabled = true;
- mPluginsEnabled = false;
- mJavascriptEnabled = true;
- mProxyEnabled = false;
- mProxyHost = "";
- mProxyPort = 0;
- mDisableGPU = false;
- mDisableNetworkService = true;
- mUseMockKeyChain = true;
- mDisableWebSecurity = false;
- mFileAccessFromFileUrls = false;
- mUserAgentSubtring = "";
- mAuthUsername = "";
- mAuthPassword = "";
- mAuthOK = false;
- mCanCut = false;
- mCanCopy = false;
- mCanPaste = false;
- mCachePath = "";
- mCefLogFile = "";
- mCefLogVerbose = false;
- mPickedFiles.clear();
- mCurVolume = 0.0;
-
- mCEFLib = new dullahan();
-
- setVolume();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-MediaPluginCEF::~MediaPluginCEF()
-{
- mCEFLib->shutdown();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::postDebugMessage(const std::string& msg)
-{
- if (mEnableMediaPluginDebugging)
- {
- std::stringstream str;
- str << "@Media Msg> " << msg;
-
- LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
- debug_message.setValue("message_text", str.str());
- debug_message.setValue("message_level", "info");
- sendMessage(debug_message);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height)
-{
- if( mPixels && pixels )
- {
- if (mWidth == width && mHeight == height)
- {
- memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
- }
- else
- {
- mCEFLib->setSize(mWidth, mHeight);
- }
- setDirty(0, 0, mWidth, mHeight);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onConsoleMessageCallback(std::string message, std::string source, int line)
-{
- std::stringstream str;
- str << "Console message: " << message << " in file(" << source << ") at line " << line;
- postDebugMessage(str.str());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onStatusMessageCallback(std::string value)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
- message.setValue("status", value);
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onTitleChangeCallback(std::string title)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", title);
- message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
- message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
- sendMessage(message);
-}
-
-void MediaPluginCEF::onTooltipCallback(std::string text)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "tooltip_text");
- message.setValue("tooltip", text);
- sendMessage(message);
-}
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onLoadStartCallback()
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
- //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed?
- message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
- message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
- sendMessage(message);
-}
-
-/////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onLoadError(int status, const std::string error_text)
-{
- std::stringstream msg;
-
- msg << "<b>Loading error!</b>";
- msg << "<p>";
- msg << "Message: " << error_text;
- msg << "<br>";
- msg << "Code: " << status;
-
- mCEFLib->showBrowserMessage(msg.str());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onRequestExitCallback()
-{
- LLPluginMessage message("base", "goodbye");
- sendMessage(message);
-
- // Will trigger delete on next staticReceiveMessage()
- mDeleteMe = true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onLoadEndCallback(int httpStatusCode, std::string url)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
- //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed?
- message.setValueS32("result_code", httpStatusCode);
- message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
- message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
- message.setValue("uri", url);
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onAddressChangeCallback(std::string url)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
- message.setValue("uri", url);
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
- message.setValue("uri", url);
- message.setValue("target", target);
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
- message.setValue("uri", url);
-
- // indicate if this interaction was from a user click (okay on a SLAPP) or
- // via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP)
- const std::string nav_type = user_gesture ? "clicked" : "navigated";
-
- message.setValue("nav_type", nav_type);
- message.setValueBoolean("is_redirect", is_redirect);
-
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password)
-{
- mAuthOK = false;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
- message.setValue("url", host);
- message.setValue("realm", realm);
- message.setValueBoolean("blocking_request", true);
-
- // The "blocking_request" key in the message means this sendMessage call will block until a response is received.
- sendMessage(message);
-
- if (mAuthOK)
- {
- username = mAuthUsername;
- password = mAuthPassword;
- }
-
- return mAuthOK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-const std::vector<std::string> MediaPluginCEF::onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, std::string dialog_accept_filter, bool& use_default)
-{
- // do not use the default CEF file picker
- use_default = false;
-
- if (dialog_type == dullahan::FD_OPEN_FILE)
- {
- mPickedFiles.clear();
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
- message.setValueBoolean("blocking_request", true);
- message.setValueBoolean("multiple_files", false);
-
- sendMessage(message);
-
- return mPickedFiles;
- }
- else if (dialog_type == dullahan::FD_OPEN_MULTIPLE_FILES)
- {
- mPickedFiles.clear();
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
- message.setValueBoolean("blocking_request", true);
- message.setValueBoolean("multiple_files", true);
-
- sendMessage(message);
-
- return mPickedFiles;
- }
- else if (dialog_type == dullahan::FD_SAVE_FILE)
- {
- mPickedFiles.clear();
- mAuthOK = false;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download");
- message.setValueBoolean("blocking_request", true);
- message.setValue("filename", default_file);
-
- sendMessage(message);
-
- return mPickedFiles;
- }
-
- return std::vector<std::string>();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool MediaPluginCEF::onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text)
-{
- // return true indicates we suppress the JavaScript alert UI entirely
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool MediaPluginCEF::onJSBeforeUnloadCallback()
-{
- // return true indicates we suppress the JavaScript UI entirely
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
-{
- std::string name = "";
-
- switch (type)
- {
- case dullahan::CT_POINTER:
- name = "UI_CURSOR_ARROW";
- break;
- case dullahan::CT_CROSS:
- name = "UI_CURSOR_CROSS";
- break;
- case dullahan::CT_HAND:
- name = "UI_CURSOR_HAND";
- break;
- case dullahan::CT_IBEAM:
- name = "UI_CURSOR_IBEAM";
- break;
- case dullahan::CT_WAIT:
- name = "UI_CURSOR_WAIT";
- break;
- //case dullahan::CT_HELP:
- case dullahan::CT_ROWRESIZE:
- case dullahan::CT_NORTHRESIZE:
- case dullahan::CT_SOUTHRESIZE:
- case dullahan::CT_NORTHSOUTHRESIZE:
- name = "UI_CURSOR_SIZENS";
- break;
- case dullahan::CT_COLUMNRESIZE:
- case dullahan::CT_EASTRESIZE:
- case dullahan::CT_WESTRESIZE:
- case dullahan::CT_EASTWESTRESIZE:
- name = "UI_CURSOR_SIZEWE";
- break;
- case dullahan::CT_NORTHEASTRESIZE:
- case dullahan::CT_SOUTHWESTRESIZE:
- case dullahan::CT_NORTHEASTSOUTHWESTRESIZE:
- name = "UI_CURSOR_SIZENESW";
- break;
- case dullahan::CT_SOUTHEASTRESIZE:
- case dullahan::CT_NORTHWESTRESIZE:
- case dullahan::CT_NORTHWESTSOUTHEASTRESIZE:
- name = "UI_CURSOR_SIZENWSE";
- break;
- case dullahan::CT_MOVE:
- name = "UI_CURSOR_SIZEALL";
- break;
- //case dullahan::CT_MIDDLEPANNING:
- //case dullahan::CT_EASTPANNING:
- //case dullahan::CT_NORTHPANNING:
- //case dullahan::CT_NORTHEASTPANNING:
- //case dullahan::CT_NORTHWESTPANNING:
- //case dullahan::CT_SOUTHPANNING:
- //case dullahan::CT_SOUTHEASTPANNING:
- //case dullahan::CT_SOUTHWESTPANNING:
- //case dullahan::CT_WESTPANNING:
- //case dullahan::CT_VERTICALTEXT:
- //case dullahan::CT_CELL:
- //case dullahan::CT_CONTEXTMENU:
- case dullahan::CT_ALIAS:
- name = "UI_CURSOR_TOOLMEDIAOPEN";
- break;
- case dullahan::CT_PROGRESS:
- name = "UI_CURSOR_WORKING";
- break;
- case dullahan::CT_COPY:
- name = "UI_CURSOR_ARROWCOPY";
- break;
- case dullahan::CT_NONE:
- name = "UI_CURSOR_NO";
- break;
- case dullahan::CT_NODROP:
- case dullahan::CT_NOTALLOWED:
- name = "UI_CURSOR_NOLOCKED";
- break;
- case dullahan::CT_ZOOMIN:
- name = "UI_CURSOR_TOOLZOOMIN";
- break;
- case dullahan::CT_ZOOMOUT:
- name = "UI_CURSOR_TOOLZOOMOUT";
- break;
- case dullahan::CT_GRAB:
- name = "UI_CURSOR_TOOLGRAB";
- break;
- //case dullahan::CT_GRABING:
- //case dullahan::CT_CUSTOM:
-
- default:
- LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL;
- break;
- }
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
- message.setValue("name", name);
- sendMessage(message);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::authResponse(LLPluginMessage &message)
-{
- mAuthOK = message.getValueBoolean("ok");
- if (mAuthOK)
- {
- mAuthUsername = message.getValue("username");
- mAuthPassword = message.getValue("password");
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::receiveMessage(const char* message_string)
-{
- // std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
- LLPluginMessage message_in;
-
- if (message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if (message_name == "init")
- {
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
- message.setValueLLSD("versions", versions);
-
- std::string plugin_version = "CEF plugin 1.1.412";
- message.setValue("plugin_version", plugin_version);
- sendMessage(message);
- }
- else if (message_name == "idle")
- {
- mCEFLib->update();
-
- mVolumeCatcher.pump();
-
- // this seems bad but unless the state changes (it won't until we figure out
- // how to get CEF to tell us if copy/cut/paste is available) then this function
- // will return immediately
- checkEditState();
- }
- else if (message_name == "cleanup")
- {
- mCEFLib->requestExit();
- }
- else if (message_name == "force_exit")
- {
- mDeleteMe = true;
- }
- else if (message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
- }
- else if (message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- if (mPixels == iter->second.mAddress)
- {
- mPixels = NULL;
- mTextureSegmentName.clear();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
- }
-
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
- }
- }
- else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if (message_name == "init")
- {
- // event callbacks from Dullahan
- mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
- mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
- mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
- mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1));
- mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this));
- mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1));
- mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2));
- mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
- mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
- mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1));
- mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this));
- mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
- mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this));
-
- dullahan::dullahan_settings settings;
-#if LL_WINDOWS
- // As of CEF version 83+, for Windows versions, we need to tell CEF
- // where the host helper process is since this DLL is not in the same
- // dir as the executable that loaded it (SLPlugin.exe). The code in
- // Dullahan that tried to figure out the location automatically uses
- // the location of the exe which isn't helpful so we tell it explicitly.
- std::vector<wchar_t> buffer(MAX_PATH + 1);
- GetCurrentDirectoryW(MAX_PATH, &buffer[0]);
- settings.host_process_path = ll_convert_wide_to_string(&buffer[0]);
-#endif
- settings.accept_language_list = mHostLanguage;
-
- // SL-15560: Product team overruled my change to set the default
- // embedded background color to match the floater background
- // and set it to white
- settings.background_color = 0xffffffff; // white
-
- settings.cache_enabled = true;
- settings.root_cache_path = mRootCachePath;
- settings.cache_path = mCachePath;
- settings.context_cache_path = mContextCachePath;
- settings.cookies_enabled = mCookiesEnabled;
-
- // configure proxy argument if enabled and valid
- if (mProxyEnabled && mProxyHost.length())
- {
- std::ostringstream proxy_url;
- proxy_url << mProxyHost << ":" << mProxyPort;
- settings.proxy_host_port = proxy_url.str();
- }
- settings.disable_gpu = mDisableGPU;
-#if LL_DARWIN
- settings.disable_network_service = mDisableNetworkService;
- settings.use_mock_keychain = mUseMockKeyChain;
-#endif
- // these were added to facilitate loading images directly into a local
- // web page for the prototype 360 project in 2017 - something that is
- // disallowed normally by the browser security model. Now the the source
- // (cubemap) images are stores as JavaScript, we can avoid opening up
- // this security hole (it was only set for the 360 floater but still
- // a concern). Leaving them here, explicitly turn off vs removing
- // entirely from this source file so that others are aware of them
- // in the future.
- settings.disable_web_security = false;
- settings.file_access_from_file_urls = false;
-
- settings.flash_enabled = mPluginsEnabled;
-
- // This setting applies to all plugins, not just Flash
- // Regarding, SL-15559 PDF files do not load in CEF v91,
- // it turns out that on Windows, PDF support is treated
- // as a plugin on Windows only so turning all plugins
- // off, disabled built in PDF support. (Works okay in
- // macOS surprisingly). To mitigrate this, we set the global
- // media enabled flag to whatever the consumer wants and
- // explicitly disable Flash with a different setting (below)
- settings.plugins_enabled = mPluginsEnabled;
-
- // SL-14897 Disable Flash support in the embedded browser
- settings.flash_enabled = false;
-
- settings.flip_mouse_y = false;
- settings.flip_pixels_y = true;
- settings.frame_rate = 60;
- settings.force_wave_audio = true;
- settings.initial_height = 1024;
- settings.initial_width = 1024;
- settings.java_enabled = false;
- settings.javascript_enabled = mJavascriptEnabled;
- settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granularity/query UI
-
- settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring);
- settings.webgl_enabled = true;
- settings.log_file = mCefLogFile;
- settings.log_verbose = mCefLogVerbose;
- settings.autoplay_without_gesture = true;
-
- std::vector<std::string> custom_schemes(1, "secondlife");
- mCEFLib->setCustomSchemes(custom_schemes);
-
- bool result = mCEFLib->init(settings);
- if (!result)
- {
- // if this fails, the media system in viewer will put up a message
- }
-
- // now we can set page zoom factor
- F32 factor = (F32)message_in.getValueReal("factor");
-#if LL_DARWIN
- //temporary fix for SL-10473: issue with displaying checkboxes on Mojave
- factor*=1.001;
-#endif
- mCEFLib->setPageZoom(factor);
-
- // Plugin gets to decide the texture parameters to use.
- mDepth = 4;
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- message.setValueS32("default_width", 1024);
- message.setValueS32("default_height", 1024);
- message.setValueS32("depth", mDepth);
- message.setValueU32("internalformat", GL_RGB);
- message.setValueU32("format", GL_BGRA);
- message.setValueU32("type", GL_UNSIGNED_BYTE);
- message.setValueBoolean("coords_opengl", true);
- sendMessage(message);
- }
- else if (message_name == "set_user_data_path")
- {
- std::string user_data_path_cache = message_in.getValue("cache_path");
- std::string subfolder = message_in.getValue("username");
-
- mRootCachePath = user_data_path_cache + "cef_cache";
- if (!subfolder.empty())
- {
- std::string delim;
-#if LL_WINDOWS
- // media plugin doesn't have access to gDirUtilp
- delim = "\\";
-#else
- delim = "/";
-#endif
- mCachePath = mRootCachePath + delim + subfolder;
- }
- else
- {
- mCachePath = mRootCachePath;
- }
- mContextCachePath = ""; // disabled by ""
- mCefLogFile = message_in.getValue("cef_log_file");
- mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log");
- }
- else if (message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
-
- if (!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- mPixels = (unsigned char*)iter->second.mAddress;
- mWidth = width;
- mHeight = height;
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
-
- mCEFLib->setSize(mWidth, mHeight);
- };
- };
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
-
- }
- else if (message_name == "set_language_code")
- {
- mHostLanguage = message_in.getValue("language");
- }
- else if (message_name == "load_uri")
- {
- std::string uri = message_in.getValue("uri");
- mCEFLib->navigate(uri);
- }
- else if (message_name == "execute_javascript")
- {
- std::string code = message_in.getValue("code");
- mCEFLib->executeJavaScript(code);
- }
- else if (message_name == "set_cookie")
- {
- std::string uri = message_in.getValue("uri");
- std::string name = message_in.getValue("name");
- std::string value = message_in.getValue("value");
- std::string domain = message_in.getValue("domain");
- std::string path = message_in.getValue("path");
- bool httponly = message_in.getValueBoolean("httponly");
- bool secure = message_in.getValueBoolean("secure");
- mCEFLib->setCookie(uri, name, value, domain, path, httponly, secure);
- }
- else if (message_name == "mouse_event")
- {
- std::string event = message_in.getValue("event");
-
- S32 x = message_in.getValueS32("x");
- S32 y = message_in.getValueS32("y");
-
- // only even send left mouse button events to the CEF library
- // (partially prompted by crash in macOS CEF when sending right button events)
- // we catch the right click in viewer and display our own context menu anyway
- S32 button = message_in.getValueS32("button");
- dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT;
-
- if (event == "down" && button == 0)
- {
- mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOWN, x, y);
- mCEFLib->setFocus();
-
- std::stringstream str;
- str << "Mouse down at = " << x << ", " << y;
- postDebugMessage(str.str());
- }
- else if (event == "up" && button == 0)
- {
- mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_UP, x, y);
-
- std::stringstream str;
- str << "Mouse up at = " << x << ", " << y;
- postDebugMessage(str.str());
- }
- else if (event == "double_click")
- {
- mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOUBLE_CLICK, x, y);
- }
- else
- {
- mCEFLib->mouseMove(x, y);
- }
- }
- else if (message_name == "scroll_event")
- {
- // Mouse coordinates for cef to be able to scroll 'containers'
- S32 x = message_in.getValueS32("x");
- S32 y = message_in.getValueS32("y");
-
- // Wheel's clicks
- S32 delta_x = message_in.getValueS32("clicks_x");
- S32 delta_y = message_in.getValueS32("clicks_y");
- const int scaling_factor = 40;
- delta_x *= -scaling_factor;
- delta_y *= -scaling_factor;
-
- mCEFLib->mouseWheel(x, y, delta_x, delta_y);
- }
- else if (message_name == "text_event")
- {
- std::string event = message_in.getValue("event");
- LLSD native_key_data = message_in.getValueLLSD("native_key_data");
- unicodeInput(event, native_key_data);
- }
- else if (message_name == "key_event")
- {
-#if LL_DARWIN
- std::string event = message_in.getValue("event");
- LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-
- dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
- if (event == "down")
- {
- key_event = dullahan::KE_KEY_DOWN;
- }
- else if (event == "repeat")
- {
- key_event = dullahan::KE_KEY_REPEAT;
- }
-
- keyEvent(key_event, native_key_data);
-
-#elif LL_WINDOWS
- std::string event = message_in.getValue("event");
- LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-
- // Treat unknown events as key-up for safety.
- dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
- if (event == "down")
- {
- key_event = dullahan::KE_KEY_DOWN;
- }
- else if (event == "repeat")
- {
- key_event = dullahan::KE_KEY_REPEAT;
- }
-
- keyEvent(key_event, native_key_data);
-#endif
- }
- else if (message_name == "enable_media_plugin_debugging")
- {
- mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");
- }
- if (message_name == "pick_file_response")
- {
- LLSD file_list_llsd = message_in.getValueLLSD("file_list");
-
- LLSD::array_const_iterator iter = file_list_llsd.beginArray();
- LLSD::array_const_iterator end = file_list_llsd.endArray();
- for (; iter != end; ++iter)
- {
- mPickedFiles.push_back(((*iter).asString()));
- }
- }
- if (message_name == "auth_response")
- {
- authResponse(message_in);
- }
- if (message_name == "edit_cut")
- {
- mCEFLib->editCut();
- }
- if (message_name == "edit_copy")
- {
- mCEFLib->editCopy();
- }
- if (message_name == "edit_paste")
- {
- mCEFLib->editPaste();
- }
- }
- else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
- {
- if (message_name == "set_page_zoom_factor")
- {
- F32 factor = (F32)message_in.getValueReal("factor");
-#if LL_DARWIN
- //temporary fix for SL-10473: issue with displaying checkboxes on Mojave
- factor*=1.001;
-#endif
- mCEFLib->setPageZoom(factor);
- }
- if (message_name == "browse_stop")
- {
- mCEFLib->stop();
- }
- else if (message_name == "browse_reload")
- {
- bool ignore_cache = true;
- mCEFLib->reload(ignore_cache);
- }
- else if (message_name == "browse_forward")
- {
- mCEFLib->goForward();
- }
- else if (message_name == "browse_back")
- {
- mCEFLib->goBack();
- }
- else if (message_name == "cookies_enabled")
- {
- mCookiesEnabled = message_in.getValueBoolean("enable");
- }
- else if (message_name == "clear_cookies")
- {
- mCEFLib->deleteAllCookies();
- }
- else if (message_name == "set_user_agent")
- {
- mUserAgentSubtring = message_in.getValue("user_agent");
- }
- else if (message_name == "show_web_inspector")
- {
- mCEFLib->showDevTools();
- }
- else if (message_name == "plugins_enabled")
- {
- mPluginsEnabled = message_in.getValueBoolean("enable");
- }
- else if (message_name == "javascript_enabled")
- {
- mJavascriptEnabled = message_in.getValueBoolean("enable");
- }
- else if (message_name == "gpu_disabled")
- {
- mDisableGPU = message_in.getValueBoolean("disable");
- }
- else if (message_name == "proxy_setup")
- {
- mProxyEnabled = message_in.getValueBoolean("enable");
- mProxyHost = message_in.getValue("host");
- mProxyPort = message_in.getValueS32("port");
- }
- else if (message_name == "web_security_disabled")
- {
- mDisableWebSecurity = message_in.getValueBoolean("disabled");
- }
- else if (message_name == "file_access_from_file_urls")
- {
- mFileAccessFromFileUrls = message_in.getValueBoolean("enabled");
- }
- }
- else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
- {
- if (message_name == "set_volume")
- {
- F32 volume = (F32)message_in.getValueReal("volume");
- mCurVolume = volume;
- setVolume();
- }
- }
- else
- {
- };
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data = LLSD::emptyMap())
-{
-#if LL_DARWIN
- U32 event_modifiers = native_key_data["event_modifiers"].asInteger();
- U32 event_keycode = native_key_data["event_keycode"].asInteger();
- U32 event_chars = native_key_data["event_chars"].asInteger();
- U32 event_umodchars = native_key_data["event_umodchars"].asInteger();
- bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean();
-
- // adding new code below in unicodeInput means we don't send ascii chars
- // here too or we get double key presses on a mac.
- bool esc_key = (event_umodchars == 27);
- bool tab_key_up = (event_umodchars == 9) && (key_event == dullahan::EKeyEvent::KE_KEY_UP);
- if ((esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f )) && !tab_key_up)
- {
- mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers,
- event_keycode, event_chars,
- event_umodchars, event_isrepeat);
- }
-#elif LL_WINDOWS
- U32 msg = ll_U32_from_sd(native_key_data["msg"]);
- U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
- U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
-
- mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);
-#endif
-};
-
-void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap())
-{
-#if LL_DARWIN
- // i didn't think this code was needed for macOS but without it, the IME
- // input in japanese (and likely others too) doesn't work correctly.
- // see maint-7654
- U32 event_modifiers = native_key_data["event_modifiers"].asInteger();
- U32 event_keycode = native_key_data["event_keycode"].asInteger();
- U32 event_chars = native_key_data["event_chars"].asInteger();
- U32 event_umodchars = native_key_data["event_umodchars"].asInteger();
- bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean();
-
- dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
- if (event == "down")
- {
- key_event = dullahan::KE_KEY_DOWN;
- }
-
- mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers,
- event_keycode, event_chars,
- event_umodchars, event_isrepeat);
-#elif LL_WINDOWS
- event = ""; // not needed here but prevents unused var warning as error
- U32 msg = ll_U32_from_sd(native_key_data["msg"]);
- U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
- U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
- mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);
-#endif
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void MediaPluginCEF::checkEditState()
-{
- bool can_cut = mCEFLib->editCanCut();
- bool can_copy = mCEFLib->editCanCopy();
- bool can_paste = mCEFLib->editCanPaste();
-
- if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
-
- if (can_cut != mCanCut)
- {
- mCanCut = can_cut;
- message.setValueBoolean("cut", can_cut);
- }
-
- if (can_copy != mCanCopy)
- {
- mCanCopy = can_copy;
- message.setValueBoolean("copy", can_copy);
- }
-
- if (can_paste != mCanPaste)
- {
- mCanPaste = can_paste;
- message.setValueBoolean("paste", can_paste);
- }
-
- sendMessage(message);
- }
-}
-
-void MediaPluginCEF::setVolume()
-{
- mVolumeCatcher.setVolume(mCurVolume);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-bool MediaPluginCEF::init()
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", "CEF Plugin");
- sendMessage(message);
-
- return true;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-//
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
- void* host_user_data,
- LLPluginInstance::sendMessageFunction *plugin_send_func,
- void **plugin_user_data)
-{
- MediaPluginCEF* self = new MediaPluginCEF(host_send_func, host_user_data);
- *plugin_send_func = MediaPluginCEF::staticReceiveMessage;
- *plugin_user_data = (void*)self;
-
- return 0;
-}
+/**
+* @file media_plugin_cef.cpp
+* @brief CEF (Chromium Embedding Framework) plugin for LLMedia API plugin system
+*
+* @cond
+* $LicenseInfo:firstyear=2008&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2010, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+* @endcond
+*/
+
+#include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
+
+#include "llglheaders.h" // for GL_* constants
+#include "llsdutil.h"
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "llstring.h"
+#include "volume_catcher.h"
+#include "media_plugin_base.h"
+
+#include "dullahan.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginCEF :
+ public MediaPluginBase
+{
+public:
+ MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginCEF();
+
+ /*virtual*/
+ void receiveMessage(const char* message_string);
+
+private:
+ bool init();
+
+ void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height);
+ void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect);
+ void onConsoleMessageCallback(std::string message, std::string source, int line);
+ void onStatusMessageCallback(std::string value);
+ void onTitleChangeCallback(std::string title);
+ void onTooltipCallback(std::string text);
+ void onLoadStartCallback();
+ void onRequestExitCallback();
+ void onLoadEndCallback(int httpStatusCode, std::string url);
+ void onLoadError(int status, const std::string error_text);
+ void onAddressChangeCallback(std::string url);
+ void onOpenPopupCallback(std::string url, std::string target);
+ bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password);
+ void onCursorChangedCallback(dullahan::ECursorType type);
+ const std::vector<std::string> onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default);
+ bool onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text);
+ bool onJSBeforeUnloadCallback();
+
+ void postDebugMessage(const std::string& msg);
+ void authResponse(LLPluginMessage &message);
+
+ void keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data);
+ void unicodeInput(std::string event, LLSD native_key_data);
+
+ void checkEditState();
+ void setVolume();
+
+ bool mEnableMediaPluginDebugging;
+ std::string mHostLanguage;
+ bool mCookiesEnabled;
+ bool mPluginsEnabled;
+ bool mJavascriptEnabled;
+ bool mProxyEnabled;
+ std::string mProxyHost;
+ int mProxyPort;
+ bool mDisableGPU;
+ bool mDisableNetworkService;
+ bool mUseMockKeyChain;
+ bool mDisableWebSecurity;
+ bool mFileAccessFromFileUrls;
+ std::string mUserAgentSubtring;
+ std::string mAuthUsername;
+ std::string mAuthPassword;
+ bool mAuthOK;
+ bool mCanCut;
+ bool mCanCopy;
+ bool mCanPaste;
+ std::string mRootCachePath;
+ std::string mCachePath;
+ std::string mContextCachePath;
+ std::string mCefLogFile;
+ bool mCefLogVerbose;
+ std::vector<std::string> mPickedFiles;
+ VolumeCatcher mVolumeCatcher;
+ F32 mCurVolume;
+ dullahan* mCEFLib;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginCEF::MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
+MediaPluginBase(host_send_func, host_user_data)
+{
+ mWidth = 0;
+ mHeight = 0;
+ mDepth = 4;
+ mPixels = 0;
+ mEnableMediaPluginDebugging = true;
+ mHostLanguage = "en";
+ mCookiesEnabled = true;
+ mPluginsEnabled = false;
+ mJavascriptEnabled = true;
+ mProxyEnabled = false;
+ mProxyHost = "";
+ mProxyPort = 0;
+ mDisableGPU = false;
+ mDisableNetworkService = true;
+ mUseMockKeyChain = true;
+ mDisableWebSecurity = false;
+ mFileAccessFromFileUrls = false;
+ mUserAgentSubtring = "";
+ mAuthUsername = "";
+ mAuthPassword = "";
+ mAuthOK = false;
+ mCanCut = false;
+ mCanCopy = false;
+ mCanPaste = false;
+ mCachePath = "";
+ mCefLogFile = "";
+ mCefLogVerbose = false;
+ mPickedFiles.clear();
+ mCurVolume = 0.0;
+
+ mCEFLib = new dullahan();
+
+ setVolume();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+MediaPluginCEF::~MediaPluginCEF()
+{
+ mCEFLib->shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::postDebugMessage(const std::string& msg)
+{
+ if (mEnableMediaPluginDebugging)
+ {
+ std::stringstream str;
+ str << "@Media Msg> " << msg;
+
+ LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
+ debug_message.setValue("message_text", str.str());
+ debug_message.setValue("message_level", "info");
+ sendMessage(debug_message);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height)
+{
+ if( mPixels && pixels )
+ {
+ if (mWidth == width && mHeight == height)
+ {
+ memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
+ }
+ else
+ {
+ mCEFLib->setSize(mWidth, mHeight);
+ }
+ setDirty(0, 0, mWidth, mHeight);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onConsoleMessageCallback(std::string message, std::string source, int line)
+{
+ std::stringstream str;
+ str << "Console message: " << message << " in file(" << source << ") at line " << line;
+ postDebugMessage(str.str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onStatusMessageCallback(std::string value)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
+ message.setValue("status", value);
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onTitleChangeCallback(std::string title)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", title);
+ message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
+ message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
+ sendMessage(message);
+}
+
+void MediaPluginCEF::onTooltipCallback(std::string text)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "tooltip_text");
+ message.setValue("tooltip", text);
+ sendMessage(message);
+}
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onLoadStartCallback()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+ //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed?
+ message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
+ message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
+ sendMessage(message);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onLoadError(int status, const std::string error_text)
+{
+ std::stringstream msg;
+
+ msg << "<b>Loading error!</b>";
+ msg << "<p>";
+ msg << "Message: " << error_text;
+ msg << "<br>";
+ msg << "Code: " << status;
+
+ mCEFLib->showBrowserMessage(msg.str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onRequestExitCallback()
+{
+ LLPluginMessage message("base", "goodbye");
+ sendMessage(message);
+
+ // Will trigger delete on next staticReceiveMessage()
+ mDeleteMe = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onLoadEndCallback(int httpStatusCode, std::string url)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+ //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed?
+ message.setValueS32("result_code", httpStatusCode);
+ message.setValueBoolean("history_back_available", mCEFLib->canGoBack());
+ message.setValueBoolean("history_forward_available", mCEFLib->canGoForward());
+ message.setValue("uri", url);
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onAddressChangeCallback(std::string url)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+ message.setValue("uri", url);
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
+ message.setValue("uri", url);
+ message.setValue("target", target);
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
+ message.setValue("uri", url);
+
+ // indicate if this interaction was from a user click (okay on a SLAPP) or
+ // via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP)
+ const std::string nav_type = user_gesture ? "clicked" : "navigated";
+
+ message.setValue("nav_type", nav_type);
+ message.setValueBoolean("is_redirect", is_redirect);
+
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password)
+{
+ mAuthOK = false;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
+ message.setValue("url", host);
+ message.setValue("realm", realm);
+ message.setValueBoolean("blocking_request", true);
+
+ // The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+ sendMessage(message);
+
+ if (mAuthOK)
+ {
+ username = mAuthUsername;
+ password = mAuthPassword;
+ }
+
+ return mAuthOK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+const std::vector<std::string> MediaPluginCEF::onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, std::string dialog_accept_filter, bool& use_default)
+{
+ // do not use the default CEF file picker
+ use_default = false;
+
+ if (dialog_type == dullahan::FD_OPEN_FILE)
+ {
+ mPickedFiles.clear();
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
+ message.setValueBoolean("blocking_request", true);
+ message.setValueBoolean("multiple_files", false);
+
+ sendMessage(message);
+
+ return mPickedFiles;
+ }
+ else if (dialog_type == dullahan::FD_OPEN_MULTIPLE_FILES)
+ {
+ mPickedFiles.clear();
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
+ message.setValueBoolean("blocking_request", true);
+ message.setValueBoolean("multiple_files", true);
+
+ sendMessage(message);
+
+ return mPickedFiles;
+ }
+ else if (dialog_type == dullahan::FD_SAVE_FILE)
+ {
+ mPickedFiles.clear();
+ mAuthOK = false;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download");
+ message.setValueBoolean("blocking_request", true);
+ message.setValue("filename", default_file);
+
+ sendMessage(message);
+
+ return mPickedFiles;
+ }
+
+ return std::vector<std::string>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text)
+{
+ // return true indicates we suppress the JavaScript alert UI entirely
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::onJSBeforeUnloadCallback()
+{
+ // return true indicates we suppress the JavaScript UI entirely
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type)
+{
+ std::string name = "";
+
+ switch (type)
+ {
+ case dullahan::CT_POINTER:
+ name = "UI_CURSOR_ARROW";
+ break;
+ case dullahan::CT_CROSS:
+ name = "UI_CURSOR_CROSS";
+ break;
+ case dullahan::CT_HAND:
+ name = "UI_CURSOR_HAND";
+ break;
+ case dullahan::CT_IBEAM:
+ name = "UI_CURSOR_IBEAM";
+ break;
+ case dullahan::CT_WAIT:
+ name = "UI_CURSOR_WAIT";
+ break;
+ //case dullahan::CT_HELP:
+ case dullahan::CT_ROWRESIZE:
+ case dullahan::CT_NORTHRESIZE:
+ case dullahan::CT_SOUTHRESIZE:
+ case dullahan::CT_NORTHSOUTHRESIZE:
+ name = "UI_CURSOR_SIZENS";
+ break;
+ case dullahan::CT_COLUMNRESIZE:
+ case dullahan::CT_EASTRESIZE:
+ case dullahan::CT_WESTRESIZE:
+ case dullahan::CT_EASTWESTRESIZE:
+ name = "UI_CURSOR_SIZEWE";
+ break;
+ case dullahan::CT_NORTHEASTRESIZE:
+ case dullahan::CT_SOUTHWESTRESIZE:
+ case dullahan::CT_NORTHEASTSOUTHWESTRESIZE:
+ name = "UI_CURSOR_SIZENESW";
+ break;
+ case dullahan::CT_SOUTHEASTRESIZE:
+ case dullahan::CT_NORTHWESTRESIZE:
+ case dullahan::CT_NORTHWESTSOUTHEASTRESIZE:
+ name = "UI_CURSOR_SIZENWSE";
+ break;
+ case dullahan::CT_MOVE:
+ name = "UI_CURSOR_SIZEALL";
+ break;
+ //case dullahan::CT_MIDDLEPANNING:
+ //case dullahan::CT_EASTPANNING:
+ //case dullahan::CT_NORTHPANNING:
+ //case dullahan::CT_NORTHEASTPANNING:
+ //case dullahan::CT_NORTHWESTPANNING:
+ //case dullahan::CT_SOUTHPANNING:
+ //case dullahan::CT_SOUTHEASTPANNING:
+ //case dullahan::CT_SOUTHWESTPANNING:
+ //case dullahan::CT_WESTPANNING:
+ //case dullahan::CT_VERTICALTEXT:
+ //case dullahan::CT_CELL:
+ //case dullahan::CT_CONTEXTMENU:
+ case dullahan::CT_ALIAS:
+ name = "UI_CURSOR_TOOLMEDIAOPEN";
+ break;
+ case dullahan::CT_PROGRESS:
+ name = "UI_CURSOR_WORKING";
+ break;
+ case dullahan::CT_COPY:
+ name = "UI_CURSOR_ARROWCOPY";
+ break;
+ case dullahan::CT_NONE:
+ name = "UI_CURSOR_NO";
+ break;
+ case dullahan::CT_NODROP:
+ case dullahan::CT_NOTALLOWED:
+ name = "UI_CURSOR_NOLOCKED";
+ break;
+ case dullahan::CT_ZOOMIN:
+ name = "UI_CURSOR_TOOLZOOMIN";
+ break;
+ case dullahan::CT_ZOOMOUT:
+ name = "UI_CURSOR_TOOLZOOMOUT";
+ break;
+ case dullahan::CT_GRAB:
+ name = "UI_CURSOR_TOOLGRAB";
+ break;
+ //case dullahan::CT_GRABING:
+ //case dullahan::CT_CUSTOM:
+
+ default:
+ LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL;
+ break;
+ }
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
+ message.setValue("name", name);
+ sendMessage(message);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::authResponse(LLPluginMessage &message)
+{
+ mAuthOK = message.getValueBoolean("ok");
+ if (mAuthOK)
+ {
+ mAuthUsername = message.getValue("username");
+ mAuthPassword = message.getValue("password");
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::receiveMessage(const char* message_string)
+{
+ // std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+ LLPluginMessage message_in;
+
+ if (message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if (message_name == "init")
+ {
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ std::string plugin_version = "CEF plugin 1.1.412";
+ message.setValue("plugin_version", plugin_version);
+ sendMessage(message);
+ }
+ else if (message_name == "idle")
+ {
+ mCEFLib->update();
+
+ mVolumeCatcher.pump();
+
+ // this seems bad but unless the state changes (it won't until we figure out
+ // how to get CEF to tell us if copy/cut/paste is available) then this function
+ // will return immediately
+ checkEditState();
+ }
+ else if (message_name == "cleanup")
+ {
+ mCEFLib->requestExit();
+ }
+ else if (message_name == "force_exit")
+ {
+ mDeleteMe = true;
+ }
+ else if (message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+ }
+ else if (message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ if (mPixels == iter->second.mAddress)
+ {
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+ }
+
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+ }
+ }
+ else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if (message_name == "init")
+ {
+ // event callbacks from Dullahan
+ mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1));
+ mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1));
+ mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1));
+ mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this));
+ mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1));
+ mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2));
+ mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
+ mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
+ mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1));
+ mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this));
+ mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this));
+
+ dullahan::dullahan_settings settings;
+#if LL_WINDOWS
+ // As of CEF version 83+, for Windows versions, we need to tell CEF
+ // where the host helper process is since this DLL is not in the same
+ // dir as the executable that loaded it (SLPlugin.exe). The code in
+ // Dullahan that tried to figure out the location automatically uses
+ // the location of the exe which isn't helpful so we tell it explicitly.
+ std::vector<wchar_t> buffer(MAX_PATH + 1);
+ GetCurrentDirectoryW(MAX_PATH, &buffer[0]);
+ settings.host_process_path = ll_convert_wide_to_string(&buffer[0]);
+#endif
+ settings.accept_language_list = mHostLanguage;
+
+ // SL-15560: Product team overruled my change to set the default
+ // embedded background color to match the floater background
+ // and set it to white
+ settings.background_color = 0xffffffff; // white
+
+ settings.cache_enabled = true;
+ settings.root_cache_path = mRootCachePath;
+ settings.cache_path = mCachePath;
+ settings.context_cache_path = mContextCachePath;
+ settings.cookies_enabled = mCookiesEnabled;
+
+ // configure proxy argument if enabled and valid
+ if (mProxyEnabled && mProxyHost.length())
+ {
+ std::ostringstream proxy_url;
+ proxy_url << mProxyHost << ":" << mProxyPort;
+ settings.proxy_host_port = proxy_url.str();
+ }
+ settings.disable_gpu = mDisableGPU;
+#if LL_DARWIN
+ settings.disable_network_service = mDisableNetworkService;
+ settings.use_mock_keychain = mUseMockKeyChain;
+#endif
+ // these were added to facilitate loading images directly into a local
+ // web page for the prototype 360 project in 2017 - something that is
+ // disallowed normally by the browser security model. Now the the source
+ // (cubemap) images are stores as JavaScript, we can avoid opening up
+ // this security hole (it was only set for the 360 floater but still
+ // a concern). Leaving them here, explicitly turn off vs removing
+ // entirely from this source file so that others are aware of them
+ // in the future.
+ settings.disable_web_security = false;
+ settings.file_access_from_file_urls = false;
+
+ settings.flash_enabled = mPluginsEnabled;
+
+ // This setting applies to all plugins, not just Flash
+ // Regarding, SL-15559 PDF files do not load in CEF v91,
+ // it turns out that on Windows, PDF support is treated
+ // as a plugin on Windows only so turning all plugins
+ // off, disabled built in PDF support. (Works okay in
+ // macOS surprisingly). To mitigrate this, we set the global
+ // media enabled flag to whatever the consumer wants and
+ // explicitly disable Flash with a different setting (below)
+ settings.plugins_enabled = mPluginsEnabled;
+
+ // SL-14897 Disable Flash support in the embedded browser
+ settings.flash_enabled = false;
+
+ settings.flip_mouse_y = false;
+ settings.flip_pixels_y = true;
+ settings.frame_rate = 60;
+ settings.force_wave_audio = true;
+ settings.initial_height = 1024;
+ settings.initial_width = 1024;
+ settings.java_enabled = false;
+ settings.javascript_enabled = mJavascriptEnabled;
+ settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granularity/query UI
+
+ settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring);
+ settings.webgl_enabled = true;
+ settings.log_file = mCefLogFile;
+ settings.log_verbose = mCefLogVerbose;
+ settings.autoplay_without_gesture = true;
+
+ std::vector<std::string> custom_schemes(1, "secondlife");
+ mCEFLib->setCustomSchemes(custom_schemes);
+
+ bool result = mCEFLib->init(settings);
+ if (!result)
+ {
+ // if this fails, the media system in viewer will put up a message
+ }
+
+ // now we can set page zoom factor
+ F32 factor = (F32)message_in.getValueReal("factor");
+#if LL_DARWIN
+ //temporary fix for SL-10473: issue with displaying checkboxes on Mojave
+ factor*=1.001;
+#endif
+ mCEFLib->setPageZoom(factor);
+
+ // Plugin gets to decide the texture parameters to use.
+ mDepth = 4;
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ message.setValueS32("default_width", 1024);
+ message.setValueS32("default_height", 1024);
+ message.setValueS32("depth", mDepth);
+ message.setValueU32("internalformat", GL_RGB);
+ message.setValueU32("format", GL_BGRA);
+ message.setValueU32("type", GL_UNSIGNED_BYTE);
+ message.setValueBoolean("coords_opengl", true);
+ sendMessage(message);
+ }
+ else if (message_name == "set_user_data_path")
+ {
+ std::string user_data_path_cache = message_in.getValue("cache_path");
+ std::string subfolder = message_in.getValue("username");
+
+ mRootCachePath = user_data_path_cache + "cef_cache";
+ if (!subfolder.empty())
+ {
+ std::string delim;
+#if LL_WINDOWS
+ // media plugin doesn't have access to gDirUtilp
+ delim = "\\";
+#else
+ delim = "/";
+#endif
+ mCachePath = mRootCachePath + delim + subfolder;
+ }
+ else
+ {
+ mCachePath = mRootCachePath;
+ }
+ mContextCachePath = ""; // disabled by ""
+ mCefLogFile = message_in.getValue("cef_log_file");
+ mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log");
+ }
+ else if (message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ if (!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mWidth = width;
+ mHeight = height;
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+
+ mCEFLib->setSize(mWidth, mHeight);
+ };
+ };
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+
+ }
+ else if (message_name == "set_language_code")
+ {
+ mHostLanguage = message_in.getValue("language");
+ }
+ else if (message_name == "load_uri")
+ {
+ std::string uri = message_in.getValue("uri");
+ mCEFLib->navigate(uri);
+ }
+ else if (message_name == "execute_javascript")
+ {
+ std::string code = message_in.getValue("code");
+ mCEFLib->executeJavaScript(code);
+ }
+ else if (message_name == "set_cookie")
+ {
+ std::string uri = message_in.getValue("uri");
+ std::string name = message_in.getValue("name");
+ std::string value = message_in.getValue("value");
+ std::string domain = message_in.getValue("domain");
+ std::string path = message_in.getValue("path");
+ bool httponly = message_in.getValueBoolean("httponly");
+ bool secure = message_in.getValueBoolean("secure");
+ mCEFLib->setCookie(uri, name, value, domain, path, httponly, secure);
+ }
+ else if (message_name == "mouse_event")
+ {
+ std::string event = message_in.getValue("event");
+
+ S32 x = message_in.getValueS32("x");
+ S32 y = message_in.getValueS32("y");
+
+ // only even send left mouse button events to the CEF library
+ // (partially prompted by crash in macOS CEF when sending right button events)
+ // we catch the right click in viewer and display our own context menu anyway
+ S32 button = message_in.getValueS32("button");
+ dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT;
+
+ if (event == "down" && button == 0)
+ {
+ mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOWN, x, y);
+ mCEFLib->setFocus();
+
+ std::stringstream str;
+ str << "Mouse down at = " << x << ", " << y;
+ postDebugMessage(str.str());
+ }
+ else if (event == "up" && button == 0)
+ {
+ mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_UP, x, y);
+
+ std::stringstream str;
+ str << "Mouse up at = " << x << ", " << y;
+ postDebugMessage(str.str());
+ }
+ else if (event == "double_click")
+ {
+ mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOUBLE_CLICK, x, y);
+ }
+ else
+ {
+ mCEFLib->mouseMove(x, y);
+ }
+ }
+ else if (message_name == "scroll_event")
+ {
+ // Mouse coordinates for cef to be able to scroll 'containers'
+ S32 x = message_in.getValueS32("x");
+ S32 y = message_in.getValueS32("y");
+
+ // Wheel's clicks
+ S32 delta_x = message_in.getValueS32("clicks_x");
+ S32 delta_y = message_in.getValueS32("clicks_y");
+ const int scaling_factor = 40;
+ delta_x *= -scaling_factor;
+ delta_y *= -scaling_factor;
+
+ mCEFLib->mouseWheel(x, y, delta_x, delta_y);
+ }
+ else if (message_name == "text_event")
+ {
+ std::string event = message_in.getValue("event");
+ LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+ unicodeInput(event, native_key_data);
+ }
+ else if (message_name == "key_event")
+ {
+#if LL_DARWIN
+ std::string event = message_in.getValue("event");
+ LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+
+ dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
+ if (event == "down")
+ {
+ key_event = dullahan::KE_KEY_DOWN;
+ }
+ else if (event == "repeat")
+ {
+ key_event = dullahan::KE_KEY_REPEAT;
+ }
+
+ keyEvent(key_event, native_key_data);
+
+#elif LL_WINDOWS
+ std::string event = message_in.getValue("event");
+ LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+
+ // Treat unknown events as key-up for safety.
+ dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
+ if (event == "down")
+ {
+ key_event = dullahan::KE_KEY_DOWN;
+ }
+ else if (event == "repeat")
+ {
+ key_event = dullahan::KE_KEY_REPEAT;
+ }
+
+ keyEvent(key_event, native_key_data);
+#endif
+ }
+ else if (message_name == "enable_media_plugin_debugging")
+ {
+ mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");
+ }
+ if (message_name == "pick_file_response")
+ {
+ LLSD file_list_llsd = message_in.getValueLLSD("file_list");
+
+ LLSD::array_const_iterator iter = file_list_llsd.beginArray();
+ LLSD::array_const_iterator end = file_list_llsd.endArray();
+ for (; iter != end; ++iter)
+ {
+ mPickedFiles.push_back(((*iter).asString()));
+ }
+ }
+ if (message_name == "auth_response")
+ {
+ authResponse(message_in);
+ }
+ if (message_name == "edit_cut")
+ {
+ mCEFLib->editCut();
+ }
+ if (message_name == "edit_copy")
+ {
+ mCEFLib->editCopy();
+ }
+ if (message_name == "edit_paste")
+ {
+ mCEFLib->editPaste();
+ }
+ }
+ else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+ {
+ if (message_name == "set_page_zoom_factor")
+ {
+ F32 factor = (F32)message_in.getValueReal("factor");
+#if LL_DARWIN
+ //temporary fix for SL-10473: issue with displaying checkboxes on Mojave
+ factor*=1.001;
+#endif
+ mCEFLib->setPageZoom(factor);
+ }
+ if (message_name == "browse_stop")
+ {
+ mCEFLib->stop();
+ }
+ else if (message_name == "browse_reload")
+ {
+ bool ignore_cache = true;
+ mCEFLib->reload(ignore_cache);
+ }
+ else if (message_name == "browse_forward")
+ {
+ mCEFLib->goForward();
+ }
+ else if (message_name == "browse_back")
+ {
+ mCEFLib->goBack();
+ }
+ else if (message_name == "cookies_enabled")
+ {
+ mCookiesEnabled = message_in.getValueBoolean("enable");
+ }
+ else if (message_name == "clear_cookies")
+ {
+ mCEFLib->deleteAllCookies();
+ }
+ else if (message_name == "set_user_agent")
+ {
+ mUserAgentSubtring = message_in.getValue("user_agent");
+ }
+ else if (message_name == "show_web_inspector")
+ {
+ mCEFLib->showDevTools();
+ }
+ else if (message_name == "plugins_enabled")
+ {
+ mPluginsEnabled = message_in.getValueBoolean("enable");
+ }
+ else if (message_name == "javascript_enabled")
+ {
+ mJavascriptEnabled = message_in.getValueBoolean("enable");
+ }
+ else if (message_name == "gpu_disabled")
+ {
+ mDisableGPU = message_in.getValueBoolean("disable");
+ }
+ else if (message_name == "proxy_setup")
+ {
+ mProxyEnabled = message_in.getValueBoolean("enable");
+ mProxyHost = message_in.getValue("host");
+ mProxyPort = message_in.getValueS32("port");
+ }
+ else if (message_name == "web_security_disabled")
+ {
+ mDisableWebSecurity = message_in.getValueBoolean("disabled");
+ }
+ else if (message_name == "file_access_from_file_urls")
+ {
+ mFileAccessFromFileUrls = message_in.getValueBoolean("enabled");
+ }
+ }
+ else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+ {
+ if (message_name == "set_volume")
+ {
+ F32 volume = (F32)message_in.getValueReal("volume");
+ mCurVolume = volume;
+ setVolume();
+ }
+ }
+ else
+ {
+ };
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data = LLSD::emptyMap())
+{
+#if LL_DARWIN
+ U32 event_modifiers = native_key_data["event_modifiers"].asInteger();
+ U32 event_keycode = native_key_data["event_keycode"].asInteger();
+ U32 event_chars = native_key_data["event_chars"].asInteger();
+ U32 event_umodchars = native_key_data["event_umodchars"].asInteger();
+ bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean();
+
+ // adding new code below in unicodeInput means we don't send ascii chars
+ // here too or we get double key presses on a mac.
+ bool esc_key = (event_umodchars == 27);
+ bool tab_key_up = (event_umodchars == 9) && (key_event == dullahan::EKeyEvent::KE_KEY_UP);
+ if ((esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f )) && !tab_key_up)
+ {
+ mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers,
+ event_keycode, event_chars,
+ event_umodchars, event_isrepeat);
+ }
+#elif LL_WINDOWS
+ U32 msg = ll_U32_from_sd(native_key_data["msg"]);
+ U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
+ U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
+
+ mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);
+#endif
+};
+
+void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap())
+{
+#if LL_DARWIN
+ // i didn't think this code was needed for macOS but without it, the IME
+ // input in japanese (and likely others too) doesn't work correctly.
+ // see maint-7654
+ U32 event_modifiers = native_key_data["event_modifiers"].asInteger();
+ U32 event_keycode = native_key_data["event_keycode"].asInteger();
+ U32 event_chars = native_key_data["event_chars"].asInteger();
+ U32 event_umodchars = native_key_data["event_umodchars"].asInteger();
+ bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean();
+
+ dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP;
+ if (event == "down")
+ {
+ key_event = dullahan::KE_KEY_DOWN;
+ }
+
+ mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers,
+ event_keycode, event_chars,
+ event_umodchars, event_isrepeat);
+#elif LL_WINDOWS
+ event = ""; // not needed here but prevents unused var warning as error
+ U32 msg = ll_U32_from_sd(native_key_data["msg"]);
+ U32 wparam = ll_U32_from_sd(native_key_data["w_param"]);
+ U64 lparam = ll_U32_from_sd(native_key_data["l_param"]);
+ mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam);
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void MediaPluginCEF::checkEditState()
+{
+ bool can_cut = mCEFLib->editCanCut();
+ bool can_copy = mCEFLib->editCanCopy();
+ bool can_paste = mCEFLib->editCanPaste();
+
+ if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
+
+ if (can_cut != mCanCut)
+ {
+ mCanCut = can_cut;
+ message.setValueBoolean("cut", can_cut);
+ }
+
+ if (can_copy != mCanCopy)
+ {
+ mCanCopy = can_copy;
+ message.setValueBoolean("copy", can_copy);
+ }
+
+ if (can_paste != mCanPaste)
+ {
+ mCanPaste = can_paste;
+ message.setValueBoolean("paste", can_paste);
+ }
+
+ sendMessage(message);
+ }
+}
+
+void MediaPluginCEF::setVolume()
+{
+ mVolumeCatcher.setVolume(mCurVolume);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool MediaPluginCEF::init()
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", "CEF Plugin");
+ sendMessage(message);
+
+ return true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
+ void* host_user_data,
+ LLPluginInstance::sendMessageFunction *plugin_send_func,
+ void **plugin_user_data)
+{
+ MediaPluginCEF* self = new MediaPluginCEF(host_send_func, host_user_data);
+ *plugin_send_func = MediaPluginCEF::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
+
+ return 0;
+}
diff --git a/indra/media_plugins/cef/volume_catcher.h b/indra/media_plugins/cef/volume_catcher.h
index 337f2913d3..ea97a24947 100644
--- a/indra/media_plugins/cef/volume_catcher.h
+++ b/indra/media_plugins/cef/volume_catcher.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file volume_catcher.h
* @brief Interface to a class with platform-specific implementations that allows control of the audio volume of all sources in the current process.
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -36,19 +36,19 @@ class VolumeCatcherImpl;
class VolumeCatcher
{
public:
- VolumeCatcher();
- ~VolumeCatcher();
+ VolumeCatcher();
+ ~VolumeCatcher();
+
+ void setVolume(F32 volume); // 0.0 - 1.0
+
+ // Set the left-right pan of audio sources
+ // where -1.0 = left, 0 = center, and 1.0 = right
+ void setPan(F32 pan);
- void setVolume(F32 volume); // 0.0 - 1.0
-
- // Set the left-right pan of audio sources
- // where -1.0 = left, 0 = center, and 1.0 = right
- void setPan(F32 pan);
+ void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume
- void pump(); // call this at least a few times a second if you can - it affects how quickly we can 'catch' a new audio source and adjust its volume
-
private:
- VolumeCatcherImpl *pimpl;
+ VolumeCatcherImpl *pimpl;
};
#endif // VOLUME_CATCHER_H
diff --git a/indra/media_plugins/cef/windows_volume_catcher.cpp b/indra/media_plugins/cef/windows_volume_catcher.cpp
index 7a36123a11..e7daeb5f74 100644
--- a/indra/media_plugins/cef/windows_volume_catcher.cpp
+++ b/indra/media_plugins/cef/windows_volume_catcher.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file windows_volume_catcher.cpp
* @brief A Windows implementation of volume level control of all audio channels opened by a process.
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -32,24 +32,24 @@
#include <mmeapi.h>
class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
{
- LLSINGLETON(VolumeCatcherImpl);
- // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
- ~VolumeCatcherImpl();
+ LLSINGLETON(VolumeCatcherImpl);
+ // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
+ ~VolumeCatcherImpl();
public:
- void setVolume(F32 volume);
- void setPan(F32 pan);
-
+ void setVolume(F32 volume);
+ void setPan(F32 pan);
+
private:
- F32 mVolume;
- F32 mPan;
- bool mSystemIsVistaOrHigher;
+ F32 mVolume;
+ F32 mPan;
+ bool mSystemIsVistaOrHigher;
};
VolumeCatcherImpl::VolumeCatcherImpl()
-: mVolume(1.0f), // default volume is max
- mPan(0.f) // default pan is centered
+: mVolume(1.0f), // default volume is max
+ mPan(0.f) // default pan is centered
{
}
@@ -59,46 +59,46 @@ VolumeCatcherImpl::~VolumeCatcherImpl()
void VolumeCatcherImpl::setVolume(F32 volume)
{
- mVolume = volume;
-
- // set both left/right to same volume
- // TODO: use pan value to set independently
- DWORD left_channel = (DWORD)(mVolume * 65535.0f);
- DWORD right_channel = (DWORD)(mVolume * 65535.0f);
- DWORD hw_volume = left_channel << 16 | right_channel;
- ::waveOutSetVolume(NULL, hw_volume);
+ mVolume = volume;
+
+ // set both left/right to same volume
+ // TODO: use pan value to set independently
+ DWORD left_channel = (DWORD)(mVolume * 65535.0f);
+ DWORD right_channel = (DWORD)(mVolume * 65535.0f);
+ DWORD hw_volume = left_channel << 16 | right_channel;
+ ::waveOutSetVolume(NULL, hw_volume);
}
void VolumeCatcherImpl::setPan(F32 pan)
-{ // remember pan for calculating individual channel levels later
- mPan = pan;
+{ // remember pan for calculating individual channel levels later
+ mPan = pan;
}
/////////////////////////////////////////////////////
VolumeCatcher::VolumeCatcher()
{
- pimpl = VolumeCatcherImpl::getInstance();
+ pimpl = VolumeCatcherImpl::getInstance();
}
VolumeCatcher::~VolumeCatcher()
{
- // Let the instance persist until exit.
+ // Let the instance persist until exit.
}
void VolumeCatcher::setVolume(F32 volume)
{
- pimpl->setVolume(volume);
+ pimpl->setVolume(volume);
}
void VolumeCatcher::setPan(F32 pan)
{
- pimpl->setPan(pan);
+ pimpl->setPan(pan);
}
void VolumeCatcher::pump()
{
- // No periodic tasks are necessary for this implementation.
+ // No periodic tasks are necessary for this implementation.
}
diff --git a/indra/media_plugins/example/media_plugin_example.cpp b/indra/media_plugins/example/media_plugin_example.cpp
index 650685fb94..0b22b7833f 100644
--- a/indra/media_plugins/example/media_plugin_example.cpp
+++ b/indra/media_plugins/example/media_plugin_example.cpp
@@ -39,30 +39,30 @@
////////////////////////////////////////////////////////////////////////////////
//
class mediaPluginExample :
- public MediaPluginBase
+ public MediaPluginBase
{
public:
- mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~mediaPluginExample();
+ mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~mediaPluginExample();
- /*virtual*/ void receiveMessage(const char* message_string);
+ /*virtual*/ void receiveMessage(const char* message_string);
private:
- bool init();
- void update(F64 milliseconds);
- bool mFirstTime;
-
- time_t mLastUpdateTime;
- enum Constants { ENumObjects = 64 };
- unsigned char* mBackgroundPixels;
- int mColorR[ENumObjects];
- int mColorG[ENumObjects];
- int mColorB[ENumObjects];
- int mXpos[ENumObjects];
- int mYpos[ENumObjects];
- int mXInc[ENumObjects];
- int mYInc[ENumObjects];
- int mBlockSize[ENumObjects];
+ bool init();
+ void update(F64 milliseconds);
+ bool mFirstTime;
+
+ time_t mLastUpdateTime;
+ enum Constants { ENumObjects = 64 };
+ unsigned char* mBackgroundPixels;
+ int mColorR[ENumObjects];
+ int mColorG[ENumObjects];
+ int mColorB[ENumObjects];
+ int mXpos[ENumObjects];
+ int mYpos[ENumObjects];
+ int mXInc[ENumObjects];
+ int mYInc[ENumObjects];
+ int mBlockSize[ENumObjects];
};
////////////////////////////////////////////////////////////////////////////////
@@ -70,15 +70,15 @@ private:
mediaPluginExample::mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
MediaPluginBase(host_send_func, host_user_data)
{
- mFirstTime = true;
- mTextureWidth = 0;
- mTextureHeight = 0;
- mWidth = 0;
- mHeight = 0;
- mDepth = 4;
- mPixels = 0;
- mLastUpdateTime = 0;
- mBackgroundPixels = 0;
+ mFirstTime = true;
+ mTextureWidth = 0;
+ mTextureHeight = 0;
+ mWidth = 0;
+ mHeight = 0;
+ mDepth = 4;
+ mPixels = 0;
+ mLastUpdateTime = 0;
+ mBackgroundPixels = 0;
}
////////////////////////////////////////////////////////////////////////////////
@@ -91,305 +91,305 @@ mediaPluginExample::~mediaPluginExample()
//
void mediaPluginExample::receiveMessage(const char* message_string)
{
- // std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
- LLPluginMessage message_in;
-
- if (message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if (message_name == "init")
- {
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
- message.setValueLLSD("versions", versions);
-
- std::string plugin_version = "Example plugin 0.0.0";
- message.setValue("plugin_version", plugin_version);
- sendMessage(message);
- }
- else if (message_name == "idle")
- {
- // no response is necessary here.
- F64 time = message_in.getValueReal("time");
-
- // Convert time to milliseconds for update()
- update((int)(time * 1000.0f));
- }
- else if (message_name == "cleanup")
- {
- LLPluginMessage message("base", "goodbye");
- sendMessage(message);
-
- mDeleteMe = true;
- }
- else if (message_name == "force_exit")
- {
- mDeleteMe = true;
- }
- else if (message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
- }
- else if (message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- if (mPixels == iter->second.mAddress)
- {
- // This is the currently active pixel buffer. Make sure we stop drawing to it.
- mPixels = NULL;
- mTextureSegmentName.clear();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
- // std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
- }
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
- // std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
- }
- }
- else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if (message_name == "init")
- {
- // Plugin gets to decide the texture parameters to use.
- mDepth = 4;
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- message.setValueS32("default_width", 1024);
- message.setValueS32("default_height", 1024);
- message.setValueS32("depth", mDepth);
- message.setValueU32("internalformat", GL_RGB);
- message.setValueU32("format", GL_RGBA);
- message.setValueU32("type", GL_UNSIGNED_BYTE);
- message.setValueBoolean("coords_opengl", true);
- sendMessage(message);
- }
- else if (message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
-
- if (!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- mPixels = (unsigned char*)iter->second.mAddress;
- mWidth = width;
- mHeight = height;
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
- };
- };
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
-
- mFirstTime = true;
- mLastUpdateTime = 0;
-
- }
- else if (message_name == "load_uri")
- {
- }
- else if (message_name == "mouse_event")
- {
- std::string event = message_in.getValue("event");
- if (event == "down")
- {
-
- }
- else if (event == "up")
- {
- }
- else if (event == "double_click")
- {
- }
- }
- }
- else
- {
- };
- }
+ // std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+ LLPluginMessage message_in;
+
+ if (message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if (message_name == "init")
+ {
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ std::string plugin_version = "Example plugin 0.0.0";
+ message.setValue("plugin_version", plugin_version);
+ sendMessage(message);
+ }
+ else if (message_name == "idle")
+ {
+ // no response is necessary here.
+ F64 time = message_in.getValueReal("time");
+
+ // Convert time to milliseconds for update()
+ update((int)(time * 1000.0f));
+ }
+ else if (message_name == "cleanup")
+ {
+ LLPluginMessage message("base", "goodbye");
+ sendMessage(message);
+
+ mDeleteMe = true;
+ }
+ else if (message_name == "force_exit")
+ {
+ mDeleteMe = true;
+ }
+ else if (message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+ }
+ else if (message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ if (mPixels == iter->second.mAddress)
+ {
+ // This is the currently active pixel buffer. Make sure we stop drawing to it.
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+ // std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+ // std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+ }
+ }
+ else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if (message_name == "init")
+ {
+ // Plugin gets to decide the texture parameters to use.
+ mDepth = 4;
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ message.setValueS32("default_width", 1024);
+ message.setValueS32("default_height", 1024);
+ message.setValueS32("depth", mDepth);
+ message.setValueU32("internalformat", GL_RGB);
+ message.setValueU32("format", GL_RGBA);
+ message.setValueU32("type", GL_UNSIGNED_BYTE);
+ message.setValueBoolean("coords_opengl", true);
+ sendMessage(message);
+ }
+ else if (message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ if (!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mWidth = width;
+ mHeight = height;
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+ };
+ };
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+
+ mFirstTime = true;
+ mLastUpdateTime = 0;
+
+ }
+ else if (message_name == "load_uri")
+ {
+ }
+ else if (message_name == "mouse_event")
+ {
+ std::string event = message_in.getValue("event");
+ if (event == "down")
+ {
+
+ }
+ else if (event == "up")
+ {
+ }
+ else if (event == "double_click")
+ {
+ }
+ }
+ }
+ else
+ {
+ };
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
void mediaPluginExample::update(F64 milliseconds)
{
- if (mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048)
- return;
-
- if (mPixels == 0)
- return;
-
- if (mFirstTime)
- {
- for (int n = 0; n < ENumObjects; ++n)
- {
- mXpos[n] = (mWidth / 2) + rand() % (mWidth / 16) - (mWidth / 32);
- mYpos[n] = (mHeight / 2) + rand() % (mHeight / 16) - (mHeight / 32);
-
- mColorR[n] = rand() % 0x60 + 0x60;
- mColorG[n] = rand() % 0x60 + 0x60;
- mColorB[n] = rand() % 0x60 + 0x60;
-
- mXInc[n] = 0;
- while (mXInc[n] == 0)
- mXInc[n] = rand() % 7 - 3;
-
- mYInc[n] = 0;
- while (mYInc[n] == 0)
- mYInc[n] = rand() % 9 - 4;
-
- mBlockSize[n] = rand() % 0x30 + 0x10;
- };
-
- delete[] mBackgroundPixels;
-
- mBackgroundPixels = new unsigned char[mWidth * mHeight * mDepth];
-
- mFirstTime = false;
- };
-
- if (time(NULL) > mLastUpdateTime + 3)
- {
- const int num_squares = rand() % 20 + 4;
- int sqr1_r = rand() % 0x80 + 0x20;
- int sqr1_g = rand() % 0x80 + 0x20;
- int sqr1_b = rand() % 0x80 + 0x20;
- int sqr2_r = rand() % 0x80 + 0x20;
- int sqr2_g = rand() % 0x80 + 0x20;
- int sqr2_b = rand() % 0x80 + 0x20;
-
- for (int y1 = 0; y1 < num_squares; ++y1)
- {
- for (int x1 = 0; x1 < num_squares; ++x1)
- {
- int px_start = mWidth * x1 / num_squares;
- int px_end = (mWidth * (x1 + 1)) / num_squares;
- int py_start = mHeight * y1 / num_squares;
- int py_end = (mHeight * (y1 + 1)) / num_squares;
-
- for (int y2 = py_start; y2 < py_end; ++y2)
- {
- for (int x2 = px_start; x2 < px_end; ++x2)
- {
- int rowspan = mWidth * mDepth;
-
- if ((y1 % 2) ^ (x1 % 2))
- {
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr1_r;
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr1_g;
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr1_b;
- }
- else
- {
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr2_r;
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr2_g;
- mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr2_b;
- };
- };
- };
- };
- };
-
- time(&mLastUpdateTime);
- };
-
- memcpy(mPixels, mBackgroundPixels, mWidth * mHeight * mDepth);
-
- for (int n = 0; n < ENumObjects; ++n)
- {
- if (rand() % 50 == 0)
- {
- mXInc[n] = 0;
- while (mXInc[n] == 0)
- mXInc[n] = rand() % 7 - 3;
-
- mYInc[n] = 0;
- while (mYInc[n] == 0)
- mYInc[n] = rand() % 9 - 4;
- };
-
- if (mXpos[n] + mXInc[n] < 0 || mXpos[n] + mXInc[n] >= mWidth - mBlockSize[n])
- mXInc[n] = -mXInc[n];
-
- if (mYpos[n] + mYInc[n] < 0 || mYpos[n] + mYInc[n] >= mHeight - mBlockSize[n])
- mYInc[n] = -mYInc[n];
-
- mXpos[n] += mXInc[n];
- mYpos[n] += mYInc[n];
-
- for (int y = 0; y < mBlockSize[n]; ++y)
- {
- for (int x = 0; x < mBlockSize[n]; ++x)
- {
- mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 0] = mColorR[n];
- mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 1] = mColorG[n];
- mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 2] = mColorB[n];
- };
- };
- };
-
- setDirty(0, 0, mWidth, mHeight);
+ if (mWidth < 1 || mWidth > 2048 || mHeight < 1 || mHeight > 2048)
+ return;
+
+ if (mPixels == 0)
+ return;
+
+ if (mFirstTime)
+ {
+ for (int n = 0; n < ENumObjects; ++n)
+ {
+ mXpos[n] = (mWidth / 2) + rand() % (mWidth / 16) - (mWidth / 32);
+ mYpos[n] = (mHeight / 2) + rand() % (mHeight / 16) - (mHeight / 32);
+
+ mColorR[n] = rand() % 0x60 + 0x60;
+ mColorG[n] = rand() % 0x60 + 0x60;
+ mColorB[n] = rand() % 0x60 + 0x60;
+
+ mXInc[n] = 0;
+ while (mXInc[n] == 0)
+ mXInc[n] = rand() % 7 - 3;
+
+ mYInc[n] = 0;
+ while (mYInc[n] == 0)
+ mYInc[n] = rand() % 9 - 4;
+
+ mBlockSize[n] = rand() % 0x30 + 0x10;
+ };
+
+ delete[] mBackgroundPixels;
+
+ mBackgroundPixels = new unsigned char[mWidth * mHeight * mDepth];
+
+ mFirstTime = false;
+ };
+
+ if (time(NULL) > mLastUpdateTime + 3)
+ {
+ const int num_squares = rand() % 20 + 4;
+ int sqr1_r = rand() % 0x80 + 0x20;
+ int sqr1_g = rand() % 0x80 + 0x20;
+ int sqr1_b = rand() % 0x80 + 0x20;
+ int sqr2_r = rand() % 0x80 + 0x20;
+ int sqr2_g = rand() % 0x80 + 0x20;
+ int sqr2_b = rand() % 0x80 + 0x20;
+
+ for (int y1 = 0; y1 < num_squares; ++y1)
+ {
+ for (int x1 = 0; x1 < num_squares; ++x1)
+ {
+ int px_start = mWidth * x1 / num_squares;
+ int px_end = (mWidth * (x1 + 1)) / num_squares;
+ int py_start = mHeight * y1 / num_squares;
+ int py_end = (mHeight * (y1 + 1)) / num_squares;
+
+ for (int y2 = py_start; y2 < py_end; ++y2)
+ {
+ for (int x2 = px_start; x2 < px_end; ++x2)
+ {
+ int rowspan = mWidth * mDepth;
+
+ if ((y1 % 2) ^ (x1 % 2))
+ {
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr1_r;
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr1_g;
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr1_b;
+ }
+ else
+ {
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 0] = sqr2_r;
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 1] = sqr2_g;
+ mBackgroundPixels[y2 * rowspan + x2 * mDepth + 2] = sqr2_b;
+ };
+ };
+ };
+ };
+ };
+
+ time(&mLastUpdateTime);
+ };
+
+ memcpy(mPixels, mBackgroundPixels, mWidth * mHeight * mDepth);
+
+ for (int n = 0; n < ENumObjects; ++n)
+ {
+ if (rand() % 50 == 0)
+ {
+ mXInc[n] = 0;
+ while (mXInc[n] == 0)
+ mXInc[n] = rand() % 7 - 3;
+
+ mYInc[n] = 0;
+ while (mYInc[n] == 0)
+ mYInc[n] = rand() % 9 - 4;
+ };
+
+ if (mXpos[n] + mXInc[n] < 0 || mXpos[n] + mXInc[n] >= mWidth - mBlockSize[n])
+ mXInc[n] = -mXInc[n];
+
+ if (mYpos[n] + mYInc[n] < 0 || mYpos[n] + mYInc[n] >= mHeight - mBlockSize[n])
+ mYInc[n] = -mYInc[n];
+
+ mXpos[n] += mXInc[n];
+ mYpos[n] += mYInc[n];
+
+ for (int y = 0; y < mBlockSize[n]; ++y)
+ {
+ for (int x = 0; x < mBlockSize[n]; ++x)
+ {
+ mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 0] = mColorR[n];
+ mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 1] = mColorG[n];
+ mPixels[(mXpos[n] + x) * mDepth + (mYpos[n] + y) * mDepth * mWidth + 2] = mColorB[n];
+ };
+ };
+ };
+
+ setDirty(0, 0, mWidth, mHeight);
};
////////////////////////////////////////////////////////////////////////////////
//
bool mediaPluginExample::init()
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", "Example Plugin");
- sendMessage(message);
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", "Example Plugin");
+ sendMessage(message);
- return true;
+ return true;
};
////////////////////////////////////////////////////////////////////////////////
//
int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
- void* host_user_data,
- LLPluginInstance::sendMessageFunction *plugin_send_func,
- void **plugin_user_data)
+ void* host_user_data,
+ LLPluginInstance::sendMessageFunction *plugin_send_func,
+ void **plugin_user_data)
{
- mediaPluginExample* self = new mediaPluginExample(host_send_func, host_user_data);
- *plugin_send_func = mediaPluginExample::staticReceiveMessage;
- *plugin_user_data = (void*)self;
+ mediaPluginExample* self = new mediaPluginExample(host_send_func, host_user_data);
+ *plugin_send_func = mediaPluginExample::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
- return 0;
+ return 0;
}
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
index 6bc272c009..cae11a5cb3 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file llmediaimplgstreamer.h
* @author Tofu Linden
* @brief implementation that supports media playback via GStreamer.
@@ -7,21 +7,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -44,8 +44,8 @@ extern "C" {
extern "C" {
gboolean llmediaimplgstreamer_bus_callback (GstBus *bus,
- GstMessage *message,
- gpointer data);
+ GstMessage *message,
+ gpointer data);
}
#endif // LL_GSTREAMER010_ENABLED
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
index 2e4baaa9eb..dcc04b37e4 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file llmediaimplgstreamer_syms.cpp
* @brief dynamic GStreamer symbol-grabbing code
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -48,8 +48,8 @@ extern "C" {
GstDebugCategory*
ll_gst_debug_category_new(gchar *name, guint color, gchar *description)
{
- static GstDebugCategory dummy;
- return &dummy;
+ static GstDebugCategory dummy;
+ return &dummy;
}
void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
{
@@ -62,105 +62,105 @@ static apr_dso_handle_t *sSymGSTDSOHandleV = NULL;
bool grab_gst_syms(std::string gst_dso_name,
- std::string gst_dso_name_vid)
+ std::string gst_dso_name_vid)
{
- if (sSymsGrabbed)
- {
- // already have grabbed good syms
- return TRUE;
- }
+ if (sSymsGrabbed)
+ {
+ // already have grabbed good syms
+ return TRUE;
+ }
- bool sym_error = false;
- bool rtn = false;
- apr_status_t rv;
- apr_dso_handle_t *sSymGSTDSOHandle = NULL;
+ bool sym_error = false;
+ bool rtn = false;
+ apr_status_t rv;
+ apr_dso_handle_t *sSymGSTDSOHandle = NULL;
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)
- //attempt to load the shared libraries
- apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
-
- if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
- gst_dso_name.c_str(),
- sSymGSTDSOMemoryPool) ))
- {
- INFOMSG("Found DSO: %s", gst_dso_name.c_str());
+ //attempt to load the shared libraries
+ apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
+
+ if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
+ gst_dso_name.c_str(),
+ sSymGSTDSOMemoryPool) ))
+ {
+ INFOMSG("Found DSO: %s", gst_dso_name.c_str());
#include "llmediaimplgstreamer_syms_raw.inc"
-
- if ( sSymGSTDSOHandle )
- {
- sSymGSTDSOHandleG = sSymGSTDSOHandle;
- sSymGSTDSOHandle = NULL;
- }
-
- if ( APR_SUCCESS ==
- (rv = apr_dso_load(&sSymGSTDSOHandle,
- gst_dso_name_vid.c_str(),
- sSymGSTDSOMemoryPool) ))
- {
- INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
+
+ if ( sSymGSTDSOHandle )
+ {
+ sSymGSTDSOHandleG = sSymGSTDSOHandle;
+ sSymGSTDSOHandle = NULL;
+ }
+
+ if ( APR_SUCCESS ==
+ (rv = apr_dso_load(&sSymGSTDSOHandle,
+ gst_dso_name_vid.c_str(),
+ sSymGSTDSOMemoryPool) ))
+ {
+ INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
#include "llmediaimplgstreamer_syms_rawv.inc"
- rtn = !sym_error;
- }
- else
- {
- INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str());
- rtn = false; // failure
- }
- }
- else
- {
- INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str());
- rtn = false; // failure
- }
-
- if (sym_error)
- {
- WARNMSG("Failed to find necessary symbols in GStreamer libraries.");
- }
-
- if ( sSymGSTDSOHandle )
- {
- sSymGSTDSOHandleV = sSymGSTDSOHandle;
- sSymGSTDSOHandle = NULL;
- }
+ rtn = !sym_error;
+ }
+ else
+ {
+ INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str());
+ rtn = false; // failure
+ }
+ }
+ else
+ {
+ INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str());
+ rtn = false; // failure
+ }
+
+ if (sym_error)
+ {
+ WARNMSG("Failed to find necessary symbols in GStreamer libraries.");
+ }
+
+ if ( sSymGSTDSOHandle )
+ {
+ sSymGSTDSOHandleV = sSymGSTDSOHandle;
+ sSymGSTDSOHandle = NULL;
+ }
#undef LL_GST_SYM
- sSymsGrabbed = !!rtn;
- return rtn;
+ sSymsGrabbed = !!rtn;
+ return rtn;
}
void ungrab_gst_syms()
-{
- // should be safe to call regardless of whether we've
- // actually grabbed syms.
-
- if ( sSymGSTDSOHandleG )
- {
- apr_dso_unload(sSymGSTDSOHandleG);
- sSymGSTDSOHandleG = NULL;
- }
-
- if ( sSymGSTDSOHandleV )
- {
- apr_dso_unload(sSymGSTDSOHandleV);
- sSymGSTDSOHandleV = NULL;
- }
-
- if ( sSymGSTDSOMemoryPool )
- {
- apr_pool_destroy(sSymGSTDSOMemoryPool);
- sSymGSTDSOMemoryPool = NULL;
- }
-
- // NULL-out all of the symbols we'd grabbed
+{
+ // should be safe to call regardless of whether we've
+ // actually grabbed syms.
+
+ if ( sSymGSTDSOHandleG )
+ {
+ apr_dso_unload(sSymGSTDSOHandleG);
+ sSymGSTDSOHandleG = NULL;
+ }
+
+ if ( sSymGSTDSOHandleV )
+ {
+ apr_dso_unload(sSymGSTDSOHandleV);
+ sSymGSTDSOHandleV = NULL;
+ }
+
+ if ( sSymGSTDSOMemoryPool )
+ {
+ apr_pool_destroy(sSymGSTDSOMemoryPool);
+ sSymGSTDSOMemoryPool = NULL;
+ }
+
+ // NULL-out all of the symbols we'd grabbed
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0)
#include "llmediaimplgstreamer_syms_raw.inc"
#include "llmediaimplgstreamer_syms_rawv.inc"
#undef LL_GST_SYM
- sSymsGrabbed = false;
+ sSymsGrabbed = false;
}
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h
index d1559089c8..57d446c7df 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file llmediaimplgstreamer_syms.h
* @brief dynamic GStreamer symbol-grabbing code
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -35,7 +35,7 @@ extern "C" {
}
bool grab_gst_syms(std::string gst_dso_name,
- std::string gst_dso_name_vid);
+ std::string gst_dso_name_vid);
void ungrab_gst_syms();
#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__)
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h
index e7b31bec94..43ebad6744 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp
index 932aaffa1b..acec0f2399 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -58,139 +58,139 @@ GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink,
GST_TYPE_VIDEO_SINK);
static void gst_slvideo_set_property (GObject * object, guint prop_id,
- const GValue * value,
- GParamSpec * pspec);
+ const GValue * value,
+ GParamSpec * pspec);
static void gst_slvideo_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
+ GValue * value, GParamSpec * pspec);
static void
gst_slvideo_base_init (gpointer gclass)
{
- static GstElementDetails element_details = {
- (gchar*)"PluginTemplate",
- (gchar*)"Generic/PluginTemplate",
- (gchar*)"Generic Template Element",
- (gchar*)"Linden Lab"
- };
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- llgst_element_class_add_pad_template (element_class,
- llgst_static_pad_template_get (&sink_factory));
- llgst_element_class_set_details (element_class, &element_details);
+ static GstElementDetails element_details = {
+ (gchar*)"PluginTemplate",
+ (gchar*)"Generic/PluginTemplate",
+ (gchar*)"Generic Template Element",
+ (gchar*)"Linden Lab"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+ llgst_element_class_add_pad_template (element_class,
+ llgst_static_pad_template_get (&sink_factory));
+ llgst_element_class_set_details (element_class, &element_details);
}
static void
gst_slvideo_finalize (GObject * object)
{
- GstSLVideo *slvideo;
- slvideo = GST_SLVIDEO (object);
- if (slvideo->caps)
- {
- llgst_caps_unref(slvideo->caps);
- }
-
- G_OBJECT_CLASS(parent_class)->finalize (object);
+ GstSLVideo *slvideo;
+ slvideo = GST_SLVIDEO (object);
+ if (slvideo->caps)
+ {
+ llgst_caps_unref(slvideo->caps);
+ }
+
+ G_OBJECT_CLASS(parent_class)->finalize (object);
}
static GstFlowReturn
gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
- GstSLVideo *slvideo;
- llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
-
- slvideo = GST_SLVIDEO(bsink);
-
- DEBUGMSG("transferring a frame of %dx%d <- %p (%d)",
- slvideo->width, slvideo->height, GST_BUFFER_DATA(buf),
- slvideo->format);
-
- if (GST_BUFFER_DATA(buf))
- {
- // copy frame and frame info into neutral territory
- GST_OBJECT_LOCK(slvideo);
- slvideo->retained_frame_ready = TRUE;
- slvideo->retained_frame_width = slvideo->width;
- slvideo->retained_frame_height = slvideo->height;
- slvideo->retained_frame_format = slvideo->format;
- int rowbytes =
- SLVPixelFormatBytes[slvideo->retained_frame_format] *
- slvideo->retained_frame_width;
- int needbytes = rowbytes * slvideo->retained_frame_width;
- // resize retained frame hunk only if necessary
- if (needbytes != slvideo->retained_frame_allocbytes)
- {
- delete[] slvideo->retained_frame_data;
- slvideo->retained_frame_data = new unsigned char[needbytes];
- slvideo->retained_frame_allocbytes = needbytes;
-
- }
- // copy the actual frame data to neutral territory -
- // flipped, for GL reasons
- for (int ypos=0; ypos<slvideo->height; ++ypos)
- {
- memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes],
- &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]),
- rowbytes);
- }
- // done with the shared data
- GST_OBJECT_UNLOCK(slvideo);
- }
-
- return GST_FLOW_OK;
+ GstSLVideo *slvideo;
+ llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+
+ slvideo = GST_SLVIDEO(bsink);
+
+ DEBUGMSG("transferring a frame of %dx%d <- %p (%d)",
+ slvideo->width, slvideo->height, GST_BUFFER_DATA(buf),
+ slvideo->format);
+
+ if (GST_BUFFER_DATA(buf))
+ {
+ // copy frame and frame info into neutral territory
+ GST_OBJECT_LOCK(slvideo);
+ slvideo->retained_frame_ready = TRUE;
+ slvideo->retained_frame_width = slvideo->width;
+ slvideo->retained_frame_height = slvideo->height;
+ slvideo->retained_frame_format = slvideo->format;
+ int rowbytes =
+ SLVPixelFormatBytes[slvideo->retained_frame_format] *
+ slvideo->retained_frame_width;
+ int needbytes = rowbytes * slvideo->retained_frame_width;
+ // resize retained frame hunk only if necessary
+ if (needbytes != slvideo->retained_frame_allocbytes)
+ {
+ delete[] slvideo->retained_frame_data;
+ slvideo->retained_frame_data = new unsigned char[needbytes];
+ slvideo->retained_frame_allocbytes = needbytes;
+
+ }
+ // copy the actual frame data to neutral territory -
+ // flipped, for GL reasons
+ for (int ypos=0; ypos<slvideo->height; ++ypos)
+ {
+ memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes],
+ &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]),
+ rowbytes);
+ }
+ // done with the shared data
+ GST_OBJECT_UNLOCK(slvideo);
+ }
+
+ return GST_FLOW_OK;
}
static GstStateChangeReturn
gst_slvideo_change_state(GstElement * element, GstStateChange transition)
{
- GstSLVideo *slvideo;
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
-
- slvideo = GST_SLVIDEO (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- slvideo->fps_n = 0;
- slvideo->fps_d = 1;
- GST_VIDEO_SINK_WIDTH(slvideo) = 0;
- GST_VIDEO_SINK_HEIGHT(slvideo) = 0;
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return ret;
+ GstSLVideo *slvideo;
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ slvideo = GST_SLVIDEO (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ slvideo->fps_n = 0;
+ slvideo->fps_d = 1;
+ GST_VIDEO_SINK_WIDTH(slvideo) = 0;
+ GST_VIDEO_SINK_HEIGHT(slvideo) = 0;
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
}
static GstCaps *
gst_slvideo_get_caps (GstBaseSink * bsink)
{
- GstSLVideo *slvideo;
- slvideo = GST_SLVIDEO(bsink);
-
- return llgst_caps_ref (slvideo->caps);
+ GstSLVideo *slvideo;
+ slvideo = GST_SLVIDEO(bsink);
+
+ return llgst_caps_ref (slvideo->caps);
}
@@ -198,199 +198,199 @@ gst_slvideo_get_caps (GstBaseSink * bsink)
static gboolean
gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
- GstSLVideo *filter;
- GstStructure *structure;
-
- GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
-
- filter = GST_SLVIDEO(bsink);
-
- int width, height;
- gboolean ret;
- const GValue *fps;
- const GValue *par;
- structure = llgst_caps_get_structure (caps, 0);
- ret = llgst_structure_get_int (structure, "width", &width);
- ret = ret && llgst_structure_get_int (structure, "height", &height);
- fps = llgst_structure_get_value (structure, "framerate");
- ret = ret && (fps != NULL);
- par = llgst_structure_get_value (structure, "pixel-aspect-ratio");
- if (!ret)
- return FALSE;
-
- INFOMSG("** filter caps set with width=%d, height=%d", width, height);
-
- GST_OBJECT_LOCK(filter);
-
- filter->width = width;
- filter->height = height;
-
- filter->fps_n = llgst_value_get_fraction_numerator(fps);
- filter->fps_d = llgst_value_get_fraction_denominator(fps);
- if (par)
- {
- filter->par_n = llgst_value_get_fraction_numerator(par);
- filter->par_d = llgst_value_get_fraction_denominator(par);
- }
- else
- {
- filter->par_n = 1;
- filter->par_d = 1;
- }
- GST_VIDEO_SINK_WIDTH(filter) = width;
- GST_VIDEO_SINK_HEIGHT(filter) = height;
-
- // crufty lump - we *always* accept *only* RGBX now.
- /*
- filter->format = SLV_PF_UNKNOWN;
- if (0 == strcmp(llgst_structure_get_name(structure),
- "video/x-raw-rgb"))
- {
- int red_mask;
- int green_mask;
- int blue_mask;
- llgst_structure_get_int(structure, "red_mask", &red_mask);
- llgst_structure_get_int(structure, "green_mask", &green_mask);
- llgst_structure_get_int(structure, "blue_mask", &blue_mask);
- if ((unsigned int)red_mask == 0xFF000000 &&
- (unsigned int)green_mask == 0x00FF0000 &&
- (unsigned int)blue_mask == 0x0000FF00)
- {
- filter->format = SLV_PF_RGBX;
- //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n");
- } else if ((unsigned int)red_mask == 0x0000FF00 &&
- (unsigned int)green_mask == 0x00FF0000 &&
- (unsigned int)blue_mask == 0xFF000000)
- {
- filter->format = SLV_PF_BGRX;
- //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n");
- }
- }*/
-
- filter->format = SLV_PF_RGBX;
-
- GST_OBJECT_UNLOCK(filter);
-
- return TRUE;
+ GstSLVideo *filter;
+ GstStructure *structure;
+
+ GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
+
+ filter = GST_SLVIDEO(bsink);
+
+ int width, height;
+ gboolean ret;
+ const GValue *fps;
+ const GValue *par;
+ structure = llgst_caps_get_structure (caps, 0);
+ ret = llgst_structure_get_int (structure, "width", &width);
+ ret = ret && llgst_structure_get_int (structure, "height", &height);
+ fps = llgst_structure_get_value (structure, "framerate");
+ ret = ret && (fps != NULL);
+ par = llgst_structure_get_value (structure, "pixel-aspect-ratio");
+ if (!ret)
+ return FALSE;
+
+ INFOMSG("** filter caps set with width=%d, height=%d", width, height);
+
+ GST_OBJECT_LOCK(filter);
+
+ filter->width = width;
+ filter->height = height;
+
+ filter->fps_n = llgst_value_get_fraction_numerator(fps);
+ filter->fps_d = llgst_value_get_fraction_denominator(fps);
+ if (par)
+ {
+ filter->par_n = llgst_value_get_fraction_numerator(par);
+ filter->par_d = llgst_value_get_fraction_denominator(par);
+ }
+ else
+ {
+ filter->par_n = 1;
+ filter->par_d = 1;
+ }
+ GST_VIDEO_SINK_WIDTH(filter) = width;
+ GST_VIDEO_SINK_HEIGHT(filter) = height;
+
+ // crufty lump - we *always* accept *only* RGBX now.
+ /*
+ filter->format = SLV_PF_UNKNOWN;
+ if (0 == strcmp(llgst_structure_get_name(structure),
+ "video/x-raw-rgb"))
+ {
+ int red_mask;
+ int green_mask;
+ int blue_mask;
+ llgst_structure_get_int(structure, "red_mask", &red_mask);
+ llgst_structure_get_int(structure, "green_mask", &green_mask);
+ llgst_structure_get_int(structure, "blue_mask", &blue_mask);
+ if ((unsigned int)red_mask == 0xFF000000 &&
+ (unsigned int)green_mask == 0x00FF0000 &&
+ (unsigned int)blue_mask == 0x0000FF00)
+ {
+ filter->format = SLV_PF_RGBX;
+ //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n");
+ } else if ((unsigned int)red_mask == 0x0000FF00 &&
+ (unsigned int)green_mask == 0x00FF0000 &&
+ (unsigned int)blue_mask == 0xFF000000)
+ {
+ filter->format = SLV_PF_BGRX;
+ //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n");
+ }
+ }*/
+
+ filter->format = SLV_PF_RGBX;
+
+ GST_OBJECT_UNLOCK(filter);
+
+ return TRUE;
}
static gboolean
gst_slvideo_start (GstBaseSink * bsink)
{
- gboolean ret = TRUE;
-
- GST_SLVIDEO(bsink);
+ gboolean ret = TRUE;
+
+ GST_SLVIDEO(bsink);
- return ret;
+ return ret;
}
static gboolean
gst_slvideo_stop (GstBaseSink * bsink)
{
- GstSLVideo *slvideo;
- slvideo = GST_SLVIDEO(bsink);
-
- // free-up retained frame buffer
- GST_OBJECT_LOCK(slvideo);
- slvideo->retained_frame_ready = FALSE;
- delete[] slvideo->retained_frame_data;
- slvideo->retained_frame_data = NULL;
- slvideo->retained_frame_allocbytes = 0;
- GST_OBJECT_UNLOCK(slvideo);
-
- return TRUE;
+ GstSLVideo *slvideo;
+ slvideo = GST_SLVIDEO(bsink);
+
+ // free-up retained frame buffer
+ GST_OBJECT_LOCK(slvideo);
+ slvideo->retained_frame_ready = FALSE;
+ delete[] slvideo->retained_frame_data;
+ slvideo->retained_frame_data = NULL;
+ slvideo->retained_frame_allocbytes = 0;
+ GST_OBJECT_UNLOCK(slvideo);
+
+ return TRUE;
}
static GstFlowReturn
gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
+ GstCaps * caps, GstBuffer ** buf)
{
- gint width, height;
- GstStructure *structure = NULL;
- GstSLVideo *slvideo;
- slvideo = GST_SLVIDEO(bsink);
-
- // caps == requested caps
- // we can ignore these and reverse-negotiate our preferred dimensions with
- // the peer if we like - we need to do this to obey dynamic resize requests
- // flowing in from the app.
- structure = llgst_caps_get_structure (caps, 0);
- if (!llgst_structure_get_int(structure, "width", &width) ||
- !llgst_structure_get_int(structure, "height", &height))
- {
- GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps);
- return GST_FLOW_NOT_NEGOTIATED;
- }
-
- GstBuffer *newbuf = llgst_buffer_new();
- bool made_bufferdata_ptr = false;
+ gint width, height;
+ GstStructure *structure = NULL;
+ GstSLVideo *slvideo;
+ slvideo = GST_SLVIDEO(bsink);
+
+ // caps == requested caps
+ // we can ignore these and reverse-negotiate our preferred dimensions with
+ // the peer if we like - we need to do this to obey dynamic resize requests
+ // flowing in from the app.
+ structure = llgst_caps_get_structure (caps, 0);
+ if (!llgst_structure_get_int(structure, "width", &width) ||
+ !llgst_structure_get_int(structure, "height", &height))
+ {
+ GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps);
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+
+ GstBuffer *newbuf = llgst_buffer_new();
+ bool made_bufferdata_ptr = false;
#define MAXDEPTHHACK 4
-
- GST_OBJECT_LOCK(slvideo);
- if (slvideo->resize_forced_always) // app is giving us a fixed size to work with
- {
- gint slwantwidth, slwantheight;
- slwantwidth = slvideo->resize_try_width;
- slwantheight = slvideo->resize_try_height;
-
- if (slwantwidth != width ||
- slwantheight != height)
- {
- // don't like requested caps, we will issue our own suggestion - copy
- // the requested caps but substitute our own width and height and see
- // if our peer is happy with that.
-
- GstCaps *desired_caps;
- GstStructure *desired_struct;
- desired_caps = llgst_caps_copy (caps);
- desired_struct = llgst_caps_get_structure (desired_caps, 0);
-
- GValue value = {0};
- g_value_init(&value, G_TYPE_INT);
- g_value_set_int(&value, slwantwidth);
- llgst_structure_set_value (desired_struct, "width", &value);
- g_value_unset(&value);
- g_value_init(&value, G_TYPE_INT);
- g_value_set_int(&value, slwantheight);
- llgst_structure_set_value (desired_struct, "height", &value);
-
- if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo),
- desired_caps))
- {
- // todo: re-use buffers from a pool?
- // todo: set MALLOCDATA to null, set DATA to point straight to shm?
-
- // peer likes our cap suggestion
- DEBUGMSG("peer loves us :)");
- GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK;
- GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
- GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
- llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps);
-
- made_bufferdata_ptr = true;
- } else {
- // peer hates our cap suggestion
- INFOMSG("peer hates us :(");
- llgst_caps_unref(desired_caps);
- }
- }
- }
-
- GST_OBJECT_UNLOCK(slvideo);
-
- if (!made_bufferdata_ptr) // need to fallback to malloc at original size
- {
- GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK;
- GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
- GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
- llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps);
- }
-
- *buf = GST_BUFFER_CAST(newbuf);
-
- return GST_FLOW_OK;
+
+ GST_OBJECT_LOCK(slvideo);
+ if (slvideo->resize_forced_always) // app is giving us a fixed size to work with
+ {
+ gint slwantwidth, slwantheight;
+ slwantwidth = slvideo->resize_try_width;
+ slwantheight = slvideo->resize_try_height;
+
+ if (slwantwidth != width ||
+ slwantheight != height)
+ {
+ // don't like requested caps, we will issue our own suggestion - copy
+ // the requested caps but substitute our own width and height and see
+ // if our peer is happy with that.
+
+ GstCaps *desired_caps;
+ GstStructure *desired_struct;
+ desired_caps = llgst_caps_copy (caps);
+ desired_struct = llgst_caps_get_structure (desired_caps, 0);
+
+ GValue value = {0};
+ g_value_init(&value, G_TYPE_INT);
+ g_value_set_int(&value, slwantwidth);
+ llgst_structure_set_value (desired_struct, "width", &value);
+ g_value_unset(&value);
+ g_value_init(&value, G_TYPE_INT);
+ g_value_set_int(&value, slwantheight);
+ llgst_structure_set_value (desired_struct, "height", &value);
+
+ if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo),
+ desired_caps))
+ {
+ // todo: re-use buffers from a pool?
+ // todo: set MALLOCDATA to null, set DATA to point straight to shm?
+
+ // peer likes our cap suggestion
+ DEBUGMSG("peer loves us :)");
+ GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK;
+ GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
+ GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
+ llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps);
+
+ made_bufferdata_ptr = true;
+ } else {
+ // peer hates our cap suggestion
+ INFOMSG("peer hates us :(");
+ llgst_caps_unref(desired_caps);
+ }
+ }
+ }
+
+ GST_OBJECT_UNLOCK(slvideo);
+
+ if (!made_bufferdata_ptr) // need to fallback to malloc at original size
+ {
+ GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK;
+ GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf));
+ GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf);
+ llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps);
+ }
+
+ *buf = GST_BUFFER_CAST(newbuf);
+
+ return GST_FLOW_OK;
}
@@ -398,32 +398,32 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
static void
gst_slvideo_class_init (GstSLVideoClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
- GstBaseSinkClass *gstbasesink_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
- gstbasesink_class = (GstBaseSinkClass *) klass;
-
- gobject_class->finalize = gst_slvideo_finalize;
- gobject_class->set_property = gst_slvideo_set_property;
- gobject_class->get_property = gst_slvideo_get_property;
-
- gstelement_class->change_state = gst_slvideo_change_state;
-
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+
+ gobject_class->finalize = gst_slvideo_finalize;
+ gobject_class->set_property = gst_slvideo_set_property;
+ gobject_class->get_property = gst_slvideo_get_property;
+
+ gstelement_class->change_state = gst_slvideo_change_state;
+
#define LLGST_DEBUG_FUNCPTR(p) (p)
- gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps);
- gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps);
- gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc);
- //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times);
- gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
- gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
-
- gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start);
- gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop);
-
- // gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock);
+ gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps);
+ gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps);
+ gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc);
+ //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times);
+ gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
+ gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
+
+ gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start);
+ gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop);
+
+ // gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock);
#undef LLGST_DEBUG_FUNCPTR
}
@@ -435,52 +435,52 @@ gst_slvideo_class_init (GstSLVideoClass * klass)
*/
static void
gst_slvideo_init (GstSLVideo * filter,
- GstSLVideoClass * gclass)
+ GstSLVideoClass * gclass)
{
- filter->caps = NULL;
- filter->width = -1;
- filter->height = -1;
-
- // this is the info we share with the client app
- GST_OBJECT_LOCK(filter);
- filter->retained_frame_ready = FALSE;
- filter->retained_frame_data = NULL;
- filter->retained_frame_allocbytes = 0;
- filter->retained_frame_width = filter->width;
- filter->retained_frame_height = filter->height;
- filter->retained_frame_format = SLV_PF_UNKNOWN;
- GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS);
- llgst_caps_replace (&filter->caps, caps);
- filter->resize_forced_always = false;
- filter->resize_try_width = -1;
- filter->resize_try_height = -1;
- GST_OBJECT_UNLOCK(filter);
+ filter->caps = NULL;
+ filter->width = -1;
+ filter->height = -1;
+
+ // this is the info we share with the client app
+ GST_OBJECT_LOCK(filter);
+ filter->retained_frame_ready = FALSE;
+ filter->retained_frame_data = NULL;
+ filter->retained_frame_allocbytes = 0;
+ filter->retained_frame_width = filter->width;
+ filter->retained_frame_height = filter->height;
+ filter->retained_frame_format = SLV_PF_UNKNOWN;
+ GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS);
+ llgst_caps_replace (&filter->caps, caps);
+ filter->resize_forced_always = false;
+ filter->resize_try_width = -1;
+ filter->resize_try_height = -1;
+ GST_OBJECT_UNLOCK(filter);
}
static void
gst_slvideo_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
+ const GValue * value, GParamSpec * pspec)
{
- llg_return_if_fail (GST_IS_SLVIDEO (object));
-
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ llg_return_if_fail (GST_IS_SLVIDEO (object));
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
gst_slvideo_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
+ GValue * value, GParamSpec * pspec)
{
- llg_return_if_fail (GST_IS_SLVIDEO (object));
+ llg_return_if_fail (GST_IS_SLVIDEO (object));
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
@@ -492,13 +492,13 @@ gst_slvideo_get_property (GObject * object, guint prop_id,
static gboolean
plugin_init (GstPlugin * plugin)
{
- DEBUGMSG("PLUGIN INIT");
+ DEBUGMSG("PLUGIN INIT");
- GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin",
- 0, (gchar*)"Second Life Video Sink");
+ GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin",
+ 0, (gchar*)"Second Life Video Sink");
- return llgst_element_register (plugin, "private-slvideo",
- GST_RANK_NONE, GST_TYPE_SLVIDEO);
+ return llgst_element_register (plugin, "private-slvideo",
+ GST_RANK_NONE, GST_TYPE_SLVIDEO);
}
/* this is the structure that gstreamer looks for to register plugins
@@ -510,17 +510,17 @@ plugin_init (GstPlugin * plugin)
#define PACKAGE (gchar*)"packagehack"
// this macro quietly refers to PACKAGE internally
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- (gchar*)"private-slvideoplugin",
- (gchar*)"SL Video sink plugin",
- plugin_init, (gchar*)"1.0", (gchar*)"LGPL",
- (gchar*)"Second Life",
- (gchar*)"http://www.secondlife.com/");
+ GST_VERSION_MINOR,
+ (gchar*)"private-slvideoplugin",
+ (gchar*)"SL Video sink plugin",
+ plugin_init, (gchar*)"1.0", (gchar*)"LGPL",
+ (gchar*)"Second Life",
+ (gchar*)"http://www.secondlife.com/");
#undef PACKAGE
void gst_slvideo_init_class (void)
{
- ll_gst_plugin_register_static (&gst_plugin_desc);
- DEBUGMSG("CLASS INIT");
+ ll_gst_plugin_register_static (&gst_plugin_desc);
+ DEBUGMSG("CLASS INIT");
}
#endif // LL_GSTREAMER010_ENABLED
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h
index 29d65fa4e9..d4e07daf4f 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -55,43 +55,43 @@ typedef struct _GstSLVideo GstSLVideo;
typedef struct _GstSLVideoClass GstSLVideoClass;
typedef enum {
- SLV_PF_UNKNOWN = 0,
- SLV_PF_RGBX = 1,
- SLV_PF_BGRX = 2,
- SLV__END = 3
+ SLV_PF_UNKNOWN = 0,
+ SLV_PF_RGBX = 1,
+ SLV_PF_BGRX = 2,
+ SLV__END = 3
} SLVPixelFormat;
const int SLVPixelFormatBytes[SLV__END] = {1, 4, 4};
struct _GstSLVideo
{
- GstVideoSink video_sink;
-
- GstCaps *caps;
-
- int fps_n, fps_d;
- int par_n, par_d;
- int height, width;
- SLVPixelFormat format;
-
- // SHARED WITH APPLICATION:
- // Access to the following should be protected by GST_OBJECT_LOCK() on
- // the GstSLVideo object, and should be totally consistent upon UNLOCK
- // (i.e. all written at once to reflect the current retained frame info
- // when the retained frame is updated.)
- bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.)
- unsigned char* retained_frame_data;
- int retained_frame_allocbytes;
- int retained_frame_width, retained_frame_height;
- SLVPixelFormat retained_frame_format;
- // sticky resize info
- bool resize_forced_always;
- int resize_try_width;
- int resize_try_height;
+ GstVideoSink video_sink;
+
+ GstCaps *caps;
+
+ int fps_n, fps_d;
+ int par_n, par_d;
+ int height, width;
+ SLVPixelFormat format;
+
+ // SHARED WITH APPLICATION:
+ // Access to the following should be protected by GST_OBJECT_LOCK() on
+ // the GstSLVideo object, and should be totally consistent upon UNLOCK
+ // (i.e. all written at once to reflect the current retained frame info
+ // when the retained frame is updated.)
+ bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.)
+ unsigned char* retained_frame_data;
+ int retained_frame_allocbytes;
+ int retained_frame_width, retained_frame_height;
+ SLVPixelFormat retained_frame_format;
+ // sticky resize info
+ bool resize_forced_always;
+ int resize_try_width;
+ int resize_try_height;
};
-struct _GstSLVideoClass
+struct _GstSLVideoClass
{
- GstVideoSinkClass parent_class;
+ GstVideoSinkClass parent_class;
};
GType gst_slvideo_get_type (void);
diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
index 352b63583e..97d1d7d7b5 100644
--- a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
+++ b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file media_plugin_gstreamer010.cpp
* @brief GStreamer-0.10 plugin for LLMedia API plugin system
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -53,114 +53,114 @@ extern "C" {
class MediaPluginGStreamer010 : public MediaPluginBase
{
public:
- MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginGStreamer010();
+ MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginGStreamer010();
- /* virtual */ void receiveMessage(const char *message_string);
+ /* virtual */ void receiveMessage(const char *message_string);
- static bool startup();
- static bool closedown();
+ static bool startup();
+ static bool closedown();
- gboolean processGSTEvents(GstBus *bus,
- GstMessage *message);
+ gboolean processGSTEvents(GstBus *bus,
+ GstMessage *message);
private:
- std::string getVersion();
- bool navigateTo( const std::string urlIn );
- bool seek( double time_sec );
- bool setVolume( float volume );
-
- // misc
- bool pause();
- bool stop();
- bool play(double rate);
- bool getTimePos(double &sec_out);
-
- static const double MIN_LOOP_SEC = 1.0F;
-
- bool mIsLooping;
-
- enum ECommand {
- COMMAND_NONE,
- COMMAND_STOP,
- COMMAND_PLAY,
- COMMAND_FAST_FORWARD,
- COMMAND_FAST_REWIND,
- COMMAND_PAUSE,
- COMMAND_SEEK,
- };
- ECommand mCommand;
+ std::string getVersion();
+ bool navigateTo( const std::string urlIn );
+ bool seek( double time_sec );
+ bool setVolume( float volume );
+
+ // misc
+ bool pause();
+ bool stop();
+ bool play(double rate);
+ bool getTimePos(double &sec_out);
+
+ static const double MIN_LOOP_SEC = 1.0F;
+
+ bool mIsLooping;
+
+ enum ECommand {
+ COMMAND_NONE,
+ COMMAND_STOP,
+ COMMAND_PLAY,
+ COMMAND_FAST_FORWARD,
+ COMMAND_FAST_REWIND,
+ COMMAND_PAUSE,
+ COMMAND_SEEK,
+ };
+ ECommand mCommand;
private:
- bool unload();
- bool load();
+ bool unload();
+ bool load();
- bool update(int milliseconds);
+ bool update(int milliseconds);
void mouseDown( int x, int y );
void mouseUp( int x, int y );
void mouseMove( int x, int y );
void sizeChanged();
-
- static bool mDoneInit;
-
- guint mBusWatchID;
-
- float mVolume;
-
- int mDepth;
-
- // media NATURAL size
- int mNaturalWidth;
- int mNaturalHeight;
- // media current size
- int mCurrentWidth;
- int mCurrentHeight;
- int mCurrentRowbytes;
- // previous media size so we can detect changes
- int mPreviousWidth;
- int mPreviousHeight;
- // desired render size from host
- int mWidth;
- int mHeight;
- // padded texture size we need to write into
- int mTextureWidth;
- int mTextureHeight;
-
- int mTextureFormatPrimary;
- int mTextureFormatType;
-
- bool mSeekWanted;
- double mSeekDestination;
-
- // Very GStreamer-specific
- GMainLoop *mPump; // event pump for this media
- GstElement *mPlaybin;
- GstElement *mVisualizer;
- GstSLVideo *mVideoSink;
+
+ static bool mDoneInit;
+
+ guint mBusWatchID;
+
+ float mVolume;
+
+ int mDepth;
+
+ // media NATURAL size
+ int mNaturalWidth;
+ int mNaturalHeight;
+ // media current size
+ int mCurrentWidth;
+ int mCurrentHeight;
+ int mCurrentRowbytes;
+ // previous media size so we can detect changes
+ int mPreviousWidth;
+ int mPreviousHeight;
+ // desired render size from host
+ int mWidth;
+ int mHeight;
+ // padded texture size we need to write into
+ int mTextureWidth;
+ int mTextureHeight;
+
+ int mTextureFormatPrimary;
+ int mTextureFormatType;
+
+ bool mSeekWanted;
+ double mSeekDestination;
+
+ // Very GStreamer-specific
+ GMainLoop *mPump; // event pump for this media
+ GstElement *mPlaybin;
+ GstElement *mVisualizer;
+ GstSLVideo *mVideoSink;
};
//static
bool MediaPluginGStreamer010::mDoneInit = false;
MediaPluginGStreamer010::MediaPluginGStreamer010(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data ) :
- MediaPluginBase(host_send_func, host_user_data),
- mBusWatchID ( 0 ),
- mCurrentRowbytes ( 4 ),
- mTextureFormatPrimary ( GL_RGBA ),
- mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ),
- mSeekWanted(false),
- mSeekDestination(0.0),
- mPump ( NULL ),
- mPlaybin ( NULL ),
- mVisualizer ( NULL ),
- mVideoSink ( NULL ),
- mCommand ( COMMAND_NONE )
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data ) :
+ MediaPluginBase(host_send_func, host_user_data),
+ mBusWatchID ( 0 ),
+ mCurrentRowbytes ( 4 ),
+ mTextureFormatPrimary ( GL_RGBA ),
+ mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ),
+ mSeekWanted(false),
+ mSeekDestination(0.0),
+ mPump ( NULL ),
+ mPlaybin ( NULL ),
+ mVisualizer ( NULL ),
+ mVideoSink ( NULL ),
+ mCommand ( COMMAND_NONE )
{
- std::ostringstream str;
- INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid()));
+ std::ostringstream str;
+ INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid()));
}
///////////////////////////////////////////////////////////////////////////////
@@ -169,188 +169,188 @@ MediaPluginGStreamer010::MediaPluginGStreamer010(
#ifdef LL_GST_REPORT_STATE_CHANGES
static char* get_gst_state_name(GstState state)
{
- switch (state) {
- case GST_STATE_VOID_PENDING: return "VOID_PENDING";
- case GST_STATE_NULL: return "NULL";
- case GST_STATE_READY: return "READY";
- case GST_STATE_PAUSED: return "PAUSED";
- case GST_STATE_PLAYING: return "PLAYING";
- }
- return "(unknown)";
+ switch (state) {
+ case GST_STATE_VOID_PENDING: return "VOID_PENDING";
+ case GST_STATE_NULL: return "NULL";
+ case GST_STATE_READY: return "READY";
+ case GST_STATE_PAUSED: return "PAUSED";
+ case GST_STATE_PLAYING: return "PLAYING";
+ }
+ return "(unknown)";
}
#endif // LL_GST_REPORT_STATE_CHANGES
gboolean
MediaPluginGStreamer010::processGSTEvents(GstBus *bus,
- GstMessage *message)
+ GstMessage *message)
{
- if (!message)
- return TRUE; // shield against GStreamer bug
-
- if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED &&
- GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING)
- {
- DEBUGMSG("Got GST message type: %s",
- LLGST_MESSAGE_TYPE_NAME (message));
- }
- else
- {
- // TODO: grok 'duration' message type
- DEBUGMSG("Got GST message type: %s",
- LLGST_MESSAGE_TYPE_NAME (message));
- }
-
- switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_BUFFERING: {
- // NEEDS GST 0.10.11+
- if (llgst_message_parse_buffering)
- {
- gint percent = 0;
- llgst_message_parse_buffering(message, &percent);
- DEBUGMSG("GST buffering: %d%%", percent);
- }
- break;
- }
- case GST_MESSAGE_STATE_CHANGED: {
- GstState old_state;
- GstState new_state;
- GstState pending_state;
- llgst_message_parse_state_changed(message,
- &old_state,
- &new_state,
- &pending_state);
+ if (!message)
+ return TRUE; // shield against GStreamer bug
+
+ if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED &&
+ GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING)
+ {
+ DEBUGMSG("Got GST message type: %s",
+ LLGST_MESSAGE_TYPE_NAME (message));
+ }
+ else
+ {
+ // TODO: grok 'duration' message type
+ DEBUGMSG("Got GST message type: %s",
+ LLGST_MESSAGE_TYPE_NAME (message));
+ }
+
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_BUFFERING: {
+ // NEEDS GST 0.10.11+
+ if (llgst_message_parse_buffering)
+ {
+ gint percent = 0;
+ llgst_message_parse_buffering(message, &percent);
+ DEBUGMSG("GST buffering: %d%%", percent);
+ }
+ break;
+ }
+ case GST_MESSAGE_STATE_CHANGED: {
+ GstState old_state;
+ GstState new_state;
+ GstState pending_state;
+ llgst_message_parse_state_changed(message,
+ &old_state,
+ &new_state,
+ &pending_state);
#ifdef LL_GST_REPORT_STATE_CHANGES
- // not generally very useful, and rather spammy.
- DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s",
- get_gst_state_name(old_state),
- get_gst_state_name(new_state),
- get_gst_state_name(pending_state));
+ // not generally very useful, and rather spammy.
+ DEBUGMSG("state change (old,<new>,pending): %s,<%s>,%s",
+ get_gst_state_name(old_state),
+ get_gst_state_name(new_state),
+ get_gst_state_name(pending_state));
#endif // LL_GST_REPORT_STATE_CHANGES
- switch (new_state) {
- case GST_STATE_VOID_PENDING:
- break;
- case GST_STATE_NULL:
- break;
- case GST_STATE_READY:
- setStatus(STATUS_LOADED);
- break;
- case GST_STATE_PAUSED:
- setStatus(STATUS_PAUSED);
- break;
- case GST_STATE_PLAYING:
- setStatus(STATUS_PLAYING);
- break;
- }
- break;
- }
- case GST_MESSAGE_ERROR: {
- GError *err = NULL;
- gchar *debug = NULL;
-
- llgst_message_parse_error (message, &err, &debug);
- WARNMSG("GST error: %s", err?err->message:"(unknown)");
- if (err)
- g_error_free (err);
- g_free (debug);
-
- mCommand = COMMAND_STOP;
-
- setStatus(STATUS_ERROR);
-
- break;
- }
- case GST_MESSAGE_INFO: {
- if (llgst_message_parse_info)
- {
- GError *err = NULL;
- gchar *debug = NULL;
-
- llgst_message_parse_info (message, &err, &debug);
- INFOMSG("GST info: %s", err?err->message:"(unknown)");
- if (err)
- g_error_free (err);
- g_free (debug);
- }
- break;
- }
- case GST_MESSAGE_WARNING: {
- GError *err = NULL;
- gchar *debug = NULL;
-
- llgst_message_parse_warning (message, &err, &debug);
- WARNMSG("GST warning: %s", err?err->message:"(unknown)");
- if (err)
- g_error_free (err);
- g_free (debug);
-
- break;
- }
- case GST_MESSAGE_EOS:
- /* end-of-stream */
- DEBUGMSG("GST end-of-stream.");
- if (mIsLooping)
- {
- DEBUGMSG("looping media...");
- double eos_pos_sec = 0.0F;
- bool got_eos_position = getTimePos(eos_pos_sec);
-
- if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC)
- {
- // if we know that the movie is really short, don't
- // loop it else it can easily become a time-hog
- // because of GStreamer spin-up overhead
- DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec);
- // inject a COMMAND_PAUSE
- mCommand = COMMAND_PAUSE;
- }
- else
- {
+ switch (new_state) {
+ case GST_STATE_VOID_PENDING:
+ break;
+ case GST_STATE_NULL:
+ break;
+ case GST_STATE_READY:
+ setStatus(STATUS_LOADED);
+ break;
+ case GST_STATE_PAUSED:
+ setStatus(STATUS_PAUSED);
+ break;
+ case GST_STATE_PLAYING:
+ setStatus(STATUS_PLAYING);
+ break;
+ }
+ break;
+ }
+ case GST_MESSAGE_ERROR: {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ llgst_message_parse_error (message, &err, &debug);
+ WARNMSG("GST error: %s", err?err->message:"(unknown)");
+ if (err)
+ g_error_free (err);
+ g_free (debug);
+
+ mCommand = COMMAND_STOP;
+
+ setStatus(STATUS_ERROR);
+
+ break;
+ }
+ case GST_MESSAGE_INFO: {
+ if (llgst_message_parse_info)
+ {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ llgst_message_parse_info (message, &err, &debug);
+ INFOMSG("GST info: %s", err?err->message:"(unknown)");
+ if (err)
+ g_error_free (err);
+ g_free (debug);
+ }
+ break;
+ }
+ case GST_MESSAGE_WARNING: {
+ GError *err = NULL;
+ gchar *debug = NULL;
+
+ llgst_message_parse_warning (message, &err, &debug);
+ WARNMSG("GST warning: %s", err?err->message:"(unknown)");
+ if (err)
+ g_error_free (err);
+ g_free (debug);
+
+ break;
+ }
+ case GST_MESSAGE_EOS:
+ /* end-of-stream */
+ DEBUGMSG("GST end-of-stream.");
+ if (mIsLooping)
+ {
+ DEBUGMSG("looping media...");
+ double eos_pos_sec = 0.0F;
+ bool got_eos_position = getTimePos(eos_pos_sec);
+
+ if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC)
+ {
+ // if we know that the movie is really short, don't
+ // loop it else it can easily become a time-hog
+ // because of GStreamer spin-up overhead
+ DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec);
+ // inject a COMMAND_PAUSE
+ mCommand = COMMAND_PAUSE;
+ }
+ else
+ {
#undef LLGST_LOOP_BY_SEEKING
// loop with a stop-start instead of a seek, because it actually seems rather
// faster than seeking on remote streams.
#ifdef LLGST_LOOP_BY_SEEKING
- // first, try looping by an explicit rewind
- bool seeksuccess = seek(0.0);
- if (seeksuccess)
- {
- play(1.0);
- }
- else
+ // first, try looping by an explicit rewind
+ bool seeksuccess = seek(0.0);
+ if (seeksuccess)
+ {
+ play(1.0);
+ }
+ else
#endif // LLGST_LOOP_BY_SEEKING
- { // use clumsy stop-start to loop
- DEBUGMSG("didn't loop by rewinding - stopping and starting instead...");
- stop();
- play(1.0);
- }
- }
- }
- else // not a looping media
- {
- // inject a COMMAND_STOP
- mCommand = COMMAND_STOP;
- }
- break;
- default:
- /* unhandled message */
- break;
- }
-
- /* we want to be notified again the next time there is a message
- * on the bus, so return true (false means we want to stop watching
- * for messages on the bus and our callback should not be called again)
- */
- return TRUE;
+ { // use clumsy stop-start to loop
+ DEBUGMSG("didn't loop by rewinding - stopping and starting instead...");
+ stop();
+ play(1.0);
+ }
+ }
+ }
+ else // not a looping media
+ {
+ // inject a COMMAND_STOP
+ mCommand = COMMAND_STOP;
+ }
+ break;
+ default:
+ /* unhandled message */
+ break;
+ }
+
+ /* we want to be notified again the next time there is a message
+ * on the bus, so return true (false means we want to stop watching
+ * for messages on the bus and our callback should not be called again)
+ */
+ return TRUE;
}
extern "C" {
gboolean
llmediaimplgstreamer_bus_callback (GstBus *bus,
- GstMessage *message,
- gpointer data)
+ GstMessage *message,
+ gpointer data)
{
- MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data;
- return impl->processGSTEvents(bus, message);
+ MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data;
+ return impl->processGSTEvents(bus, message);
}
} // extern "C"
@@ -359,159 +359,159 @@ llmediaimplgstreamer_bus_callback (GstBus *bus,
bool
MediaPluginGStreamer010::navigateTo ( const std::string urlIn )
{
- if (!mDoneInit)
- return false; // error
+ if (!mDoneInit)
+ return false; // error
- setStatus(STATUS_LOADING);
+ setStatus(STATUS_LOADING);
- DEBUGMSG("Setting media URI: %s", urlIn.c_str());
+ DEBUGMSG("Setting media URI: %s", urlIn.c_str());
- mSeekWanted = false;
+ mSeekWanted = false;
- if (NULL == mPump ||
- NULL == mPlaybin)
- {
- setStatus(STATUS_ERROR);
- return false; // error
- }
+ if (NULL == mPump ||
+ NULL == mPlaybin)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
- // set URI
- g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL);
- //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL);
+ // set URI
+ g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL);
+ //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL);
- // navigateTo implicitly plays, too.
- play(1.0);
+ // navigateTo implicitly plays, too.
+ play(1.0);
- return true;
+ return true;
}
bool
MediaPluginGStreamer010::update(int milliseconds)
{
- if (!mDoneInit)
- return false; // error
-
- DEBUGMSG("updating media...");
-
- // sanity check
- if (NULL == mPump ||
- NULL == mPlaybin)
- {
- DEBUGMSG("dead media...");
- return false;
- }
-
- // see if there's an outstanding seek wanted
- if (mSeekWanted &&
- // bleh, GST has to be happy that the movie is really truly playing
- // or it may quietly ignore the seek (with rtsp:// at least).
- (GST_STATE(mPlaybin) == GST_STATE_PLAYING))
- {
- seek(mSeekDestination);
- mSeekWanted = false;
- }
-
- // *TODO: time-limit - but there isn't a lot we can do here, most
- // time is spent in gstreamer's own opaque worker-threads. maybe
- // we can do something sneaky like only unlock the video object
- // for 'milliseconds' and otherwise hold the lock.
- while (g_main_context_pending(g_main_loop_get_context(mPump)))
- {
- g_main_context_iteration(g_main_loop_get_context(mPump), FALSE);
- }
-
- // check for availability of a new frame
-
- if (mVideoSink)
- {
- GST_OBJECT_LOCK(mVideoSink);
- if (mVideoSink->retained_frame_ready)
- {
- DEBUGMSG("NEW FRAME READY");
-
- if (mVideoSink->retained_frame_width != mCurrentWidth ||
- mVideoSink->retained_frame_height != mCurrentHeight)
- // *TODO: also check for change in format
- {
- // just resize container, don't consume frame
- int neww = mVideoSink->retained_frame_width;
- int newh = mVideoSink->retained_frame_height;
-
- int newd = 4;
- mTextureFormatPrimary = GL_RGBA;
- mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
-
- /*
- int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format];
- if (SLV_PF_BGRX == mVideoSink->retained_frame_format)
- {
- mTextureFormatPrimary = GL_BGRA;
- mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
- }
- else
- {
- mTextureFormatPrimary = GL_RGBA;
- mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
- }
- */
-
- GST_OBJECT_UNLOCK(mVideoSink);
-
- mCurrentRowbytes = neww * newd;
- DEBUGMSG("video container resized to %dx%d",
- neww, newh);
-
- mDepth = newd;
- mCurrentWidth = neww;
- mCurrentHeight = newh;
- sizeChanged();
- return true;
- }
-
- if (mPixels &&
- mCurrentHeight <= mHeight &&
- mCurrentWidth <= mWidth &&
- !mTextureSegmentName.empty())
- {
- // we're gonna totally consume this frame - reset 'ready' flag
- mVideoSink->retained_frame_ready = FALSE;
- int destination_rowbytes = mWidth * mDepth;
- for (int row=0; row<mCurrentHeight; ++row)
- {
- memcpy(&mPixels
- [destination_rowbytes * row],
- &mVideoSink->retained_frame_data
- [mCurrentRowbytes * row],
- mCurrentRowbytes);
- }
-
- GST_OBJECT_UNLOCK(mVideoSink);
- DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST");
-
- setDirty(0,0,mCurrentWidth,mCurrentHeight);
- }
- else
- {
- // new frame ready, but we're not ready to
- // consume it.
-
- GST_OBJECT_UNLOCK(mVideoSink);
-
- DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize");
- }
-
- return true;
- }
- else
- {
- // nothing to do yet.
- GST_OBJECT_UNLOCK(mVideoSink);
- return true;
- }
- }
-
- return true;
+ if (!mDoneInit)
+ return false; // error
+
+ DEBUGMSG("updating media...");
+
+ // sanity check
+ if (NULL == mPump ||
+ NULL == mPlaybin)
+ {
+ DEBUGMSG("dead media...");
+ return false;
+ }
+
+ // see if there's an outstanding seek wanted
+ if (mSeekWanted &&
+ // bleh, GST has to be happy that the movie is really truly playing
+ // or it may quietly ignore the seek (with rtsp:// at least).
+ (GST_STATE(mPlaybin) == GST_STATE_PLAYING))
+ {
+ seek(mSeekDestination);
+ mSeekWanted = false;
+ }
+
+ // *TODO: time-limit - but there isn't a lot we can do here, most
+ // time is spent in gstreamer's own opaque worker-threads. maybe
+ // we can do something sneaky like only unlock the video object
+ // for 'milliseconds' and otherwise hold the lock.
+ while (g_main_context_pending(g_main_loop_get_context(mPump)))
+ {
+ g_main_context_iteration(g_main_loop_get_context(mPump), FALSE);
+ }
+
+ // check for availability of a new frame
+
+ if (mVideoSink)
+ {
+ GST_OBJECT_LOCK(mVideoSink);
+ if (mVideoSink->retained_frame_ready)
+ {
+ DEBUGMSG("NEW FRAME READY");
+
+ if (mVideoSink->retained_frame_width != mCurrentWidth ||
+ mVideoSink->retained_frame_height != mCurrentHeight)
+ // *TODO: also check for change in format
+ {
+ // just resize container, don't consume frame
+ int neww = mVideoSink->retained_frame_width;
+ int newh = mVideoSink->retained_frame_height;
+
+ int newd = 4;
+ mTextureFormatPrimary = GL_RGBA;
+ mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
+
+ /*
+ int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format];
+ if (SLV_PF_BGRX == mVideoSink->retained_frame_format)
+ {
+ mTextureFormatPrimary = GL_BGRA;
+ mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ else
+ {
+ mTextureFormatPrimary = GL_RGBA;
+ mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ */
+
+ GST_OBJECT_UNLOCK(mVideoSink);
+
+ mCurrentRowbytes = neww * newd;
+ DEBUGMSG("video container resized to %dx%d",
+ neww, newh);
+
+ mDepth = newd;
+ mCurrentWidth = neww;
+ mCurrentHeight = newh;
+ sizeChanged();
+ return true;
+ }
+
+ if (mPixels &&
+ mCurrentHeight <= mHeight &&
+ mCurrentWidth <= mWidth &&
+ !mTextureSegmentName.empty())
+ {
+ // we're gonna totally consume this frame - reset 'ready' flag
+ mVideoSink->retained_frame_ready = FALSE;
+ int destination_rowbytes = mWidth * mDepth;
+ for (int row=0; row<mCurrentHeight; ++row)
+ {
+ memcpy(&mPixels
+ [destination_rowbytes * row],
+ &mVideoSink->retained_frame_data
+ [mCurrentRowbytes * row],
+ mCurrentRowbytes);
+ }
+
+ GST_OBJECT_UNLOCK(mVideoSink);
+ DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST");
+
+ setDirty(0,0,mCurrentWidth,mCurrentHeight);
+ }
+ else
+ {
+ // new frame ready, but we're not ready to
+ // consume it.
+
+ GST_OBJECT_UNLOCK(mVideoSink);
+
+ DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize");
+ }
+
+ return true;
+ }
+ else
+ {
+ // nothing to do yet.
+ GST_OBJECT_UNLOCK(mVideoSink);
+ return true;
+ }
+ }
+
+ return true;
}
@@ -537,253 +537,253 @@ MediaPluginGStreamer010::mouseMove( int x, int y )
bool
MediaPluginGStreamer010::pause()
{
- DEBUGMSG("pausing media...");
- // todo: error-check this?
- if (mDoneInit && mPlaybin)
- {
- llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
- return true;
- }
- return false;
+ DEBUGMSG("pausing media...");
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PAUSED);
+ return true;
+ }
+ return false;
}
bool
MediaPluginGStreamer010::stop()
{
- DEBUGMSG("stopping media...");
- // todo: error-check this?
- if (mDoneInit && mPlaybin)
- {
- llgst_element_set_state(mPlaybin, GST_STATE_READY);
- return true;
- }
- return false;
+ DEBUGMSG("stopping media...");
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_READY);
+ return true;
+ }
+ return false;
}
bool
MediaPluginGStreamer010::play(double rate)
{
- // NOTE: we don't actually support non-natural rate.
+ // NOTE: we don't actually support non-natural rate.
DEBUGMSG("playing media... rate=%f", rate);
- // todo: error-check this?
- if (mDoneInit && mPlaybin)
- {
- llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
- return true;
- }
- return false;
+ // todo: error-check this?
+ if (mDoneInit && mPlaybin)
+ {
+ llgst_element_set_state(mPlaybin, GST_STATE_PLAYING);
+ return true;
+ }
+ return false;
}
bool
MediaPluginGStreamer010::setVolume( float volume )
{
- // we try to only update volume as conservatively as
- // possible, as many gst-plugins-base versions up to at least
- // November 2008 have critical race-conditions in setting volume - sigh
- if (mVolume == volume)
- return true; // nothing to do, everything's fine
-
- mVolume = volume;
- if (mDoneInit && mPlaybin)
- {
- g_object_set(mPlaybin, "volume", mVolume, NULL);
- return true;
- }
-
- return false;
+ // we try to only update volume as conservatively as
+ // possible, as many gst-plugins-base versions up to at least
+ // November 2008 have critical race-conditions in setting volume - sigh
+ if (mVolume == volume)
+ return true; // nothing to do, everything's fine
+
+ mVolume = volume;
+ if (mDoneInit && mPlaybin)
+ {
+ g_object_set(mPlaybin, "volume", mVolume, NULL);
+ return true;
+ }
+
+ return false;
}
bool
MediaPluginGStreamer010::seek(double time_sec)
{
- bool success = false;
- if (mDoneInit && mPlaybin)
- {
- success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME,
- GstSeekFlags(GST_SEEK_FLAG_FLUSH |
- GST_SEEK_FLAG_KEY_UNIT),
- GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND),
- GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
- }
- DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d",
- float(time_sec), int(success));
- return success;
+ bool success = false;
+ if (mDoneInit && mPlaybin)
+ {
+ success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME,
+ GstSeekFlags(GST_SEEK_FLAG_FLUSH |
+ GST_SEEK_FLAG_KEY_UNIT),
+ GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND),
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+ }
+ DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d",
+ float(time_sec), int(success));
+ return success;
}
bool
MediaPluginGStreamer010::getTimePos(double &sec_out)
{
- bool got_position = false;
- if (mDoneInit && mPlaybin)
- {
- gint64 pos;
- GstFormat timefmt = GST_FORMAT_TIME;
- got_position =
- llgst_element_query_position &&
- llgst_element_query_position(mPlaybin,
- &timefmt,
- &pos);
- got_position = got_position
- && (timefmt == GST_FORMAT_TIME);
- // GStreamer may have other ideas, but we consider the current position
- // undefined if not PLAYING or PAUSED
- got_position = got_position &&
- (GST_STATE(mPlaybin) == GST_STATE_PLAYING ||
- GST_STATE(mPlaybin) == GST_STATE_PAUSED);
- if (got_position && !GST_CLOCK_TIME_IS_VALID(pos))
- {
- if (GST_STATE(mPlaybin) == GST_STATE_PLAYING)
- {
- // if we're playing then we treat an invalid clock time
- // as 0, for complicated reasons (insert reason here)
- pos = 0;
- }
- else
- {
- got_position = false;
- }
-
- }
- // If all the preconditions succeeded... we can trust the result.
- if (got_position)
- {
- sec_out = double(pos) / double(GST_SECOND); // gst to sec
- }
- }
- return got_position;
+ bool got_position = false;
+ if (mDoneInit && mPlaybin)
+ {
+ gint64 pos;
+ GstFormat timefmt = GST_FORMAT_TIME;
+ got_position =
+ llgst_element_query_position &&
+ llgst_element_query_position(mPlaybin,
+ &timefmt,
+ &pos);
+ got_position = got_position
+ && (timefmt == GST_FORMAT_TIME);
+ // GStreamer may have other ideas, but we consider the current position
+ // undefined if not PLAYING or PAUSED
+ got_position = got_position &&
+ (GST_STATE(mPlaybin) == GST_STATE_PLAYING ||
+ GST_STATE(mPlaybin) == GST_STATE_PAUSED);
+ if (got_position && !GST_CLOCK_TIME_IS_VALID(pos))
+ {
+ if (GST_STATE(mPlaybin) == GST_STATE_PLAYING)
+ {
+ // if we're playing then we treat an invalid clock time
+ // as 0, for complicated reasons (insert reason here)
+ pos = 0;
+ }
+ else
+ {
+ got_position = false;
+ }
+
+ }
+ // If all the preconditions succeeded... we can trust the result.
+ if (got_position)
+ {
+ sec_out = double(pos) / double(GST_SECOND); // gst to sec
+ }
+ }
+ return got_position;
}
bool
MediaPluginGStreamer010::load()
{
- if (!mDoneInit)
- return false; // error
-
- setStatus(STATUS_LOADING);
-
- DEBUGMSG("setting up media...");
-
- mIsLooping = false;
- mVolume = 0.1234567; // minor hack to force an initial volume update
-
- // Create a pumpable main-loop for this media
- mPump = g_main_loop_new (NULL, FALSE);
- if (!mPump)
- {
- setStatus(STATUS_ERROR);
- return false; // error
- }
-
- // instantiate a playbin element to do the hard work
- mPlaybin = llgst_element_factory_make ("playbin", "play");
- if (!mPlaybin)
- {
- setStatus(STATUS_ERROR);
- return false; // error
- }
-
- // get playbin's bus
- GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
- if (!bus)
- {
- setStatus(STATUS_ERROR);
- return false; // error
- }
- mBusWatchID = llgst_bus_add_watch (bus,
- llmediaimplgstreamer_bus_callback,
- this);
- llgst_object_unref (bus);
+ if (!mDoneInit)
+ return false; // error
+
+ setStatus(STATUS_LOADING);
+
+ DEBUGMSG("setting up media...");
+
+ mIsLooping = false;
+ mVolume = 0.1234567; // minor hack to force an initial volume update
+
+ // Create a pumpable main-loop for this media
+ mPump = g_main_loop_new (NULL, FALSE);
+ if (!mPump)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ // instantiate a playbin element to do the hard work
+ mPlaybin = llgst_element_factory_make ("playbin", "play");
+ if (!mPlaybin)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ // get playbin's bus
+ GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin));
+ if (!bus)
+ {
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+ mBusWatchID = llgst_bus_add_watch (bus,
+ llmediaimplgstreamer_bus_callback,
+ this);
+ llgst_object_unref (bus);
#if 0 // not quite stable/correct yet
- // get a visualizer element (bonus feature!)
- char* vis_name = getenv("LL_GST_VIS_NAME");
- if (!vis_name ||
- (vis_name && std::string(vis_name)!="none"))
- {
- if (vis_name)
- {
- mVisualizer = llgst_element_factory_make (vis_name, "vis");
- }
- if (!mVisualizer)
- {
- mVisualizer = llgst_element_factory_make ("libvisual_jess", "vis");
- if (!mVisualizer)
- {
- mVisualizer = llgst_element_factory_make ("goom", "vis");
- if (!mVisualizer)
- {
- mVisualizer = llgst_element_factory_make ("libvisual_lv_scope", "vis");
- if (!mVisualizer)
- {
- // That's okay, we don't NEED this.
- }
- }
- }
- }
- }
+ // get a visualizer element (bonus feature!)
+ char* vis_name = getenv("LL_GST_VIS_NAME");
+ if (!vis_name ||
+ (vis_name && std::string(vis_name)!="none"))
+ {
+ if (vis_name)
+ {
+ mVisualizer = llgst_element_factory_make (vis_name, "vis");
+ }
+ if (!mVisualizer)
+ {
+ mVisualizer = llgst_element_factory_make ("libvisual_jess", "vis");
+ if (!mVisualizer)
+ {
+ mVisualizer = llgst_element_factory_make ("goom", "vis");
+ if (!mVisualizer)
+ {
+ mVisualizer = llgst_element_factory_make ("libvisual_lv_scope", "vis");
+ if (!mVisualizer)
+ {
+ // That's okay, we don't NEED this.
+ }
+ }
+ }
+ }
+ }
#endif
- if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) {
- // instantiate a custom video sink
- mVideoSink =
- GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo"));
- if (!mVideoSink)
- {
- WARNMSG("Could not instantiate private-slvideo element.");
- // todo: cleanup.
- setStatus(STATUS_ERROR);
- return false; // error
- }
-
- // connect the pieces
- g_object_set(mPlaybin, "video-sink", mVideoSink, NULL);
- }
-
- if (mVisualizer)
- {
- g_object_set(mPlaybin, "vis-plugin", mVisualizer, NULL);
- }
-
- return true;
+ if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) {
+ // instantiate a custom video sink
+ mVideoSink =
+ GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo"));
+ if (!mVideoSink)
+ {
+ WARNMSG("Could not instantiate private-slvideo element.");
+ // todo: cleanup.
+ setStatus(STATUS_ERROR);
+ return false; // error
+ }
+
+ // connect the pieces
+ g_object_set(mPlaybin, "video-sink", mVideoSink, NULL);
+ }
+
+ if (mVisualizer)
+ {
+ g_object_set(mPlaybin, "vis-plugin", mVisualizer, NULL);
+ }
+
+ return true;
}
bool
MediaPluginGStreamer010::unload ()
{
- if (!mDoneInit)
- return false; // error
-
- DEBUGMSG("unloading media...");
-
- // stop getting callbacks for this bus
- g_source_remove(mBusWatchID);
- mBusWatchID = 0;
-
- if (mPlaybin)
- {
- llgst_element_set_state (mPlaybin, GST_STATE_NULL);
- llgst_object_unref (GST_OBJECT (mPlaybin));
- mPlaybin = NULL;
- }
-
- if (mVisualizer)
- {
- llgst_object_unref (GST_OBJECT (mVisualizer));
- mVisualizer = NULL;
- }
-
- if (mPump)
- {
- g_main_loop_quit(mPump);
- mPump = NULL;
- }
-
- mVideoSink = NULL;
-
- setStatus(STATUS_NONE);
-
- return true;
+ if (!mDoneInit)
+ return false; // error
+
+ DEBUGMSG("unloading media...");
+
+ // stop getting callbacks for this bus
+ g_source_remove(mBusWatchID);
+ mBusWatchID = 0;
+
+ if (mPlaybin)
+ {
+ llgst_element_set_state (mPlaybin, GST_STATE_NULL);
+ llgst_object_unref (GST_OBJECT (mPlaybin));
+ mPlaybin = NULL;
+ }
+
+ if (mVisualizer)
+ {
+ llgst_object_unref (GST_OBJECT (mVisualizer));
+ mVisualizer = NULL;
+ }
+
+ if (mPump)
+ {
+ g_main_loop_quit(mPump);
+ mPump = NULL;
+ }
+
+ mVideoSink = NULL;
+
+ setStatus(STATUS_NONE);
+
+ return true;
}
@@ -791,132 +791,132 @@ MediaPluginGStreamer010::unload ()
bool
MediaPluginGStreamer010::startup()
{
- // first - check if GStreamer is explicitly disabled
- if (NULL != getenv("LL_DISABLE_GSTREAMER"))
- return false;
+ // first - check if GStreamer is explicitly disabled
+ if (NULL != getenv("LL_DISABLE_GSTREAMER"))
+ return false;
- // only do global GStreamer initialization once.
- if (!mDoneInit)
- {
- g_thread_init(NULL);
+ // only do global GStreamer initialization once.
+ if (!mDoneInit)
+ {
+ g_thread_init(NULL);
- // Init the glib type system - we need it.
- g_type_init();
+ // Init the glib type system - we need it.
+ g_type_init();
- // Get symbols!
+ // Get symbols!
#if LL_DARWIN
- if (! grab_gst_syms("libgstreamer-0.10.dylib",
- "libgstvideo-0.10.dylib") )
+ if (! grab_gst_syms("libgstreamer-0.10.dylib",
+ "libgstvideo-0.10.dylib") )
#elseif LL_WINDOWS
- if (! grab_gst_syms("libgstreamer-0.10.dll",
- "libgstvideo-0.10.dll") )
+ if (! grab_gst_syms("libgstreamer-0.10.dll",
+ "libgstvideo-0.10.dll") )
#else // linux or other ELFy unixoid
- if (! grab_gst_syms("libgstreamer-0.10.so.0",
- "libgstvideo-0.10.so.0") )
+ if (! grab_gst_syms("libgstreamer-0.10.so.0",
+ "libgstvideo-0.10.so.0") )
#endif
- {
- WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled.");
- return false;
- }
-
- if (llgst_segtrap_set_enabled)
- {
- llgst_segtrap_set_enabled(FALSE);
- }
- else
- {
- WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught.");
- }
+ {
+ WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled.");
+ return false;
+ }
+
+ if (llgst_segtrap_set_enabled)
+ {
+ llgst_segtrap_set_enabled(FALSE);
+ }
+ else
+ {
+ WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught.");
+ }
#if LL_LINUX
- // Gstreamer tries a fork during init, waitpid-ing on it,
- // which conflicts with any installed SIGCHLD handler...
- struct sigaction tmpact, oldact;
- if (llgst_registry_fork_set_enabled) {
- // if we can disable SIGCHLD-using forking behaviour,
- // do it.
- llgst_registry_fork_set_enabled(false);
- }
- else {
- // else temporarily install default SIGCHLD handler
- // while GStreamer initialises
- tmpact.sa_handler = SIG_DFL;
- sigemptyset( &tmpact.sa_mask );
- tmpact.sa_flags = SA_SIGINFO;
- sigaction(SIGCHLD, &tmpact, &oldact);
- }
+ // Gstreamer tries a fork during init, waitpid-ing on it,
+ // which conflicts with any installed SIGCHLD handler...
+ struct sigaction tmpact, oldact;
+ if (llgst_registry_fork_set_enabled) {
+ // if we can disable SIGCHLD-using forking behaviour,
+ // do it.
+ llgst_registry_fork_set_enabled(false);
+ }
+ else {
+ // else temporarily install default SIGCHLD handler
+ // while GStreamer initialises
+ tmpact.sa_handler = SIG_DFL;
+ sigemptyset( &tmpact.sa_mask );
+ tmpact.sa_flags = SA_SIGINFO;
+ sigaction(SIGCHLD, &tmpact, &oldact);
+ }
#endif // LL_LINUX
- // Protect against GStreamer resetting the locale, yuck.
- static std::string saved_locale;
- saved_locale = setlocale(LC_ALL, NULL);
+ // Protect against GStreamer resetting the locale, yuck.
+ static std::string saved_locale;
+ saved_locale = setlocale(LC_ALL, NULL);
- // finally, try to initialize GStreamer!
- GError *err = NULL;
- gboolean init_gst_success = llgst_init_check(NULL, NULL, &err);
+ // finally, try to initialize GStreamer!
+ GError *err = NULL;
+ gboolean init_gst_success = llgst_init_check(NULL, NULL, &err);
- // restore old locale
- setlocale(LC_ALL, saved_locale.c_str() );
+ // restore old locale
+ setlocale(LC_ALL, saved_locale.c_str() );
#if LL_LINUX
- // restore old SIGCHLD handler
- if (!llgst_registry_fork_set_enabled)
- sigaction(SIGCHLD, &oldact, NULL);
+ // restore old SIGCHLD handler
+ if (!llgst_registry_fork_set_enabled)
+ sigaction(SIGCHLD, &oldact, NULL);
#endif // LL_LINUX
- if (!init_gst_success) // fail
- {
- if (err)
- {
- WARNMSG("GST init failed: %s", err->message);
- g_error_free(err);
- }
- else
- {
- WARNMSG("GST init failed for unspecified reason.");
- }
- return false;
- }
-
- // Init our custom plugins - only really need do this once.
- gst_slvideo_init_class();
-
- mDoneInit = true;
- }
-
- return true;
+ if (!init_gst_success) // fail
+ {
+ if (err)
+ {
+ WARNMSG("GST init failed: %s", err->message);
+ g_error_free(err);
+ }
+ else
+ {
+ WARNMSG("GST init failed for unspecified reason.");
+ }
+ return false;
+ }
+
+ // Init our custom plugins - only really need do this once.
+ gst_slvideo_init_class();
+
+ mDoneInit = true;
+ }
+
+ return true;
}
void
MediaPluginGStreamer010::sizeChanged()
{
- // the shared writing space has possibly changed size/location/whatever
-
- // Check to see whether the movie's NATURAL size has been set yet
- if (1 == mNaturalWidth &&
- 1 == mNaturalHeight)
- {
- mNaturalWidth = mCurrentWidth;
- mNaturalHeight = mCurrentHeight;
- DEBUGMSG("Media NATURAL size better detected as %dx%d",
- mNaturalWidth, mNaturalHeight);
- }
-
- // if the size has changed then the shm has changed and the app needs telling
- if (mCurrentWidth != mPreviousWidth ||
- mCurrentHeight != mPreviousHeight)
- {
- mPreviousWidth = mCurrentWidth;
- mPreviousHeight = mCurrentHeight;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
- message.setValue("name", mTextureSegmentName);
- message.setValueS32("width", mNaturalWidth);
- message.setValueS32("height", mNaturalHeight);
- DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight);
- sendMessage(message);
- }
+ // the shared writing space has possibly changed size/location/whatever
+
+ // Check to see whether the movie's NATURAL size has been set yet
+ if (1 == mNaturalWidth &&
+ 1 == mNaturalHeight)
+ {
+ mNaturalWidth = mCurrentWidth;
+ mNaturalHeight = mCurrentHeight;
+ DEBUGMSG("Media NATURAL size better detected as %dx%d",
+ mNaturalWidth, mNaturalHeight);
+ }
+
+ // if the size has changed then the shm has changed and the app needs telling
+ if (mCurrentWidth != mPreviousWidth ||
+ mCurrentHeight != mPreviousHeight)
+ {
+ mPreviousWidth = mCurrentWidth;
+ mPreviousHeight = mCurrentHeight;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
+ message.setValue("name", mTextureSegmentName);
+ message.setValueS32("width", mNaturalWidth);
+ message.setValueS32("height", mNaturalHeight);
+ DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight);
+ sendMessage(message);
+ }
}
@@ -925,306 +925,306 @@ MediaPluginGStreamer010::sizeChanged()
bool
MediaPluginGStreamer010::closedown()
{
- if (!mDoneInit)
- return false; // error
+ if (!mDoneInit)
+ return false; // error
- ungrab_gst_syms();
+ ungrab_gst_syms();
- mDoneInit = false;
+ mDoneInit = false;
- return true;
+ return true;
}
MediaPluginGStreamer010::~MediaPluginGStreamer010()
{
- DEBUGMSG("MediaPluginGStreamer010 destructor");
+ DEBUGMSG("MediaPluginGStreamer010 destructor");
- closedown();
+ closedown();
- DEBUGMSG("GStreamer010 closing down");
+ DEBUGMSG("GStreamer010 closing down");
}
std::string
MediaPluginGStreamer010::getVersion()
{
- std::string plugin_version = "GStreamer010 media plugin, GStreamer version ";
- if (mDoneInit &&
- llgst_version)
- {
- guint major, minor, micro, nano;
- llgst_version(&major, &minor, &micro, &nano);
- plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO);
- }
- else
- {
- plugin_version += "(unknown)";
- }
- return plugin_version;
+ std::string plugin_version = "GStreamer010 media plugin, GStreamer version ";
+ if (mDoneInit &&
+ llgst_version)
+ {
+ guint major, minor, micro, nano;
+ llgst_version(&major, &minor, &micro, &nano);
+ plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO);
+ }
+ else
+ {
+ plugin_version += "(unknown)";
+ }
+ return plugin_version;
}
void MediaPluginGStreamer010::receiveMessage(const char *message_string)
{
- //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
-
- LLPluginMessage message_in;
-
- if(message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if(message_name == "init")
- {
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
- message.setValueLLSD("versions", versions);
-
- if ( load() )
- {
- DEBUGMSG("GStreamer010 media instance set up");
- }
- else
- {
- WARNMSG("GStreamer010 media instance failed to set up");
- }
-
- message.setValue("plugin_version", getVersion());
- sendMessage(message);
- }
- else if(message_name == "idle")
- {
- // no response is necessary here.
- double time = message_in.getValueReal("time");
-
- // Convert time to milliseconds for update()
- update((int)(time * 1000.0f));
- }
- else if(message_name == "cleanup")
- {
- unload();
- closedown();
- }
- else if(message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
- std::ostringstream str;
- INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress);
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
- }
- else if(message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
- DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str());
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
- if(mPixels == iter->second.mAddress)
- {
- // This is the currently active pixel buffer. Make sure we stop drawing to it.
- mPixels = NULL;
- mTextureSegmentName.clear();
-
- // Make sure the movie decoder is no longer pointed at the shared segment.
- sizeChanged();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
- WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!");
- }
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
- std::ostringstream str;
- INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str());
- }
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if(message_name == "init")
- {
- // Plugin gets to decide the texture parameters to use.
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- // lame to have to decide this now, it depends on the movie. Oh well.
- mDepth = 4;
-
- mCurrentWidth = 1;
- mCurrentHeight = 1;
- mPreviousWidth = 1;
- mPreviousHeight = 1;
- mNaturalWidth = 1;
- mNaturalHeight = 1;
- mWidth = 1;
- mHeight = 1;
- mTextureWidth = 1;
- mTextureHeight = 1;
-
- message.setValueU32("format", GL_RGBA);
- message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV);
-
- message.setValueS32("depth", mDepth);
- message.setValueS32("default_width", mWidth);
- message.setValueS32("default_height", mHeight);
- message.setValueU32("internalformat", GL_RGBA8);
- message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
- message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale
- sendMessage(message);
- }
- else if(message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
-
- std::ostringstream str;
- INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height);
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
-
- if(!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
- INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height);
- INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height);
-
- mPixels = (unsigned char*)iter->second.mAddress;
- mTextureSegmentName = name;
- mWidth = width;
- mHeight = height;
-
- if (texture_width > 1 ||
- texture_height > 1) // not a dummy size from the app, a real explicit forced size
- {
- INFOMSG("**** = REAL RESIZE REQUEST FROM APP");
-
- GST_OBJECT_LOCK(mVideoSink);
- mVideoSink->resize_forced_always = true;
- mVideoSink->resize_try_width = texture_width;
- mVideoSink->resize_try_height = texture_height;
- GST_OBJECT_UNLOCK(mVideoSink);
- }
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
- }
- }
- }
- else if(message_name == "load_uri")
- {
- std::string uri = message_in.getValue("uri");
- navigateTo( uri );
- sendStatus();
- }
- else if(message_name == "mouse_event")
- {
- std::string event = message_in.getValue("event");
- S32 x = message_in.getValueS32("x");
- S32 y = message_in.getValueS32("y");
-
- if(event == "down")
- {
- mouseDown(x, y);
- }
- else if(event == "up")
- {
- mouseUp(x, y);
- }
- else if(event == "move")
- {
- mouseMove(x, y);
- };
- };
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
- {
- if(message_name == "stop")
- {
- stop();
- }
- else if(message_name == "start")
- {
- double rate = 0.0;
- if(message_in.hasValue("rate"))
- {
- rate = message_in.getValueReal("rate");
- }
- // NOTE: we don't actually support rate.
- play(rate);
- }
- else if(message_name == "pause")
- {
- pause();
- }
- else if(message_name == "seek")
- {
- double time = message_in.getValueReal("time");
- // defer the actual seek in case we haven't
- // really truly started yet in which case there
- // is nothing to seek upon
- mSeekWanted = true;
- mSeekDestination = time;
- }
- else if(message_name == "set_loop")
- {
- bool loop = message_in.getValueBoolean("loop");
- mIsLooping = loop;
- }
- else if(message_name == "set_volume")
- {
- double volume = message_in.getValueReal("volume");
- setVolume(volume);
- }
- }
- else
- {
- INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str());
- }
- }
+ //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+
+ LLPluginMessage message_in;
+
+ if(message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if(message_name == "init")
+ {
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ if ( load() )
+ {
+ DEBUGMSG("GStreamer010 media instance set up");
+ }
+ else
+ {
+ WARNMSG("GStreamer010 media instance failed to set up");
+ }
+
+ message.setValue("plugin_version", getVersion());
+ sendMessage(message);
+ }
+ else if(message_name == "idle")
+ {
+ // no response is necessary here.
+ double time = message_in.getValueReal("time");
+
+ // Convert time to milliseconds for update()
+ update((int)(time * 1000.0f));
+ }
+ else if(message_name == "cleanup")
+ {
+ unload();
+ closedown();
+ }
+ else if(message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+
+ std::ostringstream str;
+ INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress);
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+ }
+ else if(message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+ DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str());
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+ if(mPixels == iter->second.mAddress)
+ {
+ // This is the currently active pixel buffer. Make sure we stop drawing to it.
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+
+ // Make sure the movie decoder is no longer pointed at the shared segment.
+ sizeChanged();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+ WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!");
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+ std::ostringstream str;
+ INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str());
+ }
+ }
+ else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if(message_name == "init")
+ {
+ // Plugin gets to decide the texture parameters to use.
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ // lame to have to decide this now, it depends on the movie. Oh well.
+ mDepth = 4;
+
+ mCurrentWidth = 1;
+ mCurrentHeight = 1;
+ mPreviousWidth = 1;
+ mPreviousHeight = 1;
+ mNaturalWidth = 1;
+ mNaturalHeight = 1;
+ mWidth = 1;
+ mHeight = 1;
+ mTextureWidth = 1;
+ mTextureHeight = 1;
+
+ message.setValueU32("format", GL_RGBA);
+ message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV);
+
+ message.setValueS32("depth", mDepth);
+ message.setValueS32("default_width", mWidth);
+ message.setValueS32("default_height", mHeight);
+ message.setValueU32("internalformat", GL_RGBA8);
+ message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
+ message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale
+ sendMessage(message);
+ }
+ else if(message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ std::ostringstream str;
+ INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height);
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+
+ if(!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+ INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height);
+ INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height);
+
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mTextureSegmentName = name;
+ mWidth = width;
+ mHeight = height;
+
+ if (texture_width > 1 ||
+ texture_height > 1) // not a dummy size from the app, a real explicit forced size
+ {
+ INFOMSG("**** = REAL RESIZE REQUEST FROM APP");
+
+ GST_OBJECT_LOCK(mVideoSink);
+ mVideoSink->resize_forced_always = true;
+ mVideoSink->resize_try_width = texture_width;
+ mVideoSink->resize_try_height = texture_height;
+ GST_OBJECT_UNLOCK(mVideoSink);
+ }
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+ }
+ }
+ }
+ else if(message_name == "load_uri")
+ {
+ std::string uri = message_in.getValue("uri");
+ navigateTo( uri );
+ sendStatus();
+ }
+ else if(message_name == "mouse_event")
+ {
+ std::string event = message_in.getValue("event");
+ S32 x = message_in.getValueS32("x");
+ S32 y = message_in.getValueS32("y");
+
+ if(event == "down")
+ {
+ mouseDown(x, y);
+ }
+ else if(event == "up")
+ {
+ mouseUp(x, y);
+ }
+ else if(event == "move")
+ {
+ mouseMove(x, y);
+ };
+ };
+ }
+ else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+ {
+ if(message_name == "stop")
+ {
+ stop();
+ }
+ else if(message_name == "start")
+ {
+ double rate = 0.0;
+ if(message_in.hasValue("rate"))
+ {
+ rate = message_in.getValueReal("rate");
+ }
+ // NOTE: we don't actually support rate.
+ play(rate);
+ }
+ else if(message_name == "pause")
+ {
+ pause();
+ }
+ else if(message_name == "seek")
+ {
+ double time = message_in.getValueReal("time");
+ // defer the actual seek in case we haven't
+ // really truly started yet in which case there
+ // is nothing to seek upon
+ mSeekWanted = true;
+ mSeekDestination = time;
+ }
+ else if(message_name == "set_loop")
+ {
+ bool loop = message_in.getValueBoolean("loop");
+ mIsLooping = loop;
+ }
+ else if(message_name == "set_volume")
+ {
+ double volume = message_in.getValueReal("volume");
+ setVolume(volume);
+ }
+ }
+ else
+ {
+ INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str());
+ }
+ }
}
int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
{
- if (MediaPluginGStreamer010::startup())
- {
- MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data);
- *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage;
- *plugin_user_data = (void*)self;
-
- return 0; // okay
- }
- else
- {
- return -1; // failed to init
- }
+ if (MediaPluginGStreamer010::startup())
+ {
+ MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data);
+ *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
+
+ return 0; // okay
+ }
+ else
+ {
+ return -1; // failed to init
+ }
}
#else // LL_GSTREAMER010_ENABLED
@@ -1234,15 +1234,15 @@ int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void
class MediaPluginGStreamer010 : public MediaPluginBase
{
public:
- MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginGStreamer010();
- /* virtual */ void receiveMessage(const char *message_string);
+ MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginGStreamer010();
+ /* virtual */ void receiveMessage(const char *message_string);
};
MediaPluginGStreamer010::MediaPluginGStreamer010(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data ) :
- MediaPluginBase(host_send_func, host_user_data)
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data ) :
+ MediaPluginBase(host_send_func, host_user_data)
{
// no-op
}
@@ -1254,7 +1254,7 @@ MediaPluginGStreamer010::~MediaPluginGStreamer010()
void MediaPluginGStreamer010::receiveMessage(const char *message_string)
{
- // no-op
+ // no-op
}
// We're building without GStreamer enabled. Just refuse to initialize.
diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
index 89144922cc..a5d8f885fd 100644
--- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
+++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp
@@ -50,53 +50,53 @@ typedef SSIZE_T ssize_t;
////////////////////////////////////////////////////////////////////////////////
//
class MediaPluginLibVLC :
- public MediaPluginBase
+ public MediaPluginBase
{
public:
- MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginLibVLC();
+ MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginLibVLC();
- /*virtual*/ void receiveMessage(const char* message_string);
+ /*virtual*/ void receiveMessage(const char* message_string);
private:
- bool init();
+ bool init();
- void initVLC();
- void playMedia();
- void resetVLC();
- void setVolume(const F64 volume);
- void setVolumeVLC();
- void updateTitle(const char* title);
+ void initVLC();
+ void playMedia();
+ void resetVLC();
+ void setVolume(const F64 volume);
+ void setVolumeVLC();
+ void updateTitle(const char* title);
- static void* lock(void* data, void** p_pixels);
- static void unlock(void* data, void* id, void* const* raw_pixels);
- static void display(void* data, void* id);
+ static void* lock(void* data, void** p_pixels);
+ static void unlock(void* data, void* id, void* const* raw_pixels);
+ static void display(void* data, void* id);
- /*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
+ /*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
void setDurationDirty();
- static void eventCallbacks(const libvlc_event_t* event, void* ptr);
+ static void eventCallbacks(const libvlc_event_t* event, void* ptr);
- libvlc_instance_t* mLibVLC;
- libvlc_media_t* mLibVLCMedia;
- libvlc_media_player_t* mLibVLCMediaPlayer;
+ libvlc_instance_t* mLibVLC;
+ libvlc_media_t* mLibVLCMedia;
+ libvlc_media_player_t* mLibVLCMediaPlayer;
- struct mLibVLCContext
- {
- unsigned char* texture_pixels;
- libvlc_media_player_t* mp;
- MediaPluginLibVLC* parent;
- };
- struct mLibVLCContext mLibVLCCallbackContext;
+ struct mLibVLCContext
+ {
+ unsigned char* texture_pixels;
+ libvlc_media_player_t* mp;
+ MediaPluginLibVLC* parent;
+ };
+ struct mLibVLCContext mLibVLCCallbackContext;
- std::string mURL;
- F64 mCurVolume;
+ std::string mURL;
+ F64 mCurVolume;
- bool mIsLooping;
+ bool mIsLooping;
- F64 mCurTime;
- F64 mDuration;
- EStatus mVlcStatus;
+ F64 mCurTime;
+ F64 mDuration;
+ EStatus mVlcStatus;
};
////////////////////////////////////////////////////////////////////////////////
@@ -104,28 +104,28 @@ private:
MediaPluginLibVLC::MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
MediaPluginBase(host_send_func, host_user_data)
{
- mTextureWidth = 0;
- mTextureHeight = 0;
- mWidth = 0;
- mHeight = 0;
- mDepth = 4;
- mPixels = 0;
+ mTextureWidth = 0;
+ mTextureHeight = 0;
+ mWidth = 0;
+ mHeight = 0;
+ mDepth = 4;
+ mPixels = 0;
- mLibVLC = 0;
- mLibVLCMedia = 0;
- mLibVLCMediaPlayer = 0;
+ mLibVLC = 0;
+ mLibVLCMedia = 0;
+ mLibVLCMediaPlayer = 0;
- mCurVolume = 0.0;
+ mCurVolume = 0.0;
- mIsLooping = false;
+ mIsLooping = false;
- mCurTime = 0.0;
- mDuration = 0.0;
+ mCurTime = 0.0;
+ mDuration = 0.0;
- mURL = std::string();
+ mURL = std::string();
- mVlcStatus = STATUS_NONE;
- setStatus(STATUS_NONE);
+ mVlcStatus = STATUS_NONE;
+ setStatus(STATUS_NONE);
}
////////////////////////////////////////////////////////////////////////////////
@@ -138,80 +138,80 @@ MediaPluginLibVLC::~MediaPluginLibVLC()
//
void* MediaPluginLibVLC::lock(void* data, void** p_pixels)
{
- struct mLibVLCContext* context = (mLibVLCContext*)data;
+ struct mLibVLCContext* context = (mLibVLCContext*)data;
- *p_pixels = context->texture_pixels;
+ *p_pixels = context->texture_pixels;
- return NULL;
+ return NULL;
}
/////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::unlock(void* data, void* id, void* const* raw_pixels)
{
- // nothing to do here for the moment
- // we *could* modify pixels here to, for example, Y flip, but this is done with
- // a VLC video filter transform.
+ // nothing to do here for the moment
+ // we *could* modify pixels here to, for example, Y flip, but this is done with
+ // a VLC video filter transform.
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::display(void* data, void* id)
{
- struct mLibVLCContext* context = (mLibVLCContext*)data;
+ struct mLibVLCContext* context = (mLibVLCContext*)data;
- context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight);
+ context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::initVLC()
{
- char const* vlc_argv[] =
- {
- "--no-xlib",
- "--video-filter=transform{type=vflip}", // MAINT-6578 Y flip textures in plugin vs client
- };
+ char const* vlc_argv[] =
+ {
+ "--no-xlib",
+ "--video-filter=transform{type=vflip}", // MAINT-6578 Y flip textures in plugin vs client
+ };
#if LL_DARWIN
- setenv("VLC_PLUGIN_PATH", ".", 1);
+ setenv("VLC_PLUGIN_PATH", ".", 1);
#endif
- int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
- mLibVLC = libvlc_new(vlc_argc, vlc_argv);
+ int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
+ mLibVLC = libvlc_new(vlc_argc, vlc_argv);
- if (!mLibVLC)
- {
- // for the moment, if this fails, the plugin will fail and
- // the media sub-system will tell the viewer something went wrong.
- }
+ if (!mLibVLC)
+ {
+ // for the moment, if this fails, the plugin will fail and
+ // the media sub-system will tell the viewer something went wrong.
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::resetVLC()
{
- libvlc_media_player_stop(mLibVLCMediaPlayer);
- libvlc_media_player_release(mLibVLCMediaPlayer);
- libvlc_release(mLibVLC);
+ libvlc_media_player_stop(mLibVLCMediaPlayer);
+ libvlc_media_player_release(mLibVLCMediaPlayer);
+ libvlc_release(mLibVLC);
}
////////////////////////////////////////////////////////////////////////////////
// *virtual*
void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
- message.setValueS32("left", left);
- message.setValueS32("top", top);
- message.setValueS32("right", right);
- message.setValueS32("bottom", bottom);
+ message.setValueS32("left", left);
+ message.setValueS32("top", top);
+ message.setValueS32("right", right);
+ message.setValueS32("bottom", bottom);
- message.setValueReal("current_time", mCurTime);
- message.setValueReal("duration", mDuration);
- message.setValueReal("current_rate", 1.0f);
+ message.setValueReal("current_time", mCurTime);
+ message.setValueReal("duration", mDuration);
+ message.setValueReal("current_rate", 1.0f);
- sendMessage(message);
+ sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
@@ -231,363 +231,363 @@ void MediaPluginLibVLC::setDurationDirty()
//
void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
{
- MediaPluginLibVLC* parent = (MediaPluginLibVLC*)ptr;
- if (parent == 0)
- {
- return;
- }
-
- switch (event->type)
- {
- case libvlc_MediaPlayerOpening:
- parent->mVlcStatus = STATUS_LOADING;
- break;
-
- case libvlc_MediaPlayerPlaying:
- parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
- parent->mVlcStatus = STATUS_PLAYING;
- parent->setVolumeVLC();
+ MediaPluginLibVLC* parent = (MediaPluginLibVLC*)ptr;
+ if (parent == 0)
+ {
+ return;
+ }
+
+ switch (event->type)
+ {
+ case libvlc_MediaPlayerOpening:
+ parent->mVlcStatus = STATUS_LOADING;
+ break;
+
+ case libvlc_MediaPlayerPlaying:
+ parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
+ parent->mVlcStatus = STATUS_PLAYING;
+ parent->setVolumeVLC();
parent->setDurationDirty();
- break;
+ break;
- case libvlc_MediaPlayerPaused:
- parent->mVlcStatus = STATUS_PAUSED;
- break;
+ case libvlc_MediaPlayerPaused:
+ parent->mVlcStatus = STATUS_PAUSED;
+ break;
- case libvlc_MediaPlayerStopped:
- parent->mVlcStatus = STATUS_DONE;
- break;
+ case libvlc_MediaPlayerStopped:
+ parent->mVlcStatus = STATUS_DONE;
+ break;
- case libvlc_MediaPlayerEndReached:
- parent->mVlcStatus = STATUS_DONE;
+ case libvlc_MediaPlayerEndReached:
+ parent->mVlcStatus = STATUS_DONE;
parent->mCurTime = parent->mDuration;
parent->setDurationDirty();
- break;
+ break;
- case libvlc_MediaPlayerEncounteredError:
- parent->mVlcStatus = STATUS_ERROR;
- break;
+ case libvlc_MediaPlayerEncounteredError:
+ parent->mVlcStatus = STATUS_ERROR;
+ break;
- case libvlc_MediaPlayerTimeChanged:
- parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
+ case libvlc_MediaPlayerTimeChanged:
+ parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
if (parent->mVlcStatus == STATUS_DONE && libvlc_media_player_is_playing(parent->mLibVLCMediaPlayer))
{
parent->mVlcStatus = STATUS_PLAYING;
}
parent->setDurationDirty();
- break;
+ break;
- case libvlc_MediaPlayerPositionChanged:
- break;
+ case libvlc_MediaPlayerPositionChanged:
+ break;
- case libvlc_MediaPlayerLengthChanged:
- parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
+ case libvlc_MediaPlayerLengthChanged:
+ parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
parent->setDurationDirty();
- break;
-
- case libvlc_MediaPlayerTitleChanged:
- {
- char* title = libvlc_media_get_meta(parent->mLibVLCMedia, libvlc_meta_Title);
- if (title)
- {
- parent->updateTitle(title);
- }
- }
- break;
- }
+ break;
+
+ case libvlc_MediaPlayerTitleChanged:
+ {
+ char* title = libvlc_media_get_meta(parent->mLibVLCMedia, libvlc_meta_Title);
+ if (title)
+ {
+ parent->updateTitle(title);
+ }
+ }
+ break;
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::playMedia()
{
- if (mURL.length() == 0)
- {
- return;
- }
-
- // A new call to play the media is received after the initial one. Typically
- // this is due to a size change request either as the media naturally resizes
- // to the size of the prim container, or else, as a 2D window is resized by the
- // user. Stopping the media, helps avoid a race condition where the media pixel
- // buffer size is out of sync with the declared size (width/height) for a frame
- // or two and the plugin crashes as VLC tries to decode a frame into unallocated
- // memory.
- if (mLibVLCMediaPlayer)
- {
- libvlc_media_player_stop(mLibVLCMediaPlayer);
- }
-
- mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str());
- if (!mLibVLCMedia)
- {
- mLibVLCMediaPlayer = 0;
- setStatus(STATUS_ERROR);
- return;
- }
-
- mLibVLCMediaPlayer = libvlc_media_player_new_from_media(mLibVLCMedia);
- if (!mLibVLCMediaPlayer)
- {
- setStatus(STATUS_ERROR);
- return;
- }
-
- // listen to events
- libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
- if (em)
- {
- libvlc_event_attach(em, libvlc_MediaPlayerOpening, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerPlaying, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerPaused, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerStopped, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerEndReached, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, this);
- libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this);
- }
-
- libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext);
- libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth);
-
- mLibVLCCallbackContext.parent = this;
- mLibVLCCallbackContext.texture_pixels = mPixels;
- mLibVLCCallbackContext.mp = mLibVLCMediaPlayer;
-
- // Send a "navigate begin" event.
- // This is really a browser message but the QuickTime plugin did it and
- // the media system relies on this message to update internal state so we must send it too
- // Note: see "navigate_complete" message below too
- // https://jira.secondlife.com/browse/MAINT-6528
- LLPluginMessage message_begin(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
- message_begin.setValue("uri", mURL);
- message_begin.setValueBoolean("history_back_available", false);
- message_begin.setValueBoolean("history_forward_available", false);
- sendMessage(message_begin);
-
- // volume level gets set before VLC is initialized (thanks media system) so we have to record
- // it in mCurVolume and set it again here so that volume levels are correctly initialized
- setVolume(mCurVolume);
-
- setStatus(STATUS_LOADED);
-
- // note this relies on the "set_loop" message arriving before the "start" (play) one
- // but that appears to always be the case
- if (mIsLooping)
- {
- libvlc_media_add_option(mLibVLCMedia, "input-repeat=65535");
- }
-
- libvlc_media_player_play(mLibVLCMediaPlayer);
-
- // send a "location_changed" message - this informs the media system
- // that a new URL is the 'current' one and is used extensively.
- // Again, this is really a browser message but we will use it here.
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
- message.setValue("uri", mURL);
- sendMessage(message);
-
- // Send a "navigate complete" event.
- // This is really a browser message but the QuickTime plugin did it and
- // the media system relies on this message to update internal state so we must send it too
- // Note: see "navigate_begin" message above too
- // https://jira.secondlife.com/browse/MAINT-6528
- LLPluginMessage message_complete(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
- message_complete.setValue("uri", mURL);
- message_complete.setValueS32("result_code", 200);
- message_complete.setValue("result_string", "OK");
- sendMessage(message_complete);
+ if (mURL.length() == 0)
+ {
+ return;
+ }
+
+ // A new call to play the media is received after the initial one. Typically
+ // this is due to a size change request either as the media naturally resizes
+ // to the size of the prim container, or else, as a 2D window is resized by the
+ // user. Stopping the media, helps avoid a race condition where the media pixel
+ // buffer size is out of sync with the declared size (width/height) for a frame
+ // or two and the plugin crashes as VLC tries to decode a frame into unallocated
+ // memory.
+ if (mLibVLCMediaPlayer)
+ {
+ libvlc_media_player_stop(mLibVLCMediaPlayer);
+ }
+
+ mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str());
+ if (!mLibVLCMedia)
+ {
+ mLibVLCMediaPlayer = 0;
+ setStatus(STATUS_ERROR);
+ return;
+ }
+
+ mLibVLCMediaPlayer = libvlc_media_player_new_from_media(mLibVLCMedia);
+ if (!mLibVLCMediaPlayer)
+ {
+ setStatus(STATUS_ERROR);
+ return;
+ }
+
+ // listen to events
+ libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
+ if (em)
+ {
+ libvlc_event_attach(em, libvlc_MediaPlayerOpening, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerPlaying, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerPaused, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerStopped, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerEndReached, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, this);
+ libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this);
+ }
+
+ libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext);
+ libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth);
+
+ mLibVLCCallbackContext.parent = this;
+ mLibVLCCallbackContext.texture_pixels = mPixels;
+ mLibVLCCallbackContext.mp = mLibVLCMediaPlayer;
+
+ // Send a "navigate begin" event.
+ // This is really a browser message but the QuickTime plugin did it and
+ // the media system relies on this message to update internal state so we must send it too
+ // Note: see "navigate_complete" message below too
+ // https://jira.secondlife.com/browse/MAINT-6528
+ LLPluginMessage message_begin(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+ message_begin.setValue("uri", mURL);
+ message_begin.setValueBoolean("history_back_available", false);
+ message_begin.setValueBoolean("history_forward_available", false);
+ sendMessage(message_begin);
+
+ // volume level gets set before VLC is initialized (thanks media system) so we have to record
+ // it in mCurVolume and set it again here so that volume levels are correctly initialized
+ setVolume(mCurVolume);
+
+ setStatus(STATUS_LOADED);
+
+ // note this relies on the "set_loop" message arriving before the "start" (play) one
+ // but that appears to always be the case
+ if (mIsLooping)
+ {
+ libvlc_media_add_option(mLibVLCMedia, "input-repeat=65535");
+ }
+
+ libvlc_media_player_play(mLibVLCMediaPlayer);
+
+ // send a "location_changed" message - this informs the media system
+ // that a new URL is the 'current' one and is used extensively.
+ // Again, this is really a browser message but we will use it here.
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+ message.setValue("uri", mURL);
+ sendMessage(message);
+
+ // Send a "navigate complete" event.
+ // This is really a browser message but the QuickTime plugin did it and
+ // the media system relies on this message to update internal state so we must send it too
+ // Note: see "navigate_begin" message above too
+ // https://jira.secondlife.com/browse/MAINT-6528
+ LLPluginMessage message_complete(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+ message_complete.setValue("uri", mURL);
+ message_complete.setValueS32("result_code", 200);
+ message_complete.setValue("result_string", "OK");
+ sendMessage(message_complete);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::updateTitle(const char* title)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", title);
- sendMessage(message);
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", title);
+ sendMessage(message);
}
void MediaPluginLibVLC::setVolumeVLC()
{
- if (mLibVLCMediaPlayer)
- {
- int vlc_vol = (int)(mCurVolume * 100);
-
- int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, vlc_vol);
- if (result == 0)
- {
- // volume change was accepted by LibVLC
- }
- else
- {
- // volume change was NOT accepted by LibVLC and not actioned
- }
+ if (mLibVLCMediaPlayer)
+ {
+ int vlc_vol = (int)(mCurVolume * 100);
+
+ int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, vlc_vol);
+ if (result == 0)
+ {
+ // volume change was accepted by LibVLC
+ }
+ else
+ {
+ // volume change was NOT accepted by LibVLC and not actioned
+ }
#if LL_WINDOWS
- // https ://jira.secondlife.com/browse/MAINT-8119
- // CEF media plugin uses code in media_plugins/cef/windows_volume_catcher.cpp to
- // set the actual output volume of the plugin process since there is no API in
- // CEF to otherwise do this.
- // There are explicit calls to change the volume in LibVLC but sometimes they
- // are ignored SLPlugin.exe process volume is set to 0 so you never heard audio
- // from the VLC media stream.
- // The right way to solve this is to move the volume catcher stuff out of
- // the CEF plugin and into it's own folder under media_plugins and have it referenced
- // by both CEF and VLC. That's for later. The code there boils down to this so for
+ // https ://jira.secondlife.com/browse/MAINT-8119
+ // CEF media plugin uses code in media_plugins/cef/windows_volume_catcher.cpp to
+ // set the actual output volume of the plugin process since there is no API in
+ // CEF to otherwise do this.
+ // There are explicit calls to change the volume in LibVLC but sometimes they
+ // are ignored SLPlugin.exe process volume is set to 0 so you never heard audio
+ // from the VLC media stream.
+ // The right way to solve this is to move the volume catcher stuff out of
+ // the CEF plugin and into it's own folder under media_plugins and have it referenced
+ // by both CEF and VLC. That's for later. The code there boils down to this so for
// now, as we approach a release, the less risky option is to do it directly vs
// calls to volume catcher code.
- DWORD left_channel = (DWORD)(mCurVolume * 65535.0f);
- DWORD right_channel = (DWORD)(mCurVolume * 65535.0f);
- DWORD hw_volume = left_channel << 16 | right_channel;
- waveOutSetVolume(NULL, hw_volume);
+ DWORD left_channel = (DWORD)(mCurVolume * 65535.0f);
+ DWORD right_channel = (DWORD)(mCurVolume * 65535.0f);
+ DWORD hw_volume = left_channel << 16 | right_channel;
+ waveOutSetVolume(NULL, hw_volume);
#endif
- }
- else
- {
- // volume change was requested but VLC wasn't ready.
- // that's okay though because we saved the value in mCurVolume and
- // the next volume change after the VLC system is initilzied will set it
- }
+ }
+ else
+ {
+ // volume change was requested but VLC wasn't ready.
+ // that's okay though because we saved the value in mCurVolume and
+ // the next volume change after the VLC system is initilzied will set it
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::setVolume(const F64 volume)
{
- mCurVolume = volume;
+ mCurVolume = volume;
- setVolumeVLC();
+ setVolumeVLC();
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::receiveMessage(const char* message_string)
{
- LLPluginMessage message_in;
-
- if (message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if (message_name == "init")
- {
- initVLC();
-
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
- message.setValueLLSD("versions", versions);
-
- std::ostringstream s;
- s << "LibVLC plugin ";
- s << LIBVLC_VERSION_MAJOR;
- s << ".";
- s << LIBVLC_VERSION_MINOR;
- s << ".";
- s << LIBVLC_VERSION_REVISION;
-
- message.setValue("plugin_version", s.str());
- sendMessage(message);
- }
- else if (message_name == "idle")
- {
- setStatus(mVlcStatus);
- }
- else if (message_name == "cleanup")
- {
- resetVLC();
- }
- else if (message_name == "force_exit")
- {
- mDeleteMe = true;
- }
- else if (message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
- }
- else if (message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- if (mPixels == iter->second.mAddress)
- {
- libvlc_media_player_stop(mLibVLCMediaPlayer);
- libvlc_media_player_release(mLibVLCMediaPlayer);
- mLibVLCMediaPlayer = 0;
-
- mPixels = NULL;
- mTextureSegmentName.clear();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
- //std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
- }
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
- //std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
- }
- }
- else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if (message_name == "init")
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- message.setValueS32("default_width", 1024);
- message.setValueS32("default_height", 1024);
- message.setValueS32("depth", mDepth);
- message.setValueU32("internalformat", GL_RGB);
- message.setValueU32("format", GL_BGRA_EXT);
- message.setValueU32("type", GL_UNSIGNED_BYTE);
- message.setValueBoolean("coords_opengl", true);
- sendMessage(message);
- }
- else if (message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
-
- if (!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if (iter != mSharedSegments.end())
- {
- mPixels = (unsigned char*)iter->second.mAddress;
- mWidth = width;
- mHeight = height;
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
+ LLPluginMessage message_in;
+
+ if (message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if (message_name == "init")
+ {
+ initVLC();
+
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ std::ostringstream s;
+ s << "LibVLC plugin ";
+ s << LIBVLC_VERSION_MAJOR;
+ s << ".";
+ s << LIBVLC_VERSION_MINOR;
+ s << ".";
+ s << LIBVLC_VERSION_REVISION;
+
+ message.setValue("plugin_version", s.str());
+ sendMessage(message);
+ }
+ else if (message_name == "idle")
+ {
+ setStatus(mVlcStatus);
+ }
+ else if (message_name == "cleanup")
+ {
+ resetVLC();
+ }
+ else if (message_name == "force_exit")
+ {
+ mDeleteMe = true;
+ }
+ else if (message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+ }
+ else if (message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ if (mPixels == iter->second.mAddress)
+ {
+ libvlc_media_player_stop(mLibVLCMediaPlayer);
+ libvlc_media_player_release(mLibVLCMediaPlayer);
+ mLibVLCMediaPlayer = 0;
+
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+ //std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+ //std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+ }
+ }
+ else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if (message_name == "init")
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ message.setValueS32("default_width", 1024);
+ message.setValueS32("default_height", 1024);
+ message.setValueS32("depth", mDepth);
+ message.setValueU32("internalformat", GL_RGB);
+ message.setValueU32("format", GL_BGRA_EXT);
+ message.setValueU32("type", GL_UNSIGNED_BYTE);
+ message.setValueBoolean("coords_opengl", true);
+ sendMessage(message);
+ }
+ else if (message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ if (!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if (iter != mSharedSegments.end())
+ {
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mWidth = width;
+ mHeight = height;
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
libvlc_time_t time = 1000.0 * mCurTime;
- playMedia();
+ playMedia();
if (mLibVLCMediaPlayer)
{
@@ -603,37 +603,37 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
mCurTime = (F64)time / 1000.0;
}
}
- };
- };
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
- }
- else if (message_name == "load_uri")
- {
- mURL = message_in.getValue("uri");
- playMedia();
- }
- }
- else
- if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
- {
- if (message_name == "stop")
- {
- if (mLibVLCMediaPlayer)
- {
- libvlc_media_player_stop(mLibVLCMediaPlayer);
- }
- }
- else if (message_name == "start")
- {
- if (mLibVLCMediaPlayer)
- {
+ };
+ };
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+ }
+ else if (message_name == "load_uri")
+ {
+ mURL = message_in.getValue("uri");
+ playMedia();
+ }
+ }
+ else
+ if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+ {
+ if (message_name == "stop")
+ {
+ if (mLibVLCMediaPlayer)
+ {
+ libvlc_media_player_stop(mLibVLCMediaPlayer);
+ }
+ }
+ else if (message_name == "start")
+ {
+ if (mLibVLCMediaPlayer)
+ {
if (mVlcStatus == STATUS_DONE && !libvlc_media_player_is_playing(mLibVLCMediaPlayer))
{
// stop or vlc will ignore 'play', it will just
@@ -641,18 +641,18 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
// seek was used
libvlc_media_player_stop(mLibVLCMediaPlayer);
}
- libvlc_media_player_play(mLibVLCMediaPlayer);
- }
- }
- else if (message_name == "pause")
- {
- if (mLibVLCMediaPlayer)
- {
- libvlc_media_player_set_pause(mLibVLCMediaPlayer, 1);
- }
- }
- else if (message_name == "seek")
- {
+ libvlc_media_player_play(mLibVLCMediaPlayer);
+ }
+ }
+ else if (message_name == "pause")
+ {
+ if (mLibVLCMediaPlayer)
+ {
+ libvlc_media_player_set_pause(mLibVLCMediaPlayer, 1);
+ }
+ }
+ else if (message_name == "seek")
+ {
if (mLibVLCMediaPlayer)
{
libvlc_time_t time = 1000.0 * message_in.getValueReal("time");
@@ -674,43 +674,43 @@ void MediaPluginLibVLC::receiveMessage(const char* message_string)
setDurationDirty();
}
}
- }
- else if (message_name == "set_loop")
- {
- bool loop = message_in.getValueBoolean("loop");
- mIsLooping = loop;
- }
- else if (message_name == "set_volume")
- {
- // volume comes in 0 -> 1.0
- F64 volume = message_in.getValueReal("volume");
- setVolume(volume);
- }
- }
- }
+ }
+ else if (message_name == "set_loop")
+ {
+ bool loop = message_in.getValueBoolean("loop");
+ mIsLooping = loop;
+ }
+ else if (message_name == "set_volume")
+ {
+ // volume comes in 0 -> 1.0
+ F64 volume = message_in.getValueReal("volume");
+ setVolume(volume);
+ }
+ }
+ }
}
////////////////////////////////////////////////////////////////////////////////
//
bool MediaPluginLibVLC::init()
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", "LibVLC Plugin");
- sendMessage(message);
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", "LibVLC Plugin");
+ sendMessage(message);
- return true;
+ return true;
};
////////////////////////////////////////////////////////////////////////////////
//
int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
- void* host_user_data,
- LLPluginInstance::sendMessageFunction *plugin_send_func,
- void **plugin_user_data)
+ void* host_user_data,
+ LLPluginInstance::sendMessageFunction *plugin_send_func,
+ void **plugin_user_data)
{
- MediaPluginLibVLC* self = new MediaPluginLibVLC(host_send_func, host_user_data);
- *plugin_send_func = MediaPluginLibVLC::staticReceiveMessage;
- *plugin_user_data = (void*)self;
+ MediaPluginLibVLC* self = new MediaPluginLibVLC(host_send_func, host_user_data);
+ *plugin_send_func = MediaPluginLibVLC::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
- return 0;
+ return 0;
}