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