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/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"; | |
Jamie
2014/08/01 19:53:51
Are these constants duplicated somewhere in JS cod
Wez
2014/08/01 22:33:56
I've added a note to the capability definition; I'
| |
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 | |
54 DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession); | |
55 }; | |
56 | |
57 VideoFrameRecorderHostExtensionSession::VideoFrameRecorderHostExtensionSession( | |
58 int64_t max_content_bytes) { | |
59 video_frame_recorder.SetMaxContentBytes(max_content_bytes); | |
60 } | |
61 | |
62 scoped_ptr<VideoEncoder> | |
63 VideoFrameRecorderHostExtensionSession::OnCreateVideoEncoder( | |
64 scoped_ptr<VideoEncoder> encoder) { | |
65 video_frame_recorder.DetachVideoEncoderWrapper(); | |
66 return video_frame_recorder.WrapVideoEncoder(encoder.Pass()); | |
67 } | |
68 | |
69 bool VideoFrameRecorderHostExtensionSession::ModifiesVideoPipeline() const { | |
70 return true; | |
71 } | |
72 | |
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; | |
79 } | |
80 | |
81 if (!message.has_data()) { | |
82 return true; | |
83 } | |
84 | |
85 scoped_ptr<base::Value> value(base::JSONReader::Read(message.data())); | |
86 base::DictionaryValue* client_message; | |
87 if (value && value->GetAsDictionary(&client_message)) { | |
Jamie
2014/08/01 19:53:52
Elsewhere in this function, you seem to prefer ear
Wez
2014/08/01 22:33:56
Done.
| |
88 std::string type; | |
89 if (!client_message->GetString(kType, &type)) { | |
90 LOG(ERROR) << "Invalid video-recorder message"; | |
91 return true; | |
92 } | |
93 | |
94 if (type == kStartType) { | |
95 video_frame_recorder.SetEnableRecording(true); | |
96 } else if (type == kStopType) { | |
97 video_frame_recorder.SetEnableRecording(false); | |
98 } else if (type == kNextFrameType) { | |
99 scoped_ptr<webrtc::DesktopFrame> frame(video_frame_recorder.NextFrame()); | |
100 | |
101 // TODO(wez): This involves six copies of the entire frame. | |
102 // See if there's some way to optimize at least a few of them out. | |
103 base::DictionaryValue reply_message; | |
104 reply_message.SetString(kType, kNextFrameReplyType); | |
105 if (frame) { | |
106 // Encode the frame into a raw ARGB VideoPacket. | |
107 scoped_ptr<VideoPacket> encoded_frame( | |
108 verbatim_encoder.Encode(*frame)); | |
109 | |
110 // Serialize that packet into a string. | |
111 std::string data; | |
112 data.resize(encoded_frame->ByteSize()); | |
113 encoded_frame->SerializeWithCachedSizesToArray( | |
114 reinterpret_cast<uint8_t*>(&data[0])); | |
115 | |
116 // Convert that string to Base64, so it's JSON-friendly. | |
117 std::string base64_data; | |
118 base::Base64Encode(data, &base64_data); | |
119 | |
120 // Copy the Base64 data into the message. | |
121 reply_message.SetString(kData, base64_data); | |
122 } | |
123 | |
124 // JSON-encode the reply into a string. | |
125 std::string reply_json; | |
126 if (!base::JSONWriter::Write(&reply_message, &reply_json)) { | |
127 LOG(ERROR) << "Failed to create reply json"; | |
128 return true; | |
129 } | |
130 | |
131 // Return the frame (or a 'data'-less reply) to the client. | |
132 protocol::ExtensionMessage message; | |
133 message.set_type(kVideoRecorderType); | |
134 message.set_data(reply_json); | |
135 client_stub->DeliverHostMessage(message); | |
136 } | |
137 } | |
138 | |
139 return true; | |
140 } | |
141 | |
142 } // namespace | |
143 | |
144 void VideoFrameRecorderHostExtension::SetMaxContentBytes( | |
145 int64_t max_content_bytes) { | |
146 max_content_bytes_ = max_content_bytes; | |
147 } | |
148 | |
149 std::string VideoFrameRecorderHostExtension::capability() const { | |
150 return kVideoRecorderCapabilities; | |
151 } | |
152 | |
153 scoped_ptr<HostExtensionSession> | |
154 VideoFrameRecorderHostExtension::CreateExtensionSession( | |
155 ClientSessionControl* client_session_control, | |
156 protocol::ClientStub* client_stub) { | |
157 return scoped_ptr<HostExtensionSession>( | |
158 new VideoFrameRecorderHostExtensionSession(max_content_bytes_)); | |
159 } | |
160 | |
161 } // namespace remoting | |
OLD | NEW |