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