gnash-commit
[Top][All Lists]
Advanced

[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:


reply via email to

[Prev in Thread] Current Thread [Next in Thread]