1 /*
2  * Modified for use with MPlayer, detailed changelog at
3  * http://svn.mplayerhq.hu/mplayer/trunk/
4  */
5 
6 #include "loader/wine/winerror.h"
7 #include "loader/wine/windef.h"
8 #include "outputpin.h"
9 #include "mediatype.h"
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 
output_unimplemented(const char * s,void * p)14 static inline int output_unimplemented(const char* s, void* p)
15 {
16     Debug printf("%s(%p) called (UNIMPLEMENTED)", s, p);
17     return E_NOTIMPL;
18 }
19 
20 /**
21     An object beyond interface IEnumMediaTypes.
22     Returned by COutputPin through call IPin::EnumMediaTypes().
23 */
24 typedef struct CEnumMediaTypes
25 {
26     IEnumMediaTypes_vt* vt;
27     DECLARE_IUNKNOWN();
28     AM_MEDIA_TYPE type;
29     GUID interfaces[2];
30 } CEnumMediaTypes;
31 
32 /**
33    IMemOutput interface implementation
34 */
35 struct COutputMemPin
36 {
37     IMemInputPin_vt* vt;
38     DECLARE_IUNKNOWN();
39     char** frame_pointer;
40     long* frame_size_pointer;
41     MemAllocator* pAllocator;
42     COutputPin* parent;
43 };
44 
45 /**
46  * \brief IEnumMediaTypes:Next (retrives a specified number of media types )
47  *
48  * \param[in]  This pointer to CEnumMediaTypes object
49  * \param[in]  cMediaTypes number of media types to retrive
50  * \param[out] ppMediaTypes array of AM_MEDIA_TYPE structure pointers of size cMediaTypes
51  * \param[out] pcFetched address of variables that receives number of returned media types
52  *
53  * \return S_OK - success
54  * \return S_FALSE - did not return as meny structures as requested
55  * \return E_INVALIDARG Invalid argument
56  * \return E_POINTER Null pointer
57  * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
58  *
59  */
CEnumMediaTypes_Next(IEnumMediaTypes * This,ULONG cMediaTypes,AM_MEDIA_TYPE ** ppMediaTypes,ULONG * pcFetched)60 static HRESULT STDCALL CEnumMediaTypes_Next(IEnumMediaTypes * This,
61 					    /* [in] */ ULONG cMediaTypes,
62 					    /* [size_is][out] */ AM_MEDIA_TYPE **ppMediaTypes,
63 					    /* [out] */ ULONG *pcFetched)
64 {
65     AM_MEDIA_TYPE* type = &((CEnumMediaTypes*)This)->type;
66     Debug printf("CEnumMediaTypes::Next(%p) called\n", This);
67     if (!ppMediaTypes)
68 	return E_INVALIDARG;
69     if (!pcFetched && (cMediaTypes!=1))
70 	return E_INVALIDARG;
71     if (cMediaTypes <= 0)
72 	return 0;
73 
74     if (pcFetched)
75 	*pcFetched=1;
76     ppMediaTypes[0] = CreateMediaType(type);
77 
78     if (cMediaTypes == 1)
79 	return 0;
80     return 1;
81 }
82 
83 /* I expect that these methods are unused. */
84 
85 /**
86  * \brief IEnumMediaTypes::Skip (skips over a specified number of media types)
87  *
88  * \param[in]  This pointer to CEnumMEdiaTypes object
89  * \param[in]  cMediaTypes number of media types to skip
90  *
91  * \return S_OK - success
92  * \return S_FALSE - skipped past the end of the sequence
93  * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
94  *
95  */
CEnumMediaTypes_Skip(IEnumMediaTypes * This,ULONG cMediaTypes)96 static HRESULT STDCALL CEnumMediaTypes_Skip(IEnumMediaTypes * This,
97 					    /* [in] */ ULONG cMediaTypes)
98 {
99     return output_unimplemented("CEnumMediaTypes::Skip", This);
100 }
101 
102 /**
103  * \brief IEnumMediaTypes::Reset (resets enumeration sequence to beginning)
104  *
105  * \param[in]  This pointer to CEnumMEdiaTypes object
106  *
107  * \return S_OK - success
108  *
109  */
CEnumMediaTypes_Reset(IEnumMediaTypes * This)110 static HRESULT STDCALL CEnumMediaTypes_Reset(IEnumMediaTypes * This)
111 {
112     Debug printf("CEnumMediaTypes::Reset(%p) called\n", This);
113     return 0;
114 }
115 
116 /**
117  * \brief IEnumMediaTypes::Clone (makes a copy of enumerator, returned object
118  *        starts at the same position as original)
119  *
120  * \param[in]  This pointer to CEnumMEdiaTypes object
121  * \param[out] ppEnum address of variable that receives pointer to IEnumMediaTypes interface
122  *
123  * \return S_OK - success
124  * \return E_OUTOFMEMRY - Insufficient memory
125  * \return E_POINTER - Null pointer
126  * \return VFW_E_ENUM_OUT_OF_SYNC - pin's state has changed and is now inconsistent with enumerator
127  *
128  */
CEnumMediaTypes_Clone(IEnumMediaTypes * This,IEnumMediaTypes ** ppEnum)129 static HRESULT STDCALL CEnumMediaTypes_Clone(IEnumMediaTypes * This,
130 				      /* [out] */ IEnumMediaTypes **ppEnum)
131 {
132     Debug printf("CEnumMediaTypes::Clone(%p) called\n", This);
133     return E_NOTIMPL;
134 }
135 
136 /**
137  * \brief CEnumMediaTypes destructor
138  *
139  * \param[in]  This pointer to CEnumMediaTypes object
140  *
141  */
CEnumMediaTypes_Destroy(CEnumMediaTypes * This)142 static void CEnumMediaTypes_Destroy(CEnumMediaTypes* This)
143 {
144     FreeMediaType(&(This->type));
145     free(This->vt);
146     free(This);
147 }
148 
149 // IEnumMediaTypes->IUnknown methods
IMPLEMENT_IUNKNOWN(CEnumMediaTypes)150 IMPLEMENT_IUNKNOWN(CEnumMediaTypes)
151 
152 /**
153  * \brief CEnumMediaTypes constructor
154  *
155  * \param[in]  amt media type for enumerating
156  *
157  * \return pointer to CEnumMEdiaTypes object or NULL if error occured
158  *
159  */
160 static CEnumMediaTypes* CEnumMediaTypesCreate(const AM_MEDIA_TYPE* amt)
161 {
162     CEnumMediaTypes *This = malloc(sizeof(CEnumMediaTypes)) ;
163 
164     if (!This)
165         return NULL;
166 
167     This->vt = malloc(sizeof(IEnumMediaTypes_vt));
168     if (!This->vt)
169     {
170 	free(This);
171 	return NULL;
172     }
173 
174     This->refcount = 1;
175     CopyMediaType(&(This->type),amt);
176 
177     This->vt->QueryInterface = CEnumMediaTypes_QueryInterface;
178     This->vt->AddRef = CEnumMediaTypes_AddRef;
179     This->vt->Release = CEnumMediaTypes_Release;
180     This->vt->Next = CEnumMediaTypes_Next;
181     This->vt->Skip = CEnumMediaTypes_Skip;
182     This->vt->Reset = CEnumMediaTypes_Reset;
183     This->vt->Clone = CEnumMediaTypes_Clone;
184 
185     This->interfaces[0] = IID_IUnknown;
186     This->interfaces[1] = IID_IEnumMediaTypes;
187 
188     return This;
189 }
190 
191 
192 /*************
193  * COutputPin
194  *
195  * WARNING:
196  * This is implementation of INPUT pin in DirectShow's terms
197  *
198  *************/
199 
200 
201 /**
202  *
203  * \brief IUnknown::QueryInterface (query object for interface)
204  * \param[in]  This pointer to IUnknown interface
205  * \param[in]  iid  GUID of requested interface
206  * \param[out] ppv  receives pointer to interface
207  *
208  * \return S_OK - success (and *ppv contains valid pointer)
209  * \return E_NOINTERFACE - interface not found (and *ppv was set NULL)
210  *
211  * \note
212  * Make sure to call Release on received interface when you are done
213  *
214  */
COutputPin_QueryInterface(IUnknown * This,const GUID * iid,void ** ppv)215 static HRESULT STDCALL COutputPin_QueryInterface(IUnknown* This, const GUID* iid, void** ppv)
216 {
217     COutputPin* p = (COutputPin*) This;
218 
219     Debug printf("COutputPin_QueryInterface(%p) called\n", This);
220     if (!ppv)
221 	return E_INVALIDARG;
222 
223     if (memcmp(iid, &IID_IUnknown, 16) == 0)
224     {
225 	*ppv = p;
226 	p->vt->AddRef(This);
227         return 0;
228     }
229     if (memcmp(iid, &IID_IMemInputPin, 16) == 0)
230     {
231 	*ppv = p->mempin;
232 	p->mempin->vt->AddRef((IUnknown*)*ppv);
233 	return 0;
234     }
235 
236     Debug printf("Unknown interface : %08x-%04x-%04x-%02x%02x-"
237 		 "%02x%02x%02x%02x%02x%02x\n",
238 		 iid->f1,  iid->f2,  iid->f3,
239 		 (unsigned char)iid->f4[1], (unsigned char)iid->f4[0],
240 		 (unsigned char)iid->f4[2], (unsigned char)iid->f4[3],
241 		 (unsigned char)iid->f4[4], (unsigned char)iid->f4[5],
242 		 (unsigned char)iid->f4[6], (unsigned char)iid->f4[7]);
243     return E_NOINTERFACE;
244 }
245 
246 // IPin methods
247 
248 /**
249  * \brief IPin::Connect (connects pin to another pin)
250  *
251  * \param[in] This          pointer to IPin interface
252  * \param[in] pReceivePin   pointer to IPin interface of remote pin
253  * \param[in] pmt suggested media type for link. Can be NULL (any media type)
254  *
255  * \return S_OK - success.
256  * \return VFW_E_ALREADY_CONNECTED - pin already connected
257  * \return VFW_E_NOT_STOPPED - filter is active
258  * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
259  * \return Apropriate error code otherwise.
260  *
261  */
COutputPin_Connect(IPin * This,IPin * pReceivePin,AM_MEDIA_TYPE * pmt)262 static HRESULT STDCALL COutputPin_Connect(IPin * This,
263 				    /* [in] */ IPin *pReceivePin,
264 				    /* [in] */ /* const */ AM_MEDIA_TYPE *pmt)
265 {
266     Debug printf("COutputPin_Connect(%p) called\n",This);
267 /*
268     *pmt=((COutputPin*)This)->type;
269     if(pmt->cbFormat>0)
270     {
271 	pmt->pbFormat=malloc(pmt->cbFormat);
272 	memcpy(pmt->pbFormat, ((COutputPin*)This)->type.pbFormat, pmt->cbFormat);
273     }
274 */
275     //return E_NOTIMPL;
276     return 0;// XXXXXXXXXXXXX CHECKME XXXXXXXXXXXXXXX
277     // if I put return 0; here, it crashes
278 }
279 
280 /**
281  * \brief IPin::ReceiveConnection (accepts a connection from another pin)
282  *
283  * \param[in] This       pointer to IPin interface
284  * \param[in] pConnector connecting pin's IPin interface
285  * \param[in] pmt        suggested media type for connection
286  *
287  * \return S_OK - success
288  * \return E_POINTER - Null pointer
289  * \return VFW_E_ALREADY_CONNECTED - pin already connected
290  * \return VFW_E_NOT_STOPPED - filter is active
291  * \return VFW_E_TYPE_NOT_ACCEPT - type is not acceptable
292  *
293  * \note
294  * When returning S_OK method should also do the following:
295  *  - store media type and return the same type in IPin::ConnectionMediaType
296  *  - store pConnector and return it in IPin::ConnectedTo
297  *
298  */
COutputPin_ReceiveConnection(IPin * This,IPin * pConnector,const AM_MEDIA_TYPE * pmt)299 static HRESULT STDCALL COutputPin_ReceiveConnection(IPin * This,
300 						    /* [in] */ IPin *pConnector,
301 						    /* [in] */ const AM_MEDIA_TYPE *pmt)
302 {
303     Debug printf("COutputPin_ReceiveConnection(%p) called\n", This);
304     ((COutputPin*)This)->remote = pConnector;
305     return 0;
306 }
307 
308 /**
309  * \brief IPin::Disconnect (accepts a connection from another pin)
310  *
311  * \param[in] This pointer to IPin interface
312  *
313  * \return S_OK - success
314  * \return S_FALSE - pin was not connected
315  * \return VFW_E_NOT_STOPPED - filter is active
316  *
317  * \note
318  *   To break connection you have to also call Disconnect on other pin
319  */
COutputPin_Disconnect(IPin * This)320 static HRESULT STDCALL COutputPin_Disconnect(IPin * This)
321 {
322     Debug printf("COutputPin_Disconnect(%p) called\n", This);
323     return 1;
324 }
325 
326 /**
327  * \brief IPin::ConnectedTo (retrieves pointer to the connected pin, if such exist)
328  *
329  * \param[in]  This pointer to IPin interface
330  * \param[out] pPin pointer to remote pin's IPin interface
331  *
332  * \return S_OK - success
333  * \return E_POINTER - Null pointer
334  * \return VFW_E_NOT_CONNECTED - pin is not connected
335  *
336  * \note
337  * Caller must call Release on received IPin, when done
338  */
COutputPin_ConnectedTo(IPin * This,IPin ** pPin)339 static HRESULT STDCALL COutputPin_ConnectedTo(IPin * This,
340 					/* [out] */ IPin **pPin)
341 {
342     Debug printf("COutputPin_ConnectedTo(%p) called\n", This);
343     if (!pPin)
344 	return E_INVALIDARG;
345     *pPin = ((COutputPin*)This)->remote;
346     return 0;
347 }
348 
349 /**
350  * \brief IPin::ConnectionMediaType (retrieves media type for connection, if such exist)
351  *
352  * \param[in]  This pointer to IPin interface
353  * \param[out] pmt pointer to AM_MEDIA_TYPE,  that receives connection media type
354  *
355  * \return S_OK - success
356  * \return E_POINTER - Null pointer
357  * \return VFW_E_NOT_CONNECTED - pin is not connected
358  *
359  */
COutputPin_ConnectionMediaType(IPin * This,AM_MEDIA_TYPE * pmt)360 static HRESULT STDCALL COutputPin_ConnectionMediaType(IPin * This,
361 						      /* [out] */ AM_MEDIA_TYPE *pmt)
362 {
363     Debug printf("COutputPin_ConnectionMediaType(%p) called\n",This);
364     if (!pmt)
365 	return E_INVALIDARG;
366     CopyMediaType(pmt,&(((COutputPin*)This)->type));
367     return 0;
368 }
369 
370 /**
371  * \brief IPin::QueryPinInfo (retrieves information about the pin)
372  *
373  * \param[in]  This  pointer to IPin interface
374  * \param[out] pInfo pointer to PIN_INFO structure, that receives pin info
375  *
376  * \return S_OK - success
377  * \return E_POINTER - Null pointer
378  *
379  * \note
380  * If pInfo->pFilter is not NULL, then caller must call Release on pInfo->pFilter when done
381  *
382  */
COutputPin_QueryPinInfo(IPin * This,PIN_INFO * pInfo)383 static HRESULT STDCALL COutputPin_QueryPinInfo(IPin * This,
384 					       /* [out] */ PIN_INFO *pInfo)
385 {
386     return output_unimplemented("COutputPin_QueryPinInfo", This);
387 }
388 
389 /**
390  * \brief IPin::QueryDirection (retrieves pin direction)
391  *
392  * \param[in]  This    pointer to IPin interface
393  * \param[out] pPinDir pointer to variable, that receives pin direction (PINDIR_INPUT,PINDIR_OUTPUT)
394  *
395  * \return S_OK - success
396  * \return E_POINTER - Null pointer
397  *
398  */
COutputPin_QueryDirection(IPin * This,PIN_DIRECTION * pPinDir)399 static HRESULT STDCALL COutputPin_QueryDirection(IPin * This,
400 					   /* [out] */ PIN_DIRECTION *pPinDir)
401 {
402     Debug printf("COutputPin_QueryDirection(%p) called\n", This);
403     if (!pPinDir)
404 	return E_INVALIDARG;
405     *pPinDir = PINDIR_INPUT;
406     return 0;
407 }
408 
409 /**
410  * \brief IPin::QueryId (retrieves pin identificator)
411  *
412  * \param[in]  This pointer to IPin interface
413  * \param[out] Id   adress of variable, that receives string with pin's Id.
414  *
415  * \return S_OK - success
416  * \return E_OUTOFMEMORY - Insufficient memory
417  * \return E_POINTER     - Null pointer
418  *
419  * \note
420  * Pin's Id is not the same as pin's name
421  *
422  */
COutputPin_QueryId(IPin * This,LPWSTR * Id)423 static HRESULT STDCALL COutputPin_QueryId(IPin * This,
424 					  /* [out] */ LPWSTR *Id)
425 {
426     return output_unimplemented("COutputPin_QueryId", This);
427 }
428 
429 /**
430  * \brief IPin::QueryAccept (determines can media type be accepted or not)
431  *
432  * \param[in] This  pointer to IPin interface
433  * \param[in] pmt   Media type to check
434  *
435  * \return S_OK - success
436  * \return S_FALSE - pin rejects media type
437  *
438  */
COutputPin_QueryAccept(IPin * This,const AM_MEDIA_TYPE * pmt)439 static HRESULT STDCALL COutputPin_QueryAccept(IPin * This,
440 					      /* [in] */ const AM_MEDIA_TYPE *pmt)
441 {
442     return output_unimplemented("COutputPin_QueryAccept", This);
443 }
444 
445 /**
446  * \brief IPin::EnumMediaTypes (enumerates the pin's preferred media types)
447  *
448  * \param[in] This  pointer to IPin interface
449  * \param[out] ppEnum adress of variable that receives pointer to IEnumMEdiaTypes interface
450  *
451  * \return S_OK - success
452  * \return E_OUTOFMEMORY - Insufficient memory
453  * \return E_POINTER     - Null pointer
454  *
455  * \note
456  * Caller must call Release on received interface when done
457  *
458  */
COutputPin_EnumMediaTypes(IPin * This,IEnumMediaTypes ** ppEnum)459 static HRESULT STDCALL COutputPin_EnumMediaTypes(IPin * This,
460 					   /* [out] */ IEnumMediaTypes **ppEnum)
461 {
462     Debug printf("COutputPin_EnumMediaTypes(%p) called\n",This);
463     if (!ppEnum)
464 	return E_INVALIDARG;
465     *ppEnum = (IEnumMediaTypes*) CEnumMediaTypesCreate(&((COutputPin*)This)->type);
466     return 0;
467 }
468 
469 /**
470  * \brief IPin::QueryInternalConnections (retries pin's internal connections)
471  *
472  * \param[in]     This  pointer to IPin interface
473  * \param[out]    apPin Array that receives pins, internally connected to this
474  * \param[in,out] nPint Size of an array
475  *
476  * \return S_OK - success
477  * \return S_FALSE - pin rejects media type
478  * \return E_NOTIMPL - not implemented
479  *
480  */
COutputPin_QueryInternalConnections(IPin * This,IPin ** apPin,ULONG * nPin)481 static HRESULT STDCALL COutputPin_QueryInternalConnections(IPin * This,
482 						     /* [out] */ IPin **apPin,
483 						     /* [out][in] */ ULONG *nPin)
484 {
485     return output_unimplemented("COutputPin_QueryInternalConnections", This);
486 }
487 
488 /**
489  * \brief IPin::EndOfStream (notifies pin, that no data is expected, until new run command)
490  *
491  * \param[in] This  pointer to IPin interface
492  *
493  * \return S_OK - success
494  * \return E_UNEXPECTED - The pin is output pin
495  *
496  * \note
497  * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream,
498  * IMemAllocator::GetBuffer runs in different (streaming) thread then other
499  * methods (application thread).
500  * IMemoryInputPin::NewSegment runs either in streaming or application thread.
501  * Developer must use critical sections for thread-safing work.
502  *
503  */
COutputPin_EndOfStream(IPin * This)504 static HRESULT STDCALL COutputPin_EndOfStream(IPin * This)
505 {
506     return output_unimplemented("COutputPin_EndOfStream", This);
507 }
508 
509 /**
510  * \brief IPin::BeginFlush (begins a flush operation)
511  *
512  * \param[in] This  pointer to IPin interface
513  *
514  * \return S_OK - success
515  * \return E_UNEXPECTED - The pin is output pin
516  *
517  */
COutputPin_BeginFlush(IPin * This)518 static HRESULT STDCALL COutputPin_BeginFlush(IPin * This)
519 {
520     return output_unimplemented("COutputPin_BeginFlush", This);
521 }
522 
523 /**
524  * \brief IPin::EndFlush (ends a flush operation)
525  *
526  * \param[in] This  pointer to IPin interface
527  *
528  * \return S_OK - success
529  * \return E_UNEXPECTED - The pin is output pin
530  *
531  */
COutputPin_EndFlush(IPin * This)532 static HRESULT STDCALL COutputPin_EndFlush(IPin * This)
533 {
534     return output_unimplemented("COutputPin_EndFlush", This);
535 }
536 
537 /**
538  * \brief IPin::NewSegment (media sample received after this call grouped as segment with common
539  *        start,stop time and rate)
540  *
541  * \param[in] This   pointer to IPin interface
542  * \param[in] tStart start time of new segment
543  * \param[in] tStop  end time of new segment
544  * \param[in] dRate  rate at wich segment should be processed
545  *
546  * \return S_OK - success
547  * \return E_UNEXPECTED - The pin is output pin
548  *
549  */
COutputPin_NewSegment(IPin * This,REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate)550 static HRESULT STDCALL COutputPin_NewSegment(IPin * This,
551 				       /* [in] */ REFERENCE_TIME tStart,
552 				       /* [in] */ REFERENCE_TIME tStop,
553 				       /* [in] */ double dRate)
554 {
555     Debug printf("COutputPin_NewSegment(%Ld,%Ld,%f) called\n",
556 		 tStart, tStop, dRate);
557     return 0;
558 }
559 
560 
561 
562 // IMemInputPin->IUnknown methods
563 
564 /**
565  * \brief IUnknown::QueryInterface (query object for interface)
566  *
567  * \param[in]  This pointer to IUnknown interface
568  * \param[in]  iid  GUID of requested interface
569  * \param[out] ppv  receives pointer to interface
570  *
571  * \return S_OK - success (and *ppv contains valid pointer)
572  * \return E_NOINTERFACE - interface not found (and *ppv was set NULL)
573  *
574  * \note
575  * Make sure to call Release on received interface when you are done
576  *
577  */
COutputMemPin_QueryInterface(IUnknown * This,const GUID * iid,void ** ppv)578 static HRESULT STDCALL COutputMemPin_QueryInterface(IUnknown* This, const GUID* iid, void** ppv)
579 {
580     COutputMemPin* p = (COutputMemPin*)This;
581 
582     Debug printf("COutputMemPin_QueryInterface(%p) called\n", This);
583     if (!ppv)
584 	return E_INVALIDARG;
585 
586     if(!memcmp(iid, &IID_IUnknown, 16))
587     {
588 	*ppv = p;
589 	p->vt->AddRef(This);
590 	return 0;
591     }
592     /*if(!memcmp(iid, &IID_IPin, 16))
593     {
594 	COutputPin* ptr=(COutputPin*)(This-1);
595 	*ppv=(void*)ptr;
596 	AddRef((IUnknown*)ptr);
597 	return 0;
598     }*/
599     if(!memcmp(iid, &IID_IMemInputPin, 16))
600     {
601 	*ppv = p;
602 	p->vt->AddRef(This);
603 	return 0;
604     }
605     Debug printf("Unknown interface : %08x-%04x-%04x-%02x%02x-" \
606 		 "%02x%02x%02x%02x%02x%02x\n",
607 		 iid->f1,  iid->f2,  iid->f3,
608 		 (unsigned char)iid->f4[1], (unsigned char)iid->f4[0],
609 		 (unsigned char)iid->f4[2], (unsigned char)iid->f4[3],
610 		 (unsigned char)iid->f4[4], (unsigned char)iid->f4[5],
611 		 (unsigned char)iid->f4[6], (unsigned char)iid->f4[7]);
612     return E_NOINTERFACE;
613 }
614 
615 // IMemInputPin methods
616 
617 /**
618  * \brief IMemInputPin::GetAllocator (retrives memory allocator, proposed by pin)
619  *
620  * \param[in]  This pointer to IMemInputPin interface
621  * \param[out]  ppAllocator  address of variable that receives allocator's IMemAllocator interface
622  *
623  * \return S_OK - success
624  * \return VFW_E_NO_ALLOCATOR - No allocator
625  *
626  * \note
627  * Make sure to call Release on received interface when you are done
628  *
629  */
COutputMemPin_GetAllocator(IMemInputPin * This,IMemAllocator ** ppAllocator)630 static HRESULT STDCALL COutputMemPin_GetAllocator(IMemInputPin* This,
631 					 /* [out] */ IMemAllocator** ppAllocator)
632 {
633     Debug printf("COutputMemPin_GetAllocator(%p, %p) called\n", This->vt, ppAllocator);
634     *ppAllocator = (IMemAllocator*) MemAllocatorCreate();
635     return 0;
636 }
637 
638 /**
639  *
640  * \brief IMemInputPin::NotifyAllocator (specifies an allocator for the connection)
641  *
642  * \param[in]  This pointer to IMemInputPin interface
643  * \param[in]  pAllocator  allocator's IMemAllocator interface
644  * \param[in]  bReadOnly specifies whether samples from allocator are readonly
645  *
646  * \return S_OK - success
647  * \return Apropriate error code otherwise
648  *
649  */
COutputMemPin_NotifyAllocator(IMemInputPin * This,IMemAllocator * pAllocator,int bReadOnly)650 static HRESULT STDCALL COutputMemPin_NotifyAllocator(IMemInputPin* This,
651 						  /* [in] */ IMemAllocator* pAllocator,
652 						  /* [in] */ int bReadOnly)
653 {
654     Debug printf("COutputMemPin_NotifyAllocator(%p, %p) called\n", This, pAllocator);
655     ((COutputMemPin*)This)->pAllocator = (MemAllocator*) pAllocator;
656     return 0;
657 }
658 
659 /**
660  * \brief IMemInputPin::GetAllocatorRequirements (retrieves allocator properties requested by
661  *        input pin)
662  *
663  * \param[in]  This pointer to IMemInputPin interface
664  * \param[out]  pProps pointer to a structure that receives allocator properties
665  *
666  * \return S_OK - success
667  * \return E_NOTIMPL - Not implemented
668  * \return E_POINTER - Null pointer
669  *
670  */
COutputMemPin_GetAllocatorRequirements(IMemInputPin * This,ALLOCATOR_PROPERTIES * pProps)671 static HRESULT STDCALL COutputMemPin_GetAllocatorRequirements(IMemInputPin* This,
672 							   /* [out] */ ALLOCATOR_PROPERTIES* pProps)
673 {
674     return output_unimplemented("COutputMemPin_GetAllocatorRequirements", This);
675 }
676 
677 /**
678  * \brief IMemInputPin::Receive (receives the next media sample int thre stream)
679  *
680  * \param[in]  This pointer to IMemInputPin interface
681  * \param[in]  pSample pointer to sample's IMediaSample interface
682  *
683  * \return S_OK - success
684  * \return S_FALSE - The sample was rejected
685  * \return E_POINTER - Null pointer
686  * \return VFW_E_INVALIDMEDIATYPE - invalid media type
687  * \return VFW_E_RUNTIME_ERROR - run-time error occured
688  * \return VFW_E_WRONG_STATE - pin is stopped
689  *
690  * \remarks
691  * Method san do on of the following:
692  * - reject sample
693  * - accept sample and process it in another thread
694  * - accept sample and process it before returning
695  *
696  * In second case method should increase reference count for sample (through AddRef)
697  * In the last case method might block indefinitely. If this might
698  * happen IMemInpuPin::ReceiveCAnBlock returns S_OK
699  *
700  * \note
701  * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream,
702  * IMemAllocator::GetBuffer runs in different (streaming) thread then other
703  * methods (application thread).
704  * IMemoryInputPin::NewSegment runs either in streaming or application thread.
705  * Developer must use critical sections for thread-safing work.
706  *
707  */
COutputMemPin_Receive(IMemInputPin * This,IMediaSample * pSample)708 static HRESULT STDCALL COutputMemPin_Receive(IMemInputPin* This,
709 					  /* [in] */ IMediaSample* pSample)
710 {
711     Debug printf("COutputMemPin_Receive(%p) called\n", This);
712     if (!pSample)
713 	return E_INVALIDARG;
714 
715     if(((COutputMemPin*)This)->parent->SampleProc)
716         return ((COutputMemPin*)This)->parent->SampleProc(((COutputMemPin*)This)->parent->pUserData,pSample);
717     //reject sample
718     return S_FALSE;
719 }
720 
721 /**
722  * \brief IMemInputPin::ReceiveMultiple (receives multiple samples in the stream)
723  *
724  * \param[in]  This pointer to IMemInputPin interface
725  * \param[in]  pSamples          pointer to array with samples
726  * \param[in]  nSamples          number of samples in array
727  * \param[out] nSamplesProcessed number of processed samples
728  *
729  * \return S_OK - success
730  * \return S_FALSE - The sample was rejected
731  * \return E_POINTER - Null pointer
732  * \return VFW_E_INVALIDMEDIATYPE - invalid media type
733  * \return VFW_E_RUNTIME_ERROR - run-time error occured
734  * \return VFW_E_WRONG_STATE - pin is stopped
735  *
736  * \remarks
737  * This method behaves like IMemInputPin::Receive but for array of samples
738  *
739  * \note
740  * IMemoryInputPin::Receive,IMemoryInputPin::ReceiveMultiple, IMemoryInputPin::EndOfStream,
741  * IMemAllocator::GetBuffer runs in different (streaming) thread then other
742  * methods (application thread).
743  * IMemoryInputPin::NewSegment runs either in streaming or application thread.
744  * Developer must use critical sections for thread-safing work.
745  *
746  */
COutputMemPin_ReceiveMultiple(IMemInputPin * This,IMediaSample ** pSamples,long nSamples,long * nSamplesProcessed)747 static HRESULT STDCALL COutputMemPin_ReceiveMultiple(IMemInputPin * This,
748 					    /* [size_is][in] */ IMediaSample **pSamples,
749 					    /* [in] */ long nSamples,
750 					    /* [out] */ long *nSamplesProcessed)
751 {
752     HRESULT hr;
753     Debug printf("COutputMemPin_ReceiveMultiple(%p) %ld\n", This,nSamples);
754     for(*nSamplesProcessed=0; *nSamplesProcessed < nSamples; *nSamplesProcessed++) {
755          hr = This->vt->Receive(This,pSamples[*nSamplesProcessed]);
756          if (hr != S_OK) break;
757     }
758     return hr;
759 }
760 
761 /**
762  * \brief IMemInputPin::ReceiveCanBlock (determines whether IMemInputPin:::Receive might block)
763  *
764  * \param[in]  This pointer to IMemInputPin interface
765  *
766  * \return S_OK - the pin might block
767  * \return S_FALSE - the pin will not block
768  *
769  */
COutputMemPin_ReceiveCanBlock(IMemInputPin * This)770 static HRESULT STDCALL COutputMemPin_ReceiveCanBlock(IMemInputPin * This)
771 {
772     return output_unimplemented("COutputMemPin_ReceiveCanBlock", This);
773 }
774 
775 /**
776  * \brief COutputPin::SetNewFormat(sets new media format for the pin)
777  *
778  * \param[in]  This pointer to COutputPin class
779  * \param[in]  amt  new media format
780  *
781  */
COutputPin_SetNewFormat(COutputPin * This,const AM_MEDIA_TYPE * amt)782 static void COutputPin_SetNewFormat(COutputPin* This, const AM_MEDIA_TYPE* amt)
783 {
784     CopyMediaType(&(This->type),amt);
785 }
786 
787 /**
788  * \brief COutputPin destructor
789  *
790  * \param[in]  This pointer to COutputPin class
791  *
792  */
COutputPin_Destroy(COutputPin * This)793 static void COutputPin_Destroy(COutputPin* This)
794 {
795     free(This->mempin->vt);
796     free(This->mempin);
797     free(This->vt);
798     FreeMediaType(&(This->type));
799     free(This);
800 }
801 
802 /**
803  * \brief IUnknown::AddRef (increases reference counter for interface)
804  *
805  * \param[in]  This pointer to IUnknown class
806  *
807  * \return new value of reference counter
808  *
809  * \remarks
810  * Return value should be used only for debug purposes
811  *
812  */
COutputPin_AddRef(IUnknown * This)813 static HRESULT STDCALL COutputPin_AddRef(IUnknown* This)
814 {
815     Debug printf("COutputPin_AddRef(%p) called (%d)\n", This, ((COutputPin*)This)->refcount);
816     ((COutputPin*)This)->refcount++;
817     return 0;
818 }
819 
820 /**
821  * \brief IUnknown::Release (desreases reference counter for interface)
822  *
823  * \param[in]  This pointer to IUnknown class
824  *
825  * \return new value of reference counter
826  *
827  * \remarks
828  * When reference counter reaches zero calls destructor
829  * Return value should be used only for debug purposes
830  *
831  */
COutputPin_Release(IUnknown * This)832 static HRESULT STDCALL COutputPin_Release(IUnknown* This)
833 {
834     Debug printf("COutputPin_Release(%p) called (%d)\n", This, ((COutputPin*)This)->refcount);
835     if (--((COutputPin*)This)->refcount <= 0)
836 	COutputPin_Destroy((COutputPin*)This);
837 
838     return 0;
839 }
840 
841 /**
842  * \brief IUnknown::AddRef (increases reference counter for interface)
843  *
844  * \param[in]  This pointer to IUnknown class
845  *
846  * \return new value of reference counter
847  *
848  * \remarks
849  * Return value should be used only for debug purposes
850  *
851  */
COutputMemPin_AddRef(IUnknown * This)852 static HRESULT STDCALL COutputMemPin_AddRef(IUnknown* This)
853 {
854     COutputMemPin* p = (COutputMemPin*) This;
855     Debug printf("COutputMemPin_AddRef(%p) called (%p, %d)\n", p, p->parent, p->parent->refcount);
856     p->parent->refcount++;
857     return 0;
858 }
859 
860 /**
861  * \brief IUnknown::Release (desreases reference counter for interface)
862  *
863  * \param[in]  This pointer to IUnknown class
864  *
865  * \return new value of reference counter
866  *
867  * \remarks
868  * When reference counter reaches zero calls destructor
869  * Return value should be used only for debug purposes
870  *
871  */
COutputMemPin_Release(IUnknown * This)872 static HRESULT STDCALL COutputMemPin_Release(IUnknown* This)
873 {
874     COutputMemPin* p = (COutputMemPin*) This;
875     Debug printf("COutputMemPin_Release(%p) called (%p,   %d)\n",
876 		 p, p->parent, p->parent->refcount);
877     if (--p->parent->refcount <= 0)
878 	COutputPin_Destroy(p->parent);
879     return 0;
880 }
881 
882 /**
883  * \brief COutputPin constructor
884  *
885  * \param[in]  amt media type for pin
886  *
887  * \return pointer to COutputPin if success
888  * \return NULL if error occured
889  *
890  */
COutputPinCreate(const AM_MEDIA_TYPE * amt,SAMPLEPROC SampleProc,void * pUserData)891 COutputPin* COutputPinCreate(const AM_MEDIA_TYPE* amt,SAMPLEPROC SampleProc,void* pUserData)
892 {
893     COutputPin* This = malloc(sizeof(COutputPin));
894     IMemInputPin_vt* ivt;
895 
896     if (!This)
897         return NULL;
898 
899     This->vt = malloc(sizeof(IPin_vt));
900     This->mempin = malloc(sizeof(COutputMemPin));
901     ivt = malloc(sizeof(IMemInputPin_vt));
902 
903     if (!This->vt || !This->mempin || !ivt)
904     {
905         COutputPin_Destroy(This);
906         free(ivt);
907 	return NULL;
908     }
909 
910     This->SampleProc=SampleProc;
911     This->pUserData=pUserData;
912 
913     This->mempin->vt = ivt;
914 
915     This->refcount = 1;
916     This->remote = 0;
917     CopyMediaType(&(This->type),amt);
918 
919     This->vt->QueryInterface = COutputPin_QueryInterface;
920     This->vt->AddRef = COutputPin_AddRef;
921     This->vt->Release = COutputPin_Release;
922     This->vt->Connect = COutputPin_Connect;
923     This->vt->ReceiveConnection = COutputPin_ReceiveConnection;
924     This->vt->Disconnect = COutputPin_Disconnect;
925     This->vt->ConnectedTo = COutputPin_ConnectedTo;
926     This->vt->ConnectionMediaType = COutputPin_ConnectionMediaType;
927     This->vt->QueryPinInfo = COutputPin_QueryPinInfo;
928     This->vt->QueryDirection = COutputPin_QueryDirection;
929     This->vt->QueryId = COutputPin_QueryId;
930     This->vt->QueryAccept = COutputPin_QueryAccept;
931     This->vt->EnumMediaTypes = COutputPin_EnumMediaTypes;
932     This->vt->QueryInternalConnections = COutputPin_QueryInternalConnections;
933     This->vt->EndOfStream = COutputPin_EndOfStream;
934     This->vt->BeginFlush = COutputPin_BeginFlush;
935     This->vt->EndFlush = COutputPin_EndFlush;
936     This->vt->NewSegment = COutputPin_NewSegment;
937 
938     This->mempin->vt->QueryInterface = COutputMemPin_QueryInterface;
939     This->mempin->vt->AddRef = COutputMemPin_AddRef;
940     This->mempin->vt->Release = COutputMemPin_Release;
941     This->mempin->vt->GetAllocator = COutputMemPin_GetAllocator;
942     This->mempin->vt->NotifyAllocator = COutputMemPin_NotifyAllocator;
943     This->mempin->vt->GetAllocatorRequirements = COutputMemPin_GetAllocatorRequirements;
944     This->mempin->vt->Receive = COutputMemPin_Receive;
945     This->mempin->vt->ReceiveMultiple = COutputMemPin_ReceiveMultiple;
946     This->mempin->vt->ReceiveCanBlock = COutputMemPin_ReceiveCanBlock;
947 
948     This->mempin->frame_size_pointer = 0;
949     This->mempin->frame_pointer = 0;
950     This->mempin->pAllocator = 0;
951     This->mempin->refcount = 1;
952     This->mempin->parent = This;
953 
954     This->SetNewFormat = COutputPin_SetNewFormat;
955 
956     return This;
957 }
958