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.

468 lines
12 KiB

  1. // Copyright (c) Microsoft Corporation 1994-1996. All Rights Reserved
  2. // Timecode decoder, David Maymudes, November 1996
  3. //
  4. //
  5. #include <streams.h>
  6. #include <mmsystem.h>
  7. // XXX using backslashes since makedepend is broken!
  8. #include "..\timecode.h"
  9. #include "..\ltcdcode.h"
  10. #include "..\tchelper.h"
  11. #ifdef FILTER_DLL
  12. // define the GUIDs for streams and my CLSID in this file
  13. #include <initguid.h>
  14. #endif
  15. extern const AMOVIESETUP_FILTER sudTCDecode;
  16. // Class ID for CTCDecode objects
  17. //
  18. // 6a08cf9f-0e18-11cf-a24d-0020afd79767
  19. DEFINE_GUID(CLSID_TCDecoder,
  20. 0x6a08cf9f, 0x0e18, 0x11cf, 0xa2, 0x4d, 0x0, 0x20, 0xaf, 0xd7, 0x97, 0x67);
  21. const int TIMECODE_SIZE = 50; // max size of a timecode string
  22. class CTCDecode : public CTransformFilter
  23. {
  24. public:
  25. CTCDecode(TCHAR *, LPUNKNOWN, HRESULT *);
  26. ~CTCDecode();
  27. DECLARE_IUNKNOWN
  28. HRESULT Transform(IMediaSample * pIn, IMediaSample * pOut);
  29. HRESULT Receive( IMediaSample *pInSample );
  30. // check if you can support mtIn
  31. HRESULT CheckInputType(const CMediaType* mtIn);
  32. // check if you can support the transform from this input to
  33. // this output
  34. HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut);
  35. // called from CBaseOutputPin to prepare the allocator's count
  36. // of buffers and sizes
  37. HRESULT DecideBufferSize(IMemAllocator * pAllocator,
  38. ALLOCATOR_PROPERTIES *pProperties);
  39. // optional overrides - we want to know when streaming starts and stops
  40. HRESULT StartStreaming();
  41. HRESULT StopStreaming();
  42. // overriden to suggest OUTPUT pin media types
  43. HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
  44. // this goes in the factory template table to create new instances
  45. static CUnknown * CreateInstance(LPUNKNOWN, HRESULT *);
  46. STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
  47. private:
  48. LTCdecoder decoder;
  49. DWORD m_nSamplesPerSec;
  50. DWORD m_nBlockAlign;
  51. LONGLONG _sampleNumber;
  52. };
  53. //*****************************************************************************
  54. //*****************************************************************************
  55. // setup data
  56. const AMOVIESETUP_MEDIATYPE
  57. sudInTypes = { &MEDIATYPE_Audio // clsMajorType
  58. , &MEDIASUBTYPE_NULL }; // clsMinorType
  59. const AMOVIESETUP_MEDIATYPE
  60. sudOutTypes = { &MEDIATYPE_Text // clsMajorType
  61. , &MEDIASUBTYPE_NULL }; // clsMinorType
  62. const AMOVIESETUP_PIN sudpPins [] =
  63. {
  64. { L"Input" // strName
  65. , FALSE // bRendered
  66. , FALSE // bOutput
  67. , FALSE // bZero
  68. , FALSE // bMany
  69. , &CLSID_NULL // clsConnectsToFilter
  70. , L"Output" // strConnectsToPin
  71. , 1 // nTypes
  72. , &sudInTypes // lpTypes
  73. },
  74. { L"Output" // strName
  75. , FALSE // bRendered
  76. , TRUE // bOutput
  77. , FALSE // bZero
  78. , FALSE // bMany
  79. , &CLSID_NULL // clsConnectsToFilter
  80. , L"Input" // strConnectsToPin
  81. , 1 // nTypes
  82. , &sudOutTypes // lpTypes
  83. }
  84. };
  85. const AMOVIESETUP_FILTER sudTCDecode =
  86. { &CLSID_TCDecoder // clsID
  87. , L"Timecode decoder" // strName
  88. , MERIT_NORMAL // dwMerit
  89. , 2 // nPins
  90. , sudpPins }; // lpPin
  91. //*****************************************************************************
  92. //*****************************************************************************
  93. //*****************************************************************************
  94. #ifdef FILTER_DLL
  95. // List of class IDs and creator functions for class factory
  96. CFactoryTemplate g_Templates[] =
  97. {
  98. { L"Timecode Decoder"
  99. , &CLSID_TCDecoder
  100. , CTCDecode::CreateInstance
  101. , NULL
  102. , &sudTCDecode
  103. }
  104. };
  105. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  106. //*****************************************************************************
  107. //*****************************************************************************
  108. //*****************************************************************************
  109. // exported entry points for registration and unregistration (in this case they
  110. // only call through to default implmentations).
  111. //
  112. STDAPI DllRegisterServer()
  113. {
  114. return AMovieDllRegisterServer2( TRUE );
  115. }
  116. STDAPI DllUnregisterServer()
  117. {
  118. return AMovieDllRegisterServer2( FALSE );
  119. }
  120. #endif
  121. //*****************************************************************************
  122. //*****************************************************************************
  123. //*****************************************************************************
  124. //
  125. // CreateInstance()
  126. //
  127. //
  128. CUnknown *CTCDecode::CreateInstance(LPUNKNOWN pUnk, HRESULT * phr)
  129. {
  130. DbgLog((LOG_TRACE, 2, TEXT("CTCDecode::CreateInstance")));
  131. return new CTCDecode(TEXT("LTC decoder"), pUnk, phr);
  132. }
  133. //*****************************************************************************
  134. //
  135. // NonDelegatingQueryInterface()
  136. //
  137. //
  138. STDMETHODIMP CTCDecode::NonDelegatingQueryInterface( REFIID riid, void **ppv )
  139. {
  140. return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
  141. }
  142. //*****************************************************************************
  143. //
  144. // CTCDecode()
  145. //
  146. //
  147. CTCDecode::CTCDecode( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
  148. : CTransformFilter( pName,
  149. pUnk,
  150. CLSID_TCDecoder)
  151. {
  152. _sampleNumber = 0;
  153. DbgLog((LOG_TRACE,3,TEXT("CTCDecode")));
  154. }
  155. //*****************************************************************************
  156. //
  157. // ~CTCDecode()
  158. //
  159. //
  160. CTCDecode::~CTCDecode()
  161. {
  162. DbgLog((LOG_TRACE,3,TEXT("~CTCDecode")));
  163. }
  164. //*****************************************************************************
  165. //
  166. // CheckInputType()
  167. //
  168. //
  169. HRESULT CTCDecode::CheckInputType(const CMediaType* pmtIn)
  170. {
  171. DbgLog((LOG_TRACE, 3, TEXT("CTCDecode::CheckInputType")));
  172. DisplayType("pmtIn details:", pmtIn);
  173. WAVEFORMATEX * pwfx = (WAVEFORMATEX *)pmtIn->Format();
  174. if (pmtIn->majortype != MEDIATYPE_Audio) {
  175. DbgLog((LOG_ERROR, 1, TEXT("*** CheckInputType only takes audio")));
  176. return E_INVALIDARG;
  177. }
  178. if( *pmtIn->FormatType() != FORMAT_WaveFormatEx ) {
  179. DbgLog((LOG_ERROR, 1, TEXT(" pmtOut->FormatType != FORMAT_WaveFormatEx!")));
  180. return E_INVALIDARG;
  181. }
  182. if (pmtIn->FormatLength() < sizeof(PCMWAVEFORMAT)) {
  183. DbgLog((LOG_ERROR, 1, TEXT("*** pmtIn->FormatLength < PCMWAVEFORMAT")));
  184. return E_INVALIDARG;
  185. }
  186. // only accept mono 16 bit data
  187. if (pwfx->wFormatTag != WAVE_FORMAT_PCM || pwfx->wBitsPerSample != 16 ||
  188. pwfx->nChannels != 1)
  189. return E_INVALIDARG;
  190. return S_OK;
  191. }
  192. //*****************************************************************************
  193. //
  194. // GetMediaType()
  195. //
  196. HRESULT CTCDecode::GetMediaType( int iPosition, CMediaType *pmt )
  197. {
  198. DbgLog((LOG_TRACE, 3, TEXT("CTCDecode::GetMediaType")));
  199. DbgLog((LOG_TRACE, 3, TEXT(" iPosition = %d"),iPosition));
  200. if( iPosition != 0 ) {
  201. return E_INVALIDARG;
  202. }
  203. pmt->SetType( &MEDIATYPE_Text );
  204. pmt->SetSubtype( &GUID_NULL );
  205. pmt->SetFormatType( &GUID_NULL );
  206. return S_OK;
  207. }
  208. //*****************************************************************************
  209. //
  210. // CheckTransform()
  211. //
  212. //
  213. HRESULT CTCDecode::CheckTransform(const CMediaType* pmtIn,
  214. const CMediaType* pmtOut)
  215. {
  216. HRESULT hr = CheckInputType(pmtIn);
  217. if (FAILED(hr))
  218. return hr;
  219. DisplayType("pmtOut:", pmtOut);
  220. if (pmtOut->majortype != MEDIATYPE_Text) {
  221. DbgLog((LOG_ERROR, 1, TEXT("*** output type must be text")));
  222. return E_INVALIDARG;
  223. }
  224. return S_OK;
  225. }
  226. //*****************************************************************************
  227. //
  228. // DecideBufferSize()
  229. //
  230. HRESULT CTCDecode::DecideBufferSize( IMemAllocator * pAllocator,
  231. ALLOCATOR_PROPERTIES *pProperties )
  232. {
  233. DbgLog((LOG_TRACE, 3, TEXT("CTCDecode::DecideBufferSize")));
  234. if (pProperties->cBuffers < 4)
  235. pProperties->cBuffers = 4;
  236. if (pProperties->cbBuffer < TIMECODE_SIZE)
  237. pProperties->cbBuffer = TIMECODE_SIZE;
  238. if (pProperties->cbAlign < 1)
  239. pProperties->cbAlign = 1;
  240. ALLOCATOR_PROPERTIES Actual;
  241. HRESULT hr = pAllocator->SetProperties(pProperties,&Actual);
  242. if (FAILED(hr)) {
  243. return hr;
  244. }
  245. return S_OK;
  246. }
  247. //*****************************************************************************
  248. //
  249. // StartStreaming()
  250. //
  251. //
  252. HRESULT CTCDecode::StartStreaming()
  253. {
  254. CAutoLock lock(&m_csFilter);
  255. DbgLog((LOG_TRACE, 3, TEXT("CTCDecode::StartStreaming")));
  256. WAVEFORMATEX *pwfx = (WAVEFORMATEX *)m_pInput->CurrentMediaType().Format();
  257. m_nSamplesPerSec = pwfx->nSamplesPerSec ;
  258. m_nBlockAlign = pwfx->nBlockAlign ;
  259. // !!! decoder.Reset();
  260. return S_OK;
  261. }
  262. //*****************************************************************************
  263. //
  264. // StopStreaming()
  265. //
  266. //
  267. HRESULT CTCDecode::StopStreaming()
  268. {
  269. CAutoLock lock(&m_csFilter);
  270. DbgLog((LOG_TRACE, 3, TEXT("CTCDecode::StopStreaming")));
  271. return NOERROR;
  272. }
  273. HRESULT CTCDecode::Transform( IMediaSample *pIn, IMediaSample *pOut )
  274. {
  275. DbgLog((LOG_ERROR, 1, TEXT("*** CTCDecode->Transform() called!")));
  276. ASSERT(0); // !!! shouldn't be called!
  277. return E_FAIL;
  278. }
  279. HRESULT CTCDecode::Receive( IMediaSample *pInSample )
  280. {
  281. HRESULT hr = NOERROR;
  282. REFERENCE_TIME inBufStartTime; // start/stop time of input buffer
  283. REFERENCE_TIME inBufStopTime;
  284. REFERENCE_TIME tcStartTime; // start/stop time of the timecode
  285. REFERENCE_TIME tcStopTime;
  286. LONGLONG startTCsample, stopTCsample; // 1st, last sample of timecode
  287. BYTE *pbSample;
  288. LONG cbSampleLength, cbLeft;
  289. DbgLog((LOG_TRACE, 4, TEXT("CTCDecode::Receive")));
  290. // get input start and stop times
  291. pInSample->GetTime(&inBufStartTime, &inBufStopTime);
  292. pInSample->GetPointer( &pbSample );
  293. DbgLog((LOG_TRACE, 3, TEXT("Total Sample: Start = %s End = %s"),
  294. (LPCTSTR)CDisp((LONGLONG)(inBufStartTime),CDISP_HEX),
  295. (LPCTSTR)CDisp((LONGLONG)(inBufStopTime),CDISP_HEX)));
  296. cbSampleLength = pInSample->GetActualDataLength() / m_nBlockAlign;
  297. cbLeft = cbSampleLength;
  298. // sample number of the last sample in buf
  299. LONGLONG lastSampleNumber= _sampleNumber + cbSampleLength;
  300. DbgLog((LOG_TRACE, 4, TEXT(" cbSampleLength = %d"),cbSampleLength));
  301. while (cbLeft > 0) {
  302. TimeCode tc;
  303. LONGLONG syncSample; // the audio sample that this tc corresponds to
  304. if (decoder.decodeBuffer((short **) &pbSample, (int *) &cbLeft)) {
  305. IMediaSample *pOutSample;
  306. decoder.getTimeCode(&tc);
  307. decoder.getStartStopSample(&startTCsample, &stopTCsample);
  308. hr = m_pOutput->GetDeliveryBuffer( &pOutSample, NULL, NULL, 0 );
  309. if( FAILED(hr) )
  310. {
  311. DbgLog((LOG_ERROR, 1, TEXT("GetDeliveryBuffer(pOutSample) failed, hr = %u"),hr));
  312. return hr;
  313. }
  314. pOutSample->SetSyncPoint( pInSample->IsSyncPoint() == S_OK );
  315. // not really right....
  316. pOutSample->SetDiscontinuity( pInSample->IsDiscontinuity() == S_OK );
  317. tcStartTime = extrapolate(_sampleNumber, inBufStartTime, // begin bf
  318. lastSampleNumber, inBufStopTime, // end bf
  319. startTCsample); // samnumber of desired time
  320. tcStopTime = extrapolate(_sampleNumber, inBufStartTime, // begin bf
  321. lastSampleNumber, inBufStopTime, // end bf
  322. stopTCsample); // samnumber of desired time
  323. // !!! really should be last tStop of the last timecode sent....
  324. // XXX realy? I am not so sure...
  325. pOutSample->SetTime(&tcStartTime, &tcStopTime);
  326. DbgLog((LOG_TRACE, 4, TEXT(" Breaking up: Start = %s End = %s"),
  327. (LPCTSTR)CDisp((LONGLONG)(tcStartTime),CDISP_HEX),
  328. (LPCTSTR)CDisp((LONGLONG)(tcStopTime),CDISP_HEX)));
  329. BYTE *pbOut;
  330. pOutSample->GetPointer( &pbOut );
  331. tc.GetString((char *) pbOut);
  332. pOutSample->SetActualDataLength(lstrlen((char *) pbOut) + 1);
  333. hr = m_pOutput->Deliver(pOutSample);
  334. // release the output buffer. If the connected pin still needs it,
  335. // it will have addrefed it itself.
  336. pOutSample->Release();
  337. if (FAILED(hr))
  338. return hr;
  339. }
  340. }
  341. // sample count of 1st sample in decode buffer
  342. // needed because the synch will occur in a PREVIOUS buffer (or 1st samp)
  343. _sampleNumber += cbSampleLength;
  344. return S_OK;
  345. }
  346. // !!! do we need special EOS handling?