[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] /srv/bzr/gnash/rtmp r9671: minimal VM support for Cygnal,
From: |
rob |
Subject: |
[Gnash-commit] /srv/bzr/gnash/rtmp r9671: minimal VM support for Cygnal, blatanetly ripped off from processor.cpp for now. |
Date: |
Sat, 01 Nov 2008 08:48:03 -0600 |
User-agent: |
Bazaar (1.5) |
------------------------------------------------------------
revno: 9671
committer: address@hidden
branch nick: rtmp
timestamp: Sat 2008-11-01 08:48:03 -0600
message:
minimal VM support for Cygnal, blatanetly ripped off from processor.cpp for
now.
added:
cygnal/cvm.cpp
=== added file 'cygnal/cvm.cpp'
--- a/cygnal/cvm.cpp 1970-01-01 00:00:00 +0000
+++ b/cygnal/cvm.cpp 2008-11-01 14:48:03 +0000
@@ -0,0 +1,623 @@
+// processor.cpp: Flash movie processor (gprocessor command), for Gnash.
+//
+// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program 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 3 of the License, or
+// (at your option) any later version.
+//
+// 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 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include "NullSoundHandler.h"
+#ifdef USE_FFMPEG
+# include "ffmpeg/MediaHandlerFfmpeg.h"
+#elif defined(USE_GST)
+# include "gst/MediaHandlerGst.h"
+#endif
+
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <sys/time.h>
+#include <ctime>
+
+#ifdef ENABLE_NLS
+#include <locale>
+#endif
+
+#include "gettext.h"
+#include "ClockTime.h"
+#include "gnash.h"
+#include "movie_definition.h"
+#include "MovieClip.h"
+#include "movie_root.h"
+#include "log.h"
+#include "rc.h"
+#include "URL.h"
+#include "GnashException.h"
+#include "debugger.h"
+#include "VM.h"
+#include "noseek_fd_adapter.h"
+#include "ManualClock.h"
+#include "StringPredicates.h"
+#include "smart_ptr.h"
+#include "IOChannel.h" // for proper dtor call
+#include "GnashSleep.h" // for usleep comptibility.
+
+extern "C"{
+#ifdef HAVE_GETOPT_H
+ #include <getopt.h>
+#endif
+#ifndef __GNUC__
+ extern char *optarg;
+ extern int optopt;
+ extern int optind, getopt(int, char *const *, const char *);
+#endif
+}
+
+// How many seconds to wait for a frame advancement
+// before kicking the movie (forcing it to next frame)
+static const double waitforadvance = 5;
+
+// How many time do we allow for loop backs
+// (goto frame < current frame)
+static const size_t allowloopbacks = 10;
+
+// How many times to call 'advance' ?
+// If 0 number of advance is unlimited
+// (see other constraints)
+// TODO: add a command-line switch to control this
+static size_t limit_advances = 0;
+
+// How much time to sleep between advances ?
+// If set to -1 it will be computed based on FPS.
+static long int delay = 0;
+
+const char *GPROC_VERSION = "1.0";
+
+using namespace std;
+using namespace gnash;
+
+static void usage (const char *);
+
+namespace {
+gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
+gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
+#ifdef USE_DEBUGGER
+gnash::Debugger& debugger = gnash::Debugger::getDefaultInstance();
+#endif
+}
+
+struct movie_data
+{
+ gnash::movie_definition* m_movie;
+ std::string m_filename;
+};
+
+static boost::intrusive_ptr<gnash::movie_definition> play_movie(const char*
filename);
+
+static bool s_do_output = false;
+static bool s_stop_on_errors = true;
+
+// How many time do we allow to hit the end ?
+static size_t allowed_end_hits = 1;
+
+double lastAdvanceTimer;
+
+void
+resetLastAdvanceTimer()
+{
+ // clocktime::getTicks() returns milliseconds
+ lastAdvanceTimer = static_cast<double>(clocktime::getTicks()) / 1000.0;
+}
+
+double
+secondsSinceLastAdvance()
+{
+ // clocktime::getTicks() returns milliseconds
+ double now = static_cast<double>(clocktime::getTicks()) / 1000.0;
+ return ( now - lastAdvanceTimer);
+}
+
+// A flag which will be used to interrupt playback
+// by effect of a "quit" fscommand
+//
+static int quitrequested = false;
+
+class FsCommandExecutor: public movie_root::AbstractFsCallback {
+public:
+ void notify(const std::string& command, const std::string& args)
+ {
+ log_debug(_("fs_callback(%p): %s %s"), command, args);
+
+ StringNoCaseEqual ncasecomp;
+
+ if ( ncasecomp(command, "quit") ) quitrequested = true;
+ }
+};
+
+class EventCallback: public movie_root::AbstractIfaceCallback {
+public:
+ std::string call(const std::string& event, const std::string& arg)
+ {
+ log_debug(_("eventCallback: %s %s"), event, arg);
+
+ static bool mouseShown = true;
+
+ // These should return "true" if the mouse was visible before
+ // the call.
+ if ( event == "Mouse.hide" ) {
+ bool state = mouseShown;
+ mouseShown = false;
+ return state ? "true" : "false";
+ }
+
+ if ( event == "Mouse.show" ) {
+ bool state = mouseShown;
+ mouseShown = true;
+ return state ? "true" : "false" ;
+ }
+
+ // Some fake values for consistent test results.
+
+ if ( event == "System.capabilities.screenResolutionX" ) {
+ return "800";
+ }
+
+ if ( event == "System.capabilities.screenResolutionY" ) {
+ return "640";
+ }
+
+ if ( event == "System.capabilities.screenDPI" ) {
+ return "72";
+ }
+
+ if ( event == "System.capabilities.screenColor" ) {
+ return "Color";
+ }
+
+ if ( event == "System.capabilities.playerType" ) {
+ return "StandAlone";
+ }
+
+ return "";
+
+ }
+
+ bool yesNo(const std::string& /*query*/)
+ {
+ return true;
+ }
+};
+
+EventCallback eventCallback;
+FsCommandExecutor execFsCommand;
+
+int
+thread_main(int argc, char *argv[])
+{
+ /// Initialize gnash core library
+ gnashInit();
+
+ // Enable native language support, i.e. internationalization
+#ifdef ENABLE_NLS
+ std::setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif
+ int c;
+
+ // scan for the two main standard GNU options
+ for (c = 0; c < argc; c++) {
+ if (strcmp("--help", argv[c]) == 0) {
+ usage(argv[0]);
+ exit(0);
+ }
+ if (strcmp("--version", argv[c]) == 0) {
+ printf (_("Gnash gprocessor version: %s, Gnash version: %s\n"),
+ GPROC_VERSION, VERSION);
+ exit(0);
+ }
+ }
+
+ std::vector<const char*> infiles;
+
+ //RcInitFile& rcfile = RcInitFile::getDefaultInstance();
+ //rcfile.loadFiles();
+
+ if (rcfile.verbosityLevel() > 0) {
+ dbglogfile.setVerbosity(rcfile.verbosityLevel());
+ }
+
+ dbglogfile.setLogFilename(rcfile.getDebugLog());
+
+ if (rcfile.useWriteLog()) {
+ dbglogfile.setWriteDisk(true);
+ }
+
+ if (rcfile.useActionDump()) {
+ dbglogfile.setActionDump(true);
+ dbglogfile.setVerbosity();
+ }
+
+ if (rcfile.useParserDump()) {
+ dbglogfile.setParserDump(true);
+ dbglogfile.setVerbosity();
+ }
+
+ while ((c = getopt (argc, argv, ":hwvapr:gf:d:")) != -1) {
+ switch (c) {
+ case 'h':
+ usage (argv[0]);
+ dbglogfile.removeLog();
+ exit(0);
+ case 'w':
+ s_do_output = true;
+ break;
+ case 'v':
+ dbglogfile.setVerbosity();
+ log_debug (_("Verbose output turned on"));
+ break;
+ case 'g':
+#ifdef USE_DEBUGGER
+ debugger.enabled(true);
+ debugger.console();
+ log_debug (_("Setting debugger ON"));
+#else
+ log_error (_("The debugger has been disabled at configuration
time"));
+#endif
+ case 'a':
+#if VERBOSE_ACTION
+ dbglogfile.setActionDump(true);
+#else
+ log_error (_("Verbose actions disabled at compile time"));
+#endif
+ break;
+ case 'p':
+#if VERBOSE_PARSE
+ dbglogfile.setParserDump(true);
+#else
+ log_error (_("Verbose parsing disabled at compile time"));
+#endif
+ break;
+ case 'r':
+ allowed_end_hits = strtol(optarg, NULL, 0);
+ break;
+ case 'd':
+ delay = strtol(optarg, NULL, 0)*1000; // delay is in microseconds
+ // this will be recognized as a request to run at FPS speed
+ if ( delay < 0 ) delay = -1;
+ break;
+ case 'f':
+ limit_advances = strtol(optarg, NULL, 0);
+ break;
+ case ':':
+ fprintf(stderr, "Missing argument for switch ``%c''\n", optopt);
+ exit(1);
+ case '?':
+ default:
+ fprintf(stderr, "Unknown switch ``%c''\n", optopt);
+ exit(1);
+ }
+ }
+
+
+ // get the file name from the command line
+ while (optind < argc) {
+ infiles.push_back(argv[optind]);
+ optind++;
+ }
+
+ // No file names were supplied
+ if (infiles.size() == 0) {
+ printf("no input files\n");
+ usage(argv[0]);
+ dbglogfile.removeLog();
+ exit(1);
+ }
+
+#ifdef USE_FFMPEG
+ std::auto_ptr<media::MediaHandler> handler( new
gnash::media::MediaHandlerFfmpeg() );
+#elif defined(USE_GST)
+ std::auto_ptr<media::MediaHandler> handler( new
gnash::media::MediaHandlerGst() );
+#else
+ std::cerr << "Neigher SOUND_SDL nor SOUND_GST defined" << std::endl;
+ exit(1);
+#endif
+ gnash::media::MediaHandler::set(handler);
+
+ std::auto_ptr<media::sound_handler> soundHandler(new
media::NullSoundHandler());
+ gnash::set_sound_handler(soundHandler.get());
+
+ std::vector<movie_data> data;
+
+ if (infiles.size() > 1)
+ {
+ // this is due to set_base_url setting, only allowed once
+ fprintf(stderr, "Multiple input files not supported.\n");
+ usage(argv[0]);
+ dbglogfile.removeLog();
+ exit(1);
+ }
+
+ // Play through all the movies.
+ for (int i = 0, n = infiles.size(); i < n; i++) {
+
+ set_base_url(URL(infiles[i]));
+
+ boost::intrusive_ptr<gnash::movie_definition> m =
play_movie(infiles[i]);
+ if (m == NULL) {
+ if (s_stop_on_errors) {
+ // Fail.
+ fprintf(stderr, "error playing through movie '%s', quitting\n",
infiles[i]);
+ exit(1);
+ }
+ }
+
+ movie_data md;
+ md.m_movie = m.get();
+ md.m_filename = std::string(infiles[i]);
+ data.push_back(md);
+ }
+
+ // Signal core lib we're willing to quit.
+ gnash::clear();
+
+ return 0;
+}
+
+// Load the named movie, make an instance, and play it, virtually.
+// I.e. run through and render all the frames, even though we are not
+// actually doing any output (our output handlers are disabled).
+//
+// What this does is warm up all the cached data in the movie, so that
+// if we save that data for later, we won't have to tesselate shapes
+// or build font textures again.
+//
+// Return the movie definition.
+boost::intrusive_ptr<gnash::movie_definition>
+play_movie(const char* filename)
+{
+ boost::intrusive_ptr<gnash::movie_definition> md;
+ try
+ {
+ if ( ! strcmp(filename, "-") )
+ {
+ std::auto_ptr<IOChannel> in (
noseek_fd_adapter::make_stream(fileno(stdin)) );
+ md = gnash::create_movie(in, filename, false);
+ }
+ else
+ {
+ URL url(filename);
+ if ( url.protocol() == "file" )
+ {
+ const std::string& path = url.path();
+#if 1 // add the *directory* the movie was loaded from to the local sandbox
path
+ size_t lastSlash = path.find_last_of('/');
+ std::string dir = path.substr(0, lastSlash+1);
+ rcfile.addLocalSandboxPath(dir);
+ log_debug(_("%s appended to local sandboxes"), dir.c_str());
+#else // add the *file* to be loaded to the local sandbox path
+ rcfile.addLocalSandboxPath(path);
+ log_debug(_("%s appended to local sandboxes"), path.c_str());
+#endif
+ }
+ md = gnash::create_library_movie(url, NULL, false);
+ }
+ }
+ catch (GnashException& ge)
+ {
+ md = NULL;
+ fprintf(stderr, "%s\n", ge.what());
+ }
+ if (md == NULL) {
+ fprintf(stderr, "error: can't play movie '%s'\n", filename);
+ exit(1);
+ }
+
+ float fps = md->get_frame_rate();
+ long fpsDelay = long(1000000/fps);
+ long clockAdvance = fpsDelay/1000;
+ long localDelay = delay == -1 ? fpsDelay : delay; // microseconds
+
+ log_debug("Will sleep %ld microseconds between iterations - "
+ "fps is %g, clockAdvance is %lu", localDelay, fps, clockAdvance);
+
+ // Use a clock advanced at every iteration to match exact FPS speed.
+ ManualClock cl;
+ gnash::movie_root& m = VM::init(*md, cl).getRoot();
+
+ // Register processor to receive ActionScript events (Mouse, Stage
+ // System etc).
+ m.registerEventCallback(&eventCallback);
+ m.registerFSCommandCallback(&execFsCommand);
+
+ md->completeLoad();
+
+ std::auto_ptr<movie_instance> mi ( md->create_movie_instance() );
+
+ m.setRootMovie( mi.release() );
+ if ( quitrequested ) // setRootMovie would execute actions in first frame
+ {
+ quitrequested = false;
+ return md;
+ }
+
+ log_debug("iteration, timer: %lu, localDelay: %ld\n",
+ cl.elapsed(), localDelay);
+ gnashSleep(localDelay);
+
+ resetLastAdvanceTimer();
+ int kick_count = 0;
+ int stop_count=0;
+ size_t loop_back_count=0;
+ size_t latest_frame=0;
+ size_t end_hitcount=0;
+ size_t nadvances=0;
+ // Run through the movie.
+ for (;;) {
+ // @@ do we also have to run through all sprite frames
+ // as well?
+ //
+ // @@ also, ActionScript can rescale things
+ // dynamically -- we can't really do much about that I
+ // guess?
+ //
+ // @@ Maybe we should allow the user to specify some
+ // safety margin on scaled shapes.
+
+ size_t last_frame = m.get_current_frame();
+ //printf("advancing clock by %lu\n", clockAdvance);
+ cl.advance(clockAdvance);
+ m.advance();
+
+ if ( quitrequested )
+ {
+ quitrequested = false;
+ return md;
+ }
+
+ m.display(); // FIXME: for which reason are we calling display here ??
+ ++nadvances;
+ if ( limit_advances && nadvances >= limit_advances)
+ {
+ log_debug("exiting after %d advances", nadvances);
+ break;
+ }
+
+ size_t curr_frame = m.get_current_frame();
+
+ // We reached the end, done !
+ if (curr_frame >= md->get_frame_count() - 1 )
+ {
+ if ( allowed_end_hits && ++end_hitcount >= allowed_end_hits )
+ {
+ log_debug("exiting after %d"
+ " times last frame was reached", end_hitcount);
+ break;
+ }
+ }
+
+ // We didn't advance
+ if (curr_frame == last_frame)
+ {
+ // Max stop counts reached, kick it
+ if ( secondsSinceLastAdvance() > waitforadvance )
+ {
+ stop_count=0;
+
+ // Kick the movie.
+ if ( last_frame + 1 > md->get_frame_count() -1 )
+ {
+ fprintf(stderr, "Exiting after %g seconds in
STOP mode at last frame\n", waitforadvance);
+ break;
+ }
+ fprintf(stderr, "Kicking movie after %g seconds in STOP
mode, kick ct = %d\n", waitforadvance, kick_count);
+ fflush(stderr);
+ m.goto_frame(last_frame + 1);
+ m.set_play_state(gnash::MovieClip::PLAY);
+ kick_count++;
+
+ if (kick_count > 10) {
+ printf("movie is stalled; giving up on playing
it through.\n");
+ break;
+ }
+
+ resetLastAdvanceTimer(); // It's like we advanced
+ }
+ }
+
+ // We looped back. Skip ahead...
+ else if (m.get_current_frame() < last_frame)
+ {
+ if ( last_frame > latest_frame ) latest_frame = last_frame;
+ if ( ++loop_back_count > allowloopbacks )
+ {
+ log_debug("%d loop backs; jumping one-after "
+ "latest frame (%d)",
+ loop_back_count, latest_frame+1);
+ m.goto_frame(latest_frame + 1);
+ loop_back_count = 0;
+ }
+ }
+ else
+ {
+ kick_count = 0;
+ stop_count = 0;
+ resetLastAdvanceTimer();
+ }
+
+ log_debug("iteration, timer: %lu, localDelay: %ld\n",
+ cl.elapsed(), localDelay);
+ gnashSleep(localDelay);
+ }
+
+ return md;
+}
+
+static void
+usage (const char *name)
+{
+ printf(
+ _("gprocessor -- an SWF preprocessor for Gnash.\n"
+ "\n"
+ "usage: %s [options] <file>\n"
+ "\n"
+ "Preprocesses the given SWF movie files. Optionally write preprocessed
shape\n"
+ "and font data to cache files, so the associated SWF files can be
loaded\n"
+ "faster.\n"
+ "\n"
+ "%s%s%s%s"), name, _(
+ "options:\n"
+ "\n"
+ " --help(-h) Print this info.\n"
+ " --version Print the version numbers.\n"
+ " -w Write a .gsc file with preprocessed info, for each input
file.\n"
+ " -v Be verbose; i.e. print log messages to stdout\n"
+ ),
+#if VERBOSE_PARSE
+ _(" -vp Be verbose about movie parsing\n"),
+#else
+ "",
+#endif
+#if VERBOSE_ACTION
+ _(" -va Be verbose about ActionScript\n"),
+#else
+ "",
+#endif
+ _(
+ " -d [<ms>]\n"
+ " Milliseconds delay between advances (0 by default).\n"
+ " If '-1' the delay will be computed from the FPS.\n"
+ " -r <times> Allow the given number of complete runs.\n"
+ " Keep looping undefinitely if set to 0.\n"
+ " Default is 1 (end as soon as the last frame is
reached).\n"
+ " -f <frames> \n"
+ " Allow the given number of frame advancements.\n"
+ " Keep advancing untill any other stop condition\n"
+ " is encountered if set to 0 (default).\n")
+ );
+}
+
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+
+// Local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Gnash-commit] /srv/bzr/gnash/rtmp r9671: minimal VM support for Cygnal, blatanetly ripped off from processor.cpp for now.,
rob <=