vlcshell.cpp 15.9 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

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
37
#include "common.h"
38
#include "vlcshell.h"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
39
#include "vlcplugin.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
 * there is some confusion in NPAPI headers regarding definition of this API
184 185 186
 * 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
    /* 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 )
    {
249
        printf( "Using Windowless mode\n" );
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
        /* 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 );
    }
271
    if( NULL == p_plugin )
272 273 274 275
    {
        return NPERR_OUT_OF_MEMORY_ERROR;
    }

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

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

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

    instance->pdata = NULL;
298

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

302
    delete p_plugin;
303 304 305 306 307 308

    return NPERR_NO_ERROR;
}

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

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

322
    p_plugin->getVLC();
323

324 325 326 327 328 329 330 331
    /*
     * 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.
     */

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

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

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

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

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

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

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

402 403 404 405 406 407 408 409
   /*
   ** 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) )
410
    {
411 412 413
        /* TODO: use pipes !!!! */
        *stype = NP_ASFILEONLY;
        return NPERR_NO_ERROR;
414
    }
415
    return NPERR_GENERIC_ERROR;
416 417
}

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

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

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

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

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

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

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

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

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

485 486
        if( printInfo->mode == NP_FULL )
        {
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
            /*
             * 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.
             */

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

            /* Do the default*/
512
            printInfo->print.fullPrint.pluginPrinted = false;
513
        }
514 515 516
        else
        {
            /* If not fullscreen, we must be embedded */
517 518 519 520 521 522 523 524 525 526 527 528
            /*
             * 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.
             */

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

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);

}