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"
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
)),
25 static_cast<char*>(malloc(width
* height
* 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
;
39 // First look for a 32-bit format which ignores the alpha value.
40 XRenderPictFormat templ
;
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
|
58 pictformat
= XRenderFindFormat(dpy
, kMask
, &templ
, 0 /* first result */);
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
64 pictformat
= XRenderFindStandardFormat(dpy
, PictStandardARGB32
);
65 CHECK(pictformat
) << "XRender ARGB32 not supported.";
71 X11VideoRenderer::X11VideoRenderer(Display
* display
, Window window
)
79 X11VideoRenderer::~X11VideoRenderer() {
81 XDestroyImage(image_
);
83 XRenderFreePicture(display_
, picture_
);
86 void X11VideoRenderer::Paint(
87 const scoped_refptr
<media::VideoFrame
>& video_frame
) {
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
)
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
,
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.
130 memset(&image
, 0, sizeof(image
));
131 image
.width
= coded_width
;
132 image
.height
= coded_height
;
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
,
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(),
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
);
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()
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
);
181 XFreeGC(display_
, gc
);
184 void X11VideoRenderer::Initialize(gfx::Size coded_size
,
185 gfx::Rect visible_rect
) {
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.
197 use_render_
= XRenderQueryExtension(display_
, &dummy
, &dummy
);
200 VLOG(0) << "Using XRender extension.";
202 // If we are using XRender, we'll create a picture representing the
204 XWindowAttributes attr
;
205 XGetWindowAttributes(display_
, window_
, &attr
);
207 XRenderPictFormat
* pictformat
= XRenderFindVisualFormat(
210 CHECK(pictformat
) << "XRender does not support default visual";
212 picture_
= XRenderCreatePicture(display_
, window_
, pictformat
, 0, NULL
);
213 CHECK(picture_
) << "Backing picture not created";