/*
* Copyright (C) 2000-2007 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
*
*
* 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 <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
# include <sched.h>
#endif
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include <xine.h>
#include <xine/xineutils.h>
#include "npapi.h"
#include "npruntime.h"
#include "playlist.h"
#define DEMUXER_BY_MIME 0 /* whether to detect the demuxer by the mimetype */
#define VERSION_CODE(M, m, s) (((M) << 16) + ((m) << 8) + (s))
#define XINE_VERSION_CODE VERSION_CODE(XINE_MAJOR_VERSION,\
XINE_MINOR_VERSION,\
XINE_SUB_VERSION)
#ifdef LOG
# define log(x, ...) \
do {\
fprintf (stderr, "xine-plugin (%d): " x "\n", getpid(), ##__VA_ARGS__);\
fflush (stderr);\
} while (0)
#else
# define log(x, ...)
#endif
typedef struct {
NPP instance;
xine_t *xine;
xine_video_port_t *vo_driver;
xine_audio_port_t *ao_driver;
xine_stream_t *stream;
xine_event_queue_t *event_queue;
xine_osd_t *osd;
Display *display;
int screen;
Window parent;
Window window;
Cursor pointer;
int x, y;
int w, h;
int loop;
int start; /* start time */
int autostart;
#if DEMUXER_BY_MIME
char demux[32];
#endif
char base[1024];
char *override_mrl;
char *href;
playlist_entry_t *list;
playlist_entry_t *track;
int playlist_type;
pthread_mutex_t mutex;
pthread_t thread;
int playing;
#ifdef ENABLE_SCRIPTING
NPObject *object;
#endif
} xine_plugin_t;
#define OSD_WIDTH 384
#define OSD_HEIGHT 80
#define OSD_TIMEOUT 5 /* in seconds */
#define OSD_TEXT_PLAY ">"
#define OSD_TEXT_STOP "}"
#define OSD_TEXT_PAUSE "<"
#define OSD_TEXT_QUIT "{"
/*****************************************************************************/
/*
* Parse a time string in the format HH:MM:SS
* and return the time value in seconds.
*/
static int strtime (const char *str)
{
char *p = (char *) str;
int t = 0;
int i;
for (i = 0; i < 3; i++) {
t *= 60;
t += atoi (p);
p = strchr (p, ':');
if (!p)
break;
p++;
}
return t;
}
/*
* Get filename from path.
*/
static const char *filename (const char *path)
{
const char *name;
name = strrchr (path, '/');
if (name)
return name+1;
return path;
}
/*****************************************************************************/
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;
}
#ifdef XINE_VISUAL_TYPE_X11_2
static void lock_display_cb (void *data)
{
xine_plugin_t *this = data;
pthread_mutex_lock (&this->mutex);
XLockDisplay (this->display);
}
static void unlock_display_cb (void *data)
{
xine_plugin_t *this = data;
XUnlockDisplay (this->display);
pthread_mutex_unlock (&this->mutex);
}
#endif /* XINE_VISUAL_TYPE_X11_2 */
/*****************************************************************************/
typedef char timestring_t[16];
const char *int_to_timestring (int int_time, timestring_t *string_time)
{
int sign = int_time < 0;
int_time = abs (int_time);
snprintf ((char *)string_time, sizeof (*string_time), "%s%02d:%02d:%02d",
sign ? "-" : "", int_time / 3600000, (int_time / 60000) % 60,
(int_time / 1000) % 60);
return (char *)string_time;
}
static void osd_show_text (xine_plugin_t *this, const char *text) {
char *s = (char *) text;
int y = 0;
if (!this->osd)
return;
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++;
}
if (xine_osd_get_capabilities (this->osd) & XINE_OSD_CAP_UNSCALED)
xine_osd_show_unscaled (this->osd, 0);
else
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 const char *stream_error (xine_stream_t *stream) {
int err = xine_get_error (stream);
switch (err) {
case XINE_ERROR_NO_INPUT_PLUGIN:
return "no input plugin to handle stream";
case XINE_ERROR_NO_DEMUX_PLUGIN:
return "no demuxer plugin to handle stream";
case XINE_ERROR_DEMUX_FAILED:
return "demuxer plugin failed, stream probably corrupted";
case XINE_ERROR_MALFORMED_MRL:
return "corrupted mrl";
case XINE_ERROR_INPUT_FAILED:
return "input plugin failed";
default:
break;
}
return "unknown error";
}
static void *player_thread (void *data) {
xine_plugin_t *this = data;
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
while (this->track && this->playing) {
playlist_entry_t *track = this->track;
const char *error;
char buf[4096];
int len = 0;
int ret;
if (!strstr (track->mrl, "://") && access (track->mrl, F_OK))
len = snprintf (buf, sizeof(buf), "%s", this->base);
len += snprintf (buf+len, sizeof(buf)-len, "%s", track->mrl);
#if DEMUXER_BY_MIME
if (*this->demux)
snprintf (buf+len, sizeof(buf)-len, "#demux:%s", this->demux);
#endif
log ("opening \"%s\"...", buf);
NPN_Status (this->instance, "xine-plugin: opening stream...");
#if XINE_VERSION_CODE >= VERSION_CODE(1,1,4)