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 |