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

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

Issue 339073002: Add VideoFrameRecorder for use recording test frame sequences. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add missing OVERRIDEs Created 6 years, 6 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 | Annotate | Revision Log
OLDNEW
(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.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/stl_util.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "remoting/codec/video_encoder.h"
13 #include "remoting/proto/video.pb.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
17
18 namespace remoting {
19
20 const int64 kDefaultMaxContentBytes = 10 * 1024 * 1024;
Sergey Ulanov 2014/06/20 22:32:13 int64_t here and everywhere else in this file.
Sergey Ulanov 2014/06/20 22:32:13 10MB fits about 2 frames - is that enough?
Wez 2014/06/24 01:02:14 Done.
Wez 2014/06/24 01:02:15 The intention is really for the caller to choose a
21
22 static int64 FrameContentBytes(const webrtc::DesktopFrame* frame) {
Sergey Ulanov 2014/06/20 22:32:12 nit: Maybe GetFrameContentSize()? or just FrameCon
Wez 2014/06/24 01:02:14 <foo>Size() is too easy to confuse as being Deskto
23 return frame->stride() * frame->size().height();
Sergey Ulanov 2014/06/20 22:32:13 that will be broken when stride is negative for fl
Wez 2014/06/24 01:02:14 FrameContentSize() is only ever called for BasicDe
24 }
25
26 class VideoFrameRecorder::RecordingVideoEncoder : public VideoEncoder {
Sergey Ulanov 2014/06/20 22:32:13 add short comment to describe what this class is u
Wez 2014/06/24 01:02:14 Done.
27 public:
28 RecordingVideoEncoder(scoped_ptr<VideoEncoder> encoder,
29 scoped_refptr<base::TaskRunner> recorder_task_runner,
30 base::WeakPtr<VideoFrameRecorder> recorder)
31 : encoder_(encoder.Pass()),
Sergey Ulanov 2014/06/20 22:32:13 : needs to be indented 4 spaces, http://google-sty
Wez 2014/06/24 01:02:15 Done.
32 recorder_task_runner_(recorder_task_runner),
33 recorder_(recorder),
34 enable_recording_(false),
35 weak_factory_(this) {
36 DCHECK(encoder_);
37 DCHECK(recorder_task_runner_);
38 }
39
40 base::WeakPtr<RecordingVideoEncoder> AsWeakPtr() {
41 return weak_factory_.GetWeakPtr();
42 }
43
44 void SetEnableRecording(bool enable_recording) {
45 enable_recording_ = enable_recording;
Sergey Ulanov 2014/06/20 22:32:12 DCHECK we are on |encoder_taks_runner_|?
Wez 2014/06/24 01:02:14 Since SetEnableRecording() is a simple setter and
46 }
47
48 // remoting::VideoEncoder interface.
49 virtual void SetLosslessEncode(bool want_lossless) OVERRIDE {
50 encoder_->SetLosslessEncode(want_lossless);
51 }
52 virtual void SetLosslessColor(bool want_lossless) OVERRIDE {
53 encoder_->SetLosslessColor(want_lossless);
54 }
55 virtual scoped_ptr<VideoPacket> Encode(
56 const webrtc::DesktopFrame& frame) OVERRIDE {
57 // If this is the first Encode() then store the TaskRunner and inform the
58 // VideoFrameRecorder so it can post SetEnableRecording() on it.
59 if (!encoder_task_runner_) {
60 encoder_task_runner_ = base::ThreadTaskRunnerHandle::Get();
61 recorder_task_runner_->PostTask(FROM_HERE,
62 base::Bind(&VideoFrameRecorder::SetEncoderTaskRunner,
63 recorder_,
64 encoder_task_runner_));
65 }
66
67 DCHECK(encoder_task_runner_->BelongsToCurrentThread());
68
69 if (enable_recording_) {
70 // Copy the frame and post it to the VideoFrameRecorder to store.
71 scoped_ptr<webrtc::DesktopFrame> frame_copy(
72 new webrtc::BasicDesktopFrame(frame.size()));
73 *frame_copy->mutable_updated_region() = frame.updated_region();
74 frame_copy->set_dpi(frame.dpi());
75 frame_copy->CopyPixelsFrom(frame.data(),
76 frame.stride(),
77 webrtc::DesktopRect::MakeSize(frame.size()));
78 recorder_task_runner_->PostTask(FROM_HERE,
79 base::Bind(&VideoFrameRecorder::RecordFrame,
80 recorder_,
81 base::Passed(&frame_copy)));
82 }
83
84 return encoder_->Encode(frame);
85 }
86
87 private:
88 scoped_ptr<VideoEncoder> encoder_;
89 scoped_refptr<base::TaskRunner> recorder_task_runner_;
90 base::WeakPtr<VideoFrameRecorder> recorder_;
91
92 bool enable_recording_;
93 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
94
95 base::WeakPtrFactory<RecordingVideoEncoder> weak_factory_;
96
97 DISALLOW_COPY_AND_ASSIGN(RecordingVideoEncoder);
98 };
99
100 VideoFrameRecorder::VideoFrameRecorder()
101 : content_bytes_(0),
Sergey Ulanov 2014/06/20 22:32:12 indentation
Wez 2014/06/24 01:02:14 Done.
102 max_content_bytes_(kDefaultMaxContentBytes),
103 enable_recording_(false),
104 weak_factory_(this) {
105 }
106
107 VideoFrameRecorder::~VideoFrameRecorder() {
108 SetEnableRecording(false);
109 STLDeleteElements(&recorded_frames_);
110 }
111
112 scoped_ptr<VideoEncoder> VideoFrameRecorder::WrapVideoEncoder(
113 scoped_ptr<VideoEncoder> encoder) {
114 DCHECK(!caller_task_runner_);
115 caller_task_runner_ = base::ThreadTaskRunnerHandle::Get();
116
117 scoped_ptr<RecordingVideoEncoder> recording_encoder(
118 new RecordingVideoEncoder(encoder.Pass(),
119 caller_task_runner_,
120 weak_factory_.GetWeakPtr()));
121 recording_encoder_ = recording_encoder->AsWeakPtr();
122
123 return recording_encoder.PassAs<VideoEncoder>();
124 }
125
126 void VideoFrameRecorder::SetEnableRecording(bool enable_recording) {
127 DCHECK(!caller_task_runner_ || caller_task_runner_->BelongsToCurrentThread());
128
129 if (enable_recording_ == enable_recording) {
130 return;
131 }
132 enable_recording_ = enable_recording;
133
134 if (encoder_task_runner_) {
135 encoder_task_runner_->PostTask(FROM_HERE,
136 base::Bind(&RecordingVideoEncoder::SetEnableRecording,
137 recording_encoder_,
138 enable_recording_));
139 }
140 }
141
142 void VideoFrameRecorder::SetMaxContentBytes(int64 max_content_bytes) {
143 DCHECK(!caller_task_runner_ || caller_task_runner_->BelongsToCurrentThread());
144 DCHECK_GE(max_content_bytes, 0);
145
146 max_content_bytes_ = max_content_bytes;
147 }
148
149 scoped_ptr<webrtc::DesktopFrame> VideoFrameRecorder::NextFrame() {
150 DCHECK(caller_task_runner_->BelongsToCurrentThread());
151
152 scoped_ptr<webrtc::DesktopFrame> frame;
153 if (!recorded_frames_.empty()) {
154 frame.reset(recorded_frames_.front());
155 recorded_frames_.pop_front();
Sergey Ulanov 2014/06/20 22:32:13 update content_bytes_?
Wez 2014/06/24 01:02:14 Done + added a test case.
156 }
157
158 return frame.Pass();
159 }
160
161 void VideoFrameRecorder::SetEncoderTaskRunner(
162 scoped_refptr<base::TaskRunner> task_runner) {
163 DCHECK(caller_task_runner_->BelongsToCurrentThread());
164 DCHECK(!encoder_task_runner_);
165 DCHECK(task_runner);
166
167 encoder_task_runner_ = task_runner;
168
169 // If the caller already enabled recording, inform the recording encoder.
170 if (enable_recording_) {
171 enable_recording_ = false;
172 SetEnableRecording(true);
Sergey Ulanov 2014/06/20 22:32:13 It looks wrong to reset enable_recording to false,
Wez 2014/06/24 01:02:15 Done.
173 }
174 }
175
176 void VideoFrameRecorder::RecordFrame(scoped_ptr<webrtc::DesktopFrame> frame) {
177 DCHECK(caller_task_runner_->BelongsToCurrentThread());
178
179 int64 frame_bytes = FrameContentBytes(frame.get());
180 DCHECK_GE(frame_bytes, 0);
181
182 // Purge existing frames until there is space for the new one.
183 while (content_bytes_ + frame_bytes > max_content_bytes_ &&
184 !recorded_frames_.empty()) {
185 scoped_ptr<webrtc::DesktopFrame> drop_frame(recorded_frames_.front());
186 recorded_frames_.pop_front();
187 content_bytes_ -= FrameContentBytes(drop_frame.get());
188 DCHECK_GE(content_bytes_, 0);
189 }
190
191 // If the frame is still too big, ignore it.
192 if (content_bytes_ + frame_bytes > max_content_bytes_) {
193 return;
194 }
195
196 // Store the frame and update the content byte count.
197 recorded_frames_.push_back(frame.release());
198 content_bytes_ += frame_bytes;
199 }
200
201 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698