diff options
Diffstat (limited to 'player.c')
-rw-r--r-- | player.c | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/player.c b/player.c new file mode 100644 index 0000000..56cb827 --- /dev/null +++ b/player.c @@ -0,0 +1,984 @@ +/// +/// @file player.c @brief A play plugin for VDR. +/// +/// Copyright (c) 2012, 2013 by Johns. All Rights Reserved. +/// +/// Contributor(s): Dennis Bendlin +/// +/// License: AGPLv3 +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// $Id: 23f35b1a9358694e2b022aed1eff081887bc3f16 $ +////////////////////////////////////////////////////////////////////////////// + +#include <sys/types.h> +#include <sys/wait.h> + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include <poll.h> +#include <pthread.h> + +#include <libintl.h> +#define _(str) gettext(str) ///< gettext shortcut +#define _N(str) str ///< gettext_noop shortcut + +#include "player.h" +#include "video.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////////////// + +const char *ConfigBrowserRoot = "/"; ///< browser starting point + +static char ConfigOsdOverlay; ///< show osd overlay +static char ConfigUseSlave; ///< external player use slave mode +static char ConfigFullscreen; ///< external player uses fullscreen +static char *ConfigVideoOut; ///< video out device +static char *ConfigAudioOut; ///< audio out device +static char *ConfigAudioMixer; ///< audio mixer device +static char *ConfigMixerChannel; ///< audio mixer channel +static const char *ConfigMplayer = "/usr/bin/mplayer"; ///< mplayer executable +static const char *ConfigMplayerArguments; ///< extra mplayer arguments +static const char *ConfigX11Display = ":0.0"; ///< x11 display + + /// DVD-Drive for mplayer +static const char *ConfigMplayerDevice = "/dev/dvd"; +static uint32_t ConfigColorKey = 0x00020507; ///< color key + +////////////////////////////////////////////////////////////////////////////// +// Osd +////////////////////////////////////////////////////////////////////////////// + +/** +** Open OSD. +*/ +void OsdOpen(void) +{ + Debug(3, "plex: %s\n", __FUNCTION__); + + VideoWindowShow(); +} + +/** +** Close OSD. +*/ +void OsdClose(void) +{ + Debug(3, "plex: %s\n", __FUNCTION__); + + VideoWindowHide(); + VideoWindowClear(); +} + +/** +** Clear OSD. +*/ +void OsdClear(void) +{ + Debug(3, "plex: %s\n", __FUNCTION__); + + VideoWindowClear(); +} + +/** +** Get OSD size and aspect. +** +** @param width[OUT] width of OSD +** @param height[OUT] height of OSD +** @param aspect[OUT] aspect ratio (4/3, 16/9, ...) of OSD +*/ +void GetOsdSize(int *width, int *height, double *aspect) +{ + VideoGetOsdSize(width, height); + *aspect = 16.0 / 9.0 / (double)*width * (double)*height; +} + +/** +** Draw osd pixmap +*/ +void OsdDrawARGB(int x, int y, int w, int h, const uint8_t * argb) +{ + Debug(3, "plex: %s %d,%d %d,%d\n", __FUNCTION__, x, y, w, h); + + VideoDrawARGB(x, y, w, h, argb); +} + +////////////////////////////////////////////////////////////////////////////// +// External player +////////////////////////////////////////////////////////////////////////////// + +static pid_t PlayerPid; ///< player pid +static pthread_t PlayerThread; ///< player decode thread + +static char PlayerPipeBuf[4096]; ///< pipe buffer +static int PlayerPipeCnt; ///< pipe buffer count +static int PlayerPipeIdx; ///< pipe buffer index +static int PlayerPipeOut[2]; ///< player write pipe +static int PlayerPipeIn[2]; ///< player read pipe + +static int PlayerVolume = -1; ///< volume 0 - 100 + +char PlayerDvdNav; ///< dvdnav active +char PlayerPaused; ///< player paused +char PlayerSpeed; ///< player playback speed +int PlayerCurrent; ///< current postion in seconds +int PlayerTotal; ///< total length in seconds +char PlayerTitle[256]; ///< title from meta data +char PlayerFilename[256]; ///< filename + +////////////////////////////////////////////////////////////////////////////// +// Slave +////////////////////////////////////////////////////////////////////////////// + +/** +** Parse player output. +** +** @param data line pointer (\0 terminated) +** @param size line length +*/ +static void PlayerParseLine(const char *data, int size) +{ + Debug(4, "play/parse: |%.*s|\n", size, data); + (void)size; + + // data is \0 terminated + if (!strncasecmp(data, "DVDNAV_TITLE_IS_MENU", 20)) { + PlayerDvdNav = 1; + } else if (!strncasecmp(data, "DVDNAV_TITLE_IS_MOVIE", 21)) { + PlayerDvdNav = 2; + } else if (!strncasecmp(data, "ID_DVD_VOLUME_ID=", 17)) { + Debug(3, "DVD_VOLUME = %s\n", data + 17); + } else if (!strncasecmp(data, "ID_AID_", 7)) { + char lang[64]; + int aid; + + if (sscanf(data, "ID_AID_%d_LANG=%s", &aid, lang) == 2) { + Debug(3, "AID(%d) = %s\n", aid, lang); + } + } else if (!strncasecmp(data, "ID_SID_", 7)) { + char lang[64]; + int sid; + + if (sscanf(data, "ID_SID_%d_LANG=%s", &sid, lang) == 2) { + Debug(3, "SID(%d) = %s\n", sid, lang); + } + } else if (!strncasecmp(data, "ANS_META_TITLE=", 14)) { + if (sscanf(data, "ANS_META_TITLE='%[^\t\n]", PlayerTitle) == 1) { + PlayerTitle[strlen(PlayerTitle) - 1] = 0; + Debug(3, "PlayerTitle= %s\n", PlayerTitle); + } + } else if (!strncasecmp(data, "ANS_FILENAME=", 12)) { + if (sscanf(data, "ANS_FILENAME='%[^\t\n]", PlayerFilename) == 1) { + PlayerFilename[strlen(PlayerFilename) - 1] = 0; + Debug(3, "PlayerFilename= %s\n", PlayerFilename); + } + } else if (!strncasecmp(data, "ANS_LENGTH=", 10)) { + if (sscanf(data, "ANS_LENGTH=%d", &PlayerTotal) == 1) { + Debug(3, "PlayerTotal=%d\n", PlayerTotal); + } + } else if (!strncasecmp(data, "ANS_TIME_POSITION=", 17)) { + if (sscanf(data, "ANS_TIME_POSITION=%d", &PlayerCurrent) == 1) { + Debug(3, "PlayerCurrent=%d\n", PlayerCurrent); + } + } +} + +/** +** Poll input pipe. +*/ +static void PlayerPollPipe(void) +{ + struct pollfd poll_fds[1]; + int n; + int i; + int l; + + // check if something to read + poll_fds[0].fd = PlayerPipeOut[0]; + poll_fds[0].events = POLLIN; + + switch (poll(poll_fds, 1, 0)) { + case 0: // timeout + return; + case -1: // error + Error(_("play/player: poll failed: %s\n"), strerror(errno)); + return; + default: // ready + break; + } + + // fill buffer + if ((n = read(PlayerPipeOut[0], PlayerPipeBuf + PlayerPipeCnt, + sizeof(PlayerPipeBuf) - PlayerPipeCnt)) < 0) { + Error(_("play/player: read failed: %s\n"), strerror(errno)); + return; + } + + PlayerPipeCnt += n; + l = 0; + for (i = PlayerPipeIdx; i < PlayerPipeCnt; ++i) { + if (PlayerPipeBuf[i] == '\n') { + PlayerPipeBuf[i] = '\0'; + PlayerParseLine(PlayerPipeBuf + PlayerPipeIdx, i - PlayerPipeIdx); + PlayerPipeIdx = i + 1; + l = PlayerPipeIdx; + } + } + + if (l) { // remove consumed bytes + if (PlayerPipeCnt - l) { + memmove(PlayerPipeBuf, PlayerPipeBuf + l, PlayerPipeCnt - l); + } + PlayerPipeCnt -= l; + PlayerPipeIdx -= l; + } else if (PlayerPipeCnt == sizeof(PlayerPipeBuf)) { + // no '\n' in buffer use it as single line + PlayerPipeBuf[sizeof(PlayerPipeBuf) - 1] = '\0'; + PlayerParseLine(PlayerPipeBuf + PlayerPipeIdx, PlayerPipeCnt); + PlayerPipeIdx = 0; + PlayerPipeCnt = 0; + } +} + +#define MPLAYER_MAX_ARGS 64 ///< number of arguments supported + +/** +** Execute external player. +** +** @param filename path and name of file to play +*/ +static void PlayerExec(const char *filename) +{ + const char *args[MPLAYER_MAX_ARGS]; + int argn; + char wid_buf[32]; + char volume_buf[32]; + int i; + + if (ConfigUseSlave) { // connect pipe to stdin/stdout + dup2(PlayerPipeIn[0], STDIN_FILENO); + close(PlayerPipeIn[0]); + close(PlayerPipeIn[1]); + close(PlayerPipeOut[0]); + dup2(PlayerPipeOut[1], STDOUT_FILENO); + dup2(PlayerPipeOut[1], STDERR_FILENO); + close(PlayerPipeOut[1]); + } + // close all file handles + for (i = getdtablesize() - 1; i > STDERR_FILENO; i--) { + close(i); + } + + // export DISPLAY= + + args[0] = ConfigMplayer; + args[1] = "-quiet"; + args[2] = "-msglevel"; + // FIXME: play with the options +#ifdef DEBUG + args[3] = "all=6:global=4:cplayer=4:identify=4"; +#else + args[3] = "all=2:global=4:cplayer=2:identify=4"; +#endif + if (ConfigOsdOverlay) { + args[4] = "-noontop"; + } else { + args[4] = "-ontop"; + } + args[5] = "-noborder"; + if (ConfigDisableRemote) { + args[6] = "-lirc"; + } else { + args[6] = "-nolirc"; + } + args[7] = "-nojoystick"; // disable all unwanted inputs + args[8] = "-noar"; + args[9] = "-nomouseinput"; + args[10] = "-nograbpointer"; + args[11] = "-noconsolecontrols"; + args[12] = "-fixed-vo"; + args[13] = "-sid"; // subtitle selection + args[14] = "0"; + args[15] = "-slang"; + args[16] = "de,en"; // FIXME: use VDR config + args[17] = "-alang"; + args[18] = "de,en"; // FIXME: use VDR config + argn = 19; + if (ConfigMplayerDevice) { // dvd-device + args[argn++] = "-dvd-device"; + args[argn++] = ConfigMplayerDevice; + } + if (!strncasecmp(filename, "cdda://", 7)) { + args[argn++] = "-cache"; // cdrom needs cache + args[argn++] = "1000"; + } else { + args[argn++] = "-nocache"; // dvdnav needs nocache + } + if (ConfigUseSlave) { + args[argn++] = "-slave"; + //args[argn++] = "-idle"; + } + if (ConfigOsdOverlay) { // no mplayer osd with overlay + args[argn++] = "-osdlevel"; + args[argn++] = "0"; + } + if (ConfigFullscreen) { + args[argn++] = "-fs"; + args[argn++] = "-zoom"; + } else { + args[argn++] = "-nofs"; + } + if (VideoGetPlayWindow()) { + snprintf(wid_buf, sizeof(wid_buf), "%d", VideoGetPlayWindow()); + args[argn++] = "-wid"; + args[argn++] = wid_buf; + } + if (ConfigVideoOut) { + args[argn++] = "-vo"; + args[argn++] = ConfigVideoOut; + // add options based on selected video out + if (!strncmp(ConfigVideoOut, "vdpau", 5)) { + args[argn++] = "-vc"; + args[argn++] = + "ffmpeg12vdpau,ffwmv3vdpau,ffvc1vdpau,ffh264vdpau,ffodivxvdpau,"; + } else if (!strncmp(ConfigVideoOut, "vaapi", 5)) { + args[argn++] = "-va"; + args[argn++] = "vaapi"; + } + } + if (ConfigAudioOut) { + args[argn++] = "-ao"; + args[argn++] = ConfigAudioOut; + // FIXME: -ac hwac3,hwdts,hwmpa, + } + if (ConfigAudioMixer) { + args[argn++] = "-mixer"; + args[argn++] = ConfigAudioMixer; + } + if (ConfigMixerChannel) { + args[argn++] = "-mixer-channel"; + args[argn++] = ConfigMixerChannel; + } + if (ConfigX11Display) { + args[argn++] = "-display"; + args[argn++] = ConfigX11Display; + } + if (PlayerVolume != -1) { + // FIXME: here could be a problem with LANG + snprintf(volume_buf, sizeof(volume_buf), "%.2f", + (PlayerVolume * 100.0) / 255); + args[argn++] = "-volume"; + args[argn++] = volume_buf; + } + // split X server arguments string into words + if (ConfigMplayerArguments) { + const char *sval; + char *buf; + char *s; + + sval = ConfigMplayerArguments; +#ifndef __FreeBSD__ + s = buf = strdupa(sval); +#else + s = buf = alloca(strlen(sval) + 1); + strcpy(buf, sval); +#endif + while ((sval = strsep(&s, " \t"))) { + args[argn++] = sval; + + if (argn == MPLAYER_MAX_ARGS - 3) { // argument overflow + Error(_("play: too many arguments for mplayer\n")); + // argn = 1; + break; + } + } + } + args[argn++] = "--"; + args[argn++] = filename; + args[argn] = NULL; +#ifdef DEBUG + if (argn + 1 >= (int)(sizeof(args) / sizeof(*args))) { + Debug(3, "play: too many arguments %d\n", argn); + } + for (i = 0; i < argn; ++i) { + Debug(3, "%s", args[i]); + } +#endif + + execvp(args[0], (char *const *)args); + + // shouldn't be reached + Error(_("play: execvp of '%s' failed: %s\n"), args[0], strerror(errno)); + exit(-1); +} + +/** +** Execute external player. +** +** @param filename path and name of file to play +*/ +static void PlayerForkAndExec(const char *filename) +{ + pid_t pid; + + if (ConfigUseSlave) { + if (pipe(PlayerPipeIn)) { + Error(_("play: pipe failed: %s\n"), strerror(errno)); + return; + } + if (pipe(PlayerPipeOut)) { + Error(_("play: pipe failed: %s\n"), strerror(errno)); + return; + } + } + + if ((pid = fork()) == -1) { + Error(_("play: fork failed: %s\n"), strerror(errno)); + return; + } + if (!pid) { // child + PlayerExec(filename); + return; + } + PlayerPid = pid; // parent + setpgid(pid, 0); + + if (ConfigUseSlave) { + close(PlayerPipeIn[0]); + close(PlayerPipeOut[1]); + } + + Debug(3, "play: child pid=%d\n", pid); +} + +/** +** Close pipes. +*/ +static void PlayerClosePipes(void) +{ + if (ConfigUseSlave) { + if (PlayerPipeIn[0] != -1) { + close(PlayerPipeIn[0]); + } + if (PlayerPipeOut[1] != -1) { + close(PlayerPipeOut[1]); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// Thread +////////////////////////////////////////////////////////////////////////////// + +/** +** External player handler thread. +** +** @param dummy dummy pointer +*/ +static void *PlayerHandlerThread(void *dummy) +{ + Debug(3, "play: player thread started\n"); + + // Need: thread for video poll: while (PlayerIsRunning()) + for (;;) { + if (ConfigUseSlave && PlayerIsRunning()) { + PlayerPollPipe(); + // FIXME: wait only if pipe not ready + } + if (ConfigOsdOverlay) { + VideoPollEvents(10); + } else { + usleep(10 * 1000); + } + } + + Debug(3, "play: player thread stopped\n"); + PlayerThread = 0; + + return dummy; +} + +/** +** Initialize player threads. +*/ +static void PlayerThreadInit(void) +{ + pthread_create(&PlayerThread, NULL, PlayerHandlerThread, NULL); + //pthread_setname_np(PlayerThread, "play player"); +} + +/** +** Exit and cleanup player threads. +*/ +static void PlayerThreadExit(void) +{ + if (PlayerThread) { + void *retval; + + Debug(3, "play: player thread canceled\n"); + if (pthread_cancel(PlayerThread)) { + Error(_("play: can't queue cancel player thread\n")); + } + if (pthread_join(PlayerThread, &retval) || retval != PTHREAD_CANCELED) { + Error(_("play: can't cancel player thread\n")); + } + PlayerThread = 0; + } +} + +/** +** Send command to player. +** +** @param formst printf format string +*/ +static void SendCommand(const char *format, ...) +{ + va_list va; + char buf[256]; + int n; + + if (!PlayerPid) { + return; + } + if (PlayerPipeIn[1] == -1) { + Error(_("play: no pipe to send command available\n")); + return; + } + va_start(va, format); + n = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + + Debug(3, "play: send '%.*s'\n", n - 1, buf); + + // FIXME: poll pipe if ready + if (write(PlayerPipeIn[1], buf, n) != n) { + fprintf(stderr, "play: write failed\n"); + } +} + +/** +** Send player quit. +*/ +void PlayerSendQuit(void) +{ + if (ConfigUseSlave) { + SendCommand("quit\n"); + } +} + +/** +** Send player pause. +*/ +void PlayerSendPause(void) +{ + if (ConfigUseSlave) { + SendCommand("pause\n"); + } +} + +/** +** Send player speed_set. +** +** @param speed mplayer speed +*/ +void PlayerSendSetSpeed(int speed) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep speed_set %d\n", speed); + } +} + +/** +** Send player seek. +** +** @param seconds seek in seconds relative to current position +*/ +void PlayerSendSeek(int seconds) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep seek %+d 0\n", seconds); + } +} + +/** +** Send player volume. +*/ +void PlayerSendVolume(void) +{ + if (ConfigUseSlave) { + // FIXME: %.2f could have a problem with LANG + SendCommand("pausing_keep volume %.2f 1\n", + (PlayerVolume * 100.0) / 255); + } +} + +/** +** Send switch audio track. +*/ +void PlayerSendSwitchAudio(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep switch_audio\n"); + } +} + +/** +** Send select subtitle. +*/ +void PlayerSendSubSelect(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep sub_select\n"); + } +} + +/** +** Send up for dvdnav. +*/ +void PlayerSendDvdNavUp(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav up\n"); + } +} + +/** +** Send down for dvdnav. +*/ +void PlayerSendDvdNavDown(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav down\n"); + } +} + +/** +** Send left for dvdnav. +*/ +void PlayerSendDvdNavLeft(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav left\n"); + } +} + +/** +** Send right for dvdnav. +*/ +void PlayerSendDvdNavRight(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav right\n"); + } +} + +/** +** Send select for dvdnav. +*/ +void PlayerSendDvdNavSelect(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav select\n"); + } +} + +/** +** Send prev for dvdnav. +*/ +void PlayerSendDvdNavPrev(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav prev\n"); + } +} + +/** +** Send menu for dvdnav. +*/ +void PlayerSendDvdNavMenu(void) +{ + if (ConfigUseSlave) { + SendCommand("pausing_keep dvdnav menu\n"); + } +} + +/** +** Get length in seconds. +*/ +void PlayerGetLength(void) +{ + if (ConfigUseSlave) { + SendCommand("get_time_length\n"); + } +} + +/** +** Get current position in seconds. +*/ +void PlayerGetCurrentPosition(void) +{ + if (ConfigUseSlave) { + SendCommand("get_time_pos\n"); + } +} + +/** +** Get title from meta data. +*/ +void PlayerGetMetaTitle(void) +{ + if (ConfigUseSlave) { + SendCommand("get_meta_title\n"); + } +} + +/** +** Get filename. +*/ +void PlayerGetFilename(void) +{ + if (ConfigUseSlave) { + SendCommand("get_file_name\n"); + } +} + +/** +** Start external player. +** +** @param filename path and name of file to play +*/ +void PlayerStart(const char *filename) +{ + PlayerPipeCnt = 0; // reset to defaults + PlayerPipeIdx = 0; + + PlayerPipeIn[0] = -1; + PlayerPipeIn[1] = -1; + PlayerPipeOut[0] = -1; + PlayerPipeOut[1] = -1; + PlayerPid = 0; + + PlayerPaused = 0; + PlayerSpeed = 1; + + PlayerDvdNav = 0; + + if (ConfigOsdOverlay) { // overlay wanted + VideoSetColorKey(ConfigColorKey); + VideoInit(ConfigX11Display); + EnableDummyDevice(); + } + PlayerForkAndExec(filename); + + if (ConfigOsdOverlay || ConfigUseSlave) { + PlayerThreadInit(); + } +} + +/** +** Stop external player. +*/ +void PlayerStop(void) +{ + PlayerThreadExit(); + + // + // stop mplayer, if it is still running. + // + if (PlayerIsRunning()) { + int waittime; + int timeout; + + waittime = 0; + timeout = 500; // 0.5s + + kill(PlayerPid, SIGTERM); + // wait for player finishing, with timeout + while (PlayerIsRunning() && waittime++ < timeout) { + usleep(1 * 1000); + } + if (PlayerIsRunning()) { // still running + waittime = 0; + timeout = 500; // 0.5s + + kill(PlayerPid, SIGKILL); + // wait for player finishing, with timeout + while (PlayerIsRunning() && waittime++ < timeout) { + usleep(1 * 1000); + } + if (PlayerIsRunning()) { + Error(_("play: can't stop player\n")); + } + } + } + PlayerPid = 0; + PlayerClosePipes(); + + if (ConfigOsdOverlay) { + DisableDummyDevice(); + VideoExit(); + } +} + +/** +** Is external player still running? +*/ +int PlayerIsRunning(void) +{ + pid_t wpid; + int status; + + if (!PlayerPid) { // no player + return 0; + } + + wpid = waitpid(PlayerPid, &status, WNOHANG); + if (wpid <= 0) { + return 1; + } + if (WIFEXITED(status)) { + Debug(3, "play: player exited (%d)\n", WEXITSTATUS(status)); + } + if (WIFSIGNALED(status)) { + Debug(3, "play: player killed (%d)\n", WTERMSIG(status)); + } + PlayerPid = 0; + return 0; +} + +/** +** Set player volume. +** +** @param volume new volume (0..255) +*/ +void PlayerSetVolume(int volume) +{ + Debug(3, "player: set volume=%d\n", volume); + + if (PlayerVolume != volume) { + PlayerVolume = volume; + if (PlayerPid) { + PlayerSendVolume(); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// Device/Plugin C part +////////////////////////////////////////////////////////////////////////////// + +/** +** Return command line help string. +*/ +const char *CommandLineHelp(void) +{ + return " -% device\tmplayer dvd device\n" + " -/\t/dir\tbrowser root directory\n" + " -a audio\tmplayer -ao (alsa:device=hw=0.0) overwrites mplayer.conf\n" + " -d display\tX11 display (default :0.0) overwrites $DISPLAY\n" + " -f\t\tmplayer fullscreen playback\n" + " -g geometry\tx11 window geometry wxh+x+y\n" + " -k colorkey\tvideo color key (default=0x020507, mplayer2=0x76B901)\n" + " -m mplayer\tfilename of mplayer executable\n" + " -M args\targuments for mplayer\n" + " -o\t\tosd overlay experiments\n" " -s\t\tmplayer slave mode\n" + " -v video\tmplayer -vo (vdpau:deint=4:hqscaling=1) overwrites mplayer.conf\n"; +} + +/** +** Process the command line arguments. +** +** @param argc number of arguments +** @param argv arguments vector +*/ +int ProcessArgs(int argc, char *const argv[]) +{ + const char *s; + + // + // Parse arguments. + // +#ifdef __FreeBSD__ + if (!strcmp(*argv, "play")) { + ++argv; + --argc; + } +#endif + if ((s = getenv("DISPLAY"))) { + ConfigX11Display = s; + } + + for (;;) { + switch (getopt(argc, argv, "-%:/:a:b:d:fg:k:m:M:osv:")) { + case '%': // dvd-device + ConfigMplayerDevice = optarg; + continue; + case '/': // browser root + ConfigBrowserRoot = optarg; + continue; + case 'a': // audio out + ConfigAudioOut = optarg; + continue; + case 'd': // display x11 + ConfigX11Display = optarg; + continue; + case 'f': // fullscreen mode + ConfigFullscreen = 1; + continue; + case 'g': // geometry + VideoSetGeometry(optarg); + continue; + case 'k': // color key + ConfigColorKey = strtol(optarg, NULL, 0); + continue; + case 'm': // mplayer executable + ConfigMplayer = optarg; + continue; + case 'M': // mplayer extra arguments + ConfigMplayerArguments = optarg; + continue; + case 'o': // osd / overlay + ConfigOsdOverlay = 1; + continue; + case 's': // slave mode + ConfigUseSlave = 1; + continue; + case 'v': // video out + ConfigVideoOut = optarg; + continue; + case EOF: + break; + case '-': + fprintf(stderr, _("We need no long options\n")); + return 0; + case ':': + fprintf(stderr, _("Missing argument for option '%c'\n"), + optopt); + return 0; + default: + fprintf(stderr, _("Unkown option '%c'\n"), optopt); + return 0; + } + break; + } + while (optind < argc) { + fprintf(stderr, _("Unhandled argument '%s'\n"), argv[optind++]); + } + + return 1; +} |