/* * Copyright (C) 2000-2007 the xine project * * This file is part of xine, a unix 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: main.c,v 1.332 2007/04/23 22:48:20 fsck-p Exp $ * * xine main for X11 * */ /* required for getsubopt(); the __sun test gives us strncasecmp() on solaris */ #if !defined(__sun) && ! defined(__FreeBSD__) #define _XOPEN_SOURCE 500 #endif /* required for strncasecmp() */ #define _BSD_SOURCE 1 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_XINERAMA #include #endif #include #include #include #include "common.h" #ifdef HAVE_GETOPT_LONG # include #else # include "getopt.h" #endif /* * global variables */ gGui_t *gGui; extern _panel_t *panel; static char **video_driver_ids; static char **audio_driver_ids; static window_attributes_t window_attribute; #define CONFIGFILE "config" #define CONFIGDIR ".xine" typedef struct { FILE *fd; char *filename; char *ln; char buf[256]; } file_info_t; #define OPTION_VISUAL 1000 #define OPTION_INSTALL_COLORMAP 1001 #define OPTION_DISPLAY_KEYMAP 1002 #define OPTION_SK_SERVER 1003 #define OPTION_ENQUEUE 1004 #define OPTION_VERBOSE 1005 #define OPTION_BROADCAST_PORT 1006 #define OPTION_NO_LOGO 1007 #define OPTION_POST 1008 #define OPTION_DISABLE_POST 1009 #define OPTION_NO_SPLASH 1010 #define OPTION_STDCTL 1011 #define OPTION_LIST_PLUGINS 1012 #define OPTION_BUG_REPORT 1013 #define OPTION_NETWORK_PORT 1014 #define OPTION_NO_MOUSE 1015 /* options args */ static const char *short_options = "?hHgfvn" #ifdef HAVE_XINERAMA "F" #endif #ifdef HAVE_LIRC "L" #endif #ifdef HAVE_XF86VIDMODE "F" #endif "u:a:V:A:p::s:RW:G:BN:P:l::S:ZD::r:c:ET:I"; static struct option long_options[] = { {"help" , no_argument , 0, 'h' }, #ifdef HAVE_LIRC {"no-lirc" , no_argument , 0, 'L' }, #endif {"spu-channel" , required_argument, 0, 'u' }, {"audio-channel" , required_argument, 0, 'a' }, {"video-driver" , required_argument, 0, 'V' }, {"audio-driver" , required_argument, 0, 'A' }, {"auto-play" , optional_argument, 0, 'p' }, {"auto-scan" , required_argument, 0, 's' }, {"hide-gui" , no_argument , 0, 'g' }, {"hide-video" , no_argument , 0, 'H' }, {"fullscreen" , no_argument , 0, 'f' }, #ifdef HAVE_XINERAMA {"xineramafull" , no_argument , 0, 'F' }, #endif {"visual" , required_argument, 0, OPTION_VISUAL }, {"install" , no_argument , 0, OPTION_INSTALL_COLORMAP }, {"keymap" , optional_argument, 0, OPTION_DISPLAY_KEYMAP }, {"network" , no_argument , 0, 'n' }, {"network-port" , required_argument, 0, OPTION_NETWORK_PORT }, {"root" , no_argument , 0, 'R' }, {"wid" , required_argument, 0, 'W' }, {"geometry" , required_argument, 0, 'G' }, {"borderless" , no_argument , 0, 'B' }, {"animation" , required_argument, 0, 'N' }, {"playlist" , required_argument, 0, 'P' }, {"loop" , optional_argument, 0, 'l' }, {"skin-server-url", required_argument, 0, OPTION_SK_SERVER }, {"enqueue" , no_argument , 0, OPTION_ENQUEUE }, {"session" , required_argument, 0, 'S' }, {"version" , no_argument , 0, 'v' }, {"deinterlace" , optional_argument, 0, 'D' }, {"aspect-ratio" , required_argument, 0, 'r' }, {"config" , required_argument, 0, 'c' }, {"verbose" , optional_argument, 0, OPTION_VERBOSE }, {"stdctl" , optional_argument, 0, OPTION_STDCTL }, #ifdef XINE_PARAM_BROADCASTER_PORT {"broadcast-port" , required_argument, 0, OPTION_BROADCAST_PORT }, #endif {"no-logo" , no_argument , 0, OPTION_NO_LOGO }, {"no-mouse" , no_argument , 0, OPTION_NO_MOUSE }, {"no-reload" , no_argument , 0, 'E' }, {"post" , required_argument, 0, OPTION_POST }, {"disable-post" , no_argument , 0, OPTION_DISABLE_POST }, {"no-splash" , no_argument , 0, OPTION_NO_SPLASH }, {"tvout" , required_argument, 0, 'T' }, {"list-plugins" , optional_argument, 0, OPTION_LIST_PLUGINS }, {"bug-report" , optional_argument, 0, OPTION_BUG_REPORT }, {"no-gui" , no_argument , 0, 'I' }, {0 , no_argument , 0, 0 } }; #undef TRACE_RC /* * RC file related functions */ #ifdef TRACE_RC static void _rc_file_check_args(int argc, char **argv) { int i; printf("%s(): argc %d\n", __XINE_FUNCTION__, argc); for(i = 0; i < argc; i++) printf("argv[%d] = '%s'\n", i, argv[i]); } #endif static void _rc_file_clean_eol(file_info_t *rcfile) { char *p; p = rcfile->ln; if(p) { while(*p != '\0') { if(*p == '\n' || *p == '\r') { *p = '\0'; break; } p++; } while(p > rcfile->ln) { --p; if(*p == ' ') *p = '\0'; else break; } } } static int _rc_file_get_next_line(file_info_t *rcfile) { __get_next_line: rcfile->ln = fgets(rcfile->buf, 255, rcfile->fd); while(rcfile->ln && (*rcfile->ln == ' ' || *rcfile->ln == '\t')) ++rcfile->ln; if(rcfile->ln) { if(!strncmp(rcfile->ln, "#", 1)) goto __get_next_line; } _rc_file_clean_eol(rcfile); if(rcfile->ln && !strlen(rcfile->ln)) goto __get_next_line; return((rcfile->ln != NULL)); } /* * This function duplicate argv[] to an char** array,, * try to open and parse a "~/.xine/xinerc" rc file, * and concatenate found entries to the char **array. * This allow user to always specify a command line argument. */ static char **build_command_line_args(int argc, char *argv[], int *_argc) { int i = 1, j; char *cfgdir = CONFIGDIR; char *xinerc = "xinerc"; file_info_t *rcfile; char **_argv = NULL; _argv = (char **) xine_xmalloc(sizeof(char **) * (argc + 1)); (*_argc) = argc; _argv[0] = strdup(argv[0]); rcfile = (file_info_t *) xine_xmalloc(sizeof(file_info_t)); rcfile->filename = (char *) xine_xmalloc((strlen((xine_get_homedir())) + strlen(cfgdir) + strlen(xinerc)) + 3); sprintf(rcfile->filename, "%s/%s/%s", (xine_get_homedir()), cfgdir, xinerc); if((rcfile->fd = fopen(rcfile->filename, "r")) != NULL) { while(_rc_file_get_next_line(rcfile)) { _argv = (char **) realloc(_argv, sizeof(char **) * ((*_argc) + 2)); _argv[i] = strdup(rcfile->ln); i++; (*_argc)++; } fclose(rcfile->fd); } for(j = 1; i < (*_argc); i++, j++) _argv[i] = strdup(argv[j]); _argv[(*_argc)] = NULL; free(rcfile->filename); free(rcfile); return _argv; } static void free_command_line_args(char ***argv, int argc) { int _argc = argc - 1; while(_argc >= 0) { free((*argv)[_argc]); _argc--; } free(*(argv)); } static int parse_geometry(window_attributes_t *window_attribute, char *geomstr) { int width, height, xoff, yoff, ret; if((ret = XParseGeometry(geomstr, &xoff, &yoff, &width, &height))) { if(ret & XValue) window_attribute->x = xoff; if(ret & YValue) window_attribute->y = yoff; if(ret & WidthValue) window_attribute->width = width; if(ret & HeightValue) window_attribute->height = height; return 1; } return 0; } static int parse_visual(VisualID *vid, int *vclass, char *visual_str) { int ret = 0; int visual = 0; if(sscanf(visual_str, "%x", &visual) == 1) { *vid = visual; ret = 1; } else if (strcasecmp(visual_str, "StaticGray") == 0) { *vclass = StaticGray; ret = 1; } else if (strcasecmp(visual_str, "GrayScale") == 0) { *vclass = GrayScale; ret = 1; } else if (strcasecmp(visual_str, "StaticColor") == 0) { *vclass = StaticColor; ret = 1; } else if (strcasecmp(visual_str, "PseudoColor") == 0) { *vclass = PseudoColor; ret = 1; } else if (strcasecmp(visual_str, "TrueColor") == 0) { *vclass = TrueColor; ret = 1; } else if (strcasecmp(visual_str, "DirectColor") == 0) { *vclass = DirectColor; ret = 1; } return ret; } static void xrm_parse(void) { Display *display; char user_dbname[XITK_PATH_MAX + XITK_NAME_MAX + 2]; char environement_buf[XITK_PATH_MAX + XITK_NAME_MAX + 2]; char wide_dbname[XITK_PATH_MAX + XITK_NAME_MAX + 2]; char *environment; char *classname = "xine"; char *str_type; XrmDatabase rmdb, home_rmdb, server_rmdb, application_rmdb; XrmValue value; XrmInitialize(); rmdb = home_rmdb = server_rmdb = application_rmdb = NULL; snprintf(wide_dbname, sizeof(wide_dbname), "%s%s", "/usr/lib/X11/app-defaults/", classname); if((display = XOpenDisplay((getenv("DISPLAY")))) == NULL) return; application_rmdb = XrmGetFileDatabase(wide_dbname); (void) XrmMergeDatabases(application_rmdb, &rmdb); if(XResourceManagerString(display) != NULL) server_rmdb = XrmGetStringDatabase(XResourceManagerString(display)); else { snprintf(user_dbname, sizeof(user_dbname), "%s%s", (xine_get_homedir()), "/.Xdefaults"); server_rmdb = XrmGetFileDatabase(user_dbname); } (void) XrmMergeDatabases(server_rmdb, &rmdb); if((environment = getenv("XENVIRONMENT")) == NULL) { int len; environment = environement_buf; snprintf(environement_buf, sizeof(environement_buf), "%s%s", (xine_get_homedir()), "/.Xdefaults-"); len = strlen(environement_buf); (void) gethostname(environement_buf + len, sizeof(environement_buf) - len); } home_rmdb = XrmGetFileDatabase(environment); (void) XrmMergeDatabases(home_rmdb, &rmdb); if(XrmGetResource(rmdb, "xine.geometry", "xine.Geometry", &str_type, &value) == True) { if(!parse_geometry(&window_attribute, (char *)value.addr)) printf(_("Bad geometry '%s'\n"), (char *)value.addr); } if(XrmGetResource(rmdb, "xine.border", "xine.Border", &str_type, &value) == True) { window_attribute.borderless = !get_bool_value((char *) value.addr); } if(XrmGetResource(rmdb, "xine.visual", "xine.Visual", &str_type, &value) == True) { if(!parse_visual(&gGui->prefered_visual_id, &gGui->prefered_visual_class, (char *)value.addr)) { printf(_("Bad visual '%s'\n"), (char *)value.addr); } } if(XrmGetResource(rmdb, "xine.colormap", "xine.Colormap", &str_type, &value) == True) { gGui->install_colormap = !get_bool_value((char *) value.addr); } XrmDestroyDatabase(rmdb); if(display) XCloseDisplay(display); } static void main_change_logo_cb(void *data, xine_cfg_entry_t *cfg) { gGui->logo_mrl = cfg->str_value; } static void sub_autoload_cb(void *data, xine_cfg_entry_t *cfg) { gGui->subtitle_autoload = cfg->num_value; } /* * */ static void show_version(void) { printf(_("This is xine (X11 gui) - a free video player v%s"), VERSION); #ifdef DEBUG printf("-[DEBUG]"); #endif printf(_(".\n(c) 2000-2007 The xine Team.\n")); } /* * */ static void show_banner(void) { int major, minor, sub; show_version(); if(gGui->verbosity) printf(_("Built with xine library %d.%d.%d (%s)\n"), XINE_MAJOR_VERSION, XINE_MINOR_VERSION, XINE_SUB_VERSION, XINE_VERSION); xine_get_version (&major, &minor, &sub); if(gGui->verbosity) printf(_("Found xine library version: %d.%d.%d (%s).\n"), major, minor, sub, xine_get_version_string()); } static void print_formatted(char *title, const char *const *plugins) { const char *plugin; char buffer[81]; int len; static const char blanks[] = " "; printf("%s", title); strcpy(buffer, blanks); plugin = *plugins++; while(plugin) { len = strlen(buffer); if((len + (strlen(plugin) + 3)) < 80) { snprintf(buffer+len, sizeof(buffer)-len, "%s%s", (len == sizeof(blanks)-1) ? "" : ", ", plugin); } else { printf("%s,\n", buffer); snprintf(buffer, sizeof(buffer), "%s%s", blanks, plugin); } plugin = *plugins++; } printf("%s.\n\n", buffer); } static void list_plugins(char *type) { typedef struct { const char *const *(*func)(xine_t *); char *name; char *type; } _list_plugin_t; const char *const *plugins; xine_t *xine; char *cfgdir = CONFIGDIR; char *cfgfile = CONFIGFILE; char *configfile = NULL; int i; _list_plugin_t list_functions[] = { { xine_list_audio_output_plugins, _(" -Audio output:\n"), "audio_out" }, { xine_list_video_output_plugins, _(" -Video output:\n"), "video_out" }, { xine_list_demuxer_plugins, _(" -Demuxer:\n"), "demux" }, { xine_list_input_plugins, _(" -Input:\n"), "input" }, { xine_list_spu_plugins, _(" -Subpicture:\n"), "sub" }, { xine_list_post_plugins, _(" -Post processing:\n"), "post" }, { xine_list_audio_decoder_plugins, _(" -Audio decoder:\n"), "audio_decoder" }, { xine_list_video_decoder_plugins, _(" -Video decoder:\n"), "video_decoder" }, { NULL, NULL, NULL } }; configfile = (char *) xine_xmalloc(strlen(xine_get_homedir()) + strlen(cfgdir) + strlen(cfgfile) + 3); sprintf(configfile, "%s/%s", xine_get_homedir(), cfgdir); mkdir(configfile, 0755); sprintf(configfile + strlen(configfile), "/%s", cfgfile); xine = xine_new(); xine_config_load(xine, configfile); xine_init(xine); show_version(); if(type && strlen(type)) { i = 0; while(list_functions[i].name) { if(!strncasecmp(type, list_functions[i].type, strlen(type))) { if((plugins = list_functions[i].func(xine))) { printf(_("\n Available xine's plugins:\n")); print_formatted(list_functions[i].name, plugins); goto __found; } } i++; } printf(_("No available plugins found of %s type!\n"), type); __found: ; } else { printf(_("\n Available xine's plugins:\n")); i = 0; while(list_functions[i].name) { if((plugins = list_functions[i].func(xine))) print_formatted(list_functions[i].name, plugins); i++; } } xine_exit(xine); } /* * */ static void show_usage (void) { const char *const *driver_ids; const char *driver_id; xine_t *xine; char *cfgdir = CONFIGDIR; char *cfgfile = CONFIGFILE; char *configfile = NULL; char **backends, *backend; configfile = (char *) xine_xmalloc(strlen(xine_get_homedir()) + strlen(cfgdir) + strlen(cfgfile) + 3); sprintf(configfile, "%s/%s", xine_get_homedir(), cfgdir); mkdir(configfile, 0755); sprintf(configfile + strlen(configfile), "/%s", cfgfile); xine = xine_new(); xine_config_load(xine, configfile); xine_init(xine); printf("\n"); printf(_("Usage: xine [OPTIONS]... [MRL]\n")); printf("\n"); printf(_("OPTIONS are:\n")); printf(_(" -v, --version Display version.\n")); printf(_(" --verbose [=level] Set verbosity level. Default is 1.\n")); printf(_(" -c, --config Use config file instead of default one.\n")); printf(_(" -V, --video-driver Select video driver by id. Available drivers: \n")); printf(" "); if((driver_ids = xine_list_video_output_plugins (xine))) { driver_id = *driver_ids++; while (driver_id) { printf ("%s ", driver_id); driver_id = *driver_ids++; } } printf ("\n"); printf(_(" -A, --audio-driver Select audio driver by id. Available drivers: \n")); printf(" null "); if((driver_ids = xine_list_audio_output_plugins (xine))) { driver_id = *driver_ids++; while (driver_id) { printf ("%s ", driver_id); driver_id = *driver_ids++; } } printf ("\n"); printf(_(" -u, --spu-channel <#> Select SPU (subtitle) channel '#'.\n")); printf(_(" -a, --audio-channel <#> Select audio channel '#'.\n")); printf(_(" -p, --auto-play [opt] Play on start. Can be followed by:\n" " 'f': in fullscreen mode.\n" " 'h': hide GUI (panel, etc.).\n" " 'w': hide video window.\n" " 'q': quit when play is done.\n" " 'd': retrieve playlist from DVD. (deprecated. use -s DVD)\n" " 'v': retrieve playlist from VCD. (deprecated. use -s VCD)\n")); #ifdef HAVE_XINERAMA printf(_(" 'F': in xinerama fullscreen mode.\n")); #endif printf(_(" -s, --auto-scan auto-scan play list from \n")); printf(_(" -f, --fullscreen start in fullscreen mode,\n")); #ifdef HAVE_XINERAMA printf(_(" -F, --xineramafull start in xinerama fullscreen (display on several screens),\n")); #endif printf(_(" -g, --hide-gui hide GUI (panel, etc.)\n")); printf(_(" -I, --no-gui disable GUI\n")); printf(_(" --no-mouse disable mouse event\n")); printf(_(" -H, --hide-video hide video window\n")); #ifdef HAVE_LIRC printf(_(" -L, --no-lirc Turn off LIRC support.\n")); #endif printf(_(" --visual Use the specified X11 visual. \n" " is either an X11 visual class, or a visual id.\n")); printf(_(" --install Install a private colormap.\n")); printf(_(" --keymap [=option] Display keymap. Option are:\n" " 'default': display default keymap table,\n" " 'lirc': display draft of a .lircrc config file.\n" " 'remapped': user remapped keymap table.\n" " 'file:': use as keymap.\n" " -if no option is given, 'default' is selected.\n")); printf(_(" -n, --network Enable network remote control server.\n")); printf(_(" --network-port Specify network server port number.\n")); printf(_(" -R, --root Use root window as video window.\n")); printf(_(" -W, --wid Use a window id.\n")); printf(_(" -G, --geometry Set output window geometry (X style).\n")); printf(_(" -B, --borderless Borderless video output window.\n")); printf(_(" -N, --animation Specify mrl to play when video output isn't used.\n" " -can be used more than one time.\n")); printf(_(" -P, --playlist Load a playlist file.\n")); printf(_(" -l, --loop [=mode] Set playlist loop mode (default: loop). Modes are:\n" " 'loop': loop entire playlist.\n" " 'repeat': repeat current playlist entry.\n" " 'shuffle': select randomly a yet unplayed entry from playlist\n" " 'shuffle+': same as 'shuffle', but indefinetely replay the playlist.\n")); printf(_(" --skin-server-url Define the skin server url.\n")); printf(_(" --enqueue ... Enqueue mrl of a running session (session 0)\n")); printf(_(" -S, --session \n" " Session managements. Options can be:\n" " session=n specify session number,\n" " mrl=m add mrl to the playlist,\n" " audio=c select audio channel (: 'next' or 'prev'),\n" " spu=c select spu channel (: 'next' or 'prev'),\n" " volume=v set audio volume,\n" " amp=v set amplification level,\n" " loop=m set loop mode (: 'none' 'loop' 'repeat' 'shuffle' or 'shuffle+'),\n" " get_speed get speed value (see man page for returned value).\n" " (playlist|pl)=p\n" "

