New VideoEngine API implementation on top of old one, first steps.
BUG=1668
R=mflodman@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/1360004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4044 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/video_engine/test/common/direct_transport.h b/video_engine/test/common/direct_transport.h
new file mode 100644
index 0000000..69de83e
--- /dev/null
+++ b/video_engine/test/common/direct_transport.h
@@ -0,0 +1,39 @@
+/*
+ * 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_DIRECT_TRANSPORT_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_
+
+#include "webrtc/video_engine/new_include/common.h"
+
+namespace webrtc {
+namespace test {
+
+class DirectTransport : public newapi::Transport {
+ public:
+ explicit DirectTransport(newapi::PacketReceiver* receiver)
+ : receiver_(receiver) {}
+
+ void SetReceiver(newapi::PacketReceiver* receiver) { receiver_ = receiver; }
+
+ bool SendRTP(const void* data, size_t length) OVERRIDE {
+ return receiver_->DeliverPacket(data, length);
+ }
+
+ bool SendRTCP(const void* data, size_t length) OVERRIDE {
+ return SendRTP(data, length);
+ }
+
+ private:
+ newapi::PacketReceiver* receiver_;
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_
diff --git a/video_engine/test/common/generate_ssrcs.h b/video_engine/test/common/generate_ssrcs.h
new file mode 100644
index 0000000..db6c660
--- /dev/null
+++ b/video_engine/test/common/generate_ssrcs.h
@@ -0,0 +1,51 @@
+/*
+ * 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_GENERATE_SSRCS_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_GENERATE_SSRCS_H_
+
+#include <map>
+#include <vector>
+
+#include "webrtc/video_engine/new_include/video_send_stream.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+namespace test {
+
+void GenerateRandomSsrcs(newapi::VideoSendStreamConfig* config,
+ std::map<uint32_t, bool>* reserved_ssrcs) {
+ size_t num_ssrcs = config->codec.numberOfSimulcastStreams;
+ std::vector<uint32_t>* ssrcs = &config->rtp.ssrcs;
+ assert(ssrcs->size() == 0);
+
+ if (num_ssrcs == 0) {
+ num_ssrcs = 1;
+ }
+
+ while (ssrcs->size() < num_ssrcs) {
+ uint32_t rand_ssrc = static_cast<uint32_t>(rand() + 1); // NOLINT
+
+ // Make sure the ssrc is unique per-call
+ while (true) {
+ if (!(*reserved_ssrcs)[rand_ssrc]) {
+ (*reserved_ssrcs)[rand_ssrc] = true;
+ break;
+ }
+ ++rand_ssrc;
+ }
+
+ ssrcs->push_back(rand_ssrc);
+ }
+}
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_GENERATE_SSRCS_H_
diff --git a/video_engine/test/common/gl/gl_renderer.cc b/video_engine/test/common/gl/gl_renderer.cc
new file mode 100644
index 0000000..3345fac
--- /dev/null
+++ b/video_engine/test/common/gl/gl_renderer.cc
@@ -0,0 +1,112 @@
+/*
+ * 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/gl/gl_renderer.h"
+
+#include <cstring>
+
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+
+namespace webrtc {
+namespace test {
+
+GlRenderer::GlRenderer()
+ : is_init_(false), buffer_(NULL), width_(0), height_(0) {}
+
+void GlRenderer::Init() {
+ assert(!is_init_);
+ is_init_ = true;
+
+ glGenTextures(1, &texture_);
+}
+
+void GlRenderer::Destroy() {
+ if (!is_init_) {
+ return;
+ }
+
+ is_init_ = false;
+
+ delete[] buffer_;
+ buffer_ = NULL;
+
+ glDeleteTextures(1, &texture_);
+}
+
+void GlRenderer::ResizeViewport(size_t width, size_t height) {
+ // TODO(pbos): Aspect ratio, letterbox the video.
+ glViewport(0, 0, width, height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glOrtho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+void GlRenderer::ResizeVideo(size_t width, size_t height) {
+ assert(is_init_);
+ width_ = width;
+ height_ = height;
+
+ buffer_size_ = width * height * 4; // BGRA
+
+ delete[] buffer_;
+ buffer_ = new uint8_t[buffer_size_];
+ assert(buffer_ != NULL);
+ memset(buffer_, 0, buffer_size_);
+ glBindTexture(GL_TEXTURE_2D, texture_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8, static_cast<GLvoid*>(buffer_));
+}
+
+void GlRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
+ int /*render_delay_ms*/) {
+ assert(is_init_);
+
+ if (static_cast<size_t>(frame.width()) != width_ ||
+ static_cast<size_t>(frame.height()) != height_) {
+ ResizeVideo(frame.width(), frame.height());
+ }
+
+ webrtc::ConvertFromI420(frame, kBGRA, 0, buffer_);
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texture_);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8, buffer_);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glLoadIdentity();
+
+ glBegin(GL_QUADS);
+ {
+ glTexCoord2f(0.0f, 0.0f);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+
+ glTexCoord2f(0.0f, 1.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+
+ glTexCoord2f(1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, 0.0f);
+
+ glTexCoord2f(1.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ }
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFlush();
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/gl/gl_renderer.h b/video_engine/test/common/gl/gl_renderer.h
new file mode 100644
index 0000000..6a817ee
--- /dev/null
+++ b/video_engine/test/common/gl/gl_renderer.h
@@ -0,0 +1,45 @@
+/*
+ * 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_GL_GL_RENDERER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_GL_GL_RENDERER_H_
+
+#include <GL/gl.h>
+
+#include "webrtc/video_engine/test/common/video_renderer.h"
+
+namespace webrtc {
+namespace test {
+
+class GlRenderer : public VideoRenderer {
+ public:
+ virtual void RenderFrame(const webrtc::I420VideoFrame& frame,
+ int time_to_render_ms) OVERRIDE;
+
+ protected:
+ GlRenderer();
+
+ void Init();
+ void Destroy();
+
+ void ResizeViewport(size_t width, size_t height);
+
+ private:
+ bool is_init_;
+ uint8_t* buffer_;
+ GLuint texture_;
+ size_t width_, height_, buffer_size_;
+
+ void ResizeVideo(size_t width, size_t height);
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_GL_GL_RENDERER_H_
diff --git a/video_engine/test/common/linux/glx_renderer.cc b/video_engine/test/common/linux/glx_renderer.cc
new file mode 100644
index 0000000..4f7c3d2
--- /dev/null
+++ b/video_engine/test/common/linux/glx_renderer.cc
@@ -0,0 +1,180 @@
+/*
+ * 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/linux/glx_renderer.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <cassert>
+
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+
+namespace webrtc {
+namespace test {
+
+GlxRenderer::GlxRenderer(size_t width, size_t height)
+ : is_init_(false),
+ width_(width),
+ height_(height),
+ display_(NULL),
+ context_(NULL) {
+ assert(width > 0);
+ assert(height > 0);
+}
+
+bool GlxRenderer::Init(const char* window_title) {
+ if ((display_ = XOpenDisplay(NULL)) == NULL) {
+ Destroy();
+ return false;
+ }
+
+ int screen = DefaultScreen(display_);
+
+ XVisualInfo* vi;
+ int attr_list[] = { GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16,
+ None, };
+
+ if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) {
+ Destroy();
+ return false;
+ }
+
+ context_ = glXCreateContext(display_, vi, 0, true);
+ if (context_ == NULL) {
+ Destroy();
+ return false;
+ }
+
+ XSetWindowAttributes window_attributes;
+ window_attributes.colormap = XCreateColormap(
+ display_, RootWindow(display_, vi->screen), vi->visual, AllocNone);
+ window_attributes.border_pixel = 0;
+ window_attributes.event_mask = StructureNotifyMask | ExposureMask;
+ window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0,
+ width_, height_, 0, vi->depth, InputOutput,
+ vi->visual, CWBorderPixel | CWColormap | CWEventMask,
+ &window_attributes);
+ XFree(vi);
+
+ XSetStandardProperties(display_, window_, window_title, window_title, None,
+ NULL, 0, NULL);
+
+ Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True);
+ if (wm_delete != None) {
+ XSetWMProtocols(display_, window_, &wm_delete, 1);
+ }
+
+ XMapRaised(display_, window_);
+
+ if (!glXMakeCurrent(display_, window_, context_)) {
+ Destroy();
+ return false;
+ }
+ GlRenderer::Init();
+ if (!glXMakeCurrent(display_, None, NULL)) {
+ Destroy();
+ return false;
+ }
+
+ Resize(width_, height_);
+ return true;
+}
+
+void GlxRenderer::Destroy() {
+ if (!is_init_) {
+ return;
+ }
+
+ is_init_ = false;
+
+ if (context_ != NULL) {
+ glXMakeCurrent(display_, window_, context_);
+ GlRenderer::Destroy();
+ glXMakeCurrent(display_, None, NULL);
+ glXDestroyContext(display_, context_);
+ context_ = NULL;
+ }
+
+ if (display_ != NULL) {
+ XCloseDisplay(display_);
+ display_ = NULL;
+ }
+}
+
+GlxRenderer* GlxRenderer::Create(const char* window_title, size_t width,
+ size_t height) {
+ GlxRenderer* glx_renderer = new GlxRenderer(width, height);
+ if (!glx_renderer->Init(window_title)) {
+ // TODO(pbos): Add GLX-failed warning here?
+ delete glx_renderer;
+ return NULL;
+ }
+ return glx_renderer;
+}
+
+GlxRenderer::~GlxRenderer() { Destroy(); }
+
+void GlxRenderer::Resize(size_t width, size_t height) {
+ width_ = width;
+ height_ = height;
+ if (!glXMakeCurrent(display_, window_, context_)) {
+ abort();
+ }
+ GlRenderer::ResizeViewport(width_, height_);
+ if (!glXMakeCurrent(display_, None, NULL)) {
+ abort();
+ }
+
+ XSizeHints* size_hints = XAllocSizeHints();
+ if (size_hints == NULL) {
+ abort();
+ }
+ size_hints->flags = PAspect;
+ size_hints->min_aspect.x = size_hints->max_aspect.x = width_;
+ size_hints->min_aspect.y = size_hints->max_aspect.y = height_;
+ XSetWMNormalHints(display_, window_, size_hints);
+ XFree(size_hints);
+}
+
+void GlxRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
+ int /*render_delay_ms*/) {
+ if (static_cast<size_t>(frame.width()) != width_ ||
+ static_cast<size_t>(frame.height()) != height_) {
+ Resize(static_cast<size_t>(frame.width()),
+ static_cast<size_t>(frame.height()));
+ }
+
+ XEvent event;
+ if (!glXMakeCurrent(display_, window_, context_)) {
+ abort();
+ }
+ while (XPending(display_)) {
+ XNextEvent(display_, &event);
+ switch (event.type) {
+ case ConfigureNotify:
+ GlRenderer::ResizeViewport(event.xconfigure.width,
+ event.xconfigure.height);
+ break;
+ default:
+ break;
+ }
+ }
+
+ GlRenderer::RenderFrame(frame, 0);
+ glXSwapBuffers(display_, window_);
+
+ if (!glXMakeCurrent(display_, None, NULL)) {
+ abort();
+ }
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/linux/glx_renderer.h b/video_engine/test/common/linux/glx_renderer.h
new file mode 100644
index 0000000..30fc8df
--- /dev/null
+++ b/video_engine/test/common/linux/glx_renderer.h
@@ -0,0 +1,47 @@
+/*
+ * 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_LINUX_GLX_RENDERER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_GLX_RENDERER_H_
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#include "webrtc/video_engine/test/common/gl/gl_renderer.h"
+
+namespace webrtc {
+namespace test {
+
+class GlxRenderer : public GlRenderer {
+ public:
+ static GlxRenderer* Create(const char* window_title, size_t width,
+ size_t height);
+ virtual ~GlxRenderer();
+
+ virtual void RenderFrame(const webrtc::I420VideoFrame& frame, int delta)
+ OVERRIDE;
+ private:
+ GlxRenderer(size_t width, size_t height);
+
+ bool Init(const char* window_title);
+ void Resize(size_t width, size_t height);
+ void Destroy();
+
+ bool is_init_;
+ size_t width_, height_;
+
+ Display* display_;
+ Window window_;
+ GLXContext context_;
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_GLX_RENDERER_H_
diff --git a/video_engine/test/common/linux/xv_renderer.cc b/video_engine/test/common/linux/xv_renderer.cc
new file mode 100644
index 0000000..ba0b437
--- /dev/null
+++ b/video_engine/test/common/linux/xv_renderer.cc
@@ -0,0 +1,210 @@
+/*
+ * 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/linux/xv_renderer.h"
+
+#include <sys/shm.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xvlib.h>
+
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+
+#define GUID_I420_PLANAR 0x30323449
+
+namespace webrtc {
+namespace test {
+
+XvRenderer::XvRenderer(size_t width, size_t height)
+ : width(width),
+ height(height),
+ is_init(false),
+ display(NULL),
+ gc(NULL),
+ image(NULL) {
+ assert(width > 0);
+ assert(height > 0);
+}
+
+bool XvRenderer::Init(const char* window_title) {
+ assert(!is_init);
+ is_init = true;
+ if ((display = XOpenDisplay(NULL)) == NULL) {
+ Destroy();
+ return false;
+ }
+
+ int screen = DefaultScreen(display);
+
+ XVisualInfo vinfo;
+ if (!XMatchVisualInfo(display, screen, 24, TrueColor, &vinfo)) {
+ Destroy();
+ return false;
+ }
+
+ XSetWindowAttributes xswa;
+ xswa.colormap = XCreateColormap(display, DefaultRootWindow(display),
+ vinfo.visual, AllocNone);
+ xswa.event_mask = StructureNotifyMask | ExposureMask;
+ xswa.background_pixel = 0;
+ xswa.border_pixel = 0;
+
+ window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, width,
+ height, 0, vinfo.depth, InputOutput, vinfo.visual,
+ CWBackPixel | CWBorderPixel | CWColormap | CWEventMask,
+ &xswa);
+
+ XStoreName(display, window, window_title);
+ XSetIconName(display, window, window_title);
+
+ XSelectInput(display, window, StructureNotifyMask);
+
+ XMapRaised(display, window);
+
+ XEvent event;
+ do {
+ XNextEvent(display, &event);
+ } while (event.type != MapNotify || event.xmap.event != window);
+
+ if (!XShmQueryExtension(display)) {
+ Destroy();
+ return false;
+ }
+
+ xv_complete = XShmGetEventBase(display) + ShmCompletion;
+
+ XvAdaptorInfo* ai;
+ unsigned int p_num_adaptors;
+
+ if (XvQueryAdaptors(display, DefaultRootWindow(display), &p_num_adaptors,
+ &ai) !=
+ Success) {
+ Destroy();
+ return false;
+ }
+ if (p_num_adaptors <= 0) {
+ XvFreeAdaptorInfo(ai);
+ Destroy();
+ return false;
+ }
+
+ xv_port = ai[p_num_adaptors - 1].base_id;
+ XvFreeAdaptorInfo(ai);
+
+ if (xv_port == -1) {
+ Destroy();
+ return false;
+ }
+
+ gc = XCreateGC(display, window, 0, 0);
+ if (gc == NULL) {
+ Destroy();
+ return false;
+ }
+
+ Resize(width, height);
+
+ return true;
+}
+
+void XvRenderer::Destroy() {
+ if (image != NULL) {
+ XFree(image);
+ image = NULL;
+ }
+
+ if (gc != NULL) {
+ XFreeGC(display, gc);
+ gc = NULL;
+ }
+
+ if (display != NULL) {
+ XCloseDisplay(display);
+ display = NULL;
+ }
+}
+
+XvRenderer* XvRenderer::Create(const char* window_title, size_t width,
+ size_t height) {
+ XvRenderer* xv_renderer = new XvRenderer(width, height);
+ if (!xv_renderer->Init(window_title)) {
+ // TODO(pbos): Add Xv-failed warning here?
+ delete xv_renderer;
+ return NULL;
+ }
+ return xv_renderer;
+}
+
+XvRenderer::~XvRenderer() { Destroy(); }
+
+void XvRenderer::Resize(size_t width, size_t height) {
+ this->width = width;
+ this->height = height;
+
+ if (image != NULL) {
+ XFree(image);
+ }
+ image = XvShmCreateImage(display, xv_port, GUID_I420_PLANAR, 0, width, height,
+ &shm_info);
+ assert(image != NULL);
+
+ shm_info.shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
+ shm_info.shmaddr = image->data =
+ reinterpret_cast<char*>(shmat(shm_info.shmid, 0, 0));
+ shm_info.readOnly = False;
+
+ if (!XShmAttach(display, &shm_info)) {
+ abort();
+ }
+
+ XSizeHints* size_hints = XAllocSizeHints();
+ if (size_hints == NULL) {
+ abort();
+ }
+ size_hints->flags = PAspect;
+ size_hints->min_aspect.x = size_hints->max_aspect.x = width;
+ size_hints->min_aspect.y = size_hints->max_aspect.y = height;
+ XSetWMNormalHints(display, window, size_hints);
+ XFree(size_hints);
+
+ XWindowChanges wc;
+ wc.width = width;
+ wc.height = height;
+ XConfigureWindow(display, window, CWWidth | CWHeight, &wc);
+}
+
+void XvRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
+ int /*render_delay_ms*/) {
+ int size = webrtc::ExtractBuffer(frame, image->data_size,
+ reinterpret_cast<uint8_t*>(image->data));
+ if (static_cast<size_t>(frame.width()) != width ||
+ static_cast<size_t>(frame.height()) != height) {
+ Resize(static_cast<size_t>(frame.width()),
+ static_cast<size_t>(frame.height()));
+ }
+ assert(size > 0);
+ Window root;
+ int temp;
+ unsigned int window_width, window_height, u_temp;
+
+ XGetGeometry(display, window, &root, &temp, &temp, &window_width,
+ &window_height, &u_temp, &u_temp);
+
+ XvShmPutImage(display, xv_port, window, gc, image, 0, 0, image->width,
+ image->height, 0, 0, window_width, window_height, True);
+
+ XFlush(display);
+
+ XEvent event;
+ while (XPending(display)) {
+ XNextEvent(display, &event);
+ }
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/linux/xv_renderer.h b/video_engine/test/common/linux/xv_renderer.h
new file mode 100644
index 0000000..df6b050
--- /dev/null
+++ b/video_engine/test/common/linux/xv_renderer.h
@@ -0,0 +1,54 @@
+/*
+ * 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_LINUX_XV_RENDERER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_XV_RENDERER_H_
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xvlib.h>
+
+#include "webrtc/video_engine/new_include/common.h"
+#include "webrtc/video_engine/test/common/video_renderer.h"
+
+namespace webrtc {
+namespace test {
+
+class XvRenderer : public VideoRenderer {
+ public:
+ ~XvRenderer();
+
+ virtual void RenderFrame(const webrtc::I420VideoFrame& frame, int delta)
+ OVERRIDE;
+
+ static XvRenderer* Create(const char *window_title, size_t width,
+ size_t height);
+
+ private:
+ XvRenderer(size_t width, size_t height);
+
+ bool Init(const char *window_title);
+ void Resize(size_t width, size_t height);
+ void Destroy();
+
+ size_t width, height;
+ bool is_init;
+
+ Display* display;
+ Window window;
+ GC gc;
+ XvImage* image;
+ XShmSegmentInfo shm_info;
+ int xv_port, xv_complete;
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_XV_RENDERER_H_
diff --git a/video_engine/test/common/vcm_capturer.cc b/video_engine/test/common/vcm_capturer.cc
new file mode 100644
index 0000000..62f0a85
--- /dev/null
+++ b/video_engine/test/common/vcm_capturer.cc
@@ -0,0 +1,108 @@
+/*
+ * 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/vcm_capturer.h"
+
+#include "webrtc/modules/video_capture/include/video_capture_factory.h"
+#include "webrtc/video_engine/new_include/video_send_stream.h"
+
+namespace webrtc {
+namespace test {
+
+VcmCapturer::VcmCapturer(webrtc::newapi::VideoSendStreamInput* input)
+ : VideoCapturer(input), started_(false), vcm(NULL), last_timestamp(0) {}
+
+bool VcmCapturer::Init(size_t width, size_t height, size_t target_fps) {
+ VideoCaptureModule::DeviceInfo* device_info =
+ VideoCaptureFactory::CreateDeviceInfo(42); // Any ID (42) will do.
+
+ char device_name[256];
+ char unique_name[256];
+ if (device_info->GetDeviceName(0, device_name, sizeof(device_name),
+ unique_name, sizeof(unique_name)) !=
+ 0) {
+ Destroy();
+ return false;
+ }
+
+ vcm = webrtc::VideoCaptureFactory::Create(0, unique_name);
+ vcm->RegisterCaptureDataCallback(*this);
+
+ device_info->GetCapability(vcm->CurrentDeviceName(), 0, capability_);
+ delete device_info;
+
+ capability_.width = static_cast<int32_t>(width);
+ capability_.height = static_cast<int32_t>(height);
+ capability_.maxFPS = static_cast<int32_t>(target_fps);
+ capability_.rawType = kVideoI420;
+
+ if (vcm->StartCapture(capability_) != 0) {
+ Destroy();
+ return false;
+ }
+
+ assert(vcm->CaptureStarted());
+
+ return true;
+}
+
+VcmCapturer* VcmCapturer::Create(newapi::VideoSendStreamInput* input,
+ size_t width, size_t height,
+ size_t target_fps) {
+ VcmCapturer* vcm_capturer = new VcmCapturer(input);
+ if (!vcm_capturer->Init(width, height, target_fps)) {
+ // TODO(pbos): Log a warning that this failed.
+ delete vcm_capturer;
+ return NULL;
+ }
+ return vcm_capturer;
+}
+
+
+void VcmCapturer::Start() { started_ = true; }
+
+void VcmCapturer::Stop() { started_ = false; }
+
+void VcmCapturer::Destroy() {
+ if (vcm == NULL) {
+ return;
+ }
+
+ vcm->StopCapture();
+ vcm->DeRegisterCaptureDataCallback();
+ vcm->Release();
+
+ // TODO(pbos): How do I destroy the VideoCaptureModule? This still leaves
+ // non-freed memory.
+ vcm = NULL;
+}
+
+VcmCapturer::~VcmCapturer() { Destroy(); }
+
+void VcmCapturer::OnIncomingCapturedFrame(const int32_t id,
+ I420VideoFrame& frame) {
+ if (last_timestamp == 0 || frame.timestamp() < last_timestamp) {
+ last_timestamp = frame.timestamp();
+ }
+
+ if (started_) {
+ input_->PutFrame(frame, frame.timestamp() - last_timestamp);
+ }
+ last_timestamp = frame.timestamp();
+}
+
+void VcmCapturer::OnIncomingCapturedEncodedFrame(const int32_t id,
+ VideoFrame& frame,
+ VideoCodecType codec_type) {}
+
+void VcmCapturer::OnCaptureDelayChanged(const int32_t id, const int32_t delay) {
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/vcm_capturer.h b/video_engine/test/common/vcm_capturer.h
new file mode 100644
index 0000000..ac31825
--- /dev/null
+++ b/video_engine/test/common/vcm_capturer.h
@@ -0,0 +1,53 @@
+/*
+ * 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_VCM_CAPTURER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VCM_CAPTURER_H_
+
+#include "webrtc/common_types.h"
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/modules/video_capture/include/video_capture.h"
+#include "webrtc/video_engine/test/common/video_capturer.h"
+
+namespace webrtc {
+namespace test {
+
+class VcmCapturer : public VideoCapturer, public VideoCaptureDataCallback {
+ public:
+ static VcmCapturer* Create(newapi::VideoSendStreamInput* input, size_t width,
+ size_t height, size_t target_fps);
+ virtual ~VcmCapturer();
+
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ virtual void OnIncomingCapturedFrame(const int32_t id, I420VideoFrame& frame)
+ OVERRIDE;
+ virtual void OnIncomingCapturedEncodedFrame(const int32_t id,
+ VideoFrame& frame,
+ VideoCodecType codec_type)
+ OVERRIDE;
+ virtual void OnCaptureDelayChanged(const int32_t id, const int32_t delay)
+ OVERRIDE;
+
+ private:
+ explicit VcmCapturer(newapi::VideoSendStreamInput* input);
+ bool Init(size_t width, size_t height, size_t target_fps);
+ void Destroy();
+
+ bool started_;
+ VideoCaptureModule* vcm;
+ VideoCaptureCapability capability_;
+
+ uint32_t last_timestamp;
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VCM_CAPTURER_H_
diff --git a/video_engine/test/common/video_capturer.cc b/video_engine/test/common/video_capturer.cc
new file mode 100644
index 0000000..c8e5477
--- /dev/null
+++ b/video_engine/test/common/video_capturer.cc
@@ -0,0 +1,47 @@
+/*
+ * 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/video_capturer.h"
+#include "webrtc/video_engine/test/common/vcm_capturer.h"
+
+namespace webrtc {
+namespace test {
+
+class NullCapturer : public VideoCapturer {
+ public:
+ NullCapturer() : VideoCapturer(NULL) {}
+ virtual ~NullCapturer() {}
+
+ virtual void Start() {}
+ virtual void Stop() {}
+};
+
+VideoCapturer::VideoCapturer(newapi::VideoSendStreamInput* input)
+ : input_(input) {}
+
+VideoCapturer* VideoCapturer::Create(newapi::VideoSendStreamInput* input) {
+ // TODO(pbos): These should be specified by command-line parameters.
+ size_t width = 640;
+ size_t height = 480;
+ size_t target_fps = 30;
+
+ VcmCapturer* vcm_capturer = VcmCapturer::Create(input, width, height,
+ target_fps);
+ if (vcm_capturer != NULL) {
+ return vcm_capturer;
+ }
+ // TODO(pbos): Log a warning that this failed.
+
+ // TODO(pbos): Add a pseudocapturer which generates frames.
+
+ return new NullCapturer();
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/video_capturer.h b/video_engine/test/common/video_capturer.h
new file mode 100644
index 0000000..c142998
--- /dev/null
+++ b/video_engine/test/common/video_capturer.h
@@ -0,0 +1,36 @@
+/*
+ * 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_VIDEO_CAPTURER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H_
+
+namespace webrtc {
+
+namespace newapi {
+class VideoSendStreamInput;
+} // newapi
+
+namespace test {
+
+class VideoCapturer {
+ public:
+ static VideoCapturer* Create(newapi::VideoSendStreamInput* input);
+ virtual ~VideoCapturer() {}
+
+ virtual void Start() = 0;
+ virtual void Stop() = 0;
+
+ protected:
+ explicit VideoCapturer(newapi::VideoSendStreamInput* input);
+ newapi::VideoSendStreamInput* input_;
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H
diff --git a/video_engine/test/common/video_renderer.cc b/video_engine/test/common/video_renderer.cc
new file mode 100644
index 0000000..bc53fa7
--- /dev/null
+++ b/video_engine/test/common/video_renderer.cc
@@ -0,0 +1,63 @@
+/*
+ * 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/video_renderer.h"
+
+#include "webrtc/modules/video_capture/include/video_capture_factory.h"
+#include "webrtc/video_engine/new_include/video_send_stream.h"
+
+#ifdef WEBRTC_TEST_XV
+#include "webrtc/video_engine/test/common/linux/xv_renderer.h"
+#endif // WEBRTC_TEST_XV
+
+// Platform-specific renderers preferred over NullRenderer
+#ifdef WEBRTC_TEST_GLX
+#include "webrtc/video_engine/test/common/linux/glx_renderer.h"
+#endif // WEBRTC_TEST_GLX
+
+// TODO(pbos): Mac renderer
+// TODO(pbos): Windows renderer
+// TODO(pbos): Android renderer
+
+namespace webrtc {
+namespace test {
+
+class NullRenderer : public VideoRenderer {
+ virtual void RenderFrame(const I420VideoFrame& video_frame,
+ int time_to_render_ms) OVERRIDE {}
+};
+
+VideoRenderer* VideoRenderer::Create(const char* window_title) {
+ // TODO(pbos): Get these from command-line parameters.
+ int width = 640;
+ int height = 480;
+
+#ifdef WEBRTC_TEST_XV
+ XvRenderer* xv_renderer = XvRenderer::Create(window_title, width, height);
+ if (xv_renderer != NULL) {
+ return xv_renderer;
+ }
+#endif // WEBRTC_TEST_XV
+#ifdef WEBRTC_TEST_GLX
+ GlxRenderer* glx_renderer = GlxRenderer::Create(window_title, width, height);
+ if (glx_renderer != NULL) {
+ return glx_renderer;
+ }
+#endif // WEBRTC_TEST_GLX
+
+ // Avoid initialized-but-not-referenced errors when only building a
+ // NullRenderer
+ (void) width;
+ (void) height;
+
+ return new NullRenderer();
+}
+} // test
+} // webrtc
diff --git a/video_engine/test/common/video_renderer.h b/video_engine/test/common/video_renderer.h
new file mode 100644
index 0000000..60ca786
--- /dev/null
+++ b/video_engine/test/common/video_renderer.h
@@ -0,0 +1,26 @@
+/*
+ * 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_VIDEO_RENDERER_H_
+#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_
+
+#include "webrtc/video_engine/new_include/common.h"
+
+namespace webrtc {
+namespace test {
+
+class VideoRenderer : public newapi::VideoRenderer {
+ public:
+ static VideoRenderer* Create(const char* window_title);
+ virtual ~VideoRenderer() {}
+};
+} // test
+} // webrtc
+
+#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_
diff --git a/video_engine/test/loopback.cc b/video_engine/test/loopback.cc
new file mode 100644
index 0000000..c8c3ae3
--- /dev/null
+++ b/video_engine/test/loopback.cc
@@ -0,0 +1,103 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <iostream>
+#include <map>
+
+#include "webrtc/video_engine/new_include/video_engine.h"
+#include "webrtc/video_engine/test/common/direct_transport.h"
+#include "webrtc/video_engine/test/common/generate_ssrcs.h"
+#include "webrtc/video_engine/test/common/video_capturer.h"
+#include "webrtc/video_engine/test/common/video_renderer.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class LoopbackTest : public ::testing::Test {
+ protected:
+ std::map<uint32_t, bool> reserved_ssrcs;
+};
+
+TEST_F(LoopbackTest, Test) {
+ test::VideoRenderer* local_preview =
+ test::VideoRenderer::Create("Local Preview");
+ test::VideoRenderer* loopback_video =
+ test::VideoRenderer::Create("Loopback Video");
+
+ newapi::VideoEngine* video_engine =
+ newapi::VideoEngine::Create(webrtc::newapi::VideoEngineConfig());
+
+ test::DirectTransport transport(NULL);
+ newapi::VideoCall* call = video_engine->CreateCall(&transport);
+
+ // Loopback, call sends to itself.
+ transport.SetReceiver(call->Receiver());
+
+ newapi::VideoSendStreamConfig send_config;
+ call->GetDefaultSendConfig(&send_config);
+ test::GenerateRandomSsrcs(&send_config, &reserved_ssrcs);
+
+ send_config.local_renderer = local_preview;
+
+ // TODO(pbos): Should be specified by command-line parameters. And not even
+ // visible in the test. Break it out to some get-test-defaults
+ // class
+ send_config.codec.width = 640;
+ send_config.codec.height = 480;
+ send_config.codec.minBitrate = 1000;
+ send_config.codec.startBitrate = 1500;
+ send_config.codec.maxBitrate = 2000;
+
+ newapi::VideoSendStream* send_stream = call->CreateSendStream(send_config);
+
+ test::VideoCapturer* camera =
+ test::VideoCapturer::Create(send_stream->Input());
+
+ newapi::VideoReceiveStreamConfig receive_config;
+ call->GetDefaultReceiveConfig(&receive_config);
+ receive_config.rtp.ssrc = send_config.rtp.ssrcs[0];
+ receive_config.renderer = loopback_video;
+
+ newapi::VideoReceiveStream* receive_stream =
+ call->CreateReceiveStream(receive_config);
+
+ receive_stream->StartReceive();
+ send_stream->StartSend();
+
+ camera->Start();
+
+ // TODO(pbos): Run this time limited (optionally), so it can run automated.
+ std::cout << ">> Press ENTER to continue..." << std::endl;
+ std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+ receive_stream->StopReceive();
+ send_stream->StopSend();
+
+ // Stop sending
+ delete camera;
+
+ call->DestroyReceiveStream(receive_stream);
+ call->DestroySendStream(send_stream);
+
+ delete call;
+ delete video_engine;
+
+ delete loopback_video;
+ delete local_preview;
+}
+} // webrtc
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/video_engine/test/tests.gypi b/video_engine/test/tests.gypi
new file mode 100644
index 0000000..d74881a
--- /dev/null
+++ b/video_engine/test/tests.gypi
@@ -0,0 +1,115 @@
+# 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.
+
+{
+ 'variables': {
+ 'xv_renderer%': 0,
+ },
+ 'conditions': [
+ ['OS=="linux"', {
+ 'variables': {
+ 'glx_renderer%': 1,
+ },
+ }, {
+ # OS != "linux"
+ 'variables': {
+ 'glx_renderer%': 0,
+ },
+ }],
+ ],
+ 'targets': [
+ {
+ 'target_name': 'video_tests_common',
+ 'type': 'static_library',
+ 'sources': [
+ 'common/generate_ssrcs.h',
+ 'common/vcm_capturer.h',
+ 'common/vcm_capturer.cc',
+ 'common/video_capturer.cc',
+ 'common/video_capturer.h',
+ 'common/video_renderer.cc',
+ 'common/video_renderer.h',
+ ],
+ 'conditions': [
+ ['glx_renderer==1', {
+ 'defines': [
+ 'WEBRTC_TEST_GLX',
+ ],
+ 'sources' : [
+ 'common/gl/gl_renderer.cc',
+ 'common/gl/gl_renderer.h',
+ 'common/linux/glx_renderer.cc',
+ 'common/linux/glx_renderer.h',
+ ],
+ }],
+ ['xv_renderer==1', {
+ 'defines': [
+ 'WEBRTC_TEST_XV',
+ ],
+ 'sources': [
+ 'common/linux/xv_renderer.cc',
+ 'common/linux/xv_renderer.h',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'conditions': [
+ ['OS=="linux"', {
+ 'libraries': [
+ '-lXext',
+ '-lX11',
+ '-lGL',
+ ],
+ }],
+ ['xv_renderer==1', {
+ 'libraries': [
+ '-lXv',
+ ],
+ }],
+ #TODO(pbos) : These dependencies should not have to be here, they
+ # aren't used by test code directly, only by components
+ # used by the tests.
+ ['OS=="android"', {
+ 'libraries' : [
+ '-lGLESv2', '-llog',
+ ],
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings' : {
+ 'OTHER_LDFLAGS' : [
+ '-framework Foundation',
+ '-framework AppKit',
+ '-framework Cocoa',
+ '-framework OpenGL',
+ '-framework CoreVideo',
+ '-framework CoreAudio',
+ '-framework AudioToolbox',
+ ],
+ },
+ }],
+ ],
+ },
+ 'dependencies': [
+ '<(webrtc_root)/modules/modules.gyp:video_capture_module',
+ 'video_engine_core',
+ ],
+ },
+ {
+ 'target_name': 'video_loopback',
+ 'type': 'executable',
+ 'sources': [
+ 'loopback.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(webrtc_root)/modules/modules.gyp:video_capture_module',
+ 'video_tests_common',
+ ],
+ },
+ ],
+}