video_decoder_verbatim.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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
10namespace remoting {
11
12namespace {
13// Both input and output data are assumed to be RGBA32.
14const int kBytesPerPixel = 4;
15}  // namespace
16
17
18VideoDecoderVerbatim::VideoDecoderVerbatim()
19    : state_(kUninitialized),
20      clip_(SkIRect::MakeEmpty()),
21      row_pos_(0),
22      row_y_(0),
23      screen_size_(SkISize::Make(0, 0)) {
24}
25
26VideoDecoderVerbatim::~VideoDecoderVerbatim() {
27}
28
29bool VideoDecoderVerbatim::IsReadyForData() {
30  switch (state_) {
31    case kUninitialized:
32    case kError:
33      return false;
34    case kReady:
35    case kProcessing:
36    case kPartitionDone:
37    case kDone:
38      return true;
39  }
40  NOTREACHED();
41  return false;
42}
43
44void VideoDecoderVerbatim::Initialize(const SkISize& screen_size) {
45  updated_region_.setEmpty();
46  screen_buffer_.reset();
47
48  screen_size_ = screen_size;
49  // Allocate the screen buffer, if necessary.
50  if (!screen_size_.isEmpty()) {
51    screen_buffer_.reset(new uint8[
52        screen_size_.width() * screen_size_.height() * kBytesPerPixel]);
53  }
54
55  state_ = kReady;
56}
57
58VideoDecoder::DecodeResult VideoDecoderVerbatim::DecodePacket(
59    const VideoPacket* packet) {
60  UpdateStateForPacket(packet);
61
62  if (state_ == kError) {
63    return DECODE_ERROR;
64  }
65
66  const uint8* in = reinterpret_cast<const uint8*>(packet->data().data());
67  const int in_size = packet->data().size();
68  const int row_size = clip_.width() * kBytesPerPixel;
69
70  int out_stride = screen_size_.width() * kBytesPerPixel;
71  uint8* out = screen_buffer_.get() + out_stride * (clip_.top() + row_y_) +
72      kBytesPerPixel * clip_.left();
73
74  // Consume all the data in the message.
75  int used = 0;
76  while (used < in_size) {
77    if (row_y_ >= clip_.height()) {
78      state_ = kError;
79      LOG(WARNING) << "Too much data is received for the given rectangle.";
80      return DECODE_ERROR;
81    }
82
83    int bytes_to_copy = std::min(in_size - used, row_size - row_pos_);
84    memcpy(out + row_pos_, in + used, bytes_to_copy);
85
86    used += bytes_to_copy;
87    row_pos_ += bytes_to_copy;
88
89    // If this row is completely filled then move onto the next row.
90    if (row_pos_ == row_size) {
91      ++row_y_;
92      row_pos_ = 0;
93      out += out_stride;
94    }
95  }
96
97  if (state_ == kPartitionDone || state_ == kDone) {
98    if (row_y_ < clip_.height()) {
99      state_ = kError;
100      LOG(WARNING) << "Received LAST_PACKET, but didn't get enough data.";
101      return DECODE_ERROR;
102    }
103
104    updated_region_.op(clip_, SkRegion::kUnion_Op);
105  }
106
107  if (state_ == kDone) {
108    return DECODE_DONE;
109  } else {
110    return DECODE_IN_PROGRESS;
111  }
112}
113
114void VideoDecoderVerbatim::UpdateStateForPacket(const VideoPacket* packet) {
115  if (state_ == kError) {
116    return;
117  }
118
119  if (packet->flags() & VideoPacket::FIRST_PACKET) {
120    if (state_ != kReady && state_ != kDone && state_ != kPartitionDone) {
121      state_ = kError;
122      LOG(WARNING) << "Received unexpected FIRST_PACKET.";
123      return;
124    }
125
126    // Reset the buffer location status variables on the first packet.
127    clip_.setXYWH(packet->format().x(), packet->format().y(),
128                  packet->format().width(), packet->format().height());
129    if (!SkIRect::MakeSize(screen_size_).contains(clip_)) {
130      state_ = kError;
131      LOG(WARNING) << "Invalid clipping area received.";
132      return;
133    }
134
135    state_ = kProcessing;
136    row_pos_ = 0;
137    row_y_ = 0;
138  }
139
140  if (state_ != kProcessing) {
141    state_ = kError;
142    LOG(WARNING) << "Received unexpected packet.";
143    return;
144  }
145
146  if (packet->flags() & VideoPacket::LAST_PACKET) {
147    if (state_ != kProcessing) {
148      state_ = kError;
149      LOG(WARNING) << "Received unexpected LAST_PACKET.";
150      return;
151    }
152    state_ = kPartitionDone;
153  }
154
155  if (packet->flags() & VideoPacket::LAST_PARTITION) {
156    if (state_ != kPartitionDone) {
157      state_ = kError;
158      LOG(WARNING) << "Received unexpected LAST_PARTITION.";
159      return;
160    }
161    state_ = kDone;
162  }
163
164  return;
165}
166
167VideoPacketFormat::Encoding VideoDecoderVerbatim::Encoding() {
168  return VideoPacketFormat::ENCODING_VERBATIM;
169}
170
171void VideoDecoderVerbatim::Invalidate(const SkISize& view_size,
172                                      const SkRegion& region) {
173  updated_region_.op(region, SkRegion::kUnion_Op);
174}
175
176void VideoDecoderVerbatim::RenderFrame(const SkISize& view_size,
177                                       const SkIRect& clip_area,
178                                       uint8* image_buffer,
179                                       int image_stride,
180                                       SkRegion* output_region) {
181  output_region->setEmpty();
182
183  // TODO(alexeypa): scaling is not implemented.
184  SkIRect clip_rect = SkIRect::MakeSize(screen_size_);
185  if (!clip_rect.intersect(clip_area))
186    return;
187
188  int screen_stride = screen_size_.width() * kBytesPerPixel;
189
190  for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) {
191    SkIRect rect(i.rect());
192    if (!rect.intersect(clip_rect))
193      continue;
194
195    CopyRGB32Rect(screen_buffer_.get(), screen_stride,
196                  clip_rect,
197                  image_buffer, image_stride,
198                  clip_area,
199                  rect);
200    output_region->op(rect, SkRegion::kUnion_Op);
201  }
202
203  updated_region_.setEmpty();
204}
205
206}  // namespace remoting
207