// Copyright (c) 2010 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 "chrome/browser/renderer_host/video_layer_x.h" #include "app/x11_util_internal.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "media/base/yuv_convert.h" VideoLayerX::VideoLayerX(RenderWidgetHost* widget, const gfx::Size& size, void* visual, int depth) : VideoLayer(widget, size), visual_(visual), depth_(depth), display_(x11_util::GetXDisplay()) { DCHECK(!size.IsEmpty()); // Create our pixmap + GC representing an RGB version of a video frame. pixmap_ = XCreatePixmap(display_, x11_util::GetX11RootWindow(), size.width(), size.height(), depth_); pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL); pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth_); } VideoLayerX::~VideoLayerX() { // In unit tests, |display_| may be NULL. if (!display_) return; XFreePixmap(display_, pixmap_); XFreeGC(display_, static_cast(pixmap_gc_)); } void VideoLayerX::CopyTransportDIB(RenderProcessHost* process, TransportDIB::Id bitmap, const gfx::Rect& bitmap_rect) { if (!display_) return; if (bitmap_rect.IsEmpty()) return; if (bitmap_rect.size() != size()) { LOG(ERROR) << "Scaled video layer not supported."; return; } // Save location and size of destination bitmap. rgb_rect_ = bitmap_rect; // Lazy allocate |rgb_frame_|. if (!rgb_frame_.get()) { // TODO(scherkus): handle changing dimensions and re-allocating. CHECK(size() == rgb_rect_.size()); rgb_frame_.reset(new uint8[rgb_rect_.width() * rgb_rect_.height() * 4]); } const int width = bitmap_rect.width(); const int height = bitmap_rect.height(); // Assume that somewhere along the line, someone will do width * height * 4 // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = // 2**29 and floor(sqrt(2**29)) = 23170. if (width > 23170 || height > 23170) return; TransportDIB* dib = process->GetTransportDIB(bitmap); if (!dib) return; // Perform colour space conversion. const uint8* y_plane = reinterpret_cast(dib->memory()); const uint8* u_plane = y_plane + width * height; const uint8* v_plane = u_plane + ((width * height) >> 2); media::ConvertYUVToRGB32(y_plane, u_plane, v_plane, rgb_frame_.get(), width, height, width, width / 2, width * 4, media::YV12); // Draw ARGB frame onto our pixmap. x11_util::PutARGBImage(display_, visual_, depth_, pixmap_, pixmap_gc_, rgb_frame_.get(), width, height); } void VideoLayerX::XShow(XID target) { if (rgb_rect_.IsEmpty()) return; XCopyArea(display_, pixmap_, target, static_cast(pixmap_gc_), 0, 0, rgb_rect_.width(), rgb_rect_.height(), rgb_rect_.x(), rgb_rect_.y()); }