blob: cb6b5cafabdc6bf7887535370a729880822835c8 [file] [log] [blame]
/*
* 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