Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
8.5 KiB

  1. #include <wchar.h>
  2. #include <streams.h>
  3. #include <atlbase.h>
  4. #include <wmsecure.h>
  5. #include <limits.h>
  6. #include "mediaobj.h"
  7. #include "dmodshow.h"
  8. #include "filter.h"
  9. #include "inpin.h"
  10. #include "outpin.h"
  11. // BUGBUG - set proper name
  12. CWrapperInputPin::CWrapperInputPin(
  13. CMediaWrapperFilter *pFilter,
  14. ULONG Id,
  15. HRESULT *phr) :
  16. CBaseInputPin(NAME("CWrapperInputPin"),
  17. pFilter,
  18. pFilter->FilterLock(),
  19. phr,
  20. (m_pNameObject = new _PinName_(L"in", Id))->Name()
  21. ),
  22. m_Id(Id),
  23. m_fEOS(false)
  24. {
  25. }
  26. CWrapperInputPin::~CWrapperInputPin() {
  27. delete m_pNameObject;
  28. }
  29. STDMETHODIMP CWrapperInputPin::Receive(IMediaSample *pSample)
  30. {
  31. HRESULT hr = Filter()->NewSample(m_Id, pSample);
  32. // If something bad happens flush - this avoids some more deadlocks
  33. // where we're holding on to the sample
  34. if (S_OK != hr) {
  35. Filter()->m_pMediaObject->Flush();
  36. }
  37. return hr;
  38. }
  39. HRESULT CWrapperInputPin::CheckMediaType(const CMediaType *pmt)
  40. {
  41. return Filter()->InputCheckMediaType(m_Id, pmt);
  42. }
  43. HRESULT CWrapperInputPin::SetMediaType(const CMediaType *pmt)
  44. {
  45. return Filter()->InputSetMediaType(m_Id, pmt);
  46. }
  47. HRESULT CWrapperInputPin::GetMediaType(int iPosition,CMediaType *pMediaType)
  48. {
  49. return Filter()->InputGetMediaType(m_Id, (ULONG)iPosition, pMediaType);
  50. }
  51. // Remove any media type when breaking a connection
  52. HRESULT CWrapperInputPin::BreakConnect()
  53. {
  54. HRESULT hr = CBaseInputPin::BreakConnect();
  55. Filter()->m_pMediaObject->SetInputType(m_Id, &CMediaType(), DMO_SET_TYPEF_CLEAR);
  56. return hr;
  57. }
  58. // Override GetAllocator and Notify Allocator to allow
  59. // for media object streams that hold on to buffer
  60. STDMETHODIMP CWrapperInputPin::GetAllocator(IMemAllocator **ppAllocator)
  61. {
  62. CheckPointer(ppAllocator, E_POINTER);
  63. *ppAllocator = NULL;
  64. // Already got an allocator or not using special behavior?
  65. if (m_pAllocator != NULL || !HoldsOnToBuffers()) {
  66. return CBaseInputPin::GetAllocator(ppAllocator);
  67. }
  68. DWORD dwLookahead;
  69. DWORD cbBuffer;
  70. DWORD cbAlign;
  71. HRESULT hr = TranslateDMOError(Filter()->m_pMediaObject->GetInputSizeInfo(
  72. m_Id,
  73. &cbBuffer,
  74. &dwLookahead,
  75. &cbAlign));
  76. if (FAILED(hr)) {
  77. return hr;
  78. }
  79. // Create our own special allocator
  80. hr = S_OK;
  81. CSpecialAllocator *pAllocator = new CSpecialAllocator(dwLookahead, &hr);
  82. if (NULL == pAllocator) {
  83. return E_OUTOFMEMORY;
  84. }
  85. if (FAILED(hr)) {
  86. delete pAllocator;
  87. return hr;
  88. }
  89. m_pAllocator = pAllocator;
  90. m_pAllocator->AddRef();
  91. pAllocator->AddRef();
  92. *ppAllocator = pAllocator;
  93. return S_OK;
  94. }
  95. STDMETHODIMP CWrapperInputPin::NotifyAllocator(
  96. IMemAllocator *pAllocator,
  97. BOOL bReadOnly
  98. )
  99. {
  100. // If we hold on to buffers only allow our own allocator to be
  101. // used
  102. if (HoldsOnToBuffers()) {
  103. if (pAllocator != m_pAllocator) {
  104. return E_FAIL;
  105. }
  106. }
  107. CAutoLock cObjectLock(m_pLock);
  108. // It does not make sense to propose an allocator if the pin
  109. // is not connected.
  110. ASSERT(IsConnected());
  111. HRESULT hr = MP3AndWMABufferSizeWorkAround(pAllocator);
  112. if (FAILED(hr)) {
  113. DbgLog((LOG_ERROR, 5, TEXT("WARNING in CWrapperInputPin::NotifyAllocator(): MP3AndWMABufferSizeWorkAround() failed and returned %#08x"), hr ));
  114. }
  115. return CBaseInputPin::NotifyAllocator(pAllocator, bReadOnly);
  116. }
  117. STDMETHODIMP CWrapperInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps)
  118. {
  119. return Filter()->InputGetAllocatorRequirements(m_Id, pProps);
  120. }
  121. // Just grab our critical section so we know we're quiesced
  122. void CWrapperInputPin::SyncLock()
  123. {
  124. CAutoLock lck(&m_csStream);
  125. }
  126. STDMETHODIMP CWrapperInputPin::NewSegment(
  127. REFERENCE_TIME tStart,
  128. REFERENCE_TIME tStop,
  129. double dRate)
  130. {
  131. return Filter()->InputNewSegment(m_Id, tStart, tStop, dRate);
  132. }
  133. STDMETHODIMP CWrapperInputPin::BeginFlush()
  134. {
  135. CAutoLock lck(m_pLock);
  136. // Avoid deadlocks because the object is holding on to a sample
  137. // Note we flush the object in EndFlush
  138. if (m_pAllocator) {
  139. m_pAllocator->Decommit();
  140. }
  141. return Filter()->BeginFlush(m_Id);
  142. }
  143. STDMETHODIMP CWrapperInputPin::EndFlush()
  144. {
  145. CAutoLock lck(m_pLock);
  146. // Recommit the allocator - we know no samples are flowing
  147. // when EndFlush is called so this is safe to do in any order
  148. if (m_pAllocator) {
  149. m_pAllocator->Commit();
  150. }
  151. return Filter()->EndFlush(m_Id);
  152. }
  153. STDMETHODIMP CWrapperInputPin::EndOfStream()
  154. {
  155. HRESULT hr = Filter()->EndOfStream(m_Id);
  156. // where we're holding on to the sample
  157. if (S_OK != hr) {
  158. Filter()->m_pMediaObject->Flush();
  159. }
  160. return hr;
  161. }
  162. STDMETHODIMP CWrapperInputPin::Notify(IBaseFilter * pSender, Quality q)
  163. {
  164. return E_NOTIMPL;
  165. }
  166. BOOL CWrapperInputPin::HoldsOnToBuffers()
  167. {
  168. DWORD dwFlags = 0;
  169. Filter()->m_pMediaObject->GetInputStreamInfo(m_Id, &dwFlags);
  170. return 0 != (dwFlags & DMO_INPUT_STREAMF_HOLDS_BUFFERS);
  171. }
  172. HRESULT CWrapperInputPin::MP3AndWMABufferSizeWorkAround(IMemAllocator* pProposedAllocator)
  173. {
  174. if (!IsConnected()) {
  175. return E_FAIL;
  176. }
  177. PIN_INFO pi;
  178. IPin* pConnected = GetConnected();
  179. HRESULT hr = pConnected->QueryPinInfo(&pi);
  180. if (FAILED(hr)) {
  181. return hr;
  182. }
  183. if (NULL == pi.pFilter) {
  184. return E_UNEXPECTED;
  185. }
  186. // {38be3000-dbf4-11d0-860e-00a024cfef6d}
  187. const CLSID MPEG_LAYER_3_DECODER_FILTER = { 0x38be3000, 0xdbf4, 0x11d0, { 0x86, 0x0e, 0x00, 0xa0, 0x24, 0xcf, 0xef, 0x6d } };
  188. // {22E24591-49D0-11D2-BB50-006008320064}
  189. const CLSID WINDOWS_MEDIA_AUDIO_DECODER_FILTER = { 0x22E24591, 0x49D0, 0x11D2, { 0xBB, 0x50, 0x00, 0x60, 0x08, 0x32, 0x00, 0x64 } };
  190. CLSID clsidFilter;
  191. hr = pi.pFilter->GetClassID(&clsidFilter);
  192. QueryPinInfoReleaseFilter(pi);
  193. // The Windows Media Audio Decoder (WMAD) filter and the MPEG Layer 3
  194. // (MP3) Decoder filter incorrectly calculate the output allocator's
  195. // media sample size. The output allocator is the allocator used by
  196. // filter's the output pin. Both filters tell the output allocator to
  197. // create samples which are too small. Both filters then refuse to deliver
  198. // any samples when the filter graph is running because the output
  199. // allocator's samples cannot hold enough data. The DMO Wrapper filter
  200. // works around these bugs because the authors of both filters
  201. // refuse to fix any bugs. The work around is to increase the allocator's
  202. // sample size if the allocator's sample size is too small and the DMO
  203. // Wrapper filter is connected to the WMA Decoder or the MP3 decoder.
  204. // The bug stops reproing once we increase the sample size.
  205. if (IsEqualCLSID(WINDOWS_MEDIA_AUDIO_DECODER_FILTER, clsidFilter)) {
  206. const DWORD MIN_WMA_FILTER_BUFFER_SIZE = 0x80000;
  207. hr = SetBufferSize(pProposedAllocator, MIN_WMA_FILTER_BUFFER_SIZE);
  208. if (FAILED(hr)) {
  209. return hr;
  210. }
  211. } else if (IsEqualCLSID(MPEG_LAYER_3_DECODER_FILTER, clsidFilter)) {
  212. // The MP3 decoder's audio sample buffers never hold
  213. // more then one tenth of second. One tenth of second
  214. // of 44.1 KHZ 16 bit stereo PCM audio can be stored in
  215. // 17640 bytes. 17640 = (44100*2*2)/10 = 44E8.
  216. const DWORD MIN_MP3_BUFFER_SIZE = 0x44E8;
  217. hr = SetBufferSize(pProposedAllocator, MIN_MP3_BUFFER_SIZE);
  218. if (FAILED(hr)) {
  219. return hr;
  220. }
  221. } else {
  222. // Do nothing because we have not found a known broken filter.
  223. }
  224. return S_OK;
  225. }
  226. HRESULT CWrapperInputPin::SetBufferSize(IMemAllocator* pAllocator, DWORD dwMinBufferSize)
  227. {
  228. ALLOCATOR_PROPERTIES apRequested;
  229. // Make sure dwMinBufferSize can be converted to a long.
  230. ASSERT(dwMinBufferSize <= LONG_MAX);
  231. HRESULT hr = pAllocator->GetProperties(&apRequested);
  232. if (FAILED(hr)) {
  233. return hr;
  234. }
  235. apRequested.cbBuffer = max((long)dwMinBufferSize, apRequested.cbBuffer);
  236. ALLOCATOR_PROPERTIES apActual;
  237. hr = pAllocator->SetProperties(&apRequested, &apActual);
  238. if (FAILED(hr)) {
  239. return hr;
  240. }
  241. if ((apActual.cbAlign != apRequested.cbAlign) ||
  242. (apActual.cBuffers < apRequested.cBuffers) ||
  243. (apActual.cbBuffer < apRequested.cbBuffer) ||
  244. (apActual.cbPrefix != apRequested.cbPrefix)) {
  245. return E_FAIL;
  246. }
  247. return S_OK;
  248. }