summaryrefslogtreecommitdiffstats
path: root/remoting/host/video_frame_capturer_win.cc
diff options
context:
space:
mode:
authoralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-10 05:00:14 +0000
committeralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-10 05:00:14 +0000
commit3c2a701bb59b792becab4496d6dfa8fb2e891085 (patch)
tree86acff92d453e09f9435355bb3787ff6d7f27e79 /remoting/host/video_frame_capturer_win.cc
parent293a0ee99b970d702c25279616ba9d7d9485bb36 (diff)
downloadchromium_src-3c2a701bb59b792becab4496d6dfa8fb2e891085.zip
chromium_src-3c2a701bb59b792becab4496d6dfa8fb2e891085.tar.gz
chromium_src-3c2a701bb59b792becab4496d6dfa8fb2e891085.tar.bz2
Brushing up video capturers to make them more uniform.
- Video frame buffers are derived from common VideoFrameBuffer class (a data structure really). - The video frame queue logic was moved to VideoFrameCapturerQueue class. BUG=134694 Review URL: https://chromiumcodereview.appspot.com/11369120 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167058 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host/video_frame_capturer_win.cc')
-rw-r--r--remoting/host/video_frame_capturer_win.cc268
1 files changed, 124 insertions, 144 deletions
diff --git a/remoting/host/video_frame_capturer_win.cc b/remoting/host/video_frame_capturer_win.cc
index 8d33620..3386c11 100644
--- a/remoting/host/video_frame_capturer_win.cc
+++ b/remoting/host/video_frame_capturer_win.cc
@@ -15,7 +15,9 @@
#include "base/win/scoped_hdc.h"
#include "remoting/base/capture_data.h"
#include "remoting/host/differ.h"
+#include "remoting/host/video_frame.h"
#include "remoting/host/video_frame_capturer_helper.h"
+#include "remoting/host/video_frame_queue.h"
#include "remoting/host/win/desktop.h"
#include "remoting/host/win/scoped_thread_desktop.h"
#include "remoting/proto/control.pb.h"
@@ -38,6 +40,22 @@ const uint32 kPixelBgraBlack = 0xff000000;
const uint32 kPixelBgraWhite = 0xffffffff;
const uint32 kPixelBgraTransparent = 0x00000000;
+// A class representing a full-frame pixel buffer.
+class VideoFrameWin : public VideoFrame {
+ public:
+ VideoFrameWin(HDC desktop_dc, const SkISize& size);
+ virtual ~VideoFrameWin();
+
+ // Returns handle of the device independent bitmap representing this frame
+ // buffer to GDI.
+ HBITMAP GetBitmap();
+
+ private:
+ base::win::ScopedBitmap bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoFrameWin);
+};
+
// VideoFrameCapturerWin captures 32bit RGB using GDI.
//
// VideoFrameCapturerWin is double-buffered as required by VideoFrameCapturer.
@@ -56,33 +74,14 @@ class VideoFrameCapturerWin : public VideoFrameCapturer {
virtual const SkISize& size_most_recent() const OVERRIDE;
private:
- struct VideoFrameBuffer {
- VideoFrameBuffer();
-
- void* data;
- SkISize size;
- int bytes_per_pixel;
- int bytes_per_row;
- int resource_generation;
- };
-
- // Make sure that the device contexts and the current buffer match the screen
- // configuration.
+ // Make sure that the device contexts match the screen configuration.
void PrepareCaptureResources();
- // Allocates the specified capture buffer using the current device contexts
- // and desktop dimensions, releasing any pre-existing buffer.
- void AllocateBuffer(int buffer_index, int resource_generation);
-
- // Compares the most recently captured screen contents with the previous
- // contents reported to the caller, to determine the dirty region.
- void CalculateInvalidRegion();
-
// Creates a CaptureData instance wrapping the current framebuffer and
// notifies |delegate_|.
void CaptureRegion(const SkRegion& region);
- // Captures the current screen contents into the next available framebuffer.
+ // Captures the current screen contents into the current buffer.
void CaptureImage();
// Expand the cursor shape to add a white outline for visibility against
@@ -104,24 +103,18 @@ class VideoFrameCapturerWin : public VideoFrameCapturer {
scoped_array<uint8> last_cursor_;
SkISize last_cursor_size_;
- // There are two buffers for the screen images, as required by Capturer.
- static const int kNumBuffers = 2;
- VideoFrameBuffer buffers_[kNumBuffers];
+ // Queue of the frames buffers.
+ VideoFrameQueue queue_;
ScopedThreadDesktop desktop_;
// GDI resources used for screen capture.
scoped_ptr<base::win::ScopedGetDC> desktop_dc_;
base::win::ScopedCreateDC memory_dc_;
- base::win::ScopedBitmap target_bitmap_[kNumBuffers];
- int resource_generation_;
// Rectangle describing the bounds of the desktop device context.
SkIRect desktop_dc_rect_;
- // The current buffer with valid data for reading.
- int current_buffer_;
-
// Format of pixels returned in buffer.
media::VideoFrame::Format pixel_format_;
@@ -139,20 +132,46 @@ static const int kPixelsPerMeter = 3780;
// 32 bit RGBA is 4 bytes per pixel.
static const int kBytesPerPixel = 4;
-VideoFrameCapturerWin::VideoFrameBuffer::VideoFrameBuffer()
- : data(NULL),
- size(SkISize::Make(0, 0)),
- bytes_per_pixel(0),
- bytes_per_row(0),
- resource_generation(0) {
+VideoFrameWin::VideoFrameWin(HDC desktop_dc, const SkISize& size) {
+ // Describe a device independent bitmap (DIB) that is the size of the desktop.
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biHeight = -size.height();
+ bmi.bmiHeader.biWidth = size.width();
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = kBytesPerPixel * 8;
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ int bytes_per_row = size.width() * kBytesPerPixel;
+ bmi.bmiHeader.biSizeImage = bytes_per_row * size.height();
+ bmi.bmiHeader.biXPelsPerMeter = kPixelsPerMeter;
+ bmi.bmiHeader.biYPelsPerMeter = kPixelsPerMeter;
+
+ // Create the DIB, and store a pointer to its pixel buffer.
+ void* data = NULL;
+ bitmap_ = CreateDIBSection(desktop_dc, &bmi, DIB_RGB_COLORS, &data, NULL, 0);
+
+ // TODO(wez): Cope gracefully with failure (crbug.com/157170).
+ CHECK(bitmap_ != NULL);
+ CHECK(data != NULL);
+
+ set_pixels(reinterpret_cast<uint8*>(data));
+ set_dimensions(SkISize::Make(bmi.bmiHeader.biWidth,
+ std::abs(bmi.bmiHeader.biHeight)));
+ set_bytes_per_row(
+ bmi.bmiHeader.biSizeImage / std::abs(bmi.bmiHeader.biHeight));
+}
+
+VideoFrameWin::~VideoFrameWin() {
+}
+
+HBITMAP VideoFrameWin::GetBitmap() {
+ return bitmap_;
}
VideoFrameCapturerWin::VideoFrameCapturerWin()
: delegate_(NULL),
last_cursor_size_(SkISize::Make(0, 0)),
desktop_dc_rect_(SkIRect::MakeEmpty()),
- resource_generation_(0),
- current_buffer_(0),
pixel_format_(media::VideoFrame::RGB32),
composition_func_(NULL) {
}
@@ -172,8 +191,39 @@ void VideoFrameCapturerWin::CaptureInvalidRegion() {
// Force the system to power-up display hardware, if it has been suspended.
SetThreadExecutionState(ES_DISPLAY_REQUIRED);
- // Perform the capture.
- CalculateInvalidRegion();
+ // Make sure the GDI capture resources are up-to-date.
+ PrepareCaptureResources();
+
+ // Copy screen bits to the current buffer.
+ CaptureImage();
+
+ const VideoFrame* current_buffer = queue_.current_frame();
+ const VideoFrame* last_buffer = queue_.previous_frame();
+ if (last_buffer) {
+ // Make sure the differencer is set up correctly for these previous and
+ // current screens.
+ if (!differ_.get() ||
+ (differ_->width() != current_buffer->dimensions().width()) ||
+ (differ_->height() != current_buffer->dimensions().height()) ||
+ (differ_->bytes_per_row() != current_buffer->bytes_per_row())) {
+ differ_.reset(new Differ(current_buffer->dimensions().width(),
+ current_buffer->dimensions().height(),
+ kBytesPerPixel,
+ current_buffer->bytes_per_row()));
+ }
+
+ // Calculate difference between the two last captured frames.
+ SkRegion region;
+ differ_->CalcDirtyRegion(last_buffer->pixels(), current_buffer->pixels(),
+ &region);
+ InvalidateRegion(region);
+ } else {
+ // No previous frame is available. Invalidate the whole screen.
+ helper_.InvalidateScreen(current_buffer->dimensions());
+ }
+
+ // Wrap the captured frame into CaptureData structure and invoke
+ // the completion callback.
SkRegion invalid_region;
helper_.SwapInvalidRegion(&invalid_region);
CaptureRegion(invalid_region);
@@ -246,137 +296,67 @@ void VideoFrameCapturerWin::PrepareCaptureResources() {
desktop_dc_rect_.setEmpty();
}
- // Create GDI device contexts to capture from the desktop into memory, and
- // allocate buffers to capture into.
if (desktop_dc_.get() == NULL) {
DCHECK(memory_dc_.Get() == NULL);
+ // Create GDI device contexts to capture from the desktop into memory.
desktop_dc_.reset(new base::win::ScopedGetDC(NULL));
memory_dc_.Set(CreateCompatibleDC(*desktop_dc_));
desktop_dc_rect_ = screen_rect;
- ++resource_generation_;
- }
+ // Make sure the frame buffers will be reallocated.
+ queue_.SetAllFramesNeedUpdate();
- // If the current buffer is from an older generation then allocate a new one.
- // Note that we can't reallocate other buffers at this point, since the caller
- // may still be reading from them.
- if (resource_generation_ != buffers_[current_buffer_].resource_generation) {
- AllocateBuffer(current_buffer_, resource_generation_);
-
- SkRegion region;
- region.op(SkIRect::MakeSize(helper_.size_most_recent()),
- SkRegion::kUnion_Op);
- InvalidateRegion(region);
- }
-}
-
-void VideoFrameCapturerWin::AllocateBuffer(int buffer_index,
- int resource_generation) {
- DCHECK(desktop_dc_.get() != NULL);
- DCHECK(memory_dc_.Get() != NULL);
- // Windows requires DIB sections' rows to start DWORD-aligned, which is
- // implicit when working with RGB32 pixels.
- DCHECK_EQ(pixel_format_, media::VideoFrame::RGB32);
-
- // Describe a device independent bitmap (DIB) that is the size of the desktop.
- BITMAPINFO bmi;
- memset(&bmi, 0, sizeof(bmi));
- bmi.bmiHeader.biHeight = -desktop_dc_rect_.height();
- bmi.bmiHeader.biWidth = desktop_dc_rect_.width();
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = kBytesPerPixel * 8;
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- int bytes_per_row = desktop_dc_rect_.width() * kBytesPerPixel;
- bmi.bmiHeader.biSizeImage = bytes_per_row * desktop_dc_rect_.height();
- bmi.bmiHeader.biXPelsPerMeter = kPixelsPerMeter;
- bmi.bmiHeader.biYPelsPerMeter = kPixelsPerMeter;
-
- // Create the DIB, and store a pointer to its pixel buffer.
- target_bitmap_[buffer_index] =
- CreateDIBSection(*desktop_dc_, &bmi, DIB_RGB_COLORS,
- static_cast<void**>(&buffers_[buffer_index].data),
- NULL, 0);
-
- // TODO(wez): Cope gracefully with failure (crbug.com/157170).
- CHECK(target_bitmap_[buffer_index] != NULL);
- CHECK(buffers_[buffer_index].data != NULL);
-
- buffers_[buffer_index].size = SkISize::Make(bmi.bmiHeader.biWidth,
- std::abs(bmi.bmiHeader.biHeight));
- buffers_[buffer_index].bytes_per_pixel = bmi.bmiHeader.biBitCount / 8;
- buffers_[buffer_index].bytes_per_row =
- bmi.bmiHeader.biSizeImage / std::abs(bmi.bmiHeader.biHeight);
- buffers_[buffer_index].resource_generation = resource_generation;
-}
-
-void VideoFrameCapturerWin::CalculateInvalidRegion() {
- CaptureImage();
-
- const VideoFrameBuffer& current = buffers_[current_buffer_];
-
- // Find the previous and current screens.
- int prev_buffer_id = current_buffer_ - 1;
- if (prev_buffer_id < 0) {
- prev_buffer_id = kNumBuffers - 1;
- }
- const VideoFrameBuffer& prev = buffers_[prev_buffer_id];
-
- // Maybe the previous and current screens can't be differenced.
- if ((current.size != prev.size) ||
- (current.bytes_per_pixel != prev.bytes_per_pixel) ||
- (current.bytes_per_row != prev.bytes_per_row)) {
- helper_.InvalidateScreen(current.size);
- return;
- }
-
- // Make sure the differencer is set up correctly for these previous and
- // current screens.
- if (!differ_.get() ||
- (differ_->width() != current.size.width()) ||
- (differ_->height() != current.size.height()) ||
- (differ_->bytes_per_pixel() != current.bytes_per_pixel) ||
- (differ_->bytes_per_row() != current.bytes_per_row)) {
- differ_.reset(new Differ(current.size.width(), current.size.height(),
- current.bytes_per_pixel, current.bytes_per_row));
+ helper_.ClearInvalidRegion();
}
-
- SkRegion region;
- differ_->CalcDirtyRegion(prev.data, current.data, &region);
-
- InvalidateRegion(region);
}
void VideoFrameCapturerWin::CaptureRegion(const SkRegion& region) {
- const VideoFrameBuffer& buffer = buffers_[current_buffer_];
- current_buffer_ = (current_buffer_ + 1) % kNumBuffers;
+ const VideoFrame* current_buffer = queue_.current_frame();
DataPlanes planes;
- planes.data[0] = static_cast<uint8*>(buffer.data);
- planes.strides[0] = buffer.bytes_per_row;
+ planes.data[0] = current_buffer->pixels();
+ planes.strides[0] = current_buffer->bytes_per_row();
scoped_refptr<CaptureData> data(new CaptureData(planes,
- buffer.size,
+ current_buffer->dimensions(),
pixel_format_));
data->mutable_dirty_region() = region;
helper_.set_size_most_recent(data->size());
+ queue_.DoneWithCurrentFrame();
delegate_->OnCaptureCompleted(data);
}
void VideoFrameCapturerWin::CaptureImage() {
- // Make sure the GDI capture resources are up-to-date.
- PrepareCaptureResources();
-
- // Select the target bitmap into the memory dc.
- SelectObject(memory_dc_, target_bitmap_[current_buffer_]);
+ // If the current buffer is from an older generation then allocate a new one.
+ // Note that we can't reallocate other buffers at this point, since the caller
+ // may still be reading from them.
+ if (queue_.current_frame_needs_update()) {
+ DCHECK(desktop_dc_.get() != NULL);
+ DCHECK(memory_dc_.Get() != NULL);
+ // Windows requires DIB sections' rows to start DWORD-aligned, which is
+ // implicit when working with RGB32 pixels.
+ DCHECK_EQ(pixel_format_, media::VideoFrame::RGB32);
+
+ SkISize size = SkISize::Make(desktop_dc_rect_.width(),
+ desktop_dc_rect_.height());
+ scoped_ptr<VideoFrameWin> buffer(new VideoFrameWin(*desktop_dc_, size));
+ queue_.ReplaceCurrentFrame(buffer.PassAs<VideoFrame>());
+ }
- // And then copy the rect from desktop to memory.
- BitBlt(memory_dc_, 0, 0, buffers_[current_buffer_].size.width(),
- buffers_[current_buffer_].size.height(), *desktop_dc_,
- desktop_dc_rect_.x(), desktop_dc_rect_.y(),
- SRCCOPY | CAPTUREBLT);
+ // Select the target bitmap into the memory dc and copy the rect from desktop
+ // to memory.
+ VideoFrameWin* current =
+ static_cast<VideoFrameWin*>(queue_.current_frame());
+ if (SelectObject(memory_dc_, current->GetBitmap()) != NULL) {
+ BitBlt(memory_dc_,
+ 0, 0, desktop_dc_rect_.width(), desktop_dc_rect_.height(),
+ *desktop_dc_,
+ desktop_dc_rect_.x(), desktop_dc_rect_.y(),
+ SRCCOPY | CAPTUREBLT);
+ }
}
void VideoFrameCapturerWin::AddCursorOutline(int width,