1 // gnash.cpp: Main routine for top-level SWF player, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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.
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
22 #include "gnashconfig.h"
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>
34 #include <sys/types.h>
42 #include "rc.h" // for use of rcfile
44 #include "arg_parser.h"
45 #include "GnashNumeric.h" // for clamp
46 #include "GnashException.h"
48 #include "MediaHandler.h"
50 #ifdef HAVE_FFMPEG_AVCODEC_H
52 # include "ffmpeg/avcodec.h"
56 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
58 # include "libavcodec/avcodec.h"
64 # include "gst/gstversion.h"
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
74 # define gnash_main main
81 std::vector
<std::string
> infiles
;
85 gnash::LogFile
& dbglogfile
= gnash::LogFile::getDefaultInstance();
86 gnash::RcInitFile
& rcfile
= gnash::RcInitFile::getDefaultInstance();
88 gnash::Debugger
& debugger
= gnash::Debugger::getDefaultInstance();
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")
104 << _("Plays a SWF (Shockwave Flash) movie\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")
113 << _(" -va Be (very) verbose about action execution\n")
116 << _(" -vp Be (very) verbose about parsing\n")
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 "
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 "
143 << _(" -u, --real-url <url> Set \"real\" URL of the movie\n")
144 << _(" -U, --base-url <url> Set \"base\" URL for resolving relative "
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 "
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 "
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")
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")
173 version_and_copyright()
175 cout
<< "Gnash " << VERSION
<< 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
;
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
;
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
;
247 bool renderflag
= 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
);
257 version_and_copyright();
261 dbglogfile
.setVerbosity();
262 // This happens once per 'v' flag
263 gnash::log_debug(_("Verbose output turned on"));
266 version_and_copyright();
270 rcfile
.useWriteLog(true);
271 gnash::log_debug(_("Logging to disk enabled"));
275 dbglogfile
.setActionDump(true);
277 gnash::log_error(_("No verbose actions; disabled at "
283 dbglogfile
.setParserDump(true);
285 gnash::log_error (_("No verbose parsing; disabled at "
290 player
.setMaxAdvances(parser
.argument
<unsigned long>(i
));
293 player
.setStartFullscreen(true);
296 player
.hideMenu(true);
299 player
.setScale(gnash::clamp
<float>(
300 parser
.argument
<float>(i
), 0.01f
, 100.f
));
303 player
.setDelay(parser
.argument
<long>(i
));
306 url
= parser
.argument(i
);
307 gnash::log_debug (_("Setting root URL to %s"), url
.c_str());
311 player
.setBaseUrl(parser
.argument(i
));
312 gnash::log_debug (_("Setting base URL to %s"),
317 const std::string
& fds
= parser
.argument(i
);
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"),
326 cerr
<< boost::format(_("Invalid host communication "
327 "filedescriptor %d\n"))
331 player
.setHostFD (hostfd
);
334 cerr
<< boost::format(_("Invalid control communication "
335 "filedescriptor %d\n")) % controlfd
<< endl
;
338 player
.setControlFD (controlfd
);
343 player
.setWidth(parser
.argument
<long>(i
));
344 gnash::log_debug(_("Setting width to %d"),
349 gnash::log_debug(_("Setting debugger ON"));
350 debugger
.enabled(true);
351 // debugger.startServer(&debugger);
354 gnash::log_error(_("No debugger; disabled at compile "
355 "time, -g is invalid"));
361 player
.setHeight(parser
.argument
<long>(i
));
362 gnash::log_debug(_("Setting height to %d"),
367 player
.setXPosition ( parser
.argument
<int>(i
));
368 gnash::log_debug (_("Setting x position to %d"),
369 player
.getXPosition());
373 player
.setYPosition(parser
.argument
<int>(i
));
374 gnash::log_debug(_("Setting x position to %d"),
375 player
.getYPosition());
379 player
.setWindowId(parser
.argument
<long>(i
));
382 player
.setDoLoop(false);
384 // See if the hardware video decoder was specified
386 switch (parser
.argument
<char>(i
)) {
388 player
.setHWAccel("vaapi");
391 player
.setHWAccel("xv");
395 player
.setHWAccel("none");
400 cout
<< rcfile
.getFlashVersionString() << endl
;
404 player
.setMedia(parser
.argument(i
));
407 player
.setRenderer(parser
.argument(i
));
411 switch (parser
.argument
<char>(i
)) {
414 player
.setDoRender(false);
415 player
.setDoSound(false);
418 // Enable rendering, disable sound
419 player
.setDoRender(true);
420 player
.setDoSound(false);
423 // Enable sound, disable rendering
424 player
.setDoRender(false);
425 player
.setDoSound(true);
428 // Enable render & sound
429 player
.setDoRender(true);
430 player
.setDoSound(true);
432 // See if a renderer was specified
434 // Enable AGG as the rendering backend
435 player
.setRenderer("agg");
438 // Enable OpenGL as the rendering backend
439 player
.setRenderer("opengl");
442 // Enable Cairo as the rendering backend
443 player
.setRenderer("cairo");
446 gnash::log_error(_("ERROR: -r must be followed by "
452 player
.setExitTimeout(parser
.argument
<float>(i
));
455 #ifdef GNASH_FPS_DEBUG
456 player
.setFpsPrintTime(parser
.argument
<float>(i
));
458 cout
<< _("FPS debugging disabled at compile time, -f "
459 "is invalid") << endl
;
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
) {
472 name
= param
.substr(0, eq
);
473 value
= param
.substr(eq
+ 1);
475 player
.setParam(name
, value
);
480 player
.setAudioDumpfile(parser
.argument(i
));
484 // The player takes care of parsing the list.
485 player
.setScreenShots(parser
.argument(i
));
488 player
.setScreenShotFile(parser
.argument(i
));
491 infiles
.push_back(parser
.argument(i
));
495 catch (Arg_parser::ArgParserException
&e
) {
496 cerr
<< _("Error parsing command line options: ") << e
.what()
498 cerr
<< _("This is a Gnash bug.") << endl
;
503 gnash::log_debug (_("No rendering flags specified, using rcfile"));
505 player
.setDoSound(rcfile
.usePluginSound());
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
531 std::setlocale (LC_ALL
, "");
532 bindtextdomain (PACKAGE
, LOCALEDIR
);
533 textdomain (PACKAGE
);
537 parseCommandLine(argc
, argv
, player
);
539 catch (const std::exception
& ex
) {
540 cerr
<< ex
.what() << endl
;
544 cerr
<< _("Exception thrown during parseCommandLine") << endl
;
548 // No file name was supplied
549 if (infiles
.empty()) {
550 cerr
<< _("Error: no input file was specified. Exiting.") << endl
;
555 // We only expect GnashExceptions here. No others should be thrown!
557 player
.run(argc
, argv
, infiles
.front(), url
);
559 catch (const gnash::GnashException
& ex
) {
560 std::cerr
<< "Error: " << ex
.what() << "\n";