10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// libjingle
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Copyright 2004 Google Inc.
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Redistribution and use in source and binary forms, with or without
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// modification, are permitted provided that the following conditions are met:
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  1. Redistributions of source code must retain the above copyright notice,
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     this list of conditions and the following disclaimer.
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  2. Redistributions in binary form must reproduce the above copyright notice,
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     this list of conditions and the following disclaimer in the documentation
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     and/or other materials provided with the distribution.
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  3. The name of the author may not be used to endorse or promote products
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     derived from this software without specific prior written permission.
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of GdiVideoRenderer on Windows
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef WIN32
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/devices/gdivideorenderer.h"
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
32cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "talk/media/base/videocommon.h"
33cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "talk/media/base/videoframe.h"
342a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/scoped_ptr.h"
352a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/thread.h"
362a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/win32window.h"
370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket {
390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Definition of private class VideoWindow. We use a worker thread to manage
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// the window.
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
442a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgclass GdiVideoRenderer::VideoWindow : public rtc::Win32Window {
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org public:
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  VideoWindow(int x, int y, int width, int height);
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  virtual ~VideoWindow();
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Called when the video size changes. If it is called the first time, we
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // create and start the thread. Otherwise, we send kSetSizeMsg to the thread.
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Context: non-worker thread.
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool SetSize(int width, int height);
530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Called when a new frame is available. Upon this call, we send
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // kRenderFrameMsg to the window thread. Context: non-worker thread. It may be
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // better to pass RGB bytes to VideoWindow. However, we pass VideoFrame to put
570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // all the thread synchronization within VideoWindow.
580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool RenderFrame(const VideoFrame* frame);
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org protected:
612a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  // Override virtual method of rtc::Win32Window. Context: worker Thread.
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                         LRESULT& result);
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org private:
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  enum { kSetSizeMsg = WM_USER, kRenderFrameMsg};
670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
682a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  class WindowThread : public rtc::Thread {
690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org   public:
700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    explicit WindowThread(VideoWindow* window) : window_(window) {}
710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
72e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org    virtual ~WindowThread() {
73e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org      Stop();
74e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org    }
75e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org
762a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    // Override virtual method of rtc::Thread. Context: worker Thread.
770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    virtual void Run() {
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Initialize the window
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (!window_ || !window_->Initialize()) {
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return;
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Run the message loop
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      MSG msg;
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      while (GetMessage(&msg, NULL, 0, 0) > 0) {
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        TranslateMessage(&msg);
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        DispatchMessage(&msg);
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  private:
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VideoWindow* window_;
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  };
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Context: worker Thread.
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool Initialize();
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  void OnPaint();
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  void OnSize(int width, int height, bool frame_changed);
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  void OnRenderFrame(const VideoFrame* frame);
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  BITMAPINFO bmi_;
1012a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::scoped_ptr<uint8[]> image_;
1022a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::scoped_ptr<WindowThread> window_thread_;
1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // The initial position of the window.
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int initial_x_;
1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int initial_y_;
1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of class VideoWindow
1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgGdiVideoRenderer::VideoWindow::VideoWindow(
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int x, int y, int width, int height)
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : initial_x_(x),
1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      initial_y_(y) {
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  memset(&bmi_.bmiHeader, 0, sizeof(bmi_.bmiHeader));
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biPlanes = 1;
1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biBitCount = 32;
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biCompression = BI_RGB;
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biWidth = width;
1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biHeight = -height;
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bmi_.bmiHeader.biSizeImage = width * height * 4;
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgGdiVideoRenderer::VideoWindow::~VideoWindow() {
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Context: caller Thread. We cannot call Destroy() since the window was
1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // created by another thread. Instead, we send WM_CLOSE message.
1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (handle()) {
1310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SendMessage(handle(), WM_CLOSE, 0, 0);
1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::VideoWindow::SetSize(int width, int height) {
1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!window_thread_.get()) {
1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Create and start the window thread.
1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    window_thread_.reset(new WindowThread(this));
1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return window_thread_->Start();
1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (width != bmi_.bmiHeader.biWidth ||
1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      height != -bmi_.bmiHeader.biHeight) {
1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SendMessage(handle(), kSetSizeMsg, 0, MAKELPARAM(width, height));
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::VideoWindow::RenderFrame(const VideoFrame* frame) {
1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!handle()) {
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SendMessage(handle(), kRenderFrameMsg, reinterpret_cast<WPARAM>(frame), 0);
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::VideoWindow::OnMessage(UINT uMsg, WPARAM wParam,
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                              LPARAM lParam, LRESULT& result) {
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (uMsg) {
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case WM_PAINT:
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      OnPaint();
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case WM_DESTROY:
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      PostQuitMessage(0);  // post WM_QUIT to end the message loop in Run()
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case WM_SIZE:  // The window UI was resized.
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      OnSize(LOWORD(lParam), HIWORD(lParam), false);
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case kSetSizeMsg:  // The video resolution changed.
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      OnSize(LOWORD(lParam), HIWORD(lParam), true);
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case kRenderFrameMsg:
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      OnRenderFrame(reinterpret_cast<const VideoFrame*>(wParam));
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::VideoWindow::Initialize() {
1832a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  if (!rtc::Win32Window::Create(
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      NULL, L"Video Renderer",
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      WS_EX_APPWINDOW,
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      initial_x_, initial_y_,
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight)) {
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return false;
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  OnSize(bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight, false);
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid GdiVideoRenderer::VideoWindow::OnPaint() {
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  RECT rcClient;
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  GetClientRect(handle(), &rcClient);
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  PAINTSTRUCT ps;
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  HDC hdc = BeginPaint(handle(), &ps);
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  StretchDIBits(hdc,
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    0, 0, rcClient.right, rcClient.bottom,  // destination rect
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    0, 0, bmi_.bmiHeader.biWidth, -bmi_.bmiHeader.biHeight,  // source rect
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    image_.get(), &bmi_, DIB_RGB_COLORS, SRCCOPY);
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  EndPaint(handle(), &ps);
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid GdiVideoRenderer::VideoWindow::OnSize(int width, int height,
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                           bool frame_changed) {
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Get window and client sizes
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  RECT rcClient, rcWindow;
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  GetClientRect(handle(), &rcClient);
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  GetWindowRect(handle(), &rcWindow);
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find offset between window size and client size
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  POINT ptDiff;
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
2170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Resize client
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  MoveWindow(handle(), rcWindow.left, rcWindow.top,
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org             width + ptDiff.x, height + ptDiff.y, false);
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  UpdateWindow(handle());
2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ShowWindow(handle(), SW_SHOW);
2240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (frame_changed && (width != bmi_.bmiHeader.biWidth ||
2260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    height != -bmi_.bmiHeader.biHeight)) {
2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Update the bmi and image buffer
2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bmi_.bmiHeader.biWidth = width;
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bmi_.bmiHeader.biHeight = -height;
2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bmi_.bmiHeader.biSizeImage = width * height * 4;
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    image_.reset(new uint8[bmi_.bmiHeader.biSizeImage]);
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid GdiVideoRenderer::VideoWindow::OnRenderFrame(const VideoFrame* frame) {
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!frame) {
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Convert frame to ARGB format, which is accepted by GDI
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  frame->ConvertToRgbBuffer(cricket::FOURCC_ARGB, image_.get(),
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                            bmi_.bmiHeader.biSizeImage,
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                            bmi_.bmiHeader.biWidth * 4);
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  InvalidateRect(handle(), 0, 0);
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of class GdiVideoRenderer
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgGdiVideoRenderer::GdiVideoRenderer(int x, int y)
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : initial_x_(x),
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      initial_y_(y) {
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgGdiVideoRenderer::~GdiVideoRenderer() {}
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::SetSize(int width, int height, int reserved) {
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!window_.get()) {  // Create the window for the first frame
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    window_.reset(new VideoWindow(initial_x_, initial_y_, width, height));
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return window_->SetSize(width, height);
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool GdiVideoRenderer::RenderFrame(const VideoFrame* frame) {
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!frame || !window_.get()) {
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return window_->RenderFrame(frame);
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace cricket
2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // WIN32
271