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 13namespace remoting { 14 15static const int kPacketSize = 1024 * 1024; 16 17VideoEncoderVerbatim::VideoEncoderVerbatim() 18 : max_packet_size_(kPacketSize) { 19} 20 21void VideoEncoderVerbatim::SetMaxPacketSize(int size) { 22 max_packet_size_ = size; 23} 24 25VideoEncoderVerbatim::~VideoEncoderVerbatim() { 26} 27 28void 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 44void 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 109void 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 127uint8* 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