svvitch
digital signage player
|
00001 #ifdef USE_OPENCV 00002 00003 #include <Poco/DateTime.h> 00004 #include <Poco/Timezone.h> 00005 #include <Poco/Mutex.h> 00006 #include <Poco/Thread.h> 00007 #include <Poco/Runnable.h> 00008 #include <Poco/Stringtokenizer.h> 00009 #include <Poco/Util/XMLConfiguration.h> 00010 #include <Poco/UnicodeConverter.h> 00011 00012 #include "CvContent.h" 00013 00014 using Poco::Util::XMLConfiguration; 00015 00016 00017 CvContent::CvContent(Renderer& renderer, int splitType): Content(renderer, splitType), activeOpenDetectMovie(this, &CvContent::openDetectMovie), 00018 _normalItem(NULL), _normalMovie(NULL), _detectedItem(NULL), _detectedMovie(NULL), 00019 _fx(NULL), _small1(NULL), _small2(NULL), _diff(NULL), _diff2(NULL), _photo(NULL), 00020 _detected(false), _doShutter(0), _viewPhoto(0), _finished(true), _playing(false), _statusFrame(0) 00021 { 00022 initialize(); 00023 _scene = (CaptureScenePtr)_renderer.getScene("capture"); 00024 } 00025 00026 CvContent::‾CvContent() { 00027 initialize(); 00028 } 00029 00030 void CvContent::saveConfiguration() { 00031 try { 00032 Poco::Util::XMLConfiguration* xml = new Poco::Util::XMLConfiguration("cv-config.xml"); 00033 if (xml) { 00034 xml->setInt("detect", _detectThreshold); 00035 xml->setInt("intervals[@diff]", _intervalDiff); 00036 xml->setInt("intervals[@small]", _intervalSmall); 00037 xml->setInt("clip[@x]", _clipX); 00038 xml->setInt("clip[@y]", _clipY); 00039 xml->setInt("clip[@w]", _clipW); 00040 xml->setInt("clip[@h]", _clipH); 00041 xml->save("cv-config.xml"); 00042 xml->release(); 00043 _log.information("cv parameters saved"); 00044 } 00045 } catch (Poco::Exception& ex) { 00046 _log.warning(ex.displayText()); 00047 } 00048 } 00049 00050 void CvContent::initialize() { 00051 srand(time(NULL)); 00052 close(); 00053 } 00054 00056 bool CvContent::open(const MediaItemPtr media, const int offset) { 00057 initialize(); 00058 00059 int deviceW = 0; 00060 int deviceH = 0; 00061 try { 00062 XMLConfiguration* xml = new XMLConfiguration("cv-config.xml"); 00063 // _deviceNo = xml->getInt("device[@no]", 0); 00064 deviceW = xml->getInt("device[@w]", 640); 00065 deviceH = xml->getInt("device[@h]", 480); 00066 // _deviceFPS = xml->getInt("device[@fps]", 60); 00067 _subtract = xml->getDouble("subtract", 0.5); 00068 // _samples = xml->getInt("samples", 4); 00069 _detectThreshold = xml->getInt("detect", 50); 00070 _intervalDiff = xml->getInt("intervals[@diff]", 60); 00071 _intervalSmall = xml->getInt("intervals[@small]", 12); 00072 _clipX = xml->getInt("clip[@x]", 0); 00073 _clipY = xml->getInt("clip[@y]", 0); 00074 _clipW = xml->getInt("clip[@w]", deviceW); 00075 _clipH = xml->getInt("clip[@h]", deviceH); 00076 _normalFile = xml->getString("normalMovie", ""); 00077 string detectedFile = xml->getString("detectedMovie", ""); 00078 Poco::StringTokenizer files(detectedFile, ","); 00079 for (Poco::StringTokenizer::Iterator it = files.begin(); it != files.end(); it++) { 00080 _detectFiles.push_back(*it); 00081 } 00082 _detectCount = xml->getInt("detectedMovie[@count]", 1); 00083 00084 xml->release(); 00085 } catch (Poco::Exception& ex) { 00086 _log.warning(ex.displayText()); 00087 } 00088 00089 vector<MediaItemFile> file1; 00090 file1.push_back(MediaItemFile(MediaTypeMovie, _normalFile, "")); 00091 _normalItem = new MediaItem(MediaTypeMovie, "normal", "normal", 0, false, file1); 00092 _normalMovie = new FFMovieContent(_renderer, config().splitType); 00093 if (_normalMovie->open(_normalItem)) { 00094 _normalMovie->setPosition(config().stageRect.left, config().stageRect.top); 00095 _normalMovie->setBounds(config().stageRect.right, config().stageRect.bottom); 00096 _normalMovie->play(); 00097 } else { 00098 SAFE_DELETE(_normalMovie); 00099 } 00100 00101 _detectedMovie = new FFMovieContent(_renderer, config().splitType); 00102 _detectedMovie->setPosition(config().stageRect.left, config().stageRect.top); 00103 _detectedMovie->setBounds(config().stageRect.right, config().stageRect.bottom); 00104 activeOpenDetectMovie(); 00105 00106 std::wstring wfile; 00107 Poco::UnicodeConverter::toUTF16(string("subbg.fx"), wfile); 00108 LPD3DXBUFFER errors = NULL; 00109 HRESULT hr = D3DXCreateEffectFromFile(_renderer.get3DDevice(), wfile.c_str(), 0, 0, D3DXSHADER_DEBUG, 0, &_fx, &errors); 00110 if (errors) { 00111 std::vector<char> text(errors->GetBufferSize()); 00112 memcpy(&text[0], errors->GetBufferPointer(), errors->GetBufferSize()); 00113 text.push_back('¥0'); 00114 _log.warning(Poco::format("shader compile error: %s", string(&text[0]))); 00115 SAFE_RELEASE(errors); 00116 } else if (FAILED(hr)) { 00117 _log.warning(Poco::format("failed shader: %s", string(""))); 00118 } 00119 00120 _small1 = _renderer.createRenderTarget(deviceW / 8, deviceH / 8, D3DFMT_A8R8G8B8); 00121 _renderer.colorFill(_small1, 0); 00122 _small2 = _renderer.createRenderTarget(deviceW / 8, deviceH / 8, D3DFMT_A8R8G8B8); 00123 _renderer.colorFill(_small2, 0); 00124 _diff = _renderer.createRenderTarget(deviceW / 8, deviceH / 8, D3DFMT_A8R8G8B8); 00125 _diff2 = _renderer.createLockableSurface(deviceW / 8, deviceH / 8, D3DFMT_A8R8G8B8); 00126 _photo = _renderer.createRenderTarget(deviceW, deviceH, D3DFMT_A8R8G8B8); 00127 _renderer.colorFill(_photo, 0); 00128 00129 set("alpha", 1.0f); 00130 _duration = media->duration() * 60 / 1000; 00131 _current = 0; 00132 _mediaID = media->id(); 00133 return true; 00134 } 00135 00136 void CvContent::openDetectMovie() { 00137 _log.information("*openDetectMovie"); 00138 SAFE_DELETE(_detectedItem); 00139 if (!_detectFiles.empty()) { 00140 vector<MediaItemFile> files; 00141 files.push_back(MediaItemFile(MediaTypeMovie, _detectFiles.at(rand() % _detectFiles.size()), "")); 00142 _detectedItem = new MediaItem(MediaTypeMovie, "detected", "detected", 0, false, files); 00143 if (_detectedMovie->open(_detectedItem)) { 00144 // _detectedMovie->setPosition(conf->stageRect.left, conf->stageRect.top); 00145 // _detectedMovie->setBounds(conf->stageRect.right, conf->stageRect.bottom); 00146 // } else { 00147 // SAFE_DELETE(_detectedMovie); 00148 } 00149 } 00150 } 00151 00152 00156 void CvContent::play() { 00157 _playing = true; 00158 _playTimer.start(); 00159 } 00160 00164 void CvContent::stop() { 00165 _playing = false; 00166 } 00167 00168 bool CvContent::useFastStop() { 00169 return true; 00170 } 00171 00175 const bool CvContent::playing() const { 00176 return _playing; 00177 } 00178 00179 const bool CvContent::finished() { 00180 if (_duration > 0) { 00181 if (_detectedMovie && _detectedMovie->playing() && !_detectedMovie->finished()) { 00182 return false; 00183 } 00184 return _current >= _duration; 00185 } 00186 return false; 00187 } 00188 00190 void CvContent::close() { 00191 stop(); 00192 _mediaID.clear(); 00193 00194 Poco::DateTime now; 00195 now.makeLocal(Poco::Timezone::tzd()); 00196 std::wstring wfile; 00197 Poco::UnicodeConverter::toUTF16(Poco::format("photos/snap%02d%02d%02d%02d.png", now.day(), now.hour(), now.minute(), now.second()), wfile); 00198 HRESULT hr = D3DXSaveTextureToFile(wfile.c_str(), D3DXIFF_PNG, _photo, NULL); 00199 00200 { 00201 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00202 SAFE_RELEASE(_fx); 00203 SAFE_RELEASE(_small1); 00204 SAFE_RELEASE(_small2); 00205 SAFE_RELEASE(_diff); 00206 SAFE_RELEASE(_diff2); 00207 SAFE_RELEASE(_photo); 00208 SAFE_DELETE(_normalMovie); 00209 SAFE_DELETE(_normalItem); 00210 SAFE_DELETE(_detectedMovie); 00211 SAFE_DELETE(_detectedItem); 00212 } 00213 } 00214 00215 void CvContent::process(const DWORD& frame) { 00216 if (_playing) { 00217 if (_keycode != 0) { 00218 switch (_keycode) { 00219 case 'P': 00220 _clipY-=1; 00221 break; 00222 case VK_OEM_PERIOD: 00223 _clipY+=1; 00224 break; 00225 case 'L': 00226 _clipX-=1; 00227 break; 00228 case VK_OEM_PLUS: 00229 _clipX+=1; 00230 break; 00231 00232 case VK_OEM_4: 00233 _clipH-=1; 00234 break; 00235 case VK_OEM_102: 00236 _clipH+=1; 00237 break; 00238 case VK_OEM_1: 00239 _clipW-=1; 00240 break; 00241 case VK_OEM_6: 00242 _clipW+=1; 00243 break; 00244 00245 case '8': 00246 _detectThreshold--; 00247 break; 00248 case '9': 00249 _detectThreshold++; 00250 break; 00251 00252 case '0': 00253 _intervalDiff--; 00254 break; 00255 case VK_OEM_MINUS: 00256 _intervalDiff++; 00257 break; 00258 00259 case VK_OEM_7: 00260 _intervalSmall--; 00261 break; 00262 case VK_OEM_5: 00263 _intervalSmall++; 00264 break; 00265 00266 case 'S': 00267 saveConfiguration(); 00268 _statusFrame = frame; 00269 _status = "PARAMETER SAVED."; 00270 break; 00271 00272 default: 00273 _log.information(Poco::format("key: %?x", _keycode)); 00274 } 00275 } 00276 00277 // if (get("prepare") != "true") { 00278 // } 00279 if (_normalMovie) { 00280 _normalMovie->process(frame); 00281 if (_normalMovie->playing() && _normalMovie->finished()) { 00282 _normalMovie->seek(0); 00283 _normalMovie->play(); 00284 } 00285 } 00286 if (_detectedMovie) { 00287 _detectedMovie->process(frame); 00288 if (!_detectedMovie->opened().empty() && !_detected && _diffCount > _detectThreshold) { 00289 if (_viewPhoto == 0 || (frame - _viewPhoto) > 500) { 00290 if (_detectCount > 0) { 00291 if (_normalMovie) _normalMovie->stop(); 00292 _detectedMovie->play(); 00293 _detected = true; 00294 _doShutter = frame; 00295 } else { 00296 // 検出回数上限 00297 _current = _duration; 00298 } 00299 } 00300 } 00301 if (_detectedMovie->playing() && _detectedMovie->finished()) { 00302 _detectedMovie->close(); 00303 // _detectedMovie->seek(0); 00304 if (_normalMovie) _normalMovie->play(); 00305 _detectCount--; 00306 if (_detectCount > 0) activeOpenDetectMovie(); 00307 _detected = false; 00308 _viewPhoto = frame; 00309 } 00310 } 00311 _current++; 00312 } 00313 } 00314 00315 void CvContent::draw(const DWORD& frame) { 00316 if (!_mediaID.empty() && _playing) { 00317 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00318 LPDIRECT3DTEXTURE9 cameraImage = _scene->getCameraImage(); 00319 DWORD col = 0xffffffff; 00320 _renderer.drawTexture(640, 0, 640, 480, cameraImage, 0, col, col, col, col); 00321 LPDIRECT3DDEVICE9 device = _renderer.get3DDevice(); 00322 if (_fx) { 00323 LPDIRECT3DSURFACE9 orgRT; 00324 HRESULT hr = device->GetRenderTarget(0, &orgRT); 00325 00326 // 単純化 00327 col = 0xffffffff; 00328 D3DSURFACE_DESC desc; 00329 hr = _small1->GetLevelDesc(0, &desc); 00330 VERTEX dst[] = 00331 { 00332 {F(0 - 0.5), F(0 - 0.5), 0.0f, 1.0f, col, 0, 0}, 00333 {F(0 + desc.Width - 0.5), F(0 - 0.5), 0.0f, 1.0f, col, 1, 0}, 00334 {F(0 - 0.5), F(0 + desc.Height - 0.5), 0.0f, 1.0f, col, 0, 1}, 00335 {F(0 + desc.Width - 0.5), F(0 + desc.Height - 0.5), 0.0f, 1.0f, col, 1, 1} 00336 }; 00337 LPDIRECT3DSURFACE9 surface; 00338 if ((frame % _intervalDiff) == 0) { 00339 _small1->GetSurfaceLevel(0, &surface); 00340 hr = device->SetRenderTarget(0, surface); 00341 _renderer.drawTexture(0, 0, desc.Width, desc.Height, _clipX, _clipY, _clipW, _clipH, cameraImage, 0, col, col, col, col); 00342 SAFE_RELEASE(surface); 00343 } 00344 if ((frame % _intervalSmall) == 0) { 00345 _small2->GetSurfaceLevel(0, &surface); 00346 hr = device->SetRenderTarget(0, surface); 00347 _renderer.drawTexture(0, 0, desc.Width, desc.Height, _clipX, _clipY, _clipW, _clipH, cameraImage, 0, col, col, col, col); 00348 SAFE_RELEASE(surface); 00349 00350 // 差分 00351 _diff->GetSurfaceLevel(0, &surface); 00352 hr = device->SetRenderTarget(0, surface); 00353 _fx->SetTechnique("BasicTech"); 00354 _fx->SetFloat("subtract", _subtract); 00355 _fx->SetTexture("bgTex", _small1); 00356 _fx->SetTexture("currentTex", _small2); 00357 hr = _fx->Begin(0, 0); 00358 if (SUCCEEDED(hr)) { 00359 _fx->BeginPass(1); 00360 device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, dst, VERTEX_SIZE); 00361 _fx->EndPass(); 00362 _fx->End(); 00363 } 00364 SAFE_RELEASE(surface); 00365 if (_renderer.getRenderTargetData(_diff, _diff2)) { 00366 D3DSURFACE_DESC desc; 00367 _diff2->GetDesc(&desc); 00368 D3DLOCKED_RECT lockedRect; 00369 hr = _diff2->LockRect(&lockedRect, NULL, 0); 00370 if (SUCCEEDED(hr)) { 00371 _diffCount = 0; 00372 DWORD* buf = (DWORD*)lockedRect.pBits; 00373 for (int i = 0; i < lockedRect.Pitch / 4 * desc.Height; i++) { 00374 if (buf[i] == 0xffffffff) _diffCount++; 00375 } 00376 _diff2->UnlockRect(); 00377 if (desc.Width * desc.Height <= _diffCount) _diffCount = 0; 00378 } 00379 } 00380 } 00381 hr = device->SetRenderTarget(0, orgRT); 00382 SAFE_RELEASE(orgRT); 00383 } 00384 00385 if (_doShutter > 0 && (frame - _doShutter) > 60) { 00386 LPDIRECT3DDEVICE9 device = _renderer.get3DDevice(); 00387 LPDIRECT3DSURFACE9 orgRT; 00388 HRESULT hr = device->GetRenderTarget(0, &orgRT); 00389 00390 D3DSURFACE_DESC desc; 00391 hr = _photo->GetLevelDesc(0, &desc); 00392 LPDIRECT3DSURFACE9 surface; 00393 _photo->GetSurfaceLevel(0, &surface); 00394 hr = device->SetRenderTarget(0, surface); 00395 DWORD col = 0xffffffff; 00396 _renderer.drawTexture(0, 0, desc.Width, desc.Height, cameraImage, 0, col, col, col, col); 00397 SAFE_RELEASE(surface); 00398 00399 hr = device->SetRenderTarget(0, orgRT); 00400 SAFE_RELEASE(orgRT); 00401 _doShutter = 0; 00402 } 00403 00404 if (_detected) { 00405 if (_detectedMovie) _detectedMovie->draw(frame); 00406 } else { 00407 if (_normalMovie) _normalMovie->draw(frame); 00408 } 00409 00410 int x = config().stageRect.left; 00411 int y = config().stageRect.top; 00412 int w = config().stageRect.right; 00413 int h = config().stageRect.bottom; 00414 if (_viewPhoto > 0 && (frame - _viewPhoto) > 100 && (frame - _viewPhoto) < 500) { 00415 float alpha = 1.0f; 00416 if ((frame - _viewPhoto) > 400) { 00417 alpha = F(500 - (frame - _viewPhoto)) / 100; 00418 } 00419 DWORD col = ((DWORD)(0x66 * alpha) << 24) | 0x000000; 00420 _renderer.drawTexture(x + 60, y + 20, w - 80, h - 20, NULL, 0, col, col, col, col); 00421 col = ((DWORD)(0xff * alpha) << 24) | 0xffffff; 00422 _renderer.drawTexture(x + 40, y + 10, w - 80, h - 20, NULL, 0, col, col, col, col); 00423 _renderer.drawTexture(x + 43, y + 13, w - 86, h - 26, _photo, 0, col, col, col, col); 00424 } 00425 00426 // ステータス表示 00427 col = 0x66669966; 00428 _renderer.drawTexture(640 + _clipX, _clipY, _clipW, _clipH, NULL, 0, col, col, col, col); 00429 _renderer.drawFontTextureText(640 + _clipX, _clipY, 8, 10, 0xccffffff, Poco::format("(%d,%d)-%dx%d", _clipX, _clipY, _clipW, _clipH)); 00430 col = 0xffffffff; 00431 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00432 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00433 _renderer.drawTexture(320, 480, 320, 240, _diff, 0, col, col, col, col); 00434 _renderer.drawFontTextureText(320, 480, 12, 16, 0xccffffff, Poco::format("<%04d/%04d>", _diffCount, _detectThreshold)); 00435 _renderer.drawTexture(640, 480, 320, 240, _small1, 0, col, col, col, col); 00436 float interval = _intervalDiff / 60.0f; 00437 _renderer.drawFontTextureText(640, 480, 12, 16, 0xccffffff, Poco::format("%d(%0.2hfs)", _intervalDiff, interval)); 00438 _renderer.drawTexture(960, 480, 320, 240, _small2, 0, col, col, col, col); 00439 interval = _intervalSmall / 60.0f; 00440 _renderer.drawFontTextureText(960, 480, 12, 16, 0xccffffff, Poco::format("%d(%0.2hfs)", _intervalSmall, interval)); 00441 _renderer.drawTexture(0, 480, 320, 240, _photo, 0, col, col, col, col); 00442 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00443 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00444 if (_statusFrame > 0 && (frame - _statusFrame) < 200) { 00445 _renderer.drawFontTextureText(640, config().mainRect.bottom - 32, 24, 32, 0xccff3333, _status); 00446 } 00447 } 00448 } 00449 00450 #endif