OcvTransform.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. #include "OcvTransform.h"
  8. #include "bufferlock.h"
  9. #include <opencv2\core.hpp>
  10. #include <opencv2\imgproc.hpp>
  11. #include <opencv2\features2d.hpp>
  12. using namespace Microsoft::WRL;
  13. /*
  14. This sample implements a video effect as a Media Foundation transform (MFT).
  15. NOTES ON THE MFT IMPLEMENTATION
  16. 1. The MFT has fixed streams: One input stream and one output stream.
  17. 2. The MFT supports NV12 format only.
  18. 3. If the MFT is holding an input sample, SetInputType and SetOutputType both fail.
  19. 4. The input and output types must be identical.
  20. 5. If both types are set, no type can be set until the current type is cleared.
  21. 6. Preferred input types:
  22. (a) If the output type is set, that's the preferred type.
  23. (b) Otherwise, the preferred types are partial types, constructed from the
  24. list of supported subtypes.
  25. 7. Preferred output types: As above.
  26. 8. Streaming:
  27. The private BeingStreaming() method is called in response to the
  28. MFT_MESSAGE_NOTIFY_BEGIN_STREAMING message.
  29. If the client does not send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, the MFT calls
  30. BeginStreaming inside the first call to ProcessInput or ProcessOutput.
  31. This is a good approach for allocating resources that your MFT requires for
  32. streaming.
  33. 9. The configuration attributes are applied in the BeginStreaming method. If the
  34. client changes the attributes during streaming, the change is ignored until
  35. streaming is stopped (either by changing the media types or by sending the
  36. MFT_MESSAGE_NOTIFY_END_STREAMING message) and then restarted.
  37. */
  38. // Static array of media types (preferred and accepted).
  39. const GUID g_MediaSubtypes[] =
  40. {
  41. MFVideoFormat_NV12
  42. };
  43. HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride);
  44. template <typename T>
  45. inline T clamp(const T& val, const T& minVal, const T& maxVal)
  46. {
  47. return (val < minVal ? minVal : (val > maxVal ? maxVal : val));
  48. }
  49. OcvImageManipulations::OcvImageManipulations() :
  50. m_pSample(NULL), m_pInputType(NULL), m_pOutputType(NULL),
  51. m_imageWidthInPixels(0), m_imageHeightInPixels(0), m_cbImageSize(0),
  52. m_TransformType(Preview), m_bStreamingInitialized(false),
  53. m_pAttributes(NULL)
  54. {
  55. InitializeCriticalSectionEx(&m_critSec, 3000, 0);
  56. }
  57. OcvImageManipulations::~OcvImageManipulations()
  58. {
  59. SafeRelease(&m_pInputType);
  60. SafeRelease(&m_pOutputType);
  61. SafeRelease(&m_pSample);
  62. SafeRelease(&m_pAttributes);
  63. DeleteCriticalSection(&m_critSec);
  64. }
  65. // Initialize the instance.
  66. STDMETHODIMP OcvImageManipulations::RuntimeClassInitialize()
  67. {
  68. // Create the attribute store.
  69. return MFCreateAttributes(&m_pAttributes, 3);
  70. }
  71. // IMediaExtension methods
  72. //-------------------------------------------------------------------
  73. // SetProperties
  74. // Sets the configuration of the effect
  75. //-------------------------------------------------------------------
  76. HRESULT OcvImageManipulations::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
  77. {
  78. HRESULT hr = S_OK;
  79. if (!pConfiguration)
  80. return hr;
  81. HSTRING key;
  82. WindowsCreateString(L"{698649BE-8EAE-4551-A4CB-3EC98FBD3D86}", 38, &key);
  83. Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
  84. pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
  85. boolean found;
  86. spSetting->HasKey(key, &found);
  87. if (found)
  88. {
  89. Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropVal;
  90. Microsoft::WRL::ComPtr<IInspectable> spInsp;
  91. spSetting->Lookup(key, spInsp.ReleaseAndGetAddressOf());
  92. hr = spInsp.As(&spPropVal);
  93. if (hr != S_OK)
  94. {
  95. return hr;
  96. }
  97. INT32 effect;
  98. hr = spPropVal->GetInt32(&effect);
  99. if (hr != S_OK)
  100. {
  101. return hr;
  102. }
  103. if ((effect >= 0) && (effect < InvalidEffect))
  104. {
  105. m_TransformType = (ProcessingType)effect;
  106. }
  107. }
  108. return hr;
  109. }
  110. // IMFTransform methods. Refer to the Media Foundation SDK documentation for details.
  111. //-------------------------------------------------------------------
  112. // GetStreamLimits
  113. // Returns the minimum and maximum number of streams.
  114. //-------------------------------------------------------------------
  115. HRESULT OcvImageManipulations::GetStreamLimits(
  116. DWORD *pdwInputMinimum,
  117. DWORD *pdwInputMaximum,
  118. DWORD *pdwOutputMinimum,
  119. DWORD *pdwOutputMaximum
  120. )
  121. {
  122. if ((pdwInputMinimum == NULL) ||
  123. (pdwInputMaximum == NULL) ||
  124. (pdwOutputMinimum == NULL) ||
  125. (pdwOutputMaximum == NULL))
  126. {
  127. return E_POINTER;
  128. }
  129. // This MFT has a fixed number of streams.
  130. *pdwInputMinimum = 1;
  131. *pdwInputMaximum = 1;
  132. *pdwOutputMinimum = 1;
  133. *pdwOutputMaximum = 1;
  134. return S_OK;
  135. }
  136. //-------------------------------------------------------------------
  137. // GetStreamCount
  138. // Returns the actual number of streams.
  139. //-------------------------------------------------------------------
  140. HRESULT OcvImageManipulations::GetStreamCount(
  141. DWORD *pcInputStreams,
  142. DWORD *pcOutputStreams
  143. )
  144. {
  145. if ((pcInputStreams == NULL) || (pcOutputStreams == NULL))
  146. {
  147. return E_POINTER;
  148. }
  149. // This MFT has a fixed number of streams.
  150. *pcInputStreams = 1;
  151. *pcOutputStreams = 1;
  152. return S_OK;
  153. }
  154. //-------------------------------------------------------------------
  155. // GetStreamIDs
  156. // Returns stream IDs for the input and output streams.
  157. //-------------------------------------------------------------------
  158. HRESULT OcvImageManipulations::GetStreamIDs(
  159. DWORD dwInputIDArraySize,
  160. DWORD *pdwInputIDs,
  161. DWORD dwOutputIDArraySize,
  162. DWORD *pdwOutputIDs
  163. )
  164. {
  165. // It is not required to implement this method if the MFT has a fixed number of
  166. // streams AND the stream IDs are numbered sequentially from zero (that is, the
  167. // stream IDs match the stream indexes).
  168. // In that case, it is OK to return E_NOTIMPL.
  169. return E_NOTIMPL;
  170. }
  171. //-------------------------------------------------------------------
  172. // GetInputStreamInfo
  173. // Returns information about an input stream.
  174. //-------------------------------------------------------------------
  175. HRESULT OcvImageManipulations::GetInputStreamInfo(
  176. DWORD dwInputStreamID,
  177. MFT_INPUT_STREAM_INFO * pStreamInfo
  178. )
  179. {
  180. if (pStreamInfo == NULL)
  181. {
  182. return E_POINTER;
  183. }
  184. EnterCriticalSection(&m_critSec);
  185. if (!IsValidInputStream(dwInputStreamID))
  186. {
  187. LeaveCriticalSection(&m_critSec);
  188. return MF_E_INVALIDSTREAMNUMBER;
  189. }
  190. // NOTE: This method should succeed even when there is no media type on the
  191. // stream. If there is no media type, we only need to fill in the dwFlags
  192. // member of MFT_INPUT_STREAM_INFO. The other members depend on having a
  193. // a valid media type.
  194. pStreamInfo->hnsMaxLatency = 0;
  195. pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
  196. if (m_pInputType == NULL)
  197. {
  198. pStreamInfo->cbSize = 0;
  199. }
  200. else
  201. {
  202. pStreamInfo->cbSize = m_cbImageSize;
  203. }
  204. pStreamInfo->cbMaxLookahead = 0;
  205. pStreamInfo->cbAlignment = 0;
  206. LeaveCriticalSection(&m_critSec);
  207. return S_OK;
  208. }
  209. //-------------------------------------------------------------------
  210. // GetOutputStreamInfo
  211. // Returns information about an output stream.
  212. //-------------------------------------------------------------------
  213. HRESULT OcvImageManipulations::GetOutputStreamInfo(
  214. DWORD dwOutputStreamID,
  215. MFT_OUTPUT_STREAM_INFO * pStreamInfo
  216. )
  217. {
  218. if (pStreamInfo == NULL)
  219. {
  220. return E_POINTER;
  221. }
  222. EnterCriticalSection(&m_critSec);
  223. if (!IsValidOutputStream(dwOutputStreamID))
  224. {
  225. LeaveCriticalSection(&m_critSec);
  226. return MF_E_INVALIDSTREAMNUMBER;
  227. }
  228. // NOTE: This method should succeed even when there is no media type on the
  229. // stream. If there is no media type, we only need to fill in the dwFlags
  230. // member of MFT_OUTPUT_STREAM_INFO. The other members depend on having a
  231. // a valid media type.
  232. pStreamInfo->dwFlags =
  233. MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
  234. MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
  235. MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE ;
  236. if (m_pOutputType == NULL)
  237. {
  238. pStreamInfo->cbSize = 0;
  239. }
  240. else
  241. {
  242. pStreamInfo->cbSize = m_cbImageSize;
  243. }
  244. pStreamInfo->cbAlignment = 0;
  245. LeaveCriticalSection(&m_critSec);
  246. return S_OK;
  247. }
  248. //-------------------------------------------------------------------
  249. // GetAttributes
  250. // Returns the attributes for the MFT.
  251. //-------------------------------------------------------------------
  252. HRESULT OcvImageManipulations::GetAttributes(IMFAttributes** ppAttributes)
  253. {
  254. if (ppAttributes == NULL)
  255. {
  256. return E_POINTER;
  257. }
  258. EnterCriticalSection(&m_critSec);
  259. *ppAttributes = m_pAttributes;
  260. (*ppAttributes)->AddRef();
  261. LeaveCriticalSection(&m_critSec);
  262. return S_OK;
  263. }
  264. //-------------------------------------------------------------------
  265. // GetInputStreamAttributes
  266. // Returns stream-level attributes for an input stream.
  267. //-------------------------------------------------------------------
  268. HRESULT OcvImageManipulations::GetInputStreamAttributes(
  269. DWORD dwInputStreamID,
  270. IMFAttributes **ppAttributes
  271. )
  272. {
  273. // This MFT does not support any stream-level attributes, so the method is not implemented.
  274. return E_NOTIMPL;
  275. }
  276. //-------------------------------------------------------------------
  277. // GetOutputStreamAttributes
  278. // Returns stream-level attributes for an output stream.
  279. //-------------------------------------------------------------------
  280. HRESULT OcvImageManipulations::GetOutputStreamAttributes(
  281. DWORD dwOutputStreamID,
  282. IMFAttributes **ppAttributes
  283. )
  284. {
  285. // This MFT does not support any stream-level attributes, so the method is not implemented.
  286. return E_NOTIMPL;
  287. }
  288. //-------------------------------------------------------------------
  289. // DeleteInputStream
  290. //-------------------------------------------------------------------
  291. HRESULT OcvImageManipulations::DeleteInputStream(DWORD dwStreamID)
  292. {
  293. // This MFT has a fixed number of input streams, so the method is not supported.
  294. return E_NOTIMPL;
  295. }
  296. //-------------------------------------------------------------------
  297. // AddInputStreams
  298. //-------------------------------------------------------------------
  299. HRESULT OcvImageManipulations::AddInputStreams(
  300. DWORD cStreams,
  301. DWORD *adwStreamIDs
  302. )
  303. {
  304. // This MFT has a fixed number of output streams, so the method is not supported.
  305. return E_NOTIMPL;
  306. }
  307. //-------------------------------------------------------------------
  308. // GetInputAvailableType
  309. // Returns a preferred input type.
  310. //-------------------------------------------------------------------
  311. HRESULT OcvImageManipulations::GetInputAvailableType(
  312. DWORD dwInputStreamID,
  313. DWORD dwTypeIndex, // 0-based
  314. IMFMediaType **ppType
  315. )
  316. {
  317. if (ppType == NULL)
  318. {
  319. return E_INVALIDARG;
  320. }
  321. EnterCriticalSection(&m_critSec);
  322. if (!IsValidInputStream(dwInputStreamID))
  323. {
  324. LeaveCriticalSection(&m_critSec);
  325. return MF_E_INVALIDSTREAMNUMBER;
  326. }
  327. HRESULT hr = S_OK;
  328. // If the output type is set, return that type as our preferred input type.
  329. if (m_pOutputType == NULL)
  330. {
  331. // The output type is not set. Create a partial media type.
  332. hr = OnGetPartialType(dwTypeIndex, ppType);
  333. }
  334. else if (dwTypeIndex > 0)
  335. {
  336. hr = MF_E_NO_MORE_TYPES;
  337. }
  338. else
  339. {
  340. *ppType = m_pOutputType;
  341. (*ppType)->AddRef();
  342. }
  343. LeaveCriticalSection(&m_critSec);
  344. return hr;
  345. }
  346. //-------------------------------------------------------------------
  347. // GetOutputAvailableType
  348. // Returns a preferred output type.
  349. //-------------------------------------------------------------------
  350. HRESULT OcvImageManipulations::GetOutputAvailableType(
  351. DWORD dwOutputStreamID,
  352. DWORD dwTypeIndex, // 0-based
  353. IMFMediaType **ppType
  354. )
  355. {
  356. if (ppType == NULL)
  357. {
  358. return E_INVALIDARG;
  359. }
  360. EnterCriticalSection(&m_critSec);
  361. if (!IsValidOutputStream(dwOutputStreamID))
  362. {
  363. LeaveCriticalSection(&m_critSec);
  364. return MF_E_INVALIDSTREAMNUMBER;
  365. }
  366. HRESULT hr = S_OK;
  367. if (m_pInputType == NULL)
  368. {
  369. // The input type is not set. Create a partial media type.
  370. hr = OnGetPartialType(dwTypeIndex, ppType);
  371. }
  372. else if (dwTypeIndex > 0)
  373. {
  374. hr = MF_E_NO_MORE_TYPES;
  375. }
  376. else
  377. {
  378. *ppType = m_pInputType;
  379. (*ppType)->AddRef();
  380. }
  381. LeaveCriticalSection(&m_critSec);
  382. return hr;
  383. }
  384. //-------------------------------------------------------------------
  385. // SetInputType
  386. //-------------------------------------------------------------------
  387. HRESULT OcvImageManipulations::SetInputType(
  388. DWORD dwInputStreamID,
  389. IMFMediaType *pType, // Can be NULL to clear the input type.
  390. DWORD dwFlags
  391. )
  392. {
  393. // Validate flags.
  394. if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
  395. {
  396. return E_INVALIDARG;
  397. }
  398. EnterCriticalSection(&m_critSec);
  399. if (!IsValidInputStream(dwInputStreamID))
  400. {
  401. LeaveCriticalSection(&m_critSec);
  402. return MF_E_INVALIDSTREAMNUMBER;
  403. }
  404. HRESULT hr = S_OK;
  405. // Does the caller want us to set the type, or just test it?
  406. BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
  407. // If we have an input sample, the client cannot change the type now.
  408. if (HasPendingOutput())
  409. {
  410. hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
  411. goto done;
  412. }
  413. // Validate the type, if non-NULL.
  414. if (pType)
  415. {
  416. hr = OnCheckInputType(pType);
  417. if (FAILED(hr))
  418. {
  419. goto done;
  420. }
  421. }
  422. // The type is OK. Set the type, unless the caller was just testing.
  423. if (bReallySet)
  424. {
  425. OnSetInputType(pType);
  426. // When the type changes, end streaming.
  427. hr = EndStreaming();
  428. }
  429. done:
  430. LeaveCriticalSection(&m_critSec);
  431. return hr;
  432. }
  433. //-------------------------------------------------------------------
  434. // SetOutputType
  435. //-------------------------------------------------------------------
  436. HRESULT OcvImageManipulations::SetOutputType(
  437. DWORD dwOutputStreamID,
  438. IMFMediaType *pType, // Can be NULL to clear the output type.
  439. DWORD dwFlags
  440. )
  441. {
  442. // Validate flags.
  443. if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
  444. {
  445. return E_INVALIDARG;
  446. }
  447. EnterCriticalSection(&m_critSec);
  448. if (!IsValidOutputStream(dwOutputStreamID))
  449. {
  450. LeaveCriticalSection(&m_critSec);
  451. return MF_E_INVALIDSTREAMNUMBER;
  452. }
  453. HRESULT hr = S_OK;
  454. // Does the caller want us to set the type, or just test it?
  455. BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
  456. // If we have an input sample, the client cannot change the type now.
  457. if (HasPendingOutput())
  458. {
  459. hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
  460. goto done;
  461. }
  462. // Validate the type, if non-NULL.
  463. if (pType)
  464. {
  465. hr = OnCheckOutputType(pType);
  466. if (FAILED(hr))
  467. {
  468. goto done;
  469. }
  470. }
  471. // The type is OK. Set the type, unless the caller was just testing.
  472. if (bReallySet)
  473. {
  474. OnSetOutputType(pType);
  475. // When the type changes, end streaming.
  476. hr = EndStreaming();
  477. }
  478. done:
  479. LeaveCriticalSection(&m_critSec);
  480. return hr;
  481. }
  482. //-------------------------------------------------------------------
  483. // GetInputCurrentType
  484. // Returns the current input type.
  485. //-------------------------------------------------------------------
  486. HRESULT OcvImageManipulations::GetInputCurrentType(
  487. DWORD dwInputStreamID,
  488. IMFMediaType **ppType
  489. )
  490. {
  491. if (ppType == NULL)
  492. {
  493. return E_POINTER;
  494. }
  495. HRESULT hr = S_OK;
  496. EnterCriticalSection(&m_critSec);
  497. if (!IsValidInputStream(dwInputStreamID))
  498. {
  499. hr = MF_E_INVALIDSTREAMNUMBER;
  500. }
  501. else if (!m_pInputType)
  502. {
  503. hr = MF_E_TRANSFORM_TYPE_NOT_SET;
  504. }
  505. else
  506. {
  507. *ppType = m_pInputType;
  508. (*ppType)->AddRef();
  509. }
  510. LeaveCriticalSection(&m_critSec);
  511. return hr;
  512. }
  513. //-------------------------------------------------------------------
  514. // GetOutputCurrentType
  515. // Returns the current output type.
  516. //-------------------------------------------------------------------
  517. HRESULT OcvImageManipulations::GetOutputCurrentType(
  518. DWORD dwOutputStreamID,
  519. IMFMediaType **ppType
  520. )
  521. {
  522. if (ppType == NULL)
  523. {
  524. return E_POINTER;
  525. }
  526. HRESULT hr = S_OK;
  527. EnterCriticalSection(&m_critSec);
  528. if (!IsValidOutputStream(dwOutputStreamID))
  529. {
  530. hr = MF_E_INVALIDSTREAMNUMBER;
  531. }
  532. else if (!m_pOutputType)
  533. {
  534. hr = MF_E_TRANSFORM_TYPE_NOT_SET;
  535. }
  536. else
  537. {
  538. *ppType = m_pOutputType;
  539. (*ppType)->AddRef();
  540. }
  541. LeaveCriticalSection(&m_critSec);
  542. return hr;
  543. }
  544. //-------------------------------------------------------------------
  545. // GetInputStatus
  546. // Query if the MFT is accepting more input.
  547. //-------------------------------------------------------------------
  548. HRESULT OcvImageManipulations::GetInputStatus(
  549. DWORD dwInputStreamID,
  550. DWORD *pdwFlags
  551. )
  552. {
  553. if (pdwFlags == NULL)
  554. {
  555. return E_POINTER;
  556. }
  557. EnterCriticalSection(&m_critSec);
  558. if (!IsValidInputStream(dwInputStreamID))
  559. {
  560. LeaveCriticalSection(&m_critSec);
  561. return MF_E_INVALIDSTREAMNUMBER;
  562. }
  563. // If an input sample is already queued, do not accept another sample until the
  564. // client calls ProcessOutput or Flush.
  565. // NOTE: It is possible for an MFT to accept more than one input sample. For
  566. // example, this might be required in a video decoder if the frames do not
  567. // arrive in temporal order. In the case, the decoder must hold a queue of
  568. // samples. For the video effect, each sample is transformed independently, so
  569. // there is no reason to queue multiple input samples.
  570. if (m_pSample == NULL)
  571. {
  572. *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
  573. }
  574. else
  575. {
  576. *pdwFlags = 0;
  577. }
  578. LeaveCriticalSection(&m_critSec);
  579. return S_OK;
  580. }
  581. //-------------------------------------------------------------------
  582. // GetOutputStatus
  583. // Query if the MFT can produce output.
  584. //-------------------------------------------------------------------
  585. HRESULT OcvImageManipulations::GetOutputStatus(DWORD *pdwFlags)
  586. {
  587. if (pdwFlags == NULL)
  588. {
  589. return E_POINTER;
  590. }
  591. EnterCriticalSection(&m_critSec);
  592. // The MFT can produce an output sample if (and only if) there an input sample.
  593. if (m_pSample != NULL)
  594. {
  595. *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
  596. }
  597. else
  598. {
  599. *pdwFlags = 0;
  600. }
  601. LeaveCriticalSection(&m_critSec);
  602. return S_OK;
  603. }
  604. //-------------------------------------------------------------------
  605. // SetOutputBounds
  606. // Sets the range of time stamps that the MFT will output.
  607. //-------------------------------------------------------------------
  608. HRESULT OcvImageManipulations::SetOutputBounds(
  609. LONGLONG hnsLowerBound,
  610. LONGLONG hnsUpperBound
  611. )
  612. {
  613. // Implementation of this method is optional.
  614. return E_NOTIMPL;
  615. }
  616. //-------------------------------------------------------------------
  617. // ProcessEvent
  618. // Sends an event to an input stream.
  619. //-------------------------------------------------------------------
  620. HRESULT OcvImageManipulations::ProcessEvent(
  621. DWORD dwInputStreamID,
  622. IMFMediaEvent *pEvent
  623. )
  624. {
  625. // This MFT does not handle any stream events, so the method can
  626. // return E_NOTIMPL. This tells the pipeline that it can stop
  627. // sending any more events to this MFT.
  628. return E_NOTIMPL;
  629. }
  630. //-------------------------------------------------------------------
  631. // ProcessMessage
  632. //-------------------------------------------------------------------
  633. HRESULT OcvImageManipulations::ProcessMessage(
  634. MFT_MESSAGE_TYPE eMessage,
  635. ULONG_PTR ulParam
  636. )
  637. {
  638. EnterCriticalSection(&m_critSec);
  639. HRESULT hr = S_OK;
  640. switch (eMessage)
  641. {
  642. case MFT_MESSAGE_COMMAND_FLUSH:
  643. // Flush the MFT.
  644. hr = OnFlush();
  645. break;
  646. case MFT_MESSAGE_COMMAND_DRAIN:
  647. // Drain: Tells the MFT to reject further input until all pending samples are
  648. // processed. That is our default behavior already, so there is nothing to do.
  649. //
  650. // For a decoder that accepts a queue of samples, the MFT might need to drain
  651. // the queue in response to this command.
  652. break;
  653. case MFT_MESSAGE_SET_D3D_MANAGER:
  654. // Sets a pointer to the IDirect3DDeviceManager9 interface.
  655. // The pipeline should never send this message unless the MFT sets the MF_SA_D3D_AWARE
  656. // attribute set to TRUE. Because this MFT does not set MF_SA_D3D_AWARE, it is an error
  657. // to send the MFT_MESSAGE_SET_D3D_MANAGER message to the MFT. Return an error code in
  658. // this case.
  659. // NOTE: If this MFT were D3D-enabled, it would cache the IDirect3DDeviceManager9
  660. // pointer for use during streaming.
  661. hr = E_NOTIMPL;
  662. break;
  663. case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
  664. hr = BeginStreaming();
  665. break;
  666. case MFT_MESSAGE_NOTIFY_END_STREAMING:
  667. hr = EndStreaming();
  668. break;
  669. // The next two messages do not require any action from this MFT.
  670. case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
  671. break;
  672. case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
  673. break;
  674. }
  675. LeaveCriticalSection(&m_critSec);
  676. return hr;
  677. }
  678. //-------------------------------------------------------------------
  679. // ProcessInput
  680. // Process an input sample.
  681. //-------------------------------------------------------------------
  682. HRESULT OcvImageManipulations::ProcessInput(
  683. DWORD dwInputStreamID,
  684. IMFSample *pSample,
  685. DWORD dwFlags
  686. )
  687. {
  688. // Check input parameters.
  689. if (pSample == NULL)
  690. {
  691. return E_POINTER;
  692. }
  693. if (dwFlags != 0)
  694. {
  695. return E_INVALIDARG; // dwFlags is reserved and must be zero.
  696. }
  697. HRESULT hr = S_OK;
  698. EnterCriticalSection(&m_critSec);
  699. // Validate the input stream number.
  700. if (!IsValidInputStream(dwInputStreamID))
  701. {
  702. hr = MF_E_INVALIDSTREAMNUMBER;
  703. goto done;
  704. }
  705. // Check for valid media types.
  706. // The client must set input and output types before calling ProcessInput.
  707. if (!m_pInputType || !m_pOutputType)
  708. {
  709. hr = MF_E_NOTACCEPTING;
  710. goto done;
  711. }
  712. // Check if an input sample is already queued.
  713. if (m_pSample != NULL)
  714. {
  715. hr = MF_E_NOTACCEPTING; // We already have an input sample.
  716. goto done;
  717. }
  718. // Initialize streaming.
  719. hr = BeginStreaming();
  720. if (FAILED(hr))
  721. {
  722. goto done;
  723. }
  724. // Cache the sample. We do the actual work in ProcessOutput.
  725. m_pSample = pSample;
  726. pSample->AddRef(); // Hold a reference count on the sample.
  727. done:
  728. LeaveCriticalSection(&m_critSec);
  729. return hr;
  730. }
  731. //-------------------------------------------------------------------
  732. // ProcessOutput
  733. // Process an output sample.
  734. //-------------------------------------------------------------------
  735. HRESULT OcvImageManipulations::ProcessOutput(
  736. DWORD dwFlags,
  737. DWORD cOutputBufferCount,
  738. MFT_OUTPUT_DATA_BUFFER *pOutputSamples, // one per stream
  739. DWORD *pdwStatus
  740. )
  741. {
  742. // Check input parameters...
  743. // This MFT does not accept any flags for the dwFlags parameter.
  744. // The only defined flag is MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER. This flag
  745. // applies only when the MFT marks an output stream as lazy or optional. But this
  746. // MFT has no lazy or optional streams, so the flag is not valid.
  747. if (dwFlags != 0)
  748. {
  749. return E_INVALIDARG;
  750. }
  751. if (pOutputSamples == NULL || pdwStatus == NULL)
  752. {
  753. return E_POINTER;
  754. }
  755. // There must be exactly one output buffer.
  756. if (cOutputBufferCount != 1)
  757. {
  758. return E_INVALIDARG;
  759. }
  760. // It must contain a sample.
  761. if (pOutputSamples[0].pSample == NULL)
  762. {
  763. return E_INVALIDARG;
  764. }
  765. HRESULT hr = S_OK;
  766. IMFMediaBuffer *pInput = NULL;
  767. IMFMediaBuffer *pOutput = NULL;
  768. EnterCriticalSection(&m_critSec);
  769. // There must be an input sample available for processing.
  770. if (m_pSample == NULL)
  771. {
  772. hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
  773. goto done;
  774. }
  775. // Initialize streaming.
  776. hr = BeginStreaming();
  777. if (FAILED(hr))
  778. {
  779. goto done;
  780. }
  781. // Get the input buffer.
  782. hr = m_pSample->ConvertToContiguousBuffer(&pInput);
  783. if (FAILED(hr))
  784. {
  785. goto done;
  786. }
  787. // Get the output buffer.
  788. hr = pOutputSamples[0].pSample->ConvertToContiguousBuffer(&pOutput);
  789. if (FAILED(hr))
  790. {
  791. goto done;
  792. }
  793. hr = OnProcessOutput(pInput, pOutput);
  794. if (FAILED(hr))
  795. {
  796. goto done;
  797. }
  798. // Set status flags.
  799. pOutputSamples[0].dwStatus = 0;
  800. *pdwStatus = 0;
  801. // Copy the duration and time stamp from the input sample, if present.
  802. LONGLONG hnsDuration = 0;
  803. LONGLONG hnsTime = 0;
  804. if (SUCCEEDED(m_pSample->GetSampleDuration(&hnsDuration)))
  805. {
  806. hr = pOutputSamples[0].pSample->SetSampleDuration(hnsDuration);
  807. if (FAILED(hr))
  808. {
  809. goto done;
  810. }
  811. }
  812. if (SUCCEEDED(m_pSample->GetSampleTime(&hnsTime)))
  813. {
  814. hr = pOutputSamples[0].pSample->SetSampleTime(hnsTime);
  815. }
  816. done:
  817. SafeRelease(&m_pSample); // Release our input sample.
  818. SafeRelease(&pInput);
  819. SafeRelease(&pOutput);
  820. LeaveCriticalSection(&m_critSec);
  821. return hr;
  822. }
  823. // PRIVATE METHODS
  824. // All methods that follow are private to this MFT and are not part of the IMFTransform interface.
  825. // Create a partial media type from our list.
  826. //
  827. // dwTypeIndex: Index into the list of preferred media types.
  828. // ppmt: Receives a pointer to the media type.
  829. HRESULT OcvImageManipulations::OnGetPartialType(DWORD dwTypeIndex, IMFMediaType **ppmt)
  830. {
  831. if (dwTypeIndex >= ARRAYSIZE(g_MediaSubtypes))
  832. {
  833. return MF_E_NO_MORE_TYPES;
  834. }
  835. IMFMediaType *pmt = NULL;
  836. HRESULT hr = MFCreateMediaType(&pmt);
  837. if (FAILED(hr))
  838. {
  839. goto done;
  840. }
  841. hr = pmt->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
  842. if (FAILED(hr))
  843. {
  844. goto done;
  845. }
  846. hr = pmt->SetGUID(MF_MT_SUBTYPE, g_MediaSubtypes[dwTypeIndex]);
  847. if (FAILED(hr))
  848. {
  849. goto done;
  850. }
  851. *ppmt = pmt;
  852. (*ppmt)->AddRef();
  853. done:
  854. SafeRelease(&pmt);
  855. return hr;
  856. }
  857. // Validate an input media type.
  858. HRESULT OcvImageManipulations::OnCheckInputType(IMFMediaType *pmt)
  859. {
  860. assert(pmt != NULL);
  861. HRESULT hr = S_OK;
  862. // If the output type is set, see if they match.
  863. if (m_pOutputType != NULL)
  864. {
  865. DWORD flags = 0;
  866. hr = pmt->IsEqual(m_pOutputType, &flags);
  867. // IsEqual can return S_FALSE. Treat this as failure.
  868. if (hr != S_OK)
  869. {
  870. hr = MF_E_INVALIDMEDIATYPE;
  871. }
  872. }
  873. else
  874. {
  875. // Output type is not set. Just check this type.
  876. hr = OnCheckMediaType(pmt);
  877. }
  878. return hr;
  879. }
  880. // Validate an output media type.
  881. HRESULT OcvImageManipulations::OnCheckOutputType(IMFMediaType *pmt)
  882. {
  883. assert(pmt != NULL);
  884. HRESULT hr = S_OK;
  885. // If the input type is set, see if they match.
  886. if (m_pInputType != NULL)
  887. {
  888. DWORD flags = 0;
  889. hr = pmt->IsEqual(m_pInputType, &flags);
  890. // IsEqual can return S_FALSE. Treat this as failure.
  891. if (hr != S_OK)
  892. {
  893. hr = MF_E_INVALIDMEDIATYPE;
  894. }
  895. }
  896. else
  897. {
  898. // Input type is not set. Just check this type.
  899. hr = OnCheckMediaType(pmt);
  900. }
  901. return hr;
  902. }
  903. // Validate a media type (input or output)
  904. HRESULT OcvImageManipulations::OnCheckMediaType(IMFMediaType *pmt)
  905. {
  906. BOOL bFoundMatchingSubtype = FALSE;
  907. // Major type must be video.
  908. GUID major_type;
  909. HRESULT hr = pmt->GetGUID(MF_MT_MAJOR_TYPE, &major_type);
  910. if (FAILED(hr))
  911. {
  912. goto done;
  913. }
  914. if (major_type != MFMediaType_Video)
  915. {
  916. hr = MF_E_INVALIDMEDIATYPE;
  917. goto done;
  918. }
  919. // Subtype must be one of the subtypes in our global list.
  920. // Get the subtype GUID.
  921. GUID subtype;
  922. hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype);
  923. if (FAILED(hr))
  924. {
  925. goto done;
  926. }
  927. // Look for the subtype in our list of accepted types.
  928. for (DWORD i = 0; i < ARRAYSIZE(g_MediaSubtypes); i++)
  929. {
  930. if (subtype == g_MediaSubtypes[i])
  931. {
  932. bFoundMatchingSubtype = TRUE;
  933. break;
  934. }
  935. }
  936. if (!bFoundMatchingSubtype)
  937. {
  938. hr = MF_E_INVALIDMEDIATYPE; // The MFT does not support this subtype.
  939. goto done;
  940. }
  941. // Reject single-field media types.
  942. UINT32 interlace = MFGetAttributeUINT32(pmt, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
  943. if (interlace == MFVideoInterlace_FieldSingleUpper || interlace == MFVideoInterlace_FieldSingleLower)
  944. {
  945. hr = MF_E_INVALIDMEDIATYPE;
  946. }
  947. done:
  948. return hr;
  949. }
  950. // Set or clear the input media type.
  951. //
  952. // Prerequisite: The input type was already validated.
  953. void OcvImageManipulations::OnSetInputType(IMFMediaType *pmt)
  954. {
  955. // if pmt is NULL, clear the type.
  956. // if pmt is non-NULL, set the type.
  957. SafeRelease(&m_pInputType);
  958. m_pInputType = pmt;
  959. if (m_pInputType)
  960. {
  961. m_pInputType->AddRef();
  962. }
  963. // Update the format information.
  964. UpdateFormatInfo();
  965. }
  966. // Set or clears the output media type.
  967. //
  968. // Prerequisite: The output type was already validated.
  969. void OcvImageManipulations::OnSetOutputType(IMFMediaType *pmt)
  970. {
  971. // If pmt is NULL, clear the type. Otherwise, set the type.
  972. SafeRelease(&m_pOutputType);
  973. m_pOutputType = pmt;
  974. if (m_pOutputType)
  975. {
  976. m_pOutputType->AddRef();
  977. }
  978. }
  979. // Initialize streaming parameters.
  980. //
  981. // This method is called if the client sends the MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
  982. // message, or when the client processes a sample, whichever happens first.
  983. HRESULT OcvImageManipulations::BeginStreaming()
  984. {
  985. HRESULT hr = S_OK;
  986. if (!m_bStreamingInitialized)
  987. {
  988. m_bStreamingInitialized = true;
  989. hr = S_OK;
  990. }
  991. return hr;
  992. }
  993. // End streaming.
  994. // This method is called if the client sends an MFT_MESSAGE_NOTIFY_END_STREAMING
  995. // message, or when the media type changes. In general, it should be called whenever
  996. // the streaming parameters need to be reset.
  997. HRESULT OcvImageManipulations::EndStreaming()
  998. {
  999. m_bStreamingInitialized = false;
  1000. return S_OK;
  1001. }
  1002. // Generate output data.
  1003. HRESULT OcvImageManipulations::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut)
  1004. {
  1005. BYTE *pDest = NULL; // Destination buffer.
  1006. LONG lDestStride = 0; // Destination stride.
  1007. BYTE *pSrc = NULL; // Source buffer.
  1008. LONG lSrcStride = 0; // Source stride.
  1009. // Helper objects to lock the buffers.
  1010. VideoBufferLock inputLock(pIn);
  1011. VideoBufferLock outputLock(pOut);
  1012. // Stride if the buffer does not support IMF2DBuffer
  1013. LONG lDefaultStride = 0;
  1014. HRESULT hr = GetDefaultStride(m_pInputType, &lDefaultStride);
  1015. if (FAILED(hr))
  1016. {
  1017. return hr;
  1018. }
  1019. // Lock the input buffer.
  1020. hr = inputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pSrc, &lSrcStride);
  1021. if (FAILED(hr))
  1022. {
  1023. return hr;
  1024. }
  1025. // Lock the output buffer.
  1026. hr = outputLock.LockBuffer(lDefaultStride, m_imageHeightInPixels, &pDest, &lDestStride);
  1027. if (FAILED(hr))
  1028. {
  1029. return hr;
  1030. }
  1031. cv::Mat InputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pSrc, lSrcStride);
  1032. cv::Mat InputGreyScale(InputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
  1033. cv::Mat OutputFrame(m_imageHeightInPixels + m_imageHeightInPixels/2, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride);
  1034. switch (m_TransformType)
  1035. {
  1036. case Preview:
  1037. {
  1038. InputFrame.copyTo(OutputFrame);
  1039. } break;
  1040. case GrayScale:
  1041. {
  1042. OutputFrame.setTo(cv::Scalar(128));
  1043. cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
  1044. InputGreyScale.copyTo(OutputGreyScale);
  1045. } break;
  1046. case Canny:
  1047. {
  1048. OutputFrame.setTo(cv::Scalar(128));
  1049. cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
  1050. cv::Canny(InputGreyScale, OutputGreyScale, 80, 90);
  1051. } break;
  1052. case Sobel:
  1053. {
  1054. OutputFrame.setTo(cv::Scalar(128));
  1055. cv::Mat OutputGreyScale(OutputFrame, cv::Range(0, m_imageHeightInPixels), cv::Range(0, m_imageWidthInPixels));
  1056. cv::Sobel(InputGreyScale, OutputGreyScale, CV_8U, 1, 1);
  1057. } break;
  1058. case Histogram:
  1059. {
  1060. const int mHistSizeNum = 25;
  1061. const int channels[3][1] = {{0}, {1}, {2}};
  1062. const int mHistSize[] = {25};
  1063. const float baseRabge[] = {0.f,256.f};
  1064. const float* ranges[] = {baseRabge};
  1065. const cv::Scalar mColorsY[] = { cv::Scalar(76), cv::Scalar(149), cv::Scalar(29) };
  1066. const cv::Scalar mColorsUV[] = { cv::Scalar(84, 255), cv::Scalar(43, 21), cv::Scalar(255, 107) };
  1067. cv::Mat OutputY(m_imageHeightInPixels, m_imageWidthInPixels, CV_8UC1, pDest, lDestStride);
  1068. cv::Mat OutputUV(m_imageHeightInPixels/2, m_imageWidthInPixels/2,
  1069. CV_8UC2, pDest+m_imageHeightInPixels*lDestStride, lDestStride);
  1070. cv::Mat BgrFrame;
  1071. InputFrame.copyTo(OutputFrame);
  1072. cv::cvtColor(InputFrame, BgrFrame, cv::COLOR_YUV420sp2BGR);
  1073. int thikness = (int) (BgrFrame.cols / (mHistSizeNum + 10) / 5);
  1074. if(thikness > 5) thikness = 5;
  1075. int offset = (int) ((BgrFrame.cols - (5*mHistSizeNum + 4*10)*thikness)/2);
  1076. // RGB
  1077. for (int c=0; c<3; c++)
  1078. {
  1079. cv::Mat hist;
  1080. cv::calcHist(&BgrFrame, 1, channels[c], cv::Mat(), hist, 1, mHistSize, ranges);
  1081. cv::normalize(hist, hist, BgrFrame.rows/2, 0, cv::NORM_INF);
  1082. for(int h=0; h<mHistSizeNum; h++) {
  1083. cv::Point mP1, mP2;
  1084. // Draw on Y plane
  1085. mP1.x = mP2.x = offset + (c * (mHistSizeNum + 10) + h) * thikness;
  1086. mP1.y = BgrFrame.rows-1;
  1087. mP2.y = mP1.y - 2 - (int)hist.at<float>(h);
  1088. cv::line(OutputY, mP1, mP2, mColorsY[c], thikness);
  1089. // Draw on UV planes
  1090. mP1.x /= 2;
  1091. mP1.y /= 2;
  1092. mP2.x /= 2;
  1093. mP2.y /= 2;
  1094. cv::line(OutputUV, mP1, mP2, mColorsUV[c], thikness/2);
  1095. }
  1096. }
  1097. } break;
  1098. default:
  1099. break;
  1100. }
  1101. // Set the data size on the output buffer.
  1102. hr = pOut->SetCurrentLength(m_cbImageSize);
  1103. return hr;
  1104. }
  1105. // Flush the MFT.
  1106. HRESULT OcvImageManipulations::OnFlush()
  1107. {
  1108. // For this MFT, flushing just means releasing the input sample.
  1109. SafeRelease(&m_pSample);
  1110. return S_OK;
  1111. }
  1112. // Update the format information. This method is called whenever the
  1113. // input type is set.
  1114. HRESULT OcvImageManipulations::UpdateFormatInfo()
  1115. {
  1116. HRESULT hr = S_OK;
  1117. GUID subtype = GUID_NULL;
  1118. m_imageWidthInPixels = 0;
  1119. m_imageHeightInPixels = 0;
  1120. m_cbImageSize = 0;
  1121. if (m_pInputType != NULL)
  1122. {
  1123. hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype);
  1124. if (FAILED(hr))
  1125. {
  1126. goto done;
  1127. }
  1128. if (subtype != MFVideoFormat_NV12)
  1129. {
  1130. hr = E_UNEXPECTED;
  1131. goto done;
  1132. }
  1133. hr = MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels);
  1134. if (FAILED(hr))
  1135. {
  1136. goto done;
  1137. }
  1138. // Calculate the image size for YUV NV12 image(not including padding)
  1139. m_cbImageSize = (m_imageHeightInPixels + m_imageHeightInPixels/2)*m_imageWidthInPixels;
  1140. }
  1141. done:
  1142. return hr;
  1143. }
  1144. // Get the default stride for a video format.
  1145. HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
  1146. {
  1147. LONG lStride = 0;
  1148. // Try to get the default stride from the media type.
  1149. HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
  1150. if (FAILED(hr))
  1151. {
  1152. // Attribute not set. Try to calculate the default stride.
  1153. GUID subtype = GUID_NULL;
  1154. UINT32 width = 0;
  1155. UINT32 height = 0;
  1156. // Get the subtype and the image size.
  1157. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
  1158. if (SUCCEEDED(hr))
  1159. {
  1160. hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
  1161. }
  1162. if (SUCCEEDED(hr))
  1163. {
  1164. if (subtype == MFVideoFormat_NV12)
  1165. {
  1166. lStride = width;
  1167. }
  1168. else if (subtype == MFVideoFormat_YUY2 || subtype == MFVideoFormat_UYVY)
  1169. {
  1170. lStride = ((width * 2) + 3) & ~3;
  1171. }
  1172. else
  1173. {
  1174. hr = E_INVALIDARG;
  1175. }
  1176. }
  1177. // Set the attribute for later reference.
  1178. if (SUCCEEDED(hr))
  1179. {
  1180. (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
  1181. }
  1182. }
  1183. if (SUCCEEDED(hr))
  1184. {
  1185. *plStride = lStride;
  1186. }
  1187. return hr;
  1188. }