diff options
10 files changed, 358 insertions, 103 deletions
diff --git a/linden/indra/media_plugins/base/media_plugin_base.cpp b/linden/indra/media_plugins/base/media_plugin_base.cpp index 1919419..4d5e374 100644 --- a/linden/indra/media_plugins/base/media_plugin_base.cpp +++ b/linden/indra/media_plugins/base/media_plugin_base.cpp | |||
@@ -2,6 +2,8 @@ | |||
2 | * @file media_plugin_base.cpp | 2 | * @file media_plugin_base.cpp |
3 | * @brief Media plugin base class for LLMedia API plugin system | 3 | * @brief Media plugin base class for LLMedia API plugin system |
4 | * | 4 | * |
5 | * All plugins should be a subclass of MediaPluginBase. | ||
6 | * | ||
5 | * $LicenseInfo:firstyear=2008&license=viewergpl$ | 7 | * $LicenseInfo:firstyear=2008&license=viewergpl$ |
6 | * | 8 | * |
7 | * Copyright (c) 2008-2009, Linden Research, Inc. | 9 | * Copyright (c) 2008-2009, Linden Research, Inc. |
@@ -36,7 +38,10 @@ | |||
36 | 38 | ||
37 | // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint | 39 | // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint |
38 | //////////////////////////////////////////////////////////////////////////////// | 40 | //////////////////////////////////////////////////////////////////////////////// |
39 | // | 41 | /// Media plugin constructor. |
42 | /// | ||
43 | /// @param[in] host_send_func Function for sending messages from plugin to plugin loader shell | ||
44 | /// @param[in] host_user_data Message data for messages from plugin to plugin loader shell | ||
40 | 45 | ||
41 | MediaPluginBase::MediaPluginBase( | 46 | MediaPluginBase::MediaPluginBase( |
42 | LLPluginInstance::sendMessageFunction host_send_func, | 47 | LLPluginInstance::sendMessageFunction host_send_func, |
@@ -54,6 +59,12 @@ MediaPluginBase::MediaPluginBase( | |||
54 | mStatus = STATUS_NONE; | 59 | mStatus = STATUS_NONE; |
55 | } | 60 | } |
56 | 61 | ||
62 | /** | ||
63 | * Converts current media status enum value into string (STATUS_LOADING into "loading", etc.) | ||
64 | * | ||
65 | * @return Media status string ("loading", "playing", "paused", etc) | ||
66 | * | ||
67 | */ | ||
57 | std::string MediaPluginBase::statusString() | 68 | std::string MediaPluginBase::statusString() |
58 | { | 69 | { |
59 | std::string result; | 70 | std::string result; |
@@ -65,6 +76,7 @@ std::string MediaPluginBase::statusString() | |||
65 | case STATUS_ERROR: result = "error"; break; | 76 | case STATUS_ERROR: result = "error"; break; |
66 | case STATUS_PLAYING: result = "playing"; break; | 77 | case STATUS_PLAYING: result = "playing"; break; |
67 | case STATUS_PAUSED: result = "paused"; break; | 78 | case STATUS_PAUSED: result = "paused"; break; |
79 | case STATUS_DONE: result = "done"; break; | ||
68 | default: | 80 | default: |
69 | // keep the empty string | 81 | // keep the empty string |
70 | break; | 82 | break; |
@@ -73,6 +85,12 @@ std::string MediaPluginBase::statusString() | |||
73 | return result; | 85 | return result; |
74 | } | 86 | } |
75 | 87 | ||
88 | /** | ||
89 | * Set media status. | ||
90 | * | ||
91 | * @param[in] status Media status (STATUS_LOADING, STATUS_PLAYING, STATUS_PAUSED, etc) | ||
92 | * | ||
93 | */ | ||
76 | void MediaPluginBase::setStatus(EStatus status) | 94 | void MediaPluginBase::setStatus(EStatus status) |
77 | { | 95 | { |
78 | if(mStatus != status) | 96 | if(mStatus != status) |
@@ -83,6 +101,13 @@ void MediaPluginBase::setStatus(EStatus status) | |||
83 | } | 101 | } |
84 | 102 | ||
85 | 103 | ||
104 | /** | ||
105 | * Receive message from plugin loader shell. | ||
106 | * | ||
107 | * @param[in] message_string Message string | ||
108 | * @param[in] user_data Message data | ||
109 | * | ||
110 | */ | ||
86 | void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data) | 111 | void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data) |
87 | { | 112 | { |
88 | MediaPluginBase *self = (MediaPluginBase*)*user_data; | 113 | MediaPluginBase *self = (MediaPluginBase*)*user_data; |
@@ -100,12 +125,27 @@ void MediaPluginBase::staticReceiveMessage(const char *message_string, void **us | |||
100 | } | 125 | } |
101 | } | 126 | } |
102 | 127 | ||
128 | /** | ||
129 | * Send message to plugin loader shell. | ||
130 | * | ||
131 | * @param[in] message Message data being sent to plugin loader shell | ||
132 | * | ||
133 | */ | ||
103 | void MediaPluginBase::sendMessage(const LLPluginMessage &message) | 134 | void MediaPluginBase::sendMessage(const LLPluginMessage &message) |
104 | { | 135 | { |
105 | std::string output = message.generate(); | 136 | std::string output = message.generate(); |
106 | mHostSendFunction(output.c_str(), &mHostUserData); | 137 | mHostSendFunction(output.c_str(), &mHostUserData); |
107 | } | 138 | } |
108 | 139 | ||
140 | /** | ||
141 | * Notifies plugin loader shell that part of display area needs to be redrawn. | ||
142 | * | ||
143 | * @param[in] left Left X coordinate of area to redraw (0,0 is at top left corner) | ||
144 | * @param[in] top Top Y coordinate of area to redraw (0,0 is at top left corner) | ||
145 | * @param[in] right Right X-coordinate of area to redraw (0,0 is at top left corner) | ||
146 | * @param[in] bottom Bottom Y-coordinate of area to redraw (0,0 is at top left corner) | ||
147 | * | ||
148 | */ | ||
109 | void MediaPluginBase::setDirty(int left, int top, int right, int bottom) | 149 | void MediaPluginBase::setDirty(int left, int top, int right, int bottom) |
110 | { | 150 | { |
111 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); | 151 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); |
@@ -118,6 +158,10 @@ void MediaPluginBase::setDirty(int left, int top, int right, int bottom) | |||
118 | sendMessage(message); | 158 | sendMessage(message); |
119 | } | 159 | } |
120 | 160 | ||
161 | /** | ||
162 | * Sends "media_status" message to plugin loader shell ("loading", "playing", "paused", etc.) | ||
163 | * | ||
164 | */ | ||
121 | void MediaPluginBase::sendStatus() | 165 | void MediaPluginBase::sendStatus() |
122 | { | 166 | { |
123 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status"); | 167 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status"); |
@@ -141,6 +185,17 @@ extern "C" | |||
141 | LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); | 185 | LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); |
142 | } | 186 | } |
143 | 187 | ||
188 | /** | ||
189 | * Plugin initialization and entry point. Establishes communication channel for messages between plugin and plugin loader shell. TODO:DOC - Please check! | ||
190 | * | ||
191 | * @param[in] host_send_func Function for sending messages from plugin to plugin loader shell | ||
192 | * @param[in] host_user_data Message data for messages from plugin to plugin loader shell | ||
193 | * @param[out] plugin_send_func Function for plugin to receive messages from plugin loader shell | ||
194 | * @param[out] plugin_user_data Pointer to plugin instance | ||
195 | * | ||
196 | * @return int, where 0=success | ||
197 | * | ||
198 | */ | ||
144 | LLSYMEXPORT int | 199 | LLSYMEXPORT int |
145 | LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) | 200 | LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) |
146 | { | 201 | { |
diff --git a/linden/indra/media_plugins/base/media_plugin_base.h b/linden/indra/media_plugins/base/media_plugin_base.h index 4872706..24198af 100644 --- a/linden/indra/media_plugins/base/media_plugin_base.h +++ b/linden/indra/media_plugins/base/media_plugin_base.h | |||
@@ -41,14 +41,17 @@ class MediaPluginBase | |||
41 | { | 41 | { |
42 | public: | 42 | public: |
43 | MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); | 43 | MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); |
44 | /** Media plugin destructor. */ | ||
44 | virtual ~MediaPluginBase() {} | 45 | virtual ~MediaPluginBase() {} |
45 | 46 | ||
47 | /** Handle received message from plugin loader shell. */ | ||
46 | virtual void receiveMessage(const char *message_string) = 0; | 48 | virtual void receiveMessage(const char *message_string) = 0; |
47 | 49 | ||
48 | static void staticReceiveMessage(const char *message_string, void **user_data); | 50 | static void staticReceiveMessage(const char *message_string, void **user_data); |
49 | 51 | ||
50 | protected: | 52 | protected: |
51 | 53 | ||
54 | /** Plugin status. */ | ||
52 | typedef enum | 55 | typedef enum |
53 | { | 56 | { |
54 | STATUS_NONE, | 57 | STATUS_NONE, |
@@ -57,12 +60,16 @@ protected: | |||
57 | STATUS_ERROR, | 60 | STATUS_ERROR, |
58 | STATUS_PLAYING, | 61 | STATUS_PLAYING, |
59 | STATUS_PAUSED, | 62 | STATUS_PAUSED, |
63 | STATUS_DONE | ||
60 | } EStatus; | 64 | } EStatus; |
61 | 65 | ||
66 | /** Plugin shared memory. */ | ||
62 | class SharedSegmentInfo | 67 | class SharedSegmentInfo |
63 | { | 68 | { |
64 | public: | 69 | public: |
70 | /** Shared memory address. */ | ||
65 | void *mAddress; | 71 | void *mAddress; |
72 | /** Shared memory size. */ | ||
66 | size_t mSize; | 73 | size_t mSize; |
67 | }; | 74 | }; |
68 | 75 | ||
@@ -71,42 +78,56 @@ protected: | |||
71 | std::string statusString(); | 78 | std::string statusString(); |
72 | void setStatus(EStatus status); | 79 | void setStatus(EStatus status); |
73 | 80 | ||
74 | // The quicktime plugin overrides this to add current time and duration to the message... | 81 | /// Note: The quicktime plugin overrides this to add current time and duration to the message. |
75 | virtual void setDirty(int left, int top, int right, int bottom); | 82 | virtual void setDirty(int left, int top, int right, int bottom); |
76 | 83 | ||
84 | /** Map of shared memory names to shared memory. */ | ||
77 | typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap; | 85 | typedef std::map<std::string, SharedSegmentInfo> SharedSegmentMap; |
78 | 86 | ||
79 | 87 | ||
88 | /** Function to send message from plugin to plugin loader shell. */ | ||
80 | LLPluginInstance::sendMessageFunction mHostSendFunction; | 89 | LLPluginInstance::sendMessageFunction mHostSendFunction; |
90 | /** Message data being sent to plugin loader shell by mHostSendFunction. */ | ||
81 | void *mHostUserData; | 91 | void *mHostUserData; |
92 | /** Flag to delete plugin instance (self). */ | ||
82 | bool mDeleteMe; | 93 | bool mDeleteMe; |
94 | /** 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. */ | ||
83 | unsigned char* mPixels; | 95 | unsigned char* mPixels; |
96 | /** 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 */ | ||
84 | std::string mTextureSegmentName; | 97 | std::string mTextureSegmentName; |
98 | /** Width of plugin display in pixels. */ | ||
85 | int mWidth; | 99 | int mWidth; |
100 | /** Height of plugin display in pixels. */ | ||
86 | int mHeight; | 101 | int mHeight; |
102 | /** Width of plugin texture. */ | ||
87 | int mTextureWidth; | 103 | int mTextureWidth; |
104 | /** Height of plugin texture. */ | ||
88 | int mTextureHeight; | 105 | int mTextureHeight; |
106 | /** Pixel depth (pixel size in bytes). */ | ||
89 | int mDepth; | 107 | int mDepth; |
108 | /** Current status of plugin. */ | ||
90 | EStatus mStatus; | 109 | EStatus mStatus; |
110 | /** Map of shared memory segments. */ | ||
91 | SharedSegmentMap mSharedSegments; | 111 | SharedSegmentMap mSharedSegments; |
92 | 112 | ||
93 | }; | 113 | }; |
94 | 114 | ||
95 | // The plugin must define this function to create its instance. | 115 | /** The plugin <b>must</b> define this function to create its instance. |
116 | * It should look something like this: | ||
117 | * @code | ||
118 | * { | ||
119 | * MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data); | ||
120 | * *plugin_send_func = MediaPluginFoo::staticReceiveMessage; | ||
121 | * *plugin_user_data = (void*)self; | ||
122 | * | ||
123 | * return 0; | ||
124 | * } | ||
125 | * @endcode | ||
126 | */ | ||
96 | int init_media_plugin( | 127 | int init_media_plugin( |
97 | LLPluginInstance::sendMessageFunction host_send_func, | 128 | LLPluginInstance::sendMessageFunction host_send_func, |
98 | void *host_user_data, | 129 | void *host_user_data, |
99 | LLPluginInstance::sendMessageFunction *plugin_send_func, | 130 | LLPluginInstance::sendMessageFunction *plugin_send_func, |
100 | void **plugin_user_data); | 131 | void **plugin_user_data); |
101 | 132 | ||
102 | // It should look something like this: | ||
103 | /* | ||
104 | { | ||
105 | MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data); | ||
106 | *plugin_send_func = MediaPluginFoo::staticReceiveMessage; | ||
107 | *plugin_user_data = (void*)self; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | */ | ||
112 | 133 | ||
diff --git a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h index e31d4a3..04976b9 100644 --- a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h | |||
@@ -35,10 +35,16 @@ | |||
35 | 35 | ||
36 | #include <cstdio> | 36 | #include <cstdio> |
37 | 37 | ||
38 | extern "C" { | ||
39 | #include <sys/types.h> | ||
40 | #include <unistd.h> | ||
41 | } | ||
42 | |||
38 | ///////////////////////////////////////////////////////////////////////// | 43 | ///////////////////////////////////////////////////////////////////////// |
39 | // Debug/Info/Warning macros. | 44 | // Debug/Info/Warning macros. |
40 | #define MSGMODULEFOO "(media plugin)" | 45 | #define MSGMODULEFOO "(media plugin)" |
41 | #define STDERRMSG(...) do{\ | 46 | #define STDERRMSG(...) do{\ |
47 | fprintf(stderr, " pid:%d: ", (int)getpid());\ | ||
42 | fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ | 48 | fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ |
43 | fprintf(stderr, __VA_ARGS__);\ | 49 | fprintf(stderr, __VA_ARGS__);\ |
44 | fputc('\n',stderr);\ | 50 | fputc('\n',stderr);\ |
diff --git a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp index 25e96d4..ef8ff58 100644 --- a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp | |||
@@ -52,7 +52,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); | |||
52 | #define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS | 52 | #define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS |
53 | 53 | ||
54 | static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( | 54 | static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( |
55 | (gchar*)"sink", | 55 | "sink", |
56 | GST_PAD_SINK, | 56 | GST_PAD_SINK, |
57 | GST_PAD_ALWAYS, | 57 | GST_PAD_ALWAYS, |
58 | GST_STATIC_CAPS (SLV_ALLCAPS) | 58 | GST_STATIC_CAPS (SLV_ALLCAPS) |
@@ -106,11 +106,10 @@ gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) | |||
106 | 106 | ||
107 | slvideo = GST_SLVIDEO(bsink); | 107 | slvideo = GST_SLVIDEO(bsink); |
108 | 108 | ||
109 | #if 0 | 109 | DEBUGMSG("transferring a frame of %dx%d <- %p (%d)", |
110 | fprintf(stderr, "\n\ntransferring a frame of %dx%d <- %p (%d)\n\n", | 110 | slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), |
111 | slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), | 111 | slvideo->format); |
112 | slvideo->format); | 112 | |
113 | #endif | ||
114 | if (GST_BUFFER_DATA(buf)) | 113 | if (GST_BUFFER_DATA(buf)) |
115 | { | 114 | { |
116 | // copy frame and frame info into neutral territory | 115 | // copy frame and frame info into neutral territory |
@@ -335,7 +334,7 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, | |||
335 | #define MAXDEPTHHACK 4 | 334 | #define MAXDEPTHHACK 4 |
336 | 335 | ||
337 | GST_OBJECT_LOCK(slvideo); | 336 | GST_OBJECT_LOCK(slvideo); |
338 | if (slvideo->resize_forced) | 337 | if (slvideo->resize_forced_always) // app is giving us a fixed size to work with |
339 | { | 338 | { |
340 | gint slwantwidth, slwantheight; | 339 | gint slwantwidth, slwantheight; |
341 | slwantwidth = slvideo->resize_try_width; | 340 | slwantwidth = slvideo->resize_try_width; |
@@ -384,6 +383,8 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, | |||
384 | } | 383 | } |
385 | } | 384 | } |
386 | 385 | ||
386 | GST_OBJECT_UNLOCK(slvideo); | ||
387 | |||
387 | if (!made_bufferdata_ptr) // need to fallback to malloc at original size | 388 | if (!made_bufferdata_ptr) // need to fallback to malloc at original size |
388 | { | 389 | { |
389 | GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; | 390 | GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; |
@@ -392,8 +393,6 @@ gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, | |||
392 | llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); | 393 | llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); |
393 | } | 394 | } |
394 | 395 | ||
395 | GST_OBJECT_UNLOCK(slvideo); | ||
396 | |||
397 | *buf = GST_BUFFER_CAST(newbuf); | 396 | *buf = GST_BUFFER_CAST(newbuf); |
398 | 397 | ||
399 | return GST_FLOW_OK; | 398 | return GST_FLOW_OK; |
@@ -457,7 +456,7 @@ gst_slvideo_init (GstSLVideo * filter, | |||
457 | filter->retained_frame_format = SLV_PF_UNKNOWN; | 456 | filter->retained_frame_format = SLV_PF_UNKNOWN; |
458 | GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); | 457 | GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); |
459 | llgst_caps_replace (&filter->caps, caps); | 458 | llgst_caps_replace (&filter->caps, caps); |
460 | filter->resize_forced = false; | 459 | filter->resize_forced_always = false; |
461 | filter->resize_try_width = -1; | 460 | filter->resize_try_width = -1; |
462 | filter->resize_try_height = -1; | 461 | filter->resize_try_height = -1; |
463 | GST_OBJECT_UNLOCK(filter); | 462 | GST_OBJECT_UNLOCK(filter); |
@@ -498,12 +497,12 @@ gst_slvideo_get_property (GObject * object, guint prop_id, | |||
498 | static gboolean | 497 | static gboolean |
499 | plugin_init (GstPlugin * plugin) | 498 | plugin_init (GstPlugin * plugin) |
500 | { | 499 | { |
501 | DEBUGMSG("\n\n\nPLUGIN INIT\n\n\n"); | 500 | DEBUGMSG("PLUGIN INIT"); |
502 | 501 | ||
503 | GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", | 502 | GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", |
504 | 0, (gchar*)"Second Life Video Sink"); | 503 | 0, (gchar*)"Second Life Video Sink"); |
505 | 504 | ||
506 | return llgst_element_register (plugin, (gchar*)"private-slvideo", | 505 | return llgst_element_register (plugin, "private-slvideo", |
507 | GST_RANK_NONE, GST_TYPE_SLVIDEO); | 506 | GST_RANK_NONE, GST_TYPE_SLVIDEO); |
508 | } | 507 | } |
509 | 508 | ||
@@ -519,14 +518,14 @@ void gst_slvideo_init_class (void) | |||
519 | // this macro quietly refers to PACKAGE internally | 518 | // this macro quietly refers to PACKAGE internally |
520 | static GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, | 519 | static GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, |
521 | GST_VERSION_MINOR, | 520 | GST_VERSION_MINOR, |
522 | (gchar*)"private-slvideoplugin", | 521 | "private-slvideoplugin", |
523 | (gchar*)"SL Video sink plugin", | 522 | "SL Video sink plugin", |
524 | plugin_init, (gchar*)"0.1", (gchar*)GST_LICENSE_UNKNOWN, | 523 | plugin_init, "0.1", GST_LICENSE_UNKNOWN, |
525 | (gchar*)"Second Life", | 524 | "Second Life", |
526 | (gchar*)"http://www.secondlife.com/"); | 525 | "http://www.secondlife.com/"); |
527 | #undef PACKAGE | 526 | #undef PACKAGE |
528 | ll_gst_plugin_register_static (&gst_plugin_desc); | 527 | ll_gst_plugin_register_static (&gst_plugin_desc); |
529 | DEBUGMSG(stderr, "\n\n\nCLASS INIT\n\n\n"); | 528 | DEBUGMSG("CLASS INIT"); |
530 | } | 529 | } |
531 | 530 | ||
532 | #endif // LL_GSTREAMER010_ENABLED | 531 | #endif // LL_GSTREAMER010_ENABLED |
diff --git a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h index f6d55b8..8cdc72d 100644 --- a/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h +++ b/linden/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h | |||
@@ -88,7 +88,7 @@ struct _GstSLVideo | |||
88 | int retained_frame_width, retained_frame_height; | 88 | int retained_frame_width, retained_frame_height; |
89 | SLVPixelFormat retained_frame_format; | 89 | SLVPixelFormat retained_frame_format; |
90 | // sticky resize info | 90 | // sticky resize info |
91 | bool resize_forced; | 91 | bool resize_forced_always; |
92 | int resize_try_width; | 92 | int resize_try_width; |
93 | int resize_try_height; | 93 | int resize_try_height; |
94 | }; | 94 | }; |
diff --git a/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp index 77b7c13..5b3152d 100644 --- a/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp +++ b/linden/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp | |||
@@ -104,7 +104,7 @@ private: | |||
104 | void mouseUp( int x, int y ); | 104 | void mouseUp( int x, int y ); |
105 | void mouseMove( int x, int y ); | 105 | void mouseMove( int x, int y ); |
106 | 106 | ||
107 | bool sizeChanged(); | 107 | void sizeChanged(); |
108 | 108 | ||
109 | static bool mDoneInit; | 109 | static bool mDoneInit; |
110 | 110 | ||
@@ -114,13 +114,16 @@ private: | |||
114 | 114 | ||
115 | int mDepth; | 115 | int mDepth; |
116 | 116 | ||
117 | // media natural size | 117 | // media NATURAL size |
118 | int mNaturalWidth; | 118 | int mNaturalWidth; |
119 | int mNaturalHeight; | 119 | int mNaturalHeight; |
120 | int mNaturalRowbytes; | 120 | // media current size |
121 | // previous media natural size so we can detect changes | 121 | int mCurrentWidth; |
122 | int mPreviousNaturalWidth; | 122 | int mCurrentHeight; |
123 | int mPreviousNaturalHeight; | 123 | int mCurrentRowbytes; |
124 | // previous media size so we can detect changes | ||
125 | int mPreviousWidth; | ||
126 | int mPreviousHeight; | ||
124 | // desired render size from host | 127 | // desired render size from host |
125 | int mWidth; | 128 | int mWidth; |
126 | int mHeight; | 129 | int mHeight; |
@@ -148,7 +151,7 @@ MediaPluginGStreamer010::MediaPluginGStreamer010( | |||
148 | void *host_user_data ) : | 151 | void *host_user_data ) : |
149 | MediaPluginBase(host_send_func, host_user_data), | 152 | MediaPluginBase(host_send_func, host_user_data), |
150 | mBusWatchID ( 0 ), | 153 | mBusWatchID ( 0 ), |
151 | mNaturalRowbytes ( 4 ), | 154 | mCurrentRowbytes ( 4 ), |
152 | mTextureFormatPrimary ( GL_RGBA ), | 155 | mTextureFormatPrimary ( GL_RGBA ), |
153 | mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), | 156 | mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), |
154 | mSeekWanted(false), | 157 | mSeekWanted(false), |
@@ -194,6 +197,7 @@ MediaPluginGStreamer010::processGSTEvents(GstBus *bus, | |||
194 | } | 197 | } |
195 | else | 198 | else |
196 | { | 199 | { |
200 | // TODO: grok 'duration' message type | ||
197 | DEBUGMSG("Got GST message type: %s", | 201 | DEBUGMSG("Got GST message type: %s", |
198 | LLGST_MESSAGE_TYPE_NAME (message)); | 202 | LLGST_MESSAGE_TYPE_NAME (message)); |
199 | } | 203 | } |
@@ -428,8 +432,8 @@ MediaPluginGStreamer010::update(int milliseconds) | |||
428 | { | 432 | { |
429 | DEBUGMSG("NEW FRAME READY"); | 433 | DEBUGMSG("NEW FRAME READY"); |
430 | 434 | ||
431 | if (mVideoSink->retained_frame_width != mNaturalWidth || | 435 | if (mVideoSink->retained_frame_width != mCurrentWidth || |
432 | mVideoSink->retained_frame_height != mNaturalHeight) | 436 | mVideoSink->retained_frame_height != mCurrentHeight) |
433 | // *TODO: also check for change in format | 437 | // *TODO: also check for change in format |
434 | { | 438 | { |
435 | // just resize container, don't consume frame | 439 | // just resize container, don't consume frame |
@@ -456,39 +460,38 @@ MediaPluginGStreamer010::update(int milliseconds) | |||
456 | 460 | ||
457 | GST_OBJECT_UNLOCK(mVideoSink); | 461 | GST_OBJECT_UNLOCK(mVideoSink); |
458 | 462 | ||
459 | mNaturalRowbytes = neww * newd; | 463 | mCurrentRowbytes = neww * newd; |
460 | DEBUGMSG("video container resized to %dx%d", | 464 | DEBUGMSG("video container resized to %dx%d", |
461 | neww, newh); | 465 | neww, newh); |
462 | 466 | ||
463 | mDepth = newd; | 467 | mDepth = newd; |
464 | mNaturalWidth = neww; | 468 | mCurrentWidth = neww; |
465 | mNaturalHeight = newh; | 469 | mCurrentHeight = newh; |
466 | sizeChanged(); | 470 | sizeChanged(); |
467 | return true; | 471 | return true; |
468 | } | 472 | } |
469 | 473 | ||
470 | if (mPixels && | 474 | if (mPixels && |
471 | mNaturalHeight <= mHeight && | 475 | mCurrentHeight <= mHeight && |
472 | mNaturalWidth <= mWidth && | 476 | mCurrentWidth <= mWidth && |
473 | !mTextureSegmentName.empty()) | 477 | !mTextureSegmentName.empty()) |
474 | { | 478 | { |
475 | |||
476 | // we're gonna totally consume this frame - reset 'ready' flag | 479 | // we're gonna totally consume this frame - reset 'ready' flag |
477 | mVideoSink->retained_frame_ready = FALSE; | 480 | mVideoSink->retained_frame_ready = FALSE; |
478 | int destination_rowbytes = mWidth * mDepth; | 481 | int destination_rowbytes = mWidth * mDepth; |
479 | for (int row=0; row<mNaturalHeight; ++row) | 482 | for (int row=0; row<mCurrentHeight; ++row) |
480 | { | 483 | { |
481 | memcpy(&mPixels | 484 | memcpy(&mPixels |
482 | [destination_rowbytes * row], | 485 | [destination_rowbytes * row], |
483 | &mVideoSink->retained_frame_data | 486 | &mVideoSink->retained_frame_data |
484 | [mNaturalRowbytes * row], | 487 | [mCurrentRowbytes * row], |
485 | mNaturalRowbytes); | 488 | mCurrentRowbytes); |
486 | } | 489 | } |
487 | 490 | ||
488 | GST_OBJECT_UNLOCK(mVideoSink); | 491 | GST_OBJECT_UNLOCK(mVideoSink); |
489 | DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); | 492 | DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); |
490 | 493 | ||
491 | setDirty(0,0,mNaturalWidth,mNaturalHeight); | 494 | setDirty(0,0,mCurrentWidth,mCurrentHeight); |
492 | } | 495 | } |
493 | else | 496 | else |
494 | { | 497 | { |
@@ -835,27 +838,35 @@ MediaPluginGStreamer010::startup() | |||
835 | } | 838 | } |
836 | 839 | ||
837 | 840 | ||
838 | bool | 841 | void |
839 | MediaPluginGStreamer010::sizeChanged() | 842 | MediaPluginGStreamer010::sizeChanged() |
840 | { | 843 | { |
841 | // the shared writing space has possibly changed size/location/whatever | 844 | // the shared writing space has possibly changed size/location/whatever |
842 | 845 | ||
843 | // Check to see whether the movie's natural size has updated | 846 | // Check to see whether the movie's NATURAL size has been set yet |
844 | if (mNaturalWidth != mPreviousNaturalWidth || | 847 | if (1 == mNaturalWidth && |
845 | mNaturalHeight != mPreviousNaturalHeight) | 848 | 1 == mNaturalHeight) |
846 | { | 849 | { |
847 | mPreviousNaturalWidth = mNaturalWidth; | 850 | mNaturalWidth = mCurrentWidth; |
848 | mPreviousNaturalHeight = mNaturalHeight; | 851 | mNaturalHeight = mCurrentHeight; |
852 | DEBUGMSG("Media NATURAL size better detected as %dx%d", | ||
853 | mNaturalWidth, mNaturalHeight); | ||
854 | } | ||
855 | |||
856 | // if the size has changed then the shm has changed and the app needs telling | ||
857 | if (mCurrentWidth != mPreviousWidth || | ||
858 | mCurrentHeight != mPreviousHeight) | ||
859 | { | ||
860 | mPreviousWidth = mCurrentWidth; | ||
861 | mPreviousHeight = mCurrentHeight; | ||
849 | 862 | ||
850 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); | 863 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); |
851 | message.setValue("name", mTextureSegmentName); | 864 | message.setValue("name", mTextureSegmentName); |
852 | message.setValueS32("width", mNaturalWidth); | 865 | message.setValueS32("width", mNaturalWidth); |
853 | message.setValueS32("height", mNaturalHeight); | 866 | message.setValueS32("height", mNaturalHeight); |
854 | DEBUGMSG("<--- Sending size change request to application with name: '%s' - size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); | 867 | DEBUGMSG("<--- Sending size change request to application with name: '%s' - natural size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); |
855 | sendMessage(message); | 868 | sendMessage(message); |
856 | } | 869 | } |
857 | |||
858 | return true; | ||
859 | } | 870 | } |
860 | 871 | ||
861 | 872 | ||
@@ -940,10 +951,12 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) | |||
940 | // lame to have to decide this now, it depends on the movie. Oh well. | 951 | // lame to have to decide this now, it depends on the movie. Oh well. |
941 | mDepth = 4; | 952 | mDepth = 4; |
942 | 953 | ||
954 | mCurrentWidth = 1; | ||
955 | mCurrentHeight = 1; | ||
956 | mPreviousWidth = 1; | ||
957 | mPreviousHeight = 1; | ||
943 | mNaturalWidth = 1; | 958 | mNaturalWidth = 1; |
944 | mNaturalHeight = 1; | 959 | mNaturalHeight = 1; |
945 | mPreviousNaturalWidth = 1; | ||
946 | mPreviousNaturalHeight = 1; | ||
947 | mWidth = 1; | 960 | mWidth = 1; |
948 | mHeight = 1; | 961 | mHeight = 1; |
949 | mTextureWidth = 1; | 962 | mTextureWidth = 1; |
@@ -984,7 +997,6 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) | |||
984 | INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); | 997 | INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); |
985 | 998 | ||
986 | mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); | 999 | mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); |
987 | |||
988 | } | 1000 | } |
989 | else if(message_name == "shm_remove") | 1001 | else if(message_name == "shm_remove") |
990 | { | 1002 | { |
@@ -1063,7 +1075,7 @@ void MediaPluginGStreamer010::receiveMessage(const char *message_string) | |||
1063 | INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); | 1075 | INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); |
1064 | 1076 | ||
1065 | GST_OBJECT_LOCK(mVideoSink); | 1077 | GST_OBJECT_LOCK(mVideoSink); |
1066 | mVideoSink->resize_forced = true; | 1078 | mVideoSink->resize_forced_always = true; |
1067 | mVideoSink->resize_try_width = texture_width; | 1079 | mVideoSink->resize_try_width = texture_width; |
1068 | mVideoSink->resize_try_height = texture_height; | 1080 | mVideoSink->resize_try_height = texture_height; |
1069 | GST_OBJECT_UNLOCK(mVideoSink); | 1081 | GST_OBJECT_UNLOCK(mVideoSink); |
diff --git a/linden/indra/media_plugins/quicktime/CMakeLists.txt b/linden/indra/media_plugins/quicktime/CMakeLists.txt index db11c9a..f0b8f0d 100644 --- a/linden/indra/media_plugins/quicktime/CMakeLists.txt +++ b/linden/indra/media_plugins/quicktime/CMakeLists.txt | |||
@@ -56,6 +56,14 @@ add_dependencies(media_plugin_quicktime | |||
56 | ${LLCOMMON_LIBRARIES} | 56 | ${LLCOMMON_LIBRARIES} |
57 | ) | 57 | ) |
58 | 58 | ||
59 | if (WINDOWS) | ||
60 | set_target_properties( | ||
61 | media_plugin_quicktime | ||
62 | PROPERTIES | ||
63 | LINK_FLAGS "/MANIFEST:NO" | ||
64 | ) | ||
65 | endif (WINDOWS) | ||
66 | |||
59 | if (QUICKTIME) | 67 | if (QUICKTIME) |
60 | 68 | ||
61 | add_definitions(-DLL_QUICKTIME_ENABLED=1) | 69 | add_definitions(-DLL_QUICKTIME_ENABLED=1) |
diff --git a/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index 51cc8dd..6c8c41d 100644 --- a/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/linden/indra/media_plugins/quicktime/media_plugin_quicktime.cpp | |||
@@ -49,6 +49,7 @@ | |||
49 | #include "Movies.h" | 49 | #include "Movies.h" |
50 | #include "QDoffscreen.h" | 50 | #include "QDoffscreen.h" |
51 | #include "FixMath.h" | 51 | #include "FixMath.h" |
52 | #include "QTLoadLibraryUtils.h" | ||
52 | #endif | 53 | #endif |
53 | 54 | ||
54 | // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint | 55 | // TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint |
@@ -72,11 +73,14 @@ private: | |||
72 | int mCurVolume; | 73 | int mCurVolume; |
73 | bool mMediaSizeChanging; | 74 | bool mMediaSizeChanging; |
74 | bool mIsLooping; | 75 | bool mIsLooping; |
76 | std::string mMovieTitle; | ||
77 | bool mReceivedTitle; | ||
75 | const int mMinWidth; | 78 | const int mMinWidth; |
76 | const int mMaxWidth; | 79 | const int mMaxWidth; |
77 | const int mMinHeight; | 80 | const int mMinHeight; |
78 | const int mMaxHeight; | 81 | const int mMaxHeight; |
79 | F64 mPlayRate; | 82 | F64 mPlayRate; |
83 | std::string mNavigateURL; | ||
80 | 84 | ||
81 | enum ECommand { | 85 | enum ECommand { |
82 | COMMAND_NONE, | 86 | COMMAND_NONE, |
@@ -175,6 +179,11 @@ private: | |||
175 | setStatus(STATUS_ERROR); | 179 | setStatus(STATUS_ERROR); |
176 | return; | 180 | return; |
177 | }; | 181 | }; |
182 | |||
183 | mNavigateURL = url; | ||
184 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); | ||
185 | message.setValue("uri", mNavigateURL); | ||
186 | sendMessage(message); | ||
178 | 187 | ||
179 | // do pre-roll actions (typically fired for streaming movies but not always) | 188 | // do pre-roll actions (typically fired for streaming movies but not always) |
180 | PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); | 189 | PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); |
@@ -199,6 +208,9 @@ private: | |||
199 | 208 | ||
200 | bool unload() | 209 | bool unload() |
201 | { | 210 | { |
211 | // new movie and have to get title again | ||
212 | mReceivedTitle = false; | ||
213 | |||
202 | if ( mMovieHandle ) | 214 | if ( mMovieHandle ) |
203 | { | 215 | { |
204 | StopMovie( mMovieHandle ); | 216 | StopMovie( mMovieHandle ); |
@@ -382,11 +394,18 @@ private: | |||
382 | 394 | ||
383 | static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) | 395 | static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) |
384 | { | 396 | { |
385 | //MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; | 397 | MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; |
386 | 398 | ||
387 | // TODO: | 399 | // TODO: |
388 | //LLMediaEvent event( self ); | 400 | //LLMediaEvent event( self ); |
389 | //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); | 401 | //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); |
402 | |||
403 | // Send a "navigate complete" event. | ||
404 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); | ||
405 | message.setValue("uri", self->mNavigateURL); | ||
406 | message.setValueS32("result_code", 200); | ||
407 | message.setValue("result_string", "OK"); | ||
408 | self->sendMessage(message); | ||
390 | }; | 409 | }; |
391 | 410 | ||
392 | 411 | ||
@@ -400,7 +419,7 @@ private: | |||
400 | { | 419 | { |
401 | if ( mCommand == COMMAND_PLAY ) | 420 | if ( mCommand == COMMAND_PLAY ) |
402 | { | 421 | { |
403 | if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING ) | 422 | if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE ) |
404 | { | 423 | { |
405 | long state = GetMovieLoadState( mMovieHandle ); | 424 | long state = GetMovieLoadState( mMovieHandle ); |
406 | 425 | ||
@@ -426,7 +445,7 @@ private: | |||
426 | else | 445 | else |
427 | if ( mCommand == COMMAND_STOP ) | 446 | if ( mCommand == COMMAND_STOP ) |
428 | { | 447 | { |
429 | if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED ) | 448 | if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE ) |
430 | { | 449 | { |
431 | if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) | 450 | if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) |
432 | { | 451 | { |
@@ -508,11 +527,17 @@ private: | |||
508 | if ( ! mMovieController ) | 527 | if ( ! mMovieController ) |
509 | return; | 528 | return; |
510 | 529 | ||
511 | // service QuickTime | 530 | // this wasn't required in 1.xx viewer but we have to manually |
512 | // Calling it this way doesn't have good behavior on Windows... | 531 | // work the Windows message pump now |
513 | // MoviesTask( mMovieHandle, milliseconds ); | 532 | #if defined( LL_WINDOWS ) |
514 | // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle. | 533 | MSG msg; |
515 | // MoviesTask( mMovieHandle, 0 ); | 534 | while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) |
535 | { | ||
536 | GetMessage( &msg, NULL, 0, 0 ); | ||
537 | TranslateMessage( &msg ); | ||
538 | DispatchMessage( &msg ); | ||
539 | }; | ||
540 | #endif | ||
516 | 541 | ||
517 | MCIdle( mMovieController ); | 542 | MCIdle( mMovieController ); |
518 | 543 | ||
@@ -525,11 +550,14 @@ private: | |||
525 | // update state machine | 550 | // update state machine |
526 | processState(); | 551 | processState(); |
527 | 552 | ||
528 | // special code for looping - need to rewind at the end of the movie | 553 | // see if title arrived and if so, update member variable with contents |
529 | if ( mIsLooping ) | 554 | checkTitle(); |
555 | |||
556 | // QT call to see if we are at the end - can't do with controller | ||
557 | if ( IsMovieDone( mMovieHandle ) ) | ||
530 | { | 558 | { |
531 | // QT call to see if we are at the end - can't do with controller | 559 | // special code for looping - need to rewind at the end of the movie |
532 | if ( IsMovieDone( mMovieHandle ) ) | 560 | if ( mIsLooping ) |
533 | { | 561 | { |
534 | // go back to start | 562 | // go back to start |
535 | rewind(); | 563 | rewind(); |
@@ -542,8 +570,16 @@ private: | |||
542 | // set the volume | 570 | // set the volume |
543 | MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); | 571 | MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); |
544 | }; | 572 | }; |
545 | }; | 573 | } |
546 | }; | 574 | else |
575 | { | ||
576 | if(mStatus == STATUS_PLAYING) | ||
577 | { | ||
578 | setStatus(STATUS_DONE); | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | |||
547 | }; | 583 | }; |
548 | 584 | ||
549 | int getDataWidth() const | 585 | int getDataWidth() const |
@@ -586,6 +622,19 @@ private: | |||
586 | }; | 622 | }; |
587 | }; | 623 | }; |
588 | 624 | ||
625 | F64 getLoadedDuration() | ||
626 | { | ||
627 | TimeValue duration; | ||
628 | if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr) | ||
629 | { | ||
630 | // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie. | ||
631 | duration = GetMovieDuration( mMovieHandle ); | ||
632 | } | ||
633 | TimeValue scale = GetMovieTimeScale( mMovieHandle ); | ||
634 | |||
635 | return (F64)duration / (F64)scale; | ||
636 | }; | ||
637 | |||
589 | F64 getDuration() | 638 | F64 getDuration() |
590 | { | 639 | { |
591 | TimeValue duration = GetMovieDuration( mMovieHandle ); | 640 | TimeValue duration = GetMovieDuration( mMovieHandle ); |
@@ -643,6 +692,77 @@ private: | |||
643 | { | 692 | { |
644 | }; | 693 | }; |
645 | 694 | ||
695 | //////////////////////////////////////////////////////////////////////////////// | ||
696 | // Grab movie title into mMovieTitle - should be called repeatedly | ||
697 | // until it returns true since movie title takes a while to become | ||
698 | // available. | ||
699 | const bool getMovieTitle() | ||
700 | { | ||
701 | // grab meta data from movie | ||
702 | QTMetaDataRef media_data_ref; | ||
703 | OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref ); | ||
704 | if ( noErr != result ) | ||
705 | return false; | ||
706 | |||
707 | // look up "Display Name" in meta data | ||
708 | OSType meta_data_key = kQTMetaDataCommonKeyDisplayName; | ||
709 | QTMetaDataItem item = kQTMetaDataItemUninitialized; | ||
710 | result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard, | ||
711 | 0, kQTMetaDataKeyFormatCommon, | ||
712 | (const UInt8 *)&meta_data_key, | ||
713 | sizeof( meta_data_key ), &item ); | ||
714 | if ( noErr != result ) | ||
715 | return false; | ||
716 | |||
717 | // find the size of the title | ||
718 | ByteCount size; | ||
719 | result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size ); | ||
720 | if ( noErr != result || size <= 0 /*|| size > 1024 FIXME: arbitrary limit */ ) | ||
721 | return false; | ||
722 | |||
723 | // allocate some space and grab it | ||
724 | UInt8* item_data = new UInt8( size + 1 ); | ||
725 | memset( item_data, 0, ( size + 1 ) * sizeof( UInt8* ) ); | ||
726 | result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL ); | ||
727 | if ( noErr != result ) | ||
728 | { | ||
729 | delete [] item_data; | ||
730 | return false; | ||
731 | }; | ||
732 | |||
733 | // save it | ||
734 | if ( strlen( (char*)item_data ) ) | ||
735 | mMovieTitle = std::string( (char* )item_data ); | ||
736 | else | ||
737 | mMovieTitle = ""; | ||
738 | |||
739 | // clean up | ||
740 | delete [] item_data; | ||
741 | |||
742 | return true; | ||
743 | }; | ||
744 | |||
745 | // called regularly to see if title changed | ||
746 | void checkTitle() | ||
747 | { | ||
748 | // we did already receive title so keep checking | ||
749 | if ( ! mReceivedTitle ) | ||
750 | { | ||
751 | // grab title from movie meta data | ||
752 | if ( getMovieTitle() ) | ||
753 | { | ||
754 | // pass back to host application | ||
755 | LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); | ||
756 | message.setValue("name", mMovieTitle ); | ||
757 | sendMessage( message ); | ||
758 | |||
759 | // stop looking once we find a title for this movie. | ||
760 | // TODO: this may to be reset if movie title changes | ||
761 | // during playback but this is okay for now | ||
762 | mReceivedTitle = true; | ||
763 | }; | ||
764 | }; | ||
765 | }; | ||
646 | }; | 766 | }; |
647 | 767 | ||
648 | MediaPluginQuickTime::MediaPluginQuickTime( | 768 | MediaPluginQuickTime::MediaPluginQuickTime( |
@@ -664,6 +784,8 @@ MediaPluginQuickTime::MediaPluginQuickTime( | |||
664 | mCurVolume = 0x99; | 784 | mCurVolume = 0x99; |
665 | mMediaSizeChanging = false; | 785 | mMediaSizeChanging = false; |
666 | mIsLooping = false; | 786 | mIsLooping = false; |
787 | mMovieTitle = std::string(); | ||
788 | mReceivedTitle = false; | ||
667 | mCommand = COMMAND_NONE; | 789 | mCommand = COMMAND_NONE; |
668 | mPlayRate = 0.0f; | 790 | mPlayRate = 0.0f; |
669 | mStatus = STATUS_NONE; | 791 | mStatus = STATUS_NONE; |
@@ -700,22 +822,29 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) | |||
700 | versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; | 822 | versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; |
701 | versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; | 823 | versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; |
702 | // Normally a plugin would only specify one of these two subclasses, but this is a demo... | 824 | // Normally a plugin would only specify one of these two subclasses, but this is a demo... |
703 | // versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; | ||
704 | versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; | 825 | versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; |
705 | message.setValueLLSD("versions", versions); | 826 | message.setValueLLSD("versions", versions); |
706 | 827 | ||
707 | #ifdef LL_WINDOWS | 828 | #ifdef LL_WINDOWS |
708 | if ( InitializeQTML( 0L ) != noErr ) | 829 | |
830 | // QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime | ||
831 | // according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html | ||
832 | // The solution presented there appears to work. | ||
833 | QTLoadLibrary("qtcf.dll"); | ||
834 | |||
835 | // main initialization for QuickTime - only required on Windows | ||
836 | OSErr result = InitializeQTML( 0L ); | ||
837 | if ( result != noErr ) | ||
709 | { | 838 | { |
710 | //TODO: If no QT on Windows, this fails - respond accordingly. | 839 | //TODO: If no QT on Windows, this fails - respond accordingly. |
711 | //return false; | ||
712 | } | 840 | } |
713 | else | 841 | else |
714 | { | 842 | { |
715 | // std::cerr << "QuickTime initialized" << std::endl; | 843 | //std::cerr << "QuickTime initialized" << std::endl; |
716 | }; | 844 | }; |
717 | #endif | 845 | #endif |
718 | 846 | ||
847 | // required for both Windows and Mac | ||
719 | EnterMovies(); | 848 | EnterMovies(); |
720 | 849 | ||
721 | std::string plugin_version = "QuickTime media plugin, QuickTime version "; | 850 | std::string plugin_version = "QuickTime media plugin, QuickTime version "; |
@@ -773,10 +902,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string) | |||
773 | else if(message_name == "shm_added") | 902 | else if(message_name == "shm_added") |
774 | { | 903 | { |
775 | SharedSegmentInfo info; | 904 | SharedSegmentInfo info; |
776 | U64 address_lo = message_in.getValueU32("address"); | 905 | info.mAddress = message_in.getValuePointer("address"); |
777 | U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; | ||
778 | info.mAddress = (void*)((address_lo) | | ||
779 | (address_hi * (U64(1)<<31))); | ||
780 | info.mSize = (size_t)message_in.getValueS32("size"); | 906 | info.mSize = (size_t)message_in.getValueS32("size"); |
781 | std::string name = message_in.getValue("name"); | 907 | std::string name = message_in.getValue("name"); |
782 | 908 | ||
diff --git a/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp b/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp index f115c28..91efdae 100644 --- a/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/linden/indra/media_plugins/webkit/media_plugin_webkit.cpp | |||
@@ -75,6 +75,8 @@ public: | |||
75 | 75 | ||
76 | private: | 76 | private: |
77 | 77 | ||
78 | std::string mProfileDir; | ||
79 | |||
78 | enum | 80 | enum |
79 | { | 81 | { |
80 | INIT_STATE_UNINITIALIZED, // Browser instance hasn't been set up yet | 82 | INIT_STATE_UNINITIALIZED, // Browser instance hasn't been set up yet |
@@ -95,6 +97,12 @@ private: | |||
95 | int mLastMouseY; | 97 | int mLastMouseY; |
96 | bool mFirstFocus; | 98 | bool mFirstFocus; |
97 | 99 | ||
100 | void setInitState(int state) | ||
101 | { | ||
102 | // std::cerr << "changing init state to " << state << std::endl; | ||
103 | mInitState = state; | ||
104 | } | ||
105 | |||
98 | //////////////////////////////////////////////////////////////////////////////// | 106 | //////////////////////////////////////////////////////////////////////////////// |
99 | // | 107 | // |
100 | void update(int milliseconds) | 108 | void update(int milliseconds) |
@@ -186,7 +194,6 @@ private: | |||
186 | #else | 194 | #else |
187 | std::string component_dir = application_dir; | 195 | std::string component_dir = application_dir; |
188 | #endif | 196 | #endif |
189 | std::string profileDir = application_dir + "/" + "browser_profile"; // cross platform? | ||
190 | 197 | ||
191 | // window handle - needed on Windows and must be app window. | 198 | // window handle - needed on Windows and must be app window. |
192 | #if LL_WINDOWS | 199 | #if LL_WINDOWS |
@@ -198,7 +205,7 @@ private: | |||
198 | #endif | 205 | #endif |
199 | 206 | ||
200 | // main browser initialization | 207 | // main browser initialization |
201 | bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, profileDir, native_window_handle ); | 208 | bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); |
202 | if ( result ) | 209 | if ( result ) |
203 | { | 210 | { |
204 | // create single browser window | 211 | // create single browser window |
@@ -208,13 +215,15 @@ private: | |||
208 | // Enable plugins | 215 | // Enable plugins |
209 | LLQtWebKit::getInstance()->enablePlugins(true); | 216 | LLQtWebKit::getInstance()->enablePlugins(true); |
210 | #elif LL_DARWIN | 217 | #elif LL_DARWIN |
211 | // Disable plugins | 218 | // Enable plugins |
212 | LLQtWebKit::getInstance()->enablePlugins(false); | 219 | LLQtWebKit::getInstance()->enablePlugins(true); |
213 | #elif LL_LINUX | 220 | #elif LL_LINUX |
214 | // Disable plugins | 221 | // Enable plugins |
215 | LLQtWebKit::getInstance()->enablePlugins(false); | 222 | LLQtWebKit::getInstance()->enablePlugins(true); |
216 | #endif | 223 | #endif |
217 | 224 | // Enable cookies | |
225 | LLQtWebKit::getInstance()->enableCookies( true ); | ||
226 | |||
218 | // tell LLQtWebKit about the size of the browser window | 227 | // tell LLQtWebKit about the size of the browser window |
219 | LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); | 228 | LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); |
220 | 229 | ||
@@ -227,11 +236,11 @@ private: | |||
227 | // don't flip bitmap | 236 | // don't flip bitmap |
228 | LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); | 237 | LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); |
229 | 238 | ||
230 | // Set the background color to black - mostly for initial login page | 239 | // set background color to be black - mostly for initial login page |
231 | LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 ); | 240 | LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, 0x00, 0x00, 0x00 ); |
232 | 241 | ||
233 | // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. | 242 | // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. |
234 | mInitState = INIT_STATE_NAVIGATING; | 243 | setInitState(INIT_STATE_NAVIGATING); |
235 | 244 | ||
236 | // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. | 245 | // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. |
237 | // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially | 246 | // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially |
@@ -285,7 +294,7 @@ private: | |||
285 | { | 294 | { |
286 | if(mInitState == INIT_STATE_WAIT_REDRAW) | 295 | if(mInitState == INIT_STATE_WAIT_REDRAW) |
287 | { | 296 | { |
288 | mInitState = INIT_STATE_RUNNING; | 297 | setInitState(INIT_STATE_RUNNING); |
289 | } | 298 | } |
290 | 299 | ||
291 | // flag that an update is required | 300 | // flag that an update is required |
@@ -307,7 +316,7 @@ private: | |||
307 | 316 | ||
308 | if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) | 317 | if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) |
309 | { | 318 | { |
310 | mInitState = INIT_STATE_WAIT_REDRAW; | 319 | setInitState(INIT_STATE_WAIT_REDRAW); |
311 | } | 320 | } |
312 | 321 | ||
313 | } | 322 | } |
@@ -330,7 +339,7 @@ private: | |||
330 | } | 339 | } |
331 | else if(mInitState == INIT_STATE_NAVIGATING) | 340 | else if(mInitState == INIT_STATE_NAVIGATING) |
332 | { | 341 | { |
333 | mInitState = INIT_STATE_NAVIGATE_COMPLETE; | 342 | setInitState(INIT_STATE_NAVIGATE_COMPLETE); |
334 | } | 343 | } |
335 | 344 | ||
336 | } | 345 | } |
@@ -495,7 +504,16 @@ private: | |||
495 | { | 504 | { |
496 | // std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl; | 505 | // std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl; |
497 | 506 | ||
498 | LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i], modifiers); | 507 | if(wstr[i] == 32) |
508 | { | ||
509 | // For some reason, the webkit plugin really wants the space bar to come in through the key-event path, not the unicode path. | ||
510 | LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, 32, modifiers); | ||
511 | LLQtWebKit::getInstance()->keyEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, 32, modifiers); | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i], modifiers); | ||
516 | } | ||
499 | } | 517 | } |
500 | 518 | ||
501 | checkEditState(); | 519 | checkEditState(); |
@@ -576,6 +594,9 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) | |||
576 | { | 594 | { |
577 | if(message_name == "init") | 595 | if(message_name == "init") |
578 | { | 596 | { |
597 | std::string user_data_path = message_in.getValue("user_data_path"); // n.b. always has trailing platform-specific dir-delimiter | ||
598 | mProfileDir = user_data_path + "browser_profile"; | ||
599 | |||
579 | LLPluginMessage message("base", "init_response"); | 600 | LLPluginMessage message("base", "init_response"); |
580 | LLSD versions = LLSD::emptyMap(); | 601 | LLSD versions = LLSD::emptyMap(); |
581 | versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; | 602 | versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; |
@@ -611,7 +632,11 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) | |||
611 | } | 632 | } |
612 | else if(message_name == "cleanup") | 633 | else if(message_name == "cleanup") |
613 | { | 634 | { |
614 | // TODO: clean up here | 635 | // DTOR most likely won't be called but the recent change to the way this process |
636 | // is (not) killed means we see this message and can do what we need to here. | ||
637 | // Note: this cleanup is ultimately what writes cookies to the disk | ||
638 | LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); | ||
639 | LLQtWebKit::getInstance()->reset(); | ||
615 | } | 640 | } |
616 | else if(message_name == "shm_added") | 641 | else if(message_name == "shm_added") |
617 | { | 642 | { |
diff --git a/linden/indra/newview/llviewerparcelmedia.cpp b/linden/indra/newview/llviewerparcelmedia.cpp index c7f0c4b..d4ebbd9 100644 --- a/linden/indra/newview/llviewerparcelmedia.cpp +++ b/linden/indra/newview/llviewerparcelmedia.cpp | |||
@@ -193,6 +193,9 @@ void LLViewerParcelMedia::play(LLParcel* parcel) | |||
193 | S32 media_width = parcel->getMediaWidth(); | 193 | S32 media_width = parcel->getMediaWidth(); |
194 | S32 media_height = parcel->getMediaHeight(); | 194 | S32 media_height = parcel->getMediaHeight(); |
195 | 195 | ||
196 | // Debug print | ||
197 | // LL_DEBUGS("Media") << "Play media type : " << mime_type << ", url : " << media_url << LL_ENDL; | ||
198 | |||
196 | if(sMediaImpl) | 199 | if(sMediaImpl) |
197 | { | 200 | { |
198 | // If the url and mime type are the same, call play again | 201 | // If the url and mime type are the same, call play again |
@@ -221,7 +224,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel) | |||
221 | 224 | ||
222 | sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, | 225 | sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, |
223 | media_width, media_height, media_auto_scale, | 226 | media_width, media_height, media_auto_scale, |
224 | media_loop); | 227 | media_loop, mime_type); |
225 | } | 228 | } |
226 | } | 229 | } |
227 | else | 230 | else |
@@ -229,7 +232,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel) | |||
229 | // There is no media impl, make a new one | 232 | // There is no media impl, make a new one |
230 | sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, | 233 | sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, |
231 | media_width, media_height, media_auto_scale, | 234 | media_width, media_height, media_auto_scale, |
232 | media_loop); | 235 | media_loop, mime_type); |
233 | } | 236 | } |
234 | 237 | ||
235 | 238 | ||