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