Diff of /src/plugin.c [ff1c6a] .. [567293] Maximize Restore

  Switch to side-by-side view

--- a/src/plugin.c
+++ b/src/plugin.c
@@ -1,1012 +1,969 @@
-/* 
- * Copyright (C) 2000-2003 the xine project
- * 
+/*
+ * Copyright (C) 2000-2006 the xine project
+ *
  * This file is part of xine, a free video player.
- * 
+ *
  * xine 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.
- * 
+ *
  * xine 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
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  *
- * $Id$
- *
- * xine plugin for mozilla 
- *
+ * 
+ * Xine plugin for Mozilla/Firefox 
+ *      written by Claudio Ciccani <klan@users.sf.net>
+ *      
  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <pthread.h>
 
 #include <X11/X.h>
 #include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
-#include <string.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <pthread.h>
-
-#include <stdio.h>
-#include <math.h>
+#include <X11/keysym.h>
+
 #include <xine.h>
 #include <xine/xineutils.h>
 
 #include "npapi.h"
 
+#include "playlist.h"
+
+/*
 #define LOG
-
-static char         IsInitialised=0;
-static void        *lib_handle;
-static xine_t      *xine;
-
-#define INPUT_MOTION (ExposureMask | ButtonPressMask | KeyPressMask | \
-                      ButtonMotionMask | StructureNotifyMask |        \
-                      PropertyChangeMask | PointerMotionMask)
-
-#define MAX_URL      4096
-#define MAX_MIMETYPE 256
-#define MAX_DEMUX    80
-#define MAX_PLAYLIST 10
-
-#define OSD_TIMEOUT  10 /* 1 second */
+*/
+
+#ifdef LOG
+# define log(x, ...) \
+ do {\
+      fprintf (stderr, "Xine Plugin (%d): ", getpid());\
+      fprintf (stderr, x "\n", ##__VA_ARGS__);\
+      fflush  (stderr);\
+ } while (0)
+#else
+# define log(x, ...)
+#endif
+
+static int instance_num = 0;
 
 typedef struct {
   NPP                 instance;
 
-  Window              window;		/* parent window */
-  Window              video_window;	/* window used by libxine */
-  Display            *display;
-  int                 screen;
-  int                 width,height;
-  int                 xpos,ypos;
-  double              display_ratio;
-  x11_visual_t        vis;
-  
-  pthread_t           gui_thread;	/* thread to process X events */
-  pthread_t           misc_thread;	/* thread to update misc stuff (eg. osd) */
-  pthread_mutex_t     mutex;
-  
+  xine_t             *xine;
   xine_vo_driver_t   *vo_driver;
   xine_ao_driver_t   *ao_driver;
   xine_stream_t      *stream;
-
   xine_event_queue_t *event_queue;
-
-  char                *url_src;			/* src parameter from embed tag */
-  char                url[MAX_URL];		/* current playing url */
-  char                base_url[MAX_URL];	/* base for relative urls */
-  char                mime_type[MAX_MIMETYPE];	/* reported mime type */
-  char                demux[MAX_DEMUX];		/* xine demux id */
-
-  /*
-   * very simple playlist. it will be build from xine-lib events.
-   * used to support "reference streams" like asx, ram
-   */
-  char                playlist[MAX_PLAYLIST][MAX_URL];
-  int                 playlist_cur;
-  int                 playlist_entries;
-
-  int                 embed_mode;		/* true if embed tag used */
-  int                 loop_play;		/* loop parameter */
-  int                 IsFinished;
-
   xine_osd_t         *osd;
-  int                 osd_timeout;
-} plugin_instance_t;
-
-static void pprintf (const char *format, ...) {
-
-  va_list argp;
-
-#ifdef LOG
-  static FILE *log_fd=NULL;
-
-  if (!log_fd) {
-
-    log_fd = fopen ("/tmp/xine-plugin.log", "w");
-
-    if (log_fd) {
-      
-      setvbuf (log_fd, NULL, _IONBF, 0);
-
-      /* fprintf (log_fd, "\n---------------------------------------------\n\n"); */
-      
-    }
-  }
-
-  va_start (argp, format);
-    
-  if (log_fd) vfprintf (log_fd, format, argp);
-
-  va_end (argp);
-
-#else
-
-  va_start (argp, format);
-  vprintf (format, argp);
-  va_end (argp);
-  fflush(stdout);
-
-#endif
-}
-              
-/* fork2() -- like fork, but the new process is immediately orphaned
- *            (won't leave a zombie when it exits)                 
- * Returns 1 to the parent, not any meaningful pid.               
- * The parent cannot wait() for the new process (it's unrelated).
- */
-
-/* This version assumes that you *haven't* caught or ignored SIGCHLD. */
-/* If you have, then you should just be using fork() instead anyway.  */
-
-static int fork2() {
-  pid_t pid;
-  int status;
-  
-  sigset_t set,oset;
-  sigfillset(& set);
-  sigprocmask(SIG_SETMASK,&set,&oset);
-
-  if (!(pid = fork())) {
-    switch (fork()) {
-    case 0:    
-      sigprocmask(SIG_SETMASK,&oset,&set);
-      return 0;
-    case -1: 
-      _exit(errno);    /* assumes all errnos are <256 */
-    default: 
-      _exit(0);
-    }
-  }
-  
-  if (pid < 0 || waitpid(pid,&status,0) < 0) {
-      pprintf ("waitpid failed! (pid==%d)\n", pid);
-    sigprocmask(SIG_SETMASK,&oset,&set);
-    return -1;
-  }
-  sigprocmask(SIG_SETMASK,&oset,&set);
-  
-  if (WIFEXITED(status))
-    if (WEXITSTATUS(status) == 0) {
-      return 1;
-    } else
-      errno = WEXITSTATUS(status);
-  else
-    errno = EINTR;  /* well, sort of :-) */
-  
-  return -1;
-}
-
-static void launch_xine (plugin_instance_t *this) {
-
-  if (!fork2()) {
-    char cmd [MAX_URL+20];
-    
-    snprintf (cmd, sizeof(cmd), "xine --enqueue '%s'", this->url);
-
-    pprintf("lauching \"%s\"\n", cmd);
-    
-    system (cmd);
-    
-    _exit (0);
-  }
-}
-
-
-static void dest_size_cb (void *data,
-                          int video_width, int video_height,
-                          double video_pixel_aspect,
-                          int *dest_width, int *dest_height,
-                          double *dest_pixel_aspect)  {
-  plugin_instance_t  *this = (plugin_instance_t *) data;
-  
-  if(this == NULL)
+
+  Display            *display;
+  int                 screen;
+  Window              window;
+  int                 x, y;
+  int                 w, h;
+
+  int                 loop;
+
+  char                dmx[32];
+  char                mrl[1024];
+
+  pthread_mutex_t     mutex;
+  pthread_t           thread;
+} xine_plugin_t;
+
+#define OSD_TIMEOUT    5        /* in seconds */
+#define OSD_TEXT_PLAY  ">"
+#define OSD_TEXT_STOP  "}"
+#define OSD_TEXT_PAUSE "<"
+#define OSD_TEXT_QUIT  "{"
+
+/*****************************************************************************/
+
+static void
+dest_size_cb (void *data,
+              int video_width, int video_height,
+              double video_pixel_aspect,
+              int *dest_width, int *dest_height, double *dest_pixel_aspect)
+{
+  xine_plugin_t *this = data;
+
+  *dest_width = this->w;
+  *dest_height = this->h;
+  *dest_pixel_aspect = video_pixel_aspect ? : 1.0;
+}
+
+static void
+frame_output_cb (void *data,
+                 int video_width, int video_height,
+                 double video_pixel_aspect,
+                 int *dest_x, int *dest_y,
+                 int *dest_width, int *dest_height,
+                 double *dest_pixel_aspect, int *win_x, int *win_y)
+{
+  xine_plugin_t *this = data;
+
+  *dest_x = 0;
+  *dest_y = 0;
+  *win_x = this->x;
+  *win_y = this->y;
+  *dest_width = this->w;
+  *dest_height = this->h;
+  *dest_pixel_aspect = video_pixel_aspect ? : 1.0;
+}
+
+/*****************************************************************************/
+
+static void osd_show_text (xine_plugin_t *this, const char *text) {
+  char *s = (char *) text;
+  int   y = 0;
+
+  if (!this->osd)
     return;
-  
-  *dest_width        = this->width;
-  *dest_height       = this->height;
-  *dest_pixel_aspect = this->display_ratio;
-}
-
-static void frame_output_cb (void *data,
-                             int video_width, int video_height,
-                             double video_pixel_aspect,
-                             int *dest_x, int *dest_y,
-                             int *dest_width, int *dest_height,
-                             double *dest_pixel_aspect,
-                             int *win_x, int *win_y) {
-  plugin_instance_t* this = (plugin_instance_t *) data;
-
-  if(this == NULL)
-    return;
-  
-  *dest_x            = 0;
-  *dest_y            = 0;
-  *win_x             = this->xpos;
-  *win_y             = this->ypos;
-  *dest_width        = this->width;
-  *dest_height       = this->height;
-  *dest_pixel_aspect = this->display_ratio;
-}
-
-
-
-static xine_vo_driver_t *load_video_out_driver(plugin_instance_t *this) {
-  double              res_h, res_v;
-  xine_vo_driver_t   *vo_driver;
-
-  pprintf("load_video_out_driver()\n");
-
-  this->vis.display     = this->display;
-  this->vis.screen      = this->screen;
-  this->vis.d           = this->video_window;
-  
-  XLockDisplay(this->display);
-  res_h                 = (DisplayWidth  (this->display, this->screen)*1000 
-			   / DisplayWidthMM (this->display, this->screen));
-  res_v                 = (DisplayHeight (this->display, this->screen)*1000
-			   / DisplayHeightMM (this->display, this->screen));
-  XUnlockDisplay(this->display);
-  
-  this->display_ratio   = res_h / res_v;
-  
-  if (fabs(this->display_ratio - 1.0) < 0.01)
-    this->display_ratio = 1.0;
-
-  this->vis.dest_size_cb     = dest_size_cb;
-  this->vis.frame_output_cb  = frame_output_cb;
-  this->vis.user_data        = this;
-  
-  /* TODO: try config value and then fallback to autoprobing */
-  
-  vo_driver = xine_open_video_driver(xine, NULL,
-				     XINE_VISUAL_TYPE_X11, (void *) &(this->vis));
-  
-  return vo_driver;
-}
-
-static xine_ao_driver_t *load_audio_out_driver(plugin_instance_t *this) {
-  xine_ao_driver_t *ao_driver;
-
-  pprintf("load_audio_out_driver()\n");
-  
-  /* TODO: try config value and then fallback to autoprobing */
-  
-  ao_driver = xine_open_audio_driver (xine, NULL, NULL);
-  
-  return ao_driver;
-}
-
-  
-void xine_loop (void *param) {
-  plugin_instance_t  *this= (plugin_instance_t *) param;
-
-  pprintf("*** main loop started ***\n");
- 
-  while (this->IsFinished == 0) {
-    XEvent event;
-    int    got_event;
-
-    XLockDisplay(this->display);
-    got_event = XPending(this->display);
-    if( got_event )
-      XNextEvent(this->display, &event);
-    XUnlockDisplay(this->display);
-    
-    if( !got_event ) {
-      xine_usec_sleep(20000);
+
+  pthread_mutex_lock (&this->mutex);
+
+  xine_osd_clear (this->osd);
+
+  while (s && *s) {
+    char *n = strchr (s, '\n');
+    if (n) {
+      char buf[n-s+1];
+      int w, h;
+      strncpy (buf, s, n-s);
+      buf[n-s] = '\0';
+      xine_osd_draw_text (this->osd, 0, y, buf, XINE_OSD_TEXT1);
+      xine_osd_get_text_size (this->osd, buf, &w, &h);
+      y += h;
+    } else {
+      xine_osd_draw_text (this->osd, 0, y, s, XINE_OSD_TEXT1);
+    }
+    s = n;
+    if (s) s++;
+  }
+
+  xine_osd_show (this->osd, 0);
+  xine_osd_hide (this->osd,
+                 xine_get_current_vpts (this->stream) +
+                 OSD_TIMEOUT * 90000);
+
+  pthread_mutex_unlock (&this->mutex);
+}
+
+static void *player_thread (void *data) {
+  xine_plugin_t *this = data;
+
+  log ("playing \"%s\"...", this->mrl);
+
+  if (!xine_open (this->stream, this->mrl)) {
+    log ("xine_open() failed!");
+    NPN_Status (this->instance, "xine-plugin: error opening stream.");
+    return (void *) 1;
+  }
+
+  log ("... stream opened ...");
+
+  pthread_testcancel ();
+
+  if (!xine_play (this->stream, 0, 0)) {
+    log ("xine_play() failed!");
+    NPN_Status (this->instance, "xine-plugin: error playing stream.");
+    return (void *) 1;
+  }
+
+  log ("... playback started.");
+
+  while (1) {
+    XEvent evt;
+    int    got = 0;
+    int    key;
+
+    pthread_testcancel ();
+
+    pthread_mutex_lock (&this->mutex);
+    if (this->window) {
+      XLockDisplay (this->display);
+      got = XPending (this->display);
+      if (got)
+        XNextEvent (this->display, &evt);
+      XUnlockDisplay (this->display);
+    }
+    pthread_mutex_unlock (&this->mutex);
+
+    pthread_testcancel ();
+
+    if (!got) {
+      xine_usec_sleep (20000);
       continue;
     }
-    
-    if( got_event ) {
-    
-      if(event.xany.window != this->video_window)
-        continue;
-  
-      switch (event.type) {
+
+    if (evt.xany.window != this->window)
+      continue;
+
+    switch (evt.type) {
+      case KeyPress:
+        key = XLookupKeysym (&evt.xkey, 0);
+        switch (key) {
+          case XK_Escape:
+            osd_show_text (this, OSD_TEXT_QUIT);
+            xine_stop (this->stream);
+            xine_close (this->stream);
+            return (void *) 0;
+          case XK_Return:
+            if (xine_get_status (this->stream) == XINE_STATUS_PLAY) {
+              xine_stop (this->stream);
+              osd_show_text (this, OSD_TEXT_STOP);
+            } else {
+              xine_play (this->stream, 0, 0);
+              osd_show_text (this, OSD_TEXT_PLAY);
+            }
+            break;
+          case XK_Pause:
+          case XK_space:
+            if (xine_get_param (this->stream,
+                                XINE_PARAM_SPEED) == XINE_SPEED_PAUSE) {
+              xine_set_param (this->stream,
+                              XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+              osd_show_text (this, OSD_TEXT_PLAY);
+            } else {
+              xine_set_param (this->stream,
+                              XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+              osd_show_text (this, OSD_TEXT_PAUSE);
+            }
+            break;
+          case XK_Right:
+            if (xine_get_stream_info (this->stream,
+                                      XINE_STREAM_INFO_SEEKABLE)) {
+              int pos = 0;
+              if (xine_get_pos_length (this->stream, NULL, &pos, NULL))
+                xine_play (this->stream, 0, pos + 30000);
+            }
+            break;
+          case XK_Left:
+            if (xine_get_stream_info (this->stream,
+                                      XINE_STREAM_INFO_SEEKABLE)) {
+              int pos = 0;
+              if (xine_get_pos_length (this->stream, NULL, &pos, NULL))
+                xine_play (this->stream, 0, pos - 30000);
+            }
+            break;
+          case XK_F1:
+          case XK_F2:
+          case XK_F3:
+          case XK_F4:
+          case XK_F5:
+          case XK_F6:
+          case XK_F7:
+          case XK_F8:
+          case XK_F9:
+            if (xine_get_stream_info (this->stream,
+                                      XINE_STREAM_INFO_SEEKABLE)) {
+              int len = 0;
+              if (xine_get_pos_length (this->stream, NULL, NULL, &len))
+                xine_play (this->stream, 0, (key - XK_F1 + 1) * len / 10);
+            }
+            break;
+          case XK_Up:
+            xine_set_param (this->stream, XINE_PARAM_AUDIO_VOLUME,
+                            xine_get_param (this->stream,
+                                            XINE_PARAM_AUDIO_VOLUME) + 10);
+            break;
+          case XK_Down:
+            xine_set_param (this->stream, XINE_PARAM_AUDIO_VOLUME,
+                            xine_get_param (this->stream,
+                                            XINE_PARAM_AUDIO_VOLUME) - 10);
+            break;
+          case XK_Tab:{
+              char buf[22];
+              int  pos = 0;
+
+              xine_get_pos_length (this->stream, NULL, &pos, NULL);
+              pos /= 1000;
+              snprintf (buf, sizeof(buf), "%d:%02d:%02d",
+                        pos / 3600, (pos / 60) % 60, pos % 60);
+              osd_show_text (this, buf);
+            }
+            break;
+          case XK_I:
+          case XK_i:{
+              char buf[512];
+              int  vw, vh, vb;
+              int  ar, ac, ab;
+              int  bit, len = 0;
+
+              vw = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_VIDEO_WIDTH);
+              vh = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_VIDEO_HEIGHT);
+              vb = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_VIDEO_BITRATE);
+              ar = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_AUDIO_SAMPLERATE);
+              ac = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_AUDIO_CHANNELS);
+              ab = xine_get_stream_info (this->stream,
+                                         XINE_STREAM_INFO_AUDIO_BITRATE);
+
+              bit = xine_get_stream_info (this->stream,
+                                          XINE_STREAM_INFO_BITRATE);
+              xine_get_pos_length (this->stream, NULL, NULL, &len);
+              len /= 1000;
+
+              snprintf (buf, sizeof(buf),
+                        "Media: %d:%02d:%02d (%dKb/s)\n"
+                        "Video: %dx%d (%dKb/s)\n"
+                        "Audio: %dKHz %dch (%dKb/s)",
+                        len / 3600, (len / 60) % 60, len % 60, bit / 1000,
+                        vw, vh, vb / 1000, ar / 1000, ac, ab / 1000);
+              osd_show_text (this, buf);
+            } 
+            break;
+          default:
+            break;
+        }
+        break;
+
       case Expose:
-  
-        if (event.xexpose.count != 0)
+        if (evt.xexpose.count != 0)
           break;
-        
-        xine_gui_send_vo_data (this->stream, XINE_GUI_SEND_EXPOSE_EVENT, &event);
+        xine_gui_send_vo_data (this->stream,
+                               XINE_GUI_SEND_EXPOSE_EVENT, &evt);
         break;
-      
-      case ConfigureNotify:
-        {
-          XConfigureEvent *cev = (XConfigureEvent *) &event;
-          Window tmp_win;
-  
-          this->width  = cev->width;
-          this->height = cev->height;
-          
-          if ((cev->x == 0) && (cev->y == 0)) {
-            XLockDisplay(cev->display);
-            XTranslateCoordinates(cev->display, cev->window,
-                                  DefaultRootWindow(cev->display),
-                                  0, 0, &this->xpos, &this->ypos, &tmp_win);
-            XUnlockDisplay(cev->display);
+
+      case ConfigureNotify:{
+          XConfigureEvent *cev = (XConfigureEvent *) &evt;
+          Window tmp;
+
+          if (cev->x == 0 && cev->y == 0) {
+            pthread_mutex_lock (&this->mutex);
+            XLockDisplay (cev->display);
+            XTranslateCoordinates (this->display, cev->window,
+                                   DefaultRootWindow (cev->display),
+                                   0, 0, &this->x, &this->y, &tmp);
+            XUnlockDisplay (cev->display);
+            pthread_mutex_unlock (&this->mutex);
+          } else {
+            this->x = cev->x;
+            this->y = cev->y;
           }
-          else {
-            this->xpos = cev->x;
-            this->ypos = cev->y;
+        } 
+        break;
+
+      default:
+        break;
+    }
+  }
+
+  return (void *) 0;
+}
+
+static void playback_stop (xine_plugin_t *this) {
+  if (this->thread) {
+    log ("closing stream...");
+    xine_stop (this->stream);
+    xine_close (this->stream);
+    log ("...stream closed.");
+    log ("stopping player...");
+    pthread_mutex_lock (&this->mutex);
+    pthread_cancel (this->thread);
+    pthread_mutex_unlock (&this->mutex);
+    pthread_join (this->thread, NULL);
+    this->thread = 0;
+    log ("...player stopped.");
+  }
+}
+
+static void playback_start (xine_plugin_t *this) {
+  log ("starting player...");
+  if (pthread_create (&this->thread, NULL, player_thread, this))
+    log ("pthread_create() failed!");
+}
+
+/*****************************************************************************/
+
+static xine_t *xine_create (void) {
+  xine_t *xine;
+  char    path[1024];
+
+  xine = xine_new ();
+  if (!xine) {
+    log ("xine_new() failed!");
+    return NULL;
+  }
+
+  snprintf (path, sizeof(path), "%s", getenv ("XINERC") ? : "");
+  if (!*path) {
+    snprintf (path, sizeof(path), "%s/.xine", xine_get_homedir());
+    mkdir (path, 0755);
+    snprintf (path, sizeof(path), "%s/.xine/config", xine_get_homedir());
+  }
+
+  xine_config_load (xine, path);
+
+  xine_init (xine);
+
+  return xine;
+}
+
+static void event_listner_cb (void *data, const xine_event_t *event) {
+  xine_plugin_t *this = data;
+
+  switch (event->type) {
+    case XINE_EVENT_UI_PLAYBACK_FINISHED:
+      log ("playback finished.");
+      if (--this->loop > 0)
+        xine_play (this->stream, 0, 0);
+      else
+        xine_stop (this->stream);
+      break;
+
+    case XINE_EVENT_MRL_REFERENCE:
+      if (event->data) {
+        xine_mrl_reference_data_t *ref = event->data;
+        int len = 0;
+
+        log ("got reference mrl \"%s\".", ref->mrl);
+
+        if (!strstr (ref->mrl, "://") && access (ref->mrl, F_OK)) {
+          char *tmp;
+          tmp = strrchr (this->mrl, '/');
+          if (tmp) {
+            *(tmp+1) = '\0';
+            len = strlen (this->mrl);
           }
         }
-        break;
+        snprintf (this->mrl+len, sizeof(this->mrl)-len, "%s", ref->mrl);
+
+        playback_stop (this);
+        playback_start (this);
+      }
+      break;
+
+    case XINE_EVENT_PROGRESS:
+      if (event->data) {
+        xine_progress_data_t *data = event->data;
+        char buf[256];
+
+        snprintf (buf, sizeof(buf), "%s %d%%",
+                  data->description, data->percent);
+        osd_show_text (this, buf);
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+static NPError stream_create (xine_plugin_t *this) {
+
+  if (!this->vo_driver) {
+    if (this->window) {
+      const char   *driver = NULL;
+      x11_visual_t  visual;
       
+      /* Workaround for xv video driver returning 
+       * success from probe either if xv port is busy.
+       */
+      if (instance_num > 1)
+        driver = "xshm"; 
+
+      visual.display = this->display;
+      visual.screen = this->screen;
+      visual.d = this->window;
+
+      visual.dest_size_cb = dest_size_cb;
+      visual.frame_output_cb = frame_output_cb;
+      visual.user_data = this;
+
+      this->vo_driver = xine_open_video_driver (this->xine, driver,
+                                                XINE_VISUAL_TYPE_X11,
+                                                &visual);
+    } else {
+      this->vo_driver = xine_open_video_driver (this->xine, "none",
+                                                XINE_VISUAL_TYPE_NONE,
+                                                NULL);
+    }
+
+    if (!this->vo_driver) {
+      log ("xine_open_video_driver() failed!");
+      NPN_Status (this->instance, "xine-plugin: error opening video driver.");
+      return NPERR_MODULE_LOAD_FAILED_ERROR;
+    }
+  }
+
+  if (!this->ao_driver) {
+    this->ao_driver = xine_open_audio_driver (this->xine, NULL, NULL);
+    if (!this->ao_driver) {
+      log ("xine_open_audio_driver() failed!");
+      NPN_Status (this->instance, "xine-plugin: error opening audio driver.");
+      return NPERR_MODULE_LOAD_FAILED_ERROR;
+    }
+  }
+
+  if (!this->stream) {
+    this->stream = xine_stream_new (this->xine,
+                                    this->ao_driver, this->vo_driver);
+    if (!this->stream) {
+      log ("xine_stream_new() failed!");
+      return NPERR_OUT_OF_MEMORY_ERROR;
+    }
+    xine_gui_send_vo_data (this->stream, XINE_GUI_SEND_EXPOSE_EVENT, NULL);
+  }
+
+  if (!this->event_queue) {
+    this->event_queue = xine_event_new_queue (this->stream);
+    if (!this->event_queue) {
+      log ("xine_event_new_queue() failed!");
+      return NPERR_OUT_OF_MEMORY_ERROR;
+    }
+
+    xine_event_create_listener_thread (this->event_queue,
+                                       event_listner_cb, this);
+  }
+
+  if (!this->osd) {
+    this->osd = xine_osd_new (this->stream, 0, 0, 240, 80);
+    if (!this->osd) {
+      log ("xine_osd_new() failed!");
+      return NPERR_OUT_OF_MEMORY_ERROR;
+    }
+    xine_osd_set_font (this->osd, "cetus", 16);
+    xine_osd_set_text_palette (this->osd,
+                               XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT,
+                               XINE_OSD_TEXT1);
+    xine_osd_set_position (this->osd, 3, 3);
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+
+/*****************************************************************************/
+
+/* Called only once after installation. */
+char *NPP_GetMIMEDescription (void) {
+  xine_t      *xine;
+  static char  buf[4096];
+  int          len;
+
+  log ("NPP_GetMIMEDescription()");
+
+  xine = xine_create ();
+  if (!xine)
+    return "";
+
+  strncpy (buf, xine_get_mime_types(xine), sizeof(buf));
+  buf[sizeof(buf)-1] = '\0';
+
+  len = strlen (buf);
+  snprintf (buf+len, sizeof(buf)-len, "audio/x-scpls: pls: Winamp Playlist");
+
+  xine_exit (xine);
+
+  return buf;
+}
+
+NPError NPP_GetValue (void *instance, NPPVariable variable, void *value) {
+  log ("NPP_GetValue( variable=%d )", variable);
+
+  switch (variable) {
+    case NPPVpluginNameString:
+      *((char **) value) = 
+                "Xine Plugin " VERSION;
+      break;
+    case NPPVpluginDescriptionString:
+      *((char **) value) = 
+                "Xine Plugin version " VERSION ", "
+                "(c) <a href=http://www.xinehq.de>The Xine Project</a>.";
+      break;
+    default:
+      return NPERR_GENERIC_ERROR;
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+jref NPP_GetJavaClass (void) {
+  log ("NPP_GetJavaClass()");
+
+  return NULL;
+}
+
+NPError NPP_Initialize (void) {
+  log ("NPP_Initialize()");
+
+  if (!XInitThreads ()) {
+    log ("XInitThreads() failed!");
+    return NPERR_GENERIC_ERROR;
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+NPError NPP_New (NPMIMEType mimetype, NPP instance, uint16 mode,
+                 int16 argc, char *argn[], char *argv[],
+                 NPSavedData * saved) {
+  xine_plugin_t *this;
+  char          *mrl = NULL;
+  int            loop = 1;
+  char          *demux;
+  int            i;
+
+  log ("NPP_New( mimetype=%s, instance=%p, mode=%d )",
+       mimetype, instance, mode);
+
+  if (!instance)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  for (i = 0; i < argc; i++) {
+    log ("param(%s) = \"%s\"", argn[i], argv[i]);
+
+    if (!strcasecmp (argn[i], "loop")) {
+      if (!strcasecmp (argv[i], "true"))
+        loop = 0x7fffffff;
+      else if (isdigit (*argv[i]))
+        loop = atoi (argv[i]);
+    } 
+    else if (!strcasecmp (argn[i], "repeat") ||
+             !strcasecmp (argn[i], "numloop") ||
+             !strcasecmp (argn[i], "playcount")) {
+      loop = atoi (argv[i]);
+    }
+    else if (!strcasecmp (argn[i], "controls")) {
+      /* Ignore Real Player control panels. */
+      if (strcasecmp (argv[i], "ImageWindow"))
+        return NPERR_INVALID_PARAM;
+    } 
+    else if (!strcasecmp (argn[i], "src") ||
+             !strcasecmp (argn[i], "href") ||
+             !strcasecmp (argn[i], "qtsrc")) {
+      mrl = argv[i];
+    }
+  }
+
+  this = NPN_MemAlloc (sizeof(xine_plugin_t));
+  if (!this)
+    return NPERR_OUT_OF_MEMORY_ERROR;
+
+  memset (this, 0, sizeof(xine_plugin_t));
+
+  this->instance = instance;
+  this->loop = loop;
+
+  this->xine = xine_create ();
+  if (!this->xine) {
+    NPN_MemFree (this);
+    return NPERR_GENERIC_ERROR;
+  }
+
+  this->display = XOpenDisplay (getenv ("DISPLAY"));
+  if (!this->display) {
+    log ("XOpenDisplay() failed!");
+    xine_exit (this->xine);
+    NPN_MemFree (this);
+    return NPERR_GENERIC_ERROR;
+  }
+
+  XLockDisplay (this->display);
+  this->screen = DefaultScreen (this->display);
+  XUnlockDisplay (this->display);
+
+  demux = xine_get_demux_for_mime_type (this->xine, mimetype);
+  if (demux && *demux)
+    snprintf (this->dmx, sizeof(this->dmx), "%s", demux);
+
+  if (mrl && *mrl) {
+    i = snprintf (this->mrl, sizeof(this->mrl), "%s", mrl);
+    if (*this->dmx)
+      snprintf (this->mrl+i, sizeof(this->mrl)-i, "#demux:%s", this->dmx);
+  }
+
+  pthread_mutex_init (&this->mutex, NULL);
+
+  instance->pdata = this;
+  
+  instance_num++;
+
+  return NPERR_NO_ERROR;
+}
+
+NPError NPP_SetWindow (NPP instance, NPWindow *window) {
+  xine_plugin_t *this;
+
+  log ("NPP_SetWindow( instance=%p, window=%p )", instance, window);
+
+  if (!instance || !instance->pdata)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  this = instance->pdata;
+
+  if (!window || !window->window) {
+    if (this->stream) {
+      xine_set_param (this->stream, XINE_PARAM_IGNORE_VIDEO, 1);
+    }
+    else if (this->window) {
+      log ("destroying window.");
+      pthread_mutex_lock (&this->mutex);
+      
+      XLockDisplay (this->display);
+      XUnmapWindow (this->display, this->window);
+      XDestroyWindow (this->display, this->window);
+      XUnlockDisplay (this->display);
+      this->window = 0;
+      
+      pthread_mutex_unlock (&this->mutex);
+    }
+  } 
+  else {
+    if (this->window == 0 || 
+        this->w != window->width || this->h != window->height) {
+      XWindowAttributes attr;
+      unsigned int      blackpix;
+
+      pthread_mutex_lock (&this->mutex);
+
+      XLockDisplay (this->display);
+
+      if (this->window) {
+        log ("window resized: %dx%d -> %dx%d.",
+             this->w, this->h, (int) window->width, (int) window->height);
+        XUnmapWindow (this->display, this->window);
+        XDestroyWindow (this->display, this->window);
       }
-    }
-  }
-
-  pprintf("*** main loop finished ***\n");
-  pthread_exit(NULL);
-}
-
-void misc_loop (void *param) {
-  plugin_instance_t  *this= (plugin_instance_t *) param;
-
-  pprintf("*** misc loop started ***\n");
-
-  while (this->IsFinished == 0) {
-    xine_usec_sleep(100000);
+
+      XGetWindowAttributes (this->display, (Window) window->window, &attr);
+      this->x = attr.x;
+      this->y = attr.y;
+      this->w = attr.width;
+      this->h = attr.height;
+
+      blackpix = BlackPixel (this->display, this->screen);
+
+      this->window = XCreateSimpleWindow (this->display, (Window)window->window,
+                                          this->x, this->y, this->w, this->h, 1,
+                                          blackpix, blackpix);
+      XSelectInput (this->display, this->window,
+                    ExposureMask | KeyPressMask | StructureNotifyMask |
+                    PropertyChangeMask);
+      XRaiseWindow (this->display, this->window);
+      XMapWindow (this->display, this->window);
+
+      XUnlockDisplay (this->display);
+
+      pthread_mutex_unlock (&this->mutex);
+
+      if (this->stream) {
+        xine_gui_send_vo_data (this->stream,
+                               XINE_GUI_SEND_DRAWABLE_CHANGED,
+                               (void *) this->window);
+      }
+    }
     
-    pthread_mutex_lock(&this->mutex);
-    if( this->osd_timeout ) {
-      this->osd_timeout--;
-      
-      if( !this->osd_timeout ) {
-        xine_osd_hide(this->osd, 0);
-      }
-    }
-    pthread_mutex_unlock(&this->mutex);
-  }
-
-  pprintf("*** misc loop finished ***\n");
-  pthread_exit(NULL);
-}
-
-
-static void event_listener(void *user_data, const xine_event_t *event) {
-  plugin_instance_t  *this = (plugin_instance_t *) user_data;
-  int i;
+    if (this->stream)
+      xine_set_param (this->stream, XINE_PARAM_IGNORE_VIDEO, 0);
+  }
+
+  if (!this->stream && strstr (this->mrl, "://")) {
+    /* Start playback now since these protocols
+     * are not supported by mozilla & therefore
+     * NPP_NewStream() won't be called.
+     */
+    if (!strncasecmp (this->mrl, "mms", 3) ||
+        !strncasecmp (this->mrl, "pnm", 3) ||
+        !strncasecmp (this->mrl, "rtsp", 4)) {
+      int ret;
+      ret = stream_create (this);
+      if (ret)
+        return ret;
+      playback_start (this);
+    }
+  }
+
+  return NPERR_NO_ERROR;
+}
+
+NPError NPP_NewStream (NPP instance, NPMIMEType mimetype,
+                       NPStream *stream, NPBool seekable, uint16 *stype) {
+  xine_plugin_t *this;
+  char          *demux;
+  int            len;
+  int            ret;
+
+  log ("NPP_NewStream( instance=%p, mimetype=%s, stream=%p, seekable=%d )",
+       instance, mimetype, stream, seekable);
+
+  if (!instance || !instance->pdata)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  this = instance->pdata;
+
+  if (this->stream) {
+    *stype = NP_NORMAL;
+    return NPERR_NO_ERROR;
+  }
+
+  ret = stream_create (this);
+  if (ret)
+    return ret;
+
+  /* Check for playlist. */
+  if (playlist_type (stream->url)) {
+    log ("playlist detected, requesting a local copy.");
+    NPN_Status (instance, "xine-plugin: playlist detected, requesting a local copy.");
+    *stype = NP_ASFILEONLY;
+    return NPERR_NO_ERROR;
+  }
+
+  demux = xine_get_demux_for_mime_type (this->xine, mimetype);
+  if (demux && *demux)
+    snprintf (this->dmx, sizeof(this->dmx), "%s", demux);
+
+  len = snprintf (this->mrl, sizeof(this->mrl), "%s", stream->url);
+  if (*this->dmx)
+    snprintf (this->mrl+len, sizeof(this->mrl)-len, "#demux:%s", this->dmx);
+
+  playback_start (this);
+
+  *stype = NP_NORMAL;
+
+  return NPERR_NO_ERROR;
+}
+
+int32 NPP_WriteReady (NPP instance, NPStream *stream) {
+  log ("NPP_WriteReady( instance=%p, stream=%p )", instance, stream);
+
+  return 0x0fffffff;
+}
+
+int32 NPP_Write (NPP instance, NPStream *stream,
+                 int32 offset, int32 len, void *buffer) {
+  log ("NPP_Write( instance=%p, stream=%p, offset=%d, len=%d, buffer=%p )",
+       instance, stream, (int) offset, (int) len, buffer);
+
+  return -1;
+}
+
+void NPP_StreamAsFile (NPP instance, NPStream *stream, const char *file) {
+  xine_plugin_t *this;
+  char           buf[4096];
+  char          *mrl;
+  int            len = 0;
+
+  log ("NPP_StreamAsFile( instance=%p, stream=%p, file=%s )",
+       instance, stream, file);
+
+  if (!instance || !instance->pdata)
+    return;
+
+  this = instance->pdata;
+
+  mrl = playlist_parse (playlist_type (stream->url), file, buf, sizeof(buf));
+  if (!mrl) {
+    log ("no mrl found in \"%s\".", file);
+    NPN_Status (instance, "xine-plugin: no mrl found in playlist.");
+    return;
+  }
+
+  if (!strstr (mrl, "://") && access (mrl, F_OK)) {
+    char *tmp;
+    snprintf (this->mrl, sizeof(this->mrl), "%s", stream->url);
+    tmp = strrchr (this->mrl, '/');
+    if (tmp) {
+      *(tmp+1) = '\0';
+      len = strlen (this->mrl);
+    }
+  }
+  snprintf (this->mrl+len, sizeof(this->mrl)-len, "%s", mrl);
+
+  playback_start (this);
+}
+
+NPError NPP_DestroyStream (NPP instance, NPStream *stream, NPReason reason) {
+  log ("NPP_DestroyStream( instance=%p, stream=%p, reason=%d )",
+       instance, stream, reason);
+
+  if (!instance || !instance->pdata)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  return NPERR_NO_ERROR;
+}
+
+void NPP_Print (NPP instance, NPPrint *printinfo) {
+  log ("NPP_Print( instance=%p, printinfo=%p )", instance, printinfo);
+}
+
+NPError NPP_Destroy (NPP instance, NPSavedData **save) {
+  xine_plugin_t *this;
+
+  log ("NPP_Destroy( instance=%p, save=%p )", instance, save);
+
+  if (!instance || !instance->pdata)
+    return NPERR_INVALID_INSTANCE_ERROR;
+
+  this = instance->pdata;
+
+  playback_stop (this);
+
+  if (this->osd)
+    xine_osd_free (this->osd);
+
+  if (this->event_queue)
+    xine_event_dispose_queue (this->event_queue);
+
+  if (this->stream)
+    xine_dispose (this->stream);
+
+  if (this->vo_driver)
+    xine_close_video_driver (this->xine, this->vo_driver);
+
+  if (this->ao_driver)
+    xine_close_audio_driver (this->xine, this->ao_driver);
+
+  if (this->xine)
+    xine_exit (this->xine);
+
+  if (this->display) {
+    if (this->window) {
+      XLockDisplay (this->display);
+      XUnmapWindow (this->display, this->window);
+      XDestroyWindow (this->display, this->window);
+      XUnlockDisplay (this->display);
+    }
+    XCloseDisplay (this->display);
+  }
+
+  pthread_mutex_destroy (&this->mutex);
+
+  NPN_MemFree (this);
+
+  instance->pdata = NULL;
   
-  switch(event->type) { 
-
-  case XINE_EVENT_UI_PLAYBACK_FINISHED:
-    pprintf("event_listener: stream finished\n");
-
-    /* check for loop play mode (play it again, sam) */
-    if( this->loop_play ) {
-      if( this->playlist_entries && 
-          this->playlist_cur >= this->playlist_entries ) {
-        this->playlist_cur = 0;
-      } else {
-        xine_play(this->stream, 0, 0);
-        break;
-      }
-    }
-
-    /* get next playlist item */
-    while( this->playlist_cur < this->playlist_entries ) {
-      strcpy(this->url,this->playlist[this->playlist_cur]);
-      this->playlist_cur++;
-
-      pprintf("event_listener: next playlist item '%s'\n", this->url );
-      if( xine_open(this->stream, this->url) && 
-          xine_play(this->stream, 0, 0) )
-        return;
-      else
-        pprintf("event_listener: error playing '%s'\n", this->url );
-    }
-    if(this->playlist_cur >= this->playlist_entries)
-      this->playlist_cur = 0;
-    break;
-    
-  case XINE_EVENT_MRL_REFERENCE:
-    /* remove current url from playlist: it's a reference stream */
-    for( i = 0; i < this->playlist_cur; i++ ) {
-      if( !strcmp(this->url, this->playlist[i]) ) {
-        /* FIXME: move playlist entries up */
-        this->playlist[i][0] = '\0';
-      }
-    }
-    /* add new entry to playlist */
-    if( this->playlist_entries < MAX_PLAYLIST ) {
-      char *new_entry;
-
-      new_entry = ((xine_mrl_reference_data_t *)event->data)->mrl;
-
-      /* alternatives not yet supported */
-      if( ((xine_mrl_reference_data_t *)event->data)->alternative )
-        break;
-
-      /* check if url has neither a complete path or protocol */
-      if( !strstr(new_entry,"://") && new_entry[0] != '/' ) {
-        snprintf(this->playlist[this->playlist_entries],MAX_URL,"%s%s#demux:%s",
-                 this->base_url,new_entry,this->demux);
-      } else {
-        snprintf(this->playlist[this->playlist_entries],MAX_URL,"%s#demux:%s",
-                 new_entry,this->demux);
-      }
-      pprintf("event_listener: reference '%s'\n", this->playlist[this->playlist_entries] );
-      this->playlist[this->playlist_entries++][MAX_URL-1]='\0';
-    }
-    break;
-    
-  case XINE_EVENT_PROGRESS:
-  {
-    xine_progress_data_t *data = (xine_progress_data_t *)event->data;
-    char *s;
-    
-    s = malloc(strlen(data->description)+10);
-    sprintf(s,"%s [%d%%]",data->description,data->percent);
-    /* mozilla not thread-safe? */
-    /* NPN_Status(this->instance, s); */
-    
-    pthread_mutex_lock(&this->mutex);
-    if( this->osd_timeout != OSD_TIMEOUT || data->percent == 100 ) {
-      xine_osd_clear(this->osd);
-      xine_osd_draw_text(this->osd, 0, 0, s, XINE_OSD_TEXT1);
-      xine_osd_set_position(this->osd, 20, 20);
-      xine_osd_show(this->osd, 0);
-      this->osd_timeout = OSD_TIMEOUT;
-    }
-    pthread_mutex_unlock(&this->mutex);
-    
-    free(s);    
-  }
-  
-  }
-}
-
-
-NPError create_window_stream (NPP instance) {
-
-  plugin_instance_t  *this = (plugin_instance_t *) instance->pdata;
-  XWindowAttributes   attr;
-  char                *display_name = NULL;
-  unsigned int         blackpix, whitepix;
-  
-  /*
-   * initialize X11 stuff
-   */
-  
-  display_name  = getenv("DISPLAY");
-  this->display = XOpenDisplay(display_name);
-  
-  if (!this->display) {
-    pprintf ("XOpenDisplay failed!\n");
-    return NPERR_GENERIC_ERROR;
-  }
-  
-  XLockDisplay (this->display);
-
-  this->screen = DefaultScreen (this->display);
-  blackpix     = BlackPixel (this->display, this->screen);
-  whitepix     = WhitePixel (this->display, this->screen);
-
-  /*
-   * get size of parent window
-   */
-  XGetWindowAttributes (this->display, this->window, &attr);
-  this->width  = attr.width;
-  this->height = attr.height;
-  this->xpos   = attr.x;
-  this->ypos   = attr.y;
-  
-  /*
-   * create our own video window (inside browser's window)
-   */
-  pprintf ("create_window_stream: x=%u, y=%u, w=%u, h=%u\n",
-           attr.x,attr.y,attr.width,attr.height);
-    
-  this->video_window = XCreateSimpleWindow (this->display, this->window,
-                                            this->xpos, this->ypos,
-                                            this->width, this->height, 1, 
-                                            blackpix, blackpix);
-
-  XSelectInput (this->display, this->video_window, INPUT_MOTION);
-  XRaiseWindow (this->display, this->video_window);
-  XMapWindow (this->display, this->video_window);
-  XUnlockDisplay (this->display);
-
-  /*
-   * initialize xine_stream stuff
-   */
-  
-  this->vo_driver = load_video_out_driver(this) ;
-
-  if (!this->vo_driver) {
-    pprintf ("  error opening video driver\n");
-    NPN_Status(instance,"xine-plugin: error opening video driver");
-    return NPERR_MODULE_LOAD_FAILED_ERROR;
-  }
-
-  this->ao_driver   = load_audio_out_driver(this);
-  
-  this->stream      = xine_stream_new (xine, this->ao_driver, this->vo_driver);
-  
-  this->osd = xine_osd_new(this->stream, 0, 0, 300, 30);
-  xine_osd_set_font(this->osd, "sans", 16);
-  xine_osd_set_text_palette(this->osd, 
-			    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT, XINE_OSD_TEXT1);
-  
-  this->event_queue = xine_event_new_queue(this->stream);
-  xine_event_create_listener_thread(this->event_queue, event_listener, (void *) this);
-
-  xine_gui_send_vo_data(this->stream, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) this->video_window);
-  xine_gui_send_vo_data(this->stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
-  
-  this->IsFinished = 0;
-  if( pthread_create(&this->gui_thread, NULL, (void *) &xine_loop, (void *) this) ) {
-    pprintf("  error creating player thread\n");
-    NPN_Status(instance,"xine-plugin: error creating player thread");
-    return NPERR_GENERIC_ERROR;
-  }
-  if( pthread_create(&this->misc_thread, NULL, (void *) &misc_loop, (void *) this) ) {
-    pprintf("  error creating misc thread\n");
-    NPN_Status(instance,"xine-plugin: error creating misc thread");
-    return NPERR_GENERIC_ERROR;
-  }
-        
+  instance_num--;
+
   return NPERR_NO_ERROR;
-}      
-              
-char *NPP_GetMIMEDescription(void) {
-  char            *mimetypes;
-
-  if( NPP_Initialize() == NPERR_GENERIC_ERROR )
-    return "";
-
-  mimetypes = xine_get_mime_types(xine);
-  
-  pprintf("NPP_GetMIMEDescription: %s\n", mimetypes);
-
-  if( strlen(mimetypes) && mimetypes[strlen(mimetypes)-1] == ';'  )
-    mimetypes[strlen(mimetypes)-1] = '\0';
-
-  return mimetypes;
-}
-
-NPError NPP_GetValue(void *future, NPPVariable variable, void *value){
-
-  NPError err = NPERR_NO_ERROR;
-  pprintf("NPP_GetValue(future=%p, variable=%d, ...)\n", future, variable);
-
-  switch (variable) {
-
-  case NPPVpluginNameString:
-    *((char **)value) = "xine plugin";
-    break;
-
-  case NPPVpluginDescriptionString:
-    *((char **)value) = "xine - a free video player";
-    break;
-
-  default:
-    err = NPERR_GENERIC_ERROR;
-    break;
-
-  }
-
-  return err;
-}
-
-NPError NPP_Initialize(void) {
-  char configfile[256];
-  char libname[40];
-
-  sprintf(libname,"libxine.so.%d",XINE_MAJOR_VERSION);
-
-  pprintf("NPP_Initialize()\n");
-  if(!IsInitialised){
-
-    if (!XInitThreads ()) {
-      pprintf ("  XInitThreads failed - looks like you don't have a thread-safe xlib.\n");
-      fflush(stdout);
-      return NPERR_GENERIC_ERROR;
-    } 
-
-    lib_handle = dlopen (libname, RTLD_LAZY | RTLD_GLOBAL);
-
-    if (!lib_handle) {
-      pprintf("  Error opening '%s', plugin failed to initialize.\n", libname);
-      pprintf("  Is libxine installed?\n");
-      return NPERR_GENERIC_ERROR;
-    }
-
-    xine = xine_new();
-       
-    snprintf (configfile, 255, "%s/.xine/config", getenv("HOME"));
-    xine_config_load (xine, configfile);
-     
-    xine_init(xine);
-    
-    IsInitialised = 1;
-  }
-
-  return NPERR_NO_ERROR;
-}
-
-
-void * NPP_GetJavaClass() {
-  pprintf("NPP_GetJavaClass() - not implemented\n");
-  return NULL;
-}
-
-void NPP_Shutdown(void) {
-  pprintf("NPP_Shutdown()\n");
-  
-  xine_exit(xine);
-  
-  dlclose(lib_handle);
-  
-  IsInitialised = 0; 
-}
-
-
-NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, 
-		int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
-  plugin_instance_t  *this;
-
-  pprintf("NPP_New(type=%s, instance=%p, mode=%d, ...)\n", pluginType, instance, mode);
-  
-  if (instance == NULL)
-    return NPERR_INVALID_INSTANCE_ERROR;
-  
-  instance->pdata = NPN_MemAlloc(sizeof(plugin_instance_t));
-  
-  this = (plugin_instance_t *) instance->pdata;
-  this->instance = instance;
-
-  if (this != NULL) {
-    int  i;
-
-    this->loop_play    = 0;
-    this->gui_thread   = 0;
-    this->misc_thread  = 0;
-    this->vo_driver    = NULL;
-    this->ao_driver    = NULL;
-    this->stream       = NULL;
-    this->display      = NULL;
-    this->window       = 0;
-    this->video_window = 0;
-    this->event_queue  = NULL;
-    this->demux[0]     = '\0';
-    this->url[0]       = '\0';
-    this->url_src      = NULL;
-    this->playlist_cur = this->playlist_entries = 0;
-    pthread_mutex_init (&this->mutex, NULL);
-       
-    if( mode == NP_EMBED )
-      this->embed_mode = 1;
-    else
-      this->embed_mode = 0;
-    
-    /* default size, should be overwritten */
-    this->width = 320;
-    this->height = 200;
-
-    strncpy (this->mime_type,pluginType, MAX_MIMETYPE);
-    this->mime_type[MAX_MIMETYPE-1]='\0';
-
-    /* parse args */
-    for (i = 0; i < argc; i++) {
-
-      pprintf ("  argument '%s'='%s'\n", argn[i], argv[i]);
-
-      if (!strcasecmp (argn[i], "loop")) {
-	if (!strcasecmp (argv[i], "true") || !strcasecmp (argv[i], "yes") ||
-	    !strcmp (argv[i], "1")) {
-	  this->loop_play = 1;
-	}
-      } else if (!strcasecmp (argn[i], "width")) {
-	this->width = atoi(argv[i]);
-      } else if (!strcasecmp (argn[i], "height")) {
-	this->height = atoi(argv[i]);
-      } else if (!strcasecmp (argn[i], "src")) {
-	this->url_src = strdup(argv[i]);
-      } else if (!strcasecmp (argn[i], "mrl")) {
-	snprintf(this->url,MAX_URL,argv[i]);
-	this->url[MAX_URL-1]='\0';
-      }
-
-    }
-
-    pprintf("NPP_New() returns no error\n");
-    return NPERR_NO_ERROR;
-  }
-  
-  return NPERR_OUT_OF_MEMORY_ERROR;
-}
-
-NPError NPP_Destroy(NPP instance, NPSavedData **save) {
-  plugin_instance_t  *this;
-  pprintf("NPP_Destroy(instance=%p)\n", instance);
-
-  if (instance == NULL)
-    return NPERR_INVALID_INSTANCE_ERROR;
-
-  this = (plugin_instance_t *) instance->pdata;
-
-  if(this->gui_thread) {
-    this->IsFinished = 1;
-    pprintf("  Joining main thread\n");
-    pthread_join(this->gui_thread, NULL);
-    this->gui_thread = 0;
-  }
-  
-  if(this->misc_thread) {
-    this->IsFinished = 1;
-    pprintf("  Joining misc thread\n");
-    pthread_join(this->misc_thread, NULL);
-    this->misc_thread = 0;
-  }
-      
-  pprintf("  Closing xine engine\n");
-  if(this->stream)
-    xine_close(this->stream);
-  if(this->event_queue)
-    xine_event_dispose_queue(this->event_queue);
-  if(this->stream)
-    xine_dispose(this->stream);
-  if(this->ao_driver)
-    xine_close_audio_driver(xine, this->ao_driver);  
-  if(this->vo_driver)
-    xine_close_video_driver(xine, this->vo_driver);  
-
-  if(this->display) {  
-    pprintf("  Closing display\n");
-
-    XLockDisplay (this->display);
-    if( this->video_window ) {
-      XUnmapWindow (this->display, this->video_window );
-      XDestroyWindow (this->display, this->video_window );
-    }
-    XUnlockDisplay (this->display);
-  
-    XCloseDisplay (this->display);
-  }
-    
-  if (this != NULL) {
-    NPN_MemFree(instance->pdata);
-    instance->pdata = NULL;
-  }
-
-  pprintf("NPP_Destroy() returns no error\n");
-  
-  return NPERR_NO_ERROR;
-}
-
-NPError NPP_SetWindow(NPP instance, NPWindow *window) {
-  plugin_instance_t  *this;
-  NPError err;
-
-  pprintf("NPP_SetWindow(instance=%p, window=%p)\n", instance, window);
- 
-  if (instance == NULL) {
-    pprintf("  NPERR_INVALID_INSTANCE_ERROR\n");
-    return NPERR_INVALID_INSTANCE_ERROR;
-  }
-  
-  if (window == NULL) {
-    pprintf("  window == NULL, NPERR_NO_ERROR\n");
-    return NPERR_NO_ERROR;
-  }
-  
-  this = (plugin_instance_t*) instance->pdata;
-
-  pprintf("  x=%lu, y=%lu, w=%lu, h=%lu\n", window->x, window->y, window->width, window->height);
-  pprintf("  window = %lu NPERR_NO_ERROR\n", (Window) window->window);
-
-  if( !this->window && this->embed_mode ) {
-    this->window = (Window) window->window;
-
-    err = create_window_stream(instance);
-    if( err != NPERR_NO_ERROR )
-      return err;
-
-    if( strlen(this->url) ) {
-        /* we should only enter here when NPP_SetWindow is called after NPP_NewStream */
-
-        if( !xine_open(this->stream, this->url) ||
-            !xine_play (this->stream, 0, 0) ) {
-          pprintf("  error playing stream '%s'\n", this->url);
-          NPN_Status(instance,"xine-plugin: error playing stream.");
-        
-          return NPERR_GENERIC_ERROR;
-        }
-    }
-  }
-
-  pprintf("NPP_SetWindow() returns no error\n");
-  return NPERR_NO_ERROR;
-}
-
-NPError NPP_NewStream (NPP instance, NPMIMEType type, 
-		       NPStream *stream, NPBool seekable, uint16 *stype) {
-  plugin_instance_t  *this;
-  char               *demux;
-  char                *s;
-  
-  pprintf("NPP_NewStream(instance=%p, type=%s, stream=%p, seekable=%d)\n",
-           instance, type, stream, seekable);
-
-  if (instance == NULL)
-    return NPERR_INVALID_INSTANCE_ERROR;
-
-  this = (plugin_instance_t *) instance->pdata;
-  
-  /*
-   * prepare MRL for xine engine
-   * 1st step: get demux identification
-   */
-  demux = xine_get_demux_for_mime_type(xine,this->mime_type);
-  if( demux ) {
-    pprintf("  xine reports demuxer '%s' for mimetype '%s'\n", demux, this->mime_type);
-    strcpy(this->demux, demux);
-    free(demux);
-  } else {
-    pprintf("  warning: unknown demuxer for mimetype '%s'\n", this->mime_type);
-  }
-
-  /*
-   * get base url from stream->url. sometimes mozilla passes the
-   * html address here, it looks like a bug (?). 
-   * however it may be useful for relative "src" parameter.
-   */
-  strncpy(this->base_url,stream->url,MAX_URL);
-  this->base_url[MAX_URL-1]='\0';
-  s = strrchr(this->base_url,'/');
-  if( s )
-    s[1] = '\0';
-  else
-    this->base_url[0] = '\0'; /* error? */
-
-  /* if the mrl parameter was given in the EMBED tag, pass it directly to xine-lib */
-  if(!strlen(this->url)) {
-    /*
-     * use "src" tag if available. check for absolute urls, they
-     * don't need base_url.
-     */
-    if(this->url_src) {
-      if( !strstr(this->url_src,"://") && this->url_src[0] != '/' ) {
-        snprintf(this->url,MAX_URL,"%s%s#demux:%s",
-                 this->base_url,this->url_src,this->demux);
-      } else {
-        snprintf(this->url,MAX_URL,"%s#demux:%s",this->url_src,this->demux);
-      }
-  
-      free(this->url_src);
-      this->url_src = NULL;
-    } else {
-      snprintf(this->url,MAX_URL,"%s#demux:%s",stream->url,this->demux);
-    }
-    this->url[MAX_URL-1]='\0';
-  }
-
-  /* set base_url again */
-  strcpy(this->base_url, this->url);
-  s = strrchr(this->base_url,'/');
-  if( s )
-    s[1] = '\0';
-  else
-    this->base_url[0] = '\0'; /* error? */
-    
-  pprintf("  opening xine MRL: %s\n", this->url);
-  pprintf("  base URL is: %s\n", this->base_url);
-  NPN_Status(instance, this->url);
-
-  if( this->embed_mode ) {
-
-    if( this->window && this->stream ) {
-      /* 
-       * test if xine can open this url directly. it might fail because some
-       * demuxers do not handle non-seekable input plugins like http.
-       */  
-      if( xine_open(this->stream, this->url) ) {
-        
-        if( !xine_play (this->stream, 0, 0) ) {
-          pprintf("  error playing stream '%s'\n", this->url);
-          NPN_Status(instance,"xine-plugin: error playing stream.");
-    
-          return NPERR_GENERIC_ERROR;
-        }
-        *stype = NP_NORMAL;
-      } else {
-        this->url[0] = '\0';
-
-        NPN_Status(instance,"xine-plugin: streaming failed. asking browser for a local copy...");
-        pprintf("  failed to open stream directly, asking browser for a local copy...\n");
-        *stype = NP_ASFILEONLY;
-      }
-    }
-
-  } else {
-
-    /* non-embedded mode: launch full window player */
-    NPN_Status(instance,"launching external xine player...");
-    pprintf("  non-embedded mode: launching external xine player...\n");
-    launch_xine(this);
-
-    *stype = NP_NORMAL;
-  }
-
-  return NPERR_NO_ERROR;
-}
-
-
-int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
-				   * mode so we can take any size stream in our
-				   * write call (since we ignore it) */
-
-int32 NPP_WriteReady(NPP instance, NPStream *stream) {
-  return STREAMBUFSIZE;
-}
-
-
-int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) {
-  /* we don't want to download data twice: close netscape stream so xine
-   * can get data itself.
-   */
-  return -1; 
-}
-
-
-NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
-  plugin_instance_t  *this;
-
-  pprintf("NPP_DestroyStream(instance=%p, stream=%p, reason=%d)\n",
-          instance, stream, reason);
-
-  if (instance == NULL)
-    return NPERR_INVALID_INSTANCE_ERROR;
-
-  this = (plugin_instance_t *) instance->pdata;
-
-  return NPERR_NO_ERROR;
-}
-
-
-void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) {
-  plugin_instance_t  *this;
-
-  pprintf("NPP_StreamAsFile(instance=%p, stream=%p, fname=%s)\n",
-          instance, stream, fname);
-
-  if (instance == NULL)
-    return;
-    
-  this = (plugin_instance_t *) instance->pdata;
-    
-  snprintf(this->url,MAX_URL,"%s#demux:%s",fname,this->demux);
-  this->url[MAX_URL-1]='\0';
-
-  if( this->window && this->stream ) {
-    if( xine_open(this->stream, this->url) ) {
-      if( !xine_play (this->stream, 0, 0) ) {
-        pprintf("  error playing stream '%s'\n", this->url);
-        NPN_Status(instance,"xine-plugin: error playing stream");
-      }
-    } else {
-      pprintf("  failed to open local copy '%s', aborting.\n", this->url);
-      NPN_Status(instance,"xine-plugin: failed to open local copy, aborting.");
-    }
-  }
-}
-
-
-void NPP_Print(NPP instance, NPPrint *printInfo) {
-
-  pprintf("NPP_Print() - not implemented\n");
-}
-
+}
+
+void NPP_Shutdown (void) {
+  log ("NPP_Shutdown()");
+}