| Index: media/tools/player_x11/x11_video_renderer.cc | 
| diff --git a/media/tools/player_x11/x11_video_renderer.cc b/media/tools/player_x11/x11_video_renderer.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..2ae8e3b3a7ff21e907f12feeeb5995a2070b8bfa | 
| --- /dev/null | 
| +++ b/media/tools/player_x11/x11_video_renderer.cc | 
| @@ -0,0 +1,215 @@ | 
| +// Copyright (c) 2012 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/tools/player_x11/x11_video_renderer.h" | 
| + | 
| +#include <dlfcn.h> | 
| +#include <X11/Xutil.h> | 
| +#include <X11/extensions/Xrender.h> | 
| +#include <X11/extensions/Xcomposite.h> | 
| + | 
| +#include "base/bind.h" | 
| +#include "base/message_loop/message_loop.h" | 
| +#include "media/base/video_frame.h" | 
| +#include "media/base/yuv_convert.h" | 
| + | 
| +// Creates a 32-bit XImage. | 
| +static XImage* CreateImage(Display* display, int width, int height) { | 
| +  VLOG(0) << "Allocating XImage " << width << "x" << height; | 
| +  return  XCreateImage(display, | 
| +                       DefaultVisual(display, DefaultScreen(display)), | 
| +                       DefaultDepth(display, DefaultScreen(display)), | 
| +                       ZPixmap, | 
| +                       0, | 
| +                       static_cast<char*>(malloc(width * height * 4)), | 
| +                       width, | 
| +                       height, | 
| +                       32, | 
| +                       width * 4); | 
| +} | 
| + | 
| +// Returns the picture format for ARGB. | 
| +// This method is originally from chrome/common/x11_util.cc. | 
| +static XRenderPictFormat* GetRenderARGB32Format(Display* dpy) { | 
| +  static XRenderPictFormat* pictformat = NULL; | 
| +  if (pictformat) | 
| +    return pictformat; | 
| + | 
| +  // First look for a 32-bit format which ignores the alpha value. | 
| +  XRenderPictFormat templ; | 
| +  templ.depth = 32; | 
| +  templ.type = PictTypeDirect; | 
| +  templ.direct.red = 16; | 
| +  templ.direct.green = 8; | 
| +  templ.direct.blue = 0; | 
| +  templ.direct.redMask = 0xff; | 
| +  templ.direct.greenMask = 0xff; | 
| +  templ.direct.blueMask = 0xff; | 
| +  templ.direct.alphaMask = 0; | 
| + | 
| +  static const unsigned long kMask = | 
| +      PictFormatType | PictFormatDepth | | 
| +      PictFormatRed | PictFormatRedMask | | 
| +      PictFormatGreen | PictFormatGreenMask | | 
| +      PictFormatBlue | PictFormatBlueMask | | 
| +      PictFormatAlphaMask; | 
| + | 
| +  pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */); | 
| + | 
| +  if (!pictformat) { | 
| +    // Not all X servers support xRGB32 formats. However, the XRender spec | 
| +    // says that they must support an ARGB32 format, so we can always return | 
| +    // that. | 
| +    pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32); | 
| +    CHECK(pictformat) << "XRender ARGB32 not supported."; | 
| +  } | 
| + | 
| +  return pictformat; | 
| +} | 
| + | 
| +X11VideoRenderer::X11VideoRenderer(Display* display, Window window) | 
| +    : display_(display), | 
| +      window_(window), | 
| +      image_(NULL), | 
| +      picture_(0), | 
| +      use_render_(false) { | 
| +} | 
| + | 
| +X11VideoRenderer::~X11VideoRenderer() { | 
| +  if (image_) | 
| +    XDestroyImage(image_); | 
| +  if (use_render_) | 
| +    XRenderFreePicture(display_, picture_); | 
| +} | 
| + | 
| +void X11VideoRenderer::Paint( | 
| +    const scoped_refptr<media::VideoFrame>& video_frame) { | 
| +  if (!image_) | 
| +    Initialize(video_frame->coded_size(), video_frame->visible_rect()); | 
| + | 
| +  const int coded_width = video_frame->coded_size().width(); | 
| +  const int coded_height = video_frame->coded_size().height(); | 
| +  const int visible_width = video_frame->visible_rect().width(); | 
| +  const int visible_height = video_frame->visible_rect().height(); | 
| + | 
| +  // Check if we need to reallocate our XImage. | 
| +  if (image_->width != coded_width || image_->height != coded_height) { | 
| +    XDestroyImage(image_); | 
| +    image_ = CreateImage(display_, coded_width, coded_height); | 
| +  } | 
| + | 
| +  // Convert YUV frame to RGB. | 
| +  DCHECK(video_frame->format() == media::VideoFrame::YV12 || | 
| +         video_frame->format() == media::VideoFrame::I420 || | 
| +         video_frame->format() == media::VideoFrame::YV16); | 
| +  DCHECK(video_frame->stride(media::VideoFrame::kUPlane) == | 
| +         video_frame->stride(media::VideoFrame::kVPlane)); | 
| + | 
| +  DCHECK(image_->data); | 
| +  media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12 || | 
| +                             video_frame->format() == media::VideoFrame::I420) | 
| +                                ? media::YV12 | 
| +                                : media::YV16; | 
| +  media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), | 
| +                           video_frame->data(media::VideoFrame::kUPlane), | 
| +                           video_frame->data(media::VideoFrame::kVPlane), | 
| +                           (uint8*)image_->data, coded_width, coded_height, | 
| +                           video_frame->stride(media::VideoFrame::kYPlane), | 
| +                           video_frame->stride(media::VideoFrame::kUPlane), | 
| +                           image_->bytes_per_line, | 
| +                           yuv_type); | 
| + | 
| +  if (use_render_) { | 
| +    // If XRender is used, we'll upload the image to a pixmap. And then | 
| +    // creats a picture from the pixmap and composite the picture over | 
| +    // the picture represending the window. | 
| + | 
| +    // Creates a XImage. | 
| +    XImage image; | 
| +    memset(&image, 0, sizeof(image)); | 
| +    image.width = coded_width; | 
| +    image.height = coded_height; | 
| +    image.depth = 32; | 
| +    image.bits_per_pixel = 32; | 
| +    image.format = ZPixmap; | 
| +    image.byte_order = LSBFirst; | 
| +    image.bitmap_unit = 8; | 
| +    image.bitmap_bit_order = LSBFirst; | 
| +    image.bytes_per_line = image_->bytes_per_line; | 
| +    image.red_mask = 0xff; | 
| +    image.green_mask = 0xff00; | 
| +    image.blue_mask = 0xff0000; | 
| +    image.data = image_->data; | 
| + | 
| +    // Creates a pixmap and uploads from the XImage. | 
| +    unsigned long pixmap = XCreatePixmap(display_, window_, | 
| +                                         visible_width, visible_height, | 
| +                                         32); | 
| +    GC gc = XCreateGC(display_, pixmap, 0, NULL); | 
| +    XPutImage(display_, pixmap, gc, &image, | 
| +              video_frame->visible_rect().x(), | 
| +              video_frame->visible_rect().y(), | 
| +              0, 0, | 
| +              visible_width, visible_height); | 
| +    XFreeGC(display_, gc); | 
| + | 
| +    // Creates the picture representing the pixmap. | 
| +    unsigned long picture = XRenderCreatePicture( | 
| +        display_, pixmap, GetRenderARGB32Format(display_), 0, NULL); | 
| + | 
| +    // Composite the picture over the picture representing the window. | 
| +    XRenderComposite(display_, PictOpSrc, picture, 0, | 
| +                     picture_, 0, 0, 0, 0, 0, 0, | 
| +                     visible_width, visible_height); | 
| + | 
| +    XRenderFreePicture(display_, picture); | 
| +    XFreePixmap(display_, pixmap); | 
| +    return; | 
| +  } | 
| + | 
| +  // If XRender is not used, simply put the image to the server. | 
| +  // This will have a tearing effect but this is OK. | 
| +  // TODO(hclam): Upload the image to a pixmap and do XCopyArea() | 
| +  // to the window. | 
| +  GC gc = XCreateGC(display_, window_, 0, NULL); | 
| +  XPutImage(display_, window_, gc, image_, | 
| +            video_frame->visible_rect().x(), | 
| +            video_frame->visible_rect().y(), | 
| +            0, 0, visible_width, visible_height); | 
| +  XFlush(display_); | 
| +  XFreeGC(display_, gc); | 
| +} | 
| + | 
| +void X11VideoRenderer::Initialize(gfx::Size coded_size, | 
| +                                  gfx::Rect visible_rect) { | 
| +  CHECK(!image_); | 
| +  VLOG(0) << "Initializing X11 Renderer..."; | 
| + | 
| +  // Resize the window to fit that of the video. | 
| +  XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); | 
| +  image_ = CreateImage(display_, coded_size.width(), coded_size.height()); | 
| + | 
| +  // Testing XRender support. We'll use the very basic of XRender | 
| +  // so if it presents it is already good enough. We don't need | 
| +  // to check its version. | 
| +  int dummy; | 
| +  use_render_ = XRenderQueryExtension(display_, &dummy, &dummy); | 
| + | 
| +  if (use_render_) { | 
| +    VLOG(0) << "Using XRender extension."; | 
| + | 
| +    // If we are using XRender, we'll create a picture representing the | 
| +    // window. | 
| +    XWindowAttributes attr; | 
| +    XGetWindowAttributes(display_, window_, &attr); | 
| + | 
| +    XRenderPictFormat* pictformat = XRenderFindVisualFormat( | 
| +        display_, | 
| +        attr.visual); | 
| +    CHECK(pictformat) << "XRender does not support default visual"; | 
| + | 
| +    picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); | 
| +    CHECK(picture_) << "Backing picture not created"; | 
| +  } | 
| +} | 
|  |