OLD | NEW |
---|---|
(Empty) | |
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/client_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 VideoFrameRecorderHostExtensionSession() {} | |
39 virtual ~VideoFrameRecorderHostExtensionSession() {} | |
40 | |
41 // remoting::HostExtensionSession interface. | |
42 virtual bool OnExtensionMessage( | |
43 ClientSession* client_session, | |
44 const protocol::ExtensionMessage& message) OVERRIDE; | |
45 | |
46 private: | |
47 VideoEncoderVerbatim verbatim_encoder; | |
48 | |
49 DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession); | |
50 }; | |
51 | |
52 bool VideoFrameRecorderHostExtensionSession::OnExtensionMessage( | |
53 ClientSession* client_session, const protocol::ExtensionMessage& message) { | |
Sergey Ulanov
2014/07/11 18:38:03
nit: one argument per line please
Wez
2014/07/31 23:57:46
Done.
| |
54 if (!client_session->video_frame_recorder()) { | |
55 return false; | |
56 } | |
57 if (message.type() != kVideoRecorderType) { | |
58 return false; | |
59 } | |
60 | |
61 if (!message.has_data()) { | |
62 return true; | |
63 } | |
64 | |
65 scoped_ptr<base::Value> value(base::JSONReader::Read(message.data())); | |
66 base::DictionaryValue* client_message; | |
67 if (value && value->GetAsDictionary(&client_message)) { | |
68 std::string type; | |
69 if (!client_message->GetString(kType, &type)) { | |
70 LOG(ERROR) << "Invalid video-recorder message"; | |
71 return true; | |
72 } | |
73 | |
74 VideoFrameRecorder* recorder = client_session->video_frame_recorder(); | |
75 if (type == kStartType) { | |
76 recorder->SetEnableRecording(true); | |
77 } else if (type == kStopType) { | |
78 recorder->SetEnableRecording(false); | |
79 } else if (type == kNextFrameType) { | |
80 scoped_ptr<webrtc::DesktopFrame> frame(recorder->NextFrame()); | |
81 | |
82 // TODO(wez): This involves six copies of the entire frame. | |
83 // See if there's some way to optimize at least a few of them out. | |
84 base::DictionaryValue reply_message; | |
85 reply_message.SetString(kType, kNextFrameReplyType); | |
86 if (frame) { | |
Sergey Ulanov
2014/07/11 18:38:03
How will client use this extension? Will it be jus
Wez
2014/07/31 23:57:46
No, the client needs to know when the last frame w
| |
87 // Encode the frame into a raw ARGB VideoPacket. | |
88 scoped_ptr<VideoPacket> encoded_frame( | |
89 verbatim_encoder.Encode(*frame)); | |
90 | |
91 // Serialize that packet into a string. | |
92 std::string data; | |
93 data.resize(encoded_frame->ByteSize()); | |
94 encoded_frame->SerializeWithCachedSizesToArray( | |
95 reinterpret_cast<uint8_t*>(&data[0])); | |
96 | |
97 // Convert that string to Base64, so it's JSON-friendly. | |
98 std::string base64_data; | |
99 base::Base64Encode(data, &base64_data); | |
100 | |
101 // Copy the Base64 data into the message. | |
102 reply_message.SetString(kData, base64_data); | |
103 } | |
104 | |
105 // JSON-encode the reply into a string. | |
106 std::string reply_json; | |
107 if (!base::JSONWriter::Write(&reply_message, &reply_json)) { | |
Sergey Ulanov
2014/07/11 18:38:03
A single string with quotes on both ends is a vali
Wez
2014/07/31 23:57:46
We still need the kType==kNextFrameReplyType heade
| |
108 LOG(ERROR) << "Failed to create reply json"; | |
109 return true; | |
110 } | |
111 | |
112 // Return the frame (or a 'data'-less reply) to the client. | |
113 protocol::ExtensionMessage message; | |
114 message.set_type(kVideoRecorderType); | |
115 message.set_data(reply_json); | |
116 client_session->connection()->client_stub()->DeliverHostMessage(message); | |
117 } | |
118 } | |
119 | |
120 return true; | |
121 } | |
122 | |
123 } // namespace | |
124 | |
125 void VideoFrameRecorderHostExtension::SetMaxContentBytes( | |
126 int64_t max_content_bytes) { | |
127 max_content_bytes_ = max_content_bytes; | |
128 } | |
129 | |
130 std::string VideoFrameRecorderHostExtension::GetCapabilities() { | |
131 return kVideoRecorderCapabilities; | |
132 } | |
133 | |
134 scoped_ptr<HostExtensionSession> | |
135 VideoFrameRecorderHostExtension::CreateExtensionSession( | |
136 ClientSession* client_session) { | |
137 DCHECK(client_session->video_frame_recorder()); | |
138 client_session->video_frame_recorder()->SetMaxContentBytes( | |
139 max_content_bytes_); | |
140 return scoped_ptr<HostExtensionSession>( | |
141 new VideoFrameRecorderHostExtensionSession()); | |
142 } | |
143 | |
144 } // namespace remoting | |
OLD | NEW |