[KSPROXY]
[reactos.git] / reactos / dll / directx / ksproxy / interface.cpp
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
4 * FILE: dll/directx/ksproxy/interface.cpp
5 * PURPOSE: IKsInterfaceHandler interface
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9 #include "precomp.h"
10
11 const GUID IID_IKsObject = {0x423c13a2, 0x2070, 0x11d0, {0x9e, 0xf7, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}};
12
13 class CKsInterfaceHandler : public IKsInterfaceHandler
14 {
15 public:
16 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
17
18 STDMETHODIMP_(ULONG) AddRef()
19 {
20 InterlockedIncrement(&m_Ref);
21 return m_Ref;
22 }
23 STDMETHODIMP_(ULONG) Release()
24 {
25 InterlockedDecrement(&m_Ref);
26
27 if (!m_Ref)
28 {
29 delete this;
30 return 0;
31 }
32 return m_Ref;
33 }
34 HRESULT STDMETHODCALLTYPE KsSetPin(IKsPin *KsPin);
35 HRESULT STDMETHODCALLTYPE KsProcessMediaSamples(IKsDataTypeHandler *KsDataTypeHandler, IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, PKSSTREAM_SEGMENT *StreamSegment);
36 HRESULT STDMETHODCALLTYPE KsCompleteIo(PKSSTREAM_SEGMENT StreamSegment);
37
38 CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0) {m_PinName[0] = L'\0';};
39 virtual ~CKsInterfaceHandler(){};
40
41 protected:
42 LONG m_Ref;
43 HANDLE m_Handle;
44 IKsPinEx * m_Pin;
45 WCHAR m_PinName[129];
46 };
47
48 typedef struct
49 {
50 KSSTREAM_SEGMENT StreamSegment;
51 OVERLAPPED Overlapped;
52 IMediaSample * MediaSample[64];
53
54 ULONG SampleCount;
55 ULONG ExtendedSize;
56 PKSSTREAM_HEADER StreamHeader;
57 }KSSTREAM_SEGMENT_EXT, *PKSSTREAM_SEGMENT_EXT;
58
59
60 HRESULT
61 STDMETHODCALLTYPE
62 CKsInterfaceHandler::QueryInterface(
63 IN REFIID refiid,
64 OUT PVOID* Output)
65 {
66 if (IsEqualGUID(refiid, IID_IUnknown) ||
67 IsEqualGUID(refiid, IID_IKsInterfaceHandler))
68 {
69 *Output = PVOID(this);
70 reinterpret_cast<IUnknown*>(*Output)->AddRef();
71 return NOERROR;
72 }
73 return E_NOINTERFACE;
74 }
75
76 HRESULT
77 STDMETHODCALLTYPE
78 CKsInterfaceHandler::KsSetPin(
79 IKsPin *KsPin)
80 {
81 HRESULT hr;
82 IKsObject * KsObject;
83 IKsPinEx * Pin;
84
85 // get IKsPinEx interface
86 hr = KsPin->QueryInterface(IID_IKsPinEx, (void**)&Pin);
87 if (SUCCEEDED(hr))
88 {
89 // check if IKsObject is supported
90 hr = KsPin->QueryInterface(IID_IKsObject, (void**)&KsObject);
91
92 if (SUCCEEDED(hr))
93 {
94 // get pin handle
95 m_Handle = KsObject->KsGetObjectHandle();
96
97 // release IKsObject interface
98 KsObject->Release();
99
100 if (!m_Handle)
101 {
102 // expected a file handle
103 hr = E_UNEXPECTED;
104 Pin->Release();
105 }
106 else
107 {
108 if (m_Pin)
109 {
110 // release old interface
111 m_Pin->Release();
112 }
113 m_Pin = Pin;
114 }
115 }
116 else
117 {
118 //release IKsPinEx interface
119 Pin->Release();
120 }
121 }
122 #if 1
123 //DBG code
124 PIN_INFO PinInfo;
125 IPin * pPin;
126 if (SUCCEEDED(KsPin->QueryInterface(IID_IPin, (void**)&pPin)))
127 {
128 if (SUCCEEDED(pPin->QueryPinInfo(&PinInfo)))
129 {
130 if (PinInfo.pFilter)
131 PinInfo.pFilter->Release();
132
133 wcscpy(m_PinName, PinInfo.achName);
134 }
135 pPin->Release();
136 }
137 #endif
138
139 // done
140 return hr;
141 }
142
143 HRESULT
144 STDMETHODCALLTYPE
145 CKsInterfaceHandler::KsProcessMediaSamples(
146 IKsDataTypeHandler *KsDataTypeHandler,
147 IMediaSample** SampleList,
148 PLONG SampleCount,
149 KSIOOPERATION IoOperation,
150 PKSSTREAM_SEGMENT *OutStreamSegment)
151 {
152 PKSSTREAM_SEGMENT_EXT StreamSegment;
153 ULONG ExtendedSize, Index, BytesReturned;
154 HRESULT hr = S_OK;
155
156 // sanity check
157 assert(*SampleCount);
158
159 if (*SampleCount == 0 || *SampleCount < 0)
160 return E_FAIL;
161
162 // zero stream segment
163 *OutStreamSegment = NULL;
164
165 // allocate stream segment
166 StreamSegment = (PKSSTREAM_SEGMENT_EXT)CoTaskMemAlloc(sizeof(KSSTREAM_SEGMENT_EXT));
167 if (!StreamSegment)
168 return E_OUTOFMEMORY;
169
170 // zero stream segment
171 ZeroMemory(StreamSegment, sizeof(KSSTREAM_SEGMENT_EXT));
172
173 //allocate event
174 StreamSegment->StreamSegment.CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
175
176 if (!StreamSegment->StreamSegment.CompletionEvent)
177 {
178 // failed to create event
179 CoTaskMemFree(StreamSegment);
180 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
181 }
182
183 // increase our own reference count
184 AddRef();
185
186 // setup stream segment
187 StreamSegment->StreamSegment.KsDataTypeHandler = KsDataTypeHandler;
188 StreamSegment->StreamSegment.KsInterfaceHandler = (IKsInterfaceHandler*)this;
189 StreamSegment->StreamSegment.IoOperation = IoOperation;
190 StreamSegment->Overlapped.hEvent = StreamSegment->StreamSegment.CompletionEvent;
191
192
193 // ge extension size
194 ExtendedSize = 0;
195 if (KsDataTypeHandler)
196 {
197 // query extension size
198 KsDataTypeHandler->KsQueryExtendedSize(&ExtendedSize);
199
200 if (ExtendedSize)
201 {
202 // increment reference count
203 KsDataTypeHandler->AddRef();
204 }
205 else
206 {
207 // no need for the datatype handler
208 StreamSegment->StreamSegment.KsDataTypeHandler = NULL;
209 }
210 }
211
212 StreamSegment->ExtendedSize = ExtendedSize;
213 StreamSegment->SampleCount = (ULONG)*SampleCount;
214
215 // calculate stream header size count
216 ULONG StreamHeaderSize = StreamSegment->SampleCount * (sizeof(KSSTREAM_HEADER) + ExtendedSize);
217
218 // allocate stream header
219 StreamSegment->StreamHeader = (PKSSTREAM_HEADER)CoTaskMemAlloc(StreamHeaderSize);
220 if (!StreamSegment->StreamHeader)
221 {
222 // not enough memory
223 CloseHandle(StreamSegment->StreamSegment.CompletionEvent);
224
225 if (StreamSegment->StreamSegment.KsDataTypeHandler)
226 StreamSegment->StreamSegment.KsDataTypeHandler->Release();
227
228 // free stream segment
229 CoTaskMemFree(StreamSegment);
230
231 //release our reference count
232 Release();
233 return E_OUTOFMEMORY;
234 }
235
236 // zero stream headers
237 ZeroMemory(StreamSegment->StreamHeader, StreamHeaderSize);
238
239 PKSSTREAM_HEADER CurStreamHeader = StreamSegment->StreamHeader;
240
241 // initialize all stream headers
242 for(Index = 0; Index < StreamSegment->SampleCount; Index++)
243 {
244 if (ExtendedSize)
245 {
246 // initialize extended size
247 hr = KsDataTypeHandler->KsPrepareIoOperation(SampleList[Index], (CurStreamHeader + 1), IoOperation);
248 // sanity check
249 assert(hr == NOERROR);
250 }
251
252 // query for IMediaSample2 interface
253 IMediaSample2 * MediaSample;
254 AM_SAMPLE2_PROPERTIES Properties;
255 ZeroMemory(&Properties, sizeof(AM_SAMPLE2_PROPERTIES));
256
257 hr = SampleList[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
258 if (SUCCEEDED(hr))
259 {
260 //get properties
261
262 hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
263
264 //release IMediaSample2 interface
265 MediaSample->Release();
266 }
267 else
268 {
269 // get properties
270 hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer);
271 assert(hr == NOERROR);
272 hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop);
273
274 Properties.cbBuffer = SampleList[Index]->GetSize();
275 assert(Properties.cbBuffer);
276
277 Properties.dwSampleFlags = 0;
278
279 if (SampleList[Index]->IsDiscontinuity() == S_OK)
280 Properties.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
281
282 if (SampleList[Index]->IsPreroll() == S_OK)
283 Properties.dwSampleFlags |= AM_SAMPLE_PREROLL;
284
285 if (SampleList[Index]->IsSyncPoint() == S_OK)
286 Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
287 }
288
289 WCHAR Buffer[200];
290 swprintf(Buffer, L"CKsInterfaceHandler::KsProcessMediaSamples PinName %s BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u dwSampleFlags %lx\n", m_PinName, Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual, Properties.dwSampleFlags);
291 //OutputDebugStringW(Buffer);
292
293 CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize;
294 CurStreamHeader->PresentationTime.Denominator = 1;
295 CurStreamHeader->PresentationTime.Numerator = 1;
296 CurStreamHeader->FrameExtent = Properties.cbBuffer;
297 CurStreamHeader->Data = Properties.pbBuffer;
298
299 if (IoOperation == KsIoOperation_Write)
300 {
301 // set flags
302 CurStreamHeader->OptionsFlags = Properties.dwSampleFlags;
303 CurStreamHeader->DataUsed = Properties.lActual;
304 // increment reference count
305 SampleList[Index]->AddRef();
306 }
307
308 // store sample in stream segment
309 StreamSegment->MediaSample[Index] = SampleList[Index];
310
311 // move to next header
312 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
313 }
314
315 // submit to device
316 m_Pin->KsIncrementPendingIoCount();
317
318 if (DeviceIoControl(m_Handle,
319 IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM,
320 NULL, 0,
321 StreamSegment->StreamHeader,
322 StreamHeaderSize,
323 &BytesReturned,
324 &StreamSegment->Overlapped))
325 {
326 // signal completion
327 SetEvent(StreamSegment->StreamSegment.CompletionEvent);
328 hr = S_OK;
329 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
330 }
331 else
332 {
333 if (GetLastError() == ERROR_IO_PENDING)
334 {
335 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
336 hr = S_OK;
337 }
338 }
339 return hr;
340 }
341
342 HRESULT
343 STDMETHODCALLTYPE
344 CKsInterfaceHandler::KsCompleteIo(
345 PKSSTREAM_SEGMENT InStreamSegment)
346 {
347 PKSSTREAM_SEGMENT_EXT StreamSegment;
348 PKSSTREAM_HEADER CurStreamHeader;
349 DWORD dwError = ERROR_SUCCESS, BytesReturned;
350 BOOL bOverlapped;
351 ULONG Index;
352 HRESULT hr;
353 IMediaSample2 * MediaSample;
354 AM_SAMPLE2_PROPERTIES Properties;
355 REFERENCE_TIME Start, Stop;
356
357 // get private stream segment
358 StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment;
359
360 // get result
361 bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE);
362 dwError = GetLastError();
363
364 CurStreamHeader = StreamSegment->StreamHeader;
365
366 //iterate through all stream headers
367 for(Index = 0; Index < StreamSegment->SampleCount; Index++)
368 {
369 if (!bOverlapped)
370 {
371 // operation failed
372 m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError));
373 }
374
375 // query IMediaSample2 interface
376 hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
377 if (SUCCEEDED(hr))
378 {
379 // media sample properties
380 hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
381 if (SUCCEEDED(hr))
382 {
383 //update media sample properties
384 Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags;
385 Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY);
386
387 MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
388 }
389 // release IMediaSample2 interface
390 MediaSample->Release();
391 }
392
393 // was an extended header used
394 if (StreamSegment->ExtendedSize)
395 {
396 // unprepare stream header extension
397 StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE);
398 }
399
400 Start = 0;
401 Stop = 0;
402 if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
403 {
404 // update common media sample details
405 StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT));
406 StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL));
407 StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY));
408
409 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID)
410 {
411 // use valid timestamp
412 Start = CurStreamHeader->PresentationTime.Time;
413
414 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID)
415 {
416 Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration;
417 }
418 }
419 }
420
421 // now set time
422 hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop);
423 if (FAILED(hr))
424 {
425 // use start time
426 StreamSegment->MediaSample[Index]->SetTime(&Start, &Start);
427 }
428
429 // set valid data length
430 StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed);
431
432 if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
433 {
434 if (bOverlapped)
435 {
436 // deliver sample
437 m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags);
438 }
439 }
440 else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write)
441 {
442 // release media sample reference
443 StreamSegment->MediaSample[Index]->Release();
444 }
445
446 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
447 }
448
449 // delete stream headers
450 CoTaskMemFree(StreamSegment->StreamHeader);
451
452 if (StreamSegment->StreamSegment.KsDataTypeHandler)
453 {
454 // release reference
455 StreamSegment->StreamSegment.KsDataTypeHandler->Release();
456 }
457
458 // decrement pending i/o count
459 m_Pin->KsDecrementPendingIoCount();
460
461 //notify of completion
462 m_Pin->KsMediaSamplesCompleted(InStreamSegment);
463
464 //destroy stream segment
465 CoTaskMemFree(StreamSegment);
466
467 //release reference to ourselves
468 Release();
469
470 // done
471 // Event handle is closed by caller
472 return S_OK;
473 }
474
475 HRESULT
476 WINAPI
477 CKsInterfaceHandler_Constructor(
478 IUnknown * pUnkOuter,
479 REFIID riid,
480 LPVOID * ppv)
481 {
482 OutputDebugStringW(L"CKsInterfaceHandler_Constructor\n");
483
484 CKsInterfaceHandler * handler = new CKsInterfaceHandler();
485
486 if (!handler)
487 return E_OUTOFMEMORY;
488
489 if (FAILED(handler->QueryInterface(riid, ppv)))
490 {
491 /* not supported */
492 delete handler;
493 return E_NOINTERFACE;
494 }
495
496 return NOERROR;
497 }