1
0

winctrl.cpp 65 KB

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