can be:\n" " 'clear' clear the playlist,\n" " 'first' play first entry in the playlist,\n" " 'prev' play previous playlist entry,\n" " 'next' play next playlist entry,\n" " 'last' play last entry in the playlist,\n" " 'load:s' load playlist file ,\n" " 'stop' stop playback at the end of current playback.\n" " 'cont' continue playback at the end of current playback.\n" " play, slow2, slow4, pause, fast2,\n" " fast4, stop, quit, fullscreen, eject.\n")); printf(_(" -Z Don't automatically start playback (smart mode).\n")); printf(_(" -D, --deinterlace [post]... Deinterlace video output. One or more post plugin\n" " can be specified, with optional parameters.\n" " Syntax is the same as --post option.\n")); printf(_(" -r, --aspect-ratio Set aspect ratio of video output. Modes are:\n" " 'auto', 'square', '4:3', 'anamorphic', 'dvb'.\n")); #ifdef XINE_PARAM_BROADCASTER_PORT printf(_(" --broadcast-port Set port of xine broadcaster (master side)\n" " Slave is started with 'xine slave://address:port'\n")); #endif printf(_(" --no-logo Don't display the logo.\n")); printf(_(" -E, --no-reload Don't reload old playlist.\n")); printf(_(" --post [:parameter=value][,...][;...]\n" " Load one or many post plugin(s).\n" " Parameters are comma separated.\n" " This option can be used more than one time.\n")); printf(_(" --disable-post Don't enable post plugin(s).\n")); printf(_(" --no-splash Don't display the splash screen.\n")); printf(_(" --stdctl Control xine by the console, using lirc commands.\n")); printf(_(" -T, --tvout Turn on tvout support. Backend can be:\n")); printf(" "); if((backends = tvout_get_backend_names())) { backend = *backends++; while(backend) { printf("%s ", backend); backend = *backends++; } } printf("\n"); printf(_(" --list-plugins [=type] Display the list of all available plugins,\n" " Optional can be:\n" " audio_out, video_out, demux, input, sub, post,\n" " audio_decoder, video_decoder.\n")); printf(_(" --bug-report [=mrl] Enable bug report mode:\n" " Turn on verbosity, gather all output\n" " messages and write them into a file named\n" " BUG-REPORT.TXT.\n" " If is given, xine will play the mrl\n" " then quit (like -pq).\n")); printf("\n\n"); printf(_("examples for valid MRLs (media resource locator):\n" " File: 'path/foo.vob'\n" " '/path/foo.vob'\n" " 'file://path/foo.vob'\n" " 'fifo://[[mpeg1|mpeg2]:/]path/foo'\n" " 'stdin://[mpeg1|mpeg2]' or '-' (mpeg2 only)\n" " DVD: 'dvd://VTS_01_2.VOB'\n" " VCD: 'vcd://'\n")); printf("\n"); xine_exit(xine); } /* * Try to load video output plugin, by stored name or probing */ static xine_video_port_t *load_video_out_driver(int driver_number) { xine_video_port_t *video_port = NULL; double res_h, res_v; x11_visual_t vis; int driver_num; #ifdef HAVE_XINERAMA int dummy_event, dummy_error; #endif vis.display = gGui->video_display; vis.screen = gGui->video_screen; vis.d = gGui->video_window; XLockDisplay(gGui->video_display); res_h = (DisplayWidth (gGui->video_display, gGui->video_screen)*1000 / DisplayWidthMM (gGui->video_display, gGui->video_screen)); res_v = (DisplayHeight (gGui->video_display, gGui->video_screen)*1000 / DisplayHeightMM (gGui->video_display, gGui->video_screen)); XUnlockDisplay(gGui->video_display); gGui->pixel_aspect = res_v / res_h; #ifdef HAVE_XINERAMA if (XineramaQueryExtension(gGui->video_display, &dummy_event, &dummy_error)) { int count = 1; XineramaQueryScreens(gGui->video_display, &count); if (count > 1) /* multihead -> assuming square pixels */ gGui->pixel_aspect = 1.0; } #endif #ifdef DEBUG printf("pixel_aspect: %f\n", gGui->pixel_aspect); #endif vis.dest_size_cb = video_window_dest_size_cb; vis.frame_output_cb = video_window_frame_output_cb; vis.user_data = NULL; /* * Setting default (configfile stuff need registering before updating, etc...). */ driver_num = xine_config_register_enum(gGui->xine, "video.driver", 0, video_driver_ids, _("video driver to use"), _("Choose video driver. " "NOTE: you may restart xine to use the new driver"), CONFIG_LEVEL_ADV, CONFIG_NO_CB, CONFIG_NO_DATA); if (driver_number < 0) { /* video output driver auto-probing */ const char *const *driver_ids; int i; if((!strcasecmp(video_driver_ids[driver_num], "none")) || (!strcasecmp(video_driver_ids[driver_num], "null"))) { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_num], XINE_VISUAL_TYPE_NONE, (void *) &vis); if (video_port) return video_port; } else if(!strcasecmp(video_driver_ids[driver_num], "fb")) { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_num], XINE_VISUAL_TYPE_FB, NULL); if (video_port) return video_port; } else if(strcasecmp(video_driver_ids[driver_num], "auto")) { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_num], XINE_VISUAL_TYPE_X11, (void *) &vis); if (video_port) return video_port; } /* note: xine-lib can do auto-probing for us if we want. * but doing it here should do no harm. */ i = 0; driver_ids = xine_list_video_output_plugins (gGui->xine); while (driver_ids[i]) { if(gGui->verbosity) printf (_("main: probing <%s> video output plugin\n"), driver_ids[i]); video_port = xine_open_video_driver(gGui->xine, driver_ids[i], XINE_VISUAL_TYPE_X11, (void *) &vis); if (video_port) { return video_port; } i++; } if (!video_port) { printf (_("main: all available video drivers failed.\n")); exit (1); } } else { /* 'none' plugin is a special case, just change the visual type */ if((!strcasecmp(video_driver_ids[driver_number], "none")) || (!strcasecmp(video_driver_ids[driver_number], "null"))) { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_number], XINE_VISUAL_TYPE_NONE, (void *) &vis); /* do not save on config, otherwise user would never see images again... */ } else if(!strcasecmp(video_driver_ids[driver_number], "fb")) { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_number], XINE_VISUAL_TYPE_FB, NULL); } else { video_port = xine_open_video_driver(gGui->xine, video_driver_ids[driver_number], XINE_VISUAL_TYPE_X11, (void *) &vis); } if(!video_port) { printf (_("main: video driver <%s> failed\n"), video_driver_ids[driver_number]); exit (1); } } return video_port; } /* * Try to load audio output plugin, by stored name or probing */ static xine_audio_port_t *load_audio_out_driver(int driver_number) { xine_audio_port_t *audio_port = NULL; int driver_num; /* * Setting default (configfile stuff need registering before updating, etc...). */ driver_num = xine_config_register_enum(gGui->xine, "video.driver", 0, video_driver_ids, _("video driver to use"), _("Choose video driver. " "NOTE: you may restart xine to use the new driver"), CONFIG_LEVEL_ADV, CONFIG_NO_CB, CONFIG_NO_DATA); driver_num = xine_config_register_enum(gGui->xine, "audio.driver", 0, audio_driver_ids, _("audio driver to use"), _("Choose audio driver. " "NOTE: you may restart xine to use the new driver"), CONFIG_LEVEL_ADV, CONFIG_NO_CB, CONFIG_NO_DATA); if (driver_number < 0) { const char *const *driver_ids; int i; if (strcasecmp(audio_driver_ids[driver_num], "auto")) { /* don't want to load an audio driver ? */ if (!strncasecmp(audio_driver_ids[driver_num], "NULL", 4)) { if(gGui->verbosity) printf(_("main: not using any audio driver (as requested).\n")); return NULL; } audio_port = xine_open_audio_driver(gGui->xine, audio_driver_ids[driver_num], NULL); if (audio_port) return audio_port; } /* note: xine-lib can do auto-probing for us if we want. * but doing it here should do no harm. */ i = 0; driver_ids = xine_list_audio_output_plugins (gGui->xine); while (driver_ids[i]) { if(strcmp(driver_ids[i], "none")) { if(gGui->verbosity) printf(_("main: probing <%s> audio output plugin\n"), driver_ids[i]); } else { if(gGui->verbosity) printf(_("main: skipping <%s> audio output plugin from auto-probe\n"), driver_ids[i]); i++; continue; } audio_port = xine_open_audio_driver(gGui->xine, driver_ids[i], NULL); if (audio_port) { return audio_port; } i++; } printf(_("main: audio driver probing failed => no audio output\n")); } else { /* don't want to load an audio driver ? */ if (!strncasecmp (audio_driver_ids[driver_number], "NULL", 4)) { if(gGui->verbosity) printf(_("main: not using any audio driver (as requested).\n")); /* calling -A null is useful to developers, but we should not save it at * config. if user doesn't have a sound card he may go to setup screen * changing audio.driver to NULL in order to make xine start a bit faster. */ } else { audio_port = xine_open_audio_driver(gGui->xine, audio_driver_ids[driver_number], NULL); if (!audio_port) { printf (_("main: audio driver <%s> failed\n"), audio_driver_ids[driver_number]); exit(1); } } } return audio_port; } /* * */ static void event_listener(void *user_data, const xine_event_t *event) { struct timeval tv; /* * Ignoring finished event logo is displayed (or played), that save us * from a loop of death */ if(gGui->logo_mode && (event->type == XINE_EVENT_UI_PLAYBACK_FINISHED)) return; gettimeofday (&tv, NULL); if(abs(tv.tv_sec - event->tv.tv_sec) > 3) { fprintf(stderr, "Event too old, discarding\n"); return; } switch(event->type) { /* frontend can e.g. move on to next playlist entry */ case XINE_EVENT_UI_PLAYBACK_FINISHED: if(event->stream == gGui->stream) { #ifdef XINE_PARAM_GAPLESS_SWITCH if( xine_check_version(1,1,1) ) xine_set_param(gGui->stream, XINE_PARAM_GAPLESS_SWITCH, 1); #endif gui_playlist_start_next(); } else if(event->stream == gGui->visual_anim.stream) { /* printf("xitk/main.c: restarting visual stream...\n"); */ visual_anim_play_next(); } break; /* inform ui that new channel info is available */ case XINE_EVENT_UI_CHANNELS_CHANGED: if(event->stream == gGui->stream) panel_update_channel_display(); break; /* request title display change in ui */ case XINE_EVENT_UI_SET_TITLE: if(event->stream == gGui->stream) { xine_ui_data_t *uevent = (xine_ui_data_t *) event->data; if(strcmp(gGui->mmk.ident, uevent->str)) { if(gGui->mmk.ident) free(gGui->mmk.ident); if(gGui->playlist.num && gGui->playlist.cur >= 0 && gGui->playlist.mmk && gGui->playlist.mmk[gGui->playlist.cur]) { if(gGui->playlist.mmk[gGui->playlist.cur]->ident) free(gGui->playlist.mmk[gGui->playlist.cur]->ident); gGui->playlist.mmk[gGui->playlist.cur]->ident = strdup(uevent->str); } gGui->mmk.ident = strdup(uevent->str); video_window_set_mrl(gGui->mmk.ident); playlist_mrlident_toggle(); panel_update_mrl_display(); } } break; /* message (dialog) for the ui to display */ case XINE_EVENT_UI_MESSAGE: if(event->stream == gGui->stream) { xine_ui_message_data_t *data = (xine_ui_message_data_t *) event->data; char buffer[8192]; void (*report)(char *message, ...) #if __GNUC__ >= 3 __attribute__ ((format (printf, 1, 2))) #endif ; report = xine_error_with_more; memset(&buffer, 0, sizeof(buffer)); switch(data->type) { /* (messages to UI) */ case XINE_MSG_NO_ERROR: { /* copy strings, and replace '\0' separators by '\n' */ char *s, *d; report = xine_info; s = data->messages; d = buffer; while(s && (*s != '\0') && ((*s + 1) != '\0')) { switch(*s) { case '\0': *d = '\n'; break; default: *d = *s; break; } s++; d++; } *++d = '\0'; } break; /* (warning message) */ case XINE_MSG_GENERAL_WARNING: report = xine_info; snprintf(buffer, sizeof(buffer), "%s:", _("*drum roll*, xine lib wants to take your attention " "to deliver an important message to you ;-):")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " %s %s", (char *) data + data->explanation, (char *) data + data->parameters); else snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " %s", _("No information available.")); break; /* (host name) */ case XINE_MSG_UNKNOWN_HOST: snprintf(buffer, sizeof(buffer), "%s", _("The host you're trying to connect is unknown.\n" "Check the validity of the specified hostname.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (device name) */ case XINE_MSG_UNKNOWN_DEVICE: snprintf(buffer, sizeof(buffer), "%s", _("The device name you specified seems invalid.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* none */ case XINE_MSG_NETWORK_UNREACHABLE: snprintf(buffer, sizeof(buffer), "%s", _("The network looks unreachable.\nCheck your network " "setup and/or the server name.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (host name) */ case XINE_MSG_CONNECTION_REFUSED: snprintf(buffer, sizeof(buffer), "%s", _("The connection was refused.\nCheck the host name.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (file name or mrl) */ case XINE_MSG_FILE_NOT_FOUND: snprintf(buffer, sizeof(buffer), "%s", _("The specified file or MRL could not be found. Please check it twice.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (device/file/mrl) */ case XINE_MSG_READ_ERROR: snprintf(buffer, sizeof(buffer), "%s", _("The source can't be read.\nMaybe you don't have enough " "rights for this, or source doesn't contain data " "(e.g: not disc in drive).")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (library/decoder) */ case XINE_MSG_LIBRARY_LOAD_ERROR: snprintf(buffer, sizeof(buffer), "%s", _("A problem occurred while loading a library or a decoder")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), ": %s", (char *) data + data->parameters); break; /* none */ case XINE_MSG_ENCRYPTED_SOURCE: snprintf(buffer, sizeof(buffer), "%s", _("The source seems encrypted, and can't be read.")); if(!strncasecmp(gGui->mmk.mrl, "dvd:/", 5)) { strlcat(buffer, _("\nYour DVD is probably crypted. " "According to your country laws, you can or can't " "install/use libdvdcss to be able to read this disc, " "which you bought."), sizeof(buffer)); } if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s)", (char *) data + data->parameters); break; /* (warning message) */ case XINE_MSG_SECURITY: report = xine_info; if(data->explanation) snprintf(buffer, sizeof(buffer), "%s %s", (char *) data + data->explanation, (char *) data + data->parameters); else snprintf(buffer, sizeof(buffer), "%s", _("No information available.")); break; case XINE_MSG_AUDIO_OUT_UNAVAILABLE: gui_stop(NULL, NULL); snprintf(buffer, sizeof(buffer), "%s", _("The audio device is unavailable. " "Please verify if another program already uses it.")); break; default: snprintf(buffer, sizeof(buffer), "%s", _("*sight*, unkown error.")); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), " (%s %s)", (char *) data + data->explanation, (char *) data + data->parameters); break; } if(gGui->verbosity >= XINE_VERBOSITY_DEBUG) { strlcat(buffer, "\n\n[", sizeof(buffer)); if(data->explanation) snprintf(buffer+strlen(buffer), sizeof(buffer)-strlen(buffer), "'%s' '%s'", (char *) data + data->explanation, (char *) data + data->parameters); strlcat(buffer, "]", sizeof(buffer)); } if(strlen(buffer)) report("%s", buffer); } break; /* e.g. aspect ratio change during dvd playback */ case XINE_EVENT_FRAME_FORMAT_CHANGE: break; /* report current audio vol level (l/r/mute) */ case XINE_EVENT_AUDIO_LEVEL: if(event->stream == gGui->stream) { xine_audio_level_data_t *aevent = (xine_audio_level_data_t *) event->data; gGui->mixer.volume_level = (aevent->left + aevent->right) / 2; if(gGui->mixer.method == SOUND_CARD_MIXER) { gGui->mixer.mute = aevent->mute; xitk_slider_set_pos(panel->mixer.slider, gGui->mixer.volume_level); xitk_checkbox_set_state(panel->mixer.mute, gGui->mixer.mute); } } break; #ifdef XINE_EVENT_AUDIO_AMP_LEVEL /* Precaution for backward compatibility, will be removed some time */ /* report current audio amp level (l/r/mute) */ case XINE_EVENT_AUDIO_AMP_LEVEL: if(event->stream == gGui->stream) { xine_audio_level_data_t *aevent = (xine_audio_level_data_t *) event->data; gGui->mixer.amp_level = (aevent->left + aevent->right) / 2; if(gGui->mixer.method == SOFTWARE_MIXER) { gGui->mixer.mute = aevent->mute; xitk_slider_set_pos(panel->mixer.slider, gGui->mixer.amp_level); xitk_checkbox_set_state(panel->mixer.mute, gGui->mixer.mute); } } break; #endif /* last event sent when stream is disposed */ case XINE_EVENT_QUIT: break; /* index creation/network connections */ case XINE_EVENT_PROGRESS: if(event->stream == gGui->stream) { xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; char buffer[1024]; snprintf(buffer, sizeof(buffer), "%s [%d%%]\n", pevent->description, pevent->percent); gGui->mrl_overrided = 3; panel_set_title(buffer); osd_display_info("%s", buffer); } break; case XINE_EVENT_MRL_REFERENCE: if((event->stream == gGui->stream) && gGui->playlist.num) { xine_mrl_reference_data_t *ref = (xine_mrl_reference_data_t *) event->data; if(gGui->verbosity) printf("XINE_EVENT_MRL_REFERENCE got mrl [%s] (alternative=%d)\n", ref->mrl, ref->alternative); if(ref->alternative == 0) { gGui->playlist.ref_append++; mediamark_insert_entry(gGui->playlist.ref_append, ref->mrl, ref->mrl, NULL, 0, -1, 0, 0); } else { mediamark_t *mmk = mediamark_get_mmk_by_index(gGui->playlist.ref_append); if(mmk) { mediamark_append_alternate_mrl(mmk, ref->mrl); mediamark_set_got_alternate(mmk); } } } break; case XINE_EVENT_UI_NUM_BUTTONS: break; case XINE_EVENT_SPU_BUTTON: { xine_spu_button_t *spubtn = (xine_spu_button_t *) event->data; if(spubtn->direction) video_window_set_cursor(CURSOR_HAND); else video_window_set_cursor(CURSOR_ARROW); } break; case XINE_EVENT_DROPPED_FRAMES: if (xine_get_param(gGui->stream, XINE_PARAM_SPEED) <= XINE_SPEED_NORMAL) { too_slow_window(); } break; } } /* * */ int main(int argc, char *argv[]) { /* command line options will end up in these variables: */ int c = '?', aos = 0; int option_index = 0; int audio_channel = -1; int window_id = 0; int spu_channel = -1; char *audio_driver_id = NULL; char *video_driver_id = NULL; sigset_t vo_mask; char **_argv; int _argc; int driver_num; int session = -1; int aspect_ratio = XINE_VO_ASPECT_AUTO ; int no_auto_start = 0; char *cfgdir = CONFIGDIR; char *cfgfile = CONFIGFILE; int old_playlist_cfg, no_old_playlist = 0; char **pplugins = NULL; int pplugins_num = 0; char *tvout = NULL; char *pdeinterlace = NULL; int enable_deinterlace = 0; char **session_argv = NULL; int session_argv_num = 0; int retval = 0; #ifdef ENABLE_NLS if((xitk_set_locale()) != NULL) { setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); } #endif bindtextdomain(PACKAGE, XITK_LOCALE); textdomain(PACKAGE); /* Check xine library version */ if(!xine_check_version(1, 0, 0)) { int major, minor, sub; xine_get_version (&major, &minor, &sub); fprintf(stderr, _("Require xine library version 1.0.0, found %d.%d.%d.\n"), major, minor,sub); exit(1); } sigemptyset(&vo_mask); sigaddset(&vo_mask, SIGALRM); if (sigprocmask (SIG_BLOCK, &vo_mask, NULL)) fprintf (stderr, "sigprocmask() failed.\n"); gGui = (gGui_t *) xine_xmalloc(sizeof(gGui_t)); gGui->stream = NULL; gGui->debug_level = 0; gGui->autoscan_plugin = NULL; gGui->prefered_visual_class = -1; gGui->prefered_visual_id = None; gGui->install_colormap = 0; gGui->cursor_grabbed = 0; gGui->network = 0; gGui->network_port = 0; gGui->video_window = None; gGui->use_root_window = 0; #ifdef HAVE_XF86VIDMODE gGui->XF86VidMode_fullscreen = 0; #endif gGui->actions_on_start[aos] = ACTID_NOKEY; gGui->playlist.mmk = NULL; gGui->playlist.loop = PLAYLIST_LOOP_NO_LOOP; gGui->playlist.control = 0; gGui->skin_server_url = NULL; gGui->verbosity = 0; gGui->broadcast_port = 0; gGui->display_logo = 1; gGui->post_video_elements = NULL; gGui->post_video_elements_num = 0; gGui->post_video_enable = 1; gGui->post_audio_elements = NULL; gGui->post_audio_elements_num = 0; gGui->post_audio_enable = 1; gGui->splash = 1; #ifdef HAVE_LIRC gGui->lirc_enable = 1; #endif gGui->deinterlace_enable = 0; gGui->report = stdout; gGui->ssaver_enabled = 1; gGui->no_gui = 0; gGui->no_mouse = 0; gGui->wid = 0; gGui->nongui_error_msg = NULL; window_attribute.x = window_attribute.y = -8192; window_attribute.width = window_attribute.height = -1; window_attribute.borderless = 0; _argv = build_command_line_args(argc, argv, &_argc); #ifdef TRACE_RC _rc_file_check_args(_argc, _argv); #endif visual_anim_init(); /* * Parse X Ressource database */ xrm_parse(); /* * parse command line */ opterr = 0; while((c = getopt_long(_argc, _argv, short_options, long_options, &option_index)) != EOF) { switch(c) { #ifdef HAVE_LIRC case 'L': /* Disable LIRC support */ gGui->lirc_enable = 0; break; #endif case 'u': /* Select SPU channel */ sscanf(optarg, "%i", &spu_channel); break; case 'a': /* Select audio channel */ sscanf(optarg, "%i", &audio_channel); break; case 'V': /* select video driver by plugin id */ if(optarg != NULL) { video_driver_id = strdup(optarg); } else { fprintf (stderr, _("video driver id required for -V option\n")); exit (1); } break; case 'A': /* Select audio driver */ if(optarg != NULL) { audio_driver_id = strdup(optarg); } else { fprintf (stderr, _("audio driver id required for -A option\n")); exit (1); } break; case 'p':/* Play [[in fullscreen][then quit]] on start */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_PLAY; if(optarg != NULL) { if(strrchr(optarg, 'f')) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_FULLSCREEN; } #ifdef HAVE_XINERAMA if(strrchr(optarg, 'F')) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_XINERAMA_FULLSCREEN; } #endif if(strrchr(optarg, 'h')) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_VISIBLITY; } if(strrchr(optarg, 'q')) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_QUIT; } if(strrchr(optarg, 'w')) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_WINOUT_VISIBLITY; } if(strrchr(optarg, 'd')) { gGui->autoscan_plugin = "DVD"; } if(strrchr(optarg, 'v')) { gGui->autoscan_plugin = "VCD"; } } break; case 'g': /* hide panel on start */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_VISIBLITY; break; case 'H': /* hide video on start */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_WINOUT_VISIBLITY; break; case 'f': /* full screen mode on start */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_FULLSCREEN; break; #ifdef HAVE_XINERAMA case 'F': /* xinerama full screen mode on start */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_XINERAMA_FULLSCREEN; break; #endif case 'D': if(!pdeinterlace) { enable_deinterlace++; if(optarg) { char *p = xine_chomp(optarg); if(p && strlen(p)) pdeinterlace = strdup(p); } } break; case 'r': if(optarg != NULL) { char *p = xine_chomp(optarg); if(!strcasecmp(p, "auto")) aspect_ratio = XINE_VO_ASPECT_AUTO; else if(!strcasecmp(p, "square")) aspect_ratio = XINE_VO_ASPECT_SQUARE; else if(!strcasecmp(p, "4:3")) aspect_ratio = XINE_VO_ASPECT_4_3; else if(!strcasecmp(p, "anamorphic")) aspect_ratio = XINE_VO_ASPECT_ANAMORPHIC; else if(!strcasecmp(p, "dvb")) aspect_ratio = XINE_VO_ASPECT_DVB; else { printf(_("Bad aspect ratio mode '%s', see xine --help\n"), optarg); exit(1); } } break; case 's': /* autoscan on start */ gGui->autoscan_plugin = xine_chomp(optarg); break; case OPTION_VISUAL: if(optarg != NULL) { if(!parse_visual(&gGui->prefered_visual_id, &gGui->prefered_visual_class, optarg)) { show_usage(); exit(1); } } break; case OPTION_INSTALL_COLORMAP: gGui->install_colormap = 1; break; case OPTION_DISPLAY_KEYMAP: if(optarg != NULL) { char *p = xine_chomp(optarg); if(!strcasecmp(p, "default")) kbindings_display_default_bindings(); else if(!strcasecmp(p, "lirc")) kbindings_display_default_lirc_bindings(); else if(!strcasecmp(p, "remapped")) kbindings_display_current_bindings((kbindings_init_kbinding())); else if(!strncasecmp(p, "file:", 5)) { char *keymap_file = p + 5; if((gGui->keymap_file == NULL) && keymap_file && strlen(keymap_file)) { char buffer[XITK_PATH_MAX + XITK_NAME_MAX + 2]; memset(&buffer, 0, sizeof(buffer)); xitk_subst_special_chars(keymap_file, &buffer[0]); gGui->keymap_file = strdup(buffer); continue; } } else kbindings_display_default_bindings(); } else kbindings_display_default_bindings(); exit(1); break; case 'n': /* Enable remote control server */ gGui->network = 1; break; case OPTION_NETWORK_PORT: if(optarg) { int port = strtol(optarg, &optarg, 10); if((port >= 1) && (port <= 65535)) gGui->network_port = port; else printf(_("Bad port number: %d\n"), port); } break; case 'R': /* Use root window for video output */ gGui->use_root_window = 1; break; case 'G': /* Set geometry */ if(optarg != NULL) { if(!parse_geometry(&window_attribute, optarg)) { printf(_("Bad geometry '%s', see xine --help\n"), optarg); exit(1); } } break; case 'B': window_attribute.borderless = 1; break; case 'N': visual_anim_add_animation(optarg); break; case 'P': if((!actions_on_start(gGui->actions_on_start, ACTID_PLAYLIST) && (aos < MAX_ACTIONS_ON_START))) gGui->actions_on_start[aos++] = ACTID_PLAYLIST; if(!gGui->playlist.mmk) mediamark_load_mediamarks(optarg); else mediamark_concat_mediamarks(optarg); /* don't load original playlist when loading this one */ no_old_playlist = 1; break; case 'l': if(optarg != NULL) { char *p = xine_chomp(optarg); if(!strcasecmp(p, "loop")) gGui->playlist.loop = PLAYLIST_LOOP_LOOP; else if(!strcasecmp(p, "repeat")) gGui->playlist.loop = PLAYLIST_LOOP_REPEAT; else if(!strcasecmp(p, "shuffle+")) gGui->playlist.loop = PLAYLIST_LOOP_SHUF_PLUS; else if(!strcasecmp(p, "shuffle")) gGui->playlist.loop = PLAYLIST_LOOP_SHUFFLE; else { printf(_("Bad loop mode '%s', see xine --help\n"), optarg); exit(1); } } else gGui->playlist.loop = PLAYLIST_LOOP_LOOP; break; case OPTION_SK_SERVER: gGui->skin_server_url = strdup(optarg); break; case OPTION_ENQUEUE: if(is_remote_running(((session >= 0) ? session : 0))) { if(session < 0) session = 0; } break; case OPTION_VERBOSE: if(optarg != NULL) gGui->verbosity = strtol(optarg, &optarg, 10); else gGui->verbosity = 1; break; #ifdef XINE_PARAM_BROADCASTER_PORT case OPTION_BROADCAST_PORT: if(optarg != NULL) gGui->broadcast_port = strtol(optarg, &optarg, 10); break; #endif case OPTION_NO_LOGO: gGui->display_logo = 0; break; case OPTION_NO_MOUSE: gGui->no_mouse = 1; break; case 'S': if(is_remote_running(((session >= 0) ? session : 0))) retval = session_handle_subopt(optarg, &session); else { session_argv = (char **) realloc(session_argv, sizeof(char *) * (session_argv_num + 2)); session_argv[session_argv_num++] = strdup(optarg); session_argv[session_argv_num] = NULL; } break; case 'Z': no_auto_start = 1; break; case 'c': { char *cfg = xine_chomp(optarg); char buffer[XITK_PATH_MAX + XITK_NAME_MAX + 2]; memset(&buffer, 0, sizeof(buffer)); xitk_subst_special_chars(cfg, &buffer[0]); gGui->configfile = strdup(buffer); } break; case 'E': no_old_playlist = 1; break; case OPTION_POST: pplugins = (char **) realloc(pplugins, sizeof(char *) * (pplugins_num + 2)); pplugins[pplugins_num++] = optarg; pplugins[pplugins_num] = NULL; break; case OPTION_DISABLE_POST: gGui->post_video_enable = 0; gGui->post_audio_enable = 0; break; case OPTION_NO_SPLASH: gGui->splash = 0; break; case 'v': /* Display version and exit*/ show_version(); exit(1); break; case 'h': /* Display usage */ case '?': show_usage(); exit(1); break; case OPTION_STDCTL: gGui->stdctl_enable = 1; break; case 'T': tvout = optarg; break; case OPTION_LIST_PLUGINS: { char *p = NULL; if(optarg) p = xine_chomp(optarg); list_plugins(p); exit(1); } break; case OPTION_BUG_REPORT: { FILE *f; if(!(f = fopen("BUG-REPORT.TXT", "w+"))) fprintf(stderr, "fopen(%s) failed: %s.\n", "BUG-REPORT.TXT", strerror(errno)); else { printf(_("*** NOTE ***\n")); printf(_(" Bug Report mode: All output messages will be added in BUG-REPORT.TXT file.\n")); #ifdef ENABLE_NLS if((xitk_set_locale()) != NULL) { setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); } #endif if (dup2((fileno(f)), STDOUT_FILENO) < 0) fprintf(stderr, "dup2() failed: %s.\n", strerror(errno)); else { if (dup2((fileno(f)), STDERR_FILENO) < 0) fprintf(stdout, "dup2() failed: %s.\n", strerror(errno)); } gGui->report = f; gGui->verbosity = 0xff; } if(optarg) { char *p = xine_chomp(optarg); session_argv = (char **) realloc(session_argv, sizeof(char *) * (session_argv_num + 2)); session_argv[session_argv_num] = (char *) xine_xmalloc(strlen(p) + 5); sprintf(session_argv[session_argv_num], "mrl=%s", p); session_argv[++session_argv_num] = NULL; if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_PLAY; if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_QUIT; } } break; case 'I': gGui->no_gui = 1; break; case 'W': /* Select wid */ if(optarg != NULL) { sscanf(optarg, "%i", &window_id); gGui->wid = window_id; } else { fprintf(stderr, _("window id required for -W option\n")); exit(1); } break; default: show_usage(); fprintf(stderr, _("invalid argument %d => exit\n"), c); exit(1); } } if(session >= 0) { /* Session feature was used, say good bye */ if(is_remote_running(session) && (_argc - optind)) { /* send all remaining MRL options to session */ int i; if(_argv[optind]) { for(i = optind; i < _argc; i++) { char enqueue_mrl[strlen(_argv[i]) + 256]; snprintf(enqueue_mrl, sizeof(enqueue_mrl), "session=%d,mrl=%s", session, atoa(_argv[i])); (void) session_handle_subopt(enqueue_mrl, &session); } } else printf(_("You should specify at least one MRL to enqueue!\n")); } free_command_line_args(&_argv, _argc); return retval; } /* * Using root window mode don't allow * window geometry, so, reset those params. */ if(gGui->use_root_window) { window_attribute.x = window_attribute.y = -8192; window_attribute.width = window_attribute.height = -1; window_attribute.borderless = 0; } show_banner(); #ifndef DEBUG if(!gGui->verbosity) { int error_fd; if ((error_fd = open("/dev/null", O_WRONLY)) < 0) printf("cannot open /dev/null"); else { if (dup2(error_fd, STDOUT_FILENO) < 0) printf("cannot dup2 stdout"); } } #endif /* * Initialize config */ if(gGui->configfile == NULL) { struct stat st; gGui->configfile = (char *) xine_xmalloc(strlen(xine_get_homedir()) + strlen(cfgdir) + strlen(cfgfile) + 3); sprintf (gGui->configfile, "%s/%s", xine_get_homedir(), cfgdir); mkdir (gGui->configfile, 0755); sprintf (gGui->configfile + strlen(gGui->configfile), "/%s", cfgfile); /* Popup setup window if there is no config file */ if(stat(gGui->configfile, &st) < 0) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_SETUP; } } /* * Initialize keymap */ if(gGui->keymap_file == NULL) { char *cfgdir = CONFIGDIR; char *keymap = "keymap"; gGui->keymap_file = (char *) xine_xmalloc(strlen(xine_get_homedir()) + strlen(cfgdir) + strlen(cfgfile) + strlen(keymap) + 3); sprintf(gGui->keymap_file, "%s/%s/%s", xine_get_homedir(), cfgdir, keymap); } pthread_mutex_init(&gGui->xe_mutex, NULL); gGui->xine = xine_new(); xine_config_load(gGui->xine, gGui->configfile); xine_engine_set_param(gGui->xine, XINE_ENGINE_PARAM_VERBOSITY, gGui->verbosity); /* * Playlist auto reload */ old_playlist_cfg = xine_config_register_bool(gGui->xine, "gui.playlist_auto_reload", 0, _("Automatically reload old playlist"), _("If it's enabled and if you don't specify any MRL in command " "line, xine will automatically load previous playlist."), CONFIG_LEVEL_BEG, dummy_config_cb, CONFIG_NO_DATA); if(old_playlist_cfg && (!(_argc - optind)) && (!no_old_playlist)) { char buffer[XITK_PATH_MAX + XITK_NAME_MAX + 2]; snprintf(buffer, sizeof(buffer), "%s/.xine/xine-ui_old_playlist.tox", xine_get_homedir()); mediamark_load_mediamarks(buffer); } gGui->subtitle_autoload = xine_config_register_bool(gGui->xine, "gui.subtitle_autoload", 1, _("Subtitle autoloading"), _("Automatically load subtitles if they exist."), CONFIG_LEVEL_BEG, sub_autoload_cb, CONFIG_NO_DATA); enable_deinterlace += xine_config_register_bool(gGui->xine, "gui.deinterlace_by_default", 0, _("Enable deinterlacing by default"), _("Deinterlace plugin will be enabled on " "startup. Progressive streams are automaticaly " "detected with no performance penalty."), CONFIG_LEVEL_BEG, NULL, CONFIG_NO_DATA); if( enable_deinterlace ) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_INTERLEAVE; } /* * init gui */ gui_init(_argc - optind, &_argv[optind], &window_attribute); pthread_mutex_init(&gGui->download_mutex, NULL); /* Automatically start playback if new_mode is enabled and playlist is filled */ if((gGui->smart_mode && (gGui->playlist.num || actions_on_start(gGui->actions_on_start, ACTID_PLAYLIST)) && (!(actions_on_start(gGui->actions_on_start, ACTID_PLAY)))) && (no_auto_start == 0)) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_PLAY; } /* * xine init */ xine_init(gGui->xine); /* Get old working path from input plugin */ { xine_cfg_entry_t cfg_entry; if(xine_config_lookup_entry(gGui->xine, "media.files.origin_path", &cfg_entry)) snprintf(gGui->curdir, sizeof(gGui->curdir), "%s", cfg_entry.str_value); else getcwd(&(gGui->curdir[0]), XITK_PATH_MAX); } /* * load and init output drivers */ /* Video out plugin */ driver_num = -1; { const char *const *vids = xine_list_video_output_plugins(gGui->xine); int i = 0; while(vids[i++]); video_driver_ids = (char **) xine_xmalloc(sizeof(char *) * (i + 1)); i = 0; video_driver_ids[i] = strdup("auto"); while(vids[i]) { video_driver_ids[i + 1] = strdup(vids[i]); i++; } video_driver_ids[i + 1] = NULL; if(video_driver_id) { for(i = 0; video_driver_ids[i] != NULL; i++) { if(!strcasecmp(video_driver_id, video_driver_ids[i])) { driver_num = i; break; } } } gGui->vo_port = load_video_out_driver(driver_num); } { xine_cfg_entry_t cfg_vo_entry; if(xine_config_lookup_entry(gGui->xine, "video.driver", &cfg_vo_entry)) { if(!strcasecmp(video_driver_ids[cfg_vo_entry.num_value], "dxr3")) { xine_cfg_entry_t cfg_entry; if(xine_config_lookup_entry(gGui->xine, "dxr3.output.mode", &cfg_entry)) { if(((!strcmp(cfg_entry.enum_values[cfg_entry.num_value], "letterboxed tv")) || (!strcmp(cfg_entry.enum_values[cfg_entry.num_value], "widescreen tv"))) && (!(actions_on_start(gGui->actions_on_start, ACTID_TOGGLE_WINOUT_VISIBLITY)))) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_WINOUT_VISIBLITY; } } } else if(!strcasecmp(video_driver_ids[cfg_vo_entry.num_value], "fb")) { if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos++] = ACTID_TOGGLE_WINOUT_VISIBLITY; } } } SAFE_FREE(video_driver_id); /* Audio out plugin */ driver_num = -1; { const char *const *aids = xine_list_audio_output_plugins(gGui->xine); int i = 0; while(aids[i++]); audio_driver_ids = (char **) xine_xmalloc(sizeof(char *) * (i + 2)); i = 0; audio_driver_ids[i] = strdup("auto"); audio_driver_ids[i + 1] = strdup("null"); while(aids[i]) { audio_driver_ids[i + 2] = strdup(aids[i]); i++; } audio_driver_ids[i + 2] = NULL; if(audio_driver_id) { for(i = 0; audio_driver_ids[i] != NULL; i++) { if(!strcasecmp(audio_driver_id, audio_driver_ids[i])) { driver_num = i; break; } } } gGui->ao_port = load_audio_out_driver(driver_num); } SAFE_FREE(audio_driver_id); post_deinterlace_init(pdeinterlace); post_init(); gGui->stream = xine_stream_new(gGui->xine, gGui->ao_port, gGui->vo_port); #ifdef XINE_PARAM_EARLY_FINISHED_EVENT if( xine_check_version(1,1,1) ) xine_set_param(gGui->stream, XINE_PARAM_EARLY_FINISHED_EVENT, 1); #endif /* Store audio mixer level */ if(gGui->ao_port && (gGui->mixer.method == SOUND_CARD_MIXER)) gGui->mixer.original_level = xine_get_param(gGui->stream, XINE_PARAM_AUDIO_VOLUME); gGui->vo_none = xine_open_video_driver(gGui->xine, "none", XINE_VISUAL_TYPE_NONE, NULL); gGui->ao_none = xine_open_audio_driver(gGui->xine, "none", NULL); osd_init(); /* * Setup logo. */ gGui->logo_mode = 0; gGui->logo_has_changed = 0; gGui->logo_mrl = xine_config_register_string (gGui->xine, "gui.logo_mrl", XINE_LOGO_MRL, _("Logo MRL"), CONFIG_NO_HELP, CONFIG_LEVEL_EXP, main_change_logo_cb, CONFIG_NO_DATA); gGui->event_queue = xine_event_new_queue(gGui->stream); xine_event_create_listener_thread(gGui->event_queue, event_listener, NULL); if(tvout && strlen(tvout)) { if((gGui->tvout = tvout_init(gGui->display, tvout))) tvout_setup(gGui->tvout); } xine_set_param(gGui->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, audio_channel); xine_set_param(gGui->stream, XINE_PARAM_SPU_CHANNEL, spu_channel); xine_set_param(gGui->stream, XINE_PARAM_AUDIO_REPORT_LEVEL, 0); xine_set_param(gGui->stream, XINE_PARAM_AUDIO_AMP_LEVEL, gGui->mixer.amp_level); #ifdef XINE_PARAM_BROADCASTER_PORT xine_set_param(gGui->stream, XINE_PARAM_BROADCASTER_PORT, gGui->broadcast_port); #endif /* Visual animation stream init */ gGui->visual_anim.stream = xine_stream_new(gGui->xine, NULL, gGui->vo_port); gGui->visual_anim.event_queue = xine_event_new_queue(gGui->visual_anim.stream); gGui->visual_anim.current = 0; xine_event_create_listener_thread(gGui->visual_anim.event_queue, event_listener, NULL); xine_set_param(gGui->visual_anim.stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -2); xine_set_param(gGui->visual_anim.stream, XINE_PARAM_SPU_CHANNEL, -2); xine_set_param(gGui->visual_anim.stream, XINE_PARAM_AUDIO_REPORT_LEVEL, 0); /* subtitle stream */ gGui->spu_stream = xine_stream_new(gGui->xine, NULL, gGui->vo_port); xine_set_param(gGui->spu_stream, XINE_PARAM_AUDIO_REPORT_LEVEL, 0); /* init the video window */ video_window_select_visual(); xine_set_param(gGui->stream, XINE_PARAM_VO_ASPECT_RATIO, aspect_ratio); /* * hand control over to gui */ if(aos < MAX_ACTIONS_ON_START) gGui->actions_on_start[aos] = ACTID_NOKEY; /* Initialize posts, if required */ if(pplugins_num) { char **plugin = pplugins; while(*plugin) { vpplugin_parse_and_store_post((const char *) *plugin); applugin_parse_and_store_post((const char *) *plugin); plugin++; } vpplugin_rewire_posts(); applugin_rewire_posts(); } gui_run(session_argv); if(pplugins) free(pplugins); if(session_argv_num) { int i = 0; while(session_argv[i]) free(session_argv[i++]); free(session_argv); } pthread_mutex_destroy(&gGui->xe_mutex); pthread_mutex_destroy(&gGui->download_mutex); if(gGui->report != stdout) fclose(gGui->report); free_command_line_args(&_argv, _argc); return retval; }