Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / host / video_frame_recorder_host_extension.cc
blob18391634ce9491baec337c067ca013bb688e91d4
1 // Copyright 2014 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/host/video_frame_recorder_host_extension.h"
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/values.h"
12 #include "remoting/codec/video_encoder_verbatim.h"
13 #include "remoting/host/host_extension_session.h"
14 #include "remoting/host/video_frame_recorder.h"
15 #include "remoting/proto/control.pb.h"
16 #include "remoting/proto/video.pb.h"
17 #include "remoting/protocol/client_stub.h"
18 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
20 namespace remoting {
22 namespace {
24 // Name of the extension message type field, and its value for this extension.
25 const char kType[] = "type";
26 const char kVideoRecorderType[] = "video-recorder";
28 class VideoFrameRecorderHostExtensionSession : public HostExtensionSession {
29 public:
30 explicit VideoFrameRecorderHostExtensionSession(int64_t max_content_bytes);
31 ~VideoFrameRecorderHostExtensionSession() override;
33 // remoting::HostExtensionSession interface.
34 void OnCreateVideoEncoder(scoped_ptr<VideoEncoder>* encoder) override;
35 bool ModifiesVideoPipeline() const override;
36 bool OnExtensionMessage(ClientSessionControl* client_session_control,
37 protocol::ClientStub* client_stub,
38 const protocol::ExtensionMessage& message) override;
40 private:
41 // Handlers for the different frame recorder extension message types.
42 void OnStart();
43 void OnStop();
44 void OnNextFrame(protocol::ClientStub* client_stub);
46 VideoEncoderVerbatim verbatim_encoder_;
47 VideoFrameRecorder video_frame_recorder_;
48 bool first_frame_;
50 DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession);
53 VideoFrameRecorderHostExtensionSession::VideoFrameRecorderHostExtensionSession(
54 int64_t max_content_bytes)
55 : first_frame_(false) {
56 video_frame_recorder_.SetMaxContentBytes(max_content_bytes);
59 VideoFrameRecorderHostExtensionSession::
60 ~VideoFrameRecorderHostExtensionSession() {
63 void VideoFrameRecorderHostExtensionSession::OnCreateVideoEncoder(
64 scoped_ptr<VideoEncoder>* encoder) {
65 video_frame_recorder_.DetachVideoEncoderWrapper();
66 *encoder = video_frame_recorder_.WrapVideoEncoder(encoder->Pass());
69 bool VideoFrameRecorderHostExtensionSession::ModifiesVideoPipeline() const {
70 return true;
73 bool VideoFrameRecorderHostExtensionSession::OnExtensionMessage(
74 ClientSessionControl* client_session_control,
75 protocol::ClientStub* client_stub,
76 const protocol::ExtensionMessage& message) {
77 if (message.type() != kVideoRecorderType) {
78 return false;
81 if (!message.has_data()) {
82 return true;
85 scoped_ptr<base::Value> value = base::JSONReader::Read(message.data());
86 base::DictionaryValue* client_message;
87 if (!value || !value->GetAsDictionary(&client_message)) {
88 return true;
91 std::string type;
92 if (!client_message->GetString(kType, &type)) {
93 LOG(ERROR) << "Invalid video-recorder message";
94 return true;
97 const char kStartType[] = "start";
98 const char kStopType[] = "stop";
99 const char kNextFrameType[] = "next-frame";
101 if (type == kStartType) {
102 OnStart();
103 } else if (type == kStopType) {
104 OnStop();
105 } else if (type == kNextFrameType) {
106 OnNextFrame(client_stub);
109 return true;
112 void VideoFrameRecorderHostExtensionSession::OnStart() {
113 video_frame_recorder_.SetEnableRecording(true);
114 first_frame_ = true;
117 void VideoFrameRecorderHostExtensionSession::OnStop() {
118 video_frame_recorder_.SetEnableRecording(false);
121 void VideoFrameRecorderHostExtensionSession::OnNextFrame(
122 protocol::ClientStub* client_stub) {
123 scoped_ptr<webrtc::DesktopFrame> frame(video_frame_recorder_.NextFrame());
125 // TODO(wez): This involves six copies of the entire frame.
126 // See if there's some way to optimize at least a few of them out.
127 const char kNextFrameReplyType[] = "next-frame-reply";
128 base::DictionaryValue reply_message;
129 reply_message.SetString(kType, kNextFrameReplyType);
130 if (frame) {
131 // If this is the first frame then override the updated region so that
132 // the encoder will send the whole frame's contents.
133 if (first_frame_) {
134 first_frame_ = false;
136 frame->mutable_updated_region()->SetRect(
137 webrtc::DesktopRect::MakeSize(frame->size()));
140 // Encode the frame into a raw ARGB VideoPacket.
141 scoped_ptr<VideoPacket> encoded_frame(
142 verbatim_encoder_.Encode(*frame));
144 // Serialize that packet into a string.
145 std::string data(encoded_frame->ByteSize(), 0);
146 encoded_frame->SerializeWithCachedSizesToArray(
147 reinterpret_cast<uint8_t*>(&data[0]));
149 // Convert that string to Base64, so it's JSON-friendly.
150 std::string base64_data;
151 base::Base64Encode(data, &base64_data);
153 // Copy the Base64 data into the message.
154 const char kData[] = "data";
155 reply_message.SetString(kData, base64_data);
158 // JSON-encode the reply into a string.
159 // Note that JSONWriter::Write() can only fail due to invalid inputs, and will
160 // DCHECK in Debug builds in that case.
161 std::string reply_json;
162 if (!base::JSONWriter::Write(reply_message, &reply_json)) {
163 return;
166 // Return the frame (or a 'data'-less reply) to the client.
167 protocol::ExtensionMessage message;
168 message.set_type(kVideoRecorderType);
169 message.set_data(reply_json);
170 client_stub->DeliverHostMessage(message);
173 } // namespace
175 VideoFrameRecorderHostExtension::VideoFrameRecorderHostExtension() {}
177 VideoFrameRecorderHostExtension::~VideoFrameRecorderHostExtension() {}
179 void VideoFrameRecorderHostExtension::SetMaxContentBytes(
180 int64_t max_content_bytes) {
181 max_content_bytes_ = max_content_bytes;
184 std::string VideoFrameRecorderHostExtension::capability() const {
185 const char kVideoRecorderCapability[] = "videoRecorder";
186 return kVideoRecorderCapability;
189 scoped_ptr<HostExtensionSession>
190 VideoFrameRecorderHostExtension::CreateExtensionSession(
191 ClientSessionControl* client_session_control,
192 protocol::ClientStub* client_stub) {
193 return make_scoped_ptr(
194 new VideoFrameRecorderHostExtensionSession(max_content_bytes_));
197 } // namespace remoting