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.
4
5 #include "remoting/codec/video_decoder_verbatim.h"
6
7 #include "base/logging.h"
8 #include "remoting/base/util.h"
9
10 namespace remoting {
11
VideoDecoderVerbatim()12 VideoDecoderVerbatim::VideoDecoderVerbatim() {}
13
~VideoDecoderVerbatim()14 VideoDecoderVerbatim::~VideoDecoderVerbatim() {}
15
Initialize(const webrtc::DesktopSize & screen_size)16 void VideoDecoderVerbatim::Initialize(const webrtc::DesktopSize& screen_size) {
17 updated_region_.Clear();
18 screen_buffer_.reset();
19
20 screen_size_ = screen_size;
21 // Allocate the screen buffer, if necessary.
22 if (!screen_size_.is_empty()) {
23 screen_buffer_.reset(
24 new uint8[screen_size_.width() * screen_size_.height() *
25 kBytesPerPixel]);
26 }
27 }
28
DecodePacket(const VideoPacket & packet)29 bool VideoDecoderVerbatim::DecodePacket(const VideoPacket& packet) {
30 webrtc::DesktopRegion region;
31
32 const char* in = packet.data().data();
33 int stride = kBytesPerPixel * screen_size_.width();
34 for (int i = 0; i < packet.dirty_rects_size(); ++i) {
35 Rect proto_rect = packet.dirty_rects(i);
36 webrtc::DesktopRect rect =
37 webrtc::DesktopRect::MakeXYWH(proto_rect.x(),
38 proto_rect.y(),
39 proto_rect.width(),
40 proto_rect.height());
41 region.AddRect(rect);
42
43 if (!DoesRectContain(webrtc::DesktopRect::MakeSize(screen_size_), rect)) {
44 LOG(ERROR) << "Invalid packet received";
45 return false;
46 }
47
48 int rect_row_size = kBytesPerPixel * rect.width();
49 uint8_t* out = screen_buffer_.get() + rect.top() * stride +
50 rect.left() * kBytesPerPixel;
51 for (int y = rect.top(); y < rect.top() + rect.height(); ++y) {
52 if (in + rect_row_size > packet.data().data() + packet.data().size()) {
53 LOG(ERROR) << "Invalid packet received";
54 return false;
55 }
56 memcpy(out, in, rect_row_size);
57 in += rect_row_size;
58 out += stride;
59 }
60 }
61
62 if (in != packet.data().data() + packet.data().size()) {
63 LOG(ERROR) << "Invalid packet received";
64 return false;
65 }
66
67 updated_region_.AddRegion(region);
68
69 return true;
70 }
71
Invalidate(const webrtc::DesktopSize & view_size,const webrtc::DesktopRegion & region)72 void VideoDecoderVerbatim::Invalidate(const webrtc::DesktopSize& view_size,
73 const webrtc::DesktopRegion& region) {
74 updated_region_.AddRegion(region);
75 }
76
RenderFrame(const webrtc::DesktopSize & view_size,const webrtc::DesktopRect & clip_area,uint8 * image_buffer,int image_stride,webrtc::DesktopRegion * output_region)77 void VideoDecoderVerbatim::RenderFrame(const webrtc::DesktopSize& view_size,
78 const webrtc::DesktopRect& clip_area,
79 uint8* image_buffer,
80 int image_stride,
81 webrtc::DesktopRegion* output_region) {
82 output_region->Clear();
83
84 // TODO(alexeypa): scaling is not implemented.
85 webrtc::DesktopRect clip_rect = webrtc::DesktopRect::MakeSize(screen_size_);
86 clip_rect.IntersectWith(clip_area);
87 if (clip_rect.is_empty())
88 return;
89
90 int screen_stride = screen_size_.width() * kBytesPerPixel;
91
92 for (webrtc::DesktopRegion::Iterator i(updated_region_);
93 !i.IsAtEnd(); i.Advance()) {
94 webrtc::DesktopRect rect(i.rect());
95 rect.IntersectWith(clip_rect);
96 if (rect.is_empty())
97 continue;
98
99 CopyRGB32Rect(screen_buffer_.get(), screen_stride,
100 clip_rect,
101 image_buffer, image_stride,
102 clip_area,
103 rect);
104 output_region->AddRect(rect);
105 }
106
107 updated_region_.Clear();
108 }
109
GetImageShape()110 const webrtc::DesktopRegion* VideoDecoderVerbatim::GetImageShape() {
111 return NULL;
112 }
113
114 } // namespace remoting
115