Switch the sample client back to render the videos in the main window

instead of two popup windows.  This also demonstrates one way of
implementing the VideoRenderer interface.
Review URL: http://webrtc-codereview.appspot.com/51004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@143 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
tommi@google.com 2011-07-04 12:47:37 +00:00
parent cdc943e2d5
commit 53af7595d1
4 changed files with 193 additions and 21 deletions

View File

@ -71,8 +71,6 @@ bool Conductor::InitializePeerConnection() {
void Conductor::DeletePeerConnection() {
peer_connection_.reset();
local_renderer_.reset();
remote_renderer_.reset();
handshake_ = NONE;
}
@ -82,14 +80,7 @@ void Conductor::StartCaptureDevice() {
main_wnd_->SwitchToStreamingUI();
if (peer_connection_->SetVideoCapture("")) {
if (!local_renderer_.get()) {
// The window will be resized according to the stream properties
// when streaming starts.
local_renderer_.reset(
cricket::VideoRendererFactory::CreateGuiVideoRenderer(100, 100));
}
if (local_renderer_.get())
peer_connection_->SetLocalVideoRenderer(local_renderer_.get());
peer_connection_->SetLocalVideoRenderer(main_wnd_->local_renderer());
} else {
ASSERT(false);
}
@ -139,13 +130,8 @@ void Conductor::OnAddStream(const std::string& stream_id, int channel_id,
video_channel_ = channel_id;
waiting_for_video_ = false;
LOG(INFO) << "Setting video renderer for channel: " << channel_id;
if (!remote_renderer_.get()) {
// The window size will be automatically corrected.
remote_renderer_.reset(
cricket::VideoRendererFactory::CreateGuiVideoRenderer(100, 100));
}
bool ok = peer_connection_->SetVideoRenderer(stream_id,
remote_renderer_.get());
main_wnd_->remote_renderer());
ASSERT(ok);
} else {
ASSERT(audio_channel_ == -1);

View File

@ -115,8 +115,6 @@ class Conductor
MainWnd* main_wnd_;
int video_channel_;
int audio_channel_;
talk_base::scoped_ptr<cricket::VideoRenderer> local_renderer_;
talk_base::scoped_ptr<cricket::VideoRenderer> remote_renderer_;
};
#endif // PEERCONNECTION_SAMPLES_CLIENT_CONDUCTOR_H_

View File

@ -10,6 +10,8 @@
#include "peerconnection/samples/client/main_wnd.h"
#include <math.h>
#include "talk/base/common.h"
#include "talk/base/logging.h"
@ -145,6 +147,7 @@ void MainWnd::SwitchToPeerList(const Peers& peers) {
ui_ = LIST_PEERS;
LayoutPeerListUI(true);
::SetFocus(listbox_);
}
void MainWnd::SwitchToStreamingUI() {
@ -159,9 +162,64 @@ void MainWnd::OnPaint() {
RECT rc;
::GetClientRect(handle(), &rc);
HBRUSH brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
::FillRect(ps.hdc, &rc, brush);
::DeleteObject(brush);
if (ui_ == STREAMING && remote_video_.get() && local_video_.get()) {
const BITMAPINFO& bmi = remote_video_->bmi();
long height = abs(bmi.bmiHeader.biHeight);
long width = bmi.bmiHeader.biWidth;
HDC dc_mem = ::CreateCompatibleDC(ps.hdc);
// Set the map mode so that the ratio will be maintained for us.
HDC all_dc[] = { ps.hdc, dc_mem };
for (int i = 0; i < ARRAY_SIZE(all_dc); ++i) {
SetMapMode(all_dc[i], MM_ISOTROPIC);
SetWindowExtEx(all_dc[i], width, height, NULL);
SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL);
}
HBITMAP bmp_mem = ::CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom);
HGDIOBJ bmp_old = ::SelectObject(dc_mem, bmp_mem);
HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0));
::FillRect(dc_mem, &rc, brush);
::DeleteObject(brush);
POINT logical_area = { rc.right, rc.bottom };
DPtoLP(ps.hdc, &logical_area, 1);
const uint8* image = remote_video_->image();
int max_unit = std::max(width, height);
int x = (logical_area.x / 2) - (width / 2);
int y = (logical_area.y / 2) - (height / 2);
StretchDIBits(dc_mem, x, y, width, height,
0, 0, width, height, image, &bmi, DIB_RGB_COLORS, SRCCOPY);
if ((rc.right - rc.left) > 200 && (rc.bottom - rc.top) > 200) {
const BITMAPINFO& bmi = local_video_->bmi();
image = local_video_->image();
long thumb_width = bmi.bmiHeader.biWidth / 4;
long thumb_height = abs(bmi.bmiHeader.biHeight) / 4;
StretchDIBits(dc_mem,
logical_area.x - thumb_width - 10,
logical_area.y - thumb_height - 10,
thumb_width, thumb_height,
0, 0, bmi.bmiHeader.biWidth, -bmi.bmiHeader.biHeight,
image, &bmi, DIB_RGB_COLORS, SRCCOPY);
}
BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y,
dc_mem, 0, 0, SRCCOPY);
// Cleanup.
::SelectObject(dc_mem, bmp_old);
::DeleteObject(bmp_mem);
::DeleteDC(dc_mem);
} else {
HBRUSH brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
::FillRect(ps.hdc, &rc, brush);
::DeleteObject(brush);
}
::EndPaint(handle(), &ps);
}
@ -193,6 +251,11 @@ void MainWnd::OnDefaultAction() {
bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) {
switch (msg) {
case WM_CREATE:
remote_video_.reset(new VideoRenderer(handle(), 1, 1));
local_video_.reset(new VideoRenderer(handle(), 1, 1));
break;
case WM_ERASEBKGND:
*result = TRUE;
return true;
@ -202,6 +265,8 @@ bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) {
case WM_SETFOCUS:
if (ui_ == CONNECT_TO_SERVER) {
SetFocus(edit1_);
} else if (ui_ == LIST_PEERS) {
SetFocus(listbox_);
}
return true;
case WM_SIZE:
@ -224,6 +289,12 @@ bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) {
}
}
return true;
case VIDEO_RENDERER_MESSAGE: {
VideoRenderer* renderer = reinterpret_cast<VideoRenderer*>(lp);
const MSG* msg_ptr = reinterpret_cast<const MSG*>(wp);
renderer->OnMessage(*msg_ptr);
return true;
}
}
return false;
}
@ -394,3 +465,78 @@ void MainWnd::HandleTabbing() {
} while (true);
::SetFocus(next);
}
//
// MainWnd::VideoRenderer
//
MainWnd::VideoRenderer::VideoRenderer(HWND wnd, int width, int height)
: wnd_(wnd) {
ZeroMemory(&bmi_, sizeof(bmi_));
bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi_.bmiHeader.biPlanes = 1;
bmi_.bmiHeader.biBitCount = 32;
bmi_.bmiHeader.biCompression = BI_RGB;
bmi_.bmiHeader.biWidth = width;
bmi_.bmiHeader.biHeight = -height;
bmi_.bmiHeader.biSizeImage = width * height *
(bmi_.bmiHeader.biBitCount >> 3);
image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
}
MainWnd::VideoRenderer::~VideoRenderer() {
}
bool MainWnd::VideoRenderer::SetSize(int width, int height, int reserved) {
if (width != bmi_.bmiHeader.biWidth ||
height != -bmi_.bmiHeader.biHeight) {
// Update the bitmap info and image buffer.
// To avoid touching buffers from different threads, we always
// marshal messages through the main window's thread.
MSG msg = {0};
msg.message = WM_SIZE;
msg.lParam = width;
msg.wParam = height;
::SendMessage(wnd_, VIDEO_RENDERER_MESSAGE,
reinterpret_cast<WPARAM>(&msg),
reinterpret_cast<LPARAM>(this));
}
return true;
}
bool MainWnd::VideoRenderer::RenderFrame(const cricket::VideoFrame* frame) {
if (!frame)
return false;
MSG msg = {0};
msg.message = WM_PAINT;
msg.lParam = reinterpret_cast<LPARAM>(frame);
::SendMessage(wnd_, VIDEO_RENDERER_MESSAGE,
reinterpret_cast<WPARAM>(&msg),
reinterpret_cast<LPARAM>(this));
return true;
}
void MainWnd::VideoRenderer::OnMessage(const MSG& msg) {
switch (msg.message) {
case WM_SIZE:
bmi_.bmiHeader.biWidth = static_cast<int>(msg.lParam);
bmi_.bmiHeader.biHeight = -static_cast<int>(msg.wParam);
bmi_.bmiHeader.biSizeImage = bmi_.bmiHeader.biWidth *
static_cast<int>(msg.wParam) *
(bmi_.bmiHeader.biBitCount >> 3);
image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
break;
case WM_PAINT: {
const cricket::VideoFrame* frame =
reinterpret_cast<const cricket::VideoFrame*>(msg.lParam);
frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, image_.get(),
bmi_.bmiHeader.biSizeImage,
bmi_.bmiHeader.biWidth *
(bmi_.bmiHeader.biBitCount >> 3));
InvalidateRect(wnd_, 0, 0);
break;
}
}
}

