bool FBGui::run() { // GNASH_REPORT_FUNCTION; #ifdef USE_TSLIB int ts_loop_count = 0; #endif VirtualClock& timer = getClock(); int delay = 0; // let the GUI recompute the x/y scale factors to best fit the whole screen resize_view(_validbounds.width(), _validbounds.height()); float fps = getFPS(); // 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>(100000/fps); } else { // 10ms per heart beat delay = 10000; } // log_debug(_("Movie Frame Rate is %d, adjusting delay to %dms"), fps, // _interval * delay); // This loops endlessly at the frame rate while (!terminate_request) { // wait the "heartbeat" inteval. _interval is in milliseconds, // but gnashSleep() wants nanoseconds, so adjust by 1000. gnashSleep(_interval * 1000); // TODO: Do we need to check the real time slept or is it OK when we woke // up early because of some Linux signal sent to our process (and thus // "advance" faster than the "heartbeat" interval)? - Udo #ifdef USE_TSLIB ts_loop_count++; //increase loopcount #endif // check input devices checkForData(); // advance movie Gui::advance_movie(this); // check if we've reached a timeout if (_timeout && timer.elapsed() >= _timeout ) { break; } } return true; }
void SDL_sound_handler::initAudio() { // NOTE: we open and close the audio card for the sole purpose // of throwing an exception on error (unavailable audio // card). Normally we'd want to open the audio card only // when needed (it has a cost in number of wakeups). openAudio(); #ifdef WIN32 // SDL can hang on windows if SDL_CloseAudio() is called immediately // after SDL_OpenAudio(). It's evidently to do with threading, but // internal to SDL. This is a tacky solution, but it's only windows. gnashSleep(1); #endif closeAudio(); }
bool MouseDevice::command(unsigned char cmd, unsigned char *buf, int count) { // GNASH_REPORT_FUNCTION; int n; // flush input buffer char trash[16]; do { n = ::read(_fd, trash, sizeof trash); if (n > 0) log_debug(_("mouse_command: discarded %d bytes from input buffer"), n); } while (n > 0); // send command if ( -1 == ::write(_fd, &cmd, 1) ) { return false; } // read response (if any) while (count > 0) { gnashSleep(250*1000); // 250 ms inter-char timeout (simple method) // TODO: use select() instead n = read(_fd, buf, count); if (n <= 0) { return false; } count -= n; buf += n; } return true; } // command()
bool SharedMem::getSemaphore() { #ifndef __amigaos4__ // Struct for semctl union semun { int val; struct semid_ds* buf; unsigned short* array; }; #endif semun s; // We employ the textbook solution to the race condition during creation // and initialization of the semaphore: Create the semaphore with IPC_EXCL // so that for the first process, creation will succeed, but for any // concurrent process it will fail with EEXIST. Then, once the first // process is finished initializing the semaphore, semop is called (in our // case by calling lock()) which modifies semid_ds::otime, and the // concurrent process knows it can proceed with using the semaphore // (provided it obtains a lock.) _semid = ::semget(_shmkey, 1, IPC_CREAT | IPC_EXCL | 0600); if (_semid >= 0) { // Initialize semval. s.val = 1; int ret = ::semctl(_semid, 0, SETVAL, s); if (ret < 0) { log_error(_("Failed to set semaphore value: %1%"), strerror(errno)); return false; } // The first semop is executed immediately after this function returns. } else if (errno == EEXIST) { _semid = semget(_shmkey, 1, 0600); if (_semid < 0) { log_error(_("Failed to obtain nonexclusive semaphore for shared " "memory: %1%"), strerror(errno)); return false; } // Wait until semid_ds::sem_otime changes. semid_ds buf = semid_ds(); s.buf = &buf; const int maxRetries = 10; time_t uSecondsWait = 100; // 0.1ms bool ok = false; for(int i = 0; i < maxRetries; i++) { semctl(_semid, 0, IPC_STAT, s); if (buf.sem_otime != 0) { ok = true; break; } else { gnashSleep(uSecondsWait); } } if (!ok) { log_error(_("Timed out waiting for semaphore initialization.")); return false; } } else { log_error(_("Failed creating semaphore: %1%"), strerror(errno)); return false; } return true; }
// 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 std::string& filename, const RunResources& runResources) { boost::intrusive_ptr<gnash::movie_definition> md; URL url(filename); try { if (filename == "-") { std::auto_ptr<IOChannel> in ( noseek_fd_adapter::make_stream(fileno(stdin)) ); md = gnash::MovieFactory::makeMovie(in, filename, runResources, false); } else { 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::MovieFactory::makeMovie(url, runResources, NULL, false); } } catch (GnashException& ge) { md = NULL; fprintf(stderr, "%s\n", ge.what()); } if (md == NULL) { std::cerr << "error: can't play movie: "<< filename << std::endl; std::exit(EXIT_FAILURE); } 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(*md, cl, runResources); // Register processor to receive ActionScript events (Mouse, Stage // System etc). m.registerEventCallback(&eventCallback); m.registerFSCommandCallback(&execFsCommand); md->completeLoad(); m.init(md.get(), MovieClip::MovieVariables(), MovieClip::MovieVariables()); 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.getRootMovie().setPlayState(gnash::MovieClip::PLAYSTATE_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); } // Clear resources. MovieFactory::clear(); return md; }
bool DumpGui::run() { if ( _fileOutputFPS ) { _fileOutputAdvance = static_cast<int>(1000/_fileOutputFPS); } else { _fileOutputAdvance = _interval; _fileOutputFPS = static_cast<int>(1000/_fileOutputAdvance); } log_debug("DumpGui entering main loop with interval of %d ms", _interval); // heart-beat interval, in milliseconds // TODO: extract this value from the swf's FPS // by default and allow overriding it // unsigned int clockAdvance = _interval; const bool doDisplay = _fileStream.is_open(); terminate_request = false; _startTime = _clock.elapsed(); while (!terminate_request) { _clock.advance(clockAdvance); // advance movie now advanceMovie(doDisplay); if (_started) { writeSamples(); // Dump a video frame if it's time for it or no frame // was dumped yet size_t elapsed = _clock.elapsed(); if (!_framecount || (elapsed - _lastVideoFrameDump) >= _fileOutputAdvance) { writeFrame(); } // check if we've reached a timeout if (_timeout && _clock.elapsed() >= _timeout) { break; } } if (_sleepUS) gnashSleep(_sleepUS); if (!_started && !_startTrigger.empty()) { // Check whether to start std::string path; std::string var; if (parsePath(_startTrigger, path, var)) { movie_root& mr = *getStage(); const as_environment& env = mr.getRootMovie().get_environment(); as_object* o = findObject(env, path); if (o) { as_value val; o->get_member(getURI(mr.getVM(), "_ready"), &val); if (val.equals(true, 8)) { log_debug("Starting dump"); _started = true; _startTime = _clock.elapsed(); _lastVideoFrameDump = _startTime; } } } } } const boost::uint32_t total_time = _clock.elapsed() - _startTime; std::cout << "TIME=" << total_time << std::endl; std::cout << "FPS_ACTUAL=" << _fileOutputFPS << std::endl; // In this Gui, quit() does not exit, but it is necessary to catch the // last frame for screenshots. quit(); return true; }
bool DumpGui::run() { if ( _fileOutputFPS ) { _fileOutputAdvance = static_cast<int>(1000/_fileOutputFPS); } else { _fileOutputAdvance = _interval; _fileOutputFPS = static_cast<int>(1000/_fileOutputAdvance); } log_debug("DumpGui entering main loop with interval of %d ms", _interval); // heart-beat interval, in milliseconds // TODO: extract this value from the swf's FPS // by default and allow overriding it // unsigned int clockAdvance = _interval; VirtualClock& timer = getClock(); const bool doDisplay = _fileStream.is_open(); _terminate_request = false; while (!_terminate_request) { _manualClock.advance(clockAdvance); // advance movie now advanceMovie(doDisplay); writeSamples(); // Dump a video frame if it's time for it or no frame // was dumped yet size_t elapsed = timer.elapsed(); if ( ! _framecount || elapsed - _lastVideoFrameDump >= _fileOutputAdvance ) { writeFrame(); } // check if we've reached a timeout if (_timeout && timer.elapsed() >= _timeout ) { break; } if ( _sleepUS ) gnashSleep(_sleepUS); } boost::uint32_t total_time = timer.elapsed(); std::cout << "TIME=" << total_time << std::endl; std::cout << "FPS_ACTUAL=" << _fileOutputFPS << std::endl; // In this Gui, quit() does not exit, but it is necessary to catch the // last frame for screenshots. quit(); return true; }