Upstream version 10.39.233.0
[platform/framework/web/crosswalk.git] / src / remoting / host / video_frame_recorder_host_extension.cc
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.
4
5 #include "remoting/host/video_frame_recorder_host_extension.h"
6
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"
19
20 namespace remoting {
21
22 namespace {
23
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";
27
28 class VideoFrameRecorderHostExtensionSession : public HostExtensionSession {
29  public:
30   explicit VideoFrameRecorderHostExtensionSession(int64_t max_content_bytes);
31   virtual ~VideoFrameRecorderHostExtensionSession();
32
33   // remoting::HostExtensionSession interface.
34   virtual void OnCreateVideoEncoder(scoped_ptr<VideoEncoder>* encoder) OVERRIDE;
35   virtual bool ModifiesVideoPipeline() const OVERRIDE;
36   virtual bool OnExtensionMessage(
37       ClientSessionControl* client_session_control,
38       protocol::ClientStub* client_stub,
39       const protocol::ExtensionMessage& message) OVERRIDE;
40
41  private:
42   // Handlers for the different frame recorder extension message types.
43   void OnStart();
44   void OnStop();
45   void OnNextFrame(protocol::ClientStub* client_stub);
46
47   VideoEncoderVerbatim verbatim_encoder_;
48   VideoFrameRecorder video_frame_recorder_;
49   bool first_frame_;
50
51   DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession);
52 };
53
54 VideoFrameRecorderHostExtensionSession::VideoFrameRecorderHostExtensionSession(
55     int64_t max_content_bytes)
56     : first_frame_(false) {
57   video_frame_recorder_.SetMaxContentBytes(max_content_bytes);
58 }
59
60 VideoFrameRecorderHostExtensionSession::
61     ~VideoFrameRecorderHostExtensionSession() {
62 }
63
64 void VideoFrameRecorderHostExtensionSession::OnCreateVideoEncoder(
65     scoped_ptr<VideoEncoder>* encoder) {
66   video_frame_recorder_.DetachVideoEncoderWrapper();
67   *encoder = video_frame_recorder_.WrapVideoEncoder(encoder->Pass());
68 }
69
70 bool VideoFrameRecorderHostExtensionSession::ModifiesVideoPipeline() const {
71   return true;
72 }
73
74 bool VideoFrameRecorderHostExtensionSession::OnExtensionMessage(
75     ClientSessionControl* client_session_control,
76     protocol::ClientStub* client_stub,
77     const protocol::ExtensionMessage& message) {
78   if (message.type() != kVideoRecorderType) {
79     return false;
80   }
81
82   if (!message.has_data()) {
83     return true;
84   }
85
86   scoped_ptr<base::Value> value(base::JSONReader::Read(message.data()));
87   base::DictionaryValue* client_message;
88   if (!value || !value->GetAsDictionary(&client_message)) {
89     return true;
90   }
91
92   std::string type;
93   if (!client_message->GetString(kType, &type)) {
94     LOG(ERROR) << "Invalid video-recorder message";
95     return true;
96   }
97
98   const char kStartType[] = "start";
99   const char kStopType[] = "stop";
100   const char kNextFrameType[] = "next-frame";
101
102   if (type == kStartType) {
103     OnStart();
104   } else if (type == kStopType) {
105     OnStop();
106   } else if (type == kNextFrameType) {
107     OnNextFrame(client_stub);
108   }
109
110   return true;
111 }
112
113 void VideoFrameRecorderHostExtensionSession::OnStart() {
114   video_frame_recorder_.SetEnableRecording(true);
115   first_frame_ = true;
116 }
117
118 void VideoFrameRecorderHostExtensionSession::OnStop() {
119   video_frame_recorder_.SetEnableRecording(false);
120 }
121
122 void VideoFrameRecorderHostExtensionSession::OnNextFrame(
123     protocol::ClientStub* client_stub) {
124   scoped_ptr<webrtc::DesktopFrame> frame(video_frame_recorder_.NextFrame());
125
126   // TODO(wez): This involves six copies of the entire frame.
127   // See if there's some way to optimize at least a few of them out.
128   const char kNextFrameReplyType[] = "next-frame-reply";
129   base::DictionaryValue reply_message;
130   reply_message.SetString(kType, kNextFrameReplyType);
131   if (frame) {
132     // If this is the first frame then override the updated region so that
133     // the encoder will send the whole frame's contents.
134     if (first_frame_) {
135       first_frame_ = false;
136
137       frame->mutable_updated_region()->SetRect(
138           webrtc::DesktopRect::MakeSize(frame->size()));
139     }
140
141     // Encode the frame into a raw ARGB VideoPacket.
142     scoped_ptr<VideoPacket> encoded_frame(
143         verbatim_encoder_.Encode(*frame));
144
145     // Serialize that packet into a string.
146     std::string data(encoded_frame->ByteSize(), 0);
147     encoded_frame->SerializeWithCachedSizesToArray(
148         reinterpret_cast<uint8_t*>(&data[0]));
149
150     // Convert that string to Base64, so it's JSON-friendly.
151     std::string base64_data;
152     base::Base64Encode(data, &base64_data);
153
154     // Copy the Base64 data into the message.
155     const char kData[] = "data";
156     reply_message.SetString(kData, base64_data);
157   }
158
159   // JSON-encode the reply into a string.
160   // Note that JSONWriter::Write() can only fail due to invalid inputs, and will
161   // DCHECK in Debug builds in that case.
162   std::string reply_json;
163   if (!base::JSONWriter::Write(&reply_message, &reply_json)) {
164     return;
165   }
166
167   // Return the frame (or a 'data'-less reply) to the client.
168   protocol::ExtensionMessage message;
169   message.set_type(kVideoRecorderType);
170   message.set_data(reply_json);
171   client_stub->DeliverHostMessage(message);
172 }
173
174 } // namespace
175
176 VideoFrameRecorderHostExtension::VideoFrameRecorderHostExtension() {}
177
178 VideoFrameRecorderHostExtension::~VideoFrameRecorderHostExtension() {}
179
180 void VideoFrameRecorderHostExtension::SetMaxContentBytes(
181     int64_t max_content_bytes) {
182   max_content_bytes_ = max_content_bytes;
183 }
184
185 std::string VideoFrameRecorderHostExtension::capability() const {
186   const char kVideoRecorderCapability[] = "videoRecorder";
187   return kVideoRecorderCapability;
188 }
189
190 scoped_ptr<HostExtensionSession>
191 VideoFrameRecorderHostExtension::CreateExtensionSession(
192     ClientSessionControl* client_session_control,
193     protocol::ClientStub* client_stub) {
194   return scoped_ptr<HostExtensionSession>(
195       new VideoFrameRecorderHostExtensionSession(max_content_bytes_));
196 }
197
198 }  // namespace remoting