vlcshell.cpp 16.4 KB
Newer Older
1
/*****************************************************************************
2
 * vlcshell.cpp: a VLC plugin for Mozilla
3
 *****************************************************************************
4
 * Copyright (C) 2002-2013 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
8
 *          Jean-Paul Saman <jpsaman@videolan.org>
9 10 11 12
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *          Cheng Sun <chengsun9@gmail.com>
 *          Felix Paul Kühne <fkuehne # videolan.org>
 *          Damien Fouilleul <damienf@videolan.org>
13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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
26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 28 29 30 31
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
32 33 34 35 36

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

37 38
#include <stdio.h>
#include <string.h>
39
#include <stdlib.h>
40

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
41
#include "common.h"
42
#include "vlcshell.h"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
43
#include "vlcplugin.h"
44

45 46 47 48 49 50 51 52 53 54 55
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;"
56
    "audio/m4a:m4a:MPEG-4 audio;"
57 58 59 60 61 62 63 64
    /* 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 */
65
    "video/quicktime:mov,qt:QuickTime video;"
66 67 68
    /* OGG */
    "application/ogg:ogg:Ogg stream;"
    "video/ogg:ogv:Ogg video;"
69
    "audio/ogg:oga:Ogg audio;"
70
    "application/x-ogg:ogg:Ogg stream;"
71 72
    /* Opus */
    "audio/ogg;codecs=opus:opus:Opus audio;"
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 109 110 111 112 113 114 115
    /* 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;"
116
    "audio/flac:flac:FLAC audio;"
117
    ;
118 119 120 121

/******************************************************************************
 * UNIX-only API calls
 *****************************************************************************/
122
NPP_GET_MIME_CONST char * NPP_GetMIMEDescription( void )
123
{
124
    return mimetype;
125 126 127 128
}

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

132
    /* plugin class variables */
133 134 135
    switch( variable )
    {
        case NPPVpluginNameString:
136
            *((char **)value) = psz_name;
137 138 139
            return NPERR_NO_ERROR;

        case NPPVpluginDescriptionString:
140
            snprintf( psz_desc, sizeof(psz_desc), PLUGIN_DESCRIPTION,
141
                      libvlc_get_version() );
Sam Hocevar's avatar
Sam Hocevar committed
142
            *((char **)value) = psz_desc;
143
            return NPERR_NO_ERROR;
Sam Hocevar's avatar
Sam Hocevar committed
144

145 146 147 148 149 150
#if defined(XP_UNIX)
        case NPPVpluginNeedsXEmbed:
            *((bool *)value) = true;
            return NPERR_NO_ERROR;
#endif

Sam Hocevar's avatar
Sam Hocevar committed
151
        default:
152
            /* move on to instance variables ... */
153
            ;
154 155 156 157 158 159 160
    }

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

161
    /* plugin instance variables */
162

163
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
164
    if( NULL == p_plugin )
165
    {
166
        /* plugin has not been initialized yet ! */
167 168
        return NPERR_INVALID_INSTANCE_ERROR;
    }
169

170 171
    switch( variable )
    {
172
        case NPPVpluginScriptableNPObject:
173
        {
174 175 176
            /* retrieve plugin root class */
            NPClass *scriptClass = p_plugin->getScriptClass();
            if( scriptClass )
177
            {
178 179 180
                /* create an instance and return it */
                *(NPObject**)value = NPN_CreateObject(instance, scriptClass);
                return NPERR_NO_ERROR;
181 182
            }
            break;
183
        }
184 185 186 187
#if defined(XP_MACOSX)
        case NPPVpluginCoreAnimationLayer:
        {
            if( instance )
188
                return p_plugin->get_root_layer(value);
189 190 191 192

            break;
        }
#endif
193

194
        default:
195
            ;
196
    }
197
    return NPERR_GENERIC_ERROR;
198 199
}

200
/*
201
 * there is some confusion in NPAPI headers regarding definition of this API
202 203 204
 * NPPVariable is wrongly defined as NPNVariable, which sounds incorrect.
 */

205
NPError NPP_SetValue( NPP, NPNVariable, void * )
206 207 208 209
{
    return NPERR_GENERIC_ERROR;
}

210 211 212 213 214
/******************************************************************************
 * General Plug-in Calls
 *****************************************************************************/
NPError NPP_Initialize( void )
{
215 216 217 218 219 220 221 222 223 224 225
#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

226 227 228 229 230 231 232 233
    return NPERR_NO_ERROR;
}

void NPP_Shutdown( void )
{
    ;
}

234 235 236 237 238 239
static bool boolValue(const char *value) {
    return ( !strcmp(value, "1") ||
             !strcasecmp(value, "true") ||
             !strcasecmp(value, "yes") );
}

240
NPError NPP_New( NPMIMEType, NPP instance,
241
                 NPuint16_t mode, NPint16_t argc,
242
                 char* argn[], char* argv[], NPSavedData* )
243
{
244
    NPError status;
245
    VlcPluginBase *p_plugin;
246 247 248 249 250 251

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

252
    bool windowless = false;
253 254 255 256 257 258 259 260 261 262 263 264 265
    /* we need to tell whether the plugin will be windowless
     * before it is instantiated */
    for( int i = 0; i < argc; i++ )
    {
        if( !strcmp( argn[i], "windowless" ) )
        {
            windowless = boolValue(argv[i]);
            break;
        }
    }

    if( windowless )
    {
266
        printf( "Using Windowless mode\n" );
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        /* 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
    {
        p_plugin = new VlcPlugin( instance, mode );
    }
287
    if( NULL == p_plugin )
288 289 290 291
    {
        return NPERR_OUT_OF_MEMORY_ERROR;
    }

292
    status = p_plugin->init(argc, argn, argv);
293 294
    if( NPERR_NO_ERROR == status )
    {
295
        instance->pdata = reinterpret_cast<void*>(p_plugin);
Gildas Bazin's avatar
Gildas Bazin committed
296
    }
297 298
    else
    {
299 300
        delete p_plugin;
    }
301
    return status;
302 303
}

304
NPError NPP_Destroy( NPP instance, NPSavedData** )
305
{
306
    if( NULL == instance )
307 308
        return NPERR_INVALID_INSTANCE_ERROR;

309
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
310 311 312 313
    if( NULL == p_plugin )
        return NPERR_NO_ERROR;

    instance->pdata = NULL;
314

315 316
    if( p_plugin->playlist_isplaying() )
        p_plugin->playlist_stop();
317

318 319
    p_plugin->destroy_windows();

320
    delete p_plugin;
321 322 323 324 325 326

    return NPERR_NO_ERROR;
}

NPError NPP_SetWindow( NPP instance, NPWindow* window )
{
327
    if( ! instance )
328 329 330 331
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

332
    /* NPP_SetWindow may be called before NPP_New (Opera) */
333
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
334
    if( NULL == p_plugin )
335 336 337 338
    {
        /* we should probably show a splash screen here */
        return NPERR_NO_ERROR;
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
339

340 341 342 343 344 345 346 347
    /*
     * 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.
     */

348
    /* retrieve current window */
349
    NPWindow& curr_window = p_plugin->getWindow();
350

351
    if (window/* && window->window */) {
352 353
        if (!curr_window.window) {
            /* we've just been created */
354
            p_plugin->setWindow(*window);
355 356
            p_plugin->create_windows();
            p_plugin->resize_windows();
357
            p_plugin->set_player_window();
358 359

            /* now set plugin state to that requested in parameters */
360 361
            bool show_toolbar = p_plugin->get_options().get_show_toolbar();
            p_plugin->set_toolbar_visible( show_toolbar );
362 363 364 365 366 367 368 369

            /* handle streams properly */
            if( !p_plugin->b_stream )
            {
                if( p_plugin->psz_target )
                {
                    if( p_plugin->playlist_add( p_plugin->psz_target ) != -1 )
                    {
370
                        if( p_plugin->get_options().get_autoplay() )
371 372 373 374 375 376 377
                        {
                            p_plugin->playlist_play();
                        }
                    }
                    p_plugin->b_stream = true;
                }
            }
378 379

            p_plugin->update_controls();
380 381 382
        } else {
            if (window->window == curr_window.window) {
                /* resize / move notification */
383
                p_plugin->setWindow(*window);
384 385
                p_plugin->resize_windows();
            } else {
386
                /* plugin parent window was changed, notify plugin about it */
387 388 389 390
                p_plugin->destroy_windows();
                p_plugin->setWindow(*window);
                p_plugin->create_windows();
                p_plugin->resize_windows();
391
            }
392
        }
393
    } else {
394 395
        /* NOTE: on Windows, Opera does not call NPP_SetWindow
         * on window destruction. */
396 397 398 399
        if (curr_window.window) {
            /* we've been destroyed */
            p_plugin->destroy_windows();
        }
400
    }
401 402 403
    return NPERR_NO_ERROR;
}

404 405
NPError NPP_NewStream( NPP instance, NPMIMEType, NPStream *stream,
                       NPBool, NPuint16_t *stype )
406
{
407
    if( NULL == instance  )
408 409 410 411
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }

412
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
413 414 415 416
    if( NULL == p_plugin )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }
417

418 419 420 421 422 423 424 425
   /*
   ** 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) )
426
    {
427 428 429
        /* TODO: use pipes !!!! */
        *stype = NP_ASFILEONLY;
        return NPERR_NO_ERROR;
430
    }
431
    return NPERR_GENERIC_ERROR;
432 433
}

434
NPint32_t NPP_WriteReady( NPP, NPStream *)
435
{
436 437
    /* TODO */
    return 8*1024;
438 439
}

440 441
NPint32_t NPP_Write( NPP, NPStream *, NPint32_t,
                 NPint32_t len, void * )
442
{
443 444
    /* TODO */
    return len;
445 446
}

447
NPError NPP_DestroyStream( NPP instance, NPStream *, NPError )
448 449 450 451 452 453 454 455
{
    if( instance == NULL )
    {
        return NPERR_INVALID_INSTANCE_ERROR;
    }
    return NPERR_NO_ERROR;
}

456
void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* )
457 458 459 460 461 462
{
    if( instance == NULL )
    {
        return;
    }

463
    VlcPluginBase *p_plugin = reinterpret_cast<VlcPluginBase *>(instance->pdata);
464 465 466 467
    if( NULL == p_plugin )
    {
        return;
    }
468

469
    if( p_plugin->playlist_add( stream->url ) != -1 )
470
    {
471
        if( p_plugin->get_options().get_autoplay() )
472
        {
473
            p_plugin->playlist_play();
474 475
        }
    }
476
}
477

478 479
void NPP_URLNotify( NPP instance, const char* ,
                    NPReason, void* )
480 481 482 483 484 485 486 487 488 489
{
    /***** Insert NPP_URLNotify code here *****\
    PluginInstance* p_plugin;
    if (instance != NULL)
        p_plugin = (PluginInstance*) instance->pdata;
    \*********************************************/
}

void NPP_Print( NPP instance, NPPrint* printInfo )
{
490 491
    if( printInfo == NULL )
    {
492
        return;
493
    }
494

495 496 497
    if( instance != NULL )
    {
        /***** Insert NPP_Print code here *****\
498
        PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
499
        \**************************************/
500

501 502
        if( printInfo->mode == NP_FULL )
        {
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
            /*
             * 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.
             */

520
            /***** Insert NPP_Print code here *****\
521 522 523 524
            void* platformPrint =
                printInfo->print.fullPrint.platformPrint;
            NPBool printOne =
                printInfo->print.fullPrint.printOne;
525
            \**************************************/
526 527

            /* Do the default*/
528
            printInfo->print.fullPrint.pluginPrinted = false;
529
        }
530 531 532
        else
        {
            /* If not fullscreen, we must be embedded */
533 534 535 536 537 538 539 540 541 542 543 544
            /*
             * 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.
             */

545
            /***** Insert NPP_Print code here *****\
546 547 548 549
            NPWindow* printWindow =
                &(printInfo->print.embedPrint.window);
            void* platformPrint =
                printInfo->print.embedPrint.platformPrint;
550
            \**************************************/
551 552 553
        }
    }
}
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570

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

}