| OLD | NEW |
| (Empty) |
| 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/base/encoder_row_based.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "remoting/base/capture_data.h" | |
| 9 #include "remoting/base/compressor_verbatim.h" | |
| 10 #include "remoting/base/compressor_zlib.h" | |
| 11 #include "remoting/base/util.h" | |
| 12 #include "remoting/proto/video.pb.h" | |
| 13 | |
| 14 namespace remoting { | |
| 15 | |
| 16 static const int kPacketSize = 1024 * 1024; | |
| 17 | |
| 18 EncoderRowBased* EncoderRowBased::CreateZlibEncoder() { | |
| 19 return new EncoderRowBased(new CompressorZlib(), | |
| 20 VideoPacketFormat::ENCODING_ZLIB); | |
| 21 } | |
| 22 | |
| 23 EncoderRowBased* EncoderRowBased::CreateZlibEncoder(int packet_size) { | |
| 24 return new EncoderRowBased(new CompressorZlib(), | |
| 25 VideoPacketFormat::ENCODING_ZLIB, | |
| 26 packet_size); | |
| 27 } | |
| 28 | |
| 29 EncoderRowBased* EncoderRowBased::CreateVerbatimEncoder() { | |
| 30 return new EncoderRowBased(new CompressorVerbatim(), | |
| 31 VideoPacketFormat::ENCODING_VERBATIM); | |
| 32 } | |
| 33 | |
| 34 EncoderRowBased* EncoderRowBased::CreateVerbatimEncoder(int packet_size) { | |
| 35 return new EncoderRowBased(new CompressorVerbatim(), | |
| 36 VideoPacketFormat::ENCODING_VERBATIM, | |
| 37 packet_size); | |
| 38 } | |
| 39 | |
| 40 EncoderRowBased::EncoderRowBased(Compressor* compressor, | |
| 41 VideoPacketFormat::Encoding encoding) | |
| 42 : encoding_(encoding), | |
| 43 compressor_(compressor), | |
| 44 screen_size_(SkISize::Make(0,0)), | |
| 45 packet_size_(kPacketSize) { | |
| 46 } | |
| 47 | |
| 48 EncoderRowBased::EncoderRowBased(Compressor* compressor, | |
| 49 VideoPacketFormat::Encoding encoding, | |
| 50 int packet_size) | |
| 51 : encoding_(encoding), | |
| 52 compressor_(compressor), | |
| 53 screen_size_(SkISize::Make(0,0)), | |
| 54 packet_size_(packet_size) { | |
| 55 } | |
| 56 | |
| 57 EncoderRowBased::~EncoderRowBased() {} | |
| 58 | |
| 59 void EncoderRowBased::Encode( | |
| 60 scoped_refptr<CaptureData> capture_data, | |
| 61 bool key_frame, | |
| 62 const DataAvailableCallback& data_available_callback) { | |
| 63 CHECK(capture_data->pixel_format() == media::VideoFrame::RGB32) | |
| 64 << "RowBased Encoder only works with RGB32. Got " | |
| 65 << capture_data->pixel_format(); | |
| 66 capture_data_ = capture_data; | |
| 67 callback_ = data_available_callback; | |
| 68 | |
| 69 const SkRegion& region = capture_data->dirty_region(); | |
| 70 SkRegion::Iterator iter(region); | |
| 71 while (!iter.done()) { | |
| 72 SkIRect rect = iter.rect(); | |
| 73 iter.next(); | |
| 74 EncodeRect(rect, iter.done()); | |
| 75 } | |
| 76 | |
| 77 capture_data_ = NULL; | |
| 78 callback_.Reset(); | |
| 79 } | |
| 80 | |
| 81 void EncoderRowBased::EncodeRect(const SkIRect& rect, bool last) { | |
| 82 CHECK(capture_data_->data_planes().data[0]); | |
| 83 CHECK_EQ(capture_data_->pixel_format(), media::VideoFrame::RGB32); | |
| 84 const int strides = capture_data_->data_planes().strides[0]; | |
| 85 const int bytes_per_pixel = 4; | |
| 86 const int row_size = bytes_per_pixel * rect.width(); | |
| 87 | |
| 88 compressor_->Reset(); | |
| 89 | |
| 90 scoped_ptr<VideoPacket> packet(new VideoPacket()); | |
| 91 PrepareUpdateStart(rect, packet.get()); | |
| 92 const uint8* in = capture_data_->data_planes().data[0] + | |
| 93 rect.fTop * strides + rect.fLeft * bytes_per_pixel; | |
| 94 // TODO(hclam): Fill in the sequence number. | |
| 95 uint8* out = GetOutputBuffer(packet.get(), packet_size_); | |
| 96 int filled = 0; | |
| 97 int row_pos = 0; // Position in the current row in bytes. | |
| 98 int row_y = 0; // Current row. | |
| 99 bool compress_again = true; | |
| 100 while (compress_again) { | |
| 101 // Prepare a message for sending out. | |
| 102 if (!packet.get()) { | |
| 103 packet.reset(new VideoPacket()); | |
| 104 out = GetOutputBuffer(packet.get(), packet_size_); | |
| 105 filled = 0; | |
| 106 } | |
| 107 | |
| 108 Compressor::CompressorFlush flush = Compressor::CompressorNoFlush; | |
| 109 if (row_y == rect.height() - 1) { | |
| 110 flush = Compressor::CompressorFinish; | |
| 111 } | |
| 112 | |
| 113 int consumed = 0; | |
| 114 int written = 0; | |
| 115 compress_again = compressor_->Process(in + row_pos, row_size - row_pos, | |
| 116 out + filled, packet_size_ - filled, | |
| 117 flush, &consumed, &written); | |
| 118 row_pos += consumed; | |
| 119 filled += written; | |
| 120 | |
| 121 // We have reached the end of stream. | |
| 122 if (!compress_again) { | |
| 123 packet->set_flags(packet->flags() | VideoPacket::LAST_PACKET); | |
| 124 packet->set_capture_time_ms(capture_data_->capture_time_ms()); | |
| 125 packet->set_client_sequence_number( | |
| 126 capture_data_->client_sequence_number()); | |
| 127 SkIPoint dpi(capture_data_->dpi()); | |
| 128 if (dpi.x()) | |
| 129 packet->mutable_format()->set_x_dpi(dpi.x()); | |
| 130 if (dpi.y()) | |
| 131 packet->mutable_format()->set_y_dpi(dpi.y()); | |
| 132 if (last) | |
| 133 packet->set_flags(packet->flags() | VideoPacket::LAST_PARTITION); | |
| 134 DCHECK(row_pos == row_size); | |
| 135 DCHECK(row_y == rect.height() - 1); | |
| 136 } | |
| 137 | |
| 138 // If we have filled the message or we have reached the end of stream. | |
| 139 if (filled == packet_size_ || !compress_again) { | |
| 140 packet->mutable_data()->resize(filled); | |
| 141 callback_.Run(packet.Pass()); | |
| 142 } | |
| 143 | |
| 144 // Reached the end of input row and we're not at the last row. | |
| 145 if (row_pos == row_size && row_y < rect.height() - 1) { | |
| 146 row_pos = 0; | |
| 147 in += strides; | |
| 148 ++row_y; | |
| 149 } | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 void EncoderRowBased::PrepareUpdateStart(const SkIRect& rect, | |
| 154 VideoPacket* packet) { | |
| 155 packet->set_flags(packet->flags() | VideoPacket::FIRST_PACKET); | |
| 156 | |
| 157 VideoPacketFormat* format = packet->mutable_format(); | |
| 158 format->set_x(rect.fLeft); | |
| 159 format->set_y(rect.fTop); | |
| 160 format->set_width(rect.width()); | |
| 161 format->set_height(rect.height()); | |
| 162 format->set_encoding(encoding_); | |
| 163 if (capture_data_->size() != screen_size_) { | |
| 164 screen_size_ = capture_data_->size(); | |
| 165 format->set_screen_width(screen_size_.width()); | |
| 166 format->set_screen_height(screen_size_.height()); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 uint8* EncoderRowBased::GetOutputBuffer(VideoPacket* packet, size_t size) { | |
| 171 packet->mutable_data()->resize(size); | |
| 172 // TODO(ajwong): Is there a better way to do this at all??? | |
| 173 return const_cast<uint8*>(reinterpret_cast<const uint8*>( | |
| 174 packet->mutable_data()->data())); | |
| 175 } | |
| 176 | |
| 177 } // namespace remoting | |
| OLD | NEW |