vlcshell.cpp 15.8 KB
Newer Older
1
/*****************************************************************************
2
 * vlcshell.cpp: a VLC plugin for Mozilla
3
 *****************************************************************************
Jean-Paul Saman's avatar
Jean-Paul Saman committed
4
 * Copyright (C) 2002-2009 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
8
 *          Jean-Paul Saman <jpsaman@videolan.org>
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
28 29 30 31 32

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33 34
#include <stdio.h>
#include <string.h>
35
#include <stdlib.h>
36

37
#include "vlcplugin_base.h"
38
#include "vlcplugin.h"
39
#include "vlcshell.h"
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static char mimetype[] =
    /* MPEG-1 and MPEG-2 */
    "audio/mpeg:mp2,mp3,mpga,mpega:MPEG audio;"
    "audio/x-mpeg:mp2,mp3,mpga,mpega:MPEG audio;"
    "video/mpeg:mpg,mpeg,mpe:MPEG video;"
    "video/x-mpeg:mpg,mpeg,mpe:MPEG video;"
    "video/mpeg-system:mpg,mpeg,mpe,vob:MPEG video;"
    "video/x-mpeg-system:mpg,mpeg,mpe,vob:MPEG video;"
    /* MPEG-4 */
    "audio/mp4:aac,mp4,mpg4:MPEG-4 audio;"
    "audio/x-m4a:m4a:MPEG-4 audio;"
    /* MPEG-4 ASP */
    "video/mp4:mp4,mpg4:MPEG-4 video;"
    "application/mpeg4-iod:mp4,mpg4:MPEG-4 video;"
    "application/mpeg4-muxcodetable:mp4,mpg4:MPEG-4 video;"
    "video/x-m4v:m4v:MPEG-4 video;"
    /* AVI */
    "video/x-msvideo:avi:AVI video;"
    /* QuickTime */
    /* "video/quicktime:mov,qt:QuickTime video;" */
    /* OGG */
    "application/ogg:ogg:Ogg stream;"
    "video/ogg:ogv:Ogg video;"
    "application/x-ogg:ogg:Ogg stream;"
    /* VLC */
    "application/x-vlc-plugin::VLC plug-in;"
    /* Windows Media */
    "video/x-ms-asf-plugin:asf,asx:Windows Media Video;"
    "video/x-ms-asf:asf,asx:Windows Media Video;"
    "application/x-mplayer2::Windows Media;"
    "video/x-ms-wmv:wmv:Windows Media;"
    "video/x-ms-wvx:wvx:Windows Media Video;"
    "audio/x-ms-wma:wma:Windows Media Audio;"
    /* Google VLC */
    "application/x-google-vlc-plugin::Google VLC plug-in;"
    /* WAV audio */
    "audio/wav:wav:WAV audio;"
    "audio/x-wav:wav:WAV audio;"
    /* 3GPP */
    "audio/3gpp:3gp,3gpp:3GPP audio;"
    "video/3gpp:3gp,3gpp:3GPP video;"
    /* 3GPP2 */
    "audio/3gpp2:3g2,3gpp2:3GPP2 audio;"
    "video/3gpp2:3g2,3gpp2:3GPP2 video;"
    /* DIVX */
    "video/divx:divx:DivX video;"
    /* FLV */
    "video/flv:flv:FLV video;"
    "video/x-flv:flv:FLV video;"
    /* Matroska */
    "application/x-matroska:mkv:Matroska video;"
    "video/x-matroska:mkv:Matroska video;"
    "audio/x-matroska:mka:Matroska audio;"
    /* XSPF */
    "application/xspf+xml:xspf:Playlist xspf;"
    /* M3U */
    "audio/x-mpegurl:m3u:MPEG audio;"
    /* Webm */
    "video/webm:webm:WebM video;"
    "audio/webm:webm:WebM audio;"
    /* Real Media */
    "application/vnd.rn-realmedia:rm:Real Media File;"
    "audio/x-realaudio:ra:Real Media Audio;"
    /* AMR */
    "audio/amr:amr:AMR audio;"
    /* FLAC */
    "audio/x-flac:flac:FLAC audio;"
    ;
109 110 111 112

/******************************************************************************
 * UNIX-only API calls
 *****************************************************************************/
113
NPP_GET_MIME_CONST char * NPP_GetMIMEDescription( void )
114
{
115
    return mimetype;
116 117 118 119
}

