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 (johannes.anderwald@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 #ifdef KSPROXY_TRACE 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 #endif 293 294 CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize; 295 CurStreamHeader->PresentationTime.Denominator = 1; 296 CurStreamHeader->PresentationTime.Numerator = 1; 297 CurStreamHeader->FrameExtent = Properties.cbBuffer; 298 CurStreamHeader->Data = Properties.pbBuffer; 299 300 if (IoOperation == KsIoOperation_Write) 301 { 302 // set flags 303 CurStreamHeader->OptionsFlags = Properties.dwSampleFlags; 304 CurStreamHeader->DataUsed = Properties.lActual; 305 // increment reference count 306 SampleList[Index]->AddRef(); 307 } 308 309 // store sample in stream segment 310 StreamSegment->MediaSample[Index] = SampleList[Index]; 311 312 // move to next header 313 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); 314 } 315 316 // submit to device 317 m_Pin->KsIncrementPendingIoCount(); 318 319 if (DeviceIoControl(m_Handle, 320 IoOperation == KsIoOperation_Write ? IOCTL_KS_WRITE_STREAM : IOCTL_KS_READ_STREAM, 321 NULL, 0, 322 StreamSegment->StreamHeader, 323 StreamHeaderSize, 324 &BytesReturned, 325 &StreamSegment->Overlapped)) 326 { 327 // signal completion 328 SetEvent(StreamSegment->StreamSegment.CompletionEvent); 329 hr = S_OK; 330 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; 331 } 332 else 333 { 334 if (GetLastError() == ERROR_IO_PENDING) 335 { 336 *OutStreamSegment = (PKSSTREAM_SEGMENT)StreamSegment; 337 hr = S_OK; 338 } 339 } 340 return hr; 341 } 342 343 HRESULT 344 STDMETHODCALLTYPE 345 CKsInterfaceHandler::KsCompleteIo( 346 PKSSTREAM_SEGMENT InStreamSegment) 347 { 348 PKSSTREAM_SEGMENT_EXT StreamSegment; 349 PKSSTREAM_HEADER CurStreamHeader; 350 DWORD dwError = ERROR_SUCCESS, BytesReturned; 351 BOOL bOverlapped; 352 ULONG Index; 353 HRESULT hr; 354 IMediaSample2 * MediaSample; 355 AM_SAMPLE2_PROPERTIES Properties; 356 REFERENCE_TIME Start, Stop; 357 358 // get private stream segment 359 StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment; 360 361 // get result 362 bOverlapped = GetOverlappedResult(m_Handle, &StreamSegment->Overlapped, &BytesReturned, FALSE); 363 dwError = GetLastError(); 364 365 CurStreamHeader = StreamSegment->StreamHeader; 366 367 //iterate through all stream headers 368 for(Index = 0; Index < StreamSegment->SampleCount; Index++) 369 { 370 if (!bOverlapped) 371 { 372 // operation failed 373 m_Pin->KsNotifyError(StreamSegment->MediaSample[Index], MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError)); 374 } 375 376 // query IMediaSample2 interface 377 hr = StreamSegment->MediaSample[Index]->QueryInterface(IID_IMediaSample2, (void**)&MediaSample); 378 if (SUCCEEDED(hr)) 379 { 380 // media sample properties 381 hr = MediaSample->GetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); 382 if (SUCCEEDED(hr)) 383 { 384 //update media sample properties 385 Properties.dwTypeSpecificFlags = CurStreamHeader->TypeSpecificFlags; 386 Properties.dwSampleFlags |= (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY); 387 388 MediaSample->SetProperties(sizeof(AM_SAMPLE2_PROPERTIES), (BYTE*)&Properties); 389 } 390 // release IMediaSample2 interface 391 MediaSample->Release(); 392 } 393 394 // was an extended header used 395 if (StreamSegment->ExtendedSize) 396 { 397 // unprepare stream header extension 398 StreamSegment->StreamSegment.KsDataTypeHandler->KsCompleteIoOperation(StreamSegment->MediaSample[Index], (CurStreamHeader + 1), StreamSegment->StreamSegment.IoOperation, bOverlapped == FALSE); 399 } 400 401 Start = 0; 402 Stop = 0; 403 if (bOverlapped && StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) 404 { 405 // update common media sample details 406 StreamSegment->MediaSample[Index]->SetSyncPoint((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT)); 407 StreamSegment->MediaSample[Index]->SetPreroll((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_PREROLL)); 408 StreamSegment->MediaSample[Index]->SetDiscontinuity((CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY)); 409 410 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) 411 { 412 // use valid timestamp 413 Start = CurStreamHeader->PresentationTime.Time; 414 415 if (CurStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DURATIONVALID) 416 { 417 Stop = CurStreamHeader->PresentationTime.Time + CurStreamHeader->Duration; 418 } 419 } 420 } 421 422 // now set time 423 hr = StreamSegment->MediaSample[Index]->SetTime(&Start, &Stop); 424 if (FAILED(hr)) 425 { 426 // use start time 427 StreamSegment->MediaSample[Index]->SetTime(&Start, &Start); 428 } 429 430 // set valid data length 431 StreamSegment->MediaSample[Index]->SetActualDataLength(CurStreamHeader->DataUsed); 432 433 if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Read) 434 { 435 if (bOverlapped) 436 { 437 // deliver sample 438 m_Pin->KsDeliver(StreamSegment->MediaSample[Index], CurStreamHeader->OptionsFlags); 439 } 440 } 441 else if (StreamSegment->StreamSegment.IoOperation == KsIoOperation_Write) 442 { 443 // release media sample reference 444 StreamSegment->MediaSample[Index]->Release(); 445 } 446 447 CurStreamHeader = (PKSSTREAM_HEADER)((ULONG_PTR)CurStreamHeader + CurStreamHeader->Size); 448 } 449 450 // delete stream headers 451 CoTaskMemFree(StreamSegment->StreamHeader); 452 453 if (StreamSegment->StreamSegment.KsDataTypeHandler) 454 { 455 // release reference 456 StreamSegment->StreamSegment.KsDataTypeHandler->Release(); 457 } 458 459 // decrement pending i/o count 460 m_Pin->KsDecrementPendingIoCount(); 461 462 //notify of completion 463 m_Pin->KsMediaSamplesCompleted(InStreamSegment); 464 465 //destroy stream segment 466 CoTaskMemFree(StreamSegment); 467 468 //release reference to ourselves 469 Release(); 470 471 // done 472 // Event handle is closed by caller 473 return S_OK; 474 } 475 476 HRESULT 477 WINAPI 478 CKsInterfaceHandler_Constructor( 479 IUnknown * pUnkOuter, 480 REFIID riid, 481 LPVOID * ppv) 482 { 483 #ifdef KSPROXY_TRACE 484 OutputDebugStringW(L"CKsInterfaceHandler_Constructor\n"); 485 #endif 486 487 CKsInterfaceHandler * handler = new CKsInterfaceHandler(); 488 489 if (!handler) 490 return E_OUTOFMEMORY; 491 492 if (FAILED(handler->QueryInterface(riid, ppv))) 493 { 494 /* not supported */ 495 delete handler; 496 return E_NOINTERFACE; 497 } 498 499 return NOERROR; 500 } 501