blob: ed9347a3423c9aaa7534106977eab07299c7ad58 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/test/linux_output_window.h"
#include <stdint.h>
#include <algorithm>
#include "base/logging.h"
#include "media/base/video_frame.h"
#include "third_party/libyuv/include/libyuv/convert.h"
#include "ui/gfx/geometry/size.h"
namespace media {
namespace cast {
namespace test {
LinuxOutputWindow::LinuxOutputWindow(int x_pos,
int y_pos,
int width,
int height,
const std::string& name) {
CreateWindow(x_pos, y_pos, width, height, name);
}
LinuxOutputWindow::~LinuxOutputWindow() {
if (display_ && window_) {
XUnmapWindow(display_, window_);
XDestroyWindow(display_, window_);
XSync(display_, false);
if (gc_)
XFreeGC(display_, gc_);
XCloseDisplay(display_);
}
}
void LinuxOutputWindow::CreateWindow(int x_pos,
int y_pos,
int width,
int height,
const std::string& name) {
display_ = XOpenDisplay(NULL);
if (display_ == NULL) {
// There's no point to continue if this happens: nothing will work anyway.
VLOG(1) << "Failed to connect to X server: X environment likely broken";
NOTREACHED();
}
int screen = DefaultScreen(display_);
// Try to establish a 24-bit TrueColor display.
// (our environment must allow this).
XVisualInfo visual_info;
if (XMatchVisualInfo(display_, screen, 24, TrueColor, &visual_info) == 0) {
VLOG(1) << "Failed to establish 24-bit TrueColor in X environment.";
NOTREACHED();
}
// Create suitable window attributes.
XSetWindowAttributes window_attributes;
window_attributes.colormap = XCreateColormap(
display_, DefaultRootWindow(display_), visual_info.visual, AllocNone);
window_attributes.event_mask = StructureNotifyMask | ExposureMask;
window_attributes.background_pixel = 0;
window_attributes.border_pixel = 0;
unsigned long attribute_mask =
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
window_ = XCreateWindow(display_,
DefaultRootWindow(display_),
x_pos,
y_pos,
width,
height,
0,
visual_info.depth,
InputOutput,
visual_info.visual,
attribute_mask,
&window_attributes);
// Set window name.
XStoreName(display_, window_, name.c_str());
XSetIconName(display_, window_, name.c_str());
// Make x report events for mask.
XSelectInput(display_, window_, StructureNotifyMask);
// Map the window to the display.
XMapWindow(display_, window_);
// Wait for map event.
XEvent event;
do {
XNextEvent(display_, &event);
} while (event.type != MapNotify || event.xmap.event != window_);
gc_ = XCreateGC(display_, window_, 0, 0);
// create shared memory image
image_ = XShmCreateImage(
display_, CopyFromParent, 24, ZPixmap, NULL, &shminfo_, width, height);
shminfo_.shmid = shmget(
IPC_PRIVATE, (image_->bytes_per_line * image_->height), IPC_CREAT | 0777);
shminfo_.shmaddr = image_->data = (char*)shmat(shminfo_.shmid, 0, 0);
if (image_->data == reinterpret_cast<char*>(-1)) {
VLOG(1) << "XShmCreateImage failed";
NOTREACHED();
}
shminfo_.readOnly = false;
// Attach image to display.
if (!XShmAttach(display_, &shminfo_)) {
VLOG(1) << "XShmAttach failed";
NOTREACHED();
}
XSync(display_, false);
}
void LinuxOutputWindow::RenderFrame(
const scoped_refptr<media::VideoFrame>& video_frame) {
const gfx::Size damage_size(std::min(video_frame->visible_rect().width(),
image_->width),
std::min(video_frame->visible_rect().height(),
image_->height));
if (damage_size.width() < image_->width ||
damage_size.height() < image_->height)
memset(image_->data, 0x00, image_->bytes_per_line * image_->height);
if (!damage_size.IsEmpty()) {
libyuv::I420ToARGB(video_frame->visible_data(VideoFrame::kYPlane),
video_frame->stride(VideoFrame::kYPlane),
video_frame->visible_data(VideoFrame::kUPlane),
video_frame->stride(VideoFrame::kUPlane),
video_frame->visible_data(VideoFrame::kVPlane),
video_frame->stride(VideoFrame::kVPlane),
reinterpret_cast<uint8_t*>(image_->data),
image_->bytes_per_line,
damage_size.width(),
damage_size.height());
}
// Place image in window.
XShmPutImage(display_,
window_,
gc_,
image_,
0,
0,
0,
0,
image_->width,
image_->height,
true);
// Very important for the image to update properly!
XSync(display_, false);
}
} // namespace test
} // namespace cast
} // namespace media