Chromium Code Reviews| Index: remoting/host/video_frame_recorder_host_extension.cc |
| diff --git a/remoting/host/video_frame_recorder_host_extension.cc b/remoting/host/video_frame_recorder_host_extension.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4019268bc9d6aa292ac3b0de831a3b0ddb026dd1 |
| --- /dev/null |
| +++ b/remoting/host/video_frame_recorder_host_extension.cc |
| @@ -0,0 +1,144 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "remoting/host/video_frame_recorder_host_extension.h" |
| + |
| +#include "base/base64.h" |
| +#include "base/json/json_reader.h" |
| +#include "base/json/json_writer.h" |
| +#include "base/logging.h" |
| +#include "base/values.h" |
| +#include "remoting/codec/video_encoder_verbatim.h" |
| +#include "remoting/host/client_session.h" |
| +#include "remoting/host/video_frame_recorder.h" |
| +#include "remoting/proto/control.pb.h" |
| +#include "remoting/proto/video.pb.h" |
| +#include "remoting/protocol/client_stub.h" |
| +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| + |
| +namespace remoting { |
| + |
| +namespace { |
| + |
| +const char kVideoRecorderCapabilities[] = "videoRecorder"; |
| + |
| +const char kVideoRecorderType[] = "video-recorder"; |
| + |
| +const char kType[] = "type"; |
| +const char kData[] = "data"; |
| + |
| +const char kStartType[] = "start"; |
| +const char kStopType[] = "stop"; |
| +const char kNextFrameType[] = "next-frame"; |
| +const char kNextFrameReplyType[] = "next-frame-reply"; |
| + |
| +class VideoFrameRecorderHostExtensionSession : public HostExtensionSession { |
| + public: |
| + VideoFrameRecorderHostExtensionSession() {} |
| + virtual ~VideoFrameRecorderHostExtensionSession() {} |
| + |
| + // remoting::HostExtensionSession interface. |
| + virtual bool OnExtensionMessage( |
| + ClientSession* client_session, |
| + const protocol::ExtensionMessage& message) OVERRIDE; |
| + |
| + private: |
| + VideoEncoderVerbatim verbatim_encoder; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorderHostExtensionSession); |
| +}; |
| + |
| +bool VideoFrameRecorderHostExtensionSession::OnExtensionMessage( |
| + 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.
|
| + if (!client_session->video_frame_recorder()) { |
| + return false; |
| + } |
| + if (message.type() != kVideoRecorderType) { |
| + return false; |
| + } |
| + |
| + if (!message.has_data()) { |
| + return true; |
| + } |
| + |
| + scoped_ptr<base::Value> value(base::JSONReader::Read(message.data())); |
| + base::DictionaryValue* client_message; |
| + if (value && value->GetAsDictionary(&client_message)) { |
| + std::string type; |
| + if (!client_message->GetString(kType, &type)) { |
| + LOG(ERROR) << "Invalid video-recorder message"; |
| + return true; |
| + } |
| + |
| + VideoFrameRecorder* recorder = client_session->video_frame_recorder(); |
| + if (type == kStartType) { |
| + recorder->SetEnableRecording(true); |
| + } else if (type == kStopType) { |
| + recorder->SetEnableRecording(false); |
| + } else if (type == kNextFrameType) { |
| + scoped_ptr<webrtc::DesktopFrame> frame(recorder->NextFrame()); |
| + |
| + // TODO(wez): This involves six copies of the entire frame. |
| + // See if there's some way to optimize at least a few of them out. |
| + base::DictionaryValue reply_message; |
| + reply_message.SetString(kType, kNextFrameReplyType); |
| + 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
|
| + // Encode the frame into a raw ARGB VideoPacket. |
| + scoped_ptr<VideoPacket> encoded_frame( |
| + verbatim_encoder.Encode(*frame)); |
| + |
| + // Serialize that packet into a string. |
| + std::string data; |
| + data.resize(encoded_frame->ByteSize()); |
| + encoded_frame->SerializeWithCachedSizesToArray( |
| + reinterpret_cast<uint8_t*>(&data[0])); |
| + |
| + // Convert that string to Base64, so it's JSON-friendly. |
| + std::string base64_data; |
| + base::Base64Encode(data, &base64_data); |
| + |
| + // Copy the Base64 data into the message. |
| + reply_message.SetString(kData, base64_data); |
| + } |
| + |
| + // JSON-encode the reply into a string. |
| + std::string reply_json; |
| + 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
|
| + LOG(ERROR) << "Failed to create reply json"; |
| + return true; |
| + } |
| + |
| + // Return the frame (or a 'data'-less reply) to the client. |
| + protocol::ExtensionMessage message; |
| + message.set_type(kVideoRecorderType); |
| + message.set_data(reply_json); |
| + client_session->connection()->client_stub()->DeliverHostMessage(message); |
| + } |
| + } |
| + |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +void VideoFrameRecorderHostExtension::SetMaxContentBytes( |
| + int64_t max_content_bytes) { |
| + max_content_bytes_ = max_content_bytes; |
| +} |
| + |
| +std::string VideoFrameRecorderHostExtension::GetCapabilities() { |
| + return kVideoRecorderCapabilities; |
| +} |
| + |
| +scoped_ptr<HostExtensionSession> |
| +VideoFrameRecorderHostExtension::CreateExtensionSession( |
| + ClientSession* client_session) { |
| + DCHECK(client_session->video_frame_recorder()); |
| + client_session->video_frame_recorder()->SetMaxContentBytes( |
| + max_content_bytes_); |
| + return scoped_ptr<HostExtensionSession>( |
| + new VideoFrameRecorderHostExtensionSession()); |
| +} |
| + |
| +} // namespace remoting |