| // 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 "remoting/codec/video_decoder_verbatim.h" |
| |
| #include "base/logging.h" |
| #include "remoting/base/util.h" |
| |
| namespace remoting { |
| |
| VideoDecoderVerbatim::VideoDecoderVerbatim() {} |
| |
| VideoDecoderVerbatim::~VideoDecoderVerbatim() {} |
| |
| void VideoDecoderVerbatim::Initialize(const webrtc::DesktopSize& screen_size) { |
| updated_region_.Clear(); |
| screen_buffer_.reset(); |
| |
| screen_size_ = screen_size; |
| // Allocate the screen buffer, if necessary. |
| if (!screen_size_.is_empty()) { |
| screen_buffer_.reset( |
| new uint8[screen_size_.width() * screen_size_.height() * |
| kBytesPerPixel]); |
| } |
| } |
| |
| bool VideoDecoderVerbatim::DecodePacket(const VideoPacket& packet) { |
| webrtc::DesktopRegion region; |
| |
| const char* in = packet.data().data(); |
| int stride = kBytesPerPixel * screen_size_.width(); |
| for (int i = 0; i < packet.dirty_rects_size(); ++i) { |
| Rect proto_rect = packet.dirty_rects(i); |
| webrtc::DesktopRect rect = |
| webrtc::DesktopRect::MakeXYWH(proto_rect.x(), |
| proto_rect.y(), |
| proto_rect.width(), |
| proto_rect.height()); |
| region.AddRect(rect); |
| |
| if (!DoesRectContain(webrtc::DesktopRect::MakeSize(screen_size_), rect)) { |
| LOG(ERROR) << "Invalid packet received"; |
| return false; |
| } |
| |
| int rect_row_size = kBytesPerPixel * rect.width(); |
| uint8_t* out = screen_buffer_.get() + rect.top() * stride + |
| rect.left() * kBytesPerPixel; |
| for (int y = rect.top(); y < rect.top() + rect.height(); ++y) { |
| if (in + rect_row_size > packet.data().data() + packet.data().size()) { |
| LOG(ERROR) << "Invalid packet received"; |
| return false; |
| } |
| memcpy(out, in, rect_row_size); |
| in += rect_row_size; |
| out += stride; |
| } |
| } |
| |
| if (in != packet.data().data() + packet.data().size()) { |
| LOG(ERROR) << "Invalid packet received"; |
| return false; |
| } |
| |
| updated_region_.AddRegion(region); |
| |
| return true; |
| } |
| |
| void VideoDecoderVerbatim::Invalidate(const webrtc::DesktopSize& view_size, |
| const webrtc::DesktopRegion& region) { |
| updated_region_.AddRegion(region); |
| } |
| |
| void VideoDecoderVerbatim::RenderFrame(const webrtc::DesktopSize& view_size, |
| const webrtc::DesktopRect& clip_area, |
| uint8* image_buffer, |
| int image_stride, |
| webrtc::DesktopRegion* output_region) { |
| output_region->Clear(); |
| |
| // TODO(alexeypa): scaling is not implemented. |
| webrtc::DesktopRect clip_rect = webrtc::DesktopRect::MakeSize(screen_size_); |
| clip_rect.IntersectWith(clip_area); |
| if (clip_rect.is_empty()) |
| return; |
| |
| int screen_stride = screen_size_.width() * kBytesPerPixel; |
| |
| for (webrtc::DesktopRegion::Iterator i(updated_region_); |
| !i.IsAtEnd(); i.Advance()) { |
| webrtc::DesktopRect rect(i.rect()); |
| rect.IntersectWith(clip_rect); |
| if (rect.is_empty()) |
| continue; |
| |
| CopyRGB32Rect(screen_buffer_.get(), screen_stride, |
| clip_rect, |
| image_buffer, image_stride, |
| clip_area, |
| rect); |
| output_region->AddRect(rect); |
| } |
| |
| updated_region_.Clear(); |
| } |
| |
| const webrtc::DesktopRegion* VideoDecoderVerbatim::GetImageShape() { |
| return NULL; |
| } |
| |
| } // namespace remoting |