1 /* 2 * Video Renderer (Fullscreen and Windowed using Direct Draw) 3 * 4 * Copyright 2004 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "quartz_private.h" 22 23 typedef struct VideoRendererImpl 24 { 25 BaseRenderer renderer; 26 BaseControlWindow baseControlWindow; 27 BaseControlVideo baseControlVideo; 28 29 IUnknown IUnknown_inner; 30 IAMFilterMiscFlags IAMFilterMiscFlags_iface; 31 IUnknown *outer_unk; 32 33 BOOL init; 34 HANDLE hThread; 35 36 DWORD ThreadID; 37 HANDLE hEvent; 38 /* hEvent == evComplete? */ 39 BOOL ThreadResult; 40 RECT SourceRect; 41 RECT DestRect; 42 RECT WindowPos; 43 LONG VideoWidth; 44 LONG VideoHeight; 45 LONG FullScreenMode; 46 } VideoRendererImpl; 47 48 static inline VideoRendererImpl *impl_from_BaseWindow(BaseWindow *iface) 49 { 50 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.baseWindow); 51 } 52 53 static inline VideoRendererImpl *impl_from_BaseRenderer(BaseRenderer *iface) 54 { 55 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer); 56 } 57 58 static inline VideoRendererImpl *impl_from_IBaseFilter(IBaseFilter *iface) 59 { 60 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer.filter.IBaseFilter_iface); 61 } 62 63 static inline VideoRendererImpl *impl_from_IVideoWindow(IVideoWindow *iface) 64 { 65 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.IVideoWindow_iface); 66 } 67 68 static inline VideoRendererImpl *impl_from_BaseControlVideo(BaseControlVideo *iface) 69 { 70 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo); 71 } 72 73 static inline VideoRendererImpl *impl_from_IBasicVideo(IBasicVideo *iface) 74 { 75 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo.IBasicVideo_iface); 76 } 77 78 static DWORD WINAPI MessageLoop(LPVOID lpParameter) 79 { 80 VideoRendererImpl* This = lpParameter; 81 MSG msg; 82 BOOL fGotMessage; 83 84 TRACE("Starting message loop\n"); 85 86 if (FAILED(BaseWindowImpl_PrepareWindow(&This->baseControlWindow.baseWindow))) 87 { 88 This->ThreadResult = FALSE; 89 SetEvent(This->hEvent); 90 return 0; 91 } 92 93 This->ThreadResult = TRUE; 94 SetEvent(This->hEvent); 95 96 while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1) 97 { 98 TranslateMessage(&msg); 99 DispatchMessageW(&msg); 100 } 101 102 TRACE("End of message loop\n"); 103 104 return msg.wParam; 105 } 106 107 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This) 108 { 109 This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 110 if (!This->hEvent) 111 return FALSE; 112 113 This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID); 114 if (!This->hThread) 115 { 116 CloseHandle(This->hEvent); 117 return FALSE; 118 } 119 120 WaitForSingleObject(This->hEvent, INFINITE); 121 122 if (!This->ThreadResult) 123 { 124 CloseHandle(This->hEvent); 125 CloseHandle(This->hThread); 126 return FALSE; 127 } 128 129 return TRUE; 130 } 131 132 static void VideoRenderer_AutoShowWindow(VideoRendererImpl *This) 133 { 134 if (!This->init && (!This->WindowPos.right || !This->WindowPos.top)) 135 { 136 DWORD style = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE); 137 DWORD style_ex = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_EXSTYLE); 138 139 if (!This->WindowPos.right) 140 { 141 if (This->DestRect.right) 142 { 143 This->WindowPos.left = This->DestRect.left; 144 This->WindowPos.right = This->DestRect.right; 145 } 146 else 147 { 148 This->WindowPos.left = This->SourceRect.left; 149 This->WindowPos.right = This->SourceRect.right; 150 } 151 } 152 if (!This->WindowPos.bottom) 153 { 154 if (This->DestRect.bottom) 155 { 156 This->WindowPos.top = This->DestRect.top; 157 This->WindowPos.bottom = This->DestRect.bottom; 158 } 159 else 160 { 161 This->WindowPos.top = This->SourceRect.top; 162 This->WindowPos.bottom = This->SourceRect.bottom; 163 } 164 } 165 166 AdjustWindowRectEx(&This->WindowPos, style, FALSE, style_ex); 167 168 TRACE("WindowPos: %s\n", wine_dbgstr_rect(&This->WindowPos)); 169 SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, 170 This->WindowPos.left, 171 This->WindowPos.top, 172 This->WindowPos.right - This->WindowPos.left, 173 This->WindowPos.bottom - This->WindowPos.top, 174 SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE); 175 176 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect); 177 } 178 else if (!This->init) 179 This->DestRect = This->WindowPos; 180 This->init = TRUE; 181 if (This->baseControlWindow.AutoShow) 182 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW); 183 } 184 185 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size) 186 { 187 AM_MEDIA_TYPE amt; 188 HRESULT hr = S_OK; 189 BITMAPINFOHEADER *bmiHeader; 190 191 TRACE("(%p)->(%p, %d)\n", This, data, size); 192 193 hr = IPin_ConnectionMediaType(&This->renderer.pInputPin->pin.IPin_iface, &amt); 194 if (FAILED(hr)) { 195 ERR("Unable to retrieve media type\n"); 196 return hr; 197 } 198 199 if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo)) 200 { 201 bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader; 202 } 203 else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2)) 204 { 205 bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader; 206 } 207 else 208 { 209 FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype)); 210 return VFW_E_RUNTIME_ERROR; 211 } 212 213 TRACE("biSize = %d\n", bmiHeader->biSize); 214 TRACE("biWidth = %d\n", bmiHeader->biWidth); 215 TRACE("biHeight = %d\n", bmiHeader->biHeight); 216 TRACE("biPlanes = %d\n", bmiHeader->biPlanes); 217 TRACE("biBitCount = %d\n", bmiHeader->biBitCount); 218 TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4)); 219 TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage); 220 221 if (!This->baseControlWindow.baseWindow.hDC) { 222 ERR("Cannot get DC from window!\n"); 223 return E_FAIL; 224 } 225 226 TRACE("Src Rect: %s\n", wine_dbgstr_rect(&This->SourceRect)); 227 TRACE("Dst Rect: %s\n", wine_dbgstr_rect(&This->DestRect)); 228 229 StretchDIBits(This->baseControlWindow.baseWindow.hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left, 230 This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top, 231 This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top, 232 data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY); 233 234 return S_OK; 235 } 236 237 static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime) 238 { 239 /* Preroll means the sample isn't shown, this is used for key frames and things like that */ 240 if (IMediaSample_IsPreroll(pSample) == S_OK) 241 return E_FAIL; 242 return S_FALSE; 243 } 244 245 static HRESULT WINAPI VideoRenderer_DoRenderSample(BaseRenderer* iface, IMediaSample * pSample) 246 { 247 VideoRendererImpl *This = impl_from_BaseRenderer(iface); 248 LPBYTE pbSrcStream = NULL; 249 LONG cbSrcStream = 0; 250 HRESULT hr; 251 252 TRACE("(%p)->(%p)\n", This, pSample); 253 254 hr = IMediaSample_GetPointer(pSample, &pbSrcStream); 255 if (FAILED(hr)) 256 { 257 ERR("Cannot get pointer to sample data (%x)\n", hr); 258 return hr; 259 } 260 261 cbSrcStream = IMediaSample_GetActualDataLength(pSample); 262 263 TRACE("val %p %d\n", pbSrcStream, cbSrcStream); 264 265 #if 0 /* For debugging purpose */ 266 { 267 int i; 268 for(i = 0; i < cbSrcStream; i++) 269 { 270 if ((i!=0) && !(i%16)) 271 TRACE("\n"); 272 TRACE("%02x ", pbSrcStream[i]); 273 } 274 TRACE("\n"); 275 } 276 #endif 277 278 SetEvent(This->hEvent); 279 if (This->renderer.filter.state == State_Paused) 280 { 281 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); 282 SetEvent(This->hEvent); 283 if (This->renderer.filter.state == State_Paused) 284 { 285 /* Flushing */ 286 return S_OK; 287 } 288 if (This->renderer.filter.state == State_Stopped) 289 { 290 return VFW_E_WRONG_STATE; 291 } 292 } else { 293 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); 294 } 295 return S_OK; 296 } 297 298 static HRESULT WINAPI VideoRenderer_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt) 299 { 300 VideoRendererImpl *This = impl_from_BaseRenderer(iface); 301 302 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) 303 return S_FALSE; 304 305 if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) || 306 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) || 307 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) || 308 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8)) 309 { 310 LONG height; 311 312 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) 313 { 314 VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat; 315 This->SourceRect.left = 0; 316 This->SourceRect.top = 0; 317 This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth; 318 height = format->bmiHeader.biHeight; 319 if (height < 0) 320 This->SourceRect.bottom = This->VideoHeight = -height; 321 else 322 This->SourceRect.bottom = This->VideoHeight = height; 323 } 324 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) 325 { 326 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat; 327 328 This->SourceRect.left = 0; 329 This->SourceRect.top = 0; 330 This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth; 331 height = format2->bmiHeader.biHeight; 332 if (height < 0) 333 This->SourceRect.bottom = This->VideoHeight = -height; 334 else 335 This->SourceRect.bottom = This->VideoHeight = height; 336 } 337 else 338 { 339 WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype)); 340 return S_FALSE; 341 } 342 return S_OK; 343 } 344 return S_FALSE; 345 } 346 347 static HRESULT WINAPI VideoRenderer_EndFlush(BaseRenderer* iface) 348 { 349 VideoRendererImpl *This = impl_from_BaseRenderer(iface); 350 351 TRACE("(%p)->()\n", iface); 352 353 if (This->renderer.pMediaSample) { 354 ResetEvent(This->hEvent); 355 LeaveCriticalSection(iface->pInputPin->pin.pCritSec); 356 LeaveCriticalSection(&iface->filter.csFilter); 357 LeaveCriticalSection(&iface->csRenderLock); 358 WaitForSingleObject(This->hEvent, INFINITE); 359 EnterCriticalSection(&iface->csRenderLock); 360 EnterCriticalSection(&iface->filter.csFilter); 361 EnterCriticalSection(iface->pInputPin->pin.pCritSec); 362 } 363 if (This->renderer.filter.state == State_Paused) { 364 ResetEvent(This->hEvent); 365 } 366 367 return BaseRendererImpl_EndFlush(iface); 368 } 369 370 static VOID WINAPI VideoRenderer_OnStopStreaming(BaseRenderer* iface) 371 { 372 VideoRendererImpl *This = impl_from_BaseRenderer(iface); 373 374 TRACE("(%p)->()\n", This); 375 376 SetEvent(This->hEvent); 377 if (This->baseControlWindow.AutoShow) 378 /* Black it out */ 379 RedrawWindow(This->baseControlWindow.baseWindow.hWnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE); 380 } 381 382 static VOID WINAPI VideoRenderer_OnStartStreaming(BaseRenderer* iface) 383 { 384 VideoRendererImpl *This = impl_from_BaseRenderer(iface); 385 386 TRACE("(%p)\n", This); 387 388 if (This->renderer.pInputPin->pin.pConnectedTo && (This->renderer.filter.state == State_Stopped || !This->renderer.pInputPin->end_of_stream)) 389 { 390 if (This->renderer.filter.state == State_Stopped) 391 { 392 ResetEvent(This->hEvent); 393 VideoRenderer_AutoShowWindow(This); 394 } 395 } 396 } 397 398 static LPWSTR WINAPI VideoRenderer_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx) 399 { 400 static const WCHAR classnameW[] = { 'W','i','n','e',' ','A','c','t','i','v','e','M','o','v','i','e',' ','C','l','a','s','s',0 }; 401 402 *pClassStyles = 0; 403 *pWindowStyles = WS_SIZEBOX; 404 *pWindowStylesEx = 0; 405 406 return (LPWSTR)classnameW; 407 } 408 409 static RECT WINAPI VideoRenderer_GetDefaultRect(BaseWindow *iface) 410 { 411 VideoRendererImpl *This = impl_from_BaseWindow(iface); 412 static RECT defRect; 413 414 SetRect(&defRect, 0, 0, This->VideoWidth, This->VideoHeight); 415 416 return defRect; 417 } 418 419 static BOOL WINAPI VideoRenderer_OnSize(BaseWindow *iface, LONG Width, LONG Height) 420 { 421 VideoRendererImpl *This = impl_from_BaseWindow(iface); 422 423 TRACE("WM_SIZE %d %d\n", Width, Height); 424 GetClientRect(iface->hWnd, &This->DestRect); 425 TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n", 426 This->DestRect.left, 427 This->DestRect.top, 428 This->DestRect.right - This->DestRect.left, 429 This->DestRect.bottom - This->DestRect.top); 430 return BaseWindowImpl_OnSize(iface, Width, Height); 431 } 432 433 static const BaseRendererFuncTable BaseFuncTable = { 434 VideoRenderer_CheckMediaType, 435 VideoRenderer_DoRenderSample, 436 /**/ 437 NULL, 438 NULL, 439 NULL, 440 VideoRenderer_OnStartStreaming, 441 VideoRenderer_OnStopStreaming, 442 NULL, 443 NULL, 444 NULL, 445 VideoRenderer_ShouldDrawSampleNow, 446 NULL, 447 /**/ 448 NULL, 449 NULL, 450 NULL, 451 NULL, 452 VideoRenderer_EndFlush, 453 }; 454 455 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = { 456 VideoRenderer_GetClassWindowStyles, 457 VideoRenderer_GetDefaultRect, 458 NULL, 459 BaseControlWindowImpl_PossiblyEatMessage, 460 VideoRenderer_OnSize 461 }; 462 463 static HRESULT WINAPI VideoRenderer_GetSourceRect(BaseControlVideo* iface, RECT *pSourceRect) 464 { 465 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 466 CopyRect(pSourceRect,&This->SourceRect); 467 return S_OK; 468 } 469 470 static HRESULT WINAPI VideoRenderer_GetStaticImage(BaseControlVideo* iface, LONG *pBufferSize, LONG *pDIBImage) 471 { 472 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 473 BITMAPINFOHEADER *bmiHeader; 474 LONG needed_size; 475 AM_MEDIA_TYPE *amt = &This->renderer.pInputPin->pin.mtCurrent; 476 char *ptr; 477 478 FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage); 479 480 EnterCriticalSection(&This->renderer.filter.csFilter); 481 482 if (!This->renderer.pMediaSample) 483 { 484 LeaveCriticalSection(&This->renderer.filter.csFilter); 485 return (This->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED); 486 } 487 488 if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo)) 489 { 490 bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader; 491 } 492 else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2)) 493 { 494 bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader; 495 } 496 else 497 { 498 FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype)); 499 LeaveCriticalSection(&This->renderer.filter.csFilter); 500 return VFW_E_RUNTIME_ERROR; 501 } 502 503 needed_size = bmiHeader->biSize; 504 needed_size += IMediaSample_GetActualDataLength(This->renderer.pMediaSample); 505 506 if (!pDIBImage) 507 { 508 *pBufferSize = needed_size; 509 LeaveCriticalSection(&This->renderer.filter.csFilter); 510 return S_OK; 511 } 512 513 if (needed_size < *pBufferSize) 514 { 515 ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize); 516 LeaveCriticalSection(&This->renderer.filter.csFilter); 517 return E_FAIL; 518 } 519 *pBufferSize = needed_size; 520 521 memcpy(pDIBImage, bmiHeader, bmiHeader->biSize); 522 IMediaSample_GetPointer(This->renderer.pMediaSample, (BYTE **)&ptr); 523 memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->renderer.pMediaSample)); 524 525 LeaveCriticalSection(&This->renderer.filter.csFilter); 526 return S_OK; 527 } 528 529 static HRESULT WINAPI VideoRenderer_GetTargetRect(BaseControlVideo* iface, RECT *pTargetRect) 530 { 531 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 532 CopyRect(pTargetRect,&This->DestRect); 533 return S_OK; 534 } 535 536 static VIDEOINFOHEADER* WINAPI VideoRenderer_GetVideoFormat(BaseControlVideo* iface) 537 { 538 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 539 AM_MEDIA_TYPE *pmt; 540 541 TRACE("(%p/%p)\n", This, iface); 542 543 pmt = &This->renderer.pInputPin->pin.mtCurrent; 544 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) { 545 return (VIDEOINFOHEADER*)pmt->pbFormat; 546 } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) { 547 static VIDEOINFOHEADER vih; 548 VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat; 549 memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER)); 550 memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER)); 551 return &vih; 552 } else { 553 ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype)); 554 return NULL; 555 } 556 } 557 558 static HRESULT WINAPI VideoRenderer_IsDefaultSourceRect(BaseControlVideo* iface) 559 { 560 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 561 FIXME("(%p/%p)->(): stub !!!\n", This, iface); 562 563 return S_OK; 564 } 565 566 static HRESULT WINAPI VideoRenderer_IsDefaultTargetRect(BaseControlVideo* iface) 567 { 568 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 569 FIXME("(%p/%p)->(): stub !!!\n", This, iface); 570 571 return S_OK; 572 } 573 574 static HRESULT WINAPI VideoRenderer_SetDefaultSourceRect(BaseControlVideo* iface) 575 { 576 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 577 578 SetRect(&This->SourceRect, 0, 0, This->VideoWidth, This->VideoHeight); 579 580 return S_OK; 581 } 582 583 static HRESULT WINAPI VideoRenderer_SetDefaultTargetRect(BaseControlVideo* iface) 584 { 585 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 586 RECT rect; 587 588 if (!GetClientRect(This->baseControlWindow.baseWindow.hWnd, &rect)) 589 return E_FAIL; 590 591 SetRect(&This->DestRect, 0, 0, rect.right, rect.bottom); 592 593 return S_OK; 594 } 595 596 static HRESULT WINAPI VideoRenderer_SetSourceRect(BaseControlVideo* iface, RECT *pSourceRect) 597 { 598 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 599 CopyRect(&This->SourceRect,pSourceRect); 600 return S_OK; 601 } 602 603 static HRESULT WINAPI VideoRenderer_SetTargetRect(BaseControlVideo* iface, RECT *pTargetRect) 604 { 605 VideoRendererImpl *This = impl_from_BaseControlVideo(iface); 606 CopyRect(&This->DestRect,pTargetRect); 607 return S_OK; 608 } 609 610 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = { 611 VideoRenderer_GetSourceRect, 612 VideoRenderer_GetStaticImage, 613 VideoRenderer_GetTargetRect, 614 VideoRenderer_GetVideoFormat, 615 VideoRenderer_IsDefaultSourceRect, 616 VideoRenderer_IsDefaultTargetRect, 617 VideoRenderer_SetDefaultSourceRect, 618 VideoRenderer_SetDefaultTargetRect, 619 VideoRenderer_SetSourceRect, 620 VideoRenderer_SetTargetRect 621 }; 622 623 static inline VideoRendererImpl *impl_from_IUnknown(IUnknown *iface) 624 { 625 return CONTAINING_RECORD(iface, VideoRendererImpl, IUnknown_inner); 626 } 627 628 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 629 { 630 VideoRendererImpl *This = impl_from_IUnknown(iface); 631 632 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); 633 634 *ppv = NULL; 635 636 if (IsEqualIID(riid, &IID_IUnknown)) 637 *ppv = &This->IUnknown_inner; 638 else if (IsEqualIID(riid, &IID_IBasicVideo)) 639 *ppv = &This->baseControlVideo.IBasicVideo_iface; 640 else if (IsEqualIID(riid, &IID_IVideoWindow)) 641 *ppv = &This->baseControlWindow.IVideoWindow_iface; 642 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags)) 643 *ppv = &This->IAMFilterMiscFlags_iface; 644 else 645 { 646 HRESULT hr; 647 hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv); 648 if (SUCCEEDED(hr)) 649 return hr; 650 } 651 652 if (*ppv) 653 { 654 IUnknown_AddRef((IUnknown *)*ppv); 655 return S_OK; 656 } 657 658 if (!IsEqualIID(riid, &IID_IPin)) 659 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 660 661 return E_NOINTERFACE; 662 } 663 664 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown *iface) 665 { 666 VideoRendererImpl *This = impl_from_IUnknown(iface); 667 ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface); 668 669 TRACE("(%p)->(): new ref = %d\n", This, refCount); 670 671 return refCount; 672 } 673 674 static ULONG WINAPI VideoRendererInner_Release(IUnknown *iface) 675 { 676 VideoRendererImpl *This = impl_from_IUnknown(iface); 677 ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface); 678 679 TRACE("(%p)->(): new ref = %d\n", This, refCount); 680 681 if (!refCount) 682 { 683 BaseControlWindow_Destroy(&This->baseControlWindow); 684 BaseControlVideo_Destroy(&This->baseControlVideo); 685 PostThreadMessageW(This->ThreadID, WM_QUIT, 0, 0); 686 WaitForSingleObject(This->hThread, INFINITE); 687 CloseHandle(This->hThread); 688 CloseHandle(This->hEvent); 689 690 TRACE("Destroying Video Renderer\n"); 691 CoTaskMemFree(This); 692 693 return 0; 694 } 695 else 696 return refCount; 697 } 698 699 static const IUnknownVtbl IInner_VTable = 700 { 701 VideoRendererInner_QueryInterface, 702 VideoRendererInner_AddRef, 703 VideoRendererInner_Release 704 }; 705 706 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) 707 { 708 VideoRendererImpl *This = impl_from_IBaseFilter(iface); 709 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 710 } 711 712 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface) 713 { 714 VideoRendererImpl *This = impl_from_IBaseFilter(iface); 715 return IUnknown_AddRef(This->outer_unk); 716 } 717 718 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface) 719 { 720 VideoRendererImpl *This = impl_from_IBaseFilter(iface); 721 return IUnknown_Release(This->outer_unk); 722 } 723 724 /** IMediaFilter methods **/ 725 726 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface) 727 { 728 VideoRendererImpl *This = impl_from_IBaseFilter(iface); 729 730 TRACE("(%p/%p)->()\n", This, iface); 731 732 EnterCriticalSection(&This->renderer.csRenderLock); 733 if (This->renderer.filter.state != State_Paused) 734 { 735 if (This->renderer.filter.state == State_Stopped) 736 { 737 This->renderer.pInputPin->end_of_stream = 0; 738 ResetEvent(This->hEvent); 739 VideoRenderer_AutoShowWindow(This); 740 } 741 742 ResetEvent(This->renderer.RenderEvent); 743 This->renderer.filter.state = State_Paused; 744 } 745 LeaveCriticalSection(&This->renderer.csRenderLock); 746 747 return S_OK; 748 } 749 750 static const IBaseFilterVtbl VideoRenderer_Vtbl = 751 { 752 VideoRenderer_QueryInterface, 753 VideoRenderer_AddRef, 754 VideoRenderer_Release, 755 BaseFilterImpl_GetClassID, 756 BaseRendererImpl_Stop, 757 VideoRenderer_Pause, 758 BaseRendererImpl_Run, 759 BaseRendererImpl_GetState, 760 BaseRendererImpl_SetSyncSource, 761 BaseFilterImpl_GetSyncSource, 762 BaseFilterImpl_EnumPins, 763 BaseRendererImpl_FindPin, 764 BaseFilterImpl_QueryFilterInfo, 765 BaseFilterImpl_JoinFilterGraph, 766 BaseFilterImpl_QueryVendorInfo 767 }; 768 769 /*** IUnknown methods ***/ 770 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID *ppvObj) 771 { 772 VideoRendererImpl *This = impl_from_IBasicVideo(iface); 773 774 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj); 775 776 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj); 777 } 778 779 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo *iface) 780 { 781 VideoRendererImpl *This = impl_from_IBasicVideo(iface); 782 783 TRACE("(%p/%p)->()\n", This, iface); 784 785 return IUnknown_AddRef(This->outer_unk); 786 } 787 788 static ULONG WINAPI BasicVideo_Release(IBasicVideo *iface) 789 { 790 VideoRendererImpl *This = impl_from_IBasicVideo(iface); 791 792 TRACE("(%p/%p)->()\n", This, iface); 793 794 return IUnknown_Release(This->outer_unk); 795 } 796 797 static const IBasicVideoVtbl IBasicVideo_VTable = 798 { 799 BasicVideo_QueryInterface, 800 BasicVideo_AddRef, 801 BasicVideo_Release, 802 BaseControlVideoImpl_GetTypeInfoCount, 803 BaseControlVideoImpl_GetTypeInfo, 804 BaseControlVideoImpl_GetIDsOfNames, 805 BaseControlVideoImpl_Invoke, 806 BaseControlVideoImpl_get_AvgTimePerFrame, 807 BaseControlVideoImpl_get_BitRate, 808 BaseControlVideoImpl_get_BitErrorRate, 809 BaseControlVideoImpl_get_VideoWidth, 810 BaseControlVideoImpl_get_VideoHeight, 811 BaseControlVideoImpl_put_SourceLeft, 812 BaseControlVideoImpl_get_SourceLeft, 813 BaseControlVideoImpl_put_SourceWidth, 814 BaseControlVideoImpl_get_SourceWidth, 815 BaseControlVideoImpl_put_SourceTop, 816 BaseControlVideoImpl_get_SourceTop, 817 BaseControlVideoImpl_put_SourceHeight, 818 BaseControlVideoImpl_get_SourceHeight, 819 BaseControlVideoImpl_put_DestinationLeft, 820 BaseControlVideoImpl_get_DestinationLeft, 821 BaseControlVideoImpl_put_DestinationWidth, 822 BaseControlVideoImpl_get_DestinationWidth, 823 BaseControlVideoImpl_put_DestinationTop, 824 BaseControlVideoImpl_get_DestinationTop, 825 BaseControlVideoImpl_put_DestinationHeight, 826 BaseControlVideoImpl_get_DestinationHeight, 827 BaseControlVideoImpl_SetSourcePosition, 828 BaseControlVideoImpl_GetSourcePosition, 829 BaseControlVideoImpl_SetDefaultSourcePosition, 830 BaseControlVideoImpl_SetDestinationPosition, 831 BaseControlVideoImpl_GetDestinationPosition, 832 BaseControlVideoImpl_SetDefaultDestinationPosition, 833 BaseControlVideoImpl_GetVideoSize, 834 BaseControlVideoImpl_GetVideoPaletteEntries, 835 BaseControlVideoImpl_GetCurrentImage, 836 BaseControlVideoImpl_IsUsingDefaultSource, 837 BaseControlVideoImpl_IsUsingDefaultDestination 838 }; 839 840 841 /*** IUnknown methods ***/ 842 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID *ppvObj) 843 { 844 VideoRendererImpl *This = impl_from_IVideoWindow(iface); 845 846 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj); 847 848 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj); 849 } 850 851 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface) 852 { 853 VideoRendererImpl *This = impl_from_IVideoWindow(iface); 854 855 TRACE("(%p/%p)->()\n", This, iface); 856 857 return IUnknown_AddRef(This->outer_unk); 858 } 859 860 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface) 861 { 862 VideoRendererImpl *This = impl_from_IVideoWindow(iface); 863 864 TRACE("(%p/%p)->()\n", This, iface); 865 866 return IUnknown_Release(This->outer_unk); 867 } 868 869 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface, 870 LONG *FullScreenMode) 871 { 872 VideoRendererImpl *This = impl_from_IVideoWindow(iface); 873 874 TRACE("(%p/%p)->(%p): %d\n", This, iface, FullScreenMode, This->FullScreenMode); 875 876 if (!FullScreenMode) 877 return E_POINTER; 878 879 *FullScreenMode = This->FullScreenMode; 880 881 return S_OK; 882 } 883 884 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface, 885 LONG FullScreenMode) 886 { 887 VideoRendererImpl *This = impl_from_IVideoWindow(iface); 888 889 FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode); 890 891 if (FullScreenMode) { 892 This->baseControlWindow.baseWindow.WindowStyles = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE); 893 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE); 894 SetParent(This->baseControlWindow.baseWindow.hWnd, 0); 895 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, WS_POPUP); 896 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW); 897 GetWindowRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect); 898 This->WindowPos = This->DestRect; 899 } else { 900 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE); 901 SetParent(This->baseControlWindow.baseWindow.hWnd, This->baseControlWindow.hwndOwner); 902 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, This->baseControlWindow.baseWindow.WindowStyles); 903 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect); 904 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW); 905 This->WindowPos = This->DestRect; 906 } 907 This->FullScreenMode = FullScreenMode; 908 909 return S_OK; 910 } 911 912 static const IVideoWindowVtbl IVideoWindow_VTable = 913 { 914 VideoWindow_QueryInterface, 915 VideoWindow_AddRef, 916 VideoWindow_Release, 917 BaseControlWindowImpl_GetTypeInfoCount, 918 BaseControlWindowImpl_GetTypeInfo, 919 BaseControlWindowImpl_GetIDsOfNames, 920 BaseControlWindowImpl_Invoke, 921 BaseControlWindowImpl_put_Caption, 922 BaseControlWindowImpl_get_Caption, 923 BaseControlWindowImpl_put_WindowStyle, 924 BaseControlWindowImpl_get_WindowStyle, 925 BaseControlWindowImpl_put_WindowStyleEx, 926 BaseControlWindowImpl_get_WindowStyleEx, 927 BaseControlWindowImpl_put_AutoShow, 928 BaseControlWindowImpl_get_AutoShow, 929 BaseControlWindowImpl_put_WindowState, 930 BaseControlWindowImpl_get_WindowState, 931 BaseControlWindowImpl_put_BackgroundPalette, 932 BaseControlWindowImpl_get_BackgroundPalette, 933 BaseControlWindowImpl_put_Visible, 934 BaseControlWindowImpl_get_Visible, 935 BaseControlWindowImpl_put_Left, 936 BaseControlWindowImpl_get_Left, 937 BaseControlWindowImpl_put_Width, 938 BaseControlWindowImpl_get_Width, 939 BaseControlWindowImpl_put_Top, 940 BaseControlWindowImpl_get_Top, 941 BaseControlWindowImpl_put_Height, 942 BaseControlWindowImpl_get_Height, 943 BaseControlWindowImpl_put_Owner, 944 BaseControlWindowImpl_get_Owner, 945 BaseControlWindowImpl_put_MessageDrain, 946 BaseControlWindowImpl_get_MessageDrain, 947 BaseControlWindowImpl_get_BorderColor, 948 BaseControlWindowImpl_put_BorderColor, 949 VideoWindow_get_FullScreenMode, 950 VideoWindow_put_FullScreenMode, 951 BaseControlWindowImpl_SetWindowForeground, 952 BaseControlWindowImpl_NotifyOwnerMessage, 953 BaseControlWindowImpl_SetWindowPosition, 954 BaseControlWindowImpl_GetWindowPosition, 955 BaseControlWindowImpl_GetMinIdealImageSize, 956 BaseControlWindowImpl_GetMaxIdealImageSize, 957 BaseControlWindowImpl_GetRestorePosition, 958 BaseControlWindowImpl_HideCursor, 959 BaseControlWindowImpl_IsCursorHidden 960 }; 961 962 static VideoRendererImpl *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) 963 { 964 return CONTAINING_RECORD(iface, VideoRendererImpl, IAMFilterMiscFlags_iface); 965 } 966 967 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, 968 void **ppv) 969 { 970 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface); 971 return IUnknown_QueryInterface(This->outer_unk, riid, ppv); 972 } 973 974 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) 975 { 976 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface); 977 return IUnknown_AddRef(This->outer_unk); 978 } 979 980 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) 981 { 982 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface); 983 return IUnknown_Release(This->outer_unk); 984 } 985 986 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) 987 { 988 return AM_FILTER_MISC_FLAGS_IS_RENDERER; 989 } 990 991 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = { 992 AMFilterMiscFlags_QueryInterface, 993 AMFilterMiscFlags_AddRef, 994 AMFilterMiscFlags_Release, 995 AMFilterMiscFlags_GetMiscFlags 996 }; 997 998 HRESULT VideoRenderer_create(IUnknown *pUnkOuter, void **ppv) 999 { 1000 HRESULT hr; 1001 VideoRendererImpl * pVideoRenderer; 1002 1003 TRACE("(%p, %p)\n", pUnkOuter, ppv); 1004 1005 *ppv = NULL; 1006 1007 pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl)); 1008 pVideoRenderer->IUnknown_inner.lpVtbl = &IInner_VTable; 1009 pVideoRenderer->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl; 1010 1011 pVideoRenderer->init = FALSE; 1012 ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT)); 1013 ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT)); 1014 ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT)); 1015 pVideoRenderer->FullScreenMode = OAFALSE; 1016 1017 if (pUnkOuter) 1018 pVideoRenderer->outer_unk = pUnkOuter; 1019 else 1020 pVideoRenderer->outer_unk = &pVideoRenderer->IUnknown_inner; 1021 1022 hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter, 1023 &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"), 1024 &BaseFuncTable); 1025 1026 if (FAILED(hr)) 1027 goto fail; 1028 1029 hr = BaseControlWindow_Init(&pVideoRenderer->baseControlWindow, &IVideoWindow_VTable, 1030 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter, 1031 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable); 1032 if (FAILED(hr)) 1033 goto fail; 1034 1035 hr = BaseControlVideo_Init(&pVideoRenderer->baseControlVideo, &IBasicVideo_VTable, 1036 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter, 1037 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable); 1038 if (FAILED(hr)) 1039 goto fail; 1040 1041 if (!CreateRenderingSubsystem(pVideoRenderer)) { 1042 hr = E_FAIL; 1043 goto fail; 1044 } 1045 1046 *ppv = &pVideoRenderer->IUnknown_inner; 1047 return S_OK; 1048 1049 fail: 1050 BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface); 1051 CoTaskMemFree(pVideoRenderer); 1052 return hr; 1053 } 1054 1055 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv) 1056 { 1057 /* TODO: Attempt to use the VMR-7 renderer instead when possible */ 1058 return VideoRenderer_create(pUnkOuter, ppv); 1059 } 1060