svvitch
digital signage player
D:/vs_workspace/switch_sf/src/svvitch/MainScene.cpp
Go to the documentation of this file.
00001 #include "MainScene.h"
00002 
00003 #include <algorithm>
00004 #include <Psapi.h>
00005 #include <Poco/DOM/DOMParser.h>
00006 #include <Poco/DOM/Document.h>
00007 #include <Poco/DOM/Element.h>
00008 #include <Poco/DOM/NodeList.h>
00009 #include <Poco/format.h>
00010 #include <Poco/DirectoryIterator.h>
00011 #include <Poco/DateTimeFormat.h>
00012 #include <Poco/DateTimeParser.h>
00013 #include <Poco/Exception.h>
00014 #include <Poco/string.h>
00015 #include <Poco/NumberFormatter.h>
00016 #include <Poco/NumberParser.h>
00017 #include <Poco/UnicodeConverter.h>
00018 #include <Poco/Util/XMLConfiguration.h>
00019 #include <Poco/LocalDateTime.h>
00020 #include <Poco/DateTimeFormatter.h>
00021 #include <Poco/Timespan.h>
00022 #include <Poco/Timezone.h>
00023 #include <Poco/FileStream.h>
00024 #include <Poco/URIStreamOpener.h>
00025 #include <Poco/URI.h>
00026 
00027 #include "ImageContent.h"
00028 #ifdef USE_FFMPEG
00029 #include "FFMovieContent.h"
00030 #endif
00031 #include "TextContent.h"
00032 #include "DSContent.h"
00033 #include "SlideTransition.h"
00034 #include "DissolveTransition.h"
00035 #include "Schedule.h"
00036 
00037 #include "Utils.h"
00038 
00039 #include "CaptureContent.h"
00040 #include "FlashContent.h"
00041 #include "IEContent.h"
00042 #include "MixContent.h"
00043 #ifdef USE_OPENCV
00044 #include "CvContent.h"
00045 #endif
00046 
00047 using Poco::XML::Document;
00048 using Poco::XML::Element;
00049 using Poco::XML::NodeList;
00050 
00051 
00052 MainScene::MainScene(Renderer& renderer): Scene(renderer),
00053     _workspace(NULL), _updatedWorkspace(NULL),
00054     activePrepareContent(this, &MainScene::prepareContent),
00055     activePrepareNextContent(this, &MainScene::prepareNextContent),
00056     activeSwitchContent(this, &MainScene::switchContent),
00057     activeCopyRemote(this, &MainScene::copyRemote),
00058     activeAddRemovableMedia(this, &MainScene::addRemovableMedia),
00059     _frame(0), _brightness(100), _preparing(false), _playCount(0),
00060     _doPrepareNext(false), _preparingNext(false), _doSwitchNext(false), _doSwitchPrepared(false), _transition(NULL),
00061     _description(NULL), _playlistName(NULL), _currentName(NULL), _nextPlaylistName(NULL), _nextName(NULL),
00062     _prepared(NULL), _preparedPlaylistName(NULL), _preparedName(NULL),
00063     _initializing(false), _running(false), _castLog(NULL),
00064     _removableIcon(NULL), _removableIconAlpha(0), _removableAlpha(0), _removableCover(0), _copySize(0), _currentCopySize(0), _copyProgress(0), _currentCopyProgress(0),
00065     _delayedCopy(false), _copyRemoteFiles(0), _interrupttedContent(NULL), _messageFrame(0)
00066 {
00067     initialize();
00068 }
00069 
00070 MainScene::‾MainScene() {
00071     _log.information("release contents");
00072     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00073     for (vector<Container*>::iterator it = _contents.begin(); it != _contents.end(); it = _contents.erase(it)) {
00074         SAFE_DELETE(*it);
00075     }
00076     _doSwitchPrepared = false;
00077     if (_castLog) {
00078         _castLog->close();
00079         SAFE_DELETE(_castLog);
00080     }
00081     execDelayedRelease();
00082     SAFE_DELETE(_prepared);
00083     SAFE_DELETE(_transition);
00084 
00085     SAFE_RELEASE(_playlistName);
00086     SAFE_RELEASE(_currentName);
00087     SAFE_RELEASE(_nextPlaylistName);
00088     SAFE_RELEASE(_nextName);
00089     SAFE_RELEASE(_preparedName);
00090     SAFE_RELEASE(_removableIcon);
00091 
00092     while (!_deletes.empty()) {
00093         string path = _deletes.front();
00094         _deletes.pop();
00095         try {
00096             File f(path);
00097             if (f.exists()) {
00098                 try {
00099                     f.remove();
00100                     _log.information(Poco::format("file delete(not used): %s", f.path()));
00101                 } catch (Poco::FileException& ex) {
00102                     _log.warning(Poco::format("failed delete: ", ex.displayText()));
00103                 }
00104             }
00105         } catch (...) {
00106         }
00107     }
00108     SAFE_DELETE(_workspace);
00109     preparedStanbyMedia();
00110     _log.information("*release main-scene");
00111 }
00112 
00113 void MainScene::execDelayedRelease() {
00114     Poco::DateTime now;
00115     Poco::Timestamp t = now.timestamp();
00116     int count = 0;
00117     vector<ContainerPtr> deletes;
00118     {
00119         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00120         for (vector<DelayedRelease>::iterator it = _delayReleases.begin(); it != _delayReleases.end();) {
00121             DelayedRelease dr = *it;
00122             if (t - dr.timestamp() > 2000000) {
00123                 if (!_transition || !_transition->use(dr.container())) {
00124                     deletes.push_back(dr.container());
00125                     it = _delayReleases.erase(it);
00126                     continue;
00127                 }
00128             }
00129             ++it;
00130         }
00131     }
00132     for (vector<ContainerPtr>::iterator it = deletes.begin(); it != deletes.end(); ++it) {
00133         SAFE_DELETE(*it);
00134         count++;
00135         Poco::Thread::sleep(0);
00136     }
00137     _log.information(Poco::format("delayed release: %d", count));
00138 }
00139 
00140 void MainScene::pushDelayedRelease(ContainerPtr c) {
00141     _delayReleases.push_back(DelayedRelease(c));
00142 }
00143 
00144 bool MainScene::initialize() {
00145 #ifdef USE_FFMPEG
00146     avcodec_register_all();
00147     avdevice_register_all();
00148     av_register_all();
00149 #endif
00150 
00151     _contents.clear();
00152     _contents.push_back(new Container(_renderer));
00153     _contents.push_back(new Container(_renderer)); // 2個のContainer
00154     _currentContent = -1;
00155 
00156     while (!_delayUpdateFiles.empty()) updateDelayedFiles();
00157 
00158     LPDIRECT3DDEVICE9 device = _renderer.get3DDevice();
00159     if (!device) return false;
00160     device->SetRenderState(D3DRS_LIGHTING, false);
00161     device->SetRenderState(D3DRS_ZENABLE, false);
00162     device->SetRenderState(D3DRS_ZWRITEENABLE, false);
00163     device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
00164     device->SetRenderState(D3DRS_ALPHATESTENABLE, false);
00165     device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
00166     device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
00167     device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);
00168 
00169     if (true) {
00170         // blend_nomal
00171         device->SetRenderState(D3DRS_BLENDOP,   D3DBLENDOP_ADD);
00172         device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
00173         device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
00174 
00175         device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
00176         device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
00177         device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
00178         device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
00179         device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
00180         device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
00181 
00182     } else {
00183         // blend_none
00184         device->SetRenderState(D3DRS_BLENDOP,   D3DBLENDOP_ADD);
00185         device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ONE);
00186         device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
00187     }
00188 
00189     setDescription(config().description);
00190 
00191     LPDIRECT3DTEXTURE9 texture = _renderer.createTexture("images/Crystal_Clear_device_usbpendrive_unmount.png");
00192     if (texture) {
00193         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00194         _removableIcon = texture;
00195     }
00196 
00197     if (config().outCastLog) {
00198         File logDir("logs/");
00199         if (!logDir.exists()) logDir.createDirectories();
00200     }
00201 
00202     WorkspacePtr workspace = new Workspace(config().workspaceFile);
00203     if (workspace->parse()) {
00204         _workspace = workspace;
00205         setStatus("workspace", _workspace->signature());
00206         preparedStanbyMedia();
00207         preparedFont(_workspace);
00208     } else {
00209         _log.warning("failed parse workspace");
00210     }
00211     setStatus("stage-name", config().name);
00212     setStatus("stage-description", config().description);
00213     _timeSecond = -1;
00214     _frame = 0;
00215     _brightness = config().brightness;
00216     _running = true;
00217     _startup = false;
00218     _autoStart = false;
00219     _log.information("*created main-scene");
00220     return true;
00221 }
00222 
00223 void MainScene::preparedFont(WorkspacePtr workspace) {
00224     if (workspace) {
00225         vector<string> fonts = workspace->getFonts();
00226         for (vector<string>::iterator it = fonts.begin(); it != fonts.end(); it++) {
00227             _renderer.addPrivateFontFile(*it);
00228         }
00229         _renderer.getPrivateFontFamilies(fonts);
00230         for (vector<string>::iterator it = fonts.begin(); it != fonts.end(); it++) {
00231             _log.information(Poco::format("font: %s", (*it)));
00232         }
00233     }
00234 }
00235 
00236 void MainScene::preparedStanbyMedia() {
00237     Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00238     for (map<string, ContainerPtr>::iterator it = _stanbyMedias.begin(); it != _stanbyMedias.end(); it = _stanbyMedias.erase(it)) {
00239         SAFE_DELETE(it->second);
00240     }
00241     //if (_workspace) {
00242         //for (int i = 0; i < _workspace->getMediaCount(); i++) {
00243         //  MediaItemPtr media = _workspace->getMedia(i);
00244             //if (media->stanby()) {
00245             //  ContainerPtr c = new Container(_renderer);
00246             //  if (prepareMedia(c, media, "")) {
00247             //      _stanbyMedias[media->id()] = c;
00248             //      _log.information(Poco::format("standby media: %s", media->id()));
00249             //  }
00250             //}
00251         //}
00252     //}
00253 }
00254 
00255 
00256 Workspace& MainScene::getWorkspace() {
00257     return *_workspace;
00258 }
00259 
00260 
00261 void MainScene::notifyKey(const int keycode, const bool shift, const bool ctrl) {
00262     _keycode = keycode;
00263     _shift = shift;
00264     _ctrl = ctrl;
00265     if (_currentContent >= 0) {
00266         _contents[_currentContent]->notifyKey(keycode, shift, ctrl);
00267     }
00268 }
00269 
00270 bool MainScene::prepareNextContent(const PlayParameters& params) {
00271     _preparingNext = true;
00272     ContainerPtr tmp = new Container(_renderer);
00273     {
00274         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00275         int next = (_currentContent + 1) % _contents.size();
00276         ContainerPtr  oldNextContainer = _contents[next];
00277         if (oldNextContainer) pushDelayedRelease(oldNextContainer);
00278         _contents[next] = tmp;
00279     }
00280 
00281     string playlistID = params.playlistID;
00282     int i = params.i;
00283 
00284     _log.information(Poco::format("prepare next content: %s-%d %s", playlistID, i, params.action));
00285     if (!params.action.empty()) {
00286         int jump = params.action.find_first_of("jump");
00287         if (jump == 0) {
00288             string s = Poco::trim(params.action.substr(4));
00289             int j = s.find("-");
00290             if (j != string::npos) {
00291                 playlistID = s.substr(0, j);
00292                 i = Poco::NumberParser::parse(s.substr(j + 1));
00293             } else {
00294                 playlistID = s;
00295                 i = 0;
00296             }
00297         } else if (params.action == "stop") {
00298             //int next = (_currentContent + 1) % _contents.size();
00299             //_contents[next]->initialize();
00300             _preparingNext = false;
00301             LPDIRECT3DTEXTURE9 oldNextPlaylistName = NULL;
00302             LPDIRECT3DTEXTURE9 oldNextName = NULL;
00303             {
00304                 Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00305                 oldNextPlaylistName = _nextPlaylistName;
00306                 _nextPlaylistName = NULL;
00307                 oldNextName = _nextName;
00308                 _nextName = NULL;
00309             }
00310             SAFE_RELEASE(oldNextPlaylistName);
00311             SAFE_RELEASE(oldNextName);
00312             removeStatus("next-playlist");
00313             removeStatus("next-content-id");
00314             removeStatus("next-content");
00315             return true;
00316         }
00317     }
00318 
00319     ContainerPtr c = new Container(_renderer);
00320     if (preparePlaylist(c, playlistID, i, true)) {
00321         string playlistName = "ready";
00322         string itemID = "";
00323         string itemName = "ready";
00324         {
00325             Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00326             PlayListPtr playlist = _workspace?_workspace->getPlaylist(playlistID):NULL;
00327             if (playlist && playlist->itemCount() > 0) {
00328                 playlistName = playlist->name();
00329                 i = i % playlist->itemCount();
00330                 PlayListItemPtr item = playlist->items().at(i);
00331                 if (item) {
00332                     _playNext.playlistID = playlistID;
00333                     _playNext.i = i;
00334                     _playNext.action = item->next();
00335                     _playNext.transition = item->transition();
00336                     itemID = item->media()->id();
00337                     itemName = item->media()->name();
00338                 }
00339             }
00340         }
00341 
00342         LPDIRECT3DTEXTURE9 t1 = _renderer.createTexturedText(L"", 14, 0xffffffff, 0xffeeeeff, 0, 0xff000000, 0, 0xff000000, playlistName);
00343         LPDIRECT3DTEXTURE9 t2 = _renderer.createTexturedText(L"", 14, 0xffffffff, 0xffeeeeff, 0, 0xff000000, 0, 0xff000000, itemName);
00344         LPDIRECT3DTEXTURE9 oldNextPlaylistName = NULL;
00345         LPDIRECT3DTEXTURE9 oldNextName = NULL;
00346         {
00347             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00348             int next = (_currentContent + 1) % _contents.size();
00349             ContainerPtr  oldNextContainer = _contents[next];
00350             if (oldNextContainer) pushDelayedRelease(oldNextContainer);
00351             _contents[next] = c;
00352             oldNextPlaylistName = _nextPlaylistName;
00353             _nextPlaylistName = t1;
00354             oldNextName = _nextName;
00355             _nextName = t2;
00356         }
00357         SAFE_RELEASE(oldNextPlaylistName);
00358         SAFE_RELEASE(oldNextName);
00359         _status["next-playlist-id"] = playlistID;
00360         _status["next-playlist"] = playlistName;
00361         _status["next-content-id"] = itemID;
00362         _status["next-content"] = itemName;
00363     } else {
00364         SAFE_DELETE(c);
00365         _log.warning(Poco::format("failed prepare: %s-%d", playlistID, i));
00366     }
00367     _preparingNext = false;
00368     execDelayedRelease();
00369     return true;
00370 }
00371 
00372 bool MainScene::stackPrepareContent(string& playlistID, int i) {
00373     PlayParameters args;
00374     args.playlistID = playlistID;
00375     args.i = i;
00376     {
00377         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00378         _prepareStack.push_back(args);
00379         if (_prepareStack.size() > 5) _prepareStack.erase(_prepareStack.begin());
00380     }
00381     _prepareStackTime = 0;
00382     return true;
00383 }
00384 
00385 const void MainScene::setDescription(const string& description) {
00386     if (!_description || config().description != description) {
00387         config().description = description;
00388         LPDIRECT3DTEXTURE9 t = _renderer.createTexturedText(L"", 30, 0xffffffff, 0xffeeeeff, 0, 0xff000000, 0, 0xff000000, description);
00389         LPDIRECT3DTEXTURE9 old = _description;
00390         {
00391             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00392             _description = t;
00393         }
00394         SAFE_RELEASE(old);
00395     }
00396 }
00397 
00398 const string MainScene::getPlaylistText(const string& playlistID) {
00399     Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00400     PlayListPtr playlist = _workspace?_workspace->getPlaylist(playlistID):NULL;
00401     if (playlist) {
00402         return playlist->text();
00403     }
00404     return "";
00405 }
00406 
00407 bool MainScene::setPlaylistText(const string& playlistID, const string& text) {
00408     Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00409     PlayListPtr playlist = _workspace?_workspace->getPlaylist(playlistID):NULL;
00410     if (playlist) {
00411         playlist->text(text);
00412         // _status["set-text"] = Poco::format("%s:%s", playlistID, text);
00413         return true;
00414     }
00415     return false;
00416 }
00417 
00418 void MainScene::setBrightness(int i) {
00419     config().brightness = i;
00420 }
00421 
00422 void MainScene::setAction(string& action) {
00423     _playCurrent.action = action;
00424 }
00425 
00426 void MainScene::setTransition(string& transition) {
00427     _playNext.transition = transition;
00428 }
00429 
00430 bool MainScene::prepareContent(const PlayParameters& params) {
00431     removeStatus("prepared-playlist-id");
00432     removeStatus("prepared-playlist");
00433     removeStatus("prepared-content");
00434     ContainerPtr oldPrepared = NULL;
00435     LPDIRECT3DTEXTURE9 oldPreparedPlaylistName = NULL;
00436     LPDIRECT3DTEXTURE9 oldPreparedName = NULL;
00437     {
00438         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00439         oldPrepared = _prepared;
00440         _prepared = NULL;
00441         oldPreparedPlaylistName = _preparedPlaylistName;
00442         _preparedPlaylistName = NULL;
00443         oldPreparedName = _preparedName;
00444         _preparedName = NULL;
00445     }
00446     SAFE_DELETE(oldPrepared);
00447     SAFE_RELEASE(oldPreparedPlaylistName);
00448     SAFE_RELEASE(oldPreparedName);
00449 
00450     ContainerPtr c = new Container(_renderer);
00451     if (preparePlaylist(c, params.playlistID, params.i, false)) {
00452         string playlistID = params.playlistID;
00453         string playlistName = "ready";
00454         string itemID = "";
00455         string itemName = "ready";
00456         {
00457             Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00458             PlayListPtr playlist = _workspace?_workspace->getPlaylist(playlistID):NULL;
00459             if (playlist && playlist->itemCount() > 0 && playlist->itemCount() > params.i) {
00460                 playlistName = playlist->name();
00461                 PlayListItemPtr item = playlist->items()[params.i];
00462                 itemID = item->media()->id();
00463                 itemName = item->media()->name();
00464                 _playPrepared.playlistID = playlistID;
00465                 _playPrepared.i = params.i;
00466                 _playPrepared.action = item->next();
00467                 _playPrepared.transition = item->transition();
00468             } else {
00469                 _log.warning(Poco::format("failed playlist item index: %s-%d", params.playlistID, params.i));
00470                 SAFE_DELETE(c);
00471                 return false;
00472             }
00473         }
00474 
00475         LPDIRECT3DTEXTURE9 t1 = _renderer.createTexturedText(L"", 14, 0xffffffff, 0xffeeeeff, 0, 0xff000000, 0, 0xff000000, playlistName);
00476         LPDIRECT3DTEXTURE9 t2 = _renderer.createTexturedText(L"", 14, 0xffffffff, 0xffeeeeff, 0, 0xff000000, 0, 0xff000000, itemName);
00477         {
00478             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
00479             _prepared = c;
00480             _preparedPlaylistName = t1;
00481             _preparedName = t2;
00482         }
00483         _status["prepared-playlist-id"] = playlistID;
00484         _status["prepared-playlist"] = playlistName;
00485         _status["prepared-content-id"] = itemID;
00486         _status["prepared-content"] = itemName;
00487         return true;
00488     } else {
00489         _log.warning(Poco::format("failed prepareContent: %s-%d", params.playlistID, params.i));
00490     }
00491     SAFE_DELETE(c);
00492     return false;
00493 }
00494 
00495 bool MainScene::preparePlaylist(ContainerPtr container, const string& playlistID, const int i, const bool round) {
00496     _log.information(Poco::format("prepare: %s-%d", playlistID, i));
00497     PlayListPtr playlist = NULL;
00498     {
00499         Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00500         playlist = _workspace?_workspace->getPlaylist(playlistID):NULL;
00501     }
00502     container->initialize();
00503     if (playlist && playlist->itemCount() > 0 && (round || playlist->itemCount() > i)) {
00504         int index = i;
00505         if (round) index = i % playlist->itemCount();
00506         PlayListItemPtr item = playlist->items().at(index);
00507         MediaItemPtr media = item->media();
00508         if (media) {
00509             return prepareMedia(container, media, playlist->text());
00510         } else {
00511             _log.warning("failed prepare next media, no media item");
00512         }
00513     } else {
00514         _log.warning(Poco::format("failed preparing item index: %s-%d", playlistID, i));
00515     }
00516     return false;
00517 }
00518 
00519 bool MainScene::prepareMedia(ContainerPtr container, MediaItemPtr media, const string& templatedText) {
00520     //_log.information(Poco::format("file: %d", media->fileCount()));
00521     float x = F(config().stageRect.left);
00522     float y = F(config().stageRect.top);
00523     float w = F(config().stageRect.right);
00524     float h = F(config().stageRect.bottom);
00525     switch (media->type()) {
00526         case MediaTypeMix:
00527             {
00528                 MixContentPtr mix = new MixContent(_renderer, config().splitType);
00529                 if (mix->open(media)) {
00530                     mix->setPosition(x, y);
00531                     mix->setBounds(w, h);
00532                     container->add(mix);
00533                 } else {
00534                     SAFE_DELETE(mix);
00535                 }
00536             }
00537             break;
00538 
00539         case MediaTypeImage:
00540             {
00541                 ImageContentPtr image = new ImageContent(_renderer, config().splitType);
00542                 if (image->open(media)) {
00543                     image->setPosition(x, y);
00544                     image->setBounds(w, h);
00545                     container->add(image);
00546                 } else {
00547                     SAFE_DELETE(image);
00548                 }
00549             }
00550             break;
00551 
00552         case MediaTypeMovie:
00553             {
00554                 for (vector<string>::iterator it = config().movieEngines.begin(); it < config().movieEngines.end(); it++) {
00555                     string engine = Poco::toLower(*it);
00556 #ifdef USE_FFMPEG
00557                     if (engine == "ffmpeg") {
00558                         FFMovieContentPtr movie = new FFMovieContent(_renderer, config().splitType);
00559                         if (movie->open(media)) {
00560                             movie->setPosition(x, y);
00561                             movie->setBounds(w, h);
00562                             // movie->set("aspect-mode", "fit");
00563                             container->add(movie);
00564                             break;
00565                         } else {
00566                             SAFE_DELETE(movie);
00567                         }
00568                     } else if (engine == "directshow") {
00569 #else
00570                     if (engine == "directshow") {
00571 #endif
00572                         DSContentPtr movie = new DSContent(_renderer, config().splitType);
00573                         if (movie->open(media)) {
00574                             movie->setPosition(x, y);
00575                             movie->setBounds(w, h);
00576                             // movie->set("aspect-mode", "fit");
00577                             container->add(movie);
00578                             break;
00579                         } else {
00580                             SAFE_DELETE(movie);
00581                         }
00582                     } else {
00583                         _log.warning(Poco::format("failed not found movie engine: %s", engine));
00584                     }
00585                 }
00586             }
00587             break;
00588 
00589         case MediaTypeText:
00590             break;
00591 
00592         case MediaTypeFlash:
00593             {
00594                 FlashContentPtr flash = new FlashContent(_renderer, config().splitType, x, y, w, h);
00595                 if (flash->open(media)) {
00596                     container->add(flash);
00597                 } else {
00598                     SAFE_DELETE(flash);
00599                 }
00600             }
00601             break;
00602 
00603         case MediaTypeBrowser:
00604             {
00605                 IEContentPtr ie = new IEContent(_renderer, config().splitType, x, y, w, h);
00606                 if (ie->open(media)) {
00607                     container->add(ie);
00608                 } else {
00609                     SAFE_DELETE(ie);
00610                 }
00611             }
00612             break;
00613 
00614         case MediaTypeCvCap:
00615             {
00616                 CaptureContentPtr cvcap = new CaptureContent(_renderer, config().splitType);
00617                 if (cvcap->open(media)) {
00618                     container->add(cvcap);
00619                 } else {
00620                     SAFE_DELETE(cvcap);
00621                 }
00622             }
00623             break;
00624 
00625 #ifdef USE_OPENCV
00626         case MediaTypeCv:
00627             {
00628                 CvContentPtr cv = new CvContent(_renderer, config().splitType);
00629                 if (cv->open(media)) {
00630                     container->add(cv);
00631                 } else {
00632                     SAFE_DELETE(cv);
00633                 }
00634             }
00635             break;
00636 #endif
00637         default:
00638             _log.warning("media type: unknown");
00639     }
00640     if (media->containsFileType(MediaTypeText)) {
00641         _log.information("contains text");
00642         vector<TextContentPtr> ref;
00643         int j = 0;
00644         int block = -1;
00645         for (int i = 0; i < media->fileCount(); i++) {
00646             MediaItemFile mif = media->files().at(i);
00647             if (mif.type() == MediaTypeText) {
00648                 TextContentPtr text = new TextContent(_renderer, config().splitType);
00649                 if (text->open(media, i)) {
00650                     if (block <= 0 || ref.empty()) {
00651                         // 実体モード
00652                         if (mif.file().empty()) {
00653                             _log.information(Poco::format("tempate text: %s", templatedText));
00654                             text->drawTexture(templatedText);
00655                         } else if (mif.file().find("$") != string::npos) {
00656                             int line = 0;
00657                             if (Poco::NumberParser::tryParse(mif.file().substr(1), line)) {
00658                                 string s = Poco::trim(templatedText);
00659                                 if (line > 0) {
00660                                     vector<string> texts;
00661                                     svvitch::split(s, '¥r', texts);
00662                                     if (texts.size() >= line) {
00663                                         s = texts[line - 1];
00664                                         text->drawTexture(s);
00665                                     } else {
00666                                         _log.warning(Poco::format("not enough lines: %u", texts.size()));
00667                                     }
00668                                 } else {
00669                                     text->drawTexture(s);
00670                                 }
00671                             } else {
00672                                 _log.warning(Poco::format("failed text URL: %s", mif.file()));
00673                             }
00674                         }
00675                         ref.push_back(text);
00676                     } else {
00677                         // 参照モード
00678                         text->setReference(ref.at(j++ % ref.size()));
00679                     }
00680                     container->add(text);
00681                 } else {
00682                     SAFE_DELETE(text);
00683                 }
00684             } else {
00685                 block++;
00686                 j = 0;
00687             }
00688         }
00689     }
00690     if (container->size() > 0) {
00691         _log.information(Poco::format("prepared: %s", media->name()));
00692         return true;
00693     } else {
00694         _log.warning("failed prepare next media");
00695         drawConsole(Poco::format("failed prepare next media: %s", media->id()));
00696     }
00697     return false;
00698 }
00699 
00700 bool MainScene::switchContent() {
00701     _doSwitchPrepared = true;
00702     while (_doSwitchPrepared) Poco::Thread::sleep(20);
00703     return true;
00704 }
00705 
00706 bool MainScene::addStock(const string& path, File src, bool copy) {
00707     try {
00708         File parent(Path(Path(config().stockRoot, path).toString()).makeParent());
00709         //_log.information(Poco::format("parent: %s", parent.path()));
00710         if (!parent.exists()) {
00711             parent.createDirectories();
00712             _log.information(Poco::format("create directory: %s", parent.path()));
00713         }
00714         File dst(Path(config().stockRoot, Path(path).toString()).toString());
00715         _log.information(Poco::format("add stock[%s] -> %s", path, dst.path()));
00716         if (dst.exists()) {
00717             dst.remove();
00718             _log.information(Poco::format("deleted already stock file: %s", dst.path()));
00719         }
00720         if (copy) {
00721             // copy mode
00722             _log.information("not supported copy mode");
00723             return false;
00724 
00725         } else {
00726             // move mode
00727             src.renameTo(dst.path());
00728         }
00729         _stock[path] = dst;
00730         return true;
00731     } catch (Poco::FileException& ex) {
00732         _log.warning(Poco::format("failed add stock file[%s]: %s", path, ex.displayText()));
00733     } catch (Poco::PathSyntaxException& ex) {
00734         _log.warning(Poco::format("failed add stock file[%s]: %s", path, ex.displayText()));
00735     }
00736     return false;
00737 }
00738 
00739 void MainScene::clearStock() {
00740     for (map<string, File>::const_iterator it = _stock.begin(); it != _stock.end();) {
00741         File f = it->second;
00742         if (f.exists()) {
00743             try {
00744                 f.remove();
00745             } catch (Poco::FileException& ex) {
00746                 _log.warning(Poco::format("failed not remove stock file: %s", it->first));
00747             }
00748         }
00749         it = _stock.erase(it);
00750     }
00751     _log.information("clear stock");
00752 }
00753 
00754 bool MainScene::flushStock() {
00755     Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
00756     _log.information("flush stock");
00757     for (map<string, File>::const_iterator it = _stock.begin(); it != _stock.end();) {
00758         File dst(Path(config().dataRoot, it->first).toString());
00759         _log.information(Poco::format("flush stock: %s", dst.path()));
00760         File parent(Path(dst.path()).makeParent());
00761         if (!parent.exists()) parent.createDirectories();
00762         File f = it->second;
00763         if (f.exists()) {
00764             if (!_deletes.empty()) {
00765                 queue<string> deletes;
00766                 while (!_deletes.empty()) {
00767                     string path = _deletes.front();
00768                     _deletes.pop();
00769                     if (dst.path() != path) {
00770                         deletes.push(path);
00771                     } else {
00772                         _log.information(Poco::format("clear delete: %s", path));                           
00773                         if (!_messages.empty()) _messages.pop();
00774                     }
00775                 }
00776                 _deletes = deletes;
00777             }
00778             try {
00779                 if (dst.exists()) dst.remove();
00780                 f.renameTo(dst.path());
00781             } catch (Poco::FileException& ex) {
00782                 _log.warning(Poco::format("failed not move stock file: %s <- %s", it->first, dst.path()));
00783                 File tempFile(dst.path() + ".part");
00784                 if (tempFile.exists()) {
00785                     removeDelayedUpdateFile(tempFile);
00786                     tempFile.remove();
00787                 }
00788                 try {
00789                     f.renameTo(tempFile.path());
00790                     addDelayedUpdateFile(tempFile);
00791                 } catch (Poco::FileException& ex1) {
00792                     //result = false;
00793                 }
00794             }
00795         } else {
00796             _log.warning(Poco::format("file not found: %s", f.path()));
00797         }
00798         it = _stock.erase(it);
00799     }
00800     return true;
00801 }
00802 
00803 void MainScene::addDelayedUpdateFile(File& file) {
00804     Poco::ScopedLock<Poco::FastMutex> lock(_delayedUpdateLock); 
00805     _delayUpdateFiles.push_back(file);
00806     Path path(file.path());
00807     setStatus("delayed-update", path.getFileName());
00808     _log.information(Poco::format("add delayed update: %s", file.path()));
00809 }
00810 
00811 void MainScene::removeDelayedUpdateFile(File& file) {
00812     Poco::ScopedLock<Poco::FastMutex> lock(_delayedUpdateLock); 
00813     vector<File>::iterator it = std::find(_delayUpdateFiles.begin(), _delayUpdateFiles.end(), file);
00814     if (it != _delayUpdateFiles.end()) {
00815         _delayUpdateFiles.erase(it);
00816         _log.information(Poco::format("remove delayed update: %s", file.path()));
00817     }
00818 }
00819 
00820 void MainScene::updateDelayedFiles() {
00821     if (_delayUpdateFiles.empty()) {
00822         removeStatus("delayed-update");
00823     } else {
00824         Poco::ScopedLock<Poco::FastMutex> lock(_delayedUpdateLock);
00825         for (vector<File>::iterator it = _delayUpdateFiles.begin(); it != _delayUpdateFiles.end();) {
00826             string src = (*it).path();
00827             int pos = src.size() - 5;
00828             if ((*it).exists() && pos >= 0 && src.substr(pos) == ".part") {
00829                 File dst(src.substr(0, pos));
00830                 Path path(dst.path());
00831                 try {
00832                     if (dst.exists()) {
00833                         dst.remove();
00834                         _log.warning(Poco::format("delayed updating file none: %s", src));
00835                     }
00836                     (*it).renameTo(dst.path());
00837                     _log.information(Poco::format("delayed file updated: %s", path.getFileName()));
00838                     drawConsole(Poco::format("delayed file updated: %s", path.getFileName()));
00839                     it = _delayUpdateFiles.erase(it);
00840                     continue;
00841                 } catch (Poco::FileException& ex) {
00842                     _log.warning(Poco::format("failed delayed file updating[%s]: %s", src, ex.displayText()));
00843                     setStatus("delayed-update", path.getFileName());
00844                 }
00845             } else {
00846                 _log.warning(Poco::format("not found delayed file: %s", src));
00847                 it = _delayUpdateFiles.erase(it);
00848                 continue;
00849             }
00850             it++;
00851         }
00852     }
00853 }
00854 
00855 bool MainScene::updateWorkspace() {
00856     _log.information("update workspace");
00857     if (_workspace && _workspace->checkUpdate()) {
00858         WorkspacePtr workspace = new Workspace(_workspace->file());
00859         if (workspace->parse()) {
00860             _log.information("updated workspace. repreparing next contents");
00861             _updatedWorkspace = workspace;
00862             preparedFont(workspace);
00863             removeStatus("workspace");
00864             return true;
00865         } else {
00866             _log.warning("failed update workspace.");
00867             SAFE_DELETE(workspace);
00868         }
00869     } else if (!_workspace) {
00870         WorkspacePtr workspace = new Workspace(config().workspaceFile);
00871         if (workspace->parse()) {
00872             _running = false;
00873             _workspace = workspace;
00874             setStatus("workspace", _workspace->signature());
00875             preparedStanbyMedia();
00876             preparedFont(_workspace);
00877             drawConsole("updated workspace");
00878             _frame = 0;
00879             _startup = false;
00880             _autoStart = false;
00881             _running = true;
00882             return true;
00883         } else {
00884             _log.warning("failed parse workspace");
00885             SAFE_DELETE(workspace);
00886         }
00887 
00888     } else {
00889         _log.information("there is no need for updates.");
00890         return true;
00891     }
00892     return false;
00893 }
00894 
00896 void MainScene::copyRemote(const string& remote) {
00897     {
00898         Poco::ScopedLock<Poco::FastMutex> lock(_delayedUpdateLock);
00899         if (!_copyingRemote.empty()) {
00900             _log.warning(Poco::format("already remote copying: %s", _copyingRemote));
00901             _copyingRemote = remote;
00902             _delayedCopy = true;
00903             return;
00904         }
00905         _copyingRemote = remote;
00906     }
00907     _log.information(Poco::format("remote copy: %s", remote));
00908     drawConsole("start remote copy");
00909     setRemoteStatus(remote, "delayed-update", "");
00910     setRemoteStatus(remote, "remote-copy", "1");
00911     File copyDir("copys");
00912     if (copyDir.exists()) {
00913         try {
00914             copyDir.remove(true);
00915         } catch (Poco::IOException& ex) {
00916             _log.warning(Poco::format("failed remove copy dir: %s", ex.displayText()));
00917         }
00918     }
00919     //bool result = copyRemoteDir(remote, "/");
00920 
00921     Path remoteWorkspace("tmp/workspace.xml");
00922     if (copyRemoteFile(remote, "/workspace.xml", remoteWorkspace)) {
00923         setRemoteStatus(remote, "remote-copy", "2");
00924         drawConsole("check remote workspace");
00925         vector<string> remoteFiles;
00926         try {
00927             Poco::XML::DOMParser parser;
00928             Document* doc = parser.parse(remoteWorkspace.toString());
00929             if (doc) {
00930                 Element* mediaList = doc->documentElement()->getChildElement("medialist");
00931                 if (mediaList) {
00932                     NodeList* items = mediaList->getElementsByTagName("item");
00933                     for (int i = 0; i < items->length(); i++) {
00934                         Element* e = (Element*)items->item(i);
00935 
00936                         NodeList* files = e->getElementsByTagName("*");
00937                         for (int j = 0; j < files->length(); j++) {
00938                             Element* e1 = (Element*)files->item(j);
00939                             string file = e1->innerText();
00940                             string params;
00941                             if (file.find("?") != string::npos) {
00942                                 params = file.substr(file.find("?") + 1);
00943                                 file = file.substr(0, file.find("?"));
00944                             }
00945                             if (file.find("switch-data:/") == 0) {
00946                                 file = file.substr(13);
00947                                 vector<string>::iterator it = std::find(remoteFiles.begin(), remoteFiles.end(), file);
00948                                 if (it == remoteFiles.end()) remoteFiles.push_back(file);
00949                             }
00950                         }
00951                         files->release();
00952                     }
00953                     items->release();
00954                 }
00955                 Element* fonts = doc->documentElement()->getChildElement("fonts");
00956                 if (fonts) {
00957                     NodeList* file = fonts->getElementsByTagName("file");
00958                     for (int i = 0; i < file->length(); i++) {
00959                         Element* e = (Element*)file->item(i);
00960                         string file = e->innerText();
00961                         if (file.find("switch-data:/") == 0) {
00962                             file = file.substr(13);
00963                         }
00964                         vector<string>::iterator it = std::find(remoteFiles.begin(), remoteFiles.end(), file);
00965                         if (it == remoteFiles.end()) remoteFiles.push_back(file);
00966                     }
00967                     file->release();
00968                 }
00969                 doc->release();
00970 
00971                 setRemoteStatus(remote, "remote-copy", "3");
00972                 if (!remoteFiles.empty()) {
00973                     int size = remoteFiles.size();
00974                     drawConsole(Poco::format("remote copy %d files...", size));
00975                     _copyRemoteFiles = size;
00976                     for (vector<string>::iterator it = remoteFiles.begin(); it != remoteFiles.end(); it++) {
00977                         Path out(config().dataRoot, Path(*it).toString());
00978                         _log.information(Poco::format("remote: %s", out.toString()));
00979                         setRemoteStatus(remote, "remote-copy", "3:" + out.getFileName());
00980                         if (copyRemoteFile(remote, *it, out, true)) {
00981                             drawConsole(Poco::format("remote copy: %d%%", 100 * (size - _copyRemoteFiles) / size));
00982                         }
00983                         _copyRemoteFiles--;
00984                     }
00985                 }
00986                 drawConsole("remote copy: 100%");
00987                 _copyRemoteFiles = 0;
00988                 setRemoteStatus(remote, "remote-copy", "4");
00989                 File dst(config().workspaceFile);
00990                 if (dst.exists()) dst.remove();
00991                 File src(remoteWorkspace);
00992                 src.renameTo(dst.path());
00993                 if (updateWorkspace()) {
00994                     setRemoteStatus(remote, "remote-copy", "5");
00995                 }
00996             } else {
00997                 _log.warning(Poco::format("failed parse: %s", remoteWorkspace.toString()));
00998             }
00999         } catch (Poco::Exception& ex) {
01000             _log.warning(ex.displayText());
01001         }
01002     }
01003     File tmp(remoteWorkspace);
01004     if (tmp.exists()) tmp.remove();
01005     setRemoteStatus(remote, "remote-copy", "10");
01006     drawConsole("remote copy finished");
01007 
01008     // 多重でremoteCopyが呼ばれていた場合は再実行
01009     bool delayedCopy = false;
01010     string copyingRemote;
01011     {
01012         Poco::ScopedLock<Poco::FastMutex> lock(_delayedUpdateLock);
01013         if (_delayedCopy) {
01014             delayedCopy = true;
01015             _delayedCopy = false;
01016         }
01017         copyingRemote = _copyingRemote;
01018         _copyingRemote.clear();
01019     }
01020     if (delayedCopy) {
01021         drawConsole("retry remote copy");
01022         copyRemote(copyingRemote);
01023     }
01024 }
01025 
01026 bool MainScene::copyRemoteFile(const string& remote, const string& path, Path& out, bool equalityCheck) {
01027     Poco::DateTime modified;
01028     Poco::File::FileSize size = 0;
01029     try {
01030         Poco::URI uri(Poco::format("%s/files?path=%s", remote, path));
01031         std::auto_ptr<std::istream> is(Poco::URIStreamOpener::defaultOpener().open(uri));
01032         string result;
01033         Poco::StreamCopier::copyToString(*is.get(), result);
01034         //_log.debug(Poco::format("result: %s", result));
01035         map<string, string> m;
01036         svvitch::parseJSON(result, m);
01037         svvitch::parseJSON(m["files"], m);
01038         //for (map<string, string>::iterator it = m.begin(); it != m.end(); it++) {
01039         //  _log.information(Poco::format("[%s]=%s", it->first, it->second));
01040         //}
01041         int tz = 0;
01042         Poco::DateTimeParser::parse(Poco::DateTimeFormat::SORTABLE_FORMAT, m["modified"], modified, tz);
01043         int tzd = Poco::Timezone::tzd();
01044         modified.makeUTC(tzd);
01045         Poco::UInt64 num = 0;
01046         Poco::NumberParser::tryParseUnsigned64(m["size"], num);
01047         size = num;
01048         //_log.information(Poco::format("modified: %s", Poco::DateTimeFormatter::format(modified, Poco::DateTimeFormat::SORTABLE_FORMAT)));
01049         File outFile(out);
01050         if (equalityCheck && outFile.exists()) {
01051             long modifiedDiff = abs((long)((modified.timestamp() - outFile.getLastModified())));
01052             if (size == outFile.getSize() && modifiedDiff <= 1000) {
01053                 // サイズと更新日時(秒精度)があっていれば同一ファイルとする
01054                 _log.information(Poco::format("remote file already exists: %s", path));
01055                 return false;
01056             }
01057         }
01058     } catch (Poco::SyntaxException& ex) {
01059         _log.warning(Poco::format("failed remote files(URI miss): %s", ex.displayText()));
01060     } catch (Poco::IOException& ex) {
01061         _log.warning(Poco::format("failed remote I/O: %s", ex.displayText()));
01062     } catch (Poco::Exception& ex) {
01063         _log.warning(Poco::format("failed remote files: %s", ex.displayText()));
01064     }
01065 
01066     File parent(Path(out.toString()).makeDirectory());
01067     if (!parent.exists()) parent.createDirectories();
01068     bool updating = false;
01069     File tempFile(out.toString() + ".part");
01070     if (tempFile.exists()) {
01071         try {
01072             tempFile.remove();
01073         } catch (Poco::IOException& ex) {
01074             _log.warning(Poco::format("failed remove temp dir: %s", ex.displayText()));
01075         }
01076     }
01077     try {
01078         Poco::URI uri(Poco::format("%s/download?path=%s", remote, path));
01079         std::auto_ptr<std::istream> is(Poco::URIStreamOpener::defaultOpener().open(uri));
01080         Poco::FileOutputStream os(tempFile.path());
01081         long readSize = Poco::StreamCopier::copyStream(*is.get(), os, 512 * 1024);
01082         os.close();
01083         tempFile.setLastModified(modified.timestamp());
01084         updating = true;
01085         File outFile(out);
01086         if (outFile.exists()) outFile.remove();
01087         tempFile.renameTo(out.toString());
01088         _log.information(Poco::format("remote file copy %s %Lu %ld", path, size, readSize));
01089         //drawConsole(Poco::format("remote copy: %s", out.getFileName()));
01090         return true;
01091     } catch (Poco::FileException& ex) {
01092         _log.warning(Poco::format("failed file: %s", ex.displayText()));
01093         if (updating && tempFile.exists()) {
01094             addDelayedUpdateFile(tempFile);
01095             setRemoteStatus(remote, "delayed-update", out.getFileName());
01096             drawConsole(Poco::format("delayed: %s", out.getFileName()));
01097             return true;
01098         }
01099     } catch (Poco::Exception& ex) {
01100         _log.warning(Poco::format("failed remote copy: %s", ex.displayText()));
01101     }
01102     return false;
01103 }
01104 
01105 void MainScene::setRemoteStatus(const string& remote, const string& name, const string& value) {
01106     try {
01107         Poco::URI uri(Poco::format("%s/set/status?n=%s&v=%s", remote, name, value));
01108         std::auto_ptr<std::istream> is(Poco::URIStreamOpener::defaultOpener().open(uri));
01109         //return true;
01110     } catch (Poco::Exception& ex) {
01111         _log.warning(Poco::format("failed remote status: %s", ex.displayText()));
01112     }
01113 }
01114 
01115 void MainScene::addRemovableMedia(const string& driveLetter) {
01116     {
01117         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01118         if (!_addRemovable.empty() && _addRemovable == driveLetter) {
01119             _log.information(Poco::format("processing same device, ignore notifier removable device[%s]", driveLetter));
01120             return;
01121         }
01122         _addRemovable = driveLetter;
01123     }
01124     _log.information(Poco::format("addRemovableMedia: %s", driveLetter));
01125 
01126     _copySize = 0;
01127     _copyProgress = 0;
01128     _currentCopyProgress = 0;
01129     _removableAlpha = 0.01f;
01130     _removableCover = 0;
01131 
01132     Path dst = Path(config().dataRoot.parent(), "removable-copys¥¥");
01133     File dir(dst);
01134     if (dir.exists()) dir.remove(true);
01135     int size = copyFiles(Poco::format("%s:¥¥switch-datas", driveLetter), "");
01136     _currentCopySize = 0;
01137     _copySize = size;
01138     copyFiles(Poco::format("%s:¥¥switch-datas", driveLetter), dst.toString());
01139     _renderer.ejectVolume(driveLetter);
01140 
01141     // Workspaceを仮生成
01142     WorkspacePtr workspace = new Workspace(Path(dst, "workspace.xml"));
01143     if (!workspace->parse()) {
01144         SAFE_DELETE(workspace);
01145         _removableAlpha = 0;
01146         _addRemovable.clear();
01147         return;
01148     }
01149     SAFE_DELETE(workspace);
01150     while (_currentCopyProgress < 100) {
01151 //      _log.information(Poco::format("size:%lu/%lu progress:%d%%", _currentCopySize, _copySize, _copyProgress));
01152         Sleep(100);
01153     }
01154 
01155     if (_startup) {
01156         _log.information("wait viewing removable cover");
01157         while (_removableCover < 1.0f) {
01158             Sleep(100);
01159         }
01160         _log.information("stop current playing");
01161         _running = false;
01162         Sleep(1000);
01163         {
01164             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01165             for (vector<Container*>::iterator it = _contents.begin(); it != _contents.end(); it++) {
01166                 (*it)->initialize();
01167             }
01168             _log.information("purge all contents");
01169             SAFE_RELEASE(_playlistName);
01170             SAFE_RELEASE(_currentName);
01171             SAFE_RELEASE(_nextPlaylistName);
01172             SAFE_RELEASE(_nextName);
01173             SAFE_RELEASE(_preparedPlaylistName);
01174             SAFE_RELEASE(_preparedName);
01175         }
01176         _status.clear();
01177         _playCurrent.action.clear();
01178         _playCurrent.transition.clear();
01179     } else {
01180         _running = false;
01181     }
01182     while (_removableAlpha > 0.0f) {
01183         Sleep(100);
01184     }
01185     _removableAlpha = 0;
01186     _running = true;
01187     _copySize = 0;
01188     _removableCover = 0.0f;
01189 
01190     _log.information("backup current data");
01191     File old(Path(config().dataRoot.parent(), "datas_old"));
01192     if (old.exists()) old.remove(true);
01193     File currentDataDir(config().dataRoot);
01194     if (currentDataDir.exists()) {
01195         currentDataDir.renameTo(old.path());
01196     }
01197     dir.renameTo(config().dataRoot.toString());
01198     if (updateWorkspace()) {
01199         _startup = false;
01200     }
01201     _addRemovable.clear();
01202 }
01203 
01204 int MainScene::copyFiles(const string& src, const string& dst) {
01205     int size = 0;
01206     Poco::DirectoryIterator it(src);
01207     Poco::DirectoryIterator end;
01208     while (it != end) {
01209         if (it->isDirectory()) {
01210             File dir(dst + it.path().getFileName() + "¥¥");
01211             if (!dir.exists()) dir.createDirectories();
01212             if (dst.empty()) {
01213                 size += copyFiles(it->path(), "");
01214             } else {
01215                 size += copyFiles(it->path(), dst + it.path().getFileName() + "¥¥");
01216             }
01217         } else {
01218             size += it->getSize();
01219             if (!dst.empty()) {
01220                 _log.information(Poco::format("copy: %s -> %s", it->path(), dst + it.path().getFileName()));
01221                 try {
01222                     File dir(dst);
01223                     if (!dir.exists()) dir.createDirectories();
01224                     Poco::FileInputStream is(it->path());
01225                     Poco::FileOutputStream os(dst + it.path().getFileName());
01226                     if (is.good() && os.good()) {
01227                         Poco::StreamCopier::copyStream(is, os);
01228                         _currentCopySize += it->getSize();
01229                     }
01230                     is.close();
01231                     os.close();
01232                 } catch (Poco::FileException& ex) {
01233                     _log.warning(ex.displayText());
01234                 }
01235             }
01236         }
01237         ++it;
01238     }
01239     return size;
01240 }
01241 
01242 
01243 
01244 void MainScene::process() {
01245     Poco::LocalDateTime now;
01246     switch (_keycode) {
01247     case 'Z':
01248         if (config().brightness > 0) config().brightness--;
01249         break;
01250     case 'X':
01251         if (config().brightness < 100) config().brightness++;
01252         break;
01253     }
01254     if (_brightness < config().brightness) {
01255         _brightness++;
01256     } else if (_brightness > config().brightness) {
01257         _brightness--;
01258     }
01259 
01260     // 割り込みコンテンツ
01261     string interruptted = getStatus("interruptted");
01262     if (interruptted != _interruptted) {
01263         _log.information(Poco::format("interruptted: %s", interruptted));
01264         if (interruptted.empty()) {
01265             if (_interrupttedContent) {
01266                 _interrupttedContent->stop();
01267                 _interrupttedContent = NULL;
01268             }
01269         } else {
01270             map<string, ContainerPtr>::iterator it = _stanbyMedias.find(interruptted);
01271             if (it != _stanbyMedias.end()) {
01272                 _interrupttedContent = it->second;
01273                 if (!_interrupttedContent->playing()) {
01274                     // 終了していたら再生しなおす
01275                     _interrupttedContent->play();
01276                 }
01277             }
01278         }
01279         _interruptted = interruptted;
01280     }
01281 
01282     // リムーバブルメディア検出
01283     if (_renderer.hasAddDrives()) {
01284         _removableIconAlpha += 0.01f;
01285         if (_removableIconAlpha >= 1.0f) _removableIconAlpha = 1;
01286     } else if (_addRemovable.empty()) {
01287         _removableIconAlpha -= 0.01f;
01288         if (_removableIconAlpha < 0.0f) _removableIconAlpha = 0.0f;
01289     }
01290 
01291     string drive = _renderer.popReadyDrive();
01292     if (!drive.empty()) {
01293         activeAddRemovableMedia(drive);
01294         //_log.information(Poco::format("volume device arrival: %s",drive));
01295     }
01296 
01297     if (_running && _removableAlpha > 0) {
01298         _removableAlpha += 0.01f;
01299         if (_removableAlpha >= 1.0f) _removableAlpha = 1;
01300     }
01301     if (_copySize > 0) {
01302         _copyProgress = 100 * F(_currentCopySize) / F(_copySize);
01303         if (_currentCopyProgress < _copyProgress) _currentCopyProgress++;
01304         if (_copyProgress >= 100 && _removableCover < 1.0f) {
01305             _removableCover += 0.01f;
01306             if (_removableCover > 1.0f) _removableCover = 1.0f;
01307         }
01308         if (!_running && _removableAlpha > 0.0f) {
01309             _removableAlpha -= 0.01f;
01310             if (_removableAlpha < 0.0f) _removableAlpha = 0.0f;
01311         }
01312     }
01313 
01314     // ワークスペースの更新チェック
01315     {
01316         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01317         if (_updatedWorkspace && !_preparingNext && _prepareStack.empty()) {
01318             Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
01319             if (_workspace) {
01320                 vector<string> olds = _workspace->existsFiles();
01321                 vector<string> newFiles = _updatedWorkspace->existsFiles();
01322                 for (vector<string>::const_iterator it = olds.begin(); it != olds.end(); it++) {
01323                     vector<string>::const_iterator i = std::find(newFiles.begin(), newFiles.end(), *it);
01324                     if (i == newFiles.end()) {
01325                         _deletes.push(*it);
01326                         _log.information(Poco::format("file not used: %s", (*it)));
01327                     }
01328                 }
01329             }
01330             SAFE_DELETE(_workspace);
01331             _workspace = _updatedWorkspace;
01332             _updatedWorkspace = NULL;
01333             if (!_status["next-content"].empty() && _playCurrent.action.find("stop") == 0) {
01334                 activePrepareNextContent(_playNext);
01335             }
01336             setStatus("workspace", _workspace->signature());
01337             drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + "workspace updated");
01338         }
01339     }
01340     // 旧ワークスペースの未使用ファイルを削除
01341     if (_frame % 50 == 0 && !_deletes.empty()) {
01342         Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
01343         string path = _deletes.front();
01344         _deletes.pop();
01345         if (path.find("http") != 0) {
01346             try {
01347                 File f(path);
01348                 if (f.exists()) {
01349                     try {
01350                         f.remove();
01351                         _log.information(Poco::format("file delete(not used): %s", f.path()));
01352                     } catch (Poco::FileException& ex) {
01353                         _log.warning(Poco::format("failed delete(not used): ", ex.displayText()));
01354                         _deletes.push(path);
01355                         if (_messages.size() <= 1) drawConsole(Poco::format("failed delete: %s", path));
01356                     }
01357                 }
01358             } catch (...) {
01359                 _log.warning(Poco::format("failed not delete(not used): %s", path));
01360             }
01361         }
01362     }
01363 
01364     if (!_running) return;
01365 
01366     if (!_startup && _frame > 100) {
01367         Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
01368         if (_workspace && _workspace->getPlaylistCount() > 0) {
01369             // playlistがある場合は最初のplaylistを自動スタートする
01370             PlayListPtr playlist = _workspace->getPlaylist(0);
01371             int item = 0;
01372 
01373             if (_workspace && _workspace->getScheduleCount() > 0) {
01374                 Poco::LocalDateTime now;
01375                 Poco::Timespan span(0, 0, 0, 10, 0);
01376                 for (int i = 0; i < _workspace->getScheduleCount(); i++) {
01377                     SchedulePtr schedule = _workspace->getSchedule(i);
01378                     if (schedule->matchPast(now + span)) {
01379                         string command = schedule->command();
01380                         string t = Poco::DateTimeFormatter::format(now, "%Y/%m/%d(%w) %H:%M:%S");
01381                         //_log.information(Poco::format("%s %s", t, command));
01382                         if (command.find("playlist ") == 0) {
01383                             string params = command.substr(9);
01384                             string playlistID = params;
01385                             item = 0;
01386                             if (params.find("-") != string::npos) {
01387                                 playlistID = params.substr(0, params.find("-"));
01388                                 if (!Poco::NumberParser::tryParse(params.substr(params.find("-") + 1), item)) {
01389                                     // failed parse item no
01390                                 }
01391                             }
01392                             playlist = _workspace->getPlaylist(playlistID);
01393                         } else if (command.find("next") == 0) {
01394                             item++;
01395 
01396                         } else if (command.find("brightness ") == 0) {
01397                             int brightness = -1;
01398                             if (Poco::NumberParser::tryParse(command.substr(10), brightness) && brightness >= 0 && brightness <= 100) {
01399                                 setBrightness(brightness);
01400                                 drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + Poco::format("set brightness %d", brightness));
01401                             }
01402                         }
01403                     }
01404                 }
01405             }
01406 
01407             if (playlist) {
01408                 PlayParameters args;
01409                 args.playlistID = playlist->id();
01410                 args.i = item;
01411                 _log.information(Poco::format("auto preparing: %s-%d", playlist->id(), item));
01412                 drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + Poco::format("preparing playlist %s-%d", playlist->id(), item));
01413                 activePrepareNextContent(args);
01414                 _autoStart = true;
01415                 _frame = 0;
01416                 _startup = true;
01417             }
01418         } else {
01419             if (_frame == 101) _log.warning("no playlist, no auto starting");
01420             // _frame = 0;
01421         }
01422 
01423     } else if (_startup) {
01424         _status["action"] = _playCurrent.action;
01425         _status["transition"] = _playNext.transition;
01426 
01427         {
01428             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01429             ContentPtr currentContent = NULL;
01430             if (_currentContent >= 0) currentContent = _contents[_currentContent]->get(0);
01431             for (vector<Container*>::iterator it = _contents.begin(); it != _contents.end(); it++) {
01432                 (*it)->process(_frame);
01433             }
01434 
01435             bool readyNext = !_status["next-content"].empty();
01436             if (currentContent) {
01437                 if (_playCurrent.action == "stop" || _playCurrent.action == "stop-prepared") {
01438                     // 停止系
01439 
01440                 } else if (_playCurrent.action == "wait-prepared") {
01441                     // 次のコンテンツが準備でき次第切替
01442                     if (readyNext && !_transition) {
01443                         // _log.information("wait prepared next content, prepared now.");
01444                         _doSwitchNext = true;
01445                     }
01446                 } else {
01447                     // コマンド指定が無ければ現在再生中のコンテンツの終了を待つ.準備できていれば切替
01448                     if (_contents[_currentContent]->finished() && readyNext && !_transition) {
01449                         // _log.information(Poco::format("content[%d] finished: ", _currentContent));
01450                         _doSwitchNext = true;
01451                     }
01452                 }
01453             } else if (_autoStart && readyNext && _frame > 200) {
01454                 _log.information("auto start content");
01455                 _doSwitchNext = true;
01456                 _autoStart = false;
01457             }
01458         }
01459 
01460         if (_doSwitchPrepared && !_preparingNext) {
01461             if (_prepared) {
01462                 {
01463                     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01464                     int next = (_currentContent + 1) % _contents.size();
01465                     ContainerPtr oldNextContainer = _contents[next];
01466                     if (oldNextContainer) pushDelayedRelease(oldNextContainer);
01467                     _contents[next] = _prepared;
01468                     _prepared = NULL;
01469                     LPDIRECT3DTEXTURE9 tmp = _nextPlaylistName;
01470                     _nextPlaylistName = _preparedPlaylistName;
01471                     _preparedPlaylistName = tmp;
01472                     tmp = _nextName;
01473                     _nextName = _preparedName;
01474                     _preparedName = tmp;
01475                 }
01476                 Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
01477                 PlayListPtr playlist = _workspace?_workspace->getPlaylist(_playPrepared.playlistID):NULL;
01478                 if (playlist && playlist->itemCount() > 0 && playlist->itemCount() > _playPrepared.i) {
01479                     PlayListItemPtr item = playlist->items()[_playPrepared.i];
01480                     if (item) {
01481                         _log.information(Poco::format("switch content: %s-%d: %s", _playPrepared.playlistID, _playPrepared.i, item->media()->name()));
01482                         {
01483                             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01484                             _playNext = _playPrepared;
01485                         }
01486                     }
01487                 } else {
01488                     _log.warning(Poco::format("not find playlist: %s-%d", _playPrepared.playlistID, _playPrepared.i));
01489                 }
01490                 _status["next-playlist-id"] = _status["prepared-playlist-id"];
01491                 _status["next-playlist"] = _status["prepared-playlist"];
01492                 _status["next-content-id"] = _status["prepared-content-id"];
01493                 _status["next-content"] = _status["prepared-content"];
01494                 LPDIRECT3DTEXTURE9 oldPreparedPlaylistName = NULL;
01495                 LPDIRECT3DTEXTURE9 oldPreparedName = NULL;
01496                 TransitionPtr oldTransition = NULL;
01497                 {
01498                     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01499                     oldPreparedPlaylistName = _preparedPlaylistName;
01500                     _preparedPlaylistName = NULL;
01501                     oldPreparedName = _preparedName;
01502                     _preparedName = NULL;
01503                     oldTransition = _transition;
01504                     _transition = NULL;
01505                 }
01506                 SAFE_RELEASE(oldPreparedPlaylistName);
01507                 SAFE_RELEASE(oldPreparedName);
01508                 SAFE_DELETE(oldTransition);
01509                 removeStatus("prepared-playlist-id");
01510                 removeStatus("prepared-playlist");
01511                 removeStatus("prepared-content");
01512                 _doSwitchNext = true;
01513 
01514             } else {
01515                 // 準備済みコンテンツが無い場合は次のコンテンツへ切替
01516                 int next = (_currentContent + 1) % _contents.size();
01517                 ContainerPtr tmp = _contents[next];
01518                 if (tmp && tmp->size() > 0) {
01519                     _log.information("switch next contents");
01520                     SAFE_DELETE(_transition);
01521                     _doSwitchNext = true;
01522                 }
01523             }
01524             _nextStack.clear();
01525             _doSwitchPrepared = false;
01526         }
01527 
01528         // bool prepareNext = false;
01529         if (_doSwitchNext && !_transition) {
01530             //_doSwitchNext = false;
01531             //if (_currentContent >= 0 && _contents[_currentContent]->useFastStop()) {
01532             if (_currentContent >= 0) {
01533                 _contents[_currentContent]->stop();
01534             }
01535             _playCurrent = _playNext;
01536             int next = (_currentContent + 1) % _contents.size();
01537             ContentPtr nextContent = _contents[next]->get(0);
01538             if (nextContent && !nextContent->opened().empty()) {
01539                 _doSwitchNext = false;
01540                 int oldCurrent = _currentContent;
01541                 _currentContent = next;
01542                 _contents[next]->play();
01543                 LPDIRECT3DTEXTURE9 oldPlaylistName = NULL;
01544                 LPDIRECT3DTEXTURE9 oldCurrentName = NULL;
01545                 {
01546                     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01547                     oldPlaylistName = _playlistName;
01548                     _playlistName = _nextPlaylistName;
01549                     _nextPlaylistName = NULL;
01550                     oldCurrentName = _currentName;
01551                     _currentName = _nextName;
01552                     _nextName = NULL;
01553                 }
01554                 SAFE_RELEASE(oldPlaylistName);
01555                 SAFE_RELEASE(oldCurrentName);
01556                 _status["current-playlist-id"] = _status["next-playlist-id"];
01557                 _status["current-index"] = Poco::format("%d", _playCurrent.i);
01558                 _status["current-playlist"] = _status["next-playlist"];
01559                 _status["current-content-id"] = _status["next-content-id"];
01560                 _status["current-content"] = _status["next-content"];
01561                 removeStatus("next-playlist-id");
01562                 removeStatus("next-playlist");
01563                 removeStatus("next-content-id");
01564                 removeStatus("next-content");
01565 
01566                 if (config().outCastLog) {
01567                     string d = Poco::DateTimeFormatter::format(now.timestamp(), "%Y%m%d");
01568                     if (_castLogDate != d) {
01569                         if (_castLog) {
01570                             _castLog->close();
01571                             SAFE_DELETE(_castLog);
01572                         }
01573                         _castLogDate = d;
01574                         File dataFile("logs/cast-" + _castLogDate + ".csv");
01575                         bool createNewFile = !dataFile.exists();
01576                         _castLog = new Poco::FileOutputStream();
01577                         _castLog->open(dataFile.path(), std::ios::out | std::ios::app);
01578                         if (createNewFile) {
01579                             string s = "@1¥r¥n";
01580                             _castLog->write(s.c_str(), s.length());
01581                             _castLog->flush();
01582                         }
01583                     }
01584                     if (_castLog) {
01585                         string time = Poco::DateTimeFormatter::format(now.timestamp(), "%Y-%m-%d %H:%M:%S.%i");
01586                         string s = time + "," + _status["current-content"] + "¥r¥n";
01587                         _castLog->write(s.c_str(), s.length());
01588                         _castLog->flush();
01589                     }
01590                 }
01591                 _playCount++;
01592 
01593                 Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01594                 ContentPtr currentContent = NULL;
01595                 if (oldCurrent >= 0) {
01596                     _contents[oldCurrent]->pause();
01597                     currentContent = _contents[oldCurrent]->get(0);
01598                 }
01599                 if (currentContent) {
01600                     SAFE_DELETE(_transition);
01601                     if (_playCurrent.transition == "slide") {
01602                         int h = config().stageRect.bottom;
01603                         float speed = h / F(60); // 1s
01604                         _transition = new SlideTransition(currentContent, nextContent, speed, 0, h);
01605                     } else if (_playCurrent.transition == "dissolve") {
01606                         float speed = 0.05f;
01607                         _transition = new DissolveTransition(currentContent, nextContent, speed);
01608                     }
01609                     if (_transition) _transition->initialize(_frame);
01610                 }
01611                 if (!_transition) {
01612                     _doPrepareNext = true;
01613                 }
01614             } else {
01615             }
01616         }
01617 
01618         {
01619             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01620             if (_transition && _transition->process(_frame)) {
01621                 // トランジション終了
01622                 SAFE_DELETE(_transition);
01623                 // 次のコンテンツ準備
01624                 _doPrepareNext = true;
01625                 if (_currentContent >= 0 && _contents[_currentContent]->useFastStop()) {
01626                     _contents[_currentContent]->stop();
01627                 }
01628             }
01629         }
01630 
01631         if (_doPrepareNext && !_preparingNext) {
01632             _doPrepareNext = false;
01633             PlayParameters params;
01634             {
01635                 Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01636                 params.playlistID = _playCurrent.playlistID;
01637                 params.i = _playCurrent.i + 1;
01638                 params.action = _playCurrent.action;
01639             }
01640             _nextStack.push_back(params);
01641             _nextStackTime = 0;
01642         }
01643 
01644         {
01645             // 次コンテンツのスタック処理
01646             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01647             if (!_nextStack.empty()) {
01648                 _nextStackTime++;
01649                 if (_nextStackTime > 30) {
01650                     activePrepareNextContent(_nextStack.back());
01651                     _nextStack.clear();
01652                 }
01653             }
01654         }
01655 
01656         {
01657             // プレイリスト切替のスタック処理
01658             Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01659             if (!_prepareStack.empty()) {
01660                 _prepareStackTime++;
01661                 if (_prepareStackTime > 30) {
01662                     activePrepareContent(_prepareStack.back());
01663                     _prepareStack.clear();
01664                 }
01665             }
01666         }
01667     }
01668 
01669     // スケジュール処理
01670     if (now.second() != _timeSecond) {
01671         _timeSecond = now.second();
01672         _nowTime = Poco::DateTimeFormatter::format(now, "%Y/%m/%d(%w) %H:%M:%S");
01673         Poco::ScopedLock<Poco::FastMutex> lock(_workspaceLock);
01674         if (_workspace) {
01675             Poco::Timespan bf10(0, 0, 0, 10, 0);
01676             for (int i = 0; i < _workspace->getScheduleCount(); i++) {
01677                 SchedulePtr schedule = _workspace->getSchedule(i);
01678                 if (schedule->match(now + bf10)) {
01679                     // 10秒前チェック
01680                     string command = schedule->command();
01681                     if (command.find("playlist ") == 0) {
01682                         string params = command.substr(9);
01683                         string playlistID = params;
01684                         int item = 0;
01685                         if (params.find("-") != string::npos) {
01686                             playlistID = params.substr(0, params.find("-"));
01687                             if (!Poco::NumberParser::tryParse(params.substr(params.find("-") + 1), item)) {
01688                                 // failed parse item no
01689                             }
01690                         }
01691 
01692                         PlayListPtr playlist = _workspace->getPlaylist(playlistID);
01693                         if (playlist) {
01694                             _log.information(Poco::format("[%s]exec %s", _nowTime, command));
01695                             stackPrepareContent(playlistID, item);
01696                             drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + Poco::format("preparing playlist %s", playlist->id()));
01697                         } else {
01698                             _log.warning(Poco::format("[%s]failed command: %s", _nowTime, command));
01699                         }
01700                         break;
01701                     } else if (command.find("next") == 0) {
01702                         break;
01703                     } else if (command.find("brightness ") == 0) {
01704                         break;
01705                     } else {
01706                         _log.warning(Poco::format("[%s]failed command: %s", _nowTime, command));
01707                     }
01708                 } else if (schedule->match(now)) {
01709                     // 実時間チェック
01710                     string command = schedule->command();
01711                     if (command.find("playlist ") == 0) {
01712                         if (_prepared) {
01713                             activeSwitchContent();
01714                             _log.information(Poco::format("[%s]exec %s", _nowTime, command));
01715                             //_doSwitchPrepared = true;
01716                             drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + "switched " + command);
01717                         } else {
01718                             _log.warning(Poco::format("[%s]failed next content not prepared %s", _nowTime, command));
01719                             drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + "not switched " + command);
01720                         }
01721                         break;
01722                     } else if (command.find("next") == 0) {
01723                         _doSwitchNext = true;
01724                         _log.information(Poco::format("[%s]exec %s", _nowTime, command));
01725                         drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + "switched next");
01726                         break;
01727                     } else if (command.find("brightness ") == 0) {
01728                         int brightness = -1;
01729                         if (Poco::NumberParser::tryParse(command.substr(10), brightness) && brightness >= 0 && brightness <= 100) {
01730                             setBrightness(brightness);
01731                             _log.information(Poco::format("[%s]exec %s", _nowTime, command));
01732                             drawConsole(Poco::DateTimeFormatter::format(now, "[%H:%M:%S]") + Poco::format("set brightness %d", brightness));
01733                         }
01734                         break;
01735                     }
01736                 }
01737             }
01738         }
01739     }
01740 
01741     //if (_interrupttedContent) _interrupttedContent->process(_frame);
01742 
01743     _status["brightness"] = Poco::NumberFormatter::format(config().brightness);
01744     _frame++;
01745 }
01746 
01747 void MainScene::draw1() {
01748     if (!_running) return;
01749     LPDIRECT3DDEVICE9 device = _renderer.get3DDevice();
01750     device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
01751     device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
01752     device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
01753     device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
01754     if (_currentContent >= 0) {
01755         int before = _currentContent - 1;
01756         if (before < 0) before = _contents.size() - 1;
01757         _contents[before]->draw(_frame);
01758         _contents[_currentContent]->draw(_frame);
01759     }
01760     if (_interrupttedContent) _interrupttedContent->draw(_frame);
01761 
01762     if (_brightness < 100 || config().dimmer < F(1)) {
01763         DWORD col = ((DWORD)(0xff * (100 - _brightness * config().dimmer) / 100) << 24) | 0x000000;
01764         _renderer.drawTexture(config().mainRect.left, config().mainRect.top, config().mainRect.right, config().mainRect.bottom, NULL, 0, col, col, col, col);
01765     }
01766     if (_removableCover > 0.0f) {
01767         DWORD col = ((DWORD)(0xff * _removableCover) << 24) | 0x000000;
01768         _renderer.drawTexture(config().mainRect.left, config().mainRect.top, config().mainRect.right, config().mainRect.bottom, NULL, 0, col, col, col, col);
01769     }
01770     // _renderer.drawFontTextureText(0, config().mainRect.bottom - 40, 12, 16, 0xffcccccc, Poco::format("LUMINANCE:%03d", _luminance));
01771 }
01772 
01773 void MainScene::draw2() {
01774     if (config().fullsceen && _renderer.getDisplayAdapters() > 1) {
01775         LPDIRECT3DDEVICE9 device = _renderer.get3DDevice();
01776         LPDIRECT3DTEXTURE9 capture = _renderer.getCaptureTexture();
01777         if (capture) {
01778             D3DSURFACE_DESC desc;
01779             HRESULT hr = capture->GetLevelDesc(0, &desc);
01780             int x = config().subRect.left;
01781             int y = config().subRect.top;
01782             int w = config().subRect.right;
01783             int h = config().subRect.bottom - 128;
01784             float a1 = F(desc.Width) / desc.Height;
01785             float a2 = F(w) / h;
01786             if (a1 >= a2) {
01787                 // 横長
01788                 int dh = w / a1;
01789                 y = (h - dh) / 2;
01790                 h = dh;
01791             } else {
01792                 // 縦長
01793                 int dw = h / a1;
01794                 x = (w - dw) / 2;
01795                 w = dw;
01796             }
01797             device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
01798             device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
01799             _renderer.drawTexture(x, y, w, h, capture, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
01800             device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
01801             device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
01802         }
01803     }
01804 
01805     string status1;
01806     string status2;
01807     if (_currentContent >= 0) {
01808         int current = -1;
01809         int duration = -1;
01810         for (int i = 0; i < _contents[_currentContent]->size(); ++i) {
01811             ContentPtr c = _contents[_currentContent]->get(i);
01812             if (c && !c->opened().empty()) {
01813                 string s = c->get("status");
01814                 if (!s.empty()) status1 = s;
01815                 if (c->duration() > duration) {
01816                     current = c->current();
01817                     duration = c->duration();
01818                     string time = c->get("time");
01819                     status2 = Poco::format("%05d/%05d %s", current, duration, time);
01820                     string tc = c->get("time_current");
01821                     string tr = c->get("time_remain");
01822                     if (!tc.empty()) _status["time_current"] = tc;
01823                     if (!tr.empty()) _status["time_remain"] = tr;
01824                 }
01825             }
01826         }
01827     }
01828 
01829     if (config().viewStatus && _workspace) {
01830         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01831         _renderer.drawFontTextureText(0, config().subRect.bottom - 128, 24, 32, 0x996699ff, config().name);
01832         _renderer.drawTexture((config().name.size() + 1) * 24, config().subRect.bottom - 128, _description, 0, 0xcc6666ff, 0xcc6666ff, 0x993333cc, 0x993333cc);
01833         _renderer.drawFontTextureText(0, config().subRect.bottom - 96, 12, 16, 0x99ffffff, status1);
01834         _renderer.drawFontTextureText(0, config().subRect.bottom - 80, 12, 16, 0x99ccccff, "frame");
01835         _renderer.drawFontTextureText(144, config().subRect.bottom - 80, 12, 16, 0x99ccccff, "time");
01836         _renderer.drawFontTextureText(288, config().subRect.bottom - 80, 12, 16, 0x99ccccff, "remain");
01837         _renderer.drawFontTextureText(0, config().subRect.bottom - 64, 12, 16, 0x99ffffff, status2);
01838         _renderer.drawFontTextureText(0, config().subRect.bottom - 48, 12, 16, 0x99ccccff, "action");
01839         if (!_playCurrent.action.empty()) _renderer.drawFontTextureText(84, config().subRect.bottom - 48, 12, 16, 0x99ffffff, _playCurrent.action);
01840         _renderer.drawFontTextureText(264, config().subRect.bottom - 48, 12, 16, 0x99ccccff, "transition");
01841         if (!_playNext.transition.empty()) _renderer.drawFontTextureText(396, config().subRect.bottom - 48, 12, 16, 0x99ffffff, _playNext.transition);
01842 
01843         _renderer.drawFontTextureText(504, config().subRect.bottom - 128, 12, 16, 0x99ccccff, " current");
01844         _renderer.drawTexture(612, config().subRect.bottom - 128, _playlistName, 0, 0xccffffff, 0xccffffff,0x99ffffff, 0x99ffffff);
01845         _renderer.drawTexture(612, config().subRect.bottom - 112, _currentName, 0, 0xccffffff, 0xccffffff,0x99ffffff, 0x99ffffff);
01846         _renderer.drawFontTextureText(504, config().subRect.bottom - 96, 12, 16, 0x99ccccff, "    next");
01847         _renderer.drawTexture(612, config().subRect.bottom - 96, _nextName, 0, 0xccffffff, 0xccffffff,0x99ffffff, 0x99ffffff);
01848         _renderer.drawFontTextureText(504, config().subRect.bottom - 80, 12, 16, 0x99ccccff, "prepared");
01849         _renderer.drawTexture(612, config().subRect.bottom - 80, _preparedPlaylistName, 0, 0xccffffff, 0xccffffff,0x99ffffff, 0x99ffffff);
01850         _renderer.drawTexture(612, config().subRect.bottom - 64, _preparedName, 0, 0xccffffff, 0xccffffff,0x99ffffff, 0x99ffffff);
01851     }
01852     if (config().viewStatus) {
01853         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01854         int next = (_currentContent + 1) % _contents.size();
01855         string wait(_contents[next]->opened().empty()?"preparing":"ready");
01856         _renderer.drawFontTextureText(0, config().subRect.bottom - 32, 12, 16, 0x99669966, Poco::format("[%s] played>%04d current>%d state>%s", _nowTime, _playCount, _currentContent, wait));
01857         if (!_messages.empty()) {
01858             if (_messageFrame > 30 && _messages.size() > 1) {
01859                 _messageFrame = 0;
01860                 _messages.pop();
01861             }
01862             string s = _messages.front();
01863             DWORD col = ((DWORD)((0x99 * (_messageFrame > 30?30:_messageFrame) / 30) << 24)) | 0xcc9900;
01864             _renderer.drawFontTextureText(config().subRect.right - s.length() * 12, config().subRect.bottom - 48, 12, 16, col, s);
01865             _messageFrame++;
01866         }
01867 
01868         //string delayedUpdate = getStatus("delayed-update");
01869         //if (delayedUpdate.empty()) {
01870         string remoteCopy = getStatus("remote-copy");
01871         if (!remoteCopy.empty()) {
01872             if (remoteCopy != "10") {
01873                 int x = config().subRect.right - 156;
01874                 int y = config().subRect.bottom - 16;
01875                 DWORD col = ((_frame / 10) % 2 == 0)?0x99ff9933:0x99000000;
01876                 _renderer.drawFontTextureText(x, y, 12, 16, col, "[copy master]");
01877             }
01878         }
01879         //} else {
01880         //  int x = config().subRect.right - 204;
01881         //  int y = config().subRect.bottom - 16;
01882         //  _renderer.drawFontTextureText(x, y, 12, 16, 0x99ff9933, "[delayedUpdating]");
01883         //}
01884     }
01885 
01886     {
01887         Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01888         D3DSURFACE_DESC desc;
01889         HRESULT hr = _removableIcon->GetLevelDesc(0, &desc);
01890         int tw = desc.Width / 2;
01891         int th = desc.Height / 2;
01892         if (_removableIcon && _removableIconAlpha > 0) {
01893             DWORD col = ((DWORD)(0xff * _removableIconAlpha) << 24) | 0xffffff;
01894             _renderer.drawTexture(0, config().subRect.bottom - th, tw, th, _removableIcon, 0, col, col, col, col);
01895         }
01896         if (_removableAlpha > 0) {
01897             DWORD col = ((DWORD)(0x66 * _removableAlpha) << 24) | 0x333333;
01898             _renderer.drawTexture(tw + 1, config().subRect.bottom - th / 2, config().subRect.right - tw - 1, 10, NULL, 0, col, col, col, col);
01899             DWORD col1 = ((DWORD)(0x66 * _removableAlpha) << 24) | 0x33ccff;
01900             DWORD col2 = ((DWORD)(0x66 * _removableAlpha) << 24) | 0x3399cc;
01901             _renderer.drawTexture(tw + 2, config().subRect.bottom - th / 2 + 1, (config().subRect.right - tw - 2) * _currentCopyProgress / 100, 8, NULL, 0, col1, col1, col2, col2);
01902             // _renderer.drawFontTextureText(tw, config().subRect.bottom - th / 2, 12, 16, 0xccffffff, Poco::format("%d %d(%d%%)", _currentCopySize, _copySize, _currentCopyProgress));
01903         }
01904     }
01905 }
01906 
01907 void MainScene::drawConsole(string s) {
01908     Poco::ScopedLock<Poco::FastMutex> lock(_lock);
01909     _messages.push(s);
01910 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines