Chromium Code Reviews| 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 |