]> git.sesse.net Git - vlc/blob - mozilla/vlcplugin.cpp
Don't use the media library in the mozilla plugin
[vlc] / mozilla / vlcplugin.cpp
1 /*****************************************************************************
2  * vlcplugin.cpp: a VLC plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "config.h"
28
29 #ifdef HAVE_MOZILLA_CONFIG_H
30 #   include <mozilla-config.h>
31 #endif
32
33 #include "vlcplugin.h"
34 #include "control/npovlc.h"
35 #include "control/npolibvlc.h"
36
37 /*****************************************************************************
38  * VlcPlugin constructor and destructor
39  *****************************************************************************/
40 VlcPlugin::VlcPlugin( NPP instance, uint16 mode ) :
41     i_npmode(mode),
42     b_stream(0),
43     b_autoplay(0),
44     psz_target(NULL),
45     libvlc_instance(NULL),
46     scriptClass(NULL),
47     p_browser(instance),
48     psz_baseURL(NULL)
49 #if XP_WIN
50     ,pf_wndproc(NULL)
51 #endif
52 #if XP_UNIX
53     ,i_width((unsigned)-1)
54     ,i_height((unsigned)-1)
55 #endif
56 {
57     memset(&npwindow, 0, sizeof(NPWindow));
58 }
59
60 static int boolValue(const char *value) {
61     return ( !strcmp(value, "1") || 
62              !strcasecmp(value, "true") ||
63              !strcasecmp(value, "yes") );
64 }
65
66 NPError VlcPlugin::init(int argc, char* const argn[], char* const argv[])
67 {
68     /* prepare VLC command line */
69     char *ppsz_argv[32] =
70     {
71         "vlc",
72         "-vv",
73         "--no-stats",
74         "--no-media-library",
75         "--intf", "dummy",
76     };
77     int ppsz_argc = 5;
78
79     /* locate VLC module path */
80 #ifdef XP_MACOSX
81     ppsz_argv[ppsz_argc++] = "--plugin-path";
82     ppsz_argv[ppsz_argc++] = "/Library/Internet Plug-Ins/VLC Plugin.plugin/"
83                              "Contents/MacOS/modules";
84 #elif defined(XP_WIN)
85     HKEY h_key;
86     DWORD i_type, i_data = MAX_PATH + 1;
87     char p_data[MAX_PATH + 1];
88     if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\VideoLAN\\VLC",
89                       0, KEY_READ, &h_key ) == ERROR_SUCCESS )
90     {
91          if( RegQueryValueEx( h_key, "InstallDir", 0, &i_type,
92                               (LPBYTE)p_data, &i_data ) == ERROR_SUCCESS )
93          {
94              if( i_type == REG_SZ )
95              {
96                  strcat( p_data, "\\vlc" );
97                  ppsz_argv[0] = p_data;
98              }
99          }
100          RegCloseKey( h_key );
101     }
102     ppsz_argv[ppsz_argc++] = "--no-one-instance";
103 #if 0
104     ppsz_argv[ppsz_argc++] = "--fast-mutex";
105     ppsz_argv[ppsz_argc++] = "--win9x-cv-method=1";
106 #endif
107
108 #endif /* XP_MACOSX */
109
110     const char *version = NULL;
111
112     /* parse plugin arguments */
113     for( int i = 0; i < argc ; i++ )
114     {
115         fprintf(stderr, "argn=%s, argv=%s\n", argn[i], argv[i]);
116
117         if( !strcmp( argn[i], "target" )
118          || !strcmp( argn[i], "mrl")
119          || !strcmp( argn[i], "filename")
120          || !strcmp( argn[i], "src") )
121         {
122             psz_target = argv[i];
123         }
124         else if( !strcmp( argn[i], "autoplay")
125               || !strcmp( argn[i], "autostart") )
126         {
127             b_autoplay = boolValue(argv[i]);
128         }
129         else if( !strcmp( argn[i], "fullscreen" ) )
130         {
131             if( boolValue(argv[i]) )
132             {
133                 ppsz_argv[ppsz_argc++] = "--fullscreen";
134             }
135             else
136             {
137                 ppsz_argv[ppsz_argc++] = "--no-fullscreen";
138             }
139         }
140         else if( !strcmp( argn[i], "mute" ) )
141         {
142             if( boolValue(argv[i]) )
143             {
144                 ppsz_argv[ppsz_argc++] = "--volume";
145                 ppsz_argv[ppsz_argc++] = "0";
146             }
147         }
148         else if( !strcmp( argn[i], "loop")
149               || !strcmp( argn[i], "autoloop") )
150         {
151             if( boolValue(argv[i]) )
152             {
153                 ppsz_argv[ppsz_argc++] = "--loop";
154             }
155             else {
156                 ppsz_argv[ppsz_argc++] = "--no-loop";
157             }
158         }
159         else if( !strcmp( argn[i], "version") )
160         {
161             version = argv[i];
162         }
163     }
164
165     libvlc_instance = libvlc_new(ppsz_argc, ppsz_argv, NULL);
166     if( ! libvlc_instance )
167     {
168         return NPERR_GENERIC_ERROR;
169     }
170
171     /*
172     ** fetch plugin base URL, which is the URL of the page containing the plugin
173     ** this URL is used for making absolute URL from relative URL that may be
174     ** passed as an MRL argument
175     */
176     NPObject *plugin;
177
178     if( NPERR_NO_ERROR == NPN_GetValue(p_browser, NPNVWindowNPObject, &plugin) )
179     {
180         /*
181         ** is there a better way to get that info ?
182         */
183         static const char docLocHref[] = "document.location.href";
184         NPString script;
185         NPVariant result;
186
187         script.utf8characters = docLocHref;
188         script.utf8length = sizeof(docLocHref)-1;
189
190         if( NPN_Evaluate(p_browser, plugin, &script, &result) )
191         {
192             if( NPVARIANT_IS_STRING(result) )
193             {
194                 NPString &location = NPVARIANT_TO_STRING(result);
195
196                 psz_baseURL = new char[location.utf8length+1];
197                 if( psz_baseURL )
198                 {
199                     strncpy(psz_baseURL, location.utf8characters, location.utf8length);
200                     psz_baseURL[location.utf8length] = '\0';
201                 }
202             }
203             NPN_ReleaseVariantValue(&result);
204         }
205         NPN_ReleaseObject(plugin);
206     }
207
208     if( psz_target )
209     {
210         // get absolute URL from src
211         psz_target = getAbsoluteURL(psz_target);
212     }
213
214     /* assign plugin script root class */
215     if( (NULL != version) && (!strcmp(version, "VideoLAN.VLCPlugin.2")) )
216     {
217         /* new APIs */
218         scriptClass = RuntimeNPClass<LibvlcRootNPObject>::getClass();
219     }
220     else
221     {
222         /* legacy APIs */
223         scriptClass = RuntimeNPClass<VlcNPObject>::getClass();
224     }
225
226     return NPERR_NO_ERROR;
227 }
228
229 #if 0
230 #ifdef XP_WIN
231 /* This is really ugly but there is a deadlock when stopping a stream
232  * (in VLC_CleanUp()) because the video output is a child of the drawable but
233  * is in a different thread. */
234 static void HackStopVout( VlcPlugin* p_plugin )
235 {
236     MSG msg;
237     HWND hwnd;
238     vlc_value_t value;
239
240     int i_vlc = libvlc_get_vlc_id(p_plugin->libvlc_instance);
241     VLC_VariableGet( i_vlc, "drawable", &value );
242
243     hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 );
244     if( !hwnd ) return;
245
246     PostMessage( hwnd, WM_CLOSE, 0, 0 );
247
248     do
249     {
250         while( PeekMessage( &msg, (HWND)value.i_int, 0, 0, PM_REMOVE ) )
251         {
252             TranslateMessage(&msg);
253             DispatchMessage(&msg);
254         }
255         if( FindWindowEx( (HWND)value.i_int, 0, 0, 0 ) ) Sleep( 10 );
256     }
257     while( (hwnd = FindWindowEx( (HWND)value.i_int, 0, 0, 0 )) );
258 }
259 #endif /* XP_WIN */
260 #endif
261
262 VlcPlugin::~VlcPlugin()
263 {
264     delete psz_baseURL;
265     delete psz_target;
266     if( libvlc_instance )
267         libvlc_destroy(libvlc_instance);
268 }
269
270 /*****************************************************************************
271  * VlcPlugin methods
272  *****************************************************************************/
273
274 char *VlcPlugin::getAbsoluteURL(const char *url)
275 {
276     if( NULL != url )
277     {
278         // check whether URL is already absolute
279         const char *end=strchr(url, ':');
280         if( (NULL != end) && (end != url) )
281         {
282             // validate protocol header
283             const char *start = url;
284             while( start != end ) {
285                 char c = *start | 0x20;
286                 if( (c < 'a') || (c > 'z') )
287                     // not valid protocol header, assume relative URL
288                     break;
289                 ++start;
290             }
291             /* we have a protocol header, therefore URL is absolute */
292             return strdup(url);
293         }
294
295         if( psz_baseURL )
296         {
297             size_t baseLen = strlen(psz_baseURL);
298             char *href = new char[baseLen+strlen(url)];
299             if( href )
300             {
301                 /* prepend base URL */
302                 strcpy(href, psz_baseURL);
303
304                 /*
305                 ** relative url could be empty,
306                 ** in which case return base URL
307                 */
308                 if( '\0' == *url )
309                     return href;
310
311                 /*
312                 ** locate pathname part of base URL
313                 */
314
315                 /* skip over protocol part  */
316                 char *pathstart = strchr(href, ':');
317                 char *pathend;
318                 if( '/' == *(++pathstart) )
319                 {
320                     if( '/' == *(++pathstart) )
321                     {
322                         ++pathstart;
323                     }
324                 }
325                 /* skip over host part */
326                 pathstart = strchr(pathstart, '/');
327                 pathend = href+baseLen;
328                 if( ! pathstart )
329                 {
330                     // no path, add a / past end of url (over '\0')
331                     pathstart = pathend;
332                     *pathstart = '/';
333                 }
334
335                 /* relative URL made of an absolute path ? */
336                 if( '/' == *url )
337                 {
338                     /* replace path completely */
339                     strcpy(pathstart, url);
340                     return href;
341                 }
342
343                 /* find last path component and replace it */ 
344                 while( '/' != *pathend) --pathend;
345
346                 /*
347                 ** if relative url path starts with one or more '../',
348                 ** factor them out of href so that we return a
349                 ** normalized URL
350                 */
351                 while( pathend != pathstart )
352                 {
353                     const char *p = url;
354                     if( '.' != *p )
355                         break;
356                     ++p;
357                     if( '.' != *p ) 
358                         break;
359                     ++p;
360                     if( '/' != *p ) 
361                         break;
362                     ++p;
363                     url = p;
364                     while( '/' != *pathend ) --pathend;
365                 }
366                 /* concatenate remaining base URL and relative URL */
367                 strcpy(pathend+1, url);
368             }
369             return href;
370         }
371     }
372     return NULL;
373 }
374
375 #if XP_UNIX
376 int  VlcPlugin::setSize(unsigned width, unsigned height)
377 {
378     int diff = (width != i_width) || (height != i_height);
379
380     i_width = width;
381     i_height = height;
382
383     /* return size */
384     return diff;
385 }
386 #endif
387