blob: c68d314a74796330c2954cfcc2770da71da26651 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
Donald E Curtisa8736442015-08-05 15:48:13 -07002 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
Donald E Curtisa8736442015-08-05 15:48:13 -07004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "examples/peerconnection/client/main_wnd.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
13#include <math.h>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "examples/peerconnection/client/defaults.h"
17#include "rtc_base/arraysize.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Niels Möllerd7b91312018-05-24 11:21:34 +020020#include "rtc_base/stringutils.h"
Mirko Bonadei65432062017-12-11 09:32:13 +010021#include "third_party/libyuv/include/libyuv/convert_argb.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000022
23ATOM MainWnd::wnd_class_ = 0;
24const wchar_t MainWnd::kClassName[] = L"WebRTC_MainWnd";
25
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000026using rtc::sprintfn;
kjellander@webrtc.org04025152014-07-01 16:28:13 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028namespace {
29
30const char kConnecting[] = "Connecting... ";
31const char kNoVideoStreams[] = "(no video streams either way)";
32const char kNoIncomingStream[] = "(no incoming video)";
33
Yves Gerey665174f2018-06-19 15:03:05 +020034void CalculateWindowSizeForText(HWND wnd,
35 const wchar_t* text,
36 size_t* width,
37 size_t* height) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038 HDC dc = ::GetDC(wnd);
39 RECT text_rc = {0};
40 ::DrawText(dc, text, -1, &text_rc, DT_CALCRECT | DT_SINGLELINE);
41 ::ReleaseDC(wnd, dc);
42 RECT client, window;
43 ::GetClientRect(wnd, &client);
44 ::GetWindowRect(wnd, &window);
45
46 *width = text_rc.right - text_rc.left;
Yves Gerey665174f2018-06-19 15:03:05 +020047 *width += (window.right - window.left) - (client.right - client.left);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048 *height = text_rc.bottom - text_rc.top;
Yves Gerey665174f2018-06-19 15:03:05 +020049 *height += (window.bottom - window.top) - (client.bottom - client.top);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050}
51
52HFONT GetDefaultFont() {
53 static HFONT font = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
54 return font;
55}
56
57std::string GetWindowText(HWND wnd) {
58 char text[MAX_PATH] = {0};
59 ::GetWindowTextA(wnd, &text[0], ARRAYSIZE(text));
60 return text;
61}
62
63void AddListBoxItem(HWND listbox, const std::string& str, LPARAM item_data) {
64 LRESULT index = ::SendMessageA(listbox, LB_ADDSTRING, 0,
Yves Gerey665174f2018-06-19 15:03:05 +020065 reinterpret_cast<LPARAM>(str.c_str()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066 ::SendMessageA(listbox, LB_SETITEMDATA, index, item_data);
67}
68
69} // namespace
70
Yves Gerey665174f2018-06-19 15:03:05 +020071MainWnd::MainWnd(const char* server,
72 int port,
73 bool auto_connect,
kjellander@webrtc.org04025152014-07-01 16:28:13 +000074 bool auto_call)
Yves Gerey665174f2018-06-19 15:03:05 +020075 : ui_(CONNECT_TO_SERVER),
76 wnd_(NULL),
77 edit1_(NULL),
78 edit2_(NULL),
79 label1_(NULL),
80 label2_(NULL),
81 button_(NULL),
82 listbox_(NULL),
83 destroyed_(false),
84 callback_(NULL),
85 nested_msg_(NULL),
86 server_(server),
87 auto_connect_(auto_connect),
88 auto_call_(auto_call) {
kjellander@webrtc.org04025152014-07-01 16:28:13 +000089 char buffer[10] = {0};
90 sprintfn(buffer, sizeof(buffer), "%i", port);
91 port_ = buffer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092}
93
94MainWnd::~MainWnd() {
nisseede5da42017-01-12 05:15:36 -080095 RTC_DCHECK(!IsWindow());
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096}
97
98bool MainWnd::Create() {
nisseede5da42017-01-12 05:15:36 -080099 RTC_DCHECK(wnd_ == NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100 if (!RegisterWindowClass())
101 return false;
102
103 ui_thread_id_ = ::GetCurrentThreadId();
Yves Gerey665174f2018-06-19 15:03:05 +0200104 wnd_ =
105 ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC",
106 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
107 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
108 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109
110 ::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
111 TRUE);
112
113 CreateChildWindows();
114 SwitchToConnectUI();
115
116 return wnd_ != NULL;
117}
118
119bool MainWnd::Destroy() {
120 BOOL ret = FALSE;
121 if (IsWindow()) {
122 ret = ::DestroyWindow(wnd_);
123 }
124
125 return ret != FALSE;
126}
127
128void MainWnd::RegisterObserver(MainWndCallback* callback) {
129 callback_ = callback;
130}
131
132bool MainWnd::IsWindow() {
133 return wnd_ && ::IsWindow(wnd_) != FALSE;
134}
135
136bool MainWnd::PreTranslateMessage(MSG* msg) {
137 bool ret = false;
138 if (msg->message == WM_CHAR) {
139 if (msg->wParam == VK_TAB) {
140 HandleTabbing();
141 ret = true;
142 } else if (msg->wParam == VK_RETURN) {
143 OnDefaultAction();
144 ret = true;
145 } else if (msg->wParam == VK_ESCAPE) {
146 if (callback_) {
147 if (ui_ == STREAMING) {
148 callback_->DisconnectFromCurrentPeer();
149 } else {
150 callback_->DisconnectFromServer();
151 }
152 }
153 }
154 } else if (msg->hwnd == NULL && msg->message == UI_THREAD_CALLBACK) {
155 callback_->UIThreadCallback(static_cast<int>(msg->wParam),
156 reinterpret_cast<void*>(msg->lParam));
157 ret = true;
158 }
159 return ret;
160}
161
162void MainWnd::SwitchToConnectUI() {
nisseede5da42017-01-12 05:15:36 -0800163 RTC_DCHECK(IsWindow());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 LayoutPeerListUI(false);
165 ui_ = CONNECT_TO_SERVER;
166 LayoutConnectUI(true);
167 ::SetFocus(edit1_);
kjellander@webrtc.org04025152014-07-01 16:28:13 +0000168
169 if (auto_connect_)
170 ::PostMessage(button_, BM_CLICK, 0, 0);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171}
172
173void MainWnd::SwitchToPeerList(const Peers& peers) {
174 LayoutConnectUI(false);
175
176 ::SendMessage(listbox_, LB_RESETCONTENT, 0, 0);
177
178 AddListBoxItem(listbox_, "List of currently connected peers:", -1);
179 Peers::const_iterator i = peers.begin();
180 for (; i != peers.end(); ++i)
181 AddListBoxItem(listbox_, i->second.c_str(), i->first);
182
183 ui_ = LIST_PEERS;
184 LayoutPeerListUI(true);
185 ::SetFocus(listbox_);
kjellander@webrtc.org04025152014-07-01 16:28:13 +0000186
187 if (auto_call_ && peers.begin() != peers.end()) {
188 // Get the number of items in the list
189 LRESULT count = ::SendMessage(listbox_, LB_GETCOUNT, 0, 0);
190 if (count != LB_ERR) {
191 // Select the last item in the list
Yves Gerey665174f2018-06-19 15:03:05 +0200192 LRESULT selection = ::SendMessage(listbox_, LB_SETCURSEL, count - 1, 0);
kjellander@webrtc.org04025152014-07-01 16:28:13 +0000193 if (selection != LB_ERR)
Yves Gerey665174f2018-06-19 15:03:05 +0200194 ::PostMessage(wnd_, WM_COMMAND,
195 MAKEWPARAM(GetDlgCtrlID(listbox_), LBN_DBLCLK),
kjellander@webrtc.org04025152014-07-01 16:28:13 +0000196 reinterpret_cast<LPARAM>(listbox_));
197 }
198 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199}
200
201void MainWnd::SwitchToStreamingUI() {
202 LayoutConnectUI(false);
203 LayoutPeerListUI(false);
204 ui_ = STREAMING;
205}
206
207void MainWnd::MessageBox(const char* caption, const char* text, bool is_error) {
208 DWORD flags = MB_OK;
209 if (is_error)
210 flags |= MB_ICONERROR;
211
212 ::MessageBoxA(handle(), text, caption, flags);
213}
214
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215void MainWnd::StartLocalRenderer(webrtc::VideoTrackInterface* local_video) {
216 local_renderer_.reset(new VideoRenderer(handle(), 1, 1, local_video));
217}
218
219void MainWnd::StopLocalRenderer() {
220 local_renderer_.reset();
221}
222
223void MainWnd::StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video) {
224 remote_renderer_.reset(new VideoRenderer(handle(), 1, 1, remote_video));
225}
226
227void MainWnd::StopRemoteRenderer() {
228 remote_renderer_.reset();
229}
230
231void MainWnd::QueueUIThreadCallback(int msg_id, void* data) {
232 ::PostThreadMessage(ui_thread_id_, UI_THREAD_CALLBACK,
Yves Gerey665174f2018-06-19 15:03:05 +0200233 static_cast<WPARAM>(msg_id),
234 reinterpret_cast<LPARAM>(data));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235}
236
237void MainWnd::OnPaint() {
238 PAINTSTRUCT ps;
239 ::BeginPaint(handle(), &ps);
240
241 RECT rc;
242 ::GetClientRect(handle(), &rc);
243
244 VideoRenderer* local_renderer = local_renderer_.get();
245 VideoRenderer* remote_renderer = remote_renderer_.get();
246 if (ui_ == STREAMING && remote_renderer && local_renderer) {
247 AutoLock<VideoRenderer> local_lock(local_renderer);
248 AutoLock<VideoRenderer> remote_lock(remote_renderer);
249
250 const BITMAPINFO& bmi = remote_renderer->bmi();
251 int height = abs(bmi.bmiHeader.biHeight);
252 int width = bmi.bmiHeader.biWidth;
253
Peter Boström0c4e06b2015-10-07 12:23:21 +0200254 const uint8_t* image = remote_renderer->image();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 if (image != NULL) {
256 HDC dc_mem = ::CreateCompatibleDC(ps.hdc);
257 ::SetStretchBltMode(dc_mem, HALFTONE);
258
259 // Set the map mode so that the ratio will be maintained for us.
Yves Gerey665174f2018-06-19 15:03:05 +0200260 HDC all_dc[] = {ps.hdc, dc_mem};
tfarina5237aaf2015-11-10 23:44:30 -0800261 for (int i = 0; i < arraysize(all_dc); ++i) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 SetMapMode(all_dc[i], MM_ISOTROPIC);
263 SetWindowExtEx(all_dc[i], width, height, NULL);
264 SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL);
265 }
266
267 HBITMAP bmp_mem = ::CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom);
268 HGDIOBJ bmp_old = ::SelectObject(dc_mem, bmp_mem);
269
Yves Gerey665174f2018-06-19 15:03:05 +0200270 POINT logical_area = {rc.right, rc.bottom};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 DPtoLP(ps.hdc, &logical_area, 1);
272
273 HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0));
Yves Gerey665174f2018-06-19 15:03:05 +0200274 RECT logical_rect = {0, 0, logical_area.x, logical_area.y};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 ::FillRect(dc_mem, &logical_rect, brush);
276 ::DeleteObject(brush);
277
278 int x = (logical_area.x / 2) - (width / 2);
279 int y = (logical_area.y / 2) - (height / 2);
280
Yves Gerey665174f2018-06-19 15:03:05 +0200281 StretchDIBits(dc_mem, x, y, width, height, 0, 0, width, height, image,
282 &bmi, DIB_RGB_COLORS, SRCCOPY);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283
284 if ((rc.right - rc.left) > 200 && (rc.bottom - rc.top) > 200) {
285 const BITMAPINFO& bmi = local_renderer->bmi();
286 image = local_renderer->image();
287 int thumb_width = bmi.bmiHeader.biWidth / 4;
288 int thumb_height = abs(bmi.bmiHeader.biHeight) / 4;
Yves Gerey665174f2018-06-19 15:03:05 +0200289 StretchDIBits(dc_mem, logical_area.x - thumb_width - 10,
290 logical_area.y - thumb_height - 10, thumb_width,
291 thumb_height, 0, 0, bmi.bmiHeader.biWidth,
292 -bmi.bmiHeader.biHeight, image, &bmi, DIB_RGB_COLORS,
293 SRCCOPY);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 }
295
Yves Gerey665174f2018-06-19 15:03:05 +0200296 BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y, dc_mem, 0, 0,
297 SRCCOPY);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298
299 // Cleanup.
300 ::SelectObject(dc_mem, bmp_old);
301 ::DeleteObject(bmp_mem);
302 ::DeleteDC(dc_mem);
303 } else {
304 // We're still waiting for the video stream to be initialized.
305 HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0));
306 ::FillRect(ps.hdc, &rc, brush);
307 ::DeleteObject(brush);
308
309 HGDIOBJ old_font = ::SelectObject(ps.hdc, GetDefaultFont());
310 ::SetTextColor(ps.hdc, RGB(0xff, 0xff, 0xff));
311 ::SetBkMode(ps.hdc, TRANSPARENT);
312
313 std::string text(kConnecting);
314 if (!local_renderer->image()) {
315 text += kNoVideoStreams;
316 } else {
317 text += kNoIncomingStream;
318 }
319 ::DrawTextA(ps.hdc, text.c_str(), -1, &rc,
Yves Gerey665174f2018-06-19 15:03:05 +0200320 DT_SINGLELINE | DT_CENTER | DT_VCENTER);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321 ::SelectObject(ps.hdc, old_font);
322 }
323 } else {
324 HBRUSH brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
325 ::FillRect(ps.hdc, &rc, brush);
326 ::DeleteObject(brush);
327 }
328
329 ::EndPaint(handle(), &ps);
330}
331
332void MainWnd::OnDestroyed() {
333 PostQuitMessage(0);
334}
335
336void MainWnd::OnDefaultAction() {
337 if (!callback_)
338 return;
339 if (ui_ == CONNECT_TO_SERVER) {
340 std::string server(GetWindowText(edit1_));
341 std::string port_str(GetWindowText(edit2_));
342 int port = port_str.length() ? atoi(port_str.c_str()) : 0;
343 callback_->StartLogin(server, port);
344 } else if (ui_ == LIST_PEERS) {
345 LRESULT sel = ::SendMessage(listbox_, LB_GETCURSEL, 0, 0);
346 if (sel != LB_ERR) {
347 LRESULT peer_id = ::SendMessage(listbox_, LB_GETITEMDATA, sel, 0);
348 if (peer_id != -1 && callback_) {
349 callback_->ConnectToPeer(peer_id);
350 }
351 }
352 } else {
353 MessageBoxA(wnd_, "OK!", "Yeah", MB_OK);
354 }
355}
356
357bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) {
358 switch (msg) {
359 case WM_ERASEBKGND:
360 *result = TRUE;
361 return true;
362
363 case WM_PAINT:
364 OnPaint();
365 return true;
366
367 case WM_SETFOCUS:
368 if (ui_ == CONNECT_TO_SERVER) {
369 SetFocus(edit1_);
370 } else if (ui_ == LIST_PEERS) {
371 SetFocus(listbox_);
372 }
373 return true;
374
375 case WM_SIZE:
376 if (ui_ == CONNECT_TO_SERVER) {
377 LayoutConnectUI(true);
378 } else if (ui_ == LIST_PEERS) {
379 LayoutPeerListUI(true);
380 }
381 break;
382
383 case WM_CTLCOLORSTATIC:
384 *result = reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_WINDOW));
385 return true;
386
387 case WM_COMMAND:
388 if (button_ == reinterpret_cast<HWND>(lp)) {
389 if (BN_CLICKED == HIWORD(wp))
390 OnDefaultAction();
391 } else if (listbox_ == reinterpret_cast<HWND>(lp)) {
392 if (LBN_DBLCLK == HIWORD(wp)) {
393 OnDefaultAction();
394 }
395 }
396 return true;
397
398 case WM_CLOSE:
399 if (callback_)
400 callback_->Close();
401 break;
402 }
403 return false;
404}
405
406// static
407LRESULT CALLBACK MainWnd::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
Yves Gerey665174f2018-06-19 15:03:05 +0200408 MainWnd* me =
409 reinterpret_cast<MainWnd*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 if (!me && WM_CREATE == msg) {
411 CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lp);
412 me = reinterpret_cast<MainWnd*>(cs->lpCreateParams);
413 me->wnd_ = hwnd;
414 ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(me));
415 }
416
417 LRESULT result = 0;
418 if (me) {
419 void* prev_nested_msg = me->nested_msg_;
420 me->nested_msg_ = &msg;
421
422 bool handled = me->OnMessage(msg, wp, lp, &result);
423 if (WM_NCDESTROY == msg) {
424 me->destroyed_ = true;
425 } else if (!handled) {
426 result = ::DefWindowProc(hwnd, msg, wp, lp);
427 }
428
429 if (me->destroyed_ && prev_nested_msg == NULL) {
430 me->OnDestroyed();
431 me->wnd_ = NULL;
432 me->destroyed_ = false;
433 }
434
435 me->nested_msg_ = prev_nested_msg;
436 } else {
437 result = ::DefWindowProc(hwnd, msg, wp, lp);
438 }
439
440 return result;
441}
442
443// static
444bool MainWnd::RegisterWindowClass() {
445 if (wnd_class_)
446 return true;
447
Yves Gerey665174f2018-06-19 15:03:05 +0200448 WNDCLASSEX wcex = {sizeof(WNDCLASSEX)};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 wcex.style = CS_DBLCLKS;
450 wcex.hInstance = GetModuleHandle(NULL);
451 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
452 wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
453 wcex.lpfnWndProc = &WndProc;
454 wcex.lpszClassName = kClassName;
455 wnd_class_ = ::RegisterClassEx(&wcex);
nisseede5da42017-01-12 05:15:36 -0800456 RTC_DCHECK(wnd_class_ != 0);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 return wnd_class_ != 0;
458}
459
Yves Gerey665174f2018-06-19 15:03:05 +0200460void MainWnd::CreateChildWindow(HWND* wnd,
461 MainWnd::ChildWindowID id,
462 const wchar_t* class_name,
463 DWORD control_style,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 DWORD ex_style) {
465 if (::IsWindow(*wnd))
466 return;
467
468 // Child windows are invisible at first, and shown after being resized.
469 DWORD style = WS_CHILD | control_style;
Yves Gerey665174f2018-06-19 15:03:05 +0200470 *wnd = ::CreateWindowEx(ex_style, class_name, L"", style, 100, 100, 100, 100,
471 wnd_, reinterpret_cast<HMENU>(id),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 GetModuleHandle(NULL), NULL);
nisseede5da42017-01-12 05:15:36 -0800473 RTC_DCHECK(::IsWindow(*wnd) != FALSE);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 ::SendMessage(*wnd, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
475 TRUE);
476}
477
478void MainWnd::CreateChildWindows() {
479 // Create the child windows in tab order.
480 CreateChildWindow(&label1_, LABEL1_ID, L"Static", ES_CENTER | ES_READONLY, 0);
481 CreateChildWindow(&edit1_, EDIT_ID, L"Edit",
482 ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE);
483 CreateChildWindow(&label2_, LABEL2_ID, L"Static", ES_CENTER | ES_READONLY, 0);
484 CreateChildWindow(&edit2_, EDIT_ID, L"Edit",
485 ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE);
486 CreateChildWindow(&button_, BUTTON_ID, L"Button", BS_CENTER | WS_TABSTOP, 0);
487
488 CreateChildWindow(&listbox_, LISTBOX_ID, L"ListBox",
489 LBS_HASSTRINGS | LBS_NOTIFY, WS_EX_CLIENTEDGE);
490
kjellander@webrtc.org04025152014-07-01 16:28:13 +0000491 ::SetWindowTextA(edit1_, server_.c_str());
492 ::SetWindowTextA(edit2_, port_.c_str());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493}
494
495void MainWnd::LayoutConnectUI(bool show) {
496 struct Windows {
497 HWND wnd;
498 const wchar_t* text;
499 size_t width;
500 size_t height;
501 } windows[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200502 {label1_, L"Server"}, {edit1_, L"XXXyyyYYYgggXXXyyyYYYggg"},
503 {label2_, L":"}, {edit2_, L"XyXyX"},
504 {button_, L"Connect"},
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 };
506
507 if (show) {
508 const size_t kSeparator = 5;
509 size_t total_width = (ARRAYSIZE(windows) - 1) * kSeparator;
510
511 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
512 CalculateWindowSizeForText(windows[i].wnd, windows[i].text,
513 &windows[i].width, &windows[i].height);
514 total_width += windows[i].width;
515 }
516
517 RECT rc;
518 ::GetClientRect(wnd_, &rc);
519 size_t x = (rc.right / 2) - (total_width / 2);
520 size_t y = rc.bottom / 2;
521 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
522 size_t top = y - (windows[i].height / 2);
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000523 ::MoveWindow(windows[i].wnd, static_cast<int>(x), static_cast<int>(top),
524 static_cast<int>(windows[i].width),
Yves Gerey665174f2018-06-19 15:03:05 +0200525 static_cast<int>(windows[i].height), TRUE);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 x += kSeparator + windows[i].width;
527 if (windows[i].text[0] != 'X')
528 ::SetWindowText(windows[i].wnd, windows[i].text);
529 ::ShowWindow(windows[i].wnd, SW_SHOWNA);
530 }
531 } else {
532 for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
533 ::ShowWindow(windows[i].wnd, SW_HIDE);
534 }
535 }
536}
537
538void MainWnd::LayoutPeerListUI(bool show) {
539 if (show) {
540 RECT rc;
541 ::GetClientRect(wnd_, &rc);
542 ::MoveWindow(listbox_, 0, 0, rc.right, rc.bottom, TRUE);
543 ::ShowWindow(listbox_, SW_SHOWNA);
544 } else {
545 ::ShowWindow(listbox_, SW_HIDE);
546 InvalidateRect(wnd_, NULL, TRUE);
547 }
548}
549
550void MainWnd::HandleTabbing() {
551 bool shift = ((::GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
552 UINT next_cmd = shift ? GW_HWNDPREV : GW_HWNDNEXT;
553 UINT loop_around_cmd = shift ? GW_HWNDLAST : GW_HWNDFIRST;
554 HWND focus = GetFocus(), next;
555 do {
556 next = ::GetWindow(focus, next_cmd);
557 if (IsWindowVisible(next) &&
558 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) {
559 break;
560 }
561
562 if (!next) {
563 next = ::GetWindow(focus, loop_around_cmd);
564 if (IsWindowVisible(next) &&
565 (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) {
566 break;
567 }
568 }
569 focus = next;
570 } while (true);
571 ::SetFocus(next);
572}
573
574//
575// MainWnd::VideoRenderer
576//
577
578MainWnd::VideoRenderer::VideoRenderer(
Yves Gerey665174f2018-06-19 15:03:05 +0200579 HWND wnd,
580 int width,
581 int height,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 webrtc::VideoTrackInterface* track_to_render)
583 : wnd_(wnd), rendered_track_(track_to_render) {
584 ::InitializeCriticalSection(&buffer_lock_);
585 ZeroMemory(&bmi_, sizeof(bmi_));
586 bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
587 bmi_.bmiHeader.biPlanes = 1;
588 bmi_.bmiHeader.biBitCount = 32;
589 bmi_.bmiHeader.biCompression = BI_RGB;
590 bmi_.bmiHeader.biWidth = width;
591 bmi_.bmiHeader.biHeight = -height;
Yves Gerey665174f2018-06-19 15:03:05 +0200592 bmi_.bmiHeader.biSizeImage =
593 width * height * (bmi_.bmiHeader.biBitCount >> 3);
Niels Möller8f597622016-03-23 10:33:07 +0100594 rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595}
596
597MainWnd::VideoRenderer::~VideoRenderer() {
Niels Möller8f597622016-03-23 10:33:07 +0100598 rendered_track_->RemoveSink(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 ::DeleteCriticalSection(&buffer_lock_);
600}
601
602void MainWnd::VideoRenderer::SetSize(int width, int height) {
603 AutoLock<VideoRenderer> lock(this);
604
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000605 if (width == bmi_.bmiHeader.biWidth && height == bmi_.bmiHeader.biHeight) {
606 return;
607 }
608
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 bmi_.bmiHeader.biWidth = width;
610 bmi_.bmiHeader.biHeight = -height;
Yves Gerey665174f2018-06-19 15:03:05 +0200611 bmi_.bmiHeader.biSizeImage =
612 width * height * (bmi_.bmiHeader.biBitCount >> 3);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200613 image_.reset(new uint8_t[bmi_.bmiHeader.biSizeImage]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614}
615
Yves Gerey665174f2018-06-19 15:03:05 +0200616void MainWnd::VideoRenderer::OnFrame(const webrtc::VideoFrame& video_frame) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 {
618 AutoLock<VideoRenderer> lock(this);
619
magjed3f075492017-06-01 10:02:26 -0700620 rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
621 video_frame.video_frame_buffer()->ToI420());
nisseaf916892017-01-10 07:44:26 -0800622 if (video_frame.rotation() != webrtc::kVideoRotation_0) {
623 buffer = webrtc::I420Buffer::Rotate(*buffer, video_frame.rotation());
624 }
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000625
nisseacd935b2016-11-11 03:55:13 -0800626 SetSize(buffer->width(), buffer->height());
guoweis@webrtc.org00c509a2015-03-12 21:37:26 +0000627
nisseede5da42017-01-12 05:15:36 -0800628 RTC_DCHECK(image_.get() != NULL);
Yves Gerey665174f2018-06-19 15:03:05 +0200629 libyuv::I420ToARGB(buffer->DataY(), buffer->StrideY(), buffer->DataU(),
630 buffer->StrideU(), buffer->DataV(), buffer->StrideV(),
nisse9f8e37b2016-09-01 01:06:23 -0700631 image_.get(),
Yves Gerey665174f2018-06-19 15:03:05 +0200632 bmi_.bmiHeader.biWidth * bmi_.bmiHeader.biBitCount / 8,
nisse9f8e37b2016-09-01 01:06:23 -0700633 buffer->width(), buffer->height());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 }
635 InvalidateRect(wnd_, NULL, TRUE);
636}