Merge branch 'master' of git://git.sv.gnu.org/gnash
[gnash.git] / gui / gnash.cpp
bloba3e914832d35938a779110225019179f1979d0f0
1 // gnash.cpp: Main routine for top-level SWF player, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "gnashconfig.h"
23 #endif
25 #include <string>
26 #include <iostream>
27 #include <iterator>
28 #include <ios>
29 #include <boost/format.hpp>
30 #include <boost/algorithm/string/join.hpp>
31 #include <boost/algorithm/string/split.hpp>
32 #include <boost/algorithm/string/classification.hpp>
33 #include <cstdlib>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #ifdef ENABLE_NLS
37 # include <clocale>
38 #endif
40 #include "Player.h"
41 #include "log.h"
42 #include "rc.h" // for use of rcfile
43 #include "debugger.h"
44 #include "arg_parser.h"
45 #include "GnashNumeric.h" // for clamp
46 #include "GnashException.h"
47 #include "revno.h"
48 #include "MediaHandler.h"
50 #ifdef HAVE_FFMPEG_AVCODEC_H
51 extern "C" {
52 # include "ffmpeg/avcodec.h"
54 #endif
56 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
57 extern "C" {
58 # include "libavcodec/avcodec.h"
60 #endif
62 #ifdef HAVE_GST_GST_H
63 # include "gst/gst.h"
64 # include "gst/gstversion.h"
65 #endif
67 #ifdef GUI_ALP
68 #include <alp/title.h>
69 #include <alp/menubar.h>
70 #include <alp/bundlemgr.h>
71 #include <alp/appmgr.h>
72 # define gnash_main alp_main
73 #else
74 # define gnash_main main
75 #endif
77 using std::cerr;
78 using std::endl;
79 using std::cout;
81 std::vector<std::string> infiles;
82 std::string url;
84 namespace {
85 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
86 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
87 #ifdef USE_DEBUGGER
88 gnash::Debugger& debugger = gnash::Debugger::getDefaultInstance();
89 #endif
92 static void
93 usage()
95 std::vector<std::string> handlers;
96 gnash::media::MediaFactory::instance().listKeys(back_inserter(handlers));
98 std::vector<std::string> renderers;
99 boost::split(renderers, RENDERER_CONFIG,
100 boost::is_any_of(" "), boost::token_compress_on);
102 cout << _("Usage: gnash [options] movie_file.swf\n")
103 << "\n"
104 << _("Plays a SWF (Shockwave Flash) movie\n")
105 << _("Options:\n")
106 << "\n"
107 << _(" -h, --help Print this help and exit\n")
108 << _(" -V, --version Print version information and exit\n")
109 << _(" -s, --scale <factor> Scale the movie by the specified factor\n")
110 << _(" -d, --delay <num> Number of milliseconds to delay in main loop\n")
111 << _(" -v, --verbose Produce verbose output\n")
112 #if VERBOSE_ACTION
113 << _(" -va Be (very) verbose about action execution\n")
114 #endif
115 #if VERBOSE_PARSE
116 << _(" -vp Be (very) verbose about parsing\n")
117 #endif
118 << _(" -A <file> Audio dump file (wave format)\n")
119 << _(" --hwaccel <none|vaapi|xv> Hardware Video Accelerator to use\n")
120 << _(" none|vaapi|xv|omap (default: none)\n")
121 << _(" -x, --xid <ID> X11 Window ID for display\n")
122 << _(" -w, --writelog Produce the disk based debug log\n")
123 << _(" -j, --width <width> Set window width\n")
124 << _(" -k, --height <height> Set window height\n")
125 << _(" -X, --x-pos <x-pos> Set window x position\n")
126 << _(" -Y, --y-pos <y-pos> Set window y position\n")
127 << _(" -1, --once Exit when/if movie reaches the last "
128 "frame\n")
129 << _(" -g, --debugger Turn on the SWF debugger\n")
130 << _(" -r, --render-mode <0|1|2|3>\n")
131 << _(" 0 disable rendering and sound\n")
132 << _(" 1 enable rendering, disable sound\n")
133 << _(" 2 enable sound, disable rendering\n")
134 << _(" 3 enable rendering and sound (default)\n")
135 << _(" -M, --media <") << boost::join(handlers, "|") << ">\n"
136 << _(" The media handler to use")
137 << " (default: " << handlers.front() << ")\n"
138 << _(" -R, --renderer <") << boost::join(renderers, "|") << ">\n"
139 << _(" The renderer to use")
140 << " (default: agg)\n"
141 << _(" -t, --timeout <sec> Exit after the specified number of "
142 "seconds\n")
143 << _(" -u, --real-url <url> Set \"real\" URL of the movie\n")
144 << _(" -U, --base-url <url> Set \"base\" URL for resolving relative "
145 "URLs\n")
146 << _(" -P, --param <param> Set parameter (e.g. "
147 "\"FlashVars=A=1&b=2\")\n")
148 << _(" -F, --fd <fd>:<fd> Filedescriptor to use for external "
149 "communications\n")
150 #ifdef GNASH_FPS_DEBUG
151 << _(" -f, --debug-fps <num> Print FPS every num seconds (float)\n")
152 #endif // def GNASH_FPS_DEBUG
154 << _(" --max-advances <num> Exit after specified number of frame "
155 "advances\n")
156 << _(" --fullscreen Start in fullscreen mode\n")
157 << _(" --hide-menubar Start without displaying the menu bar\n")
158 << _(" --screenshot <list> List of frames to save as screenshots\n")
159 << _(" --screenshot-file <file> Filename pattern for screenshot images.\n")
160 << "\n"
161 << _("Keys:\n")
162 << "\n"
163 << _(" CTRL-Q, CTRL-W Quit\n")
164 << _(" CTRL-F Toggle fullscreen\n")
165 << _(" CTRL-P Toggle pause\n")
166 << _(" CTRL-R Restart the movie\n")
167 << _(" CTRL-O Take a screenshot\n")
168 << _(" CTRL-L Force immediate redraw\n")
169 << endl;
172 static void
173 version_and_copyright()
175 cout << "Gnash " << VERSION << endl
176 << endl
177 << _("Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 "
178 "Free Software Foundation, Inc.\n"
179 "Gnash comes with NO WARRANTY, to the extent permitted "
180 "by law.\nYou may redistribute copies of Gnash under the "
181 "terms of the GNU General\nPublic License. For more "
182 "information, see the file named COPYING.\n") << endl;
185 static void
186 build_options()
188 cout << _("Build options ") << VERSION << endl
189 << _(" Renderers: ") << RENDERER_CONFIG << endl
190 << _(" Hardware Acceleration: ") << HWACCEL_CONFIG << endl
191 << _(" GUI: ") << GUI_CONFIG << endl
192 << _(" Media handlers: ") << MEDIA_CONFIG << endl
194 << _(" Configured with: ") << CONFIG_CONFIG << endl
195 << _(" CXXFLAGS: ") << CXXFLAGS << endl
196 << " Version: " << BRANCH_NICK << ":" << BRANCH_REVNO << endl;
199 static void
200 parseCommandLine(int argc, char* argv[], gnash::Player& player)
203 const Arg_parser::Option opts[] =
205 { 'h', "help", Arg_parser::no },
206 { 'v', "verbose", Arg_parser::no },
207 { 'a', 0, Arg_parser::no },
208 { 'p', 0, Arg_parser::no },
209 { 's', "scale", Arg_parser::yes },
210 { 256, "max-advances", Arg_parser::yes },
211 { 257, "fullscreen", Arg_parser::no },
212 { 258, "hide-menubar", Arg_parser::no },
213 { 'd', "delay", Arg_parser::yes },
214 { 'x', "xid", Arg_parser::yes },
215 { 'R', "renderer", Arg_parser::yes },
216 { 'M', "media", Arg_parser::yes },
217 { 'r', "render-mode", Arg_parser::yes },
218 { 't', "timeout", Arg_parser::yes },
219 { '1', "once", Arg_parser::no },
220 { 'w', "writelog", Arg_parser::no },
221 { 'j', "width", Arg_parser::yes },
222 { 'k', "height", Arg_parser::yes },
223 { 'X', "x-position", Arg_parser::yes },
224 { 'Y', "y-position", Arg_parser::yes },
225 { 'u', "real-url", Arg_parser::yes },
226 { 'P', "param", Arg_parser::yes },
227 { 'U', "base-url", Arg_parser::yes },
228 { 'g', "debugger", Arg_parser::no },
229 { 'V', "version", Arg_parser::no },
230 { 'f', "debug-fps", Arg_parser::yes },
231 { 'F', "fifo", Arg_parser::yes },
232 { 'A', "dump", Arg_parser::yes },
233 { 259, "screenshot", Arg_parser::yes },
234 { 260, "screenshot-file", Arg_parser::yes },
235 { 261, "hwaccel", Arg_parser::yes },
236 { 262, "flash-version", Arg_parser::no },
237 { 'D', 0, Arg_parser::yes }, // Handled in dump gui
238 { 0, 0, Arg_parser::no }
241 Arg_parser parser(argc, argv, opts);
242 if (!parser.error().empty()) {
243 cout << parser.error() << endl;
244 exit(EXIT_FAILURE);
247 bool renderflag = false;
248 bool plugin = false;
249 bool widthGiven = false, heightGiven = false;
250 bool xPosGiven = false, yPosGiven = false;
252 for (int i = 0; i < parser.arguments(); ++i) {
253 const int code = parser.code(i);
254 try {
255 switch (code) {
256 case 'h':
257 version_and_copyright();
258 usage ();
259 exit(EXIT_SUCCESS);
260 case 'v':
261 dbglogfile.setVerbosity();
262 // This happens once per 'v' flag
263 gnash::log_debug(_("Verbose output turned on"));
264 break;
265 case 'V':
266 version_and_copyright();
267 build_options();
268 exit(EXIT_SUCCESS);
269 case 'w':
270 rcfile.useWriteLog(true);
271 gnash::log_debug(_("Logging to disk enabled"));
272 break;
273 case 'a':
274 #if VERBOSE_ACTION
275 dbglogfile.setActionDump(true);
276 #else
277 gnash::log_error(_("No verbose actions; disabled at "
278 "compile time"));
279 #endif
280 break;
281 case 'p':
282 #if VERBOSE_PARSE
283 dbglogfile.setParserDump(true);
284 #else
285 gnash::log_error (_("No verbose parsing; disabled at "
286 "compile time"));
287 #endif
288 break;
289 case 256:
290 player.setMaxAdvances(parser.argument<unsigned long>(i));
291 break;
292 case 257:
293 player.setStartFullscreen(true);
294 break;
295 case 258:
296 player.hideMenu(true);
297 break;
298 case 's':
299 player.setScale(gnash::clamp<float>(
300 parser.argument<float>(i), 0.01f, 100.f));
301 break;
302 case 'd':
303 player.setDelay(parser.argument<long>(i));
304 break;
305 case 'u':
306 url = parser.argument(i);
307 gnash::log_debug (_("Setting root URL to %s"), url.c_str());
308 break;
309 case 'U':
310 // Set base URL
311 player.setBaseUrl(parser.argument(i));
312 gnash::log_debug (_("Setting base URL to %s"),
313 parser.argument(i));
314 break;
315 case 'F':
317 const std::string& fds = parser.argument(i);
318 fds.find(":");
319 int hostfd = 0, controlfd = 0;
320 hostfd = strtol(fds.substr(0, fds.find(":")).c_str(), NULL, 0);
321 std::string csub = fds.substr(fds.find(":")+1, fds.size());
322 controlfd = strtol(csub.c_str(), 0, 0);
323 gnash::log_debug(_("Host FD #%d, Control FD #%d\n"),
324 hostfd, controlfd);
325 if (hostfd < 0) {
326 cerr << boost::format(_("Invalid host communication "
327 "filedescriptor %d\n"))
328 % hostfd << endl;
329 exit(EXIT_FAILURE);
331 player.setHostFD (hostfd);
333 if (controlfd < 0) {
334 cerr << boost::format(_("Invalid control communication "
335 "filedescriptor %d\n")) % controlfd << endl;
336 exit(EXIT_FAILURE);
338 player.setControlFD (controlfd);
340 break;
341 case 'j':
342 widthGiven = true;
343 player.setWidth(parser.argument<long>(i));
344 gnash::log_debug(_("Setting width to %d"),
345 player.getWidth());
346 break;
347 case 'g':
348 #ifdef USE_DEBUGGER
349 gnash::log_debug(_("Setting debugger ON"));
350 debugger.enabled(true);
351 // debugger.startServer(&debugger);
352 debugger.console();
353 #else
354 gnash::log_error(_("No debugger; disabled at compile "
355 "time, -g is invalid"));
356 exit(EXIT_FAILURE);
357 #endif
358 break;
359 case 'k':
360 heightGiven = true;
361 player.setHeight(parser.argument<long>(i));
362 gnash::log_debug(_("Setting height to %d"),
363 player.getHeight());
364 break;
365 case 'X':
366 xPosGiven = true;
367 player.setXPosition ( parser.argument<int>(i));
368 gnash::log_debug (_("Setting x position to %d"),
369 player.getXPosition());
370 break;
371 case 'Y':
372 yPosGiven = true;
373 player.setYPosition(parser.argument<int>(i));
374 gnash::log_debug(_("Setting x position to %d"),
375 player.getYPosition());
376 break;
377 case 'x':
378 plugin = true;
379 player.setWindowId(parser.argument<long>(i));
380 break;
381 case '1':
382 player.setDoLoop(false);
383 break;
384 // See if the hardware video decoder was specified
385 case 261:
386 switch (parser.argument<char>(i)) {
387 case 'v':
388 player.setHWAccel("vaapi");
389 break;
390 case 'x':
391 player.setHWAccel("xv");
392 break;
393 case 'n':
394 default:
395 player.setHWAccel("none");
396 break;
398 break;
399 case 262:
400 cout << rcfile.getFlashVersionString() << endl;
401 exit(EXIT_SUCCESS);
402 break;
403 case 'M':
404 player.setMedia(parser.argument(i));
405 break;
406 case 'R':
407 player.setRenderer(parser.argument(i));
408 break;
409 case 'r':
410 renderflag = true;
411 switch (parser.argument<char>(i)) {
412 case '0':
413 // Disable both
414 player.setDoRender(false);
415 player.setDoSound(false);
416 break;
417 case '1':
418 // Enable rendering, disable sound
419 player.setDoRender(true);
420 player.setDoSound(false);
421 break;
422 case '2':
423 // Enable sound, disable rendering
424 player.setDoRender(false);
425 player.setDoSound(true);
426 break;
427 case '3':
428 // Enable render & sound
429 player.setDoRender(true);
430 player.setDoSound(true);
431 break;
432 // See if a renderer was specified
433 case 'a':
434 // Enable AGG as the rendering backend
435 player.setRenderer("agg");
436 break;
437 case 'o':
438 // Enable OpenGL as the rendering backend
439 player.setRenderer("opengl");
440 break;
441 case 'c':
442 // Enable Cairo as the rendering backend
443 player.setRenderer("cairo");
444 break;
445 default:
446 gnash::log_error(_("ERROR: -r must be followed by "
447 "0, 1, 2 or 3 "));
448 break;
450 break;
451 case 't':
452 player.setExitTimeout(parser.argument<float>(i));
453 break;
454 case 'f':
455 #ifdef GNASH_FPS_DEBUG
456 player.setFpsPrintTime(parser.argument<float>(i));
457 #else
458 cout << _("FPS debugging disabled at compile time, -f "
459 "is invalid") << endl;
460 exit(EXIT_FAILURE);
461 #endif
462 break;
463 case 'P':
465 const std::string& param = parser.argument(i);
466 const size_t eq = param.find("=");
467 std::string name, value;
468 if (eq == std::string::npos) {
469 name = param;
470 value = "true";
471 } else {
472 name = param.substr(0, eq);
473 value = param.substr(eq + 1);
475 player.setParam(name, value);
476 break;
478 case 'A':
480 player.setAudioDumpfile(parser.argument(i));
481 break;
483 case 259:
484 // The player takes care of parsing the list.
485 player.setScreenShots(parser.argument(i));
486 break;
487 case 260:
488 player.setScreenShotFile(parser.argument(i));
489 break;
490 case 0:
491 infiles.push_back(parser.argument(i));
492 break;
495 catch (Arg_parser::ArgParserException &e) {
496 cerr << _("Error parsing command line options: ") << e.what()
497 << endl;
498 cerr << _("This is a Gnash bug.") << endl;
502 if (!renderflag) {
503 gnash::log_debug (_("No rendering flags specified, using rcfile"));
504 if (plugin) {
505 player.setDoSound(rcfile.usePluginSound());
507 else {
508 player.setDoSound(rcfile.useSound());
512 if (plugin && heightGiven && widthGiven && !player.getHeight() &&
513 !player.getWidth()) {
514 // We were given dimensions of 0x0 to render to (probably the plugin
515 // is playing an "invisible" movie. Disable video rendering.
516 player.setDoRender(false);
522 gnash_main(int argc, char *argv[])
525 std::ios::sync_with_stdio(false);
527 gnash::Player player;
529 // Enable native language support, i.e. internationalization
530 #ifdef ENABLE_NLS
531 std::setlocale (LC_ALL, "");
532 bindtextdomain (PACKAGE, LOCALEDIR);
533 textdomain (PACKAGE);
534 #endif
536 try {
537 parseCommandLine(argc, argv, player);
539 catch (const std::exception& ex) {
540 cerr << ex.what() << endl;
541 return EXIT_FAILURE;
543 catch (...) {
544 cerr << _("Exception thrown during parseCommandLine") << endl;
545 return EXIT_FAILURE;
548 // No file name was supplied
549 if (infiles.empty()) {
550 cerr << _("Error: no input file was specified. Exiting.") << endl;
551 usage();
552 return EXIT_FAILURE;
555 // We only expect GnashExceptions here. No others should be thrown!
556 try {
557 player.run(argc, argv, infiles.front(), url);
559 catch (const gnash::GnashException& ex) {
560 std::cerr << "Error: " << ex.what() << "\n";
561 return EXIT_FAILURE;
563 return EXIT_SUCCESS;