Home | History | Annotate | Download | only in codec
      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 
     12 namespace {
     13 // Both input and output data are assumed to be RGBA32.
     14 const int kBytesPerPixel = 4;
     15 }  // namespace
     16 
     17 
     18 VideoDecoderVerbatim::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 
     26 VideoDecoderVerbatim::~VideoDecoderVerbatim() {
     27 }
     28 
     29 bool 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 
     44 void 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 
     58 VideoDecoder::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 
    114 void 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 
    167 VideoPacketFormat::Encoding VideoDecoderVerbatim::Encoding() {
    168   return VideoPacketFormat::ENCODING_VERBATIM;
    169 }
    170 
    171 void VideoDecoderVerbatim::Invalidate(const SkISize& view_size,
    172                                       const SkRegion& region) {
    173   updated_region_.op(region, SkRegion::kUnion_Op);
    174 }
    175 
    176 void 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 const SkRegion* VideoDecoderVerbatim::GetImageShape() {
    207   return NULL;
    208 }
    209 
    210 }  // namespace remoting
    211