| // 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 |