Upstream version 9.38.198.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 const char kVideoRecorderCapabilities[] = "videoRecorder";
25
26 const char kVideoRecorderType[] = "video-recorder";
27
28 const char kType[] = "type";
29 const char kData[] = "data";
30
31 const char kStartType[] = "start";
32 const char kStopType[] = "stop";
33 const char kNextFrameType[] = "next-frame";
34 const char kNextFrameReplyType[] = "next-frame-reply";
35
36 class VideoFrameRecorderHostExtensionSession : public HostExtensionSession {
37  public:
38   explicit VideoFrameRecorderHostExtensionSession(int64_t max_content_bytes);
39   virtual ~VideoFrameRecorderHostExtensionSession() {}
40
41   // remoting::HostExtensionSession interface.
42   virtual scoped_ptr<VideoEncoder> OnCreateVideoEncoder(
43       scoped_ptr<VideoEncoder> encoder) OVERRIDE;
44   virtual bool ModifiesVideoPipeline() const OVERRIDE;
45   virtual bool OnExtensionMessage(
46       ClientSessionControl* client_session_control,
47       protocol::ClientStub* client_stub,
48       const protocol::ExtensionMessage& message) OVERRIDE;
49
50  private:
51   VideoEncoderVerbatim verbatim_encoder;
52   VideoFrameRecorder video_frame_recorder;
53   bool first_frame_;
54
55   DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession);
56 };
57
58 VideoFrameRecorderHostExtensionSession::VideoFrameRecorderHostExtensionSession(
59     int64_t max_content_bytes) : first_frame_(false) {
60   video_frame_recorder.SetMaxContentBytes(max_content_bytes);
61 }
62
63 scoped_ptr<VideoEncoder>
64 VideoFrameRecorderHostExtensionSession::OnCreateVideoEncoder(
65     scoped_ptr<VideoEncoder> encoder) {
66   video_frame_recorder.DetachVideoEncoderWrapper();
67   return 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     std::string type;
90     if (!client_message->GetString(kType, &type)) {
91       LOG(ERROR) << "Invalid video-recorder message";
92       return true;
93     }
94
95     if (type == kStartType) {
96       video_frame_recorder.SetEnableRecording(true);
97       first_frame_ = true;
98     } else if (type == kStopType) {
99       video_frame_recorder.SetEnableRecording(false);
100     } else if (type == kNextFrameType) {
101       scoped_ptr<webrtc::DesktopFrame> frame(video_frame_recorder.NextFrame());
102
103       // TODO(wez): This involves six copies of the entire frame.
104       // See if there's some way to optimize at least a few of them out.
105       base::DictionaryValue reply_message;
106       reply_message.SetString(kType, kNextFrameReplyType);
107       if (frame) {
108         // If this is the first frame then override the updated region so that
109         // the encoder will send the whole frame's contents.
110         if (first_frame_) {
111           first_frame_ = false;
112
113           frame->mutable_updated_region()->SetRect(
114               webrtc::DesktopRect::MakeSize(frame->size()));
115         }
116
117         // Encode the frame into a raw ARGB VideoPacket.
118         scoped_ptr<VideoPacket> encoded_frame(
119             verbatim_encoder.Encode(*frame));
120
121         // Serialize that packet into a string.
122         std::string data;
123         data.resize(encoded_frame->ByteSize());
124         encoded_frame->SerializeWithCachedSizesToArray(
125             reinterpret_cast<uint8_t*>(&data[0]));
126
127         // Convert that string to Base64, so it's JSON-friendly.
128         std::string base64_data;
129         base::Base64Encode(data, &base64_data);
130
131         // Copy the Base64 data into the message.
132         reply_message.SetString(kData, base64_data);
133       }
134
135       // JSON-encode the reply into a string.
136       std::string reply_json;
137       if (!base::JSONWriter::Write(&reply_message, &reply_json)) {
138         LOG(ERROR) << "Failed to create reply json";
139         return true;
140       }
141
142       // Return the frame (or a 'data'-less reply) to the client.
143       protocol::ExtensionMessage message;
144       message.set_type(kVideoRecorderType);
145       message.set_data(reply_json);
146       client_stub->DeliverHostMessage(message);
147     }
148   }
149
150   return true;
151 }
152
153 } // namespace
154
155 void VideoFrameRecorderHostExtension::SetMaxContentBytes(
156     int64_t max_content_bytes) {
157   max_content_bytes_ = max_content_bytes;
158 }
159
160 std::string VideoFrameRecorderHostExtension::capability() const {
161   return kVideoRecorderCapabilities;
162 }
163
164 scoped_ptr<HostExtensionSession>
165 VideoFrameRecorderHostExtension::CreateExtensionSession(
166     ClientSessionControl* client_session_control,
167     protocol::ClientStub* client_stub) {
168   return scoped_ptr<HostExtensionSession>(
169       new VideoFrameRecorderHostExtensionSession(max_content_bytes_));
170 }
171
172 }  // namespace remoting