DSDisplayGraph.cxx 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /* Copyright (C) 2011-2013 Doubango Telecom <http://www.doubango.org>
  2. *
  3. * This file is part of Open Source Doubango Framework.
  4. *
  5. * DOUBANGO is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * DOUBANGO is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with DOUBANGO.
  17. */
  18. #if defined(VMR9)
  19. #define DIRECT3D_VERSION 0x0900
  20. #endif
  21. #include "internals/DSDisplayGraph.h"
  22. #include "internals/DSUtils.h"
  23. #include "internals/DSOutputFilter.h"
  24. #include "tsk_debug.h"
  25. #include <iostream>
  26. using namespace std;
  27. DSDisplayGraph::DSDisplayGraph(HRESULT *hr)
  28. {
  29. this->running = FALSE;
  30. this->paused = FALSE;
  31. this->fps = 15;
  32. this->graphBuilder = NULL;
  33. this->sourceFilter = NULL;
  34. this->colorspaceConverterFilter = NULL;
  35. this->videoRendererFilter = NULL;
  36. this->mediaController = NULL;
  37. this->mediaEvent = NULL;
  38. this->videoWindow = NULL;
  39. #if defined(VMR) ||defined(VMR9) || defined(VMR9_WINDOWLESS)
  40. this->mixerBitmap = NULL;
  41. this->filterConfig = NULL;
  42. #endif
  43. #if defined(VMR9_WINDOWLESS)
  44. this->windowlessControl = NULL;
  45. #endif
  46. *hr = this->createDisplayGraph();
  47. if (FAILED(*hr)) {
  48. return;
  49. }
  50. *hr = this->connect();
  51. if (FAILED(*hr)) {
  52. return;
  53. }
  54. }
  55. DSDisplayGraph::~DSDisplayGraph()
  56. {
  57. this->disconnect();
  58. #if defined(VMR9_WINDOWLESS)
  59. SAFE_RELEASE(this->windowlessControl);
  60. #endif
  61. #if defined(VMR) ||defined(VMR9) || defined(VMR9_WINDOWLESS)
  62. SAFE_RELEASE(this->filterConfig);
  63. SAFE_RELEASE(this->mixerBitmap);
  64. #endif
  65. SAFE_RELEASE(this->videoWindow);
  66. SAFE_RELEASE(this->mediaEvent);
  67. SAFE_RELEASE(this->mediaController);
  68. SAFE_RELEASE(this->colorspaceConverterFilter);
  69. SAFE_RELEASE(this->videoRendererFilter);
  70. //SAFE_RELEASE(this->sourceFilter);
  71. SAFE_RELEASE(this->graphBuilder);
  72. }
  73. void DSDisplayGraph::setDisplayFps(int fps_)
  74. {
  75. this->fps = fps_;
  76. if(this->sourceFilter) {
  77. this->sourceFilter->setFps(fps_);
  78. }
  79. }
  80. bool DSDisplayGraph::getImageFormat(UINT &width, UINT &height)
  81. {
  82. if(this->sourceFilter) {
  83. return this->sourceFilter->getImageFormat(width, height);
  84. }
  85. return false;
  86. }
  87. bool DSDisplayGraph::setImageFormat(UINT width, UINT height)
  88. {
  89. bool ret = true;
  90. if(this->sourceFilter) {
  91. UINT w=width, h = height;
  92. if(this->sourceFilter->getImageFormat(w, h)) {
  93. if(w!= width || h!=height) { // Image format has changed
  94. bool reconnect = this->connected; // IMPORTANT: Must reconnect all elements
  95. HRESULT hr;
  96. if(reconnect) {
  97. if((hr = this->disconnect()) != S_OK) {
  98. return false;
  99. }
  100. }
  101. ret = (this->sourceFilter->setImageFormat(width, height) == S_OK);
  102. if(reconnect) {
  103. if((hr = this->connect())) {
  104. return false;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. return ret;
  111. }
  112. HRESULT DSDisplayGraph::connect()
  113. {
  114. HRESULT hr;
  115. if((hr = ConnectFilters(this->graphBuilder, this->sourceFilter, this->colorspaceConverterFilter)) != S_OK) {
  116. TSK_DEBUG_ERROR("Failed to connect sourcefilter with the colorspace");
  117. return hr;
  118. }
  119. if((hr = ConnectFilters(this->graphBuilder, this->colorspaceConverterFilter, this->videoRendererFilter)) != S_OK) {
  120. TSK_DEBUG_ERROR("Failed to connect colorspace with the videorenderer");
  121. return hr;
  122. }
  123. this->connected = true;
  124. return S_OK;
  125. }
  126. HRESULT DSDisplayGraph::disconnect()
  127. {
  128. HRESULT hr;
  129. if((hr = DisconnectFilters(this->graphBuilder, this->sourceFilter, this->colorspaceConverterFilter)) != S_OK) {
  130. TSK_DEBUG_ERROR("Failed to disconnect sourcefilter with the colorspace");
  131. return hr;
  132. }
  133. if((hr = DisconnectFilters(this->graphBuilder, this->colorspaceConverterFilter, this->videoRendererFilter)) != S_OK) {
  134. TSK_DEBUG_ERROR("Failed to connect colorspace with the videorenderer");
  135. return hr;
  136. }
  137. this->connected = false;
  138. return S_OK;
  139. }
  140. HRESULT DSDisplayGraph::start()
  141. {
  142. HRESULT hr;
  143. this->running = true;
  144. this->sourceFilter->reset();
  145. hr = this->mediaController->Run();
  146. if (!SUCCEEDED(hr)) {
  147. TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Run() has failed with %ld", hr);
  148. }
  149. return hr;
  150. }
  151. HRESULT DSDisplayGraph::pause()
  152. {
  153. HRESULT hr = S_OK;
  154. if(isRunning() && !isPaused()) {
  155. hr = this->mediaController->Pause();
  156. if(SUCCEEDED(hr)) {
  157. this->paused = true;
  158. }
  159. }
  160. return hr;
  161. }
  162. HRESULT DSDisplayGraph::stop()
  163. {
  164. HRESULT hr;
  165. hr = this->mediaController->Pause();
  166. if (hr == S_FALSE) {
  167. TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Pause() has failed with %ld. Waiting for transition.", hr);
  168. FILTER_STATE pfs;
  169. hr = this->mediaController->GetState(2500, (OAFilterState*) &pfs);
  170. }
  171. hr = this->mediaController->Stop();
  172. if (!SUCCEEDED(hr)) {
  173. TSK_DEBUG_ERROR("DSDisplayGraph::mediaController->Stop() has failed with %ld", hr);
  174. }
  175. this->running = false;
  176. this->paused = false;
  177. return hr;
  178. }
  179. bool DSDisplayGraph::isRunning()
  180. {
  181. return this->running;
  182. }
  183. bool DSDisplayGraph::isPaused()
  184. {
  185. return this->paused;
  186. }
  187. void DSDisplayGraph::handleFrame(const void* data, int w, int h)
  188. {
  189. HRESULT hr;
  190. if(!this->sourceFilter) {
  191. TSK_DEBUG_ERROR("Invalid parameter");
  192. return;
  193. }
  194. if(!data || !this->running) {
  195. this->sourceFilter->setBuffer(NULL, (w*h*3));
  196. return;
  197. }
  198. hr = this->sourceFilter->setImageFormat(w, h);
  199. if (hr == S_OK) {
  200. this->stop();
  201. this->disconnect();
  202. this->connect();
  203. this->start();
  204. }
  205. this->sourceFilter->setBuffer((void*)data, (w*h*3));
  206. }
  207. HRESULT DSDisplayGraph::createDisplayGraph()
  208. {
  209. HRESULT hr;
  210. // Create the graph builder
  211. hr = COCREATE(CLSID_FilterGraph, IID_IGraphBuilder, this->graphBuilder);
  212. if(FAILED(hr)) {
  213. return hr;
  214. }
  215. // Create my custom filter
  216. LPUNKNOWN pUnk = NULL;
  217. this->sourceFilter = new DSOutputFilter(pUnk, &hr /*, this*/);
  218. if(FAILED(hr) || this->sourceFilter == NULL) {
  219. return hr;
  220. }
  221. // Create the color space convertor filter
  222. hr = COCREATE(CLSID_Colour, IID_IBaseFilter, this->colorspaceConverterFilter);
  223. if(FAILED(hr)) {
  224. return hr;
  225. }
  226. #if defined(VMR)
  227. // Create the video mixing renderer based on Direct X
  228. hr = COCREATE(CLSID_VideoMixingRenderer, IID_IBaseFilter, this->videoRendererFilter);
  229. if(FAILED(hr)) {
  230. return hr;
  231. }
  232. #elif defined(VMR9) || defined(VMR9_WINDOWLESS)
  233. // Create the video mixing renderer based on Direct X 9.0
  234. hr = COCREATE(CLSID_VideoMixingRenderer9, IID_IBaseFilter, this->videoRendererFilter);
  235. if(FAILED(hr)) {
  236. return hr;
  237. }
  238. #else
  239. // Create the video renderer
  240. hr = COCREATE(CLSID_VideoRenderer, IID_IBaseFilter, this->videoRendererFilter);
  241. if(FAILED(hr)) {
  242. return hr;
  243. }
  244. #endif
  245. // Add dource filter to the graph
  246. hr = this->graphBuilder->AddFilter(this->sourceFilter, FILTER_OUTPUT);
  247. if(FAILED(hr)) {
  248. return hr;
  249. }
  250. // Add the color space convertor to the graph
  251. hr = this->graphBuilder->AddFilter(this->colorspaceConverterFilter, FILTER_COLORSPACE_CONVERTOR);
  252. if(FAILED(hr)) {
  253. return hr;
  254. }
  255. // Add video renderer to the graph
  256. hr = this->graphBuilder->AddFilter(this->videoRendererFilter, FILTER_VIDEO_RENDERER);
  257. if(FAILED(hr)) {
  258. return hr;
  259. }
  260. // Find media control
  261. hr = QUERY(this->graphBuilder, IID_IMediaControl, this->mediaController);
  262. if(FAILED(hr)) {
  263. return hr;
  264. }
  265. // Find media event
  266. hr = QUERY(this->graphBuilder, IID_IMediaEventEx, this->mediaEvent);
  267. if(FAILED(hr)) {
  268. return hr;
  269. }
  270. // hr = this->mediaEvent->SetNotifyFlags(AM_MEDIAEVENT_NONOTIFY);
  271. #if defined(VMR)
  272. // Find the bitmap mixer (Direct X)
  273. hr = QUERY(this->videoRendererFilter, IID_IVMRMixerBitmap, this->mixerBitmap);
  274. if(FAILED(hr)) {
  275. return hr;
  276. }
  277. // Find the bitmap configurer (Direct X)
  278. hr = QUERY(this->videoRendererFilter, IID_IVMRFilterConfig, this->filterConfig);
  279. if(FAILED(hr)) {
  280. return hr;
  281. }
  282. // Set the number of streams (Direct X)
  283. hr = this->filterConfig->SetNumberOfStreams(1);
  284. if(FAILED(hr)) {
  285. return hr;
  286. }
  287. #elif defined(VMR9) || defined(VMR9_WINDOWLESS)
  288. // Find the bitmap mixer (Direct X 9.0)
  289. hr = QUERY(this->videoRendererFilter, IID_IVMRMixerBitmap9, this->mixerBitmap);
  290. if(FAILED(hr)) {
  291. return hr;
  292. }
  293. // Find the bitmap configurer (Direct X 9.0)
  294. hr = QUERY(this->videoRendererFilter, IID_IVMRFilterConfig9, this->filterConfig);
  295. if(FAILED(hr)) {
  296. return hr;
  297. }
  298. // Set the number of streams (Direct X 9.0)
  299. hr = this->filterConfig->SetNumberOfStreams(1);
  300. if(FAILED(hr)) {
  301. return hr;
  302. }
  303. #endif
  304. #if defined(VMR9_WINDOWLESS)
  305. // Set the rendering mode (Direct X 9.0)
  306. hr = this->filterConfig->SetRenderingMode(VMR9Mode_Windowless);
  307. if(FAILED(hr)) {
  308. return hr;
  309. }
  310. // Find the windowless control (Direct X 9.0)
  311. hr = QUERY(this->videoRendererFilter, IID_IVMRWindowlessControl9, this->windowlessControl);
  312. if(FAILED(hr)) {
  313. return hr;
  314. }
  315. #else
  316. // Find IVideoWindow interface
  317. hr = QUERY(this->graphBuilder, IID_IVideoWindow, this->videoWindow);
  318. if(FAILED(hr)) {
  319. return hr;
  320. }
  321. #endif
  322. return hr;
  323. }