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_encoder_verbatim.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/stl_util.h"
      9 #include "remoting/base/util.h"
     10 #include "remoting/proto/video.pb.h"
     11 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
     12 
     13 namespace remoting {
     14 
     15 static const int kPacketSize = 1024 * 1024;
     16 
     17 VideoEncoderVerbatim::VideoEncoderVerbatim()
     18     : max_packet_size_(kPacketSize) {
     19 }
     20 
     21 void VideoEncoderVerbatim::SetMaxPacketSize(int size) {
     22   max_packet_size_ = size;
     23 }
     24 
     25 VideoEncoderVerbatim::~VideoEncoderVerbatim() {
     26 }
     27 
     28 void VideoEncoderVerbatim::Encode(
     29     const webrtc::DesktopFrame* frame,
     30     const DataAvailableCallback& data_available_callback) {
     31   callback_ = data_available_callback;
     32   encode_start_time_ = base::Time::Now();
     33 
     34   webrtc::DesktopRegion::Iterator iter(frame->updated_region());
     35   while (!iter.IsAtEnd()) {
     36     const webrtc::DesktopRect& rect = iter.rect();
     37     iter.Advance();
     38     EncodeRect(frame, rect, iter.IsAtEnd());
     39   }
     40 
     41   callback_.Reset();
     42 }
     43 
     44 void VideoEncoderVerbatim::EncodeRect(const webrtc::DesktopFrame* frame,
     45                                       const webrtc::DesktopRect& rect,
     46                                       bool last) {
     47   CHECK(frame->data());
     48   const int stride = frame->stride();
     49   const int bytes_per_pixel = 4;
     50   const int row_size = bytes_per_pixel * rect.width();
     51 
     52   scoped_ptr<VideoPacket> packet(new VideoPacket());
     53   PrepareUpdateStart(frame, rect, packet.get());
     54   const uint8* in = frame->data() +
     55       rect.top() * stride + rect.left() * bytes_per_pixel;
     56   // TODO(hclam): Fill in the sequence number.
     57   uint8* out = GetOutputBuffer(packet.get(), max_packet_size_);
     58   int filled = 0;
     59   int row_pos = 0;  // Position in the current row in bytes.
     60   int row_y = 0;  // Current row.
     61   while (row_y < rect.height()) {
     62     // Prepare a message for sending out.
     63     if (!packet.get()) {
     64       packet.reset(new VideoPacket());
     65       out = GetOutputBuffer(packet.get(), max_packet_size_);
     66       filled = 0;
     67     }
     68 
     69     if (row_y < rect.height()) {
     70       int bytes_to_copy =
     71           std::min(row_size - row_pos, max_packet_size_ - filled);
     72       memcpy(out + filled, in + row_pos, bytes_to_copy);
     73       row_pos += bytes_to_copy;
     74       filled += bytes_to_copy;
     75 
     76       // Jump to the next row when we've reached the end of the current row.
     77       if (row_pos == row_size) {
     78         row_pos = 0;
     79         in += stride;
     80         ++row_y;
     81       }
     82     }
     83 
     84     if (row_y == rect.height()) {
     85       DCHECK_EQ(row_pos, 0);
     86 
     87       packet->mutable_data()->resize(filled);
     88       packet->set_flags(packet->flags() | VideoPacket::LAST_PACKET);
     89 
     90       packet->set_capture_time_ms(frame->capture_time_ms());
     91       packet->set_encode_time_ms(
     92           (base::Time::Now() - encode_start_time_).InMillisecondsRoundedUp());
     93       if (!frame->dpi().is_zero()) {
     94         packet->mutable_format()->set_x_dpi(frame->dpi().x());
     95         packet->mutable_format()->set_y_dpi(frame->dpi().y());
     96       }
     97       if (last)
     98         packet->set_flags(packet->flags() | VideoPacket::LAST_PARTITION);
     99     }
    100 
    101     // If we have filled the current packet, then send it.
    102     if (filled == max_packet_size_ || row_y == rect.height()) {
    103       packet->mutable_data()->resize(filled);
    104       callback_.Run(packet.Pass());
    105     }
    106   }
    107 }
    108 
    109 void VideoEncoderVerbatim::PrepareUpdateStart(const webrtc::DesktopFrame* frame,
    110                                               const webrtc::DesktopRect& rect,
    111                                               VideoPacket* packet) {
    112   packet->set_flags(packet->flags() | VideoPacket::FIRST_PACKET);
    113 
    114   VideoPacketFormat* format = packet->mutable_format();
    115   format->set_x(rect.left());
    116   format->set_y(rect.top());
    117   format->set_width(rect.width());
    118   format->set_height(rect.height());
    119   format->set_encoding(VideoPacketFormat::ENCODING_VERBATIM);
    120   if (frame->size().equals(screen_size_)) {
    121     screen_size_ = frame->size();
    122     format->set_screen_width(screen_size_.width());
    123     format->set_screen_height(screen_size_.height());
    124   }
    125 }
    126 
    127 uint8* VideoEncoderVerbatim::GetOutputBuffer(VideoPacket* packet, size_t size) {
    128   packet->mutable_data()->resize(size);
    129   return reinterpret_cast<uint8*>(string_as_array(packet->mutable_data()));
    130 }
    131 
    132 }  // namespace remoting
    133