svvitch
digital signage player
|
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 }