Example #1
0
/// \brief Run, used to open a new flash file. Using previous initialization
void
Player::run(int argc, char* argv[], const std::string& infile,
        const std::string& url)
{
    // Call this at run() time, so the caller has
    // a cache of setting some parameter before calling us...
    // (example: setDoSound(), setWindowId() etc.. ) 
    init_logfile();
   
    // gnash.cpp should check that a filename is supplied.
    assert (!infile.empty());

    _infile = infile;

    // Work out base url
    if (_baseurl.empty()) {
        if (!url.empty()) _baseurl = url;
        else if (infile == "-") _baseurl = URL("./").str();
        else _baseurl = infile;
    }

    // Set _root._url (either explicit of from infile)
    if (!url.empty()) {
        _url = url;
    } else {
        _url = infile;
    }

    // Parse player parameters. These are not passed to the SWF, but rather
    // control stage properties etc.
    // NOTE: it is intentional to force a trailing slash to "base" argument
    //       as it was tested that the "base" argument is always considered
    //       a directory!
    Params::const_iterator it = _params.find("base");
    const URL baseURL = (it == _params.end()) ? _baseurl :
                                               URL(it->second+"/", _baseurl);
    /// The RunResources should be populated before parsing.
    _runResources.reset(new RunResources());

    boost::shared_ptr<SWF::TagLoadersTable> loaders(new SWF::TagLoadersTable());
    addDefaultLoaders(*loaders);
    _runResources->setTagLoaders(loaders);

    std::auto_ptr<NamingPolicy> np(new IncrementalRename(_baseurl));

    /// The StreamProvider uses the actual URL of the loaded movie.
    boost::shared_ptr<StreamProvider> sp(new StreamProvider(_url, baseURL, np));
    _runResources->setStreamProvider(sp);

    // Set the Hardware video decoding resources. none, vaapi, omap
    _runResources->setHWAccelBackend(_hwaccel);
    
    // Set the Renderer resource, opengl, openvg, agg, or cairo
    _runResources->setRenderBackend(_renderer);

#ifdef USE_MEDIA
    _mediaHandler.reset(media::MediaFactory::instance().get(_media));
#endif
    
    if (!_media.empty() && !_mediaHandler.get()) {
        boost::format fmt =
            boost::format(_("Non-existent media handler %1% specified"))
            % _media;
        throw GnashException(fmt.str());
    }

    _runResources->setMediaHandler(_mediaHandler);
    
    init_sound();
    _runResources->setSoundHandler(_soundHandler);
    
    init_gui();

    // Initialize gui (we need argc/argv for this)
    // note that this will also initialize the renderer
    // which is *required* during movie loading
    if (!_gui->init(argc, &argv)) {
        throw GnashException("Could not initialize GUI");
    }

    // Parse querystring (before FlashVars, see
    // testsuite/misc-ming.all/FlashVarsTest*)
    setFlashVars(URL(_url).querystring());

    // Add FlashVars.
    Params::const_iterator fv = _params.find("flashvars");
    if (fv != _params.end()) {
        setFlashVars(fv->second);
    }

    // Load the actual movie.
    _movieDef = load_movie();
    if (!_movieDef) {
        throw GnashException("Could not load movie!");
    }

    // Get info about the width & height of the movie.
    const size_t movie_width = _movieDef->get_width_pixels();
    const size_t movie_height = _movieDef->get_height_pixels();

    if (! _width) {
        _width = static_cast<size_t>(movie_width * _scale);
    }
    if (! _height) {
        _height = static_cast<size_t>(movie_height * _scale);
    }

    if (!_width || !_height) {
        log_debug("Input movie has collapsed dimensions "
                  "%d/%d. Setting to 1/1 and going on.",
                  _width, _height);
        if (!_width) _width = 1;
        if (!_height) _height = 1;
    }

    // Register movie definition before creating the window
    _gui->setMovieDefinition(_movieDef.get());

    // Now that we know about movie size, create gui window.
    _gui->createWindow(_url.c_str(), _width, _height, _xPosition, _yPosition);

    { // we construct movie_root in its own scope, to be sure it's destroyed
      // (bringing down the MovieLoader) before we clear the MovieLibrary

    movie_root root(_gui->getClock(), *_runResources);
    
    _callbacksHandler.reset(new CallbacksHandler(*_gui, *this)); 
    
    // Register Player to receive events from the core (Mouse, Stage,
    // System etc)
    root.registerEventCallback(_callbacksHandler.get());
    
    // Register Player to receive FsCommand events from the core.
    root.registerFSCommandCallback(_callbacksHandler.get());

    // log_debug("Player Host FD #%d, Player Control FD #%d", _hostfd, _controlfd);
    
    // Set host requests fd (if any)
    if ( _hostfd != -1 ) {
        root.setHostFD(_hostfd);
    }
    
    if (_controlfd != -1) {
        root.setControlFD(_controlfd);        
    }

    _gui->setStage(&root);
    
    // When startStopped is true, stop here after the stage has been 
    // registered, but before the movie has started. Initial loading
    // and VM initialization have been done by this stage, but not
    // the complete parsing of the SWF. This is important because
    // the Gui accesses movie_root to get the sound_handler, but also
    // because the gui window should be properly set up by this point.
    RcInitFile& rcfile = RcInitFile::getDefaultInstance();

    if (rcfile.startStopped()) {
        _gui->stop();
    }

    // Start loader thread
    // NOTE: the loader thread might (in IMPORT tag parsing)
    //       create new movies and register them to the MovieLibrary.
    //       If MovieLibrary size exceeded, _movieDef might be
    //       destroyed prematurely. movie_root might actually be
    //       keeping it alive, as Gui might as well, but why relying
    //       on luck ? So we made sure to keep _movieDef by 
    //       intrusive_ptr...
    _movieDef->completeLoad();

    if (! _delay) {
        float fps = _movieDef->get_frame_rate();
        // log_debug("Movie Frame Rate is %g, adjusting delay", fps);
        // FIXME: this value is arbitrary, and will make any movie with
        // less than 12 frames eat up more of the cpu. It should probably
        // be a much lower value, like 2.
        if (fps > 12) {
            _delay = static_cast<int>(1000/fps);
        } else {
            // 10ms per heart beat
            _delay = 10;
        }
    }
    // This is the time between the main loop waking up and processing
    // network messages, external calls, and displaying the next frame.
    _gui->setInterval(_delay);

    if (_exitTimeout) {
      _gui->setTimeout(static_cast<unsigned int>(_exitTimeout * 1000));
    }

    if (!_windowID && _startFullscreen) {
        _gui->setFullscreen();
    }

    if (!_windowID && _hideMenu) {
        _gui->hideMenu();
    }
    
    // Now handle stage alignment and scale mode. This should be done after
    // the GUI is created, after its stage member is set, and after the
    // interface callbacks are registered.
    it = _params.find("salign");
    if (it != _params.end()) {
        log_debug("Setting align");
        const short align = stringToStageAlign(it->second);
        root.setStageAlignment(align);
    }

    it = _params.find("allowscriptaccess");
    if (it != _params.end()) {
        StringNoCaseEqual noCaseCompare;
        const std::string& str = it->second;
                
        movie_root::AllowScriptAccessMode mode = 
            movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
        
        if (noCaseCompare(str, "never")) {
            mode = movie_root::SCRIPT_ACCESS_NEVER;
        } 
        else if (noCaseCompare(str, "sameDomain")) {
            mode = movie_root::SCRIPT_ACCESS_SAME_DOMAIN;
        } 
        else if (noCaseCompare(str, "always")) {
            mode = movie_root::SCRIPT_ACCESS_ALWAYS;
        }
        log_debug("Setting allowscriptaccess to %s", mode);
        root.setAllowScriptAccess(mode);
    }

    it = _params.find("scale");
    if (it != _params.end()) {                
        StringNoCaseEqual noCaseCompare;
        const std::string& str = it->second;
        movie_root::ScaleMode mode = movie_root::SCALEMODE_SHOWALL;
        
        if (noCaseCompare(str, "noScale")) {
            mode = movie_root::SCALEMODE_NOSCALE;
        } 
        else if (noCaseCompare(str, "exactFit")) {
            mode = movie_root::SCALEMODE_EXACTFIT;
        }
        else if (noCaseCompare(str, "noBorder")) {
            mode = movie_root::SCALEMODE_NOBORDER;
        }

        log_debug("Setting scale mode");
            root.setStageScaleMode(mode);
    }

    // Set up screenshots. 
    if (!_screenshots.empty()) {
        std::istringstream is(_screenshots);
        std::string arg;
        bool last = false;
        ScreenShotter::FrameList v;

        while (std::getline(is, arg, ',')) {
            if (arg == "last") last = true;
            else try {
                const size_t frame = boost::lexical_cast<size_t>(arg);
                v.push_back(frame);
            }
            catch (const boost::bad_lexical_cast&) {}
        }

        // Use default if filename is empty.
        if (_screenshotFile.empty()) {
            URL url(_runResources->streamProvider().baseURL());
            std::string::size_type p = url.path().rfind('/');
            const std::string& name = (p == std::string::npos) ? url.path() :
                url.path().substr(p + 1);
            _screenshotFile = "screenshot-" + name + "-%f";
        }
        if (!last && v.empty()) return;
        
        std::auto_ptr<ScreenShotter> ss(new ScreenShotter(_screenshotFile,
                                                          _screenshotQuality));
        if (last) ss->lastFrame();
        ss->setFrames(v);
        _gui->setScreenShotter(ss);
    }

    _gui->run();

    log_debug("Main loop ended, cleaning up");

    }

    // Clean up the MovieLibrary so left-over SWFMovieDefinitions
    // get destroyed and join any loader thread
    MovieFactory::clear();

}