AJA NTV2 SDK  18.0.0.2717
NTV2 SDK 18.0.0.2717
source.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // File: Source.cpp
3 //
4 // Desc: DirectShow base classes - implements CSource, which is a Quartz
5 // source filter 'template.'
6 //
7 // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 
11 // Locking Strategy.
12 //
13 // Hold the filter critical section (m_pFilter->pStateLock()) to serialise
14 // access to functions. Note that, in general, this lock may be held
15 // by a function when the worker thread may want to hold it. Therefore
16 // if you wish to access shared state from the worker thread you will
17 // need to add another critical section object. The execption is during
18 // the threads processing loop, when it is safe to get the filter critical
19 // section from within FillBuffer().
20 
21 #include <streams.h>
22 
23 
24 //
25 // CSource::Constructor
26 //
27 // Initialise the pin count for the filter. The user will create the pins in
28 // the derived class.
29 CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid)
30  : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
31  m_iPins(0),
32  m_paStreams(NULL)
33 {
34 }
35 
36 CSource::CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr)
37  : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
38  m_iPins(0),
39  m_paStreams(NULL)
40 {
41  UNREFERENCED_PARAMETER(phr);
42 }
43 
44 #ifdef UNICODE
45 CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid)
46  : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
47  m_iPins(0),
48  m_paStreams(NULL)
49 {
50 }
51 
52 CSource::CSource(__in_opt LPCSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr)
53  : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
54  m_iPins(0),
55  m_paStreams(NULL)
56 {
57  UNREFERENCED_PARAMETER(phr);
58 }
59 #endif
60 
61 //
62 // CSource::Destructor
63 //
65 {
66  /* Free our pins and pin array */
67  while (m_iPins != 0) {
68  // deleting the pins causes them to be removed from the array...
69  delete m_paStreams[m_iPins - 1];
70  }
71 
73 }
74 
75 
76 //
77 // Add a new pin
78 //
79 HRESULT CSource::AddPin(__in CSourceStream *pStream)
80 {
81  CAutoLock lock(&m_cStateLock);
82 
83  /* Allocate space for this pin and the old ones */
84  CSourceStream **paStreams = new CSourceStream *[m_iPins + 1];
85  if (paStreams == NULL) {
86  return E_OUTOFMEMORY;
87  }
88  if (m_paStreams != NULL) {
89  CopyMemory((PVOID)paStreams, (PVOID)m_paStreams,
90  m_iPins * sizeof(m_paStreams[0]));
91  paStreams[m_iPins] = pStream;
92  delete [] m_paStreams;
93  }
94  m_paStreams = paStreams;
95  m_paStreams[m_iPins] = pStream;
96  m_iPins++;
97  return S_OK;
98 }
99 
100 //
101 // Remove a pin - pStream is NOT deleted
102 //
103 HRESULT CSource::RemovePin(__in CSourceStream *pStream)
104 {
105  int i;
106  for (i = 0; i < m_iPins; i++) {
107  if (m_paStreams[i] == pStream) {
108  if (m_iPins == 1) {
109  delete [] m_paStreams;
110  m_paStreams = NULL;
111  } else {
112  /* no need to reallocate */
113  while (++i < m_iPins)
114  m_paStreams[i - 1] = m_paStreams[i];
115  }
116  m_iPins--;
117  return S_OK;
118  }
119  }
120  return S_FALSE;
121 }
122 
123 //
124 // FindPin
125 //
126 // Set *ppPin to the IPin* that has the id Id.
127 // or to NULL if the Id cannot be matched.
128 STDMETHODIMP CSource::FindPin(LPCWSTR Id, __deref_out IPin **ppPin)
129 {
130  CheckPointer(ppPin,E_POINTER);
131  ValidateReadWritePtr(ppPin,sizeof(IPin *));
132  // The -1 undoes the +1 in QueryId and ensures that totally invalid
133  // strings (for which WstrToInt delivers 0) give a deliver a NULL pin.
134  int i = WstrToInt(Id) -1;
135  *ppPin = GetPin(i);
136  if (*ppPin!=NULL){
137  (*ppPin)->AddRef();
138  return NOERROR;
139  } else {
140  return VFW_E_NOT_FOUND;
141  }
142 }
143 
144 //
145 // FindPinNumber
146 //
147 // return the number of the pin with this IPin* or -1 if none
148 int CSource::FindPinNumber(__in IPin *iPin) {
149  int i;
150  for (i=0; i<m_iPins; ++i) {
151  if ((IPin *)(m_paStreams[i])==iPin) {
152  return i;
153  }
154  }
155  return -1;
156 }
157 
158 //
159 // GetPinCount
160 //
161 // Returns the number of pins this filter has
163 
164  CAutoLock lock(&m_cStateLock);
165  return m_iPins;
166 }
167 
168 
169 //
170 // GetPin
171 //
172 // Return a non-addref'd pointer to pin n
173 // needed by CBaseFilter
175 
176  CAutoLock lock(&m_cStateLock);
177 
178  // n must be in the range 0..m_iPins-1
179  // if m_iPins>n && n>=0 it follows that m_iPins>0
180  // which is what used to be checked (i.e. checking that we have a pin)
181  if ((n >= 0) && (n < m_iPins)) {
182 
183  ASSERT(m_paStreams[n]);
184  return m_paStreams[n];
185  }
186  return NULL;
187 }
188 
189 
190 //
191 
192 
193 // *
194 // * --- CSourceStream ----
195 // *
196 
197 //
198 // Set Id to point to a CoTaskMemAlloc'd
199 STDMETHODIMP CSourceStream::QueryId(__deref_out LPWSTR *Id) {
200  CheckPointer(Id,E_POINTER);
201  ValidateReadWritePtr(Id,sizeof(LPWSTR));
202 
203  // We give the pins id's which are 1,2,...
204  // FindPinNumber returns -1 for an invalid pin
205  int i = 1+ m_pFilter->FindPinNumber(this);
206  if (i<1) return VFW_E_NOT_FOUND;
207  *Id = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * 12);
208  if (*Id==NULL) {
209  return E_OUTOFMEMORY;
210  }
211  IntToWstr(i, *Id);
212  return NOERROR;
213 }
214 
215 
216 
217 //
218 // CSourceStream::Constructor
219 //
220 // increments the number of pins present on the filter
222  __in_opt LPCTSTR pObjectName,
223  __inout HRESULT *phr,
224  __inout CSource *ps,
225  __in_opt LPCWSTR pPinName)
226  : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
227  m_pFilter(ps) {
228 
229  *phr = m_pFilter->AddPin(this);
230 }
231 
232 #ifdef UNICODE
234  __in_opt LPCSTR pObjectName,
235  __inout HRESULT *phr,
236  __inout CSource *ps,
237  __in_opt LPCWSTR pPinName)
238  : CBaseOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
239  m_pFilter(ps) {
240 
241  *phr = m_pFilter->AddPin(this);
242 }
243 #endif
244 //
245 // CSourceStream::Destructor
246 //
247 // Decrements the number of pins on this filter
249 
250  m_pFilter->RemovePin(this);
251 }
252 
253 
254 //
255 // CheckMediaType
256 //
257 // Do we support this type? Provides the default support for 1 type.
258 HRESULT CSourceStream::CheckMediaType(const CMediaType *pMediaType) {
259 
260  CAutoLock lock(m_pFilter->pStateLock());
261 
262  CMediaType mt;
263  GetMediaType(&mt);
264 
265  if (mt == *pMediaType) {
266  return NOERROR;
267  }
268 
269  return E_FAIL;
270 }
271 
272 
273 //
274 // GetMediaType/3
275 //
276 // By default we support only one type
277 // iPosition indexes are 0-n
278 HRESULT CSourceStream::GetMediaType(int iPosition, __inout CMediaType *pMediaType) {
279 
280  CAutoLock lock(m_pFilter->pStateLock());
281 
282  if (iPosition<0) {
283  return E_INVALIDARG;
284  }
285  if (iPosition>0) {
286  return VFW_S_NO_MORE_ITEMS;
287  }
288  return GetMediaType(pMediaType);
289 }
290 
291 
292 //
293 // Active
294 //
295 // The pin is active - start up the worker thread
296 HRESULT CSourceStream::Active(void) {
297 
298  CAutoLock lock(m_pFilter->pStateLock());
299 
300  HRESULT hr;
301 
302  if (m_pFilter->IsActive()) {
303  return S_FALSE; // succeeded, but did not allocate resources (they already exist...)
304  }
305 
306  // do nothing if not connected - its ok not to connect to
307  // all pins of a source filter
308  if (!IsConnected()) {
309  return NOERROR;
310  }
311 
313  if (FAILED(hr)) {
314  return hr;
315  }
316 
317  ASSERT(!ThreadExists());
318 
319  // start the thread
320  if (!Create()) {
321  return E_FAIL;
322  }
323 
324  // Tell thread to initialize. If OnThreadCreate Fails, so does this.
325  hr = Init();
326  if (FAILED(hr))
327  return hr;
328 
329  return Pause();
330 }
331 
332 
333 //
334 // Inactive
335 //
336 // Pin is inactive - shut down the worker thread
337 // Waits for the worker to exit before returning.
338 HRESULT CSourceStream::Inactive(void) {
339 
340  CAutoLock lock(m_pFilter->pStateLock());
341 
342  HRESULT hr;
343 
344  // do nothing if not connected - its ok not to connect to
345  // all pins of a source filter
346  if (!IsConnected()) {
347  return NOERROR;
348  }
349 
350  // !!! need to do this before trying to stop the thread, because
351  // we may be stuck waiting for our own allocator!!!
352 
353  hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator
354  if (FAILED(hr)) {
355  return hr;
356  }
357 
358  if (ThreadExists()) {
359  hr = Stop();
360 
361  if (FAILED(hr)) {
362  return hr;
363  }
364 
365  hr = Exit();
366  if (FAILED(hr)) {
367  return hr;
368  }
369 
370  Close(); // Wait for the thread to exit, then tidy up.
371  }
372 
373  // hr = CBaseOutputPin::Inactive(); // call this first to Decommit the allocator
374  //if (FAILED(hr)) {
375  // return hr;
376  //}
377 
378  return NOERROR;
379 }
380 
381 
382 //
383 // ThreadProc
384 //
385 // When this returns the thread exits
386 // Return codes > 0 indicate an error occured
388 
389  HRESULT hr; // the return code from calls
390  Command com;
391 
392  do {
393  com = GetRequest();
394  if (com != CMD_INIT) {
395  DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
396  Reply((DWORD) E_UNEXPECTED);
397  }
398  } while (com != CMD_INIT);
399 
400  DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread initializing")));
401 
402  hr = OnThreadCreate(); // perform set up tasks
403  if (FAILED(hr)) {
404  DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadCreate failed. Aborting thread.")));
405  OnThreadDestroy();
406  Reply(hr); // send failed return code from OnThreadCreate
407  return 1;
408  }
409 
410  // Initialisation suceeded
411  Reply(NOERROR);
412 
413  Command cmd;
414  do {
415  cmd = GetRequest();
416 
417  switch (cmd) {
418 
419  case CMD_EXIT:
420  Reply(NOERROR);
421  break;
422 
423  case CMD_RUN:
424  DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???")));
425  // !!! fall through???
426 
427  case CMD_PAUSE:
428  Reply(NOERROR);
430  break;
431 
432  case CMD_STOP:
433  Reply(NOERROR);
434  break;
435 
436  default:
437  DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
438  Reply((DWORD) E_NOTIMPL);
439  break;
440  }
441  } while (cmd != CMD_EXIT);
442 
443  hr = OnThreadDestroy(); // tidy up.
444  if (FAILED(hr)) {
445  DbgLog((LOG_ERROR, 1, TEXT("CSourceStream::OnThreadDestroy failed. Exiting thread.")));
446  return 1;
447  }
448 
449  DbgLog((LOG_TRACE, 1, TEXT("CSourceStream worker thread exiting")));
450  return 0;
451 }
452 
453 
454 //
455 // DoBufferProcessingLoop
456 //
457 // Grabs a buffer and calls the users processing function.
458 // Overridable, so that different delivery styles can be catered for.
460 
461  Command com;
462 
464 
465  do {
466  while (!CheckRequest(&com)) {
467 
468  IMediaSample *pSample;
469 
470  HRESULT hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
471  if (FAILED(hr)) {
472  Sleep(1);
473  continue; // go round again. Perhaps the error will go away
474  // or the allocator is decommited & we will be asked to
475  // exit soon.
476  }
477 
478  // Virtual function user will override.
479  hr = FillBuffer(pSample);
480 
481  if (hr == S_OK) {
482  hr = Deliver(pSample);
483  pSample->Release();
484 
485  // downstream filter returns S_FALSE if it wants us to
486  // stop or an error if it's reporting an error.
487  if(hr != S_OK)
488  {
489  DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
490  return S_OK;
491  }
492 
493  } else if (hr == S_FALSE) {
494  // derived class wants us to stop pushing data
495  pSample->Release();
497  return S_OK;
498  } else {
499  // derived class encountered an error
500  pSample->Release();
501  DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));
503  m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
504  return hr;
505  }
506 
507  // all paths release the sample
508  }
509 
510  // For all commands sent to us there must be a Reply call!
511 
512  if (com == CMD_RUN || com == CMD_PAUSE) {
513  Reply(NOERROR);
514  } else if (com != CMD_STOP) {
515  Reply((DWORD) E_UNEXPECTED);
516  DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
517  }
518  } while (com != CMD_STOP);
519 
520  return S_FALSE;
521 }
522 
CSource::pStateLock
CCritSec * pStateLock(void)
Definition: source.h:59
CSourceStream::QueryId
STDMETHODIMP QueryId(__deref_out LPWSTR *Id)
Definition: source.cpp:199
CSource::GetPinCount
int GetPinCount(void)
Definition: source.cpp:162
CSourceStream::Command
Command
Definition: source.h:135
CBaseFilter::NotifyEvent
HRESULT NotifyEvent(long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
Definition: amfilter.cpp:811
CSourceStream::CMD_RUN
@ CMD_RUN
Definition: source.h:135
CSource::CSource
CSource(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN lpunk, CLSID clsid, __inout HRESULT *phr)
Definition: source.cpp:36
CBasePin
Definition: amfilter.h:330
streams.h
CSourceStream::OnThreadCreate
virtual HRESULT OnThreadCreate(void)
Definition: source.h:122
NULL
#define NULL
Definition: ntv2caption608types.h:19
CSourceStream::CMD_INIT
@ CMD_INIT
Definition: source.h:135
CSourceStream::CMD_EXIT
@ CMD_EXIT
Definition: source.h:135
CSource::m_iPins
int m_iPins
Definition: source.h:73
CSourceStream::Stop
HRESULT Stop(void)
Definition: source.h:140
LOG_TRACE
@ LOG_TRACE
Definition: wxdebug.h:45
CSourceStream
Definition: source.h:88
CBaseOutputPin::Deliver
virtual HRESULT Deliver(IMediaSample *)
Definition: amfilter.cpp:2685
CBaseOutputPin::Inactive
HRESULT Inactive(void)
Definition: amfilter.cpp:2729
CAutoLock
Definition: wxutil.h:83
CBaseOutputPin::GetDeliveryBuffer
virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample **ppSample, __in_opt REFERENCE_TIME *pStartTime, __in_opt REFERENCE_TIME *pEndTime, DWORD dwFlags)
Definition: amfilter.cpp:2648
CSource::m_cStateLock
CCritSec m_cStateLock
Definition: source.h:77
CSourceStream::GetRequest
Command GetRequest(void)
Definition: source.h:143
CSource::GetPin
CBasePin * GetPin(int n)
Definition: source.cpp:174
CSourceStream::FillBuffer
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE
CBasePin::IsConnected
BOOL IsConnected(void)
Definition: amfilter.h:499
CSourceStream::DoBufferProcessingLoop
virtual HRESULT DoBufferProcessingLoop(void)
Definition: source.cpp:459
CSource::FindPinNumber
int FindPinNumber(__in IPin *iPin)
Definition: source.cpp:148
CSourceStream::OnThreadDestroy
virtual HRESULT OnThreadDestroy(void)
Definition: source.h:123
CMediaType
Definition: mtype.h:18
CSource::m_paStreams
CSourceStream ** m_paStreams
Definition: source.h:75
n
unsigned int n
Definition: pstream.cpp:148
ValidateReadWritePtr
#define ValidateReadWritePtr(p, cb)
Definition: wxdebug.h:241
CSourceStream::Inactive
HRESULT Inactive(void)
Definition: source.cpp:338
CBaseFilter::IsActive
BOOL IsActive()
Definition: amfilter.h:240
CSourceStream::OnThreadStartPlay
virtual HRESULT OnThreadStartPlay(void)
Definition: source.h:124
LOG_ERROR
@ LOG_ERROR
Definition: wxdebug.h:48
CSourceStream::ThreadProc
virtual DWORD ThreadProc(void)
Definition: source.cpp:387
pName
CHAR * pName
Definition: amvideo.cpp:26
DbgLog
#define DbgLog(_x_)
Definition: wxdebug.h:183
CSourceStream::m_pFilter
CSource * m_pFilter
Definition: source.h:105
CSource::AddPin
HRESULT AddPin(__in CSourceStream *)
Definition: source.cpp:79
CSourceStream::Init
HRESULT Init(void)
Definition: source.h:136
PVOID
void * PVOID
Definition: ajatypes.h:339
CBaseOutputPin
Definition: amfilter.h:712
CBaseOutputPin::DeliverEndOfStream
virtual HRESULT DeliverEndOfStream(void)
Definition: amfilter.cpp:2702
CopyMemory
#define CopyMemory(a, b, c)
Definition: ntv2baremetaldriverinterface.h:16
CSourceStream::CheckMediaType
virtual HRESULT CheckMediaType(const CMediaType *pMediaType)
Definition: source.cpp:258
WstrToInt
#define WstrToInt(sz)
Definition: wxutil.h:396
CSource
Definition: source.h:43
CSource::~CSource
~CSource()
Definition: source.cpp:64
IntToWstr
void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr)
Definition: wxutil.cpp:359
CSourceStream::~CSourceStream
virtual ~CSourceStream(void)
Definition: source.cpp:248
CBaseFilter
Definition: amfilter.h:148
CSourceStream::Active
HRESULT Active(void)
Definition: source.cpp:296
CSourceStream::GetMediaType
virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType)
Definition: source.cpp:278
CSourceStream::CMD_STOP
@ CMD_STOP
Definition: source.h:135
CSourceStream::CSourceStream
CSourceStream(__in_opt LPCTSTR pObjectName, __inout HRESULT *phr, __inout CSource *pms, __in_opt LPCWSTR pName)
Definition: source.cpp:221
CheckPointer
#define CheckPointer(p, ret)
Definition: wxdebug.h:225
ASSERT
#define ASSERT(_x_)
Definition: wxdebug.h:205
CSource::RemovePin
HRESULT RemovePin(__in CSourceStream *)
Definition: source.cpp:103
hr
__out HRESULT & hr
Definition: pstream.cpp:145
CSource::FindPin
STDMETHODIMP FindPin(LPCWSTR Id, __deref_out IPin **ppPin)
Definition: source.cpp:128
CSourceStream::CMD_PAUSE
@ CMD_PAUSE
Definition: source.h:135
CSourceStream::Exit
HRESULT Exit(void)
Definition: source.h:137
CSourceStream::CheckRequest
BOOL CheckRequest(Command *pCom)
Definition: source.h:144
CSourceStream::Pause
HRESULT Pause(void)
Definition: source.h:139
CBaseOutputPin::Active
HRESULT Active(void)
Definition: amfilter.cpp:2716