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:
parent
cdc943e2d5
commit
53af7595d1
@ -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);
|
||||
|
@ -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_
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user