diff options
Diffstat (limited to 'indra/media_plugins')
-rw-r--r-- | indra/media_plugins/CMakeLists.txt | 7 | ||||
-rw-r--r-- | indra/media_plugins/cef/media_plugin_cef.cpp | 62 | ||||
-rw-r--r-- | indra/media_plugins/libvlc/CMakeLists.txt | 86 | ||||
-rw-r--r-- | indra/media_plugins/libvlc/media_plugin_libvlc.cpp | 398 | ||||
-rwxr-xr-x[-rw-r--r--] | indra/media_plugins/quicktime/CMakeLists.txt | 10 | ||||
-rwxr-xr-x[-rw-r--r--] | indra/media_plugins/quicktime/media_plugin_quicktime.cpp | 13 |
6 files changed, 555 insertions, 21 deletions
diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 24eb3947b4..9055e0111a 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -4,15 +4,18 @@ add_subdirectory(base) if (LINUX) add_subdirectory(gstreamer010) + add_subdirectory(libvlc) endif (LINUX) -if (WINDOWS OR DARWIN) +if (DARWIN) add_subdirectory(quicktime) add_subdirectory(cef) -endif (WINDOWS OR DARWIN) +endif (DARWIN) if (WINDOWS) + add_subdirectory(cef) add_subdirectory(winmmshim) + add_subdirectory(libvlc) endif (WINDOWS) ### add_subdirectory(example) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 8d9d1dd975..be16ff7946 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -100,6 +100,12 @@ private: LLCEFLib* mLLCEFLib; VolumeCatcher mVolumeCatcher; + + U8 *mPopupBuffer; + U32 mPopupW; + U32 mPopupH; + U32 mPopupX; + U32 mPopupY; }; //////////////////////////////////////////////////////////////////////////////// @@ -127,12 +133,19 @@ MediaPluginBase(host_send_func, host_user_data) mCookiePath = ""; mPickedFile = ""; mLLCEFLib = new LLCEFLib(); + + mPopupBuffer = NULL; + mPopupW = 0; + mPopupH = 0; + mPopupX = 0; + mPopupY = 0; } //////////////////////////////////////////////////////////////////////////////// // MediaPluginCEF::~MediaPluginCEF() { + delete[] mPopupBuffer; } //////////////////////////////////////////////////////////////////////////////// @@ -155,20 +168,28 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg) // void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup) { - if (mPixels && pixels) + if( is_popup ) + { + delete mPopupBuffer; + mPopupBuffer = NULL; + mPopupH = 0; + mPopupW = 0; + mPopupX = 0; + mPopupY = 0; + } + + if( mPixels && pixels ) { if (is_popup) { - for (int line = 0; line < height; ++line) + if( width > 0 && height> 0 ) { - int inverted_y = mHeight - y - height; - int src = line * width * mDepth; - int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth; - - if (dst + width * mDepth < mWidth * mHeight * mDepth) - { - memcpy(mPixels + dst, pixels + src, width * mDepth); - } + mPopupBuffer = new U8[ width * height * mDepth ]; + memcpy( mPopupBuffer, pixels, width * height * mDepth ); + mPopupH = height; + mPopupW = width; + mPopupX = x; + mPopupY = y; } } else @@ -177,6 +198,23 @@ void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, { memcpy(mPixels, pixels, mWidth * mHeight * mDepth); } + if( mPopupBuffer && mPopupH && mPopupW ) + { + U32 bufferSize = mWidth * mHeight * mDepth; + U32 popupStride = mPopupW * mDepth; + U32 bufferStride = mWidth * mDepth; + int dstY = mPopupY; + + int src = 0; + int dst = dstY * mWidth * mDepth + mPopupX * mDepth; + + for( int line = 0; dst + popupStride < bufferSize && line < mPopupH; ++line ) + { + memcpy( mPixels + dst, mPopupBuffer + src, popupStride ); + src += popupStride; + dst += bufferStride; + } + } } setDirty(0, 0, mWidth, mHeight); @@ -488,7 +526,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) message.setValueU32("internalformat", GL_RGB); message.setValueU32("format", GL_BGRA); message.setValueU32("type", GL_UNSIGNED_BYTE); - message.setValueBoolean("coords_opengl", true); + message.setValueBoolean("coords_opengl", false); sendMessage(message); } else if (message_name == "set_user_data_path") @@ -559,6 +597,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string) S32 x = message_in.getValueS32("x"); S32 y = message_in.getValueS32("y"); + y = mHeight - y; + // only even send left mouse button events to LLCEFLib // (partially prompted by crash in OS X CEF when sending right button events) // we catch the right click in viewer and display our own context menu anyway diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt new file mode 100644 index 0000000000..535d29125b --- /dev/null +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -0,0 +1,86 @@ +# -*- cmake -*- + +project(media_plugin_libvlc) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(OpenGL) + +include(LibVLCPlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${VLC_INCLUDE_DIR} +) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ) + + +### media_plugin_libvlc + +if(NOT WORD_SIZE EQUAL 32) + if(WINDOWS) + add_definitions(/FIXED:NO) + else(WINDOWS) # not windows therefore gcc LINUX and DARWIN + add_definitions(-fPIC) + endif(WINDOWS) +endif(NOT WORD_SIZE EQUAL 32) + +set(media_plugin_libvlc_SOURCE_FILES + media_plugin_libvlc.cpp + ) + +add_library(media_plugin_libvlc + SHARED + ${media_plugin_libvlc_SOURCE_FILES} +) + +target_link_libraries(media_plugin_libvlc + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${VLC_PLUGIN_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_libvlc + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (WINDOWS) + set_target_properties( + media_plugin_libvlc + PROPERTIES + LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT" + ) +endif (WINDOWS) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_libvlc + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + +endif (DARWIN) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp new file mode 100644 index 0000000000..3852d10c44 --- /dev/null +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -0,0 +1,398 @@ +/** + * @file media_plugin_libvlc.cpp + * @brief LibVLC 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 "llgl.h" +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#include "vlc/vlc.h" +#include "vlc/libvlc_version.h" + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginLibVLC : + public MediaPluginBase +{ + public: + MediaPluginLibVLC( LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data ); + ~MediaPluginLibVLC(); + + /*virtual*/ void receiveMessage( const char* message_string ); + + private: + bool init(); + + void initVLC(); + void playMedia(); + void resetVLC(); + + 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); + + libvlc_instance_t* gLibVLC; + libvlc_media_t* gLibVLCMedia; + libvlc_media_player_t* gLibVLCMediaPlayer; + + struct gVLCContext + { + unsigned char* texture_pixels; + libvlc_media_player_t* mp; + MediaPluginLibVLC* parent; + }; + struct gVLCContext gVLCCallbackContext; + + std::string mURL; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +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; + + gLibVLC = 0; + gLibVLCMedia = 0; + gLibVLCMediaPlayer = 0; + + mURL = std::string(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginLibVLC::~MediaPluginLibVLC() +{ +} + +///////////////////////////////////////////////////////////////////////////////// +// +void* MediaPluginLibVLC::lock(void* data, void** p_pixels) +{ + struct gVLCContext* context = (gVLCContext*)data; + + *p_pixels = context->texture_pixels; + + return NULL; +} + +///////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::unlock(void* data, void* id, void* const* raw_pixels) +{ + // nothing to do here for the moment. + // we can modify the raw_pixels here if we want to. +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::display(void* data, void* id) +{ + struct gVLCContext* context = (gVLCContext*)data; + + context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::initVLC() +{ + char const* vlc_argv[] = + { + "--no-xlib", + }; + + int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); + gLibVLC = libvlc_new(vlc_argc, vlc_argv); + + if (!gLibVLC) + { + // 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(gLibVLCMediaPlayer); + libvlc_media_player_release(gLibVLCMediaPlayer); + libvlc_release(gLibVLC); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginLibVLC::playMedia() +{ + if (mURL.length() == 0) + { + return; + } + + if (gLibVLCMediaPlayer) + { + libvlc_media_player_stop(gLibVLCMediaPlayer); + libvlc_media_player_release(gLibVLCMediaPlayer); + } + + gLibVLCMedia = libvlc_media_new_location(gLibVLC, mURL.c_str()); + if (!gLibVLCMedia) + { + gLibVLCMediaPlayer = 0; + return; + } + + gLibVLCMediaPlayer = libvlc_media_player_new_from_media(gLibVLCMedia); + if (!gLibVLCMediaPlayer) + { + return; + } + + libvlc_media_release(gLibVLCMedia); + + gVLCCallbackContext.parent = this; + gVLCCallbackContext.texture_pixels = mPixels; + gVLCCallbackContext.mp = gLibVLCMediaPlayer; + + libvlc_video_set_callbacks(gLibVLCMediaPlayer, lock, unlock, display, &gVLCCallbackContext); + libvlc_video_set_format(gLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth); + libvlc_media_player_play(gLibVLCMediaPlayer); +} + +//////////////////////////////////////////////////////////////////////////////// +// +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_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_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") + { + } + else if(message_name == "cleanup") + { + resetVLC(); + } + 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(gLibVLCMediaPlayer); + libvlc_media_player_release(gLibVLCMediaPlayer); + gLibVLCMediaPlayer = 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", false); + 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; + + playMedia(); + }; + }; + + 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 (gLibVLCMediaPlayer) + { + libvlc_media_player_stop(gLibVLCMediaPlayer); + } + } + else if (message_name == "start") + { + if (gLibVLCMediaPlayer) + { + libvlc_media_player_play(gLibVLCMediaPlayer); + } + } + else if (message_name == "pause") + { + if (gLibVLCMediaPlayer) + { + libvlc_media_player_pause(gLibVLCMediaPlayer); + } + } + else if (message_name == "seek") + { + } + else if (message_name == "set_loop") + { + } + else if (message_name == "set_volume") + { + if (gLibVLCMediaPlayer) + { + F64 volume = message_in.getValueReal("volume"); + libvlc_audio_set_volume(gLibVLCMediaPlayer, (int)(volume * 100)); + } + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginLibVLC::init() +{ + LLPluginMessage message( LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text" ); + message.setValue( "name", "LibVLC 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 ) +{ + MediaPluginLibVLC* self = new MediaPluginLibVLC( host_send_func, host_user_data ); + *plugin_send_func = MediaPluginLibVLC::staticReceiveMessage; + *plugin_user_data = ( void* )self; + + return 0; +} diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt index c5615145be..58391007ff 100644..100755 --- a/indra/media_plugins/quicktime/CMakeLists.txt +++ b/indra/media_plugins/quicktime/CMakeLists.txt @@ -14,7 +14,6 @@ include(PluginAPI) include(MediaPluginBase) include(OpenGL) include(QuickTimePlugin) -include(Boost) include_directories( ${LLPLUGIN_INCLUDE_DIRS} @@ -54,12 +53,17 @@ target_link_libraries(media_plugin_quicktime ${PLUGIN_API_WINDOWS_LIBRARIES} ) +add_dependencies(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + if (WINDOWS) set_target_properties( media_plugin_quicktime PROPERTIES - LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD" + LINK_FLAGS "/MANIFEST:NO" ) endif (WINDOWS) diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index 7ef5a0fe44..6d4c6ca43d 100644..100755 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -311,7 +311,9 @@ private: MatrixRecord transform; SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix double scaleX = (double) mWidth / mNaturalWidth; - double scaleY = -1.0 * (double) mHeight / mNaturalHeight; + + // 2016-05-31 CP remove local flip (via -1.0) since texture coods for media on a prim are now flipped for VLC/CEF + double scaleY = 1.0 * (double) mHeight / mNaturalHeight; double centerX = mWidth / 2.0; double centerY = mHeight / 2.0; ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) ); @@ -837,9 +839,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) else if(message_name == "cleanup") { // TODO: clean up here - LLPluginMessage message("base", "goodbye"); - sendMessage(message); - } + } else if(message_name == "shm_added") { SharedSegmentInfo info; @@ -921,7 +921,10 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) #endif message.setValueS32("depth", mDepth); message.setValueU32("internalformat", GL_RGB); - message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + + // note this apparently only has an effect when media is opened in 2D browser. + // see https://jira.secondlife.com/browse/BUG-18252 - media flipped in 2D so flipping it back. + message.setValueBoolean("coords_opengl", false); // true == use OpenGL-style coordinates, false == (0,0) is upper left. message.setValueBoolean("allow_downsample", true); sendMessage(message); } |