svvitch
digital signage player
D:/vs_workspace/switch_sf/src/svvitch/DSContent.cpp
Go to the documentation of this file.
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(&current, &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*)&param1, (LONG_PTR*)&param2, 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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines