svvitch
digital signage player
|
00001 #include "DSContent.h" 00002 #include <Poco/UnicodeConverter.h> 00003 00004 00005 DSContent::DSContent(Renderer& renderer, int splitType): Content(renderer, splitType), 00006 activePlay(this, &DSContent::syncronizedPlay), 00007 _gb(NULL), _vmr9(NULL), _allocator(NULL), _vr(NULL), _mc(NULL), _ms(NULL), _me(NULL) 00008 { 00009 } 00010 00011 DSContent::‾DSContent() { 00012 initialize(); 00013 } 00014 00015 void DSContent::initialize() { 00016 close(); 00017 } 00018 00020 bool DSContent::open(const MediaItemPtr media, const int offset) { 00021 initialize(); 00022 if (media->files().empty()) return false; 00023 00024 HRESULT hr; 00025 hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&_gb); 00026 if (FAILED(hr)) { 00027 _log.warning(Poco::format("failed create filter graph: hr=0x%lx", ((unsigned long)hr))); 00028 return false; 00029 } 00030 00031 if (true) { 00032 hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&_vmr9); 00033 if (FAILED(hr)) { 00034 //SAFE_RELEASE(s->gb); 00035 //TCHAR err[1024]; 00036 //DWORD res = AMGetErrorText(hr, err, 1024); 00037 //_log.warning(L"failed creation VideoMixingRenderer9: [%s]", err); 00038 _log.warning("failed creation VideoMixingRenderer9"); 00039 return false; 00040 } 00041 00042 IVMRFilterConfig9 *fc; 00043 hr = _vmr9->QueryInterface(&fc); 00044 if (FAILED(hr)) { 00045 _log.warning("VMR-9 setup failed(VMRFilterConfig9 not found)"); 00046 return false; 00047 } 00048 00049 hr = fc->SetRenderingMode(VMR9Mode_Renderless); 00050 if (FAILED(hr)) { 00051 _log.warning("VMR-9 setup failed(failed set renderless)"); 00052 return false; 00053 } 00054 hr = fc->SetNumberOfStreams(1); 00055 if (FAILED(hr)) { 00056 _log.warning("VMR-9 setup failed(failed set streams)"); 00057 return false; 00058 } 00059 00060 IVMRSurfaceAllocatorNotify9 *allocatorNotify; 00061 _vmr9->QueryInterface(&allocatorNotify); 00062 if (FAILED(hr)) { 00063 SAFE_RELEASE(fc); 00064 _log.warning("failed surface allocator not created"); 00065 return false; 00066 } 00067 00068 // VMR-9にカスタムアロケータを通知 00069 _allocator = new VideoTextureAllocator(_renderer); 00070 // s->allocator->setSurfacePrepareInterval(1); 00071 hr = allocatorNotify->AdviseSurfaceAllocator(0, _allocator); 00072 if (FAILED(hr)) { 00073 SAFE_RELEASE(allocatorNotify); 00074 SAFE_RELEASE(fc); 00075 _log.warning("failed advise surface allocator"); 00076 return false; 00077 } 00078 00079 // アロケータにVMR-9に登録したことを通知 00080 hr = _allocator->AdviseNotify(allocatorNotify); 00081 if (FAILED(hr)) { 00082 SAFE_RELEASE(allocatorNotify); 00083 SAFE_RELEASE(fc); 00084 _log.warning("failed not advised notify surface allocator"); 00085 return false; 00086 } 00087 00088 hr = fc->SetImageCompositor(_allocator); 00089 if (FAILED(hr)) { 00090 SAFE_RELEASE(allocatorNotify); 00091 SAFE_RELEASE(fc); 00092 _log.warning("***ImageCompositor creation failed"); 00093 return false; 00094 } 00095 SAFE_RELEASE(allocatorNotify); 00096 SAFE_RELEASE(fc); 00097 00098 hr = _gb->AddFilter(_vmr9, L"VMR-9"); 00099 if (FAILED(hr)) { 00100 _log.warning("failed not add VMR-9"); 00101 return false; 00102 } 00103 00104 00105 00106 } else { 00107 _vr = new DSVideoRenderer(_renderer, false, NULL, &hr); 00108 if (FAILED(hr = _gb->AddFilter(_vr, L"DSVideoRenderer"))) { 00109 _log.warning(Poco::format("failed add filter: hr=0x%lx", hr)); 00110 return false; 00111 } 00112 } 00113 00114 MediaItemFile mif = media->files()[offset]; 00115 wstring wfile; 00116 Poco::UnicodeConverter::toUTF16(Path(mif.file()).absolute(config().dataRoot).toString(), wfile); 00117 IBaseFilter* src = NULL; 00118 hr = _gb->AddSourceFilter(wfile.c_str(), L"File Source", &src); 00119 if (SUCCEEDED(hr) && src) { 00120 IPin* srcOut = NULL; 00121 if (getOutPin(src, &srcOut)) { 00122 hr = _gb->Render(srcOut); 00123 SAFE_RELEASE(srcOut); 00124 if SUCCEEDED(hr) { 00125 while (getOutPin(src, &srcOut)) { 00126 // ソースから複数の出力ピンが出てる場合を考慮… 00127 hr = _gb->Render(srcOut); 00128 SAFE_RELEASE(srcOut); 00129 if (FAILED(hr)) { 00130 _log.warning("multi src out pin rendering failed"); 00131 break; 00132 } 00133 } 00134 _log.information("rendered outpin"); 00135 } else { 00136 _log.warning("failed render outpin"); 00137 } 00138 } else { 00139 _log.warning("not found outpin"); 00140 } 00141 } else if (hr == VFW_E_NOT_FOUND) { 00142 _log.warning(Poco::format("source not found: %s", mif.file())); 00143 } else { 00144 _log.warning(Poco::format("failed add source filter: %s", mif.file())); 00145 } 00146 SAFE_RELEASE(src); 00147 if FAILED(hr) { 00148 return false; 00149 } 00150 if (dumpFilter(_gb) > 0) { 00151 _log.warning("failed lookup another video renderer"); 00152 return false; 00153 } 00154 00155 hr = _gb->QueryInterface(&_mc); 00156 if (FAILED(hr)) { 00157 _log.warning("failed query interface: IMediaControl"); 00158 return false; 00159 } 00160 hr = _mc->Pause(); 00161 00162 hr = _gb->QueryInterface(&_ms); 00163 if (FAILED(hr)) { 00164 _log.warning("failed query interface: IMediaSeeking"); 00165 return false; 00166 } 00167 hr = _gb->QueryInterface(&_me); 00168 if (FAILED(hr)) { 00169 _log.warning("failed query interface: IMediaEvent"); 00170 return false; 00171 } 00172 00173 set("alpha", 1.0f); 00174 LONGLONG duration; 00175 hr = _ms->GetStopPosition(&duration); 00176 if (SUCCEEDED(hr)) { 00177 _duration = duration / 100000; 00178 _log.information(Poco::format("duration: %d", _duration)); 00179 } 00180 _current = 0; 00181 _mediaID = media->id(); 00182 _finished = false; 00183 return true; 00184 } 00185 00189 void DSContent::play() { 00190 if (_mc) activePlay(); 00191 } 00192 00193 void DSContent::syncronizedPlay() { 00194 if (_mc) { 00195 HRESULT hr = _mc->Run(); 00196 _playing = true; 00197 } 00198 } 00199 00203 void DSContent::stop() { 00204 if (_mc) { 00205 HRESULT hr = _mc->Stop(); 00206 } 00207 _playing = false; 00208 } 00209 00213 const bool DSContent::playing() const { 00214 return _playing; 00215 } 00216 00217 const bool DSContent::finished() { 00218 return _finished; 00219 } 00220 00222 void DSContent::close() { 00223 stop(); 00224 SAFE_RELEASE(_me); 00225 SAFE_RELEASE(_ms); 00226 SAFE_RELEASE(_mc); 00227 SAFE_RELEASE(_vr); 00228 SAFE_RELEASE(_vmr9); 00229 SAFE_RELEASE(_gb); 00230 _mediaID.clear(); 00231 //CoUninitialize(); 00232 } 00233 00234 void DSContent::process(const DWORD& frame) { 00235 if (_ms) { 00236 LONGLONG current; 00237 LONGLONG stop; 00238 _ms->GetPositions(¤t, &stop); 00239 _current = current / 100000; 00240 //_duration = stop / 100000; 00241 } 00242 if (_me) { 00243 long eventCode; 00244 long param1; 00245 long param2; 00246 HRESULT hr = _me->GetEvent(&eventCode, (LONG_PTR*)¶m1, (LONG_PTR*)¶m2, 0); 00247 if (SUCCEEDED(hr)) { 00248 if (EC_COMPLETE == eventCode) { 00249 // hr = _mp->put_CurrentPosition(0); 00250 _finished = true; 00251 } 00252 hr = _me->FreeEventParams(eventCode, param1, param2); 00253 } 00254 } 00255 00256 int fps = 0; 00257 if (_vr) { 00258 _vr->get_AvgFrameRate(&fps); 00259 set("status", Poco::format("%03.2hffps(%03lums)", fps / F(100), _vr->readTime())); 00260 } 00261 00262 unsigned long cu = _current / 100; 00263 unsigned long re = (_duration - _current) / 100; 00264 string t1 = Poco::format("%02lu:%02lu:%02lu.%02d", cu / 3600, cu / 60, cu % 60, _current % 100); 00265 string t2 = Poco::format("%02lu:%02lu:%02lu.%02d", re / 3600, re / 60, re % 60, (_duration - _current) % 100); 00266 set("time", Poco::format("%s %s", t1, t2)); 00267 set("time_current", t1); 00268 set("time_remain", t2); 00269 } 00270 00271 void DSContent::draw(const DWORD& frame) { 00272 if (!_mediaID.empty() && _playing) { 00273 LPDIRECT3DDEVICE9 device = _renderer.get3DDevice(); 00274 float alpha = getF("alpha"); 00275 int cw = config().splitSize.cx; 00276 int ch = config().splitSize.cy; 00277 DWORD col = ((DWORD)(0xff * alpha) << 24) | 0xffffff; 00278 if (_vr) { 00279 switch (_splitType) { 00280 case 1: 00281 { 00282 int sx = 0, sy = 0, dx = 0, dy = 0; 00283 int cww = 0; 00284 int chh = ch; 00285 while (dx < config().mainRect.right) { 00286 if ((sx + cw) >= _vr->width()) { 00287 // はみ出る 00288 cww = _vr->width() - sx; 00289 _vr->draw(dx, dy, cww, chh, 0, 2, col, sx, sy, cww, chh); 00290 sx = 0; 00291 sy += ch; 00292 if (sy >= _vr->height()) break; 00293 if (_vr->height() - sy < ch) chh = _vr->height() - sy; 00294 // クイの分 00295 _vr->draw(dx + cww, dy, cw - cww, chh, 0, 2, col, sx, sy, cw - cww, chh); 00296 sx += (cw - cww); 00297 } else { 00298 _vr->draw(dx, dy, cw, chh, 0, 2, col, sx, sy, cw, chh); 00299 sx += cw; 00300 } 00301 // _log.information(Poco::format("split dst: %04d,%03d src: %04d,%03d", dx, dy, sx, sy)); 00302 dy += ch; 00303 if (dy >= config().stageRect.bottom * config().splitCycles) { 00304 dx += cw; 00305 dy = 0; 00306 } 00307 } 00308 } 00309 break; 00310 00311 case 2: 00312 { 00313 int sw = L(_w / cw); 00314 if (sw <= 0) sw = 1; 00315 int sh = L(_h / ch); 00316 if (sh <= 0) sh = 1; 00317 for (int sy = 0; sy < sh; sy++) { 00318 int ox = (sy % 2) * cw * 8 + config().stageRect.left; 00319 int oy = (sy / 2) * ch * 4 + config().stageRect.top; 00320 // int ox = (sy % 2) * cw * 8; 00321 // int oy = (sy / 2) * ch * 4; 00322 for (int sx = 0; sx < sw; sx++) { 00323 int dx = (sx / 4) * cw; 00324 int dy = ch * 3 - (sx % 4) * ch; 00325 _vr->draw(ox + dx, oy + dy, cw, ch, 0, 2, col, sx * cw, sy * ch, cw, ch); 00326 // _renderer.drawTexture(ox + dx, oy + dy, cw, ch, sx * cw, sy * ch, cw, ch, _target, col, col, col, col); 00327 } 00328 } 00329 } 00330 break; 00331 00332 case 11: 00333 { 00334 if (_vr->height() == 120) { 00335 _vr->draw(0, 360, 320, 120, 0, 2, col, 2880, 0, 320, 120); 00336 _vr->draw(0, 240, 960, 120, 0, 2, col, 1920, 0, 960, 120); 00337 _vr->draw(0, 120, 960, 120, 0, 2, col, 960, 0, 960, 120); 00338 _vr->draw(0, 0, 960, 120, 0, 2, col, 0, 0, 960, 120); 00339 } else { 00340 int w = config().mainRect.right; 00341 int h = config().mainRect.bottom; 00342 if (_vr->width() > w || _vr->height() > h) { 00343 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00344 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00345 _vr->draw( 0, 0, w, h, 1, 2, col); 00346 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00347 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00348 } else { 00349 _vr->draw(0, 0, -1, -1, 0, 2, col); 00350 } 00351 } 00352 } 00353 break; 00354 default: 00355 { 00356 RECT rect = config().stageRect; 00357 string aspectMode = get("aspect-mode"); 00358 if (aspectMode == "fit") { 00359 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00360 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00361 _vr->draw(L(_x), L(_y), L(_w), L(_h), 0, col); 00362 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00363 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00364 00365 } else { 00366 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00367 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00368 if (alpha > 0.0f) { 00369 DWORD base = ((DWORD)(0xff * alpha) << 24) | 0x000000; 00370 _renderer.drawTexture(_x, _y, _w, _h, NULL, 0, base, base, base, base); 00371 float dar = _vr->getDisplayAspectRatio(); 00372 if (_h * dar > _w) { 00373 // 画角よりディスプレイサイズは横長 00374 long h = _w / dar; 00375 long dy = (_h - h) / 2; 00376 _vr->draw(L(_x), L(_y + dy), L(_w), h, 0, 2, col); 00377 } else { 00378 long w = _h * dar; 00379 long dx = (_w - w) / 2; 00380 _vr->draw(L(_x + dx), L(_y), w, L(_h), 0, 2, col); 00381 } 00382 } 00383 00384 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00385 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00386 } 00387 } 00388 break; 00389 } 00390 } else if (_allocator) { 00391 LPDIRECT3DTEXTURE9 texture = _allocator->getTexture(); 00392 switch (_splitType) { 00393 default: 00394 { 00395 RECT rect = config().stageRect; 00396 string aspectMode = get("aspect-mode"); 00397 if (aspectMode == "fit") { 00398 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00399 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00400 _renderer.drawTexture(L(_x), L(_y), L(_w), L(_h), texture, 0, col, col, col, col); 00401 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00402 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00403 00404 } else { 00405 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 00406 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 00407 if (alpha > 0.0f) { 00408 DWORD base = ((DWORD)(0xff * alpha) << 24) | 0x000000; 00409 _renderer.drawTexture(_x, _y, _w, _h, NULL, 0, base, base, base, base); 00410 float dar = _allocator->getDisplayAspectRatio(); 00411 if (_h * dar > _w) { 00412 // 画角よりディスプレイサイズは横長 00413 long h = _w / dar; 00414 long dy = (_h - h) / 2; 00415 _renderer.drawTexture(L(_x), L(_y + dy), L(_w), h, texture, 0, col, col, col, col); 00416 } else { 00417 long w = _h * dar; 00418 long dx = (_w - w) / 2; 00419 _renderer.drawTexture(L(_x + dx), L(_y), w, L(_h), texture, 0, col, col, col, col); 00420 } 00421 } 00422 device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 00423 device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 00424 } 00425 } 00426 break; 00427 } 00428 } 00429 } 00430 } 00431 00432 int DSContent::getPinCount(IBaseFilter* pFilter, PIN_DIRECTION PinDir) { 00433 int count = 0; 00434 IEnumPins* pEnum = NULL; 00435 HRESULT hr = pFilter->EnumPins(&pEnum); 00436 if (SUCCEEDED(hr)) { 00437 IPin* pin = NULL; 00438 while (pEnum->Next(1, &pin, 0) == S_OK) { 00439 PIN_DIRECTION PinDirThis; 00440 pin->QueryDirection(&PinDirThis); 00441 if (PinDir == PinDirThis) count++; 00442 SAFE_RELEASE(pin); 00443 } 00444 // ピンの参照は残したまま戻す 00445 SAFE_RELEASE(pEnum); 00446 } 00447 return count; 00448 } 00449 00450 bool DSContent::getPin(IBaseFilter *pFilter, IPin** pPin, PIN_DIRECTION PinDir, int index) { 00451 bool bFound = false; 00452 IEnumPins *pEnum = NULL; 00453 HRESULT hr = pFilter->EnumPins(&pEnum); 00454 if (SUCCEEDED(hr)) { 00455 int i = 0; 00456 while (!bFound && pEnum->Next(1, pPin, 0) == S_OK) { 00457 PIN_DIRECTION PinDirThis; 00458 (*pPin)->QueryDirection(&PinDirThis); 00459 if (PinDir == PinDirThis) { 00460 IPin *pToPin = NULL; 00461 hr = (*pPin)->ConnectedTo(&pToPin); 00462 if (SUCCEEDED(hr)) { 00463 SAFE_RELEASE(pToPin); 00464 SAFE_RELEASE(*pPin); 00465 } else if (hr == VFW_E_NOT_CONNECTED) { 00466 if (index == -1 || i == index) bFound = true; 00467 } 00468 } 00469 i++; 00470 } 00471 // ピンの参照は残したまま戻す 00472 SAFE_RELEASE(pEnum); 00473 } 00474 return bFound; 00475 } 00476 00477 /* 指定したフィルタの入力ピンを返します */ 00478 bool DSContent::getInPin(IBaseFilter *pFilter, IPin** pPin, int index) { 00479 return getPin(pFilter, pPin, PINDIR_INPUT, index); 00480 } 00481 00482 /* 指定したフィルタの出力ピンを返します */ 00483 bool DSContent::getOutPin(IBaseFilter *pFilter, IPin** pPin, int index) { 00484 return getPin(pFilter, pPin, PINDIR_OUTPUT, index); 00485 } 00486 00491 int DSContent::dumpFilter(IGraphBuilder* gb) { 00492 if (!gb) return 0; 00493 00494 IEnumFilters *pEnum = NULL; 00495 HRESULT hr = gb->EnumFilters(&pEnum); 00496 00497 int count = 0; 00498 int vcount = 0; 00499 IBaseFilter *pFilter = NULL; 00500 while (pEnum->Next(1, &pFilter, 0) == S_OK) { 00501 FILTER_INFO info; 00502 HRESULT hr = pFilter->QueryFilterInfo(&info); 00503 if (SUCCEEDED(hr)) { 00504 wstring wname(info.achName); 00505 string name; 00506 Poco::UnicodeConverter::toUTF8(wname, name); 00507 _log.information(Poco::format("filter: %s", name)); 00508 SAFE_RELEASE(info.pGraph); 00509 } 00510 IVideoWindow *vw; 00511 hr = pFilter->QueryInterface(&vw); 00512 if (SUCCEEDED(hr) && vw != NULL) { 00513 vcount++; 00514 SAFE_RELEASE(vw); 00515 } 00516 SAFE_RELEASE(pFilter); 00517 count++; 00518 } 00519 SAFE_RELEASE(pEnum); 00520 _log.information(Poco::format("dump filters: %d(in windowed filters: %d)", count, vcount)); 00521 return vcount; 00522 }