Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2057 lines
64 KiB

  1. //------------------------------------------------------------------------------
  2. // File: WinCtrl.cpp
  3. //
  4. // Desc: DirectShow base classes - implements video control interface class.
  5. //
  6. //@@BEGIN_MSINTERNAL
  7. //
  8. // December 1995
  9. //
  10. //@@END_MSINTERNAL
  11. // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
  12. //------------------------------------------------------------------------------
  13. #include <streams.h>
  14. // The control interface methods require us to be connected
  15. #define CheckConnected(pin,code) \
  16. { \
  17. if (pin == NULL) { \
  18. ASSERT(!TEXT("Pin not set")); \
  19. } else if (pin->IsConnected() == FALSE) { \
  20. return (code); \
  21. } \
  22. }
  23. // This checks to see whether the window has a drain. An application can in
  24. // most environments set the owner/parent of windows so that they appear in
  25. // a compound document context (for example). In this case, the application
  26. // would probably like to be told of any keyboard/mouse messages. Therefore
  27. // we pass these messages on untranslated, returning TRUE if we're successful
  28. BOOL WINAPI PossiblyEatMessage(HWND hwndDrain, UINT uMsg, WPARAM wParam, LPARAM lParam)
  29. {
  30. if (hwndDrain != NULL && !InSendMessage())
  31. {
  32. switch (uMsg)
  33. {
  34. case WM_CHAR:
  35. case WM_DEADCHAR:
  36. case WM_KEYDOWN:
  37. case WM_KEYUP:
  38. case WM_LBUTTONDBLCLK:
  39. case WM_LBUTTONDOWN:
  40. case WM_LBUTTONUP:
  41. case WM_MBUTTONDBLCLK:
  42. case WM_MBUTTONDOWN:
  43. case WM_MBUTTONUP:
  44. case WM_MOUSEACTIVATE:
  45. case WM_MOUSEMOVE:
  46. // If we pass this on we don't get any mouse clicks
  47. //case WM_NCHITTEST:
  48. case WM_NCLBUTTONDBLCLK:
  49. case WM_NCLBUTTONDOWN:
  50. case WM_NCLBUTTONUP:
  51. case WM_NCMBUTTONDBLCLK:
  52. case WM_NCMBUTTONDOWN:
  53. case WM_NCMBUTTONUP:
  54. case WM_NCMOUSEMOVE:
  55. case WM_NCRBUTTONDBLCLK:
  56. case WM_NCRBUTTONDOWN:
  57. case WM_NCRBUTTONUP:
  58. case WM_RBUTTONDBLCLK:
  59. case WM_RBUTTONDOWN:
  60. case WM_RBUTTONUP:
  61. case WM_SYSCHAR:
  62. case WM_SYSDEADCHAR:
  63. case WM_SYSKEYDOWN:
  64. case WM_SYSKEYUP:
  65. DbgLog((LOG_TRACE, 2, TEXT("Forwarding %x to drain")));
  66. PostMessage(hwndDrain, uMsg, wParam, lParam);
  67. return TRUE;
  68. }
  69. }
  70. return FALSE;
  71. }
  72. // This class implements the IVideoWindow control functions (dual interface)
  73. // we support a large number of properties and methods designed to allow the
  74. // client (whether it be an automation controller or a C/C++ application) to
  75. // set and get a number of window related properties such as it's position.
  76. // We also support some methods that duplicate the properties but provide a
  77. // more direct and efficient mechanism as many values may be changed in one
  78. CBaseControlWindow::CBaseControlWindow(
  79. CBaseFilter *pFilter, // Owning filter
  80. CCritSec *pInterfaceLock, // Locking object
  81. TCHAR *pName, // Object description
  82. LPUNKNOWN pUnk, // Normal COM ownership
  83. HRESULT *phr) : // OLE return code
  84. CBaseVideoWindow(pName,pUnk),
  85. m_pInterfaceLock(pInterfaceLock),
  86. m_hwndOwner(NULL),
  87. m_hwndDrain(NULL),
  88. m_bAutoShow(TRUE),
  89. m_pFilter(pFilter),
  90. m_bCursorHidden(FALSE),
  91. m_pPin(NULL)
  92. {
  93. ASSERT(m_pFilter);
  94. ASSERT(m_pInterfaceLock);
  95. ASSERT(phr);
  96. m_BorderColour = VIDEO_COLOUR;
  97. }
  98. // Set the title caption on the base window, we don't do any field checking
  99. // as we really don't care what title they intend to have. We can always get
  100. // it back again later with GetWindowText. The only other complication is to
  101. // do the necessary string conversions between ANSI and OLE Unicode strings
  102. STDMETHODIMP CBaseControlWindow::put_Caption(BSTR strCaption)
  103. {
  104. CheckPointer(strCaption,E_POINTER);
  105. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  106. #ifdef UNICODE
  107. SetWindowText(m_hwnd, strCaption);
  108. #else
  109. CHAR Caption[CAPTION];
  110. WideCharToMultiByte(CP_ACP,0,strCaption,-1,Caption,CAPTION,NULL,NULL);
  111. SetWindowText(m_hwnd, Caption);
  112. #endif
  113. return NOERROR;
  114. }
  115. // Get the current base window title caption, once again we do no real field
  116. // checking. We allocate a string for the window title to be filled in with
  117. // which ensures the interface doesn't fiddle around with getting memory. A
  118. // BSTR is a normal C string with the length at position (-1), we use the
  119. // WriteBSTR helper function to create the caption to try and avoid OLE32
  120. STDMETHODIMP CBaseControlWindow::get_Caption(BSTR *pstrCaption)
  121. {
  122. CheckPointer(pstrCaption,E_POINTER);
  123. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  124. WCHAR WideCaption[CAPTION];
  125. #ifdef UNICODE
  126. GetWindowText(m_hwnd,WideCaption,CAPTION);
  127. #else
  128. // Convert the ASCII caption to a UNICODE string
  129. TCHAR Caption[CAPTION];
  130. GetWindowText(m_hwnd,Caption,CAPTION);
  131. MultiByteToWideChar(CP_ACP,0,Caption,-1,WideCaption,CAPTION);
  132. #endif
  133. return WriteBSTR(pstrCaption,WideCaption);
  134. }
  135. // Set the window style using GWL_EXSTYLE
  136. STDMETHODIMP CBaseControlWindow::put_WindowStyleEx(long WindowStyleEx)
  137. {
  138. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  139. // Should we be taking off WS_EX_TOPMOST
  140. if (GetWindowLong(m_hwnd,GWL_EXSTYLE) & WS_EX_TOPMOST) {
  141. if ((WindowStyleEx & WS_EX_TOPMOST) == 0) {
  142. SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) FALSE,(LPARAM) 0);
  143. }
  144. }
  145. // Likewise should we be adding WS_EX_TOPMOST
  146. if (WindowStyleEx & WS_EX_TOPMOST) {
  147. SendMessage(m_hwnd,m_ShowStageTop,(WPARAM) TRUE,(LPARAM) 0);
  148. WindowStyleEx &= (~WS_EX_TOPMOST);
  149. if (WindowStyleEx == 0) return NOERROR;
  150. }
  151. return DoSetWindowStyle(WindowStyleEx,GWL_EXSTYLE);
  152. }
  153. // Gets the current GWL_EXSTYLE base window style
  154. STDMETHODIMP CBaseControlWindow::get_WindowStyleEx(long *pWindowStyleEx)
  155. {
  156. CheckPointer(pWindowStyleEx,E_POINTER);
  157. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  158. return DoGetWindowStyle(pWindowStyleEx,GWL_EXSTYLE);
  159. }
  160. // Set the window style using GWL_STYLE
  161. STDMETHODIMP CBaseControlWindow::put_WindowStyle(long WindowStyle)
  162. {
  163. // These styles cannot be changed dynamically
  164. if ((WindowStyle & WS_DISABLED) ||
  165. (WindowStyle & WS_ICONIC) ||
  166. (WindowStyle & WS_MAXIMIZE) ||
  167. (WindowStyle & WS_MINIMIZE) ||
  168. (WindowStyle & WS_HSCROLL) ||
  169. (WindowStyle & WS_VSCROLL)) {
  170. return E_INVALIDARG;
  171. }
  172. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  173. return DoSetWindowStyle(WindowStyle,GWL_STYLE);
  174. }
  175. // Get the current GWL_STYLE base window style
  176. STDMETHODIMP CBaseControlWindow::get_WindowStyle(long *pWindowStyle)
  177. {
  178. CheckPointer(pWindowStyle,E_POINTER);
  179. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  180. return DoGetWindowStyle(pWindowStyle,GWL_STYLE);
  181. }
  182. // Change the base window style or the extended styles depending on whether
  183. // WindowLong is GWL_STYLE or GWL_EXSTYLE. We must call SetWindowPos to have
  184. // the window displayed in it's new style after the change which is a little
  185. // tricky if the window is not currently visible as we realise it offscreen.
  186. // In most cases the client will call get_WindowStyle before they call this
  187. // and then AND and OR in extra bit settings according to the requirements
  188. HRESULT CBaseControlWindow::DoSetWindowStyle(long Style,long WindowLong)
  189. {
  190. RECT WindowRect;
  191. // Get the window's visibility before setting the style
  192. BOOL bVisible = IsWindowVisible(m_hwnd);
  193. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  194. // Set the new style flags for the window
  195. SetWindowLong(m_hwnd,WindowLong,Style);
  196. UINT WindowFlags = SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  197. WindowFlags |= SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
  198. // Show the window again in the current position
  199. if (bVisible == TRUE) {
  200. SetWindowPos(m_hwnd, // Base window handle
  201. HWND_TOP, // Just a place holder
  202. 0,0,0,0, // Leave size and position
  203. WindowFlags); // Just draw it again
  204. return NOERROR;
  205. }
  206. // Move the window offscreen so the user doesn't see the changes
  207. MoveWindow((HWND) m_hwnd, // Base window handle
  208. GetSystemMetrics(SM_CXSCREEN), // Current desktop width
  209. GetSystemMetrics(SM_CYSCREEN), // Likewise it's height
  210. WIDTH(&WindowRect), // Use the same width
  211. HEIGHT(&WindowRect), // Keep height same to
  212. TRUE); // May as well repaint
  213. // Now show the previously hidden window
  214. SetWindowPos(m_hwnd, // Base window handle
  215. HWND_TOP, // Just a place holder
  216. 0,0,0,0, // Leave size and position
  217. WindowFlags); // Just draw it again
  218. ShowWindow(m_hwnd,SW_HIDE);
  219. if (GetParent(m_hwnd)) {
  220. MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2);
  221. }
  222. MoveWindow((HWND) m_hwnd, // Base window handle
  223. WindowRect.left, // Existing x coordinate
  224. WindowRect.top, // Existing y coordinate
  225. WIDTH(&WindowRect), // Use the same width
  226. HEIGHT(&WindowRect), // Keep height same to
  227. TRUE); // May as well repaint
  228. return NOERROR;
  229. }
  230. // Get the current base window style (either GWL_STYLE or GWL_EXSTYLE)
  231. HRESULT CBaseControlWindow::DoGetWindowStyle(long *pStyle,long WindowLong)
  232. {
  233. *pStyle = GetWindowLong(m_hwnd,WindowLong);
  234. return NOERROR;
  235. }
  236. // Change the visibility of the base window, this takes the same parameters
  237. // as the ShowWindow Win32 API does, so the client can have the window hidden
  238. // or shown, minimised to an icon, or maximised to play in full screen mode
  239. // We pass the request on to the base window to actually make the change
  240. STDMETHODIMP CBaseControlWindow::put_WindowState(long WindowState)
  241. {
  242. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  243. DoShowWindow(WindowState);
  244. return NOERROR;
  245. }
  246. // Get the current window state, this function returns a subset of the SW bit
  247. // settings available in ShowWindow, if the window is visible then SW_SHOW is
  248. // set, if it is hidden then the SW_HIDDEN is set, if it is either minimised
  249. // or maximised then the SW_MINIMIZE or SW_MAXIMIZE is set respectively. The
  250. // other SW bit settings are really set commands not readable output values
  251. STDMETHODIMP CBaseControlWindow::get_WindowState(long *pWindowState)
  252. {
  253. CheckPointer(pWindowState,E_POINTER);
  254. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  255. ASSERT(pWindowState);
  256. *pWindowState = FALSE;
  257. // Is the window visible, a window is termed visible if it is somewhere on
  258. // the current desktop even if it is completely obscured by other windows
  259. // so the flag is a style for each window set with the WS_VISIBLE bit
  260. if (IsWindowVisible(m_hwnd) == TRUE) {
  261. // Is the base window iconic
  262. if (IsIconic(m_hwnd) == TRUE) {
  263. *pWindowState |= SW_MINIMIZE;
  264. }
  265. // Has the window been maximised
  266. else if (IsZoomed(m_hwnd) == TRUE) {
  267. *pWindowState |= SW_MAXIMIZE;
  268. }
  269. // Window is normal
  270. else {
  271. *pWindowState |= SW_SHOW;
  272. }
  273. } else {
  274. *pWindowState |= SW_HIDE;
  275. }
  276. return NOERROR;
  277. }
  278. // This makes sure that any palette we realise in the base window (through a
  279. // media type or through the overlay interface) is done in the background and
  280. // is therefore mapped to existing device entries rather than taking it over
  281. // as it will do when we this window gets the keyboard focus. An application
  282. // uses this to make sure it doesn't have it's palette removed by the window
  283. STDMETHODIMP CBaseControlWindow::put_BackgroundPalette(long BackgroundPalette)
  284. {
  285. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  286. CAutoLock cWindowLock(&m_WindowLock);
  287. // Check this is a valid automation boolean type
  288. if (BackgroundPalette != OATRUE) {
  289. if (BackgroundPalette != OAFALSE) {
  290. return E_INVALIDARG;
  291. }
  292. }
  293. // Make sure the window realises any palette it has again
  294. m_bBackground = (BackgroundPalette == OATRUE ? TRUE : FALSE);
  295. PostMessage(m_hwnd,m_RealizePalette,0,0);
  296. PaintWindow(FALSE);
  297. return NOERROR;
  298. }
  299. // This returns the current background realisation setting
  300. STDMETHODIMP
  301. CBaseControlWindow::get_BackgroundPalette(long *pBackgroundPalette)
  302. {
  303. CheckPointer(pBackgroundPalette,E_POINTER);
  304. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  305. CAutoLock cWindowLock(&m_WindowLock);
  306. // Get the current background palette setting
  307. *pBackgroundPalette = (m_bBackground == TRUE ? OATRUE : OAFALSE);
  308. return NOERROR;
  309. }
  310. // Change the visibility of the base window
  311. STDMETHODIMP CBaseControlWindow::put_Visible(long Visible)
  312. {
  313. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  314. // Check this is a valid automation boolean type
  315. if (Visible != OATRUE) {
  316. if (Visible != OAFALSE) {
  317. return E_INVALIDARG;
  318. }
  319. }
  320. // Convert the boolean visibility into SW_SHOW and SW_HIDE
  321. INT Mode = (Visible == OATRUE ? SW_SHOWNORMAL : SW_HIDE);
  322. DoShowWindow(Mode);
  323. return NOERROR;
  324. }
  325. // Return OATRUE if the window is currently visible otherwise OAFALSE
  326. STDMETHODIMP CBaseControlWindow::get_Visible(long *pVisible)
  327. {
  328. CheckPointer(pVisible,E_POINTER);
  329. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  330. // See if the base window has a WS_VISIBLE style - this will return TRUE
  331. // even if the window is completely obscured by other desktop windows, we
  332. // return FALSE if the window is not showing because of earlier calls
  333. BOOL Mode = IsWindowVisible(m_hwnd);
  334. *pVisible = (Mode == TRUE ? OATRUE : OAFALSE);
  335. return NOERROR;
  336. }
  337. // Change the left position of the base window. This keeps the window width
  338. // and height properties the same so it effectively shunts the window left or
  339. // right accordingly - there is the Width property to change that dimension
  340. STDMETHODIMP CBaseControlWindow::put_Left(long Left)
  341. {
  342. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  343. BOOL bSuccess;
  344. RECT WindowRect;
  345. // Get the current window position in a RECT
  346. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  347. if (GetParent(m_hwnd)) {
  348. MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2);
  349. }
  350. // Adjust the coordinates ready for SetWindowPos, the window rectangle we
  351. // get back from GetWindowRect is in left,top,right and bottom while the
  352. // coordinates SetWindowPos wants are left,top,width and height values
  353. WindowRect.bottom = WindowRect.bottom - WindowRect.top;
  354. WindowRect.right = WindowRect.right - WindowRect.left;
  355. UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  356. bSuccess = SetWindowPos(m_hwnd, // Window handle
  357. HWND_TOP, // Put it at the top
  358. Left, // New left position
  359. WindowRect.top, // Leave top alone
  360. WindowRect.right, // The WIDTH (not right)
  361. WindowRect.bottom, // The HEIGHT (not bottom)
  362. WindowFlags); // Show window options
  363. if (bSuccess == FALSE) {
  364. return E_INVALIDARG;
  365. }
  366. return NOERROR;
  367. }
  368. // Return the current base window left position
  369. STDMETHODIMP CBaseControlWindow::get_Left(long *pLeft)
  370. {
  371. CheckPointer(pLeft,E_POINTER);
  372. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  373. RECT WindowRect;
  374. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  375. *pLeft = WindowRect.left;
  376. return NOERROR;
  377. }
  378. // Change the current width of the base window. This property complements the
  379. // left position property so we must keep the left edge constant and expand or
  380. // contract to the right, the alternative would be to change the left edge so
  381. // keeping the right edge constant but this is maybe a little more intuitive
  382. STDMETHODIMP CBaseControlWindow::put_Width(long Width)
  383. {
  384. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  385. BOOL bSuccess;
  386. RECT WindowRect;
  387. // Adjust the coordinates ready for SetWindowPos, the window rectangle we
  388. // get back from GetWindowRect is in left,top,right and bottom while the
  389. // coordinates SetWindowPos wants are left,top,width and height values
  390. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  391. if (GetParent(m_hwnd)) {
  392. MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2);
  393. }
  394. WindowRect.bottom = WindowRect.bottom - WindowRect.top;
  395. UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  396. // This seems to have a bug in that calling SetWindowPos on a window with
  397. // just the width changing causes it to ignore the width that you pass in
  398. // and sets it to a mimimum value of 110 pixels wide (Windows NT 3.51)
  399. bSuccess = SetWindowPos(m_hwnd, // Window handle
  400. HWND_TOP, // Put it at the top
  401. WindowRect.left, // Leave left alone
  402. WindowRect.top, // Leave top alone
  403. Width, // New WIDTH dimension
  404. WindowRect.bottom, // The HEIGHT (not bottom)
  405. WindowFlags); // Show window options
  406. if (bSuccess == FALSE) {
  407. return E_INVALIDARG;
  408. }
  409. return NOERROR;
  410. }
  411. // Return the current base window width
  412. STDMETHODIMP CBaseControlWindow::get_Width(long *pWidth)
  413. {
  414. CheckPointer(pWidth,E_POINTER);
  415. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  416. RECT WindowRect;
  417. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  418. *pWidth = WindowRect.right - WindowRect.left;
  419. return NOERROR;
  420. }
  421. // This allows the client program to change the top position for the window in
  422. // the same way that changing the left position does not affect the width of
  423. // the image so changing the top position does not affect the window height
  424. STDMETHODIMP CBaseControlWindow::put_Top(long Top)
  425. {
  426. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  427. BOOL bSuccess;
  428. RECT WindowRect;
  429. // Get the current window position in a RECT
  430. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  431. if (GetParent(m_hwnd)) {
  432. MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2);
  433. }
  434. // Adjust the coordinates ready for SetWindowPos, the window rectangle we
  435. // get back from GetWindowRect is in left,top,right and bottom while the
  436. // coordinates SetWindowPos wants are left,top,width and height values
  437. WindowRect.bottom = WindowRect.bottom - WindowRect.top;
  438. WindowRect.right = WindowRect.right - WindowRect.left;
  439. UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  440. bSuccess = SetWindowPos(m_hwnd, // Window handle
  441. HWND_TOP, // Put it at the top
  442. WindowRect.left, // Leave left alone
  443. Top, // New top position
  444. WindowRect.right, // The WIDTH (not right)
  445. WindowRect.bottom, // The HEIGHT (not bottom)
  446. WindowFlags); // Show window flags
  447. if (bSuccess == FALSE) {
  448. return E_INVALIDARG;
  449. }
  450. return NOERROR;
  451. }
  452. // Return the current base window top position
  453. STDMETHODIMP CBaseControlWindow::get_Top(long *pTop)
  454. {
  455. CheckPointer(pTop,E_POINTER);
  456. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  457. RECT WindowRect;
  458. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  459. *pTop = WindowRect.top;
  460. return NOERROR;
  461. }
  462. // Change the height of the window, this complements the top property so when
  463. // we change this we must keep the top position for the base window, as said
  464. // before we could keep the bottom and grow upwards although this is perhaps
  465. // a little more intuitive since we already have a top position property
  466. STDMETHODIMP CBaseControlWindow::put_Height(long Height)
  467. {
  468. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  469. BOOL bSuccess;
  470. RECT WindowRect;
  471. // Adjust the coordinates ready for SetWindowPos, the window rectangle we
  472. // get back from GetWindowRect is in left,top,right and bottom while the
  473. // coordinates SetWindowPos wants are left,top,width and height values
  474. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  475. if (GetParent(m_hwnd)) {
  476. MapWindowPoints(HWND_DESKTOP, GetParent(m_hwnd), (LPPOINT)&WindowRect, 2);
  477. }
  478. WindowRect.right = WindowRect.right - WindowRect.left;
  479. UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  480. bSuccess = SetWindowPos(m_hwnd, // Window handle
  481. HWND_TOP, // Put it at the top
  482. WindowRect.left, // Leave left alone
  483. WindowRect.top, // Leave top alone
  484. WindowRect.right, // The WIDTH (not right)
  485. Height, // New height dimension
  486. WindowFlags); // Show window flags
  487. if (bSuccess == FALSE) {
  488. return E_INVALIDARG;
  489. }
  490. return NOERROR;
  491. }
  492. // Return the current base window height
  493. STDMETHODIMP CBaseControlWindow::get_Height(long *pHeight)
  494. {
  495. CheckPointer(pHeight,E_POINTER);
  496. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  497. RECT WindowRect;
  498. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  499. *pHeight = WindowRect.bottom - WindowRect.top;
  500. return NOERROR;
  501. }
  502. // This can be called to change the owning window. Setting the owner is done
  503. // through this function, however to make the window a true child window the
  504. // style must also be set to WS_CHILD. After resetting the owner to NULL an
  505. // application should also set the style to WS_OVERLAPPED | WS_CLIPCHILDREN.
  506. // We cannot lock the object here because the SetParent causes an interthread
  507. // SendMessage to the owner window. If they are in GetState we will sit here
  508. // incomplete with the critical section locked therefore blocking out source
  509. // filter threads from accessing us. Because the source thread can't enter us
  510. // it can't get buffers or call EndOfStream so the GetState will not complete
  511. STDMETHODIMP CBaseControlWindow::put_Owner(OAHWND Owner)
  512. {
  513. // Check we are connected otherwise reject the call
  514. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  515. m_hwndOwner = (HWND) Owner;
  516. HWND hwndParent = m_hwndOwner;
  517. // Add or remove WS_CHILD as appropriate
  518. LONG Style = GetWindowLong(m_hwnd,GWL_STYLE);
  519. if (Owner == NULL) {
  520. Style &= (~WS_CHILD);
  521. } else {
  522. Style |= (WS_CHILD);
  523. }
  524. SetWindowLong(m_hwnd,GWL_STYLE,Style);
  525. // Don't call this with the filter locked
  526. SetParent(m_hwnd,hwndParent);
  527. PaintWindow(TRUE);
  528. NOTE1("Changed parent %lx",hwndParent);
  529. return NOERROR;
  530. }
  531. // This complements the put_Owner to get the current owning window property
  532. // we always return NOERROR although the returned window handle may be NULL
  533. // to indicate no owning window (the desktop window doesn't qualify as one)
  534. // If an application sets the owner we call SetParent, however that returns
  535. // NULL until the WS_CHILD bit is set on, so we store the owner internally
  536. STDMETHODIMP CBaseControlWindow::get_Owner(OAHWND *Owner)
  537. {
  538. CheckPointer(Owner,E_POINTER);
  539. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  540. *Owner = (OAHWND) m_hwndOwner;
  541. return NOERROR;
  542. }
  543. // And renderer supporting IVideoWindow may have an HWND set who will get any
  544. // keyboard and mouse messages we receive posted on to them. This is separate
  545. // from setting an owning window. By separating the two, applications may get
  546. // messages sent on even when they have set no owner (perhaps it's maximised)
  547. STDMETHODIMP CBaseControlWindow::put_MessageDrain(OAHWND Drain)
  548. {
  549. // Check we are connected otherwise reject the call
  550. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  551. m_hwndDrain = (HWND) Drain;
  552. return NOERROR;
  553. }
  554. // Return the current message drain
  555. STDMETHODIMP CBaseControlWindow::get_MessageDrain(OAHWND *Drain)
  556. {
  557. CheckPointer(Drain,E_POINTER);
  558. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  559. *Drain = (OAHWND) m_hwndDrain;
  560. return NOERROR;
  561. }
  562. // This is called by the filter graph to inform us of a message we should know
  563. // is being sent to our owning window. We have this because as a child window
  564. // we do not get certain messages that are only sent to top level windows. We
  565. // must see the palette changed/changing/query messages so that we know if we
  566. // have the foreground palette or not. We pass the message on to our window
  567. // using SendMessage - this will cause an interthread send message to occur
  568. STDMETHODIMP
  569. CBaseControlWindow::NotifyOwnerMessage(OAHWND hwnd, // Window handle
  570. long uMsg, // Message ID
  571. LONG_PTR wParam, // Parameters
  572. LONG_PTR lParam) // for message
  573. {
  574. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  575. // Only interested in these Windows messages
  576. switch (uMsg) {
  577. case WM_SYSCOLORCHANGE:
  578. case WM_PALETTECHANGED:
  579. case WM_PALETTEISCHANGING:
  580. case WM_QUERYNEWPALETTE:
  581. case WM_DEVMODECHANGE:
  582. case WM_DISPLAYCHANGE:
  583. case WM_ACTIVATEAPP:
  584. // If we do not have an owner then ignore
  585. if (m_hwndOwner == NULL) {
  586. return NOERROR;
  587. }
  588. SendMessage(m_hwnd,uMsg,(WPARAM)wParam,(LPARAM)lParam);
  589. break;
  590. // do NOT fwd WM_MOVE. the parameters are the location of the parent
  591. // window, NOT what the renderer should be looking at. But we need
  592. // to make sure the overlay is moved with the parent window, so we
  593. // do this.
  594. case WM_MOVE:
  595. PostMessage(m_hwnd,WM_PAINT,0,0);
  596. break;
  597. }
  598. return NOERROR;
  599. }
  600. // Allow an application to have us set the base window in the foreground. We
  601. // have this because it is difficult for one thread to do do this to a window
  602. // owned by another thread. We ask the base window class to do the real work
  603. STDMETHODIMP CBaseControlWindow::SetWindowForeground(long Focus)
  604. {
  605. // Check this is a valid automation boolean type
  606. if (Focus != OATRUE) {
  607. if (Focus != OAFALSE) {
  608. return E_INVALIDARG;
  609. }
  610. }
  611. // We shouldn't lock as this sends a message
  612. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  613. BOOL bFocus = (Focus == OATRUE ? TRUE : FALSE);
  614. DoSetWindowForeground(bFocus);
  615. return NOERROR;
  616. }
  617. // This allows a client to set the complete window size and position in one
  618. // atomic operation. The same affect can be had by changing each dimension
  619. // in turn through their individual properties although some flashing will
  620. // occur as each of them gets updated (they are better set at design time)
  621. STDMETHODIMP
  622. CBaseControlWindow::SetWindowPosition(long Left,long Top,long Width,long Height)
  623. {
  624. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  625. BOOL bSuccess;
  626. // Set the new size and position
  627. UINT WindowFlags = SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE;
  628. ASSERT(IsWindow(m_hwnd));
  629. bSuccess = SetWindowPos(m_hwnd, // Window handle
  630. HWND_TOP, // Put it at the top
  631. Left, // Left position
  632. Top, // Top position
  633. Width, // Window width
  634. Height, // Window height
  635. WindowFlags); // Show window flags
  636. ASSERT(bSuccess);
  637. #ifdef DEBUG
  638. DbgLog((LOG_TRACE, 1, TEXT("SWP failed error %d"), GetLastError()));
  639. #endif
  640. if (bSuccess == FALSE) {
  641. return E_INVALIDARG;
  642. }
  643. return NOERROR;
  644. }
  645. // This complements the SetWindowPosition to return the current window place
  646. // in device coordinates. As before the same information can be retrived by
  647. // calling the property get functions individually but this is atomic and is
  648. // therefore more suitable to a live environment rather than design time
  649. STDMETHODIMP
  650. CBaseControlWindow::GetWindowPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight)
  651. {
  652. // Should check the pointers are not NULL
  653. CheckPointer(pLeft,E_POINTER);
  654. CheckPointer(pTop,E_POINTER);
  655. CheckPointer(pWidth,E_POINTER);
  656. CheckPointer(pHeight,E_POINTER);
  657. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  658. RECT WindowRect;
  659. // Get the current window coordinates
  660. EXECUTE_ASSERT(GetWindowRect(m_hwnd,&WindowRect));
  661. // Convert the RECT into left,top,width and height values
  662. *pLeft = WindowRect.left;
  663. *pTop = WindowRect.top;
  664. *pWidth = WindowRect.right - WindowRect.left;
  665. *pHeight = WindowRect.bottom - WindowRect.top;
  666. return NOERROR;
  667. }
  668. // When a window is maximised or iconic calling GetWindowPosition will return
  669. // the current window position (likewise for the properties). However if the
  670. // restored size (ie the size we'll return to when normally shown) is needed
  671. // then this should be used. When in a normal position (neither iconic nor
  672. // maximised) then this returns the same coordinates as GetWindowPosition
  673. STDMETHODIMP
  674. CBaseControlWindow::GetRestorePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight)
  675. {
  676. // Should check the pointers are not NULL
  677. CheckPointer(pLeft,E_POINTER);
  678. CheckPointer(pTop,E_POINTER);
  679. CheckPointer(pWidth,E_POINTER);
  680. CheckPointer(pHeight,E_POINTER);
  681. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  682. // Use GetWindowPlacement to find the restore position
  683. WINDOWPLACEMENT Place;
  684. Place.length = sizeof(WINDOWPLACEMENT);
  685. EXECUTE_ASSERT(GetWindowPlacement(m_hwnd,&Place));
  686. RECT WorkArea;
  687. // We must take into account any task bar present
  688. if (SystemParametersInfo(SPI_GETWORKAREA,0,&WorkArea,FALSE) == TRUE) {
  689. if (GetParent(m_hwnd) == NULL) {
  690. Place.rcNormalPosition.top += WorkArea.top;
  691. Place.rcNormalPosition.bottom += WorkArea.top;
  692. Place.rcNormalPosition.left += WorkArea.left;
  693. Place.rcNormalPosition.right += WorkArea.left;
  694. }
  695. }
  696. // Convert the RECT into left,top,width and height values
  697. *pLeft = Place.rcNormalPosition.left;
  698. *pTop = Place.rcNormalPosition.top;
  699. *pWidth = Place.rcNormalPosition.right - Place.rcNormalPosition.left;
  700. *pHeight = Place.rcNormalPosition.bottom - Place.rcNormalPosition.top;
  701. return NOERROR;
  702. }
  703. // Return the current border colour, if we are playing something to a subset
  704. // of the base window display there is an outside area exposed. The default
  705. // action is to paint this colour in the Windows background colour (defined
  706. // as value COLOR_WINDOW) We reset to this default when we're disconnected
  707. STDMETHODIMP CBaseControlWindow::get_BorderColor(long *Color)
  708. {
  709. CheckPointer(Color,E_POINTER);
  710. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  711. *Color = (long) m_BorderColour;
  712. return NOERROR;
  713. }
  714. // This can be called to set the current border colour
  715. STDMETHODIMP CBaseControlWindow::put_BorderColor(long Color)
  716. {
  717. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  718. // Have the window repainted with the new border colour
  719. m_BorderColour = (COLORREF) Color;
  720. PaintWindow(TRUE);
  721. return NOERROR;
  722. }
  723. // Delegate fullscreen handling to plug in distributor
  724. STDMETHODIMP CBaseControlWindow::get_FullScreenMode(long *FullScreenMode)
  725. {
  726. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  727. CheckPointer(FullScreenMode,E_POINTER);
  728. return E_NOTIMPL;
  729. }
  730. // Delegate fullscreen handling to plug in distributor
  731. STDMETHODIMP CBaseControlWindow::put_FullScreenMode(long FullScreenMode)
  732. {
  733. return E_NOTIMPL;
  734. }
  735. // This sets the auto show property, this property causes the base window to
  736. // be displayed whenever we change state. This allows an application to have
  737. // to do nothing to have the window appear but still allow them to change the
  738. // default behaviour if for example they want to keep it hidden for longer
  739. STDMETHODIMP CBaseControlWindow::put_AutoShow(long AutoShow)
  740. {
  741. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  742. // Check this is a valid automation boolean type
  743. if (AutoShow != OATRUE) {
  744. if (AutoShow != OAFALSE) {
  745. return E_INVALIDARG;
  746. }
  747. }
  748. m_bAutoShow = (AutoShow == OATRUE ? TRUE : FALSE);
  749. return NOERROR;
  750. }
  751. // This can be called to get the current auto show flag. The flag is updated
  752. // when we connect and disconnect and through this interface all of which are
  753. // controlled and serialised by means of the main renderer critical section
  754. STDMETHODIMP CBaseControlWindow::get_AutoShow(long *AutoShow)
  755. {
  756. CheckPointer(AutoShow,E_POINTER);
  757. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  758. *AutoShow = (m_bAutoShow == TRUE ? OATRUE : OAFALSE);
  759. return NOERROR;
  760. }
  761. // Return the minimum ideal image size for the current video. This may differ
  762. // to the actual video dimensions because we may be using DirectDraw hardware
  763. // that has specific stretching requirements. For example the Cirrus Logic
  764. // cards have a minimum stretch factor depending on the overlay surface size
  765. STDMETHODIMP
  766. CBaseControlWindow::GetMinIdealImageSize(long *pWidth,long *pHeight)
  767. {
  768. CheckPointer(pWidth,E_POINTER);
  769. CheckPointer(pHeight,E_POINTER);
  770. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  771. FILTER_STATE State;
  772. // Must not be stopped for this to work correctly
  773. m_pFilter->GetState(0,&State);
  774. if (State == State_Stopped) {
  775. return VFW_E_WRONG_STATE;
  776. }
  777. RECT DefaultRect = GetDefaultRect();
  778. *pWidth = WIDTH(&DefaultRect);
  779. *pHeight = HEIGHT(&DefaultRect);
  780. return NOERROR;
  781. }
  782. // Return the maximum ideal image size for the current video. This may differ
  783. // to the actual video dimensions because we may be using DirectDraw hardware
  784. // that has specific stretching requirements. For example the Cirrus Logic
  785. // cards have a maximum stretch factor depending on the overlay surface size
  786. STDMETHODIMP
  787. CBaseControlWindow::GetMaxIdealImageSize(long *pWidth,long *pHeight)
  788. {
  789. CheckPointer(pWidth,E_POINTER);
  790. CheckPointer(pHeight,E_POINTER);
  791. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  792. FILTER_STATE State;
  793. // Must not be stopped for this to work correctly
  794. m_pFilter->GetState(0,&State);
  795. if (State == State_Stopped) {
  796. return VFW_E_WRONG_STATE;
  797. }
  798. RECT DefaultRect = GetDefaultRect();
  799. *pWidth = WIDTH(&DefaultRect);
  800. *pHeight = HEIGHT(&DefaultRect);
  801. return NOERROR;
  802. }
  803. // Allow an application to hide the cursor on our window
  804. STDMETHODIMP
  805. CBaseControlWindow::HideCursor(long HideCursor)
  806. {
  807. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  808. // Check this is a valid automation boolean type
  809. if (HideCursor != OATRUE) {
  810. if (HideCursor != OAFALSE) {
  811. return E_INVALIDARG;
  812. }
  813. }
  814. m_bCursorHidden = (HideCursor == OATRUE ? TRUE : FALSE);
  815. return NOERROR;
  816. }
  817. // Returns whether we have the cursor hidden or not
  818. STDMETHODIMP CBaseControlWindow::IsCursorHidden(long *CursorHidden)
  819. {
  820. CheckPointer(CursorHidden,E_POINTER);
  821. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  822. *CursorHidden = (m_bCursorHidden == TRUE ? OATRUE : OAFALSE);
  823. return NOERROR;
  824. }
  825. // This class implements the IBasicVideo control functions (dual interface)
  826. // we support a large number of properties and methods designed to allow the
  827. // client (whether it be an automation controller or a C/C++ application) to
  828. // set and get a number of video related properties such as the native video
  829. // size. We support some methods that duplicate the properties but provide a
  830. // more direct and efficient mechanism as many values may be changed in one
  831. CBaseControlVideo::CBaseControlVideo(
  832. CBaseFilter *pFilter, // Owning filter
  833. CCritSec *pInterfaceLock, // Locking object
  834. TCHAR *pName, // Object description
  835. LPUNKNOWN pUnk, // Normal COM ownership
  836. HRESULT *phr) : // OLE return code
  837. CBaseBasicVideo(pName,pUnk),
  838. m_pFilter(pFilter),
  839. m_pInterfaceLock(pInterfaceLock),
  840. m_pPin(NULL)
  841. {
  842. ASSERT(m_pFilter);
  843. ASSERT(m_pInterfaceLock);
  844. ASSERT(phr);
  845. }
  846. // Return an approximate average time per frame
  847. STDMETHODIMP CBaseControlVideo::get_AvgTimePerFrame(REFTIME *pAvgTimePerFrame)
  848. {
  849. CheckPointer(pAvgTimePerFrame,E_POINTER);
  850. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  851. CAutoLock cInterfaceLock(m_pInterfaceLock);
  852. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  853. if (pVideoInfo == NULL)
  854. return E_OUTOFMEMORY;
  855. COARefTime AvgTime(pVideoInfo->AvgTimePerFrame);
  856. *pAvgTimePerFrame = (REFTIME) AvgTime;
  857. return NOERROR;
  858. }
  859. // Return an approximate bit rate for the video
  860. STDMETHODIMP CBaseControlVideo::get_BitRate(long *pBitRate)
  861. {
  862. CheckPointer(pBitRate,E_POINTER);
  863. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  864. CAutoLock cInterfaceLock(m_pInterfaceLock);
  865. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  866. if (pVideoInfo == NULL)
  867. return E_OUTOFMEMORY;
  868. *pBitRate = pVideoInfo->dwBitRate;
  869. return NOERROR;
  870. }
  871. // Return an approximate bit error rate
  872. STDMETHODIMP CBaseControlVideo::get_BitErrorRate(long *pBitErrorRate)
  873. {
  874. CheckPointer(pBitErrorRate,E_POINTER);
  875. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  876. CAutoLock cInterfaceLock(m_pInterfaceLock);
  877. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  878. if (pVideoInfo == NULL)
  879. return E_OUTOFMEMORY;
  880. *pBitErrorRate = pVideoInfo->dwBitErrorRate;
  881. return NOERROR;
  882. }
  883. // This returns the current video width
  884. STDMETHODIMP CBaseControlVideo::get_VideoWidth(long *pVideoWidth)
  885. {
  886. CheckPointer(pVideoWidth,E_POINTER);
  887. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  888. CAutoLock cInterfaceLock(m_pInterfaceLock);
  889. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  890. if (pVideoInfo == NULL)
  891. return E_OUTOFMEMORY;
  892. *pVideoWidth = pVideoInfo->bmiHeader.biWidth;
  893. return NOERROR;
  894. }
  895. // This returns the current video height
  896. STDMETHODIMP CBaseControlVideo::get_VideoHeight(long *pVideoHeight)
  897. {
  898. CheckPointer(pVideoHeight,E_POINTER);
  899. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  900. CAutoLock cInterfaceLock(m_pInterfaceLock);
  901. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  902. if (pVideoInfo == NULL)
  903. return E_OUTOFMEMORY;
  904. *pVideoHeight = pVideoInfo->bmiHeader.biHeight;
  905. return NOERROR;
  906. }
  907. // This returns the current palette the video is using as an array allocated
  908. // by the user. To remain consistent we use PALETTEENTRY fields to return the
  909. // colours in rather than RGBQUADs that multimedia decided to use. The memory
  910. // is allocated by the user so we simple copy each in turn. We check that the
  911. // number of entries requested and the start position offset are both valid
  912. // If the number of entries evaluates to zero then we return an S_FALSE code
  913. STDMETHODIMP CBaseControlVideo::GetVideoPaletteEntries(long StartIndex,
  914. long Entries,
  915. long *pRetrieved,
  916. long *pPalette)
  917. {
  918. CheckPointer(pRetrieved,E_POINTER);
  919. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  920. CAutoLock cInterfaceLock(m_pInterfaceLock);
  921. CMediaType MediaType;
  922. // Get the video format from the derived class
  923. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  924. if (pVideoInfo == NULL)
  925. return E_OUTOFMEMORY;
  926. BITMAPINFOHEADER *pHeader = HEADER(pVideoInfo);
  927. // Is the current format palettised
  928. if (PALETTISED(pVideoInfo) == FALSE) {
  929. *pRetrieved = 0;
  930. return VFW_E_NO_PALETTE_AVAILABLE;
  931. }
  932. // Do they just want to know how many are available
  933. if (pPalette == NULL) {
  934. *pRetrieved = pHeader->biClrUsed;
  935. return NOERROR;
  936. }
  937. // Make sure the start position is a valid offset
  938. if (StartIndex >= (LONG) pHeader->biClrUsed || StartIndex < 0) {
  939. *pRetrieved = 0;
  940. return E_INVALIDARG;
  941. }
  942. // Correct the number we can retrieve
  943. LONG Available = (LONG) pHeader->biClrUsed - StartIndex;
  944. *pRetrieved = max(0,min(Available,Entries));
  945. if (*pRetrieved == 0) {
  946. return S_FALSE;
  947. }
  948. // Copy the palette entries to the output buffer
  949. PALETTEENTRY *pEntries = (PALETTEENTRY *) pPalette;
  950. RGBQUAD *pColours = COLORS(pVideoInfo) + StartIndex;
  951. for (LONG Count = 0;Count < *pRetrieved;Count++) {
  952. pEntries[Count].peRed = pColours[Count].rgbRed;
  953. pEntries[Count].peGreen = pColours[Count].rgbGreen;
  954. pEntries[Count].peBlue = pColours[Count].rgbBlue;
  955. pEntries[Count].peFlags = 0;
  956. }
  957. return NOERROR;
  958. }
  959. // This returns the current video dimensions as a method rather than a number
  960. // of individual property get calls. For the same reasons as said before we
  961. // cannot access the renderer media type directly as the window object thread
  962. // may be updating it since dynamic format changes may change these values
  963. STDMETHODIMP CBaseControlVideo::GetVideoSize(long *pWidth,long *pHeight)
  964. {
  965. CheckPointer(pWidth,E_POINTER);
  966. CheckPointer(pHeight,E_POINTER);
  967. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  968. CAutoLock cInterfaceLock(m_pInterfaceLock);
  969. // Get the video format from the derived class
  970. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  971. if (pVideoInfo == NULL)
  972. return E_OUTOFMEMORY;
  973. *pWidth = pVideoInfo->bmiHeader.biWidth;
  974. *pHeight = pVideoInfo->bmiHeader.biHeight;
  975. return NOERROR;
  976. }
  977. // Set the source video rectangle as left,top,right and bottom coordinates
  978. // rather than left,top,width and height as per OLE automation interfaces
  979. // Then pass the rectangle on to the window object to set the source
  980. STDMETHODIMP
  981. CBaseControlVideo::SetSourcePosition(long Left,long Top,long Width,long Height)
  982. {
  983. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  984. CAutoLock cInterfaceLock(m_pInterfaceLock);
  985. RECT SourceRect;
  986. SourceRect.left = Left;
  987. SourceRect.top = Top;
  988. SourceRect.right = Left + Width;
  989. SourceRect.bottom = Top + Height;
  990. // Check the source rectangle is valid
  991. HRESULT hr = CheckSourceRect(&SourceRect);
  992. if (FAILED(hr)) {
  993. return hr;
  994. }
  995. // Now set the source rectangle
  996. hr = SetSourceRect(&SourceRect);
  997. if (FAILED(hr)) {
  998. return hr;
  999. }
  1000. return OnUpdateRectangles();
  1001. }
  1002. // Return the source rectangle in left,top,width and height rather than the
  1003. // left,top,right and bottom values that RECT uses (and which the window
  1004. // object returns through GetSourceRect) which requires a little work
  1005. STDMETHODIMP
  1006. CBaseControlVideo::GetSourcePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight)
  1007. {
  1008. // Should check the pointers are non NULL
  1009. CheckPointer(pLeft,E_POINTER);
  1010. CheckPointer(pTop,E_POINTER);
  1011. CheckPointer(pWidth,E_POINTER);
  1012. CheckPointer(pHeight,E_POINTER);
  1013. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1014. RECT SourceRect;
  1015. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1016. GetSourceRect(&SourceRect);
  1017. *pLeft = SourceRect.left;
  1018. *pTop = SourceRect.top;
  1019. *pWidth = WIDTH(&SourceRect);
  1020. *pHeight = HEIGHT(&SourceRect);
  1021. return NOERROR;
  1022. }
  1023. // Set the video destination as left,top,right and bottom coordinates rather
  1024. // than the left,top,width and height uses as per OLE automation interfaces
  1025. // Then pass the rectangle on to the window object to set the destination
  1026. STDMETHODIMP
  1027. CBaseControlVideo::SetDestinationPosition(long Left,long Top,long Width,long Height)
  1028. {
  1029. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1030. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1031. RECT DestinationRect;
  1032. DestinationRect.left = Left;
  1033. DestinationRect.top = Top;
  1034. DestinationRect.right = Left + Width;
  1035. DestinationRect.bottom = Top + Height;
  1036. // Check the target rectangle is valid
  1037. HRESULT hr = CheckTargetRect(&DestinationRect);
  1038. if (FAILED(hr)) {
  1039. return hr;
  1040. }
  1041. // Now set the new target rectangle
  1042. hr = SetTargetRect(&DestinationRect);
  1043. if (FAILED(hr)) {
  1044. return hr;
  1045. }
  1046. return OnUpdateRectangles();
  1047. }
  1048. // Return the destination rectangle in left,top,width and height rather than
  1049. // the left,top,right and bottom values that RECT uses (and which the window
  1050. // object returns through GetDestinationRect) which requires a little work
  1051. STDMETHODIMP
  1052. CBaseControlVideo::GetDestinationPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight)
  1053. {
  1054. // Should check the pointers are not NULL
  1055. CheckPointer(pLeft,E_POINTER);
  1056. CheckPointer(pTop,E_POINTER);
  1057. CheckPointer(pWidth,E_POINTER);
  1058. CheckPointer(pHeight,E_POINTER);
  1059. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1060. RECT DestinationRect;
  1061. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1062. GetTargetRect(&DestinationRect);
  1063. *pLeft = DestinationRect.left;
  1064. *pTop = DestinationRect.top;
  1065. *pWidth = WIDTH(&DestinationRect);
  1066. *pHeight = HEIGHT(&DestinationRect);
  1067. return NOERROR;
  1068. }
  1069. // Set the source left position, the source rectangle we get back from the
  1070. // window object is a true rectangle in left,top,right and bottom positions
  1071. // so all we have to do is to update the left position and pass it back. We
  1072. // must keep the current width constant when we're updating this property
  1073. STDMETHODIMP CBaseControlVideo::put_SourceLeft(long SourceLeft)
  1074. {
  1075. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1076. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1077. RECT SourceRect;
  1078. GetSourceRect(&SourceRect);
  1079. SourceRect.right = SourceLeft + WIDTH(&SourceRect);
  1080. SourceRect.left = SourceLeft;
  1081. // Check the source rectangle is valid
  1082. HRESULT hr = CheckSourceRect(&SourceRect);
  1083. if (FAILED(hr)) {
  1084. return hr;
  1085. }
  1086. // Now set the source rectangle
  1087. hr = SetSourceRect(&SourceRect);
  1088. if (FAILED(hr)) {
  1089. return hr;
  1090. }
  1091. return OnUpdateRectangles();
  1092. }
  1093. // Return the current left source video position
  1094. STDMETHODIMP CBaseControlVideo::get_SourceLeft(long *pSourceLeft)
  1095. {
  1096. CheckPointer(pSourceLeft,E_POINTER);
  1097. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1098. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1099. RECT SourceRect;
  1100. GetSourceRect(&SourceRect);
  1101. *pSourceLeft = SourceRect.left;
  1102. return NOERROR;
  1103. }
  1104. // Set the source width, we get the current source rectangle and then update
  1105. // the right position to be the left position (thereby keeping it constant)
  1106. // plus the new source width we are passed in (it expands to the right)
  1107. STDMETHODIMP CBaseControlVideo::put_SourceWidth(long SourceWidth)
  1108. {
  1109. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1110. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1111. RECT SourceRect;
  1112. GetSourceRect(&SourceRect);
  1113. SourceRect.right = SourceRect.left + SourceWidth;
  1114. // Check the source rectangle is valid
  1115. HRESULT hr = CheckSourceRect(&SourceRect);
  1116. if (FAILED(hr)) {
  1117. return hr;
  1118. }
  1119. // Now set the source rectangle
  1120. hr = SetSourceRect(&SourceRect);
  1121. if (FAILED(hr)) {
  1122. return hr;
  1123. }
  1124. return OnUpdateRectangles();
  1125. }
  1126. // Return the current source width
  1127. STDMETHODIMP CBaseControlVideo::get_SourceWidth(long *pSourceWidth)
  1128. {
  1129. CheckPointer(pSourceWidth,E_POINTER);
  1130. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1131. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1132. RECT SourceRect;
  1133. GetSourceRect(&SourceRect);
  1134. *pSourceWidth = WIDTH(&SourceRect);
  1135. return NOERROR;
  1136. }
  1137. // Set the source top position - changing this property does not affect the
  1138. // current source height. So changing this shunts the source rectangle up and
  1139. // down appropriately. Changing the height complements this functionality by
  1140. // keeping the top position constant and simply changing the source height
  1141. STDMETHODIMP CBaseControlVideo::put_SourceTop(long SourceTop)
  1142. {
  1143. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1144. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1145. RECT SourceRect;
  1146. GetSourceRect(&SourceRect);
  1147. SourceRect.bottom = SourceTop + HEIGHT(&SourceRect);
  1148. SourceRect.top = SourceTop;
  1149. // Check the source rectangle is valid
  1150. HRESULT hr = CheckSourceRect(&SourceRect);
  1151. if (FAILED(hr)) {
  1152. return hr;
  1153. }
  1154. // Now set the source rectangle
  1155. hr = SetSourceRect(&SourceRect);
  1156. if (FAILED(hr)) {
  1157. return hr;
  1158. }
  1159. return OnUpdateRectangles();
  1160. }
  1161. // Return the current top position
  1162. STDMETHODIMP CBaseControlVideo::get_SourceTop(long *pSourceTop)
  1163. {
  1164. CheckPointer(pSourceTop,E_POINTER);
  1165. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1166. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1167. RECT SourceRect;
  1168. GetSourceRect(&SourceRect);
  1169. *pSourceTop = SourceRect.top;
  1170. return NOERROR;
  1171. }
  1172. // Set the source height
  1173. STDMETHODIMP CBaseControlVideo::put_SourceHeight(long SourceHeight)
  1174. {
  1175. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1176. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1177. RECT SourceRect;
  1178. GetSourceRect(&SourceRect);
  1179. SourceRect.bottom = SourceRect.top + SourceHeight;
  1180. // Check the source rectangle is valid
  1181. HRESULT hr = CheckSourceRect(&SourceRect);
  1182. if (FAILED(hr)) {
  1183. return hr;
  1184. }
  1185. // Now set the source rectangle
  1186. hr = SetSourceRect(&SourceRect);
  1187. if (FAILED(hr)) {
  1188. return hr;
  1189. }
  1190. return OnUpdateRectangles();
  1191. }
  1192. // Return the current source height
  1193. STDMETHODIMP CBaseControlVideo::get_SourceHeight(long *pSourceHeight)
  1194. {
  1195. CheckPointer(pSourceHeight,E_POINTER);
  1196. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1197. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1198. RECT SourceRect;
  1199. GetSourceRect(&SourceRect);
  1200. *pSourceHeight = HEIGHT(&SourceRect);
  1201. return NOERROR;
  1202. }
  1203. // Set the target left position, the target rectangle we get back from the
  1204. // window object is a true rectangle in left,top,right and bottom positions
  1205. // so all we have to do is to update the left position and pass it back. We
  1206. // must keep the current width constant when we're updating this property
  1207. STDMETHODIMP CBaseControlVideo::put_DestinationLeft(long DestinationLeft)
  1208. {
  1209. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1210. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1211. RECT DestinationRect;
  1212. GetTargetRect(&DestinationRect);
  1213. DestinationRect.right = DestinationLeft + WIDTH(&DestinationRect);
  1214. DestinationRect.left = DestinationLeft;
  1215. // Check the target rectangle is valid
  1216. HRESULT hr = CheckTargetRect(&DestinationRect);
  1217. if (FAILED(hr)) {
  1218. return hr;
  1219. }
  1220. // Now set the new target rectangle
  1221. hr = SetTargetRect(&DestinationRect);
  1222. if (FAILED(hr)) {
  1223. return hr;
  1224. }
  1225. return OnUpdateRectangles();
  1226. }
  1227. // Return the left position for the destination rectangle
  1228. STDMETHODIMP CBaseControlVideo::get_DestinationLeft(long *pDestinationLeft)
  1229. {
  1230. CheckPointer(pDestinationLeft,E_POINTER);
  1231. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1232. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1233. RECT DestinationRect;
  1234. GetTargetRect(&DestinationRect);
  1235. *pDestinationLeft = DestinationRect.left;
  1236. return NOERROR;
  1237. }
  1238. // Set the destination width
  1239. STDMETHODIMP CBaseControlVideo::put_DestinationWidth(long DestinationWidth)
  1240. {
  1241. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1242. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1243. RECT DestinationRect;
  1244. GetTargetRect(&DestinationRect);
  1245. DestinationRect.right = DestinationRect.left + DestinationWidth;
  1246. // Check the target rectangle is valid
  1247. HRESULT hr = CheckTargetRect(&DestinationRect);
  1248. if (FAILED(hr)) {
  1249. return hr;
  1250. }
  1251. // Now set the new target rectangle
  1252. hr = SetTargetRect(&DestinationRect);
  1253. if (FAILED(hr)) {
  1254. return hr;
  1255. }
  1256. return OnUpdateRectangles();
  1257. }
  1258. // Return the width for the destination rectangle
  1259. STDMETHODIMP CBaseControlVideo::get_DestinationWidth(long *pDestinationWidth)
  1260. {
  1261. CheckPointer(pDestinationWidth,E_POINTER);
  1262. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1263. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1264. RECT DestinationRect;
  1265. GetTargetRect(&DestinationRect);
  1266. *pDestinationWidth = WIDTH(&DestinationRect);
  1267. return NOERROR;
  1268. }
  1269. // Set the target top position - changing this property does not affect the
  1270. // current target height. So changing this shunts the target rectangle up and
  1271. // down appropriately. Changing the height complements this functionality by
  1272. // keeping the top position constant and simply changing the target height
  1273. STDMETHODIMP CBaseControlVideo::put_DestinationTop(long DestinationTop)
  1274. {
  1275. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1276. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1277. RECT DestinationRect;
  1278. GetTargetRect(&DestinationRect);
  1279. DestinationRect.bottom = DestinationTop + HEIGHT(&DestinationRect);
  1280. DestinationRect.top = DestinationTop;
  1281. // Check the target rectangle is valid
  1282. HRESULT hr = CheckTargetRect(&DestinationRect);
  1283. if (FAILED(hr)) {
  1284. return hr;
  1285. }
  1286. // Now set the new target rectangle
  1287. hr = SetTargetRect(&DestinationRect);
  1288. if (FAILED(hr)) {
  1289. return hr;
  1290. }
  1291. return OnUpdateRectangles();
  1292. }
  1293. // Return the top position for the destination rectangle
  1294. STDMETHODIMP CBaseControlVideo::get_DestinationTop(long *pDestinationTop)
  1295. {
  1296. CheckPointer(pDestinationTop,E_POINTER);
  1297. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1298. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1299. RECT DestinationRect;
  1300. GetTargetRect(&DestinationRect);
  1301. *pDestinationTop = DestinationRect.top;
  1302. return NOERROR;
  1303. }
  1304. // Set the destination height
  1305. STDMETHODIMP CBaseControlVideo::put_DestinationHeight(long DestinationHeight)
  1306. {
  1307. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1308. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1309. RECT DestinationRect;
  1310. GetTargetRect(&DestinationRect);
  1311. DestinationRect.bottom = DestinationRect.top + DestinationHeight;
  1312. // Check the target rectangle is valid
  1313. HRESULT hr = CheckTargetRect(&DestinationRect);
  1314. if (FAILED(hr)) {
  1315. return hr;
  1316. }
  1317. // Now set the new target rectangle
  1318. hr = SetTargetRect(&DestinationRect);
  1319. if (FAILED(hr)) {
  1320. return hr;
  1321. }
  1322. return OnUpdateRectangles();
  1323. }
  1324. // Return the height for the destination rectangle
  1325. STDMETHODIMP CBaseControlVideo::get_DestinationHeight(long *pDestinationHeight)
  1326. {
  1327. CheckPointer(pDestinationHeight,E_POINTER);
  1328. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1329. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1330. RECT DestinationRect;
  1331. GetTargetRect(&DestinationRect);
  1332. *pDestinationHeight = HEIGHT(&DestinationRect);
  1333. return NOERROR;
  1334. }
  1335. // Reset the source rectangle to the full video dimensions
  1336. STDMETHODIMP CBaseControlVideo::SetDefaultSourcePosition()
  1337. {
  1338. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1339. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1340. HRESULT hr = SetDefaultSourceRect();
  1341. if (FAILED(hr)) {
  1342. return hr;
  1343. }
  1344. return OnUpdateRectangles();
  1345. }
  1346. // Return S_OK if we're using the default source otherwise S_FALSE
  1347. STDMETHODIMP CBaseControlVideo::IsUsingDefaultSource()
  1348. {
  1349. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1350. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1351. return IsDefaultSourceRect();
  1352. }
  1353. // Reset the video renderer to use the entire playback area
  1354. STDMETHODIMP CBaseControlVideo::SetDefaultDestinationPosition()
  1355. {
  1356. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1357. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1358. HRESULT hr = SetDefaultTargetRect();
  1359. if (FAILED(hr)) {
  1360. return hr;
  1361. }
  1362. return OnUpdateRectangles();
  1363. }
  1364. // Return S_OK if we're using the default target otherwise S_FALSE
  1365. STDMETHODIMP CBaseControlVideo::IsUsingDefaultDestination()
  1366. {
  1367. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1368. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1369. return IsDefaultTargetRect();
  1370. }
  1371. // Return a copy of the current image in the video renderer
  1372. STDMETHODIMP
  1373. CBaseControlVideo::GetCurrentImage(long *pBufferSize,long *pVideoImage)
  1374. {
  1375. CheckPointer(pBufferSize,E_POINTER);
  1376. CheckConnected(m_pPin,VFW_E_NOT_CONNECTED);
  1377. CAutoLock cInterfaceLock(m_pInterfaceLock);
  1378. FILTER_STATE State;
  1379. // Make sure we are in a paused state
  1380. if (pVideoImage != NULL) {
  1381. m_pFilter->GetState(0,&State);
  1382. if (State != State_Paused) {
  1383. return VFW_E_NOT_PAUSED;
  1384. }
  1385. return GetStaticImage(pBufferSize,pVideoImage);
  1386. }
  1387. // Just return the memory required
  1388. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  1389. if (pVideoInfo == NULL)
  1390. return E_OUTOFMEMORY;
  1391. RECT SourceRect;
  1392. GetSourceRect(&SourceRect);
  1393. return GetImageSize(pVideoInfo,pBufferSize,&SourceRect);
  1394. }
  1395. // An application has two ways of using GetCurrentImage, one is to pass a real
  1396. // buffer which should be filled with the current image. The other is to pass
  1397. // a NULL buffer pointer which is interpreted as asking us to return how much
  1398. // memory is required for the image. The constraints for when the latter can
  1399. // be called are much looser. To calculate the memory required we synthesize
  1400. // a VIDEOINFO that takes into account the source rectangle that's being used
  1401. HRESULT CBaseControlVideo::GetImageSize(VIDEOINFOHEADER *pVideoInfo,
  1402. LONG *pBufferSize,
  1403. RECT *pSourceRect)
  1404. {
  1405. NOTE("Entering GetImageSize");
  1406. ASSERT(pSourceRect);
  1407. // Check we have the correct input parameters
  1408. if (pSourceRect == NULL ||
  1409. pVideoInfo == NULL ||
  1410. pBufferSize == NULL) {
  1411. return E_UNEXPECTED;
  1412. }
  1413. // Is the data format compatible
  1414. if (pVideoInfo->bmiHeader.biCompression != BI_RGB) {
  1415. if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) {
  1416. return E_INVALIDARG;
  1417. }
  1418. }
  1419. ASSERT(IsRectEmpty(pSourceRect) == FALSE);
  1420. BITMAPINFOHEADER bih;
  1421. bih.biWidth = WIDTH(pSourceRect);
  1422. bih.biHeight = HEIGHT(pSourceRect);
  1423. bih.biBitCount = pVideoInfo->bmiHeader.biBitCount;
  1424. LONG Size = DIBSIZE(bih);
  1425. Size += GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER;
  1426. *pBufferSize = Size;
  1427. return NOERROR;
  1428. }
  1429. // Given an IMediaSample containing a linear buffer with an image and a type
  1430. // describing the bitmap make a rendering of the image into the output buffer
  1431. // This may be called by derived classes who render typical video images to
  1432. // handle the IBasicVideo GetCurrentImage method. The pVideoImage pointer may
  1433. // be NULL when passed to GetCurrentImage in which case GetImageSize will be
  1434. // called instead, which will just do the calculation of the memory required
  1435. HRESULT CBaseControlVideo::CopyImage(IMediaSample *pMediaSample,
  1436. VIDEOINFOHEADER *pVideoInfo,
  1437. LONG *pBufferSize,
  1438. BYTE *pVideoImage,
  1439. RECT *pSourceRect)
  1440. {
  1441. NOTE("Entering CopyImage");
  1442. ASSERT(pSourceRect);
  1443. BYTE *pCurrentImage;
  1444. // Check we have an image to copy
  1445. if (pMediaSample == NULL || pSourceRect == NULL ||
  1446. pVideoInfo == NULL || pVideoImage == NULL ||
  1447. pBufferSize == NULL) {
  1448. return E_UNEXPECTED;
  1449. }
  1450. // Is the data format compatible
  1451. if (pVideoInfo->bmiHeader.biCompression != BI_RGB) {
  1452. if (pVideoInfo->bmiHeader.biCompression != BI_BITFIELDS) {
  1453. return E_INVALIDARG;
  1454. }
  1455. }
  1456. ASSERT(IsRectEmpty(pSourceRect) == FALSE);
  1457. BITMAPINFOHEADER bih;
  1458. bih.biWidth = WIDTH(pSourceRect);
  1459. bih.biHeight = HEIGHT(pSourceRect);
  1460. bih.biBitCount = pVideoInfo->bmiHeader.biBitCount;
  1461. LONG Size = GetBitmapFormatSize(HEADER(pVideoInfo)) - SIZE_PREHEADER;
  1462. LONG Total = Size + DIBSIZE(bih);
  1463. // Make sure we have a large enough buffer
  1464. if (*pBufferSize < Total) {
  1465. return E_OUTOFMEMORY;
  1466. }
  1467. // Copy the BITMAPINFO
  1468. CopyMemory((PVOID)pVideoImage, (PVOID)&pVideoInfo->bmiHeader, Size);
  1469. ((BITMAPINFOHEADER *)pVideoImage)->biWidth = WIDTH(pSourceRect);
  1470. ((BITMAPINFOHEADER *)pVideoImage)->biHeight = HEIGHT(pSourceRect);
  1471. ((BITMAPINFOHEADER *)pVideoImage)->biSizeImage = DIBSIZE(bih);
  1472. BYTE *pImageData = pVideoImage + Size;
  1473. // Get the pointer to it's image data
  1474. HRESULT hr = pMediaSample->GetPointer(&pCurrentImage);
  1475. if (FAILED(hr)) {
  1476. return hr;
  1477. }
  1478. // Now we are ready to start copying the source scan lines
  1479. LONG ScanLine = (pVideoInfo->bmiHeader.biBitCount / 8) * WIDTH(pSourceRect);
  1480. LONG LinesToSkip = pVideoInfo->bmiHeader.biHeight;
  1481. LinesToSkip -= pSourceRect->top + HEIGHT(pSourceRect);
  1482. pCurrentImage += LinesToSkip * DIBWIDTHBYTES(pVideoInfo->bmiHeader);
  1483. pCurrentImage += pSourceRect->left * (pVideoInfo->bmiHeader.biBitCount / 8);
  1484. // Even money on this GP faulting sometime...
  1485. for (LONG Line = 0;Line < HEIGHT(pSourceRect);Line++) {
  1486. CopyMemory((PVOID)pImageData, (PVOID)pCurrentImage, ScanLine);
  1487. pImageData += DIBWIDTHBYTES(*(BITMAPINFOHEADER *)pVideoImage);
  1488. pCurrentImage += DIBWIDTHBYTES(pVideoInfo->bmiHeader);
  1489. }
  1490. return NOERROR;
  1491. }
  1492. // Called when we change media types either during connection or dynamically
  1493. // We inform the filter graph and therefore the application that the video
  1494. // size may have changed, we don't bother looking to see if it really has as
  1495. // we leave that to the application - the dimensions are the event parameters
  1496. HRESULT CBaseControlVideo::OnVideoSizeChange()
  1497. {
  1498. // Get the video format from the derived class
  1499. VIDEOINFOHEADER *pVideoInfo = GetVideoFormat();
  1500. if (pVideoInfo == NULL)
  1501. return E_OUTOFMEMORY;
  1502. WORD Width = (WORD) pVideoInfo->bmiHeader.biWidth;
  1503. WORD Height = (WORD) pVideoInfo->bmiHeader.biHeight;
  1504. return m_pFilter->NotifyEvent(EC_VIDEO_SIZE_CHANGED,
  1505. MAKELPARAM(Width,Height),
  1506. MAKEWPARAM(0,0));
  1507. }
  1508. // Set the video source rectangle. We must check the source rectangle against
  1509. // the actual video dimensions otherwise when we come to draw the pictures we
  1510. // get access violations as GDI tries to touch data outside of the image data
  1511. // Although we store the rectangle in left, top, right and bottom coordinates
  1512. // instead of left, top, width and height as OLE uses we do take into account
  1513. // that the rectangle is used up to, but not including, the right column and
  1514. // bottom row of pixels, see the Win32 documentation on RECT for more details
  1515. HRESULT CBaseControlVideo::CheckSourceRect(RECT *pSourceRect)
  1516. {
  1517. CheckPointer(pSourceRect,E_POINTER);
  1518. LONG Width,Height;
  1519. GetVideoSize(&Width,&Height);
  1520. // Check the coordinates are greater than zero
  1521. // and that the rectangle is valid (left<right, top<bottom)
  1522. if ((pSourceRect->left >= pSourceRect->right) ||
  1523. (pSourceRect->left < 0) ||
  1524. (pSourceRect->top >= pSourceRect->bottom) ||
  1525. (pSourceRect->top < 0)) {
  1526. return E_INVALIDARG;
  1527. }
  1528. // Check the coordinates are less than the extents
  1529. if ((pSourceRect->right > Width) ||
  1530. (pSourceRect->bottom > Height)) {
  1531. return E_INVALIDARG;
  1532. }
  1533. return NOERROR;
  1534. }
  1535. // Check the target rectangle has some valid coordinates, which amounts to
  1536. // little more than checking the destination rectangle isn't empty. Derived
  1537. // classes may call this when they have their SetTargetRect method called to
  1538. // check the rectangle validity, we do not update the rectangles passed in
  1539. // Although we store the rectangle in left, top, right and bottom coordinates
  1540. // instead of left, top, width and height as OLE uses we do take into account
  1541. // that the rectangle is used up to, but not including, the right column and
  1542. // bottom row of pixels, see the Win32 documentation on RECT for more details
  1543. HRESULT CBaseControlVideo::CheckTargetRect(RECT *pTargetRect)
  1544. {
  1545. // Check the pointer is valid
  1546. if (pTargetRect == NULL) {
  1547. return E_POINTER;
  1548. }
  1549. // These overflow the WIDTH and HEIGHT checks
  1550. if (pTargetRect->left > pTargetRect->right ||
  1551. pTargetRect->top > pTargetRect->bottom) {
  1552. return E_INVALIDARG;
  1553. }
  1554. // Check the rectangle has valid coordinates
  1555. if (WIDTH(pTargetRect) <= 0 || HEIGHT(pTargetRect) <= 0) {
  1556. return E_INVALIDARG;
  1557. }
  1558. ASSERT(IsRectEmpty(pTargetRect) == FALSE);
  1559. return NOERROR;
  1560. }