View File

@ -17,6 +17,8 @@
#include "peerconnection/samples/client/peer_connection_client.h"
#include "talk/base/win32.h"
#include "talk/session/phone/mediachannel.h"
#include "talk/session/phone/videocommon.h"
class MainWndCallback {
public:
@ -38,6 +40,10 @@ class MainWnd {
STREAMING,
};
enum WindowMessages {
VIDEO_RENDERER_MESSAGE = WM_APP + 1,
};
MainWnd();
~MainWnd();
@ -56,6 +62,40 @@ class MainWnd {
HWND handle() const { return wnd_; }
UI current_ui() const { return ui_; }
cricket::VideoRenderer* local_renderer() const {
return local_video_.get();
}
cricket::VideoRenderer* remote_renderer() const {
return remote_video_.get();
}
class VideoRenderer : public cricket::VideoRenderer {
public:
VideoRenderer(HWND wnd, int width, int height);
virtual ~VideoRenderer();
virtual bool SetSize(int width, int height, int reserved);
// Called when a new frame is available for display.
virtual bool RenderFrame(const cricket::VideoFrame* frame);
void OnMessage(const MSG& msg);
const BITMAPINFO& bmi() const { return bmi_; }
const uint8* image() const { return image_.get(); }
protected:
enum {
SET_SIZE,
RENDER_FRAME,
};
HWND wnd_;
BITMAPINFO bmi_;
talk_base::scoped_array<uint8> image_;
};
protected:
enum ChildWindowID {
EDIT_ID = 1,
@ -85,6 +125,8 @@ class MainWnd {
void HandleTabbing();
private:
talk_base::scoped_ptr<VideoRenderer> remote_video_;
talk_base::scoped_ptr<VideoRenderer> local_video_;
UI ui_;
HWND wnd_;
HWND edit1_;