[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / media / tools / player_x11 / x11_video_renderer.cc
blob2ae8e3b3a7ff21e907f12feeeb5995a2070b8bfa
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/tools/player_x11/x11_video_renderer.h"
7 #include <dlfcn.h>
8 #include <X11/Xutil.h>
9 #include <X11/extensions/Xrender.h>
10 #include <X11/extensions/Xcomposite.h>
12 #include "base/bind.h"
13 #include "base/message_loop/message_loop.h"
14 #include "media/base/video_frame.h"
15 #include "media/base/yuv_convert.h"
17 // Creates a 32-bit XImage.
18 static XImage* CreateImage(Display* display, int width, int height) {
19 VLOG(0) << "Allocating XImage " << width << "x" << height;
20 return XCreateImage(display,
21 DefaultVisual(display, DefaultScreen(display)),
22 DefaultDepth(display, DefaultScreen(display)),
23 ZPixmap,
25 static_cast<char*>(malloc(width * height * 4)),
26 width,
27 height,
28 32,
29 width * 4);
32 // Returns the picture format for ARGB.
33 // This method is originally from chrome/common/x11_util.cc.
34 static XRenderPictFormat* GetRenderARGB32Format(Display* dpy) {
35 static XRenderPictFormat* pictformat = NULL;
36 if (pictformat)
37 return pictformat;
39 // First look for a 32-bit format which ignores the alpha value.
40 XRenderPictFormat templ;
41 templ.depth = 32;
42 templ.type = PictTypeDirect;
43 templ.direct.red = 16;
44 templ.direct.green = 8;
45 templ.direct.blue = 0;
46 templ.direct.redMask = 0xff;
47 templ.direct.greenMask = 0xff;
48 templ.direct.blueMask = 0xff;
49 templ.direct.alphaMask = 0;
51 static const unsigned long kMask =
52 PictFormatType | PictFormatDepth |
53 PictFormatRed | PictFormatRedMask |
54 PictFormatGreen | PictFormatGreenMask |
55 PictFormatBlue | PictFormatBlueMask |
56 PictFormatAlphaMask;
58 pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
60 if (!pictformat) {
61 // Not all X servers support xRGB32 formats. However, the XRender spec
62 // says that they must support an ARGB32 format, so we can always return
63 // that.
64 pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
65 CHECK(pictformat) << "XRender ARGB32 not supported.";
68 return pictformat;
71 X11VideoRenderer::X11VideoRenderer(Display* display, Window window)
72 : display_(display),
73 window_(window),
74 image_(NULL),
75 picture_(0),
76 use_render_(false) {
79 X11VideoRenderer::~X11VideoRenderer() {
80 if (image_)
81 XDestroyImage(image_);
82 if (use_render_)
83 XRenderFreePicture(display_, picture_);
86 void X11VideoRenderer::Paint(
87 const scoped_refptr<media::VideoFrame>& video_frame) {
88 if (!image_)
89 Initialize(video_frame->coded_size(), video_frame->visible_rect());
91 const int coded_width = video_frame->coded_size().width();
92 const int coded_height = video_frame->coded_size().height();
93 const int visible_width = video_frame->visible_rect().width();
94 const int visible_height = video_frame->visible_rect().height();
96 // Check if we need to reallocate our XImage.
97 if (image_->width != coded_width || image_->height != coded_height) {
98 XDestroyImage(image_);
99 image_ = CreateImage(display_, coded_width, coded_height);
102 // Convert YUV frame to RGB.
103 DCHECK(video_frame->format() == media::VideoFrame::YV12 ||
104 video_frame->format() == media::VideoFrame::I420 ||
105 video_frame->format() == media::VideoFrame::YV16);
106 DCHECK(video_frame->stride(media::VideoFrame::kUPlane) ==
107 video_frame->stride(media::VideoFrame::kVPlane));
109 DCHECK(image_->data);
110 media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12 ||
111 video_frame->format() == media::VideoFrame::I420)
112 ? media::YV12
113 : media::YV16;
114 media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane),
115 video_frame->data(media::VideoFrame::kUPlane),
116 video_frame->data(media::VideoFrame::kVPlane),
117 (uint8*)image_->data, coded_width, coded_height,
118 video_frame->stride(media::VideoFrame::kYPlane),
119 video_frame->stride(media::VideoFrame::kUPlane),
120 image_->bytes_per_line,
121 yuv_type);
123 if (use_render_) {
124 // If XRender is used, we'll upload the image to a pixmap. And then
125 // creats a picture from the pixmap and composite the picture over
126 // the picture represending the window.
128 // Creates a XImage.
129 XImage image;
130 memset(&image, 0, sizeof(image));
131 image.width = coded_width;
132 image.height = coded_height;
133 image.depth = 32;
134 image.bits_per_pixel = 32;
135 image.format = ZPixmap;
136 image.byte_order = LSBFirst;
137 image.bitmap_unit = 8;
138 image.bitmap_bit_order = LSBFirst;
139 image.bytes_per_line = image_->bytes_per_line;
140 image.red_mask = 0xff;
141 image.green_mask = 0xff00;
142 image.blue_mask = 0xff0000;
143 image.data = image_->data;
145 // Creates a pixmap and uploads from the XImage.
146 unsigned long pixmap = XCreatePixmap(display_, window_,
147 visible_width, visible_height,
148 32);
149 GC gc = XCreateGC(display_, pixmap, 0, NULL);
150 XPutImage(display_, pixmap, gc, &image,
151 video_frame->visible_rect().x(),
152 video_frame->visible_rect().y(),
153 0, 0,
154 visible_width, visible_height);
155 XFreeGC(display_, gc);
157 // Creates the picture representing the pixmap.
158 unsigned long picture = XRenderCreatePicture(
159 display_, pixmap, GetRenderARGB32Format(display_), 0, NULL);
161 // Composite the picture over the picture representing the window.
162 XRenderComposite(display_, PictOpSrc, picture, 0,
163 picture_, 0, 0, 0, 0, 0, 0,
164 visible_width, visible_height);
166 XRenderFreePicture(display_, picture);
167 XFreePixmap(display_, pixmap);
168 return;
171 // If XRender is not used, simply put the image to the server.
172 // This will have a tearing effect but this is OK.
173 // TODO(hclam): Upload the image to a pixmap and do XCopyArea()
174 // to the window.
175 GC gc = XCreateGC(display_, window_, 0, NULL);
176 XPutImage(display_, window_, gc, image_,
177 video_frame->visible_rect().x(),
178 video_frame->visible_rect().y(),
179 0, 0, visible_width, visible_height);
180 XFlush(display_);
181 XFreeGC(display_, gc);
184 void X11VideoRenderer::Initialize(gfx::Size coded_size,
185 gfx::Rect visible_rect) {
186 CHECK(!image_);
187 VLOG(0) << "Initializing X11 Renderer...";
189 // Resize the window to fit that of the video.
190 XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height());
191 image_ = CreateImage(display_, coded_size.width(), coded_size.height());
193 // Testing XRender support. We'll use the very basic of XRender
194 // so if it presents it is already good enough. We don't need
195 // to check its version.
196 int dummy;
197 use_render_ = XRenderQueryExtension(display_, &dummy, &dummy);
199 if (use_render_) {
200 VLOG(0) << "Using XRender extension.";
202 // If we are using XRender, we'll create a picture representing the
203 // window.
204 XWindowAttributes attr;
205 XGetWindowAttributes(display_, window_, &attr);
207 XRenderPictFormat* pictformat = XRenderFindVisualFormat(
208 display_,
209 attr.visual);
210 CHECK(pictformat) << "XRender does not support default visual";
212 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL);
213 CHECK(picture_) << "Backing picture not created";