NPError NPP_GetValue( NPP instance, NPPVariable variable, void *value )
{
120
    static char psz_name[] = PLUGIN_NAME;
Sam Hocevar's avatar
Sam Hocevar committed
121
    static char psz_desc[1000];
122

123
    /* plugin class variables */
124 125 126
    switch( variable )
    {
        case NPPVpluginNameString:
127
            *((char **)value) = psz_name;
128 129 130
            return NPERR_NO_ERROR;

        case NPPVpluginDescriptionString:
131
            snprintf( psz_desc, sizeof(psz_desc), PLUGIN_DESCRIPTION,
132
                      libvlc_get_version() );
Sam Hocevar's avatar
Sam Hocevar committed
133
            *((char **)value) = psz_desc;
134
            return NPERR_NO_ERROR;
Sam Hocevar's avatar
Sam Hocevar committed
135

136 137 138 139 140 141
#if defined(XP_UNIX)
        case NPPVpluginNeedsXEmbed:
            *((bool *)value) = true;
            return NPERR_NO_ERROR;
#endif

Sam Hocevar's avatar
Sam Hocevar committed
142
        default:
143
            /* move on to instance variables ... */
144
            ;
145 146 147 148 149 150 151
    }

    if( instance == NULL )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

152
    /* plugin instance variables */
153

154
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
155
    if( NULL == p_plugin )
156
    {
157
        /* plugin has not been initialized yet ! */
158 159
        return NPERR_INVALID_INSTANCE_ERROR;
    }
160

161 162
    switch( variable )
    {
163
        case NPPVpluginScriptableNPObject:
164
        {
165 166 167
            /* retrieve plugin root class */
            NPClass *scriptClass = p_plugin->getScriptClass();
            if( scriptClass )
168
            {
169 170 171
                /* create an instance and return it */
                *(NPObject**)value = NPN_CreateObject(instance, scriptClass);
                return NPERR_NO_ERROR;
172 173
            }
            break;
174
        }
175

176
        default:
177
            ;
178
    }
179
    return NPERR_GENERIC_ERROR;
180 181
}

182 183 184 185 186
/*
 * there is some confusion in gecko headers regarding definition of this API
 * NPPVariable is wrongly defined as NPNVariable, which sounds incorrect.
 */

187
NPError NPP_SetValue( NPP, NPNVariable, void * )
188 189 190 191
{
    return NPERR_GENERIC_ERROR;
}

192 193 194 195 196
/******************************************************************************
 * General Plug-in Calls
 *****************************************************************************/
NPError NPP_Initialize( void )
{
197 198 199 200 201 202 203 204 205 206 207
#ifdef XP_UNIX
    NPError err = NPERR_NO_ERROR;
    bool supportsXEmbed = false;

    err = NPN_GetValue( NULL, NPNVSupportsXEmbedBool,
                        (void *)&supportsXEmbed );

    if ( err != NPERR_NO_ERROR || supportsXEmbed != true )
        return NPERR_INCOMPATIBLE_VERSION_ERROR;
#endif

208 209 210 211 212 213 214 215
    return NPERR_NO_ERROR;
}

void NPP_Shutdown( void )
{
    ;
}

216 217 218 219 220 221
static bool boolValue(const char *value) {
    return ( !strcmp(value, "1") ||
             !strcasecmp(value, "true") ||
             !strcasecmp(value, "yes") );
}

222
NPError NPP_New( NPMIMEType, NPP instance,
223
                 NPuint16_t mode, NPint16_t argc,
224
                 char* argn[], char* argv[], NPSavedData* )
225
{
226
    NPError status;
227
    VlcPluginBase *p_plugin;
228 229 230 231 232 233

    if( instance == NULL )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
    /* we need to tell whether the plugin will be windowless
     * before it is instantiated */
    bool windowless = false;
    for( int i = 0; i < argc; i++ )
    {
        if( !strcmp( argn[i], "windowless" ) )
        {
            windowless = boolValue(argv[i]);
            break;
        }
    }

#ifdef WINDOWLESS
    if( windowless )
    {
        /* set windowless flag */
        status = NPN_SetValue( instance, NPPVpluginWindowBool,
                                       (void *)false);
        if( NPERR_NO_ERROR != status )
        {
            return status;
        }
        status = NPN_SetValue( instance, NPPVpluginTransparentBool,
                                       (void *)false);
        if( NPERR_NO_ERROR != status )
        {
            return status;
        }

        p_plugin = new VlcWindowless( instance, mode );
    }
    else
#endif
    {
        p_plugin = new VlcPlugin( instance, mode );
    }
270
    if( NULL == p_plugin )
271 272 273 274
    {
        return NPERR_OUT_OF_MEMORY_ERROR;
    }

275
    status = p_plugin->init(argc, argn, argv);
276 277
    if( NPERR_NO_ERROR == status )
    {
278
        instance->pdata = reinterpret_cast<void*>(p_plugin);
279
    }
280 281
    else
    {
282 283
        delete p_plugin;
    }
284
    return status;
285 286
}

287
NPError NPP_Destroy( NPP instance, NPSavedData** )
288
{
289
    if( NULL == instance )
290 291
        return NPERR_INVALID_INSTANCE_ERROR;

292
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
293 294 295 296
    if( NULL == p_plugin )
        return NPERR_NO_ERROR;

    instance->pdata = NULL;
297

298 299
    if( p_plugin->playlist_isplaying() )
        p_plugin->playlist_stop();
300

301
    delete p_plugin;
302 303 304 305 306 307

    return NPERR_NO_ERROR;
}

NPError NPP_SetWindow( NPP instance, NPWindow* window )
{
308
    if( ! instance )
309 310 311 312
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

313
    /* NPP_SetWindow may be called before NPP_New (Opera) */
314
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
315
    if( NULL == p_plugin )
316 317 318 319
    {
        /* we should probably show a splash screen here */
        return NPERR_NO_ERROR;
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
320

321
    p_plugin->getVLC();
322

323 324 325 326 327 328 329 330
    /*
     * PLUGIN DEVELOPERS:
     *  Before setting window to point to the
     *  new window, you may wish to compare the new window
     *  info to the previous window (if any) to note window
     *  size changes, etc.
     */

331
    /* retrieve current window */
332
    NPWindow& curr_window = p_plugin->getWindow();
333

334
    if (window/* && window->window */) {
335 336
        if (!curr_window.window) {
            /* we've just been created */
337
            p_plugin->setWindow(*window);
338 339
            p_plugin->create_windows();
            p_plugin->resize_windows();
340
            p_plugin->set_player_window();
341 342

            /* now set plugin state to that requested in parameters */
343 344
            bool show_toolbar = p_plugin->get_options().get_show_toolbar();
            p_plugin->set_toolbar_visible( show_toolbar );
345 346 347 348 349 350 351 352

            /* handle streams properly */
            if( !p_plugin->b_stream )
            {
                if( p_plugin->psz_target )
                {
                    if( p_plugin->playlist_add( p_plugin->psz_target ) != -1 )
                    {
353
                        if( p_plugin->get_options().get_autoplay() )
354 355 356 357 358 359 360
                        {
                            p_plugin->playlist_play();
                        }
                    }
                    p_plugin->b_stream = true;
                }
            }
361 362

            p_plugin->update_controls();
363 364 365
        } else {
            if (window->window == curr_window.window) {
                /* resize / move notification */
366
                p_plugin->setWindow(*window);
367 368
                p_plugin->resize_windows();
            } else {
369
                /* plugin parent window was changed, notify plugin about it */
370 371 372 373
                p_plugin->destroy_windows();
                p_plugin->setWindow(*window);
                p_plugin->create_windows();
                p_plugin->resize_windows();
374
            }
375
        }
376
    } else {
377 378
        /* NOTE: on Windows, Opera does not call NPP_SetWindow
         * on window destruction. */
379 380 381 382
        if (curr_window.window) {
            /* we've been destroyed */
            p_plugin->destroy_windows();
        }
383
    }
384 385 386
    return NPERR_NO_ERROR;
}

387 388
NPError NPP_NewStream( NPP instance, NPMIMEType, NPStream *stream,
                       NPBool, NPuint16_t *stype )
389
{
390
    if( NULL == instance  )
391 392 393 394
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

395
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
396 397 398 399
    if( NULL == p_plugin )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }
400

401 402 403 404 405 406 407 408
   /*
   ** Firefox/Mozilla may decide to open a stream from the URL specified
   ** in the SRC parameter of the EMBED tag and pass it to us
   **
   ** since VLC will open the SRC URL as well, we're not interested in
   ** that stream. Otherwise, we'll take it and queue it up in the playlist
   */
    if( !p_plugin->psz_target || strcmp(stream->url, p_plugin->psz_target) )
409
    {
410 411 412
        /* TODO: use pipes !!!! */
        *stype = NP_ASFILEONLY;
        return NPERR_NO_ERROR;
413
    }
414
    return NPERR_GENERIC_ERROR;
415 416
}

417
NPint32_t NPP_WriteReady( NPP, NPStream *)
418
{
419 420
    /* TODO */
    return 8*1024;
421 422
}

423 424
NPint32_t NPP_Write( NPP, NPStream *, NPint32_t,
                 NPint32_t len, void * )
425
{
426 427
    /* TODO */
    return len;
428 429
}

430
NPError NPP_DestroyStream( NPP instance, NPStream *, NPError )
431 432 433 434 435 436 437 438
{
    if( instance == NULL )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }
    return NPERR_NO_ERROR;
}

439
void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* )
440 441 442 443 444 445
{
    if( instance == NULL )
    {
        return;
    }

446
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
447 448 449 450
    if( NULL == p_plugin )
    {
        return;
    }
451

452
    if( p_plugin->playlist_add( stream->url ) != -1 )
453
    {
454
        if( p_plugin->get_options().get_autoplay() )
455
        {
456
            p_plugin->playlist_play();
457 458
        }
    }
459
}
460

461 462
void NPP_URLNotify( NPP instance, const char* ,
                    NPReason, void* )
463 464 465 466 467 468 469 470 471 472
{
    /***** Insert NPP_URLNotify code here *****\
    PluginInstance* p_plugin;
    if (instance != NULL)
        p_plugin = (PluginInstance*) instance->pdata;
    \*********************************************/
}

void NPP_Print( NPP instance, NPPrint* printInfo )
{
473 474
    if( printInfo == NULL )
    {
475
        return;
476
    }
477

478 479 480
    if( instance != NULL )
    {
        /***** Insert NPP_Print code here *****\
481
        PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
482
        \**************************************/
483

484 485
        if( printInfo->mode == NP_FULL )
        {
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
            /*
             * PLUGIN DEVELOPERS:
             *  If your plugin would like to take over
             *  printing completely when it is in full-screen mode,
             *  set printInfo->pluginPrinted to TRUE and print your
             *  plugin as you see fit.  If your plugin wants Netscape
             *  to handle printing in this case, set
             *  printInfo->pluginPrinted to FALSE (the default) and
             *  do nothing.  If you do want to handle printing
             *  yourself, printOne is true if the print button
             *  (as opposed to the print menu) was clicked.
             *  On the Macintosh, platformPrint is a THPrint; on
             *  Windows, platformPrint is a structure
             *  (defined in npapi.h) containing the printer name, port,
             *  etc.
             */

503
            /***** Insert NPP_Print code here *****\
504 505 506 507
            void* platformPrint =
                printInfo->print.fullPrint.platformPrint;
            NPBool printOne =
                printInfo->print.fullPrint.printOne;
508
            \**************************************/
509 510

            /* Do the default*/
511
            printInfo->print.fullPrint.pluginPrinted = false;
512
        }
513 514 515
        else
        {
            /* If not fullscreen, we must be embedded */
516 517 518 519 520 521 522 523 524 525 526 527
            /*
             * PLUGIN DEVELOPERS:
             *  If your plugin is embedded, or is full-screen
             *  but you returned false in pluginPrinted above, NPP_Print
             *  will be called with mode == NP_EMBED.  The NPWindow
             *  in the printInfo gives the location and dimensions of
             *  the embedded plugin on the printed page.  On the
             *  Macintosh, platformPrint is the printer port; on
             *  Windows, platformPrint is the handle to the printing
             *  device context.
             */

528
            /***** Insert NPP_Print code here *****\
529 530 531 532
            NPWindow* printWindow =
                &(printInfo->print.embedPrint.window);
            void* platformPrint =
                printInfo->print.embedPrint.platformPrint;
533
            \**************************************/
534 535 536
        }
    }
}
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

int16_t NPP_HandleEvent( NPP instance, void * event )
{
    if( instance == NULL )
    {
        return false;
    }

    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
    if( p_plugin == NULL )
    {
        return false;
    }

    return p_plugin->handle_event(event);

}