Handle a number as a parameter for custom action 19.
[wine] / dlls / quartz / transform.c
1 /*
2  * Transform Filter (Base for decoders, etc...)
3  *
4  * Copyright 2005 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
27 #include "uuids.h"
28 #include "aviriff.h"
29 #include "mmreg.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "strmif.h"
36 #include "vfwmsgs.h"
37 #include "evcode.h"
38 #include "vfw.h"
39
40 #include <assert.h>
41
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
44
45 #include "transform.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
48
49 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
50 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
51
52 static const IBaseFilterVtbl TransformFilter_Vtbl;
53 static const IPinVtbl TransformFilter_InputPin_Vtbl;
54 static const IMemInputPinVtbl MemInputPin_Vtbl; 
55 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
56
57 static HRESULT TransformFilter_Sample(LPVOID iface, IMediaSample * pSample)
58 {
59     TransformFilterImpl *This = (TransformFilterImpl *)iface;
60     LPBYTE pbSrcStream = NULL;
61     long cbSrcStream = 0;
62     REFERENCE_TIME tStart, tStop;
63     HRESULT hr;
64
65     TRACE("%p %p\n", iface, pSample);
66
67     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
68     if (FAILED(hr))
69     {
70         ERR("Cannot get pointer to sample data (%lx)\n", hr);
71         return hr;
72     }
73
74     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
75     if (FAILED(hr))
76         ERR("Cannot get sample time (%lx)\n", hr);
77
78     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
79
80     TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream);
81
82 #if 0 /* For debugging purpose */
83     {
84         int i;
85         for(i = 0; i < cbSrcStream; i++)
86         {
87             if ((i!=0) && !(i%16))
88                 DPRINTF("\n");
89             DPRINTF("%02x ", pbSrcStream[i]);
90         }
91         DPRINTF("\n");
92     }
93 #endif
94
95     This->pfnProcessSample(This, pbSrcStream, cbSrcStream);
96
97     return S_OK;
98 }
99
100 static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
101 {
102     TransformFilterImpl* This = (TransformFilterImpl*)iface;
103     TRACE("%p\n", iface);
104     dump_AM_MEDIA_TYPE(pmt);
105
106     return This->pfnConnectInput(This, pmt);
107 }
108
109
110 static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
111 {
112     TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)iface;
113     AM_MEDIA_TYPE* outpmt = &((OutputPin*)pTransformFilter->ppPins[1])->pin.mtCurrent;
114     TRACE("%p\n", iface);
115
116     if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype))
117         return S_OK;
118     return S_FALSE;
119 }
120
121 static HRESULT TransformFilter_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
122 {
123     InputPin * pPinImpl;
124
125     *ppPin = NULL;
126
127     if (pPinInfo->dir != PINDIR_INPUT)
128     {
129         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
130         return E_INVALIDARG;
131     }
132
133     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
134
135     if (!pPinImpl)
136         return E_OUTOFMEMORY;
137
138     if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
139     {
140         pPinImpl->pin.lpVtbl = &TransformFilter_InputPin_Vtbl;
141         pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
142
143         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
144         return S_OK;
145     }
146     return E_FAIL;
147 }
148
149 HRESULT TransformFilter_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
150 {
151     OutputPin * pPinImpl;
152
153     *ppPin = NULL;
154
155     if (pPinInfo->dir != PINDIR_OUTPUT)
156     {
157         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
158         return E_INVALIDARG;
159     }
160
161     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
162
163     if (!pPinImpl)
164         return E_OUTOFMEMORY;
165
166     if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
167     {
168         pPinImpl->pin.lpVtbl = &TransformFilter_OutputPin_Vtbl;
169
170         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
171         return S_OK;
172     }
173     return E_FAIL;
174 }
175
176 HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, PFN_PROCESS_SAMPLE pps, PFN_CONNECT_INPUT pci, PFN_CLEANUP pcu)
177 {
178     HRESULT hr;
179     PIN_INFO piInput;
180     PIN_INFO piOutput;
181
182     /* pTransformFilter is already allocated */
183     pTransformFilter->clsid = *pClsid;
184     pTransformFilter->pfnProcessSample = pps;
185     pTransformFilter->pfnConnectInput = pci;
186     pTransformFilter->pfnCleanup = pcu;
187
188     pTransformFilter->lpVtbl = &TransformFilter_Vtbl;
189
190     pTransformFilter->refCount = 1;
191     InitializeCriticalSection(&pTransformFilter->csFilter);
192     pTransformFilter->state = State_Stopped;
193     pTransformFilter->pClock = NULL;
194     ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO));
195
196     pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
197
198     /* construct input pin */
199     piInput.dir = PINDIR_INPUT;
200     piInput.pFilter = (IBaseFilter *)pTransformFilter;
201     strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
202     piOutput.dir = PINDIR_OUTPUT;
203     piOutput.pFilter = (IBaseFilter *)pTransformFilter;
204     strncpyW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
205
206     hr = TransformFilter_InputPin_Construct(&piInput, TransformFilter_Sample, (LPVOID)pTransformFilter, TransformFilter_Input_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[0]);
207
208     if (SUCCEEDED(hr))
209     {
210         ALLOCATOR_PROPERTIES props;
211         props.cbAlign = 1;
212         props.cbPrefix = 0;
213         props.cbBuffer = 0; /* Will be updated at connection time */
214         props.cBuffers = 2;
215
216         hr = TransformFilter_OutputPin_Construct(&piOutput, &props, NULL, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
217
218         if (FAILED(hr))
219             ERR("Cannot create output pin (%lx)\n", hr);
220     }
221     else
222     {
223         CoTaskMemFree(pTransformFilter->ppPins);
224         DeleteCriticalSection(&pTransformFilter->csFilter);
225         CoTaskMemFree(pTransformFilter);
226     }
227
228     return hr;
229 }
230
231 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
232 {
233     TransformFilterImpl *This = (TransformFilterImpl *)iface;
234     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
235
236     *ppv = NULL;
237
238     if (IsEqualIID(riid, &IID_IUnknown))
239         *ppv = (LPVOID)This;
240     else if (IsEqualIID(riid, &IID_IPersist))
241         *ppv = (LPVOID)This;
242     else if (IsEqualIID(riid, &IID_IMediaFilter))
243         *ppv = (LPVOID)This;
244     else if (IsEqualIID(riid, &IID_IBaseFilter))
245         *ppv = (LPVOID)This;
246
247     if (*ppv)
248     {
249         IUnknown_AddRef((IUnknown *)(*ppv));
250         return S_OK;
251     }
252
253     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
254
255     return E_NOINTERFACE;
256 }
257
258 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
259 {
260     TransformFilterImpl *This = (TransformFilterImpl *)iface;
261     ULONG refCount = InterlockedIncrement(&This->refCount);
262
263     TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
264
265     return refCount;
266 }
267
268 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
269 {
270     TransformFilterImpl *This = (TransformFilterImpl *)iface;
271     ULONG refCount = InterlockedDecrement(&This->refCount);
272
273     TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
274
275     if (!refCount)
276     {
277         ULONG i;
278
279         DeleteCriticalSection(&This->csFilter);
280         IReferenceClock_Release(This->pClock);
281
282         for (i = 0; i < 2; i++)
283             IPin_Release(This->ppPins[i]);
284
285         HeapFree(GetProcessHeap(), 0, This->ppPins);
286         This->lpVtbl = NULL;
287
288         This->pfnCleanup(This);
289
290         TRACE("Destroying transform filter\n");
291         CoTaskMemFree(This);
292
293         return 0;
294     }
295     else
296         return refCount;
297 }
298
299 /** IPersist methods **/
300
301 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
302 {
303     TransformFilterImpl *This = (TransformFilterImpl *)iface;
304
305     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
306
307     *pClsid = This->clsid;
308
309     return S_OK;
310 }
311
312 /** IMediaFilter methods **/
313
314 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
315 {
316     TransformFilterImpl *This = (TransformFilterImpl *)iface;
317
318     TRACE("(%p/%p)\n", This, iface);
319
320     EnterCriticalSection(&This->csFilter);
321     {
322         This->state = State_Stopped;
323     }
324     LeaveCriticalSection(&This->csFilter);
325
326     return S_OK;
327 }
328
329 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
330 {
331     TransformFilterImpl *This = (TransformFilterImpl *)iface;
332
333     TRACE("(%p/%p)->()\n", This, iface);
334
335     EnterCriticalSection(&This->csFilter);
336     {
337         This->state = State_Paused;
338     }
339     LeaveCriticalSection(&This->csFilter);
340
341     return S_OK;
342 }
343
344 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
345 {
346     HRESULT hr = S_OK;
347     TransformFilterImpl *This = (TransformFilterImpl *)iface;
348
349     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
350
351     EnterCriticalSection(&This->csFilter);
352     {
353         This->rtStreamStart = tStart;
354         This->state = State_Running;
355         OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
356     }
357     LeaveCriticalSection(&This->csFilter);
358
359     return hr;
360 }
361
362 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
363 {
364     TransformFilterImpl *This = (TransformFilterImpl *)iface;
365
366     TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState);
367
368     EnterCriticalSection(&This->csFilter);
369     {
370         *pState = This->state;
371     }
372     LeaveCriticalSection(&This->csFilter);
373
374     return S_OK;
375 }
376
377 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
378 {
379     TransformFilterImpl *This = (TransformFilterImpl *)iface;
380
381     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
382
383     EnterCriticalSection(&This->csFilter);
384     {
385         if (This->pClock)
386             IReferenceClock_Release(This->pClock);
387         This->pClock = pClock;
388         if (This->pClock)
389             IReferenceClock_AddRef(This->pClock);
390     }
391     LeaveCriticalSection(&This->csFilter);
392
393     return S_OK;
394 }
395
396 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
397 {
398     TransformFilterImpl *This = (TransformFilterImpl *)iface;
399
400     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
401
402     EnterCriticalSection(&This->csFilter);
403     {
404         *ppClock = This->pClock;
405         IReferenceClock_AddRef(This->pClock);
406     }
407     LeaveCriticalSection(&This->csFilter);
408
409     return S_OK;
410 }
411
412 /** IBaseFilter implementation **/
413
414 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
415 {
416     ENUMPINDETAILS epd;
417     TransformFilterImpl *This = (TransformFilterImpl *)iface;
418
419     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
420
421     epd.cPins = 2; /* input and output pins */
422     epd.ppPins = This->ppPins;
423     return IEnumPinsImpl_Construct(&epd, ppEnum);
424 }
425
426 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
427 {
428     TransformFilterImpl *This = (TransformFilterImpl *)iface;
429
430     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
431
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
436 {
437     TransformFilterImpl *This = (TransformFilterImpl *)iface;
438
439     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
440
441     strcpyW(pInfo->achName, This->filterInfo.achName);
442     pInfo->pGraph = This->filterInfo.pGraph;
443
444     if (pInfo->pGraph)
445         IFilterGraph_AddRef(pInfo->pGraph);
446
447     return S_OK;
448 }
449
450 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
451 {
452     HRESULT hr = S_OK;
453     TransformFilterImpl *This = (TransformFilterImpl *)iface;
454
455     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
456
457     EnterCriticalSection(&This->csFilter);
458     {
459         if (pName)
460             strcpyW(This->filterInfo.achName, pName);
461         else
462             *This->filterInfo.achName = '\0';
463         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
464     }
465     LeaveCriticalSection(&This->csFilter);
466
467     return hr;
468 }
469
470 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
471 {
472     TransformFilterImpl *This = (TransformFilterImpl *)iface;
473     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
474     return E_NOTIMPL;
475 }
476
477 static const IBaseFilterVtbl TransformFilter_Vtbl =
478 {
479     TransformFilter_QueryInterface,
480     TransformFilter_AddRef,
481     TransformFilter_Release,
482     TransformFilter_GetClassID,
483     TransformFilter_Stop,
484     TransformFilter_Pause,
485     TransformFilter_Run,
486     TransformFilter_GetState,
487     TransformFilter_SetSyncSource,
488     TransformFilter_GetSyncSource,
489     TransformFilter_EnumPins,
490     TransformFilter_FindPin,
491     TransformFilter_QueryFilterInfo,
492     TransformFilter_JoinFilterGraph,
493     TransformFilter_QueryVendorInfo
494 };
495
496 static const IPinVtbl TransformFilter_InputPin_Vtbl = 
497 {
498     InputPin_QueryInterface,
499     IPinImpl_AddRef,
500     InputPin_Release,
501     InputPin_Connect,
502     InputPin_ReceiveConnection,
503     IPinImpl_Disconnect,
504     IPinImpl_ConnectedTo,
505     IPinImpl_ConnectionMediaType,
506     IPinImpl_QueryPinInfo,
507     IPinImpl_QueryDirection,
508     IPinImpl_QueryId,
509     IPinImpl_QueryAccept,
510     IPinImpl_EnumMediaTypes,
511     IPinImpl_QueryInternalConnections,
512     InputPin_EndOfStream,
513     InputPin_BeginFlush,
514     InputPin_EndFlush,
515     InputPin_NewSegment
516 };
517
518 HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
519 {
520     IPinImpl *This = (IPinImpl *)iface;
521     ENUMMEDIADETAILS emd;
522
523     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
524
525     emd.cMediaTypes = 1;
526     emd.pMediaTypes = &This->mtCurrent;
527
528     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
529 }
530
531 HRESULT WINAPI TransformFilter_Output_Disconnect(IPin * iface)
532 {
533     OutputPin* This = (OutputPin*)iface;
534     HRESULT hr;
535     TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
536
537     TRACE("(%p/%p)->()\n", This, iface);
538
539     hr = OutputPin_Disconnect(iface);
540
541     if (hr == S_OK)
542     {
543         pTransformFilter->pfnCleanup(pTransformFilter);
544     }
545
546     return hr;
547 }
548
549 static const IPinVtbl TransformFilter_OutputPin_Vtbl = 
550 {
551     OutputPin_QueryInterface,
552     IPinImpl_AddRef,
553     OutputPin_Release,
554     OutputPin_Connect,
555     OutputPin_ReceiveConnection,
556     TransformFilter_Output_Disconnect,
557     IPinImpl_ConnectedTo,
558     IPinImpl_ConnectionMediaType,
559     IPinImpl_QueryPinInfo,
560     IPinImpl_QueryDirection,
561     IPinImpl_QueryId,
562     IPinImpl_QueryAccept,
563     TransformFilter_Output_EnumMediaTypes,
564     IPinImpl_QueryInternalConnections,
565     OutputPin_EndOfStream,
566     OutputPin_BeginFlush,
567     OutputPin_EndFlush,
568     OutputPin_NewSegment
569 };
570
571 static const IMemInputPinVtbl MemInputPin_Vtbl = 
572 {
573     MemInputPin_QueryInterface,
574     MemInputPin_AddRef,
575     MemInputPin_Release,
576     MemInputPin_GetAllocator,
577     MemInputPin_NotifyAllocator,
578     MemInputPin_GetAllocatorRequirements,
579     MemInputPin_Receive,
580     MemInputPin_ReceiveMultiple,
581     MemInputPin_ReceiveCanBlock
582 };