Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: remoting/host/video_frame_recorder.cc

Issue 1846893002: Interface with webrtc through encoded frames (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed sergeyu comments and rebased Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
Sergey Ulanov 2016/04/12 18:57:31 I deleted this file recently.
Irfan 2016/04/12 21:13:11 Done.
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.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/macros.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/stl_util.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "remoting/codec/video_encoder.h"
16 #include "remoting/proto/video.pb.h"
17 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
18 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
20
21 namespace remoting {
22
23 static int64_t FrameContentSize(const webrtc::DesktopFrame* frame) {
24 DCHECK_GT(frame->stride(), 0);
25 return frame->stride() * frame->size().height();
26 }
27
28 // VideoEncoder wrapper used to intercept frames passed to a real VideoEncoder.
29 class VideoFrameRecorder::RecordingVideoEncoder : public VideoEncoder {
30 public:
31 RecordingVideoEncoder(scoped_ptr<VideoEncoder> encoder,
32 scoped_refptr<base::TaskRunner> recorder_task_runner,
33 base::WeakPtr<VideoFrameRecorder> recorder);
34
35 base::WeakPtr<RecordingVideoEncoder> AsWeakPtr();
36
37 void set_enable_recording(bool enable_recording) {
38 DCHECK(!encoder_task_runner_.get() ||
39 encoder_task_runner_->BelongsToCurrentThread());
40 enable_recording_ = enable_recording;
41 }
42
43 // remoting::VideoEncoder interface.
44 void SetLosslessEncode(bool want_lossless) override;
45 void SetLosslessColor(bool want_lossless) override;
46 scoped_ptr<VideoPacket> Encode(const webrtc::DesktopFrame& frame,
47 uint32_t flags = 0) override;
48
49 private:
50 scoped_ptr<VideoEncoder> encoder_;
51 scoped_refptr<base::TaskRunner> recorder_task_runner_;
52 base::WeakPtr<VideoFrameRecorder> recorder_;
53
54 bool enable_recording_;
55 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
56
57 base::WeakPtrFactory<RecordingVideoEncoder> weak_factory_;
58
59 DISALLOW_COPY_AND_ASSIGN(RecordingVideoEncoder);
60 };
61
62 VideoFrameRecorder::RecordingVideoEncoder::RecordingVideoEncoder(
63 scoped_ptr<VideoEncoder> encoder,
64 scoped_refptr<base::TaskRunner> recorder_task_runner,
65 base::WeakPtr<VideoFrameRecorder> recorder)
66 : encoder_(std::move(encoder)),
67 recorder_task_runner_(recorder_task_runner),
68 recorder_(recorder),
69 enable_recording_(false),
70 weak_factory_(this) {
71 DCHECK(encoder_);
72 DCHECK(recorder_task_runner_.get());
73 }
74
75 base::WeakPtr<VideoFrameRecorder::RecordingVideoEncoder>
76 VideoFrameRecorder::RecordingVideoEncoder::AsWeakPtr() {
77 return weak_factory_.GetWeakPtr();
78 }
79
80 void VideoFrameRecorder::RecordingVideoEncoder::SetLosslessEncode(
81 bool want_lossless) {
82 encoder_->SetLosslessEncode(want_lossless);
83 }
84
85 void VideoFrameRecorder::RecordingVideoEncoder::SetLosslessColor(
86 bool want_lossless) {
87 encoder_->SetLosslessColor(want_lossless);
88 }
89
90 scoped_ptr<VideoPacket> VideoFrameRecorder::RecordingVideoEncoder::Encode(
91 const webrtc::DesktopFrame& frame,
92 uint32_t flags) {
93 // If this is the first Encode() then store the TaskRunner and inform the
94 // VideoFrameRecorder so it can post set_enable_recording() on it.
95 if (!encoder_task_runner_.get()) {
96 encoder_task_runner_ = base::ThreadTaskRunnerHandle::Get();
97 recorder_task_runner_->PostTask(
98 FROM_HERE, base::Bind(&VideoFrameRecorder::SetEncoderTaskRunner,
99 recorder_, encoder_task_runner_));
100 }
101
102 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
103
104 if (enable_recording_) {
105 // Copy the frame and post it to the VideoFrameRecorder to store.
106 scoped_ptr<webrtc::DesktopFrame> frame_copy(
107 new webrtc::BasicDesktopFrame(frame.size()));
108 *frame_copy->mutable_updated_region() = frame.updated_region();
109 frame_copy->set_dpi(frame.dpi());
110 frame_copy->CopyPixelsFrom(frame.data(), frame.stride(),
111 webrtc::DesktopRect::MakeSize(frame.size()));
112 recorder_task_runner_->PostTask(
113 FROM_HERE, base::Bind(&VideoFrameRecorder::RecordFrame, recorder_,
114 base::Passed(&frame_copy)));
115 }
116
117 return encoder_->Encode(frame, flags);
118 }
119
120 VideoFrameRecorder::VideoFrameRecorder()
121 : content_bytes_(0),
122 max_content_bytes_(0),
123 enable_recording_(false),
124 weak_factory_(this) {}
125
126 VideoFrameRecorder::~VideoFrameRecorder() {
127 DetachVideoEncoderWrapper();
128 }
129
130 scoped_ptr<VideoEncoder> VideoFrameRecorder::WrapVideoEncoder(
131 scoped_ptr<VideoEncoder> encoder) {
132 DCHECK(!encoder_task_runner_.get());
133 DCHECK(!caller_task_runner_.get());
134 caller_task_runner_ = base::ThreadTaskRunnerHandle::Get();
135
136 scoped_ptr<RecordingVideoEncoder> recording_encoder(new RecordingVideoEncoder(
137 std::move(encoder), caller_task_runner_, weak_factory_.GetWeakPtr()));
138 recording_encoder_ = recording_encoder->AsWeakPtr();
139
140 return std::move(recording_encoder);
141 }
142
143 void VideoFrameRecorder::DetachVideoEncoderWrapper() {
144 DCHECK(!caller_task_runner_.get() ||
145 caller_task_runner_->BelongsToCurrentThread());
146
147 // Immediately detach the wrapper from this recorder.
148 weak_factory_.InvalidateWeakPtrs();
149
150 // Clean up any pending recorded frames.
151 STLDeleteElements(&recorded_frames_);
152 content_bytes_ = 0;
153
154 // Tell the wrapper to stop recording and posting frames to us.
155 if (encoder_task_runner_.get()) {
156 encoder_task_runner_->PostTask(
157 FROM_HERE, base::Bind(&RecordingVideoEncoder::set_enable_recording,
158 recording_encoder_, false));
159 }
160
161 // Detach this recorder from the calling and encode threads.
162 caller_task_runner_ = nullptr;
163 encoder_task_runner_ = nullptr;
164 }
165
166 void VideoFrameRecorder::SetEnableRecording(bool enable_recording) {
167 DCHECK(!caller_task_runner_.get() ||
168 caller_task_runner_->BelongsToCurrentThread());
169
170 if (enable_recording_ == enable_recording) {
171 return;
172 }
173 enable_recording_ = enable_recording;
174
175 if (encoder_task_runner_.get()) {
176 encoder_task_runner_->PostTask(
177 FROM_HERE, base::Bind(&RecordingVideoEncoder::set_enable_recording,
178 recording_encoder_, enable_recording_));
179 }
180 }
181
182 void VideoFrameRecorder::SetMaxContentBytes(int64_t max_content_bytes) {
183 DCHECK(!caller_task_runner_.get() ||
184 caller_task_runner_->BelongsToCurrentThread());
185 DCHECK_GE(max_content_bytes, 0);
186
187 max_content_bytes_ = max_content_bytes;
188 }
189
190 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorder::NextFrame() {
191 DCHECK(caller_task_runner_->BelongsToCurrentThread());
192
193 scoped_ptr<webrtc::DesktopFrame> frame;
194 if (!recorded_frames_.empty()) {
195 frame.reset(recorded_frames_.front());
196 recorded_frames_.pop_front();
197 content_bytes_ -= FrameContentSize(frame.get());
198 DCHECK_GE(content_bytes_, 0);
199 }
200
201 return frame;
202 }
203
204 void VideoFrameRecorder::SetEncoderTaskRunner(
205 scoped_refptr<base::TaskRunner> task_runner) {
206 DCHECK(caller_task_runner_->BelongsToCurrentThread());
207 DCHECK(!encoder_task_runner_.get());
208 DCHECK(task_runner.get());
209
210 encoder_task_runner_ = task_runner;
211
212 // If the caller already enabled recording, inform the recording encoder.
213 if (enable_recording_ && encoder_task_runner_.get()) {
214 encoder_task_runner_->PostTask(
215 FROM_HERE, base::Bind(&RecordingVideoEncoder::set_enable_recording,
216 recording_encoder_, enable_recording_));
217 }
218 }
219
220 void VideoFrameRecorder::RecordFrame(scoped_ptr<webrtc::DesktopFrame> frame) {
221 DCHECK(caller_task_runner_->BelongsToCurrentThread());
222
223 int64_t frame_bytes = FrameContentSize(frame.get());
224 DCHECK_GE(frame_bytes, 0);
225
226 // Purge existing frames until there is space for the new one.
227 while (content_bytes_ + frame_bytes > max_content_bytes_ &&
228 !recorded_frames_.empty()) {
229 scoped_ptr<webrtc::DesktopFrame> drop_frame(recorded_frames_.front());
230 recorded_frames_.pop_front();
231 content_bytes_ -= FrameContentSize(drop_frame.get());
232 DCHECK_GE(content_bytes_, 0);
233 }
234
235 // If the frame is still too big, ignore it.
236 if (content_bytes_ + frame_bytes > max_content_bytes_) {
237 return;
238 }
239
240 // Store the frame and update the content byte count.
241 recorded_frames_.push_back(frame.release());
242 content_bytes_ += frame_bytes;
243 }
244
245 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698