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.

329 lines
8.8 KiB

  1. // Copyright (c) 1997 - 1999 Microsoft Corporation. All Rights Reserved.
  2. // bytestrm.cpp : Implementation of CByteStream
  3. #include "stdafx.h"
  4. #include "project.h"
  5. /////////////////////////////////////////////////////////////////////////////
  6. // CByteStream
  7. CByteStream::CByteStream() :
  8. m_cbData(0),
  9. m_lBytesPerSecond(0),
  10. m_bEOSPending(false)
  11. {
  12. }
  13. STDMETHODIMP CByteStream::GetBuffer(
  14. IMediaSample **ppBuffer,
  15. REFERENCE_TIME * pStartTime,
  16. REFERENCE_TIME * pEndTime,
  17. DWORD dwFlags
  18. )
  19. {
  20. HRESULT hr;
  21. *ppBuffer = NULL;
  22. if (m_bStopIfNoSamples && m_cAllocated == 0) {
  23. return E_FAIL;
  24. }
  25. if (m_Direction == PINDIR_INPUT) {
  26. AtlTrace(_T("Should never get here!\n"));
  27. _ASSERTE(FALSE);
  28. hr = E_UNEXPECTED;
  29. } else {
  30. CSample *pSample;
  31. hr = AllocSampleFromPool(pStartTime, &pSample);
  32. if (hr == NOERROR) {
  33. pSample->m_pMediaSample->m_dwFlags = dwFlags;
  34. pSample->m_bReceived = false;
  35. pSample->m_bModified = true;
  36. *ppBuffer = (IMediaSample *)(pSample->m_pMediaSample);
  37. (*ppBuffer)->AddRef();
  38. }
  39. }
  40. return hr;
  41. }
  42. STDMETHODIMP CByteStream::BeginFlush()
  43. {
  44. AUTO_CRIT_LOCK;
  45. m_bEOSPending = false;
  46. m_arSamples.RemoveAll();
  47. m_cbData = 0;
  48. m_TimeStamp.Reset();
  49. return CStream::BeginFlush();
  50. }
  51. STDMETHODIMP CByteStream::EndOfStream()
  52. {
  53. HRESULT hr = S_OK;
  54. Lock();
  55. if (m_bFlushing || m_bEndOfStream || m_bEOSPending) {
  56. hr = E_FAIL;
  57. } else {
  58. m_bEOSPending = TRUE;
  59. CheckEndOfStream();
  60. }
  61. Unlock();
  62. return hr;
  63. }
  64. STDMETHODIMP CByteStream::GetAllocator(IMemAllocator ** ppAllocator)
  65. {
  66. HRESULT hr;
  67. AUTO_CRIT_LOCK;
  68. if (m_Direction == PINDIR_OUTPUT) {
  69. hr = CStream::GetAllocator(ppAllocator);
  70. } else {
  71. if (m_pAllocator == NULL) {
  72. hr = CoCreateInstance(CLSID_MemoryAllocator,
  73. 0,
  74. CLSCTX_INPROC_SERVER,
  75. IID_IMemAllocator,
  76. (void **)&m_pAllocator);
  77. if (FAILED(hr)) {
  78. goto Exit;
  79. }
  80. }
  81. m_pAllocator->AddRef();
  82. *ppAllocator = m_pAllocator;
  83. hr = NOERROR;
  84. }
  85. Exit:
  86. return hr;
  87. }
  88. STDMETHODIMP CByteStream::Receive(IMediaSample *pSample)
  89. {
  90. AUTO_CRIT_LOCK;
  91. if (m_bFlushing || m_bStopIfNoSamples && m_cAllocated == 0) {
  92. EndOfStream();
  93. return S_FALSE;
  94. }
  95. if(m_FilterState == State_Stopped) {
  96. return VFW_E_WRONG_STATE;
  97. }
  98. /* Put it on the queue */
  99. if (!m_arSamples.Add(pSample)) {
  100. EndOfStream();
  101. return E_OUTOFMEMORY;
  102. }
  103. /* Eat as much as we can, then return */
  104. FillSamples();
  105. return S_OK;
  106. }
  107. STDMETHODIMP CByteStream::SetState(
  108. /* [in] */ FILTER_STATE State
  109. )
  110. {
  111. HRESULT hr = CStream::SetState(State); // Must be called with the critical seciton unowned!
  112. Lock();
  113. if (State == State_Stopped) {
  114. m_bEOSPending = false;
  115. m_arSamples.RemoveAll();
  116. m_cbData = 0;
  117. m_TimeStamp.Reset();
  118. }
  119. Unlock();
  120. if (State == State_Stopped) {
  121. _ASSERTE(m_arSamples.Size() == 0);
  122. }
  123. return hr;
  124. }
  125. // Fill any samples lying around
  126. void CByteStream::FillSamples()
  127. {
  128. while (m_arSamples.Size() != 0 && m_pFirstFree != NULL) {
  129. if (m_cbData == 0) {
  130. IMediaSample * const pSample = m_arSamples.Element(0);
  131. /* At the start so initialize some stuff */
  132. pSample->GetPointer(&m_pbData);
  133. m_cbData = m_arSamples.Element(0)->GetActualDataLength();
  134. /* See if there are any time stamps */
  135. REFERENCE_TIME rtStart, rtStop;
  136. if (SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) {
  137. #if 0
  138. AtlTrace("TimeStamp current %d, new %d, length %d length(ms) %d, bytelen %d\n",
  139. (long)(m_TimeStamp.TimeStamp(0, m_lBytesPerSecond) / 10000),
  140. (long)(rtStart / 10000),
  141. (long)((rtStop - rtStart) / 10000),
  142. MulDiv(m_cbData, 1000, m_lBytesPerSecond),
  143. m_cbData);
  144. #endif
  145. m_TimeStamp.SetTime(rtStart);
  146. }
  147. }
  148. /* Copy some data across */
  149. CByteStreamSample* const pStreamSample = (CByteStreamSample *)m_pFirstFree;
  150. /* Do timestamps */
  151. if (pStreamSample->m_cbData == 0) {
  152. pStreamSample->m_pMediaSample->m_rtEndTime =
  153. pStreamSample->m_pMediaSample->m_rtStartTime =
  154. m_TimeStamp.TimeStamp(0, m_lBytesPerSecond);
  155. }
  156. /* See how much we can copy */
  157. _ASSERTE(pStreamSample->m_cbData <= pStreamSample->m_cbSize);
  158. DWORD cbBytesToCopy = min(m_cbData,
  159. pStreamSample->m_cbSize -
  160. pStreamSample->m_cbData);
  161. CopyMemory(pStreamSample->m_pbData + pStreamSample->m_cbData,
  162. m_pbData,
  163. cbBytesToCopy);
  164. m_cbData -= cbBytesToCopy;
  165. m_TimeStamp.AccumulateBytes(cbBytesToCopy);
  166. /* Is this a bit expensive? - who cares about the stop time */
  167. pStreamSample->m_pMediaSample->m_rtEndTime =
  168. m_TimeStamp.TimeStamp(0, m_lBytesPerSecond);
  169. if (m_cbData == 0) {
  170. // This performs the Release()
  171. m_arSamples.Remove(0);
  172. }
  173. m_pbData += cbBytesToCopy;
  174. pStreamSample->m_cbData += cbBytesToCopy;
  175. // Update the actual data object
  176. pStreamSample->m_pMemData->SetActual(pStreamSample->m_cbData);
  177. if (pStreamSample->m_cbData == pStreamSample->m_cbSize) {
  178. // this is a lot of overhead since we know
  179. // it's free but it's not a bug
  180. #if 0
  181. AtlTrace("Sample start %dms, length %dms bytelen %dms\n",
  182. (long)(pStreamSample->m_pMediaSample->m_rtEndTime / 10000),
  183. (long)((pStreamSample->m_pMediaSample->m_rtEndTime -
  184. pStreamSample->m_pMediaSample->m_rtStartTime) / 10000),
  185. MulDiv(pStreamSample->m_cbData, 1000, m_lBytesPerSecond));
  186. #endif
  187. StealSampleFromFreePool(m_pFirstFree, true);
  188. pStreamSample->SetCompletionStatus(S_OK);
  189. }
  190. }
  191. CheckEndOfStream();
  192. }
  193. void CByteStream::CheckEndOfStream()
  194. {
  195. AUTO_CRIT_LOCK;
  196. if (m_bEOSPending && m_arSamples.Size() == 0) {
  197. m_bEOSPending = false;
  198. // If the first sample contains data set the status on the
  199. // next one
  200. if (m_pFirstFree != NULL) {
  201. CByteStreamSample* const pStreamSample =
  202. (CByteStreamSample *)m_pFirstFree;
  203. if (pStreamSample->m_cbData != 0) {
  204. StealSampleFromFreePool(m_pFirstFree, true);
  205. pStreamSample->SetCompletionStatus(S_OK);
  206. }
  207. }
  208. CStream::EndOfStream();
  209. }
  210. }
  211. #if 0
  212. HRESULT CByteStream::InternalAllocateSample(
  213. IByteStreamSample **ppBSSample
  214. )
  215. {
  216. CByteStreamSample *pBSSample = new CComObject<CByteStreamSample>;
  217. if (pBSSample == NULL) {
  218. *ppBSSample = NULL;
  219. return E_OUTOFMEMORY;
  220. } else {
  221. return pBSSample->GetControllingUnknown()->QueryInterface(
  222. IID_IByteStreamSample, (void **)ppBSSample
  223. );
  224. }
  225. }
  226. #endif
  227. //
  228. // CByteStreamSample
  229. //
  230. CByteStreamSample::CByteStreamSample() :
  231. m_pbData(NULL),
  232. m_cbSize(0),
  233. m_cbData(0)
  234. {
  235. }
  236. HRESULT CByteStreamSample::InternalUpdate(
  237. DWORD dwFlags,
  238. HANDLE hEvent,
  239. PAPCFUNC pfnAPC,
  240. DWORD_PTR dwAPCData
  241. )
  242. {
  243. if (m_pMemData == NULL) {
  244. return MS_E_NOTINIT;
  245. }
  246. HRESULT hr = m_pMemData->GetInfo(
  247. &m_cbSize,
  248. &m_pbData,
  249. &m_cbData
  250. );
  251. if (FAILED(hr)) {
  252. return hr;
  253. }
  254. // InternalUpdate will check everything and add us to queues etc
  255. hr = CSample::InternalUpdate(dwFlags, hEvent, pfnAPC, dwAPCData);
  256. if (SUCCEEDED(hr) && m_pStream->m_Direction == PINDIR_INPUT) {
  257. m_cbData = 0;
  258. m_pMemData->SetActual(0);
  259. CByteStream *pStream = (CByteStream *)m_pStream;
  260. pStream->FillSamples();
  261. }
  262. return hr;
  263. }
  264. STDMETHODIMP::CByteStreamSample::GetInformation(
  265. /* [out] */ DWORD *pdwLength,
  266. /* [out] */ PBYTE *ppbData,
  267. /* [out] */ DWORD *pcbActualData
  268. )
  269. {
  270. if (m_pbData == NULL) {
  271. return MS_E_NOTINIT;
  272. }
  273. if (pdwLength) {
  274. *pdwLength = m_cbSize;
  275. }
  276. if (ppbData) {
  277. *ppbData = m_pbData;
  278. }
  279. if (pcbActualData) {
  280. *pcbActualData = m_cbData;
  281. }
  282. return S_OK;
  283. }
  284. HRESULT CByteStreamSample::Init(
  285. IMemoryData *pMemData
  286. )
  287. {
  288. if (m_pMemData) {
  289. _ASSERTE(_T("Initialization called twice!"));
  290. return E_UNEXPECTED;
  291. }
  292. m_pMemData = pMemData;
  293. return S_OK;
  294. }