kernel32: Update function docs for GetBinayType.
[wine] / dlls / strmbase / transform.c
1 /*
2  * Transform Filter (Base for decoders, etc...)
3  *
4  * Copyright 2005 Christian Costa
5  * Copyright 2010 Aric Stewart, CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 #include "config.h"
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "dshow.h"
29 #include "amvideo.h"
30 #include "strmif.h"
31 #include "vfw.h"
32
33 #include <assert.h>
34
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "wine/strmbase.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
40
41 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
42 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
43
44 static const IBaseFilterVtbl TransformFilter_Vtbl;
45 static const IPinVtbl TransformFilter_InputPin_Vtbl;
46 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
47
48 static HRESULT WINAPI TransformFilter_Input_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
49 {
50     BaseInputPin* This = (BaseInputPin*) iface;
51     TransformFilter * pTransform;
52
53     TRACE("%p\n", iface);
54     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
55
56     if (pTransform->pFuncsTable->pfnCheckInputType)
57         return pTransform->pFuncsTable->pfnCheckInputType(pTransform, pmt);
58     /* Assume OK if there's no query method (the connection will fail if
59        needed) */
60     return S_OK;
61 }
62
63 static HRESULT WINAPI TransformFilter_Input_Receive(BaseInputPin *This, IMediaSample *pInSample)
64 {
65     HRESULT hr = S_FALSE;
66     TransformFilter * pTransform;
67     TRACE("%p\n", This);
68     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
69
70     EnterCriticalSection(&pTransform->filter.csFilter);
71     if (pTransform->filter.state == State_Stopped)
72     {
73         LeaveCriticalSection(&pTransform->filter.csFilter);
74         return VFW_E_WRONG_STATE;
75     }
76
77     if (This->end_of_stream || This->flushing)
78     {
79         LeaveCriticalSection(&pTransform->filter.csFilter);
80         return S_FALSE;
81     }
82     LeaveCriticalSection(&pTransform->filter.csFilter);
83
84     if (pTransform->pFuncsTable->pfnReceive)
85         hr = pTransform->pFuncsTable->pfnReceive(pTransform, pInSample);
86     else
87         hr = S_FALSE;
88
89     return hr;
90 }
91
92 static HRESULT WINAPI TransformFilter_Output_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt)
93 {
94     BasePin *This = (BasePin *)iface;
95     TransformFilter *pTransformFilter = (TransformFilter *)This->pinInfo.pFilter;
96     AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
97     TRACE("%p\n", iface);
98
99     if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
100         && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
101         return S_OK;
102     return S_FALSE;
103 }
104
105 static HRESULT WINAPI TransformFilter_Output_DecideBufferSize(BaseOutputPin *This, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
106 {
107     TransformFilter *pTransformFilter = (TransformFilter *)This->pin.pinInfo.pFilter;
108     return pTransformFilter->pFuncsTable->pfnDecideBufferSize(pTransformFilter, pAlloc, ppropInputRequest);
109 }
110
111 static HRESULT WINAPI TransformFilter_Output_GetMediaType(BasePin *This, int iPosition, AM_MEDIA_TYPE *pmt)
112 {
113     TransformFilter *pTransform = (TransformFilter *)This->pinInfo.pFilter;
114
115     if (iPosition < 0)
116         return E_INVALIDARG;
117     if (iPosition > 0)
118         return VFW_S_NO_MORE_ITEMS;
119     CopyMediaType(pmt, &pTransform->pmt);
120     return S_OK;
121 }
122
123 static IPin* WINAPI TransformFilter_GetPin(BaseFilter *iface, int pos)
124 {
125     TransformFilter *This = (TransformFilter *)iface;
126
127     if (pos >= This->npins || pos < 0)
128         return NULL;
129
130     IPin_AddRef(This->ppPins[pos]);
131     return This->ppPins[pos];
132 }
133
134 static LONG WINAPI TransformFilter_GetPinCount(BaseFilter *iface)
135 {
136     TransformFilter *This = (TransformFilter *)iface;
137
138     return (This->npins+1);
139 }
140
141 static const BaseFilterFuncTable tfBaseFuncTable = {
142     TransformFilter_GetPin,
143     TransformFilter_GetPinCount
144 };
145
146 static const  BasePinFuncTable tf_input_BaseFuncTable = {
147     TransformFilter_Input_CheckMediaType,
148     NULL,
149     BasePinImpl_GetMediaTypeVersion,
150     BasePinImpl_GetMediaType
151 };
152
153 static const BaseInputPinFuncTable tf_input_BaseInputFuncTable = {
154     TransformFilter_Input_Receive
155 };
156
157 static const  BasePinFuncTable tf_output_BaseFuncTable = {
158     NULL,
159     BaseOutputPinImpl_AttemptConnection,
160     BasePinImpl_GetMediaTypeVersion,
161     TransformFilter_Output_GetMediaType
162 };
163
164 static const BaseOutputPinFuncTable tf_output_BaseOutputFuncTable = {
165     TransformFilter_Output_DecideBufferSize,
166     BaseOutputPinImpl_DecideAllocator,
167     BaseOutputPinImpl_BreakConnect
168 };
169
170 static HRESULT TransformFilter_Init(const IBaseFilterVtbl *pVtbl, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, TransformFilter* pTransformFilter)
171 {
172     HRESULT hr;
173     PIN_INFO piInput;
174     PIN_INFO piOutput;
175
176     BaseFilter_Init(&pTransformFilter->filter, pVtbl, pClsid, (DWORD_PTR)(__FILE__ ": TransformFilter.csFilter"), &tfBaseFuncTable);
177
178     /* pTransformFilter is already allocated */
179     pTransformFilter->pFuncsTable = pFuncsTable;
180     ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
181     pTransformFilter->npins = 2;
182
183     pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
184
185     /* construct input pin */
186     piInput.dir = PINDIR_INPUT;
187     piInput.pFilter = (IBaseFilter *)pTransformFilter;
188     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
189     piOutput.dir = PINDIR_OUTPUT;
190     piOutput.pFilter = (IBaseFilter *)pTransformFilter;
191     lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
192
193     hr = BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, &tf_input_BaseFuncTable, &tf_input_BaseInputFuncTable, &pTransformFilter->filter.csFilter, NULL, &pTransformFilter->ppPins[0]);
194
195     if (SUCCEEDED(hr))
196     {
197         hr = BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(BaseOutputPin), &piOutput, &tf_output_BaseFuncTable, &tf_output_BaseOutputFuncTable, &pTransformFilter->filter.csFilter, &pTransformFilter->ppPins[1]);
198
199         if (FAILED(hr))
200             ERR("Cannot create output pin (%x)\n", hr);
201     }
202     if (FAILED(hr))
203     {
204         CoTaskMemFree(pTransformFilter->ppPins);
205         BaseFilterImpl_Release((IBaseFilter*)pTransformFilter);
206     }
207
208     return hr;
209 }
210
211 HRESULT TransformFilter_Construct(const IBaseFilterVtbl *pVtbl, LONG filter_size, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, IBaseFilter ** ppTransformFilter)
212 {
213     TransformFilter* pTf;
214
215     *ppTransformFilter = NULL;
216
217     assert(filter_size >= sizeof(TransformFilter));
218
219     pTf = CoTaskMemAlloc(filter_size);
220     ZeroMemory(pTf, filter_size);
221
222     if (!pTf)
223         return E_OUTOFMEMORY;
224
225     if (SUCCEEDED(TransformFilter_Init(pVtbl, pClsid, pFuncsTable, pTf)))
226     {
227         *ppTransformFilter = (IBaseFilter*)(&pTf->filter.lpVtbl);
228         return S_OK;
229     }
230
231     CoTaskMemFree(pTf);
232     return E_FAIL;
233 }
234
235 HRESULT WINAPI TransformFilterImpl_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
236 {
237     HRESULT hr;
238     TransformFilter *This = (TransformFilter *)iface;
239     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
240
241     hr = BaseFilterImpl_QueryInterface(iface, riid, ppv);
242
243     if (FAILED(hr) && (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)))
244         FIXME("No interface for %s!\n", debugstr_guid(riid));
245
246     return hr;
247 }
248
249 ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
250 {
251     TransformFilter *This = (TransformFilter *)iface;
252     ULONG refCount = BaseFilterImpl_Release(iface);
253
254     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
255
256     if (!refCount)
257     {
258         ULONG i;
259
260         for (i = 0; i < This->npins; i++)
261         {
262             IPin *pConnectedTo;
263
264             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
265             {
266                 IPin_Disconnect(pConnectedTo);
267                 IPin_Release(pConnectedTo);
268             }
269             IPin_Disconnect(This->ppPins[i]);
270
271             IPin_Release(This->ppPins[i]);
272         }
273
274         CoTaskMemFree(This->ppPins);
275
276         TRACE("Destroying transform filter\n");
277         FreeMediaType(&This->pmt);
278         CoTaskMemFree(This);
279
280         return 0;
281     }
282     else
283         return refCount;
284 }
285
286 /** IMediaFilter methods **/
287
288 HRESULT WINAPI TransformFilterImpl_Stop(IBaseFilter * iface)
289 {
290     TransformFilter *This = (TransformFilter *)iface;
291     HRESULT hr = S_OK;
292
293     TRACE("(%p/%p)\n", This, iface);
294
295     EnterCriticalSection(&This->filter.csFilter);
296     {
297         This->filter.state = State_Stopped;
298         if (This->pFuncsTable->pfnStopStreaming)
299             hr = This->pFuncsTable->pfnStopStreaming(This);
300     }
301     LeaveCriticalSection(&This->filter.csFilter);
302
303     return hr;
304 }
305
306 HRESULT WINAPI TransformFilterImpl_Pause(IBaseFilter * iface)
307 {
308     TransformFilter *This = (TransformFilter *)iface;
309     HRESULT hr;
310
311     TRACE("(%p/%p)->()\n", This, iface);
312
313     EnterCriticalSection(&This->filter.csFilter);
314     {
315         if (This->filter.state == State_Stopped)
316             hr = IBaseFilter_Run(iface, -1);
317         else
318             hr = S_OK;
319
320         if (SUCCEEDED(hr))
321             This->filter.state = State_Paused;
322     }
323     LeaveCriticalSection(&This->filter.csFilter);
324
325     return hr;
326 }
327
328 HRESULT WINAPI TransformFilterImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
329 {
330     HRESULT hr = S_OK;
331     TransformFilter *This = (TransformFilter *)iface;
332
333     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
334
335     EnterCriticalSection(&This->filter.csFilter);
336     {
337         if (This->filter.state == State_Stopped)
338         {
339             ((BaseInputPin *)This->ppPins[0])->end_of_stream = 0;
340             if (This->pFuncsTable->pfnStartStreaming)
341                 hr = This->pFuncsTable->pfnStartStreaming(This);
342             if (SUCCEEDED(hr))
343                 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[1]);
344         }
345
346         if (SUCCEEDED(hr))
347         {
348             This->filter.rtStreamStart = tStart;
349             This->filter.state = State_Running;
350         }
351     }
352     LeaveCriticalSection(&This->filter.csFilter);
353
354     return hr;
355 }
356
357 /** IBaseFilter implementation **/
358
359 HRESULT WINAPI TransformFilterImpl_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
360 {
361     TransformFilter *This = (TransformFilter *)iface;
362
363     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
364
365     return E_NOTIMPL;
366 }
367
368 static const IBaseFilterVtbl TransformFilter_Vtbl =
369 {
370     TransformFilterImpl_QueryInterface,
371     BaseFilterImpl_AddRef,
372     TransformFilterImpl_Release,
373     BaseFilterImpl_GetClassID,
374     TransformFilterImpl_Stop,
375     TransformFilterImpl_Pause,
376     TransformFilterImpl_Run,
377     BaseFilterImpl_GetState,
378     BaseFilterImpl_SetSyncSource,
379     BaseFilterImpl_GetSyncSource,
380     BaseFilterImpl_EnumPins,
381     TransformFilterImpl_FindPin,
382     BaseFilterImpl_QueryFilterInfo,
383     BaseFilterImpl_JoinFilterGraph,
384     BaseFilterImpl_QueryVendorInfo
385 };
386
387 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
388 {
389     BaseInputPin* This = (BaseInputPin*) iface;
390     TransformFilter* pTransform;
391     IPin* ppin;
392     HRESULT hr;
393
394     TRACE("(%p)->()\n", iface);
395
396     /* Since we process samples synchronously, just forward notification downstream */
397     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
398     if (!pTransform)
399         hr = E_FAIL;
400     else
401         hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
402     if (SUCCEEDED(hr))
403     {
404         hr = IPin_EndOfStream(ppin);
405         IPin_Release(ppin);
406     }
407
408     if (FAILED(hr))
409         ERR("%x\n", hr);
410     return hr;
411 }
412
413 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
414 {
415     BaseInputPin* This = (BaseInputPin*) iface;
416     TransformFilter* pTransform;
417     HRESULT hr = S_OK;
418
419     TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
420
421     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
422
423     if (pTransform->pFuncsTable->pfnSetMediaType)
424         hr = pTransform->pFuncsTable->pfnSetMediaType(pTransform, PINDIR_INPUT, pmt);
425
426     if (SUCCEEDED(hr) && pTransform->pFuncsTable->pfnCompleteConnect)
427         hr = pTransform->pFuncsTable->pfnCompleteConnect(pTransform, PINDIR_INPUT, pReceivePin);
428
429     if (SUCCEEDED(hr))
430     {
431         hr = BaseInputPinImpl_ReceiveConnection(iface, pReceivePin, pmt);
432         if (FAILED(hr) && pTransform->pFuncsTable->pfnBreakConnect)
433             pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
434     }
435
436     return hr;
437 }
438
439 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
440 {
441     BaseInputPin* This = (BaseInputPin*) iface;
442     TransformFilter* pTransform;
443
444     TRACE("(%p)->()\n", iface);
445
446     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
447     if (pTransform->pFuncsTable->pfnBreakConnect)
448         pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
449
450     return BasePinImpl_Disconnect(iface);
451 }
452
453 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
454 {
455     BaseInputPin* This = (BaseInputPin*) iface;
456     TransformFilter* pTransform;
457     HRESULT hr = S_OK;
458
459     TRACE("(%p)->()\n", iface);
460
461     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
462     EnterCriticalSection(&pTransform->filter.csFilter);
463     if (pTransform->pFuncsTable->pfnBeginFlush)
464         hr = pTransform->pFuncsTable->pfnBeginFlush(pTransform);
465     if (SUCCEEDED(hr))
466         hr = BaseInputPinImpl_BeginFlush(iface);
467     LeaveCriticalSection(&pTransform->filter.csFilter);
468     return hr;
469 }
470
471 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
472 {
473     BaseInputPin* This = (BaseInputPin*) iface;
474     TransformFilter* pTransform;
475     HRESULT hr = S_OK;
476
477     TRACE("(%p)->()\n", iface);
478
479     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
480     EnterCriticalSection(&pTransform->filter.csFilter);
481     if (pTransform->pFuncsTable->pfnEndFlush)
482         hr = pTransform->pFuncsTable->pfnEndFlush(pTransform);
483     if (SUCCEEDED(hr))
484         hr = BaseInputPinImpl_EndFlush(iface);
485     LeaveCriticalSection(&pTransform->filter.csFilter);
486     return hr;
487 }
488
489 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
490 {
491     BaseInputPin* This = (BaseInputPin*) iface;
492     TransformFilter* pTransform;
493     HRESULT hr = S_OK;
494
495     TRACE("(%p)->()\n", iface);
496
497     pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
498     EnterCriticalSection(&pTransform->filter.csFilter);
499     if (pTransform->pFuncsTable->pfnNewSegment)
500         hr = pTransform->pFuncsTable->pfnNewSegment(pTransform, tStart, tStop, dRate);
501     if (SUCCEEDED(hr))
502         hr = BaseInputPinImpl_NewSegment(iface, tStart, tStop, dRate);
503     LeaveCriticalSection(&pTransform->filter.csFilter);
504     return hr;
505 }
506
507 static const IPinVtbl TransformFilter_InputPin_Vtbl =
508 {
509     BaseInputPinImpl_QueryInterface,
510     BasePinImpl_AddRef,
511     BaseInputPinImpl_Release,
512     BaseInputPinImpl_Connect,
513     TransformFilter_InputPin_ReceiveConnection,
514     TransformFilter_InputPin_Disconnect,
515     BasePinImpl_ConnectedTo,
516     BasePinImpl_ConnectionMediaType,
517     BasePinImpl_QueryPinInfo,
518     BasePinImpl_QueryDirection,
519     BasePinImpl_QueryId,
520     BaseInputPinImpl_QueryAccept,
521     BasePinImpl_EnumMediaTypes,
522     BasePinImpl_QueryInternalConnections,
523     TransformFilter_InputPin_EndOfStream,
524     TransformFilter_InputPin_BeginFlush,
525     TransformFilter_InputPin_EndFlush,
526     TransformFilter_InputPin_NewSegment
527 };
528
529 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
530 {
531     BaseOutputPinImpl_QueryInterface,
532     BasePinImpl_AddRef,
533     BaseOutputPinImpl_Release,
534     BaseOutputPinImpl_Connect,
535     BaseOutputPinImpl_ReceiveConnection,
536     BaseOutputPinImpl_Disconnect,
537     BasePinImpl_ConnectedTo,
538     BasePinImpl_ConnectionMediaType,
539     BasePinImpl_QueryPinInfo,
540     BasePinImpl_QueryDirection,
541     BasePinImpl_QueryId,
542     TransformFilter_Output_QueryAccept,
543     BasePinImpl_EnumMediaTypes,
544     BasePinImpl_QueryInternalConnections,
545     BaseOutputPinImpl_EndOfStream,
546     BaseOutputPinImpl_BeginFlush,
547     BaseOutputPinImpl_EndFlush,
548     BaseOutputPinImpl_NewSegment
549 };