OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/client/x11_view.h" | 5 #include "remoting/client/x11_view.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/Xutil.h> | 8 #include <X11/Xutil.h> |
9 #include <X11/extensions/Xrender.h> | 9 #include <X11/extensions/Xrender.h> |
10 #include <X11/extensions/Xcomposite.h> | 10 #include <X11/extensions/Xcomposite.h> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "remoting/base/decoder_zlib.h" | 13 #include "base/task.h" |
14 | 14 |
15 namespace remoting { | 15 namespace remoting { |
16 | 16 |
17 X11View::X11View() | 17 X11View::X11View() |
18 : display_(NULL), | 18 : display_(NULL), |
19 window_(0), | 19 window_(0), |
20 picture_(0) { | 20 picture_(0) { |
21 } | 21 } |
22 | 22 |
23 X11View::~X11View() { | 23 X11View::~X11View() { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 if (display_ && window_) { | 58 if (display_ && window_) { |
59 // Shutdown the window system. | 59 // Shutdown the window system. |
60 XDestroyWindow(display_, window_); | 60 XDestroyWindow(display_, window_); |
61 XCloseDisplay(display_); | 61 XCloseDisplay(display_); |
62 } | 62 } |
63 display_ = NULL; | 63 display_ = NULL; |
64 window_ = 0; | 64 window_ = 0; |
65 } | 65 } |
66 | 66 |
67 void X11View::Paint() { | 67 void X11View::Paint() { |
| 68 NOTIMPLEMENTED() << "Not sure if we need this call anymore."; |
| 69 } |
| 70 |
| 71 void X11View::PaintRect(media::VideoFrame* frame, const gfx::Rect& clip) { |
68 // Don't bother attempting to paint if the display hasn't been set up. | 72 // Don't bother attempting to paint if the display hasn't been set up. |
69 if (!display_ || !window_ || !frame_height_ || !frame_width_ || !frame_) { | 73 if (!display_ || !window_ || !frame) { |
70 return; | 74 return; |
71 } | 75 } |
72 | 76 |
73 // TODO(hclam): Paint only the updated regions. | |
74 all_update_rects_.clear(); | |
75 | |
76 // If we have not initialized the render target then do it now. | 77 // If we have not initialized the render target then do it now. |
77 if (!picture_) | 78 if (!picture_) |
78 InitPaintTarget(); | 79 InitPaintTarget(); |
79 | 80 |
80 // Upload the image to a pixmap. And then create a picture from the pixmap | 81 // Upload the image to a pixmap. And then create a picture from the pixmap |
81 // and composite the picture over the picture representing the window. | 82 // and composite the picture over the picture representing the window. |
82 | 83 |
83 // Creates a XImage. | 84 // Creates a XImage. |
84 XImage image; | 85 XImage image; |
85 memset(&image, 0, sizeof(image)); | 86 memset(&image, 0, sizeof(image)); |
86 image.width = frame_width_; | 87 image.width = frame->width(); |
87 image.height = frame_height_; | 88 image.height = frame->height(); |
88 image.depth = 32; | 89 image.depth = 32; |
89 image.bits_per_pixel = 32; | 90 image.bits_per_pixel = 32; |
90 image.format = ZPixmap; | 91 image.format = ZPixmap; |
91 image.byte_order = LSBFirst; | 92 image.byte_order = LSBFirst; |
92 image.bitmap_unit = 8; | 93 image.bitmap_unit = 8; |
93 image.bitmap_bit_order = LSBFirst; | 94 image.bitmap_bit_order = LSBFirst; |
94 image.bytes_per_line = frame_->stride(media::VideoFrame::kRGBPlane); | 95 image.bytes_per_line = frame_->stride(media::VideoFrame::kRGBPlane); |
95 image.red_mask = 0xff; | 96 image.red_mask = 0xff; |
96 image.green_mask = 0xff00; | 97 image.green_mask = 0xff00; |
97 image.blue_mask = 0xff0000; | 98 image.blue_mask = 0xff0000; |
98 image.data = reinterpret_cast<char*>( | 99 image.data = reinterpret_cast<char*>( |
99 frame_->data(media::VideoFrame::kRGBPlane)); | 100 frame_->data(media::VideoFrame::kRGBPlane)); |
100 | 101 |
101 // Creates a pixmap and uploads from the XImage. | 102 // Creates a pixmap and uploads from the XImage. |
102 unsigned long pixmap = XCreatePixmap(display_, window_, | 103 unsigned long pixmap = XCreatePixmap(display_, window_, |
103 frame_width_, frame_height_, 32); | 104 frame->width(), frame->height(), 32); |
104 | 105 |
105 GC gc = XCreateGC(display_, pixmap, 0, NULL); | 106 GC gc = XCreateGC(display_, pixmap, 0, NULL); |
106 XPutImage(display_, pixmap, gc, &image, 0, 0, 0, 0, | 107 XPutImage(display_, pixmap, gc, &image, clip.x(), clip.y(), |
107 frame_width_, frame_height_); | 108 clip.x(), clip.y(), clip.width(), clip.height()); |
108 XFreeGC(display_, gc); | 109 XFreeGC(display_, gc); |
109 | 110 |
110 // Creates the picture representing the pixmap. | 111 // Creates the picture representing the pixmap. |
111 XID picture = XRenderCreatePicture( | 112 XID picture = XRenderCreatePicture( |
112 display_, pixmap, | 113 display_, pixmap, |
113 XRenderFindStandardFormat(display_, PictStandardARGB32), | 114 XRenderFindStandardFormat(display_, PictStandardARGB32), |
114 0, NULL); | 115 0, NULL); |
115 | 116 |
116 // Composite the picture over the picture representing the window. | 117 // Composite the picture over the picture representing the window. |
117 XRenderComposite(display_, PictOpSrc, picture, 0, | 118 XRenderComposite(display_, PictOpSrc, picture, 0, |
118 picture_, 0, 0, 0, 0, 0, 0, | 119 picture_, 0, 0, 0, 0, clip.x(), clip.y(), |
119 frame_width_, frame_height_); | 120 clip.width(), clip.height()); |
120 | 121 |
121 XRenderFreePicture(display_, picture); | 122 XRenderFreePicture(display_, picture); |
122 XFreePixmap(display_, pixmap); | 123 XFreePixmap(display_, pixmap); |
123 } | 124 } |
124 | 125 |
125 void X11View::SetSolidFill(uint32 color) { | 126 void X11View::SetSolidFill(uint32 color) { |
126 // TODO(garykac): Implement. | 127 // TODO(garykac): Implement. |
127 // NOTIMPLEMENTED(); | 128 // NOTIMPLEMENTED(); |
128 } | 129 } |
129 | 130 |
130 void X11View::UnsetSolidFill() { | 131 void X11View::UnsetSolidFill() { |
131 // TODO(garykac): Implement. | 132 // TODO(garykac): Implement. |
132 // NOTIMPLEMENTED(); | 133 // NOTIMPLEMENTED(); |
133 } | 134 } |
134 | 135 |
135 void X11View::SetViewport(int x, int y, int width, int height) { | 136 void X11View::SetViewport(int x, int y, int width, int height) { |
136 // TODO(garykac): Implement. | 137 // TODO(garykac): Implement. |
137 // NOTIMPLEMENTED(); | 138 // NOTIMPLEMENTED(); |
138 } | 139 } |
139 | 140 |
140 void X11View::SetHostScreenSize(int width, int height) { | |
141 frame_width_ = width; | |
142 frame_height_ = height; | |
143 frame_ = NULL; | |
144 | |
145 XResizeWindow(display_, window_, frame_width_, frame_height_); | |
146 } | |
147 | |
148 void X11View::InitPaintTarget() { | 141 void X11View::InitPaintTarget() { |
149 // Testing XRender support. | 142 // Testing XRender support. |
150 int dummy; | 143 int dummy; |
151 bool xrender_support = XRenderQueryExtension(display_, &dummy, &dummy); | 144 bool xrender_support = XRenderQueryExtension(display_, &dummy, &dummy); |
152 CHECK(xrender_support) << "XRender is not supported!"; | 145 CHECK(xrender_support) << "XRender is not supported!"; |
153 | 146 |
154 XWindowAttributes attr; | 147 XWindowAttributes attr; |
155 XGetWindowAttributes(display_, window_, &attr); | 148 XGetWindowAttributes(display_, window_, &attr); |
156 | 149 |
157 XRenderPictFormat* pictformat = XRenderFindVisualFormat( | 150 XRenderPictFormat* pictformat = XRenderFindVisualFormat( |
158 display_, | 151 display_, |
159 attr.visual); | 152 attr.visual); |
160 CHECK(pictformat) << "XRENDER does not support default visual"; | 153 CHECK(pictformat) << "XRENDER does not support default visual"; |
161 | 154 |
162 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); | 155 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); |
163 CHECK(picture_) << "Backing picture not created"; | 156 CHECK(picture_) << "Backing picture not created"; |
164 } | 157 } |
165 | 158 |
166 void X11View::HandleBeginUpdateStream(ChromotingHostMessage* msg) { | 159 void X11View::AllocateFrame(media::VideoFrame::Format format, |
167 scoped_ptr<ChromotingHostMessage> deleter(msg); | 160 size_t width, |
| 161 size_t height, |
| 162 base::TimeDelta timestamp, |
| 163 base::TimeDelta duration, |
| 164 scoped_refptr<media::VideoFrame>* frame_out, |
| 165 Task* done) { |
| 166 // TODO(ajwong): Implement this to use the native X window rather than |
| 167 // just a generic frame buffer. |
| 168 media::VideoFrame::CreateFrame(media::VideoFrame::RGB32, |
| 169 width, height, |
| 170 base::TimeDelta(), base::TimeDelta(), |
| 171 frame_out); |
| 172 if (*frame_out) { |
| 173 (*frame_out)->AddRef(); |
| 174 } |
| 175 done->Run(); |
| 176 delete done; |
| 177 } |
168 | 178 |
169 // Make sure the |frame_| is initialized. | 179 void X11View::ReleaseFrame(media::VideoFrame* frame) { |
170 if (!frame_) { | 180 if (frame) { |
171 media::VideoFrame::CreateFrame(media::VideoFrame::RGB32, | 181 LOG(WARNING) << "Frame released."; |
172 frame_width_, frame_height_, | 182 frame->Release(); |
173 base::TimeDelta(), base::TimeDelta(), | |
174 &frame_); | |
175 CHECK(frame_); | |
176 } | 183 } |
177 } | 184 } |
178 | 185 |
179 void X11View::HandleUpdateStreamPacket(ChromotingHostMessage* msg) { | 186 void X11View::OnPartialFrameOutput(media::VideoFrame* frame, |
180 // Lazily initialize the decoder. | 187 UpdatedRects* rects, |
181 SetupDecoder(msg->update_stream_packet().begin_rect().encoding()); | 188 Task* done) { |
182 if (!decoder_->IsStarted()) { | |
183 BeginDecoding(NewRunnableMethod(this, &X11View::OnPartialDecodeDone), | |
184 NewRunnableMethod(this, &X11View::OnDecodeDone)); | |
185 } | |
186 | |
187 Decode(msg); | |
188 } | |
189 | |
190 void X11View::HandleEndUpdateStream(ChromotingHostMessage* msg) { | |
191 scoped_ptr<ChromotingHostMessage> deleter(msg); | |
192 EndDecoding(); | |
193 } | |
194 | |
195 void X11View::OnPartialDecodeDone() { | |
196 // Decoder has produced some output so schedule a paint. We'll get a Paint() | |
197 // call in the near future. Note that we can get UpdateStreamPacket during | |
198 // this short period of time and we will perform decode again and the | |
199 // information in updated rects will be lost. | |
200 // There are several ways to solve this problem. | |
201 // 1. Merge the updated rects and perform one paint. | |
202 // 2. Queue the updated rects and perform two paints. | |
203 // 3. Ignore the updated rects and always paint the full image. Since we | |
204 // use one frame as output this will always be correct. | |
205 // We will take (1) and simply concat the list of rectangles. | |
206 all_update_rects_.insert(all_update_rects_.begin() + | |
207 all_update_rects_.size(), | |
208 update_rects_.begin(), update_rects_.end()); | |
209 | |
210 // TODO(hclam): Make sure we call this method on the right thread. Since | 189 // TODO(hclam): Make sure we call this method on the right thread. Since |
211 // decoder is single-threaded we don't have a problem but we better post | 190 // decoder is single-threaded we don't have a problem but we better post |
212 // a task to do the right thing. | 191 // a task to do the right thing. |
| 192 |
| 193 for (UpdatedRects::iterator it = rects->begin(); it != rects->end(); ++it) { |
| 194 PaintRect(frame, *it); |
| 195 } |
| 196 |
| 197 // TODO(ajwong): Shouldn't we only expose the part of the window that was |
| 198 // damanged? |
213 XEvent event; | 199 XEvent event; |
214 event.type = Expose; | 200 event.type = Expose; |
215 XSendEvent(display_, static_cast<int>(window_), true, ExposureMask, &event); | 201 XSendEvent(display_, static_cast<int>(window_), true, ExposureMask, &event); |
216 } | |
217 | 202 |
218 void X11View::OnDecodeDone() { | 203 done->Run(); |
219 // Since we do synchronous decoding here there's nothing in this method. | 204 delete done; |
220 } | 205 } |
221 | 206 |
222 } // namespace remoting | 207 } // namespace remoting |
OLD | NEW |