[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
138 IKsAllocatorEx * Allocator;
139
140 if (SUCCEEDED(KsPin->QueryInterface(IID_IKsAllocatorEx, (void**)&Allocator)))
141 {
142 PALLOCATOR_PROPERTIES_EX Properties = Allocator->KsGetProperties();
143
144 if (Properties)
145 {
146 WCHAR Buffer[100];
147 swprintf(Buffer, L"CKsInterfaceHandler::KsSetPin PinName %s Properties.cbAlign %u cbBuffer %u cbPrefix %u cBuffers %u\n", m_PinName, Properties->cbAlign, Properties->cbBuffer, Properties->cbPrefix, Properties->cBuffers);
148 OutputDebugStringW(Buffer);
149 }
150 Allocator->Release();
151 }
152
153 #endif
154
155 // done
156 return hr;
157 }
158
159 HRESULT
160 STDMETHODCALLTYPE
161 CKsInterfaceHandler::KsProcessMediaSamples(
162 IKsDataTypeHandler *KsDataTypeHandler,
163 IMediaSample** SampleList,
164 PLONG SampleCount,
165 KSIOOPERATION IoOperation,
166 PKSSTREAM_SEGMENT *OutStreamSegment)
167 {
168 PKSSTREAM_SEGMENT_EXT StreamSegment;
169 ULONG ExtendedSize, Index, BytesReturned;
170 HRESULT hr = S_OK;
171
172 // sanity check
173 assert(*SampleCount);
174
175 if (*SampleCount == 0 || *SampleCount < 0)
176 return E_FAIL;
177
178 // zero stream segment
179 *OutStreamSegment = NULL;
180
181 // allocate stream segment
182 StreamSegment = (PKSSTREAM_SEGMENT_EXT)CoTaskMemAlloc(sizeof(KSSTREAM_SEGMENT_EXT));
183 if (!StreamSegment)
184 return E_OUTOFMEMORY;
185
186 // zero stream segment
187 ZeroMemory(StreamSegment, sizeof(KSSTREAM_SEGMENT_EXT));
188
189 //allocate event
190 StreamSegment->StreamSegment.CompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191
192 if (!StreamSegment->StreamSegment.CompletionEvent)
193 {
194 // failed to create event
195 CoTaskMemFree(StreamSegment);
196 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
197 }
198
199 // increase our own reference count
200 AddRef();
201
202 // setup stream segment
203 StreamSegment->StreamSegment.KsDataTypeHandler = KsDataTypeHandler;
204 StreamSegment->StreamSegment.KsInterfaceHandler = (IKsInterfaceHandler*)this;
205 StreamSegment->StreamSegment.IoOperation = IoOperation;
206 StreamSegment->Overlapped.hEvent = StreamSegment->StreamSegment.CompletionEvent;
207
208
209 // ge extension size
210 ExtendedSize = 0;
211 if (KsDataTypeHandler)
212 {
213 // query extension size
214 KsDataTypeHandler->KsQueryExtendedSize(&ExtendedSize);
215
216 if (ExtendedSize)
217 {
218 // increment reference count
219 KsDataTypeHandler->AddRef();
220 }
221 else
222 {
223 // no need for the datatype handler
224 StreamSegment->StreamSegment.KsDataTypeHandler = NULL;
225 }
226 }
227
228 StreamSegment->ExtendedSize = ExtendedSize;
229 StreamSegment->SampleCount = (ULONG)*SampleCount;
230
231 // calculate stream header size count
232 ULONG StreamHeaderSize = StreamSegment->SampleCount * (sizeof(KSSTREAM_HEADER) + ExtendedSize);
233
234 // allocate stream header
235 StreamSegment->StreamHeader = (PKSSTREAM_HEADER)CoTaskMemAlloc(StreamHeaderSize);
236 if (!StreamSegment->StreamHeader)
237 {
238 // not enough memory
239 CloseHandle(StreamSegment->StreamSegment.CompletionEvent);
240
241 if (StreamSegment->StreamSegment.KsDataTypeHandler)
242 StreamSegment->StreamSegment.KsDataTypeHandler->Release();
243
244 // free stream segment
245 CoTaskMemFree(StreamSegment);
246
247 //release our reference count
248 Release();
249 return E_OUTOFMEMORY;
250 }
251
252 // zero stream headers
253 ZeroMemory(StreamSegment->StreamHeader, StreamHeaderSize);
254
255 PKSSTREAM_HEADER CurStreamHeader = StreamSegment->StreamHeader;
256
257 // initialize all stream headers
258 for(Index = 0; Index < StreamSegment->SampleCount; Index++)
259 {
260 if (ExtendedSize)
261 {
262 // initialize extended size
263 hr = KsDataTypeHandler->KsPrepareIoOperation(SampleList[Index], (CurStreamHeader + 1), IoOperation);
264 // sanity check
265 assert(hr == NOERROR);
266 }
267
268 // query for IMediaSample2 interface
269 IMediaSample2 * MediaSample;
270 AM_SAMPLE2_PROPERTIES Properties;
271
272 hr = SampleList[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
273 if (SUCCEEDED(hr))
274 {
275 //get properties
276
277 hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
278
279 //release IMediaSample2 interface
280 MediaSample->Release();
281 }
282 else
283 {
284 // get properties
285 hr = SampleList[Index]->GetPointer((BYTE**)&Properties.pbBuffer);
286 assert(hr == NOERROR);
287 hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop);
288 assert(hr == NOERROR);
289
290 Properties.cbBuffer = SampleList[Index]->GetSize();
291 assert(Properties.cbBuffer);
292
293 Properties.dwSampleFlags = 0;
294
295 if (SampleList[Index]->IsDiscontinuity() == S_OK)
296 Properties.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
297
298 if (SampleList[Index]->IsPreroll() == S_OK)
299 Properties.dwSampleFlags |= AM_SAMPLE_PREROLL;
300
301 if (SampleList[Index]->IsSyncPoint() == S_OK)
302 Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
303 }
304
305 WCHAR Buffer[200];
306 swprintf(Buffer, L"CKsInterfaceHandler::KsProcessMediaSamples PinName %s BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", m_PinName, Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual);
307 //OutputDebugStringW(Buffer);
308
309 CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize;
310 CurStreamHeader->PresentationTime.Denominator = 1;
311 CurStreamHeader->PresentationTime.Numerator = 1;
312 CurStreamHeader->FrameExtent = Properties.cbBuffer;
313 CurStreamHeader->Data = Properties.pbBuffer;
314
315 if (IoOperation == KsIoOperation_Write)
316 {
317 // set flags
318 CurStreamHeader->OptionsFlags = Properties.dwSampleFlags;
319 CurStreamHeader->DataUsed = Properties.lActual;
320 // increment reference count
321 SampleList[Index]->AddRef();
322 }
323
324 // store sample in stream segment
325 StreamSegment->MediaSample[Index] = SampleList[Index];
326
327 // move to next header
328 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
329 }
330
331 // submit to device
332 m_Pin->KsIncrementPendingIoCount();
333
334 if (DeviceIoControl(m_Handle,
335 IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM,
336 NULL, 0,
337 StreamSegment->StreamHeader,
338 StreamHeaderSize,
339 &BytesReturned,
340 &StreamSegment->Overlapped))
341 {
342 // signal completion
343 SetEvent(StreamSegment->StreamSegment.CompletionEvent);
344 hr = S_OK;
345 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
346 }
347 else
348 {
349 if (GetLastError() == ERROR_IO_PENDING)
350 {
351 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment;
352 hr = S_OK;
353 }
354 }
355 return hr;
356 }
357
358 HRESULT
359 STDMETHODCALLTYPE
360 CKsInterfaceHandler::KsCompleteIo(
361 PKSSTREAM_SEGMENT InStreamSegment)
362 {
363 PKSSTREAM_SEGMENT_EXT StreamSegment;
364 PKSSTREAM_HEADER CurStreamHeader;
365 DWORD dwError = ERROR_SUCCESS, BytesReturned;
366 BOOL bOverlapped;
367 ULONG Index;
368 HRESULT hr;
369 IMediaSample2 * MediaSample;
370 AM_SAMPLE2_PROPERTIES Properties;
371 REFERENCE_TIME Start, Stop;
372
373 // get private stream segment
374 StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment;
375
376 // get result
377 bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE);
378 dwError = GetLastError();
379
380 CurStreamHeader = StreamSegment->StreamHeader;
381
382 WCHAR Buffer[100];
383 swprintf(Buffer, L"CKsInterfaceHandler::KsCompleteIo PinName %s bOverlapped %u hr %lx\n", m_PinName, bOverlapped, dwError);
384 //OutputDebugStringW(Buffer);
385
386 //iterate through all stream headers
387 for(Index = 0; Index < StreamSegment->SampleCount; Index++)
388 {
389 if (!bOverlapped)
390 {
391 // operation failed
392 m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError));
393 }
394
395 // query IMediaSample2 interface
396 hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample);
397 if (SUCCEEDED(hr))
398 {
399 // media sample properties
400 hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
401 if (SUCCEEDED(hr))
402 {
403 //update media sample properties
404 Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags;
405 Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY);
406
407 MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties);
408 }
409 // release IMediaSample2 interface
410 MediaSample->Release();
411 }
412
413 // was an extended header used
414 if (StreamSegment->ExtendedSize)
415 {
416 // unprepare stream header extension
417 StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE);
418 }
419
420 Start = 0;
421 Stop = 0;
422 if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
423 {
424 // update common media sample details
425 StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT));
426 StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL));
427 StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY));
428
429 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID)
430 {
431 // use valid timestamp
432 Start = CurStreamHeader->PresentationTime.Time;
433
434 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID)
435 {
436 Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration;
437 }
438 }
439 }
440
441 // now set time
442 hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop);
443 if (FAILED(hr))
444 {
445 // use start time
446 StreamSegment->MediaSample[Index]->SetTime(&Start, &Start);
447 }
448
449 // set valid data length
450 StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed);
451
452 if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read)
453 {
454 if (bOverlapped)
455 {
456 // deliver sample
457 m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags);
458 }
459 }
460 else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write)
461 {
462 // release media sample reference
463 StreamSegment->MediaSample[Index]->Release();
464 }
465
466 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size);
467 }
468
469 // delete stream headers
470 CoTaskMemFree(StreamSegment->StreamHeader);
471
472 if (StreamSegment->StreamSegment.KsDataTypeHandler)
473 {
474 // release reference
475 StreamSegment->StreamSegment.KsDataTypeHandler->Release();
476 }
477
478 // decrement pending i/o count
479 m_Pin->KsDecrementPendingIoCount();
480
481 //notify of completion
482 m_Pin->KsMediaSamplesCompleted(InStreamSegment);
483
484 //destroy stream segment
485 CoTaskMemFree(StreamSegment);
486
487 //release reference to ourselves
488 Release();
489
490 // done
491 // Event handle is closed by caller
492 return S_OK;
493 }
494
495 HRESULT
496 WINAPI
497 CKsInterfaceHandler_Constructor(
498 IUnknown * pUnkOuter,
499 REFIID riid,
500 LPVOID * ppv)
501 {
502 OutputDebugStringW(L"CKsInterfaceHandler_Constructor\n");
503
504 CKsInterfaceHandler * handler = new CKsInterfaceHandler();
505
506 if (!handler)
507 return E_OUTOFMEMORY;
508
509 if (FAILED(handler->QueryInterface(riid, ppv)))
510 {
511 /* not supported */
512 delete handler;
513 return E_NOINTERFACE;
514 }
515
516 return NOERROR;
517 }