diff --git a/webrtc/video_engine/test/common/run_loop.cc b/webrtc/video_engine/test/common/run_loop.cc new file mode 100644 index 000000000..730071d4c --- /dev/null +++ b/webrtc/video_engine/test/common/run_loop.cc @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "webrtc/video_engine/test/common/run_loop.h" + +#include + +namespace webrtc { +namespace test { + +void PressEnterToContinue() { + puts(">> Press ENTER to continue..."); + while (getchar() != '\n' && !feof(stdin)); +} +} // namespace test +} // namespace webrtc diff --git a/webrtc/video_engine/test/common/run_loop.h b/webrtc/video_engine/test/common/run_loop.h new file mode 100644 index 000000000..31012525e --- /dev/null +++ b/webrtc/video_engine/test/common/run_loop.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_RUN_LOOP_H_ +#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_RUN_LOOP_H_ + +namespace webrtc { +namespace test { + +// Blocks until the user presses enter. +void PressEnterToContinue(); + +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_RUN_LOOP_H_ diff --git a/webrtc/video_engine/test/common/run_tests.cc b/webrtc/video_engine/test/common/run_tests.cc index 607a1e58f..4692ba615 100644 --- a/webrtc/video_engine/test/common/run_tests.cc +++ b/webrtc/video_engine/test/common/run_tests.cc @@ -7,7 +7,6 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - #include "testing/gtest/include/gtest/gtest.h" namespace webrtc { diff --git a/webrtc/video_engine/test/common/run_tests.h b/webrtc/video_engine/test/common/run_tests.h index e7a685adf..3f42866fa 100644 --- a/webrtc/video_engine/test/common/run_tests.h +++ b/webrtc/video_engine/test/common/run_tests.h @@ -7,17 +7,18 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - #ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_TEST_RUNNER_H_ #define WEBRTC_VIDEO_ENGINE_TEST_COMMON_TEST_RUNNER_H_ namespace webrtc { namespace test { +// Blocks until the user presses enter. +void PressEnterToContinue(); + // Performs platform-dependent initializations and calls gtest's // RUN_ALL_TESTS(). - int RunAllTests(); - +int RunAllTests(); } // namespace test } // namespace webrtc diff --git a/webrtc/video_engine/test/common/video_renderer.cc b/webrtc/video_engine/test/common/video_renderer.cc index 62ede3946..84aab894c 100644 --- a/webrtc/video_engine/test/common/video_renderer.cc +++ b/webrtc/video_engine/test/common/video_renderer.cc @@ -7,10 +7,8 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - #include "webrtc/video_engine/test/common/video_renderer.h" -// TODO(pbos): Windows renderer // TODO(pbos): Android renderer #include "webrtc/typedefs.h" @@ -23,14 +21,16 @@ class NullRenderer : public VideoRenderer { int time_to_render_ms) OVERRIDE {} }; -VideoRenderer* VideoRenderer::Create(const char* window_title, size_t width, +VideoRenderer* VideoRenderer::Create(const char* window_title, + size_t width, size_t height) { VideoRenderer* renderer = CreatePlatformRenderer(window_title, width, height); if (renderer != NULL) { // TODO(mflodman) Add a warning log. return renderer; } + return new NullRenderer(); } -} // test -} // webrtc +} // namespace test +} // namespace webrtc diff --git a/webrtc/video_engine/test/common/video_renderer.h b/webrtc/video_engine/test/common/video_renderer.h index 2d441034e..ac94522cc 100644 --- a/webrtc/video_engine/test/common/video_renderer.h +++ b/webrtc/video_engine/test/common/video_renderer.h @@ -34,7 +34,7 @@ class VideoRenderer : public newapi::VideoRenderer { protected: VideoRenderer() {} }; -} // test -} // webrtc +} // namespace test +} // namespace webrtc #endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_ diff --git a/webrtc/video_engine/test/common/win/d3d_renderer.cc b/webrtc/video_engine/test/common/win/d3d_renderer.cc new file mode 100644 index 000000000..2f9b29f4a --- /dev/null +++ b/webrtc/video_engine/test/common/win/d3d_renderer.cc @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "webrtc/video_engine/test/common/win/d3d_renderer.h" + +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" + +namespace webrtc { +namespace test { + +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1) + +struct D3dCustomVertex { + float x, y, z; + float u, v; +}; + +const char kD3DClassName[] = "d3d_renderer"; + +VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title, + size_t width, + size_t height) { + return D3dRenderer::Create(window_title, width, height); +} + +D3dRenderer::D3dRenderer(size_t width, size_t height) + : width_(width), + height_(height), + hwnd_(NULL), + d3d_(NULL), + d3d_device_(NULL), + texture_(NULL), + vertex_buffer_(NULL) { + assert(width > 0); + assert(height > 0); +} + +D3dRenderer::~D3dRenderer() { Destroy(); } + +LRESULT WINAPI D3dRenderer::WindowProc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam) { + if (msg == WM_DESTROY || (msg == WM_CHAR && wparam == VK_RETURN)) { + PostQuitMessage(0); + return 0; + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +void D3dRenderer::Destroy() { + texture_ = NULL; + vertex_buffer_ = NULL; + d3d_device_ = NULL; + d3d_ = NULL; + + if (hwnd_ != NULL) { + DestroyWindow(hwnd_); + assert(!IsWindow(hwnd_)); + hwnd_ = NULL; + } +} + +bool D3dRenderer::Init(const char* window_title) { + hwnd_ = CreateWindowA(kD3DClassName, + window_title, + WS_OVERLAPPEDWINDOW, + 0, + 0, + static_cast(width_), + static_cast(height_), + NULL, + NULL, + NULL, + NULL); + + if (hwnd_ == NULL) { + Destroy(); + return false; + } + + d3d_ = Direct3DCreate9(D3D_SDK_VERSION); + if (d3d_ == NULL) { + Destroy(); + return false; + } + + D3DPRESENT_PARAMETERS d3d_params = {}; + + d3d_params.Windowed = TRUE; + d3d_params.SwapEffect = D3DSWAPEFFECT_COPY; + + IDirect3DDevice9* d3d_device; + if (d3d_->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hwnd_, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3d_params, + &d3d_device) != D3D_OK) { + Destroy(); + return false; + } + d3d_device_ = d3d_device; + d3d_device->Release(); + + IDirect3DVertexBuffer9* vertex_buffer; + const int kRectVertices = 4; + if (d3d_device_->CreateVertexBuffer(kRectVertices * sizeof(D3dCustomVertex), + 0, + D3DFVF_CUSTOMVERTEX, + D3DPOOL_MANAGED, + &vertex_buffer, + NULL) != D3D_OK) { + Destroy(); + return false; + } + vertex_buffer_ = vertex_buffer; + vertex_buffer->Release(); + + d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE); + Resize(width_, height_); + + ShowWindow(hwnd_, SW_SHOWNOACTIVATE); + d3d_device_->Present(NULL, NULL, NULL, NULL); + + return true; +} + +D3dRenderer* D3dRenderer::Create(const char* window_title, + size_t width, + size_t height) { + static ATOM wc_atom = 0; + if (wc_atom == 0) { + WNDCLASSA wc = {}; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WindowProc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = reinterpret_cast(COLOR_WINDOW); + wc.lpszClassName = kD3DClassName; + + wc_atom = RegisterClassA(&wc); + if (wc_atom == 0) + return false; + } + + D3dRenderer* d3d_renderer = new D3dRenderer(width, height); + if (!d3d_renderer->Init(window_title)) { + delete d3d_renderer; + return NULL; + } + + return d3d_renderer; +} + +void D3dRenderer::Resize(size_t width, size_t height) { + width_ = width; + height_ = height; + IDirect3DTexture9* texture; + + d3d_device_->CreateTexture(static_cast(width_), + static_cast(height_), + 1, + 0, + D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &texture, + NULL); + texture_ = texture; + texture->Release(); + + // Vertices for the video frame to be rendered to. + static const D3dCustomVertex rect[] = { + {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f}, + {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f}, + {1.0f, -1.0f, 0.0f, 1.0f, 1.0f}, + {1.0f, 1.0f, 0.0f, 1.0f, 0.0f}, + }; + + void* buf_data; + if (vertex_buffer_->Lock(0, 0, &buf_data, 0) != D3D_OK) + return; + + memcpy(buf_data, &rect, sizeof(rect)); + vertex_buffer_->Unlock(); +} + +void D3dRenderer::RenderFrame(const webrtc::I420VideoFrame& frame, + int /*render_delay_ms*/) { + if (static_cast(frame.width()) != width_ || + static_cast(frame.height()) != height_) { + Resize(static_cast(frame.width()), + static_cast(frame.height())); + } + + D3DLOCKED_RECT lock_rect; + if (texture_->LockRect(0, &lock_rect, NULL, 0) != D3D_OK) + return; + + ConvertFromI420(frame, kARGB, 0, static_cast(lock_rect.pBits)); + texture_->UnlockRect(0); + + d3d_device_->BeginScene(); + d3d_device_->SetFVF(D3DFVF_CUSTOMVERTEX); + d3d_device_->SetStreamSource(0, vertex_buffer_, 0, sizeof(D3dCustomVertex)); + d3d_device_->SetTexture(0, texture_); + d3d_device_->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); + d3d_device_->EndScene(); + + d3d_device_->Present(NULL, NULL, NULL, NULL); +} +} // namespace test +} // namespace webrtc diff --git a/webrtc/video_engine/test/common/win/d3d_renderer.h b/webrtc/video_engine/test/common/win/d3d_renderer.h new file mode 100644 index 000000000..38efa4628 --- /dev/null +++ b/webrtc/video_engine/test/common/win/d3d_renderer.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_WIN_D3D_RENDERER_H_ +#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_WIN_D3D_RENDERER_H_ + +#include +#include + +#include "webrtc/system_wrappers/interface/scoped_refptr.h" +#include "webrtc/typedefs.h" +#include "webrtc/video_engine/test/common/video_renderer.h" + +namespace webrtc { +namespace test { + +class D3dRenderer : public VideoRenderer { + public: + static D3dRenderer* Create(const char* window_title, size_t width, + size_t height); + virtual ~D3dRenderer(); + + virtual void RenderFrame(const webrtc::I420VideoFrame& frame, int delta) + OVERRIDE; + private: + D3dRenderer(size_t width, size_t height); + + static LRESULT WINAPI WindowProc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam); + bool Init(const char* window_title); + void Resize(size_t width, size_t height); + void Destroy(); + + size_t width_, height_; + + HWND hwnd_; + scoped_refptr d3d_; + scoped_refptr d3d_device_; + + scoped_refptr texture_; + scoped_refptr vertex_buffer_; +}; +} // namespace test +} // namespace webrtc + +#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_WIN_D3D_RENDERER_H_ diff --git a/webrtc/video_engine/test/common/win/run_loop_win.cc b/webrtc/video_engine/test/common/win/run_loop_win.cc new file mode 100644 index 000000000..c62eeb131 --- /dev/null +++ b/webrtc/video_engine/test/common/win/run_loop_win.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "webrtc/video_engine/test/common/run_loop.h" + +#include + +#include +#include +#include + +namespace webrtc { +namespace test { + +void PressEnterToContinue() { + puts(">> Press ENTER to continue..."); + + MSG msg; + BOOL ret; + while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) { + assert(ret != -1); + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} +} // namespace test +} // namespace webrtc diff --git a/webrtc/video_engine/test/loopback.cc b/webrtc/video_engine/test/loopback.cc index 86d6d5767..5040799e8 100644 --- a/webrtc/video_engine/test/loopback.cc +++ b/webrtc/video_engine/test/loopback.cc @@ -20,6 +20,8 @@ #include "webrtc/video_engine/test/common/direct_transport.h" #include "webrtc/video_engine/test/common/flags.h" #include "webrtc/video_engine/test/common/generate_ssrcs.h" +#include "webrtc/video_engine/test/common/run_loop.h" +#include "webrtc/video_engine/test/common/run_tests.h" #include "webrtc/video_engine/test/common/video_capturer.h" #include "webrtc/video_engine/test/common/video_renderer.h" @@ -82,13 +84,9 @@ TEST_F(LoopbackTest, Test) { receive_stream->StartReceive(); send_stream->StartSend(); - camera->Start(); - // TODO(pbos): Run this time limited (optionally), so it can run automated. - puts(">> Press ENTER to continue..."); - while (getchar() != '\n' && !feof(stdin)) - ; + test::PressEnterToContinue(); camera->Stop(); send_stream->StopSend(); diff --git a/webrtc/video_engine/test/tests.gypi b/webrtc/video_engine/test/tests.gypi index 40a500441..250938ded 100644 --- a/webrtc/video_engine/test/tests.gypi +++ b/webrtc/video_engine/test/tests.gypi @@ -32,6 +32,8 @@ 'common/null_platform_renderer.cc', 'common/run_tests.cc', 'common/run_tests.h', + 'common/run_loop.cc', + 'common/run_loop.h', 'common/statistics.cc', 'common/statistics.h', 'common/vcm_capturer.cc', @@ -40,6 +42,9 @@ 'common/video_capturer.h', 'common/video_renderer.cc', 'common/video_renderer.h', + 'common/win/d3d_renderer.cc', + 'common/win/d3d_renderer.h', + 'common/win/run_loop_win.cc', ], 'conditions': [ ['OS=="linux"', { @@ -59,6 +64,12 @@ 'common/gl/gl_renderer.h', ], }], + ['OS=="win"', { + 'sources!': [ + 'common/null_platform_renderer.cc', + 'common/run_loop.cc', + ], + }], ], 'direct_dependent_settings': { 'conditions': [