1 --- a/configure Wed Jul 25 17:52:00 2007 +0200
2 +++ b/configure Thu Jul 26 13:02:44 2007 +0200
3 @@ -35,6 +35,8 @@
4 echo " --enable-xine build xine wrapper"
5 echo " --disable-xine do not build xine wrapper"
6 echo " --with-xine-dir=DIR check for libxine installed in DIR"
7 + echo " --enable-mplayer build MPlayer wrapper"
8 + echo " --disable-mplayer do not build MPlayer wrapper"
9 echo " --enable-vlc build VLC wrapper"
10 echo " --disable-vlc do not build VLC wrapper"
11 echo " --with-vlc-dir=DIR check for libvlc installed in DIR"
12 @@ -300,6 +302,7 @@
13 installstrip="-s"
14 cross_compile="no"
15 wrapper_xine="yes"
16 +wrapper_mplayer="yes"
17 wrapper_vlc="yes"
18 INSTALL="install"
19
20 @@ -395,6 +398,10 @@
21 --disable-xine) wrapper_xine="no";
22 ;;
23 --with-xine-dir=*) libxinedir="$optval";
24 + ;;
25 + --enable-mplayer) wrapper_mplayer="yes";
26 + ;;
27 + --disable-mplayer) wrapper_mplayer="no";
28 ;;
29 --enable-vlc) wrapper_vlc="yes";
30 ;;
31 @@ -601,6 +608,14 @@
32 fi
33
34 #################################################
35 +# check for mplayer
36 +#################################################
37 +if test "$wrapper_mplayer" = "yes"; then
38 + add_cflags -DHAVE_MPLAYER
39 + add_extralibs -lpthread
40 +fi
41 +
42 +#################################################
43 # check for libvlc
44 #################################################
45 if test "$wrapper_vlc" = "yes"; then
46 @@ -668,6 +683,7 @@
47
48 append_config "DEBUG=$debug"
49 append_config "WRAPPER_XINE=$wrapper_xine"
50 +append_config "WRAPPER_MPLAYER=$wrapper_mplayer"
51 append_config "WRAPPER_VLC=$wrapper_vlc"
52
53 clean
1.1 --- a/regtest-libplayer.c Wed Jul 25 17:52:00 2007 +0200
1.2 +++ b/regtest-libplayer.c Thu Jul 26 13:02:44 2007 +0200
1.3 @@ -34,6 +34,7 @@
1.4 typedef enum player_id {
1.5 PLAYER_ID_ALL = 0,
1.6 PLAYER_ID_XINE,
1.7 + PLAYER_ID_MPLAYER,
1.8 PLAYER_ID_VLC,
1.9 PLAYER_ID_DUMMY
1.10 } player_id_t;
1.11 @@ -108,6 +109,14 @@
1.12 }
1.13 #endif /* HAVE_XINE */
1.14
1.15 +#ifdef HAVE_MPLAYER
1.16 + if (player_id == PLAYER_ID_MPLAYER || player_id == PLAYER_ID_ALL)
1.17 + {
1.18 + printf ("\n--- MPlayer ---\n");
1.19 + player_run_test (PLAYER_TYPE_MPLAYER);
1.20 + }
1.21 +#endif /* HAVE_MPLAYER */
1.22 +
1.23 #ifdef HAVE_VLC
1.24 if (player_id == PLAYER_ID_VLC || player_id == PLAYER_ID_ALL)
1.25 {
1.26 @@ -133,6 +142,10 @@
1.27 else if (!strcmp (argv[1], "xine"))
1.28 player_id = PLAYER_ID_XINE;
1.29 #endif /* HAVE_XINE */
1.30 +#ifdef HAVE_MPLAYER
1.31 + else if (!strcmp (argv[1], "mplayer"))
1.32 + player_id = PLAYER_ID_MPLAYER;
1.33 +#endif /* HAVE_MPLAYER */
1.34 #ifdef HAVE_VLC
1.35 else if (!strcmp (argv[1], "vlc"))
1.36 player_id = PLAYER_ID_VLC;
2.1 --- a/src/Makefile Wed Jul 25 17:52:00 2007 +0200
2.2 +++ b/src/Makefile Thu Jul 26 13:02:44 2007 +0200
2.3 @@ -15,6 +15,10 @@
2.4
2.5 ifeq ($(WRAPPER_VLC),yes)
2.6 SRCS += wrapper_vlc.c
2.7 +endif
2.8 +
2.9 +ifeq ($(WRAPPER_MPLAYER),yes)
2.10 + SRCS += wrapper_mplayer.c
2.11 endif
2.12
2.13 OBJS = $(SRCS:.c=.o)
3.1 --- a/src/player.c Wed Jul 25 17:52:00 2007 +0200
3.2 +++ b/src/player.c Thu Jul 26 13:02:44 2007 +0200
3.3 @@ -32,6 +32,9 @@
3.4 #ifdef HAVE_XINE
3.5 #include "wrapper_xine.h"
3.6 #endif /* HAVE_XINE */
3.7 +#ifdef HAVE_MPLAYER
3.8 +#include "wrapper_mplayer.h"
3.9 +#endif /* HAVE_MPLAYER */
3.10 #ifdef HAVE_VLC
3.11 #include "wrapper_vlc.h"
3.12 #endif /* HAVE_VLC */
3.13 @@ -69,6 +72,12 @@
3.14 player->priv = register_private_xine ();
3.15 break;
3.16 #endif /* HAVE_XINE */
3.17 +#ifdef HAVE_MPLAYER
3.18 + case PLAYER_TYPE_MPLAYER:
3.19 + player->funcs = register_functions_mplayer ();
3.20 + player->priv = register_private_mplayer ();
3.21 + break;
3.22 +#endif /* HAVE_MPLAYER */
3.23 #ifdef HAVE_VLC
3.24 case PLAYER_TYPE_VLC:
3.25 player->funcs = register_functions_vlc ();
4.1 --- a/src/player.h Wed Jul 25 17:52:00 2007 +0200
4.2 +++ b/src/player.h Thu Jul 26 13:02:44 2007 +0200
4.3 @@ -28,6 +28,7 @@
4.4
4.5 typedef enum player_type {
4.6 PLAYER_TYPE_XINE,
4.7 + PLAYER_TYPE_MPLAYER,
4.8 PLAYER_TYPE_VLC,
4.9 PLAYER_TYPE_DUMMY
4.10 } player_type_t;
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/src/wrapper_mplayer.c Thu Jul 26 13:02:44 2007 +0200
5.3 @@ -0,0 +1,913 @@
5.4 +/*
5.5 + * GeeXboX libplayer: a multimedia A/V abstraction layer API.
5.6 + * Copyright (C) 2007 Mathieu Schroeter <mathieu.schroeter@gamesover.ch>
5.7 + *
5.8 + * This file is part of libplayer.
5.9 + *
5.10 + * libplayer is free software; you can redistribute it and/or
5.11 + * modify it under the terms of the GNU Lesser General Public
5.12 + * License as published by the Free Software Foundation; either
5.13 + * version 2.1 of the License, or (at your option) any later version.
5.14 + *
5.15 + * libplayer is distributed in the hope that it will be useful,
5.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5.18 + * Lesser General Public License for more details.
5.19 + *
5.20 + * You should have received a copy of the GNU Lesser General Public
5.21 + * License along with libplayer; if not, write to the Free Software
5.22 + * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
5.23 + */
5.24 +
5.25 +#include <stdlib.h>
5.26 +#include <inttypes.h>
5.27 +#include <stdio.h>
5.28 +#include <string.h> /* strstr strlen memcpy strdup */
5.29 +#include <stdarg.h> /* va_start va_end */
5.30 +#include <unistd.h> /* pipe fork close dup2 */
5.31 +#include <math.h> /* rintf */
5.32 +#include <sys/wait.h> /* waitpid */
5.33 +#include <sys/types.h>
5.34 +#include <sys/stat.h> /* stat */
5.35 +#include <signal.h> /* sigaction */
5.36 +
5.37 +#include "player.h"
5.38 +#include "player_internals.h"
5.39 +#include "logs.h"
5.40 +#include "wrapper_mplayer.h"
5.41 +
5.42 +#define MODULE_NAME "mplayer"
5.43 +
5.44 +#define SLAVE_CMD_BUFFER 256
5.45 +
5.46 +/* Status of MPlayer child */
5.47 +typedef enum mplayer_status {
5.48 + MPLAYER_IS_IDLE,
5.49 + MPLAYER_IS_DEAD
5.50 +} mplayer_status_t;
5.51 +
5.52 +/* player specific structure */
5.53 +typedef struct mplayer_s {
5.54 + mplayer_status_t status;
5.55 + pid_t pid; /* process pid */
5.56 + int pipe_in[2]; /* pipe for send commands to MPlayer */
5.57 + int pipe_out[2]; /* pipe for receive results */
5.58 + FILE *fifo_in; /* fifo on the pipe_in (write only) */
5.59 + FILE *fifo_out; /* fifo on the pipe_out (read only) */
5.60 +} mplayer_t;
5.61 +
5.62 +/* slave commands */
5.63 +typedef enum slave_cmd {
5.64 + SLAVE_GET_PROPERTY, /* get_property string */
5.65 + SLAVE_LOADFILE, /* loadfile string [int] */
5.66 + SLAVE_PAUSE, /* pause */
5.67 + SLAVE_SEEK, /* seek float [int] */
5.68 + SLAVE_SET_PROPERTY, /* set_property string string */
5.69 + SLAVE_STOP
5.70 +} slave_cmd_t;
5.71 +
5.72 +/* slave properties */
5.73 +typedef enum slave_property {
5.74 + PROPERTY_AUDIO_BITRATE,
5.75 + PROPERTY_AUDIO_CODEC,
5.76 + PROPERTY_CHANNELS,
5.77 + PROPERTY_HEIGHT,
5.78 + PROPERTY_LOOP,
5.79 + PROPERTY_METADATA_ALBUM,
5.80 + PROPERTY_METADATA_ARTIST,
5.81 + PROPERTY_METADATA_GENRE,
5.82 + PROPERTY_METADATA_TITLE,
5.83 + PROPERTY_METADATA_TRACK,
5.84 + PROPERTY_METADATA_YEAR,
5.85 + PROPERTY_MUTE,
5.86 + PROPERTY_SAMPLERATE,
5.87 + PROPERTY_VIDEO_BITRATE,
5.88 + PROPERTY_VIDEO_CODEC,
5.89 + PROPERTY_VOLUME,
5.90 + PROPERTY_WIDTH
5.91 +} slave_property_t;
5.92 +
5.93 +
5.94 +static const struct {
5.95 + slave_property_t property;
5.96 + char *text;
5.97 +} g_slave_props[] = {
5.98 + {PROPERTY_AUDIO_BITRATE, "audio_bitrate"},
5.99 + {PROPERTY_AUDIO_CODEC, "audio_codec"},
5.100 + {PROPERTY_CHANNELS, "channels"},
5.101 + {PROPERTY_HEIGHT, "height"},
5.102 + {PROPERTY_LOOP, "loop"},
5.103 + {PROPERTY_METADATA_ALBUM, "metadata/album"},
5.104 + {PROPERTY_METADATA_ARTIST, "metadata/artist"},
5.105 + {PROPERTY_METADATA_GENRE, "metadata/genre"},
5.106 + {PROPERTY_METADATA_TITLE, "metadata/title"},
5.107 + {PROPERTY_METADATA_TRACK, "metadata/track"},
5.108 + {PROPERTY_METADATA_YEAR, "metadata/year"},
5.109 + {PROPERTY_MUTE, "mute"},
5.110 + {PROPERTY_SAMPLERATE, "samplerate"},
5.111 + {PROPERTY_VIDEO_BITRATE, "video_bitrate"},
5.112 + {PROPERTY_VIDEO_CODEC, "video_codec"},
5.113 + {PROPERTY_VOLUME, "volume"},
5.114 + {PROPERTY_WIDTH, "width"}
5.115 +};
5.116 +
5.117 +
5.118 +static void
5.119 +sig_handler (int signal)
5.120 +{
5.121 + if (signal == SIGPIPE)
5.122 + plog (MODULE_NAME, "SIGPIPE detected by the death of MPlayer");
5.123 +}
5.124 +
5.125 +/**
5.126 + * Get the text for a specific property in the g_slave_props. This function
5.127 + * should never return NULL. If that is the case, then a property is missed
5.128 + * in the table.
5.129 + */
5.130 +static char *
5.131 +get_prop (slave_property_t property)
5.132 +{
5.133 + int i;
5.134 +
5.135 + for (i = 0; i < sizeof (g_slave_props) / sizeof (g_slave_props[0]); i++)
5.136 + if (g_slave_props[i].property == property)
5.137 + return g_slave_props[i].text;
5.138 +
5.139 + return NULL;
5.140 +}
5.141 +
5.142 +/**
5.143 + * Send a formatted command to the MPlayer's slave. fifo_in is a file
5.144 + * descriptor on a pipe for the MPlayer's stdin.
5.145 + */
5.146 +static void
5.147 +send_to_slave (mplayer_t *mplayer, const char *format, ...)
5.148 +{
5.149 + va_list va;
5.150 +
5.151 + if (!mplayer || !mplayer->fifo_in)
5.152 + return;
5.153 +
5.154 + va_start (va, format);
5.155 + vfprintf (mplayer->fifo_in, format, va);
5.156 + fprintf (mplayer->fifo_in, "\n");
5.157 + fflush (mplayer->fifo_in);
5.158 + va_end (va);
5.159 +}
5.160 +
5.161 +/**
5.162 + * Get results of commands sent to MPlayer. The MPlayer's stdout and sterr
5.163 + * are connected to fifo_out. Because MPlayer doesn't confirm all commands
5.164 + * (for example, a get_property with no stream return nothing), that is
5.165 + * necessary for send an other command with an output in all cases.
5.166 + * Here, this command create an error captured in the stderr for confirm
5.167 + * the end of the fifo_out.
5.168 + */
5.169 +static char *
5.170 +slave_result (slave_property_t property, player_t *player)
5.171 +{
5.172 + char str[SLAVE_CMD_BUFFER];
5.173 + char *buffer;
5.174 + char *prop;
5.175 + char *ret = NULL;
5.176 + char *its, *ite;
5.177 + mplayer_t *mplayer = NULL;
5.178 +
5.179 + if (!player)
5.180 + return NULL;
5.181 +
5.182 + mplayer = (mplayer_t *) player->priv;
5.183 +
5.184 + if (!mplayer || !mplayer->fifo_in || !mplayer->fifo_out)
5.185 + return NULL;
5.186 +
5.187 + /* get the right property in the global list */
5.188 + prop = get_prop (property);
5.189 + if (prop)
5.190 + sprintf (str, "ANS_%s=", prop);
5.191 + else
5.192 + /* should never going here */
5.193 + return NULL;
5.194 +
5.195 + /* NOTE: /!\ That is ugly but it works pretty well :o)
5.196 + * Because MPlayer doesn't confirm commands, that is necessary for
5.197 + * have a text in the fifo_out for know if there is no new message.
5.198 + * Else, the fgets (read) will block on the pipe. NONBLOCK is not a
5.199 + * solution, better for have an information that will to confirm if
5.200 + * MPlayer has no result and then to stop the read.
5.201 + *
5.202 + * An error is created by the command 'loadfile' without arguments. This
5.203 + * error is got with fgets() and the while is break if there is no
5.204 + * result for the real command in var 'str'.
5.205 + */
5.206 + send_to_slave (mplayer, "loadfile");
5.207 +
5.208 + if ((buffer = malloc (SLAVE_CMD_BUFFER))) {
5.209 + /* MPlayer's stdout parser */
5.210 + while (fgets (buffer, SLAVE_CMD_BUFFER, mplayer->fifo_out))
5.211 + {
5.212 + /* search the result */
5.213 + if ((its = strstr(buffer, str))) {
5.214 + /* value start */
5.215 + its += strlen (str);
5.216 + ite = its;
5.217 + while (*ite != '\0' && *ite != '\n')
5.218 + ite++;
5.219 +
5.220 + /* value end */
5.221 + *ite = '\0';
5.222 +
5.223 + if ((ret = malloc (strlen (its) + 1))) {
5.224 + memcpy (ret, its, strlen (its));
5.225 + *(ret + strlen (its)) = '\0';
5.226 + }
5.227 + }
5.228 + /* If this error (from stderr) exists, then we can go out
5.229 + * because there is no result for the real command.
5.230 + */
5.231 + else if (strstr (buffer, "Command loadfile"))
5.232 + break;
5.233 +
5.234 + *buffer = '\0';
5.235 + }
5.236 +
5.237 + free (buffer);
5.238 + }
5.239 +
5.240 + return ret;
5.241 +}
5.242 +
5.243 +static int
5.244 +slave_result_int (player_t *player, slave_property_t property)
5.245 +{
5.246 + int value = -1;
5.247 + char *result;
5.248 +
5.249 + result = slave_result (property, player);
5.250 +
5.251 + if (result) {
5.252 + /* string to float and round to int */
5.253 + value = (int) rintf (atof (result));
5.254 + free (result);
5.255 + }
5.256 +
5.257 + return value;
5.258 +}
5.259 +
5.260 +static inline char *
5.261 +slave_result_str (player_t *player, slave_property_t property)
5.262 +{
5.263 + return slave_result (property, player);
5.264 +}
5.265 +
5.266 +/**
5.267 + * Set a value for a property. Currently, only integer can be used as value.
5.268 + * If a string must be set a day, then this function must be split like
5.269 + * slave_get_property() and use two inlined functions for set int or str.
5.270 + */
5.271 +static void
5.272 +slave_set_property_int (player_t *player, slave_property_t property, int value)
5.273 +{
5.274 + mplayer_t *mplayer = NULL;
5.275 + char *prop;
5.276 + char cmd[SLAVE_CMD_BUFFER];
5.277 +
5.278 + if (!player)
5.279 + return;
5.280 +
5.281 + mplayer = (mplayer_t *) player->priv;
5.282 +
5.283 + if (!mplayer || !mplayer->fifo_in)
5.284 + return;
5.285 +
5.286 + /* get the right property in the global list */
5.287 + prop = get_prop (property);
5.288 + if (prop)
5.289 + sprintf (cmd, "set_property %s", prop);
5.290 + else
5.291 + /* should never going here */
5.292 + return;
5.293 +
5.294 + switch (property) {
5.295 + case PROPERTY_LOOP:
5.296 + case PROPERTY_MUTE:
5.297 + send_to_slave (mplayer, "%s %i", cmd, value);
5.298 + break;
5.299 +
5.300 + case PROPERTY_VOLUME:
5.301 + send_to_slave (mplayer, "%s %.2f", cmd, (float) value);
5.302 + break;
5.303 +
5.304 + default:
5.305 + return;
5.306 + }
5.307 +}
5.308 +
5.309 +/**
5.310 + * Send a command to slave for get a property. That will return nothing
5.311 + * because the response is grabbed with slave_result().
5.312 + */
5.313 +static void
5.314 +slave_get_property (player_t *player, slave_property_t property)
5.315 +{
5.316 + mplayer_t *mplayer = NULL;
5.317 + char *prop;
5.318 +
5.319 + if (!player)
5.320 + return;
5.321 +
5.322 + mplayer = (mplayer_t *) player->priv;
5.323 +
5.324 + if (!mplayer || !mplayer->fifo_in)
5.325 + return;
5.326 +
5.327 + /* get the right property in the global list */
5.328 + prop = get_prop (property);
5.329 + if (prop)
5.330 + send_to_slave (mplayer, "get_property %s", prop);
5.331 + else
5.332 + /* should never going here */
5.333 + return;
5.334 +}
5.335 +
5.336 +static inline int
5.337 +slave_get_property_int (player_t *player, slave_property_t property)
5.338 +{
5.339 + slave_get_property (player, property);
5.340 + return slave_result_int (player, property);
5.341 +}
5.342 +
5.343 +static inline char *
5.344 +slave_get_property_str (player_t *player, slave_property_t property)
5.345 +{
5.346 + slave_get_property (player, property);
5.347 + return slave_result_str (player, property);
5.348 +}
5.349 +
5.350 +static void
5.351 +slave_action (player_t *player, slave_cmd_t cmd, void *value)
5.352 +{
5.353 + mplayer_t *mplayer = NULL;
5.354 +
5.355 + if (!player)
5.356 + return;
5.357 +
5.358 + mplayer = (mplayer_t *) player->priv;
5.359 +
5.360 + if (!mplayer || !mplayer->fifo_in)
5.361 + return;
5.362 +
5.363 + switch (cmd) {
5.364 + case SLAVE_LOADFILE:
5.365 + if (player->mrl->name)
5.366 + send_to_slave (mplayer, "loadfile \"%s\" %i",
5.367 + player->mrl->name, *((int *) value));
5.368 + break;
5.369 +
5.370 + case SLAVE_PAUSE:
5.371 + send_to_slave (mplayer, "pause");
5.372 + break;
5.373 +
5.374 + case SLAVE_SEEK:
5.375 + send_to_slave (mplayer, "seek %.2f 0", *((float *) value));
5.376 + break;
5.377 +
5.378 + case SLAVE_STOP:
5.379 + slave_set_property_int (player, PROPERTY_LOOP, -1);
5.380 + send_to_slave (mplayer, "seek 100.00 1");
5.381 + break;
5.382 +
5.383 + default:
5.384 + return;
5.385 + }
5.386 +}
5.387 +
5.388 +static inline void
5.389 +slave_cmd (player_t *player, slave_cmd_t cmd)
5.390 +{
5.391 + slave_action (player, cmd, NULL);
5.392 +}
5.393 +
5.394 +static inline void
5.395 +slave_cmd_int (player_t *player, slave_cmd_t cmd, int value)
5.396 +{
5.397 + slave_action (player, cmd, &value);
5.398 +}
5.399 +
5.400 +
5.401 +/* Use only these commands for speak with MPlayer!
5.402 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5.403 + * void slave_cmd (player_t, slave_cmd_t)
5.404 + * void slave_cmd_int (player_t, slave_cmd_t, int)
5.405 + * int slave_get_property_int (player_t, slave_property_t)
5.406 + * char *slave_get_property_str (player_t, slave_property_t)
5.407 + * void slave_set_property_int (player_t, slave_property_t, int)
5.408 + */
5.409 +
5.410 +/**
5.411 + * Init MPlayer as a forked process (son) and speak with libplayer (father)
5.412 + * throught two pipes. One for send command to slave mode and a second
5.413 + * for get results. MPlayer must not dead, else the pipes are broken and a
5.414 + * SIGPIPE is sent to libplayer. In this case, a new init is necessary.
5.415 + */
5.416 +static init_status_t
5.417 +mplayer_init (player_t *player)
5.418 +{
5.419 + struct sigaction action;
5.420 + mplayer_t *mplayer = NULL;
5.421 + char *params[32];
5.422 + int pp = 0;
5.423 +
5.424 + plog (MODULE_NAME, "init");
5.425 +
5.426 + if (!player)
5.427 + return PLAYER_INIT_ERROR;
5.428 +
5.429 + mplayer = (mplayer_t *) player->priv;
5.430 +
5.431 + if (!mplayer)
5.432 + return PLAYER_INIT_ERROR;
5.433 +
5.434 + /* action for SIGPIPE */
5.435 + action.sa_handler = sig_handler;
5.436 + sigemptyset (&action.sa_mask);
5.437 + action.sa_flags = 0;
5.438 + sigaction (SIGPIPE, &action, NULL);
5.439 +
5.440 + /* create pipes */
5.441 + if (pipe (mplayer->pipe_in) != -1) {
5.442 + if (pipe (mplayer->pipe_out) != -1) {
5.443 + /* create the fork */
5.444 + mplayer->pid = fork ();
5.445 +
5.446 + switch (mplayer->pid) {
5.447 + /* the son (a new hope) */
5.448 + case 0:
5.449 + close (mplayer->pipe_in[1]);
5.450 + close (mplayer->pipe_out[0]);
5.451 +
5.452 + /* connect the pipe to MPlayer's stdin */
5.453 + dup2 (mplayer->pipe_in[0], STDIN_FILENO);
5.454 + /* connect stdout and stderr to the second pipe */
5.455 + dup2 (mplayer->pipe_out[1], STDERR_FILENO);
5.456 + dup2 (mplayer->pipe_out[1], STDOUT_FILENO);
5.457 +
5.458 + /* default MPlayer arguments */
5.459 + params[pp++] = "mplayer";
5.460 + params[pp++] = "-slave"; /* work in slave mode */
5.461 + params[pp++] = "-quiet"; /* reduce output messages */
5.462 + params[pp++] = "-idle"; /* MPlayer stays always alive */
5.463 + params[pp++] = "-fs"; /* fullscreen (if possible) */
5.464 + params[pp++] = "-ontop"; /* ontop (if possible) */
5.465 + params[pp++] = "-noborder"; /* no border decoration */
5.466 + params[pp++] = "-nolirc";
5.467 + params[pp++] = "-nojoystick";
5.468 + params[pp++] = "-nomouseinput";
5.469 + params[pp++] = "-nograbpointer";
5.470 + params[pp++] = "-noconsolecontrols";
5.471 +
5.472 + /* select the video output */
5.473 + params[pp++] = "-vo";
5.474 + /* TODO: possibility to add parameters for each video output */
5.475 + switch (player->vo) {
5.476 + case PLAYER_VO_NULL:
5.477 + params[pp++] = "null";
5.478 + break;
5.479 +
5.480 + case PLAYER_VO_X11:
5.481 + params[pp++] = "x11";
5.482 + break;
5.483 +
5.484 + /* with MPlayer, SDL is not specific to X11 */
5.485 + case PLAYER_VO_X11_SDL:
5.486 + params[pp++] = "sdl";
5.487 + break;
5.488 +
5.489 + case PLAYER_VO_XV:
5.490 + params[pp++] = "xv";
5.491 + break;
5.492 +
5.493 + case PLAYER_VO_FB:
5.494 + params[pp++] = "fbdev";
5.495 + }
5.496 +
5.497 + /* select the audio output */
5.498 + params[pp++] = "-ao";
5.499 + /* TODO: possibility to add parameters for each audio output */
5.500 + switch (player->ao) {
5.501 + /* 'null' output seems to be bugged (MPlayer crash in some cases) */
5.502 + case PLAYER_AO_NULL:
5.503 + params[pp++] = "null";
5.504 + break;
5.505 +
5.506 + case PLAYER_AO_ALSA:
5.507 + params[pp++] = "alsa";
5.508 + break;
5.509 +
5.510 + case PLAYER_AO_OSS:
5.511 + params[pp++] = "oss";
5.512 + }
5.513 +
5.514 + params[pp] = NULL;
5.515 +
5.516 + /* launch MPlayer, if execvp returns there is an error */
5.517 + execvp ("mplayer", params);
5.518 +
5.519 + case -1:
5.520 + break;
5.521 +
5.522 + /* I'm your father */
5.523 + default:
5.524 + close (mplayer->pipe_in[0]);
5.525 + close (mplayer->pipe_out[1]);
5.526 +
5.527 + mplayer->fifo_in = fdopen (mplayer->pipe_in[1], "w");
5.528 + mplayer->fifo_out = fdopen (mplayer->pipe_out[0], "r");
5.529 +
5.530 + plog (MODULE_NAME, "MPlayer child loaded");
5.531 +
5.532 + mplayer->status = MPLAYER_IS_IDLE;
5.533 +
5.534 + return PLAYER_INIT_OK;
5.535 + }
5.536 + }
5.537 + }
5.538 +
5.539 + return PLAYER_INIT_ERROR;
5.540 +}
5.541 +
5.542 +static void
5.543 +mplayer_uninit (void *priv)
5.544 +{
5.545 + mplayer_t *mplayer = NULL;
5.546 +
5.547 + plog (MODULE_NAME, "uninit");
5.548 +
5.549 + if (!priv)
5.550 + return;
5.551 +
5.552 + mplayer = (mplayer_t *) priv;
5.553 +
5.554 + if (mplayer && mplayer->fifo_in) {
5.555 + /* suicide of MPlayer */
5.556 + send_to_slave (mplayer, "quit");
5.557 +
5.558 + /* wait the death of MPlayer */
5.559 + waitpid (mplayer->pid, NULL, 0);
5.560 +
5.561 + mplayer->status = MPLAYER_IS_DEAD;
5.562 +
5.563 + /* close pipes */
5.564 + close (mplayer->pipe_in[1]);
5.565 + close (mplayer->pipe_out[0]);
5.566 +
5.567 + /* close fifos */
5.568 + fclose (mplayer->fifo_in);
5.569 + fclose (mplayer->fifo_out);
5.570 +
5.571 + plog (MODULE_NAME, "MPlayer child terminated");
5.572 + }
5.573 +
5.574 + free (mplayer);
5.575 +}
5.576 +
5.577 +static void
5.578 +mplayer_mrl_get_audio_properties (player_t *player,
5.579 + mrl_properties_audio_t *audio)
5.580 +{
5.581 + char *buffer_c;
5.582 + int buffer_i;
5.583 + mplayer_t *mplayer = NULL;
5.584 +
5.585 + if (!player || !audio)
5.586 + return;
5.587 +
5.588 + mplayer = (mplayer_t *) player->priv;
5.589 + /* FIXME: test for know if it's playing or not will be better */
5.590 + if (mplayer->status == MPLAYER_IS_DEAD)
5.591 + return;
5.592 +
5.593 + buffer_c = slave_get_property_str (player, PROPERTY_AUDIO_CODEC);
5.594 + if (buffer_c) {
5.595 + audio->codec = strdup (buffer_c);
5.596 + free (buffer_c);
5.597 + }
5.598 + if (audio->codec)
5.599 + plog (MODULE_NAME, "Audio Codec: %s", audio->codec);
5.600 +
5.601 + buffer_i = slave_get_property_int (player, PROPERTY_AUDIO_BITRATE);
5.602 + if (buffer_i > -1) {
5.603 + audio->bitrate = buffer_i;
5.604 + plog (MODULE_NAME, "Audio Bitrate: %i kbps", audio->bitrate / 1000);
5.605 + }
5.606 +
5.607 + // TODO: autio->bits
5.608 +
5.609 + buffer_i = slave_get_property_int (player, PROPERTY_CHANNELS);
5.610 + if (buffer_i > -1) {
5.611 + audio->channels = buffer_i;
5.612 + plog (MODULE_NAME, "Audio Channels: %i", audio->channels);
5.613 + }
5.614 +
5.615 + buffer_i = slave_get_property_int (player, PROPERTY_SAMPLERATE);
5.616 + if (buffer_i > -1) {
5.617 + audio->samplerate = buffer_i;
5.618 + plog (MODULE_NAME, "Audio Sample Rate: %i Hz", audio->samplerate);
5.619 + }
5.620 +}
5.621 +
5.622 +static void
5.623 +mplayer_mrl_get_video_properties (player_t *player,
5.624 + mrl_properties_video_t *video)
5.625 +{
5.626 + char *buffer_c;
5.627 + int buffer_i;
5.628 + mplayer_t *mplayer = NULL;
5.629 +
5.630 + if (!player || !video)
5.631 + return;
5.632 +
5.633 + mplayer = (mplayer_t *) player->priv;
5.634 + /* FIXME: test for know if it's playing or not will be better */
5.635 + if (mplayer->status == MPLAYER_IS_DEAD)
5.636 + return;
5.637 +
5.638 + buffer_c = slave_get_property_str (player, PROPERTY_VIDEO_CODEC);
5.639 + if (buffer_c) {
5.640 + video->codec = strdup (buffer_c);
5.641 + free (buffer_c);
5.642 + }
5.643 + if (video->codec)
5.644 + plog (MODULE_NAME, "Video Codec: %s", video->codec);
5.645 +
5.646 + buffer_i = slave_get_property_int (player, PROPERTY_VIDEO_BITRATE);
5.647 + if (buffer_i > -1) {
5.648 + video->bitrate = buffer_i;
5.649 + plog (MODULE_NAME, "Video Bitrate: %i kbps", video->bitrate / 1000);
5.650 + }
5.651 +
5.652 + buffer_i = slave_get_property_int (player, PROPERTY_WIDTH);
5.653 + if (buffer_i > -1) {
5.654 + video->width = buffer_i;
5.655 + plog (MODULE_NAME, "Video Width: %i", video->width);
5.656 + }
5.657 +
5.658 + buffer_i = slave_get_property_int (player, PROPERTY_HEIGHT);
5.659 + if (buffer_i > -1) {
5.660 + video->height = buffer_i;
5.661 + plog (MODULE_NAME, "Video Height: %i", video->height);
5.662 + }
5.663 +
5.664 + // TODO: audio->channels and audio->streams
5.665 +}
5.666 +
5.667 +static void
5.668 +mplayer_mrl_get_properties (player_t *player)
5.669 +{
5.670 + mplayer_t *mplayer = NULL;
5.671 + struct stat st;
5.672 + mrl_t *mrl;
5.673 +
5.674 + plog (MODULE_NAME, "mrl_get_properties");
5.675 +
5.676 + mrl = player->mrl;
5.677 +
5.678 + if (!player || !mrl || !mrl->prop)
5.679 + return;
5.680 +
5.681 + mplayer = (mplayer_t *) player->priv;
5.682 + if (mplayer->status == MPLAYER_IS_DEAD)
5.683 + return;
5.684 +
5.685 + /* now fetch properties */
5.686 + stat (mrl->name, &st);
5.687 + mrl->prop->size = st.st_size;
5.688 + plog (MODULE_NAME, "File Size: %.2f MB",
5.689 + (float) mrl->prop->size / 1024 / 1024);
5.690 +
5.691 + /* FIXME: no idea how implement */
5.692 + // mrl->prop->seekable =
5.693 +
5.694 + mrl->prop->audio = mrl_properties_audio_new ();
5.695 + mplayer_mrl_get_audio_properties (player, mrl->prop->audio);
5.696 +
5.697 + mrl->prop->video = mrl_properties_video_new ();
5.698 + mplayer_mrl_get_video_properties (player, mrl->prop->video);
5.699 +}
5.700 +
5.701 +static void
5.702 +mplayer_mrl_get_metadata (player_t *player)
5.703 +{
5.704 + char *buffer_c;
5.705 + mplayer_t *mplayer = NULL;
5.706 + mrl_t *mrl;
5.707 +
5.708 + plog (MODULE_NAME, "mrl_get_metadata");
5.709 +
5.710 + mrl = player->mrl;
5.711 +
5.712 + if (!player || !mrl || !mrl->meta)
5.713 + return;
5.714 +
5.715 + mplayer = (mplayer_t *) player->priv;
5.716 + if (mplayer->status == MPLAYER_IS_DEAD)
5.717 + return;
5.718 +
5.719 + /* now fetch metadata */
5.720 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_TITLE);
5.721 + if (buffer_c) {
5.722 + mrl->meta->title = strdup (buffer_c);
5.723 + free (buffer_c);
5.724 + }
5.725 + if (mrl->meta->title)
5.726 + plog (MODULE_NAME, "Meta Title: %s", mrl->meta->title);
5.727 +
5.728 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_ARTIST);
5.729 + if (buffer_c) {
5.730 + mrl->meta->artist = strdup (buffer_c);
5.731 + free (buffer_c);
5.732 + }
5.733 + if (mrl->meta->artist)
5.734 + plog (MODULE_NAME, "Meta Artist: %s", mrl->meta->artist);
5.735 +
5.736 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_GENRE);
5.737 + if (buffer_c) {
5.738 + mrl->meta->genre = strdup (buffer_c);
5.739 + free (buffer_c);
5.740 + }
5.741 + if (mrl->meta->genre)
5.742 + plog (MODULE_NAME, "Meta Genre: %s", mrl->meta->genre);
5.743 +
5.744 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_ALBUM);
5.745 + if (buffer_c) {
5.746 + mrl->meta->album = strdup (buffer_c);
5.747 + free (buffer_c);
5.748 + }
5.749 + if (mrl->meta->album)
5.750 + plog (MODULE_NAME, "Meta Album: %s", mrl->meta->album);
5.751 +
5.752 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_YEAR);
5.753 + if (buffer_c) {
5.754 + mrl->meta->year = strdup (buffer_c);
5.755 + free (buffer_c);
5.756 + }
5.757 + if (mrl->meta->year)
5.758 + plog (MODULE_NAME, "Meta Year: %s", mrl->meta->year);
5.759 +
5.760 + buffer_c = slave_get_property_str (player, PROPERTY_METADATA_TRACK);
5.761 + if (buffer_c) {
5.762 + mrl->meta->track = strdup (buffer_c);
5.763 + free (buffer_c);
5.764 + }
5.765 + if (mrl->meta->track)
5.766 + plog (MODULE_NAME, "Meta Track: %s", mrl->meta->track);
5.767 +}
5.768 +
5.769 +static playback_status_t
5.770 +mplayer_playback_start (player_t *player)
5.771 +{
5.772 + plog (MODULE_NAME, "playback_start");
5.773 +
5.774 + if (!player)
5.775 + return PLAYER_PB_FATAL;
5.776 +
5.777 + // FIXME: playback error if not loaded
5.778 + /* 0: new play, 1: append to the current playlist */
5.779 + slave_cmd_int (player, SLAVE_LOADFILE, 0);
5.780 +
5.781 + return PLAYER_PB_OK;
5.782 +}
5.783 +
5.784 +static void
5.785 +mplayer_playback_stop (player_t *player)
5.786 +{
5.787 + plog (MODULE_NAME, "playback_stop");
5.788 +
5.789 + if (!player)
5.790 + return;
5.791 +
5.792 + slave_cmd (player, SLAVE_STOP);
5.793 +}
5.794 +
5.795 +static playback_status_t
5.796 +mplayer_playback_pause (player_t *player)
5.797 +{
5.798 + plog (MODULE_NAME, "playback_pause");
5.799 +
5.800 + if (!player)
5.801 + return PLAYER_PB_FATAL;
5.802 +
5.803 + slave_cmd (player, SLAVE_PAUSE);
5.804 +
5.805 + return PLAYER_PB_OK;
5.806 +}
5.807 +
5.808 +static void
5.809 +mplayer_playback_seek (player_t *player, int value)
5.810 +{
5.811 + plog (MODULE_NAME, "playback_seek: %d", value);
5.812 +
5.813 + if (!player)
5.814 + return;
5.815 +
5.816 + slave_cmd_int (player, SLAVE_SEEK, value);
5.817 +}
5.818 +
5.819 +static int
5.820 +mplayer_get_volume (player_t *player)
5.821 +{
5.822 + int volume = 0;
5.823 +
5.824 + plog (MODULE_NAME, "get_volume");
5.825 +
5.826 + if (!player)
5.827 + return volume;
5.828 +
5.829 + volume = slave_get_property_int (player, PROPERTY_VOLUME);
5.830 +
5.831 + if (volume < 0)
5.832 + return -1;
5.833 +
5.834 + return volume;
5.835 +}
5.836 +
5.837 +static player_mute_t
5.838 +mplayer_get_mute (player_t *player)
5.839 +{
5.840 + plog (MODULE_NAME, "get_mute");
5.841 +
5.842 + if (!player)
5.843 + return PLAYER_MUTE_UNKNOWN;
5.844 +
5.845 + if (slave_get_property_int (player, PROPERTY_MUTE))
5.846 + return PLAYER_MUTE_ON;
5.847 +
5.848 + return PLAYER_MUTE_OFF;
5.849 +}
5.850 +
5.851 +static void
5.852 +mplayer_set_volume (player_t *player, int value)
5.853 +{
5.854 + plog (MODULE_NAME, "set_volume: %d", value);
5.855 +
5.856 + if (!player)
5.857 + return;
5.858 +
5.859 + slave_set_property_int (player, PROPERTY_VOLUME, value);
5.860 +}
5.861 +
5.862 +static void
5.863 +mplayer_set_mute (player_t *player, player_mute_t value)
5.864 +{
5.865 + int mute = 0;
5.866 +
5.867 + if (value == PLAYER_MUTE_UNKNOWN)
5.868 + return;
5.869 +
5.870 + if (value == PLAYER_MUTE_ON)
5.871 + mute = 1;
5.872 +
5.873 + plog (MODULE_NAME, "set_mute: %s", mute ? "on" : "off");
5.874 +
5.875 + if (!player)
5.876 + return;
5.877 +
5.878 + slave_set_property_int (player, PROPERTY_MUTE, mute);
5.879 +}
5.880 +
5.881 +/* public API */
5.882 +player_funcs_t *
5.883 +register_functions_mplayer (void)
5.884 +{
5.885 + player_funcs_t *funcs = NULL;
5.886 +
5.887 + funcs = (player_funcs_t *) malloc (sizeof (player_funcs_t));
5.888 + funcs->init = mplayer_init;
5.889 + funcs->uninit = mplayer_uninit;
5.890 + funcs->mrl_get_props = mplayer_mrl_get_properties;
5.891 + funcs->mrl_get_meta = mplayer_mrl_get_metadata;
5.892 + funcs->pb_start = mplayer_playback_start;
5.893 + funcs->pb_stop = mplayer_playback_stop;
5.894 + funcs->pb_pause = mplayer_playback_pause;
5.895 + funcs->pb_seek = mplayer_playback_seek;
5.896 + funcs->get_volume = mplayer_get_volume;
5.897 + funcs->get_mute = mplayer_get_mute;
5.898 + funcs->set_volume = mplayer_set_volume;
5.899 + funcs->set_mute = mplayer_set_mute;
5.900 +
5.901 + return funcs;
5.902 +}
5.903 +
5.904 +void *
5.905 +register_private_mplayer (void)
5.906 +{
5.907 + mplayer_t *mplayer = NULL;
5.908 +
5.909 + mplayer = (mplayer_t *) malloc (sizeof (mplayer_t));
5.910 +
5.911 + mplayer->status = MPLAYER_IS_DEAD;
5.912 + mplayer->fifo_in = NULL;
5.913 + mplayer->fifo_out = NULL;
5.914 +
5.915 + return mplayer;
5.916 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/src/wrapper_mplayer.h Thu Jul 26 13:02:44 2007 +0200
6.3 @@ -0,0 +1,28 @@
6.4 +/*
6.5 + * GeeXboX libplayer: a multimedia A/V abstraction layer API.
6.6 + * Copyright (C) 2007 Mathieu Schroeter <mathieu.schroeter@gamesover.ch>
6.7 + *
6.8 + * This file is part of libplayer.
6.9 + *
6.10 + * libplayer is free software; you can redistribute it and/or
6.11 + * modify it under the terms of the GNU Lesser General Public
6.12 + * License as published by the Free Software Foundation; either
6.13 + * version 2.1 of the License, or (at your option) any later version.
6.14 + *
6.15 + * libplayer is distributed in the hope that it will be useful,
6.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6.18 + * Lesser General Public License for more details.
6.19 + *
6.20 + * You should have received a copy of the GNU Lesser General Public
6.21 + * License along with libplayer; if not, write to the Free Software
6.22 + * Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6.23 + */
6.24 +
6.25 +#ifndef _WRAPPER_MPLAYER_H_
6.26 +#define _WRAPPER_MPLAYER_H_
6.27 +
6.28 +player_funcs_t * register_functions_mplayer (void);
6.29 +void *register_private_mplayer (void);
6.30 +
6.31 +#endif /* _WRAPPER_MPLAYER_H_ */