summaryrefslogtreecommitdiffstats
path: root/remoting/codec/video_decoder_verbatim.cc
blob: b6b21793cc99e224198c88643e9a459e2f3bdd5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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 {

namespace {
// Both input and output data are assumed to be RGBA32.
const int kBytesPerPixel = 4;
}  // namespace

VideoDecoderVerbatim::VideoDecoderVerbatim()
    : screen_size_(SkISize::Make(0, 0)) {}

VideoDecoderVerbatim::~VideoDecoderVerbatim() {}

bool VideoDecoderVerbatim::IsReadyForData() {
  return true;
}

void VideoDecoderVerbatim::Initialize(const SkISize& screen_size) {
  updated_region_.setEmpty();
  screen_buffer_.reset();

  screen_size_ = screen_size;
  // Allocate the screen buffer, if necessary.
  if (!screen_size_.isEmpty()) {
    screen_buffer_.reset(
        new uint8
            [screen_size_.width() * screen_size_.height() * kBytesPerPixel]);
  }
}

VideoDecoder::DecodeResult VideoDecoderVerbatim::DecodePacket(
    const VideoPacket* packet) {
  SkRegion 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);
    SkIRect rect = SkIRect::MakeXYWH(proto_rect.x(),
                                     proto_rect.y(),
                                     proto_rect.width(),
                                     proto_rect.height());
    region.op(rect, SkRegion::kUnion_Op);

    if (!SkIRect::MakeSize(screen_size_).contains(rect)) {
      LOG(ERROR) << "Invalid packet received";
      return DECODE_ERROR;
    }

    int rect_row_size = kBytesPerPixel * rect.width();
    uint8_t* out = screen_buffer_.get() + rect.y() * stride +
                   rect.x() * kBytesPerPixel;
    for (int y = rect.y(); y < rect.y() + rect.height(); ++y) {
      if (in + rect_row_size > packet->data().data() + packet->data().size()) {
        LOG(ERROR) << "Invalid packet received";
        return DECODE_ERROR;
      }
      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 DECODE_ERROR;
  }

  updated_region_.op(region, SkRegion::kUnion_Op);

  return DECODE_DONE;
}

VideoPacketFormat::Encoding VideoDecoderVerbatim::Encoding() {
  return VideoPacketFormat::ENCODING_VERBATIM;
}

void VideoDecoderVerbatim::Invalidate(const SkISize& view_size,
                                      const SkRegion& region) {
  updated_region_.op(region, SkRegion::kUnion_Op);
}

void VideoDecoderVerbatim::RenderFrame(const SkISize& view_size,
                                       const SkIRect& clip_area,
                                       uint8* image_buffer,
                                       int image_stride,
                                       SkRegion* output_region) {
  output_region->setEmpty();

  // TODO(alexeypa): scaling is not implemented.
  SkIRect clip_rect = SkIRect::MakeSize(screen_size_);
  if (!clip_rect.intersect(clip_area))
    return;

  int screen_stride = screen_size_.width() * kBytesPerPixel;

  for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) {
    SkIRect rect(i.rect());
    if (!rect.intersect(clip_rect))
      continue;

    CopyRGB32Rect(screen_buffer_.get(), screen_stride,
                  clip_rect,
                  image_buffer, image_stride,
                  clip_area,
                  rect);
    output_region->op(rect, SkRegion::kUnion_Op);
  }

  updated_region_.setEmpty();
}

const SkRegion* VideoDecoderVerbatim::GetImageShape() {
  return NULL;
}

}  // namespace remoting