BUG=1662 R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1492004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4056 4adac7df-926f-26a2-2b94-8c16560cd09d
211 lines
5.3 KiB
C++
211 lines
5.3 KiB
C++
/*
|
|
* 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 <X11/Xutil.h>
|
|
#include <X11/extensions/Xvlib.h>
|
|
#include <sys/shm.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
|