Chromium Code Reviews| 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_verbatim.h" | 5 #include "remoting/codec/video_encoder_verbatim.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
| 9 #include "base/time/time.h" | |
| 9 #include "remoting/base/util.h" | 10 #include "remoting/base/util.h" |
| 10 #include "remoting/proto/video.pb.h" | 11 #include "remoting/proto/video.pb.h" |
| 11 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 12 | 13 |
| 13 namespace remoting { | 14 namespace remoting { |
| 14 | 15 |
| 15 static const int kPacketSize = 1024 * 1024; | 16 static const int kPacketSize = 1024 * 1024; |
| 16 | 17 |
| 17 VideoEncoderVerbatim::VideoEncoderVerbatim() | 18 VideoEncoderVerbatim::VideoEncoderVerbatim() {} |
| 18 : max_packet_size_(kPacketSize) { | 19 VideoEncoderVerbatim::~VideoEncoderVerbatim() {} |
| 19 } | |
| 20 | 20 |
| 21 void VideoEncoderVerbatim::SetMaxPacketSize(int size) { | 21 scoped_ptr<VideoPacket> VideoEncoderVerbatim::Encode( |
| 22 max_packet_size_ = size; | 22 const webrtc::DesktopFrame& frame) { |
| 23 } | 23 CHECK(frame.data()); |
| 24 | 24 |
| 25 VideoEncoderVerbatim::~VideoEncoderVerbatim() { | 25 base::Time encode_start_time = base::Time::Now(); |
| 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()); | 26 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 | 27 |
| 114 VideoPacketFormat* format = packet->mutable_format(); | 28 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); | 29 format->set_encoding(VideoPacketFormat::ENCODING_VERBATIM); |
| 120 if (frame->size().equals(screen_size_)) { | 30 if (!frame.size().equals(screen_size_)) { |
| 121 screen_size_ = frame->size(); | 31 screen_size_ = frame.size(); |
| 122 format->set_screen_width(screen_size_.width()); | 32 format->set_screen_width(screen_size_.width()); |
| 123 format->set_screen_height(screen_size_.height()); | 33 format->set_screen_height(screen_size_.height()); |
| 124 } | 34 } |
| 35 | |
| 36 // Calculate output size. | |
| 37 size_t output_size = 0; | |
| 38 for (webrtc::DesktopRegion::Iterator iter(frame.updated_region()); | |
| 39 !iter.IsAtEnd(); iter.Advance()) { | |
| 40 const webrtc::DesktopRect& rect = iter.rect(); | |
| 41 output_size += rect.width() * rect.height() * | |
| 42 webrtc::DesktopFrame::kBytesPerPixel; | |
| 43 } | |
| 44 | |
| 45 uint8_t* out = GetOutputBuffer(packet.get(), output_size); | |
| 46 const int stride = frame.stride(); | |
|
Wez
2013/09/12 14:20:15
nit: in_stride?
Sergey Ulanov
2013/09/12 19:18:45
Done.
| |
| 47 | |
| 48 // Store all changed rectangles in the packet. | |
| 49 for (webrtc::DesktopRegion::Iterator iter(frame.updated_region()); | |
| 50 !iter.IsAtEnd(); iter.Advance()) { | |
| 51 const webrtc::DesktopRect& rect = iter.rect(); | |
| 52 const int row_size = webrtc::DesktopFrame::kBytesPerPixel * rect.width(); | |
|
Wez
2013/09/12 14:20:15
nit: row_bytes or out_stride?
Sergey Ulanov
2013/09/12 19:18:45
there is no out_stride, because it's not a single
Wez
2013/09/13 11:12:21
Strictly no, but while processing a given rect |ou
| |
| 53 const uint8_t* in = frame.data() + rect.top() * stride + | |
| 54 rect.left() * webrtc::DesktopFrame::kBytesPerPixel; | |
| 55 for (int y = rect.top(); y < rect.top() + rect.height(); ++y) { | |
| 56 memcpy(out, in, row_size); | |
| 57 out += row_size; | |
| 58 in += stride; | |
| 59 } | |
| 60 | |
| 61 Rect* dirty_rect = packet->add_dirty_rects(); | |
| 62 dirty_rect->set_x(rect.left()); | |
| 63 dirty_rect->set_y(rect.top()); | |
| 64 dirty_rect->set_width(rect.width()); | |
| 65 dirty_rect->set_height(rect.height()); | |
| 66 } | |
| 67 | |
| 68 packet->set_flags(VideoPacket::FIRST_PACKET | VideoPacket::LAST_PACKET); | |
| 69 packet->set_capture_time_ms(frame.capture_time_ms()); | |
| 70 packet->set_encode_time_ms( | |
| 71 (base::Time::Now() - encode_start_time).InMillisecondsRoundedUp()); | |
| 72 if (!frame.dpi().is_zero()) { | |
| 73 packet->mutable_format()->set_x_dpi(frame.dpi().x()); | |
| 74 packet->mutable_format()->set_y_dpi(frame.dpi().y()); | |
| 75 } | |
| 76 packet->set_flags(packet->flags() | VideoPacket::LAST_PARTITION); | |
|
Wez
2013/09/12 14:20:15
nit: Merge this into the earlier set_flags() call.
Sergey Ulanov
2013/09/12 19:18:45
Done.
| |
| 77 | |
| 78 return packet.Pass(); | |
| 125 } | 79 } |
| 126 | 80 |
| 127 uint8* VideoEncoderVerbatim::GetOutputBuffer(VideoPacket* packet, size_t size) { | 81 uint8_t* VideoEncoderVerbatim::GetOutputBuffer(VideoPacket* packet, |
| 82 size_t size) { | |
| 128 packet->mutable_data()->resize(size); | 83 packet->mutable_data()->resize(size); |
| 129 return reinterpret_cast<uint8*>(string_as_array(packet->mutable_data())); | 84 return reinterpret_cast<uint8_t*>(string_as_array(packet->mutable_data())); |
| 130 } | 85 } |
| 131 | 86 |
| 132 } // namespace remoting | 87 } // namespace remoting |
| OLD | NEW |