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.
5 #include "remoting/codec/video_encoder_verbatim.h"
7 #include "base/logging.h"
8 #include "media/video/capture/screen/screen_capture_data.h"
9 #include "remoting/base/util.h"
10 #include "remoting/proto/video.pb.h"
14 static const int kPacketSize
= 1024 * 1024;
16 VideoEncoderVerbatim::VideoEncoderVerbatim()
17 : screen_size_(SkISize::Make(0,0)),
18 max_packet_size_(kPacketSize
) {
21 void VideoEncoderVerbatim::SetMaxPacketSize(int size
) {
22 max_packet_size_
= size
;
25 VideoEncoderVerbatim::~VideoEncoderVerbatim() {
28 void VideoEncoderVerbatim::Encode(
29 scoped_refptr
<media::ScreenCaptureData
> capture_data
,
31 const DataAvailableCallback
& data_available_callback
) {
32 capture_data_
= capture_data
;
33 callback_
= data_available_callback
;
34 encode_start_time_
= base::Time::Now();
36 const SkRegion
& region
= capture_data
->dirty_region();
37 SkRegion::Iterator
iter(region
);
38 while (!iter
.done()) {
39 SkIRect rect
= iter
.rect();
41 EncodeRect(rect
, iter
.done());
48 void VideoEncoderVerbatim::EncodeRect(const SkIRect
& rect
, bool last
) {
49 CHECK(capture_data_
->data());
50 const int stride
= capture_data_
->stride();
51 const int bytes_per_pixel
= 4;
52 const int row_size
= bytes_per_pixel
* rect
.width();
54 scoped_ptr
<VideoPacket
> packet(new VideoPacket());
55 PrepareUpdateStart(rect
, packet
.get());
56 const uint8
* in
= capture_data_
->data() +
57 rect
.fTop
* stride
+ rect
.fLeft
* bytes_per_pixel
;
58 // TODO(hclam): Fill in the sequence number.
59 uint8
* out
= GetOutputBuffer(packet
.get(), max_packet_size_
);
61 int row_pos
= 0; // Position in the current row in bytes.
62 int row_y
= 0; // Current row.
63 while (row_y
< rect
.height()) {
64 // Prepare a message for sending out.
66 packet
.reset(new VideoPacket());
67 out
= GetOutputBuffer(packet
.get(), max_packet_size_
);
71 if (row_y
< rect
.height()) {
73 std::min(row_size
- row_pos
, max_packet_size_
- filled
);
74 memcpy(out
+ filled
, in
+ row_pos
, bytes_to_copy
);
75 row_pos
+= bytes_to_copy
;
76 filled
+= bytes_to_copy
;
78 // Jump to the next row when we've reached the end of the current row.
79 if (row_pos
== row_size
) {
86 if (row_y
== rect
.height()) {
87 DCHECK_EQ(row_pos
, 0);
89 packet
->mutable_data()->resize(filled
);
90 packet
->set_flags(packet
->flags() | VideoPacket::LAST_PACKET
);
91 packet
->set_capture_time_ms(capture_data_
->capture_time_ms());
92 packet
->set_encode_time_ms(
93 (base::Time::Now() - encode_start_time_
).InMillisecondsRoundedUp());
94 packet
->set_client_sequence_number(
95 capture_data_
->client_sequence_number());
96 SkIPoint
dpi(capture_data_
->dpi());
98 packet
->mutable_format()->set_x_dpi(dpi
.x());
100 packet
->mutable_format()->set_y_dpi(dpi
.y());
102 packet
->set_flags(packet
->flags() | VideoPacket::LAST_PARTITION
);
105 // If we have filled the current packet, then send it.
106 if (filled
== max_packet_size_
|| row_y
== rect
.height()) {
107 packet
->mutable_data()->resize(filled
);
108 callback_
.Run(packet
.Pass());
113 void VideoEncoderVerbatim::PrepareUpdateStart(const SkIRect
& rect
,
114 VideoPacket
* packet
) {
115 packet
->set_flags(packet
->flags() | VideoPacket::FIRST_PACKET
);
117 VideoPacketFormat
* format
= packet
->mutable_format();
118 format
->set_x(rect
.fLeft
);
119 format
->set_y(rect
.fTop
);
120 format
->set_width(rect
.width());
121 format
->set_height(rect
.height());
122 format
->set_encoding(VideoPacketFormat::ENCODING_VERBATIM
);
123 if (capture_data_
->size() != screen_size_
) {
124 screen_size_
= capture_data_
->size();
125 format
->set_screen_width(screen_size_
.width());
126 format
->set_screen_height(screen_size_
.height());
130 uint8
* VideoEncoderVerbatim::GetOutputBuffer(VideoPacket
* packet
, size_t size
) {
131 packet
->mutable_data()->resize(size
);
132 // TODO(ajwong): Is there a better way to do this at all???
133 return const_cast<uint8
*>(reinterpret_cast<const uint8
*>(
134 packet
->mutable_data()->data()));
137 } // namespace remoting