00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #ifdef __HAVE_MMSFLASH__
00034 
00035 #include "mmsflash/mmsflash.h"
00036 #include "mmsflash/mmsflashthread.h"
00037 
00038 extern "C" {
00039 #include <swfdec/swfdec.h>
00040 #include <swfdec/swfdec_buffer.h>
00041 }
00042 
00043 #include <cairo.h>
00044 #include <cairo-features.h>
00045 
00046 
00047 
00048 bool MMSFlash::swfdec_initialized = false;
00049 
00050 
00051 MMSFlash::MMSFlash(MMSWindow *window) {
00052     
00053     this->window = window;
00054     this->window->onHandleInput->connect(sigc::mem_fun(this,&MMSFlash::onHandleInput));
00055 
00056     
00057     this->ready                 = false;
00058     this->playing               = false;
00059     this->swfdec_player         = NULL;
00060     this->swfdec_rate           = 0;
00061     this->width                 = 0;
00062     this->height                = 0;
00063     this->flash_temp_surface    = NULL;
00064     this->loaderthread          = new MMSFlashThread(this, MMSFLASHTHREAD_MODE_LOADER, "MMSFlashLoaderThread");
00065     this->playerthread          = new MMSFlashThread(this, MMSFLASHTHREAD_MODE_PLAYER, "MMSFlashPlayerThread");
00066 
00067     if (!this->swfdec_initialized) {
00068         DEBUGMSG("MMSFLASH", "initializing swfdec");
00069         swfdec_init();
00070         DEBUGMSG("MMSFLASH", "swfdec initialized");
00071         this->swfdec_initialized = true;
00072     }
00073 }
00074 
00075 MMSFlash::~MMSFlash() {
00076     stopThreads();
00077     if (this->flash_temp_surface)
00078         delete this->flash_temp_surface;
00079     if (this->swfdec_player)
00080         g_object_unref(this->swfdec_player);
00081 }
00082 
00083 
00084 void MMSFlash::loader(bool &stop) {
00085 
00086     
00087     lock.lock();
00088     this->ready = false;
00089     this->playing = false;
00090 
00091     
00092     if (this->swfdec_player)
00093         g_object_unref(this->swfdec_player);
00094     DEBUGMSG("MMSFLASH", "creating swfdec player");
00095     this->swfdec_player = swfdec_player_new(NULL);
00096     if (!this->swfdec_player) {
00097         lock.unlock();
00098         DEBUGMSG("MMSFLASH", "Cannot get a new SwfdecPlayer object");
00099         return;
00100     }
00101 
00102     
00103     DEBUGMSG("MMSFLASH", "setting swfdec player url");
00104     SwfdecURL *url = swfdec_url_new(this->filename.c_str());
00105     swfdec_player_set_url((SwfdecPlayer*)this->swfdec_player, url);
00106     swfdec_url_free(url);
00107 
00108     
00109     DEBUGMSG("MMSFLASH", "checking swfdec player");
00110     swfdec_player_advance((SwfdecPlayer*)this->swfdec_player, 0);
00111     if (!swfdec_player_is_initialized((SwfdecPlayer*)this->swfdec_player)) {
00112         g_object_unref(this->swfdec_player);
00113         this->swfdec_player = NULL;
00114         lock.unlock();
00115         fprintf(stderr, "Cannot initialize SwfdecPlayer object\n");
00116         return;
00117     }
00118 
00119     
00120     this->swfdec_rate = swfdec_player_get_rate((SwfdecPlayer*)this->swfdec_player);
00121     DEBUGMSG("MMSFLASH", "frame rate = %d", this->swfdec_rate);
00122 
00123     
00124     guint ww,hh;
00125     swfdec_player_get_default_size((SwfdecPlayer*)this->swfdec_player, &ww, &hh);
00126     this->width=ww;
00127     this->height=hh;
00128     DEBUGMSG("MMSFLASH", "size = %d x %d", this->width, this->height);
00129 
00130     
00131     if (this->flash_temp_surface)
00132         delete flash_temp_surface;
00133     DEBUGMSG("MMSFLASH", "creating surface for cairo/swfdec");
00134     this->window->getLayer()->createSurface(&(this->flash_temp_surface), this->width, this->height, MMSFB_PF_ARGB, 0);
00135     if (!this->flash_temp_surface) {
00136         g_object_unref(this->swfdec_player);
00137         this->swfdec_player = NULL;
00138         lock.unlock();
00139         DEBUGMSG("MMSFLASH", "Cannot create temporary surface");
00140         return;
00141     }
00142     void *ptr;
00143     int pitch;
00144     this->flash_temp_surface->lock(MMSFB_LOCK_WRITE, &ptr, &pitch);
00145     this->flash_temp_surface->unlock();
00146     DEBUGMSG("MMSFLASH", "creating cairo surface");
00147     this->cairosurface = cairo_image_surface_create_for_data((unsigned char*)ptr, CAIRO_FORMAT_ARGB32,
00148                                                                 this->width, this->height, pitch);
00149     if (!this->cairosurface) {
00150         delete this->flash_temp_surface;
00151         this->flash_temp_surface = NULL;
00152         g_object_unref(this->swfdec_player);
00153         this->swfdec_player = NULL;
00154         lock.unlock();
00155         DEBUGMSG("MMSFLASH", "Cannot create cairo surface");
00156         return;
00157     }
00158     DEBUGMSG("MMSFLASH", "creating cairo object");
00159     this->cairo = cairo_create((cairo_surface_t *)cairosurface);
00160     cairo_surface_destroy((cairo_surface_t *)cairosurface);
00161     if (!this->cairo) {
00162         delete this->flash_temp_surface;
00163         this->flash_temp_surface = NULL;
00164         g_object_unref(this->swfdec_player);
00165         this->swfdec_player = NULL;
00166         lock.unlock();
00167         DEBUGMSG("MMSFLASH", "Cannot create cairo object");
00168         return;
00169     }
00170 
00171     
00172     this->ready = true;
00173 
00174     
00175     lock.unlock();
00176     DEBUGMSG("MMSFLASH", "loading finished");
00177 }
00178 
00179 void MMSFlash::player(bool &stop) {
00180     
00181     this->playing = false;
00182     while ((!stop)&&(!this->ready)) {
00183         msleep(50);
00184         if ((!this->ready)&&(!this->loaderthread->isRunning()))
00185             return;
00186     }
00187     this->playing = true;
00188 
00189     
00190     unsigned int sleep_time = (unsigned int)(1000 / this->swfdec_rate);
00191     while (!stop) {
00192         if (!this->window->isShown(true)) {
00193             
00194             msleep(500);
00195             continue;
00196         }
00197 
00198         
00199         lock.lock();
00200 
00201         
00202         unsigned int start_ts = getMTimeStamp();
00203 
00204         
00205         unsigned int bg = swfdec_player_get_background_color((SwfdecPlayer*)this->swfdec_player);
00206         this->flash_temp_surface->clear( (bg >> 16) & 0xff, (bg >> 8) & 0xff, bg & 0xff, bg >> 24 );
00207 
00208         
00209         DEBUGMSG("MMSFLASH", "rendering");
00210         swfdec_player_render((SwfdecPlayer*)this->swfdec_player, (cairo_t *)this->cairo);
00211         DEBUGMSG("MMSFLASH", "finished rendering");
00212 
00213         
00214         lock.unlock();
00215 
00216         
00217         this->window->getSurface()->stretchBlit(this->flash_temp_surface, NULL, NULL);
00218         this->window->flip();
00219 
00220         
00221         unsigned int end_ts = getMTimeStamp();
00222         end_ts = getMDiff(start_ts, end_ts);
00223         if (end_ts < sleep_time)
00224             msleep(sleep_time - end_ts);
00225     }
00226 
00227     
00228     this->playing = false;
00229 }
00230 
00231 void MMSFlash::stopThreads(void) {
00232     
00233     this->loaderthread->invokeStop();
00234     this->playerthread->invokeStop();
00235     this->loaderthread->waitUntilStopped();
00236     this->playerthread->waitUntilStopped();
00237 
00238     
00239     this->ready = false;
00240     this->playing = false;
00241 }
00242 
00243 unsigned int MMSFlash::mapKey(MMSKeySymbol key) {
00244     switch (key) {
00245     case MMSKEY_CURSOR_UP:
00246         return SWFDEC_KEY_UP;
00247     case MMSKEY_CURSOR_DOWN:
00248         return SWFDEC_KEY_DOWN;
00249     case MMSKEY_CURSOR_LEFT:
00250         return SWFDEC_KEY_LEFT;
00251     case MMSKEY_CURSOR_RIGHT:
00252         return SWFDEC_KEY_RIGHT;
00253     case MMSKEY_SPACE:
00254         return SWFDEC_KEY_SPACE;
00255     case MMSKEY_BACKSPACE:
00256         return SWFDEC_KEY_BACKSPACE;
00257     case MMSKEY_SLASH:
00258         return SWFDEC_KEY_SLASH;
00259     case MMSKEY_BACKSLASH:
00260         return SWFDEC_KEY_BACKSLASH;
00261     case MMSKEY_TAB:
00262         return SWFDEC_KEY_TAB;
00263     case MMSKEY_CLEAR:
00264         return SWFDEC_KEY_CLEAR;
00265     case MMSKEY_RETURN:
00266         return SWFDEC_KEY_ENTER;
00267     case MMSKEY_SHIFT:
00268         return SWFDEC_KEY_SHIFT;
00269     case MMSKEY_CONTROL:
00270         return SWFDEC_KEY_CONTROL;
00271     case MMSKEY_ALT:
00272         return SWFDEC_KEY_ALT;
00273     case MMSKEY_CAPS_LOCK:
00274         return SWFDEC_KEY_CAPS_LOCK;
00275     case MMSKEY_ESCAPE:
00276         return SWFDEC_KEY_ESCAPE;
00277     case MMSKEY_PAGE_UP:
00278         return SWFDEC_KEY_PAGE_UP;
00279     case MMSKEY_PAGE_DOWN:
00280         return SWFDEC_KEY_PAGE_DOWN;
00281     case MMSKEY_END:
00282         return SWFDEC_KEY_END;
00283     case MMSKEY_HOME:
00284         return SWFDEC_KEY_HOME;
00285     case MMSKEY_INSERT:
00286         return SWFDEC_KEY_INSERT;
00287     case MMSKEY_DELETE:
00288         return SWFDEC_KEY_DELETE;
00289     case MMSKEY_HELP:
00290         return SWFDEC_KEY_HELP;
00291     case MMSKEY_0:
00292         return SWFDEC_KEY_0;
00293     case MMSKEY_1:
00294         return SWFDEC_KEY_1;
00295     case MMSKEY_2:
00296         return SWFDEC_KEY_2;
00297     case MMSKEY_3:
00298         return SWFDEC_KEY_3;
00299     case MMSKEY_4:
00300         return SWFDEC_KEY_4;
00301     case MMSKEY_5:
00302         return SWFDEC_KEY_5;
00303     case MMSKEY_6:
00304         return SWFDEC_KEY_6;
00305     case MMSKEY_7:
00306         return SWFDEC_KEY_7;
00307     case MMSKEY_8:
00308         return SWFDEC_KEY_8;
00309     case MMSKEY_9:
00310         return SWFDEC_KEY_9;
00311     case MMSKEY_CAPITAL_A:
00312     case MMSKEY_SMALL_A:
00313         return SWFDEC_KEY_A;
00314     case MMSKEY_CAPITAL_B:
00315     case MMSKEY_SMALL_B:
00316         return SWFDEC_KEY_B;
00317     case MMSKEY_CAPITAL_C:
00318     case MMSKEY_SMALL_C:
00319         return SWFDEC_KEY_C;
00320     case MMSKEY_CAPITAL_D:
00321     case MMSKEY_SMALL_D:
00322         return SWFDEC_KEY_D;
00323     case MMSKEY_CAPITAL_E:
00324     case MMSKEY_SMALL_E:
00325         return SWFDEC_KEY_E;
00326     case MMSKEY_CAPITAL_F:
00327     case MMSKEY_SMALL_F:
00328         return SWFDEC_KEY_F;
00329     case MMSKEY_CAPITAL_G:
00330     case MMSKEY_SMALL_G:
00331         return SWFDEC_KEY_G;
00332     case MMSKEY_CAPITAL_H:
00333     case MMSKEY_SMALL_H:
00334         return SWFDEC_KEY_H;
00335     case MMSKEY_CAPITAL_I:
00336     case MMSKEY_SMALL_I:
00337         return SWFDEC_KEY_I;
00338     case MMSKEY_CAPITAL_J:
00339     case MMSKEY_SMALL_J:
00340         return SWFDEC_KEY_J;
00341     case MMSKEY_CAPITAL_K:
00342     case MMSKEY_SMALL_K:
00343         return SWFDEC_KEY_K;
00344     case MMSKEY_CAPITAL_L:
00345     case MMSKEY_SMALL_L:
00346         return SWFDEC_KEY_L;
00347     case MMSKEY_CAPITAL_M:
00348     case MMSKEY_SMALL_M:
00349         return SWFDEC_KEY_M;
00350     case MMSKEY_CAPITAL_N:
00351     case MMSKEY_SMALL_N:
00352         return SWFDEC_KEY_N;
00353     case MMSKEY_CAPITAL_O:
00354     case MMSKEY_SMALL_O:
00355         return SWFDEC_KEY_O;
00356     case MMSKEY_CAPITAL_P:
00357     case MMSKEY_SMALL_P:
00358         return SWFDEC_KEY_P;
00359     case MMSKEY_CAPITAL_Q:
00360     case MMSKEY_SMALL_Q:
00361         return SWFDEC_KEY_Q;
00362     case MMSKEY_CAPITAL_R:
00363     case MMSKEY_SMALL_R:
00364         return SWFDEC_KEY_R;
00365     case MMSKEY_CAPITAL_S:
00366     case MMSKEY_SMALL_S:
00367         return SWFDEC_KEY_S;
00368     case MMSKEY_CAPITAL_T:
00369     case MMSKEY_SMALL_T:
00370         return SWFDEC_KEY_T;
00371     case MMSKEY_CAPITAL_U:
00372     case MMSKEY_SMALL_U:
00373         return SWFDEC_KEY_U;
00374     case MMSKEY_CAPITAL_V:
00375     case MMSKEY_SMALL_V:
00376         return SWFDEC_KEY_V;
00377     case MMSKEY_CAPITAL_W:
00378     case MMSKEY_SMALL_W:
00379         return SWFDEC_KEY_W;
00380     case MMSKEY_CAPITAL_X:
00381     case MMSKEY_SMALL_X:
00382         return SWFDEC_KEY_X;
00383     case MMSKEY_CAPITAL_Y:
00384     case MMSKEY_SMALL_Y:
00385         return SWFDEC_KEY_Y;
00386     case MMSKEY_CAPITAL_Z:
00387     case MMSKEY_SMALL_Z:
00388         return SWFDEC_KEY_Z;
00389     case MMSKEY_F1:
00390         return SWFDEC_KEY_F1;
00391     case MMSKEY_F2:
00392         return SWFDEC_KEY_F2;
00393     case MMSKEY_F3:
00394         return SWFDEC_KEY_F3;
00395     case MMSKEY_F4:
00396         return SWFDEC_KEY_F4;
00397     case MMSKEY_F5:
00398         return SWFDEC_KEY_F5;
00399     case MMSKEY_F6:
00400         return SWFDEC_KEY_F6;
00401     case MMSKEY_F7:
00402         return SWFDEC_KEY_F7;
00403     case MMSKEY_F8:
00404         return SWFDEC_KEY_F8;
00405     case MMSKEY_F9:
00406         return SWFDEC_KEY_F9;
00407     case MMSKEY_F10:
00408         return SWFDEC_KEY_F10;
00409     case MMSKEY_F11:
00410         return SWFDEC_KEY_F11;
00411     case MMSKEY_F12:
00412         return SWFDEC_KEY_F12;
00413     case MMSKEY_NUM_LOCK:
00414         return SWFDEC_KEY_NUM_LOCK;
00415     case MMSKEY_SCROLL_LOCK:
00416         return SWFDEC_KEY_SCROLL_LOCK;
00417     case MMSKEY_SEMICOLON:
00418         return SWFDEC_KEY_SEMICOLON;
00419     case MMSKEY_EQUALS_SIGN:
00420         return SWFDEC_KEY_EQUAL;
00421     case MMSKEY_COMMA:
00422         return SWFDEC_KEY_COMMA;
00423     case MMSKEY_MINUS_SIGN:
00424         return SWFDEC_KEY_MINUS;
00425     case MMSKEY_PERIOD:
00426         return SWFDEC_KEY_DOT;
00427     case MMSKEY_GRAVE_ACCENT:
00428         return SWFDEC_KEY_GRAVE;
00429     case MMSKEY_APOSTROPHE:
00430         return SWFDEC_KEY_APOSTROPHE;
00431     default:
00432         return 0;
00433     }
00434 }
00435 
00436 bool MMSFlash::onHandleInput(MMSWindow *window, MMSInputEvent *input) {
00437     unsigned int    key;
00438 
00439     
00440     if (!this->swfdec_player)
00441         return false;
00442     if (!input)
00443         return false;
00444 
00445     
00446     lock.lock();
00447 
00448     
00449     int posx = input->posx;
00450     int posy = input->posy;
00451     if (input->type == MMSINPUTEVENTTYPE_BUTTONPRESS || input->type == MMSINPUTEVENTTYPE_BUTTONRELEASE || input->type == MMSINPUTEVENTTYPE_AXISMOTION) {
00452         MMSFBRectangle ig = window->getGeometry();
00453         if (this->width != ig.w)
00454             posx = ((posx * (this->width << 8)) / ig.w) >> 8;
00455         if (this->height != ig.h)
00456             posy = ((posy * (this->height << 8)) / ig.h) >> 8;
00457     }
00458 
00459     
00460     switch (input->type) {
00461     case MMSINPUTEVENTTYPE_KEYPRESS:
00462         if ((key = mapKey(input->key)))
00463             swfdec_player_key_press((SwfdecPlayer*)this->swfdec_player, key, 0);
00464         break;
00465     case MMSINPUTEVENTTYPE_KEYRELEASE:
00466         if ((key = mapKey(input->key)))
00467             swfdec_player_key_release((SwfdecPlayer*)this->swfdec_player, key, 0);
00468         break;
00469     case MMSINPUTEVENTTYPE_BUTTONPRESS:
00470         swfdec_player_mouse_press((SwfdecPlayer*)this->swfdec_player, posx, posy, 1);
00471         break;
00472     case MMSINPUTEVENTTYPE_BUTTONRELEASE:
00473         swfdec_player_mouse_release((SwfdecPlayer*)this->swfdec_player, posx, posy, 1);
00474         break;
00475     case MMSINPUTEVENTTYPE_AXISMOTION:
00476         swfdec_player_mouse_move((SwfdecPlayer*)this->swfdec_player, posx, posy);
00477         break;
00478     default:
00479         break;
00480     }
00481 
00482     
00483     lock.unlock();
00484 
00485     return true;
00486 }
00487 
00488 void MMSFlash::startPlaying(string filename) {
00489     
00490     if (!this->window)
00491         return;
00492 
00493     
00494     stopThreads();
00495 
00496     
00497     string prefix = filename.substr(0, 7);
00498     strToUpr(&prefix);
00499     if ((prefix != "FILE://")&&(prefix != "HTTP://"))
00500         if (filename.substr(0,1) != "/") {
00501             char path[1024];
00502             memset(path, 0, sizeof(path));
00503             this->filename = "file://" + (string)getcwd(path, 1024) + "/" + filename;
00504         }
00505         else
00506             this->filename = "file://" + filename;
00507     else
00508         this->filename = filename;
00509 
00510     
00511     this->loaderthread->start();
00512 
00513     
00514     this->playerthread->start();
00515 }
00516 
00517 bool MMSFlash::isReady() {
00518     
00519     while (!this->loaderthread->isStarted())
00520         msleep(50);
00521 
00522     
00523     while ((!this->ready)&&(this->loaderthread->isRunning()))
00524         msleep(50);
00525 
00526     return this->ready;
00527 }
00528 
00529 bool MMSFlash::isPlaying(bool wait) {
00530     if (wait)
00531         while ((!this->playing)&&(this->playerthread->isRunning()))
00532             msleep(50);
00533     return this->playing;
00534 }
00535 
00536 
00537 #endif