OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/test/test_video_renderer.h" | 5 #include "remoting/test/test_video_renderer.h" |
6 | 6 |
7 #include "base/bind.h" | |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/synchronization/lock.h" | |
10 #include "base/thread_task_runner_handle.h" | |
11 #include "base/threading/thread.h" | |
12 #include "remoting/codec/video_decoder.h" | |
13 #include "remoting/codec/video_decoder_verbatim.h" | |
14 #include "remoting/codec/video_decoder_vpx.h" | |
8 #include "remoting/proto/video.pb.h" | 15 #include "remoting/proto/video.pb.h" |
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
17 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | |
9 | 18 |
10 namespace remoting { | 19 namespace remoting { |
11 namespace test { | 20 namespace test { |
12 | 21 |
13 TestVideoRenderer::TestVideoRenderer() : video_frames_processed_(0) { | 22 // Implements video decoding functionality. |
23 class TestVideoRenderer::Core { | |
24 public: | |
25 Core(); | |
26 ~Core(); | |
27 | |
28 // Initializes the internal structures of the class. | |
29 void Initialize(); | |
30 | |
31 // Used to decode video packets. | |
32 void ProcessVideoPacket(scoped_ptr<VideoPacket> packet, | |
33 const base::Closure& done); | |
34 | |
35 // Initialize a decoder to decode video packets. | |
36 void SetDecoderForDecoding(const protocol::ChannelConfig::Codec codec); | |
joedow
2015/06/30 20:07:11
SetCodec or SetCodecForDecoding
liaoyuke
2015/06/30 21:15:01
Done.
| |
37 | |
38 // Returns a copy of the current buffer. | |
39 scoped_ptr<webrtc::DesktopFrame> GetBufferForTest() const; | |
40 | |
41 private: | |
42 // Used to ensure TestVideoRenderer::Core methods are called on the same | |
43 // thread. | |
joedow
2015/06/30 20:07:12
nit: Can you shorten the comment so it fits on one
liaoyuke
2015/06/30 21:15:01
Done.
| |
44 base::ThreadChecker thread_checker_; | |
45 | |
46 // Used to decode video packets. | |
47 scoped_ptr<VideoDecoder> decoder_; | |
48 | |
49 // Updated region of the current desktop frame compared to previous one. | |
50 webrtc::DesktopRegion updated_region_; | |
51 | |
52 // Screen size of the remote host. | |
53 webrtc::DesktopSize screen_size_; | |
54 | |
55 // Used to post tasks back to main thread. | |
56 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | |
57 | |
58 // Used to store decoded video frame. | |
59 scoped_ptr<webrtc::DesktopFrame> buffer_; | |
60 | |
61 // Protects access to |buffer_|. | |
62 mutable base::Lock lock_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(Core); | |
65 }; | |
66 | |
67 TestVideoRenderer::Core::Core() | |
68 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
69 thread_checker_.DetachFromThread(); | |
70 } | |
71 | |
72 TestVideoRenderer::Core::~Core() { | |
73 DCHECK(thread_checker_.CalledOnValidThread()); | |
74 } | |
75 | |
76 void TestVideoRenderer::Core::Initialize() { | |
77 DCHECK(thread_checker_.CalledOnValidThread()); | |
78 } | |
79 | |
80 void TestVideoRenderer::Core::SetDecoderForDecoding( | |
81 const protocol::ChannelConfig::Codec codec) { | |
82 DCHECK(thread_checker_.CalledOnValidThread()); | |
83 | |
84 if (decoder_) { | |
85 LOG(WARNING) << "Decoder is set more than once"; | |
86 } | |
87 | |
88 switch (codec) { | |
89 case protocol::ChannelConfig::CODEC_VP8: { | |
90 DVLOG(2) << "Test Video Renderer will use VP8 decoder"; | |
91 decoder_ = VideoDecoderVpx::CreateForVP8(); | |
92 break; | |
93 } | |
94 case protocol::ChannelConfig::CODEC_VP9: { | |
95 DVLOG(2) << "Test Video Renderer will use VP9 decoder"; | |
96 decoder_ = VideoDecoderVpx::CreateForVP9(); | |
97 break; | |
98 } | |
99 case protocol::ChannelConfig::CODEC_VERBATIM: { | |
100 DVLOG(2) << "Test Video Renderer will use VERBATIM decoder"; | |
101 decoder_.reset(new VideoDecoderVerbatim()); | |
102 break; | |
103 } | |
104 default: { | |
105 NOTREACHED() << "Unsupported codec: " << codec; | |
106 } | |
107 } | |
108 } | |
109 | |
110 scoped_ptr<webrtc::DesktopFrame> | |
111 TestVideoRenderer::Core::GetBufferForTest() const { | |
112 base::AutoLock auto_lock(lock_); | |
113 DCHECK(buffer_); | |
114 return make_scoped_ptr(webrtc::BasicDesktopFrame::CopyOf(*buffer_.get())); | |
115 } | |
116 | |
117 void TestVideoRenderer::Core::ProcessVideoPacket( | |
118 scoped_ptr<VideoPacket> packet, const base::Closure& done) { | |
119 DCHECK(thread_checker_.CalledOnValidThread()); | |
120 DCHECK(decoder_); | |
121 DCHECK(packet); | |
122 | |
123 DVLOG(2) << "TestVideoRenderer::Core::ProcessVideoPacket() Called"; | |
124 | |
125 // Screen size is attached on the first packet as well as when the | |
126 // host screen is resized. | |
127 if (packet->format().has_screen_width() && | |
128 packet->format().has_screen_height()) { | |
129 webrtc::DesktopSize source_size(packet->format().screen_width(), | |
130 packet->format().screen_height()); | |
131 if (!screen_size_.equals(source_size)) { | |
132 screen_size_ = source_size; | |
133 decoder_->Initialize(screen_size_); | |
134 buffer_.reset(new webrtc::BasicDesktopFrame(screen_size_)); | |
135 } | |
136 } | |
137 | |
138 // To make life easier, assume that the desktop shape is a single rectangle. | |
139 packet->clear_use_desktop_shape(); | |
140 if (!decoder_->DecodePacket(*packet.get())) { | |
141 LOG(ERROR) << "Decoder::DecodePacket() failed."; | |
142 return; | |
143 } | |
144 | |
145 { | |
146 base::AutoLock auto_lock(lock_); | |
147 | |
148 // Render the decoded packet and write results to the buffer. | |
149 // Note that the |updated_region_| maintains the changed regions compared to | |
150 // previous video frame. | |
151 decoder_->RenderFrame(screen_size_, | |
152 webrtc::DesktopRect::MakeWH(screen_size_.width(), | |
153 screen_size_.height()), buffer_->data(), | |
154 buffer_->stride(), &updated_region_); | |
155 } | |
156 | |
157 main_task_runner_->PostTask(FROM_HERE, done); | |
158 } | |
159 | |
160 TestVideoRenderer::TestVideoRenderer() | |
161 : video_decode_thread_( | |
162 new base::Thread("TestVideoRendererVideoDecodingThread")), | |
163 weak_factory_(this) { | |
164 DCHECK(thread_checker_.CalledOnValidThread()); | |
165 | |
166 core_.reset(new Core()); | |
167 if (!video_decode_thread_->Start()) { | |
168 LOG(ERROR) << "Cannot start TestVideoRenderer"; | |
169 } else { | |
170 video_decode_task_runner_ = video_decode_thread_->task_runner(); | |
171 video_decode_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Initialize, | |
172 base::Unretained(core_.get()))); | |
173 } | |
14 } | 174 } |
15 | 175 |
16 TestVideoRenderer::~TestVideoRenderer() { | 176 TestVideoRenderer::~TestVideoRenderer() { |
177 DCHECK(thread_checker_.CalledOnValidThread()); | |
178 | |
179 video_decode_task_runner_->DeleteSoon(FROM_HERE, core_.release()); | |
180 | |
181 // The thread's message loop will run until it runs out of work. | |
182 video_decode_thread_->Stop(); | |
17 } | 183 } |
18 | 184 |
19 void TestVideoRenderer::OnSessionConfig(const protocol::SessionConfig& config) { | 185 void TestVideoRenderer::OnSessionConfig(const protocol::SessionConfig& config) { |
186 DCHECK(thread_checker_.CalledOnValidThread()); | |
187 | |
20 DVLOG(2) << "TestVideoRenderer::OnSessionConfig() Called"; | 188 DVLOG(2) << "TestVideoRenderer::OnSessionConfig() Called"; |
189 protocol::ChannelConfig::Codec codec = config.video_config().codec; | |
190 SetDecoderForDecoding(codec); | |
21 } | 191 } |
22 | 192 |
23 ChromotingStats* TestVideoRenderer::GetStats() { | 193 ChromotingStats* TestVideoRenderer::GetStats() { |
194 DCHECK(thread_checker_.CalledOnValidThread()); | |
195 | |
24 DVLOG(2) << "TestVideoRenderer::GetStats() Called"; | 196 DVLOG(2) << "TestVideoRenderer::GetStats() Called"; |
25 return nullptr; | 197 return nullptr; |
26 } | 198 } |
27 | 199 |
28 protocol::VideoStub* TestVideoRenderer::GetVideoStub() { | 200 protocol::VideoStub* TestVideoRenderer::GetVideoStub() { |
201 DCHECK(thread_checker_.CalledOnValidThread()); | |
202 | |
29 DVLOG(2) << "TestVideoRenderer::GetVideoStub() Called"; | 203 DVLOG(2) << "TestVideoRenderer::GetVideoStub() Called"; |
30 return this; | 204 return this; |
31 } | 205 } |
32 | 206 |
33 void TestVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, | 207 void TestVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, |
34 const base::Closure& done) { | 208 const base::Closure& done) { |
35 if (!video_packet->data().empty()) { | 209 DCHECK(thread_checker_.CalledOnValidThread()); |
36 // If the video frame was not a keep alive frame (i.e. not empty) then | 210 DCHECK(video_decode_task_runner_) << "Failed to start video decode thread"; |
37 // count it. | 211 |
38 DVLOG(2) << "Video Packet Processed, Total: " << ++video_frames_processed_; | 212 if (video_packet->has_data() && video_packet->data().size() != 0) { |
213 DVLOG(2) << "process video packet is called!"; | |
214 | |
215 // Post video process task to the video decode thread. | |
216 base::Closure process_video_task = base::Bind( | |
217 &TestVideoRenderer::Core::ProcessVideoPacket, | |
218 base::Unretained(core_.get()), base::Passed(&video_packet), done); | |
219 video_decode_task_runner_->PostTask(FROM_HERE, process_video_task); | |
39 } else { | 220 } else { |
40 // Log at a high verbosity level as we receive empty packets frequently and | 221 // Log at a high verbosity level as we receive empty packets frequently and |
41 // they can clutter up the debug output if the level is set too low. | 222 // they can clutter up the debug output if the level is set too low. |
42 DVLOG(3) << "Empty Video Packet received."; | 223 DVLOG(3) << "Empty Video Packet received."; |
43 } | 224 done.Run(); |
44 | 225 } |
45 done.Run(); | 226 } |
227 | |
228 void TestVideoRenderer::SetDecoderForDecoding( | |
229 const protocol::ChannelConfig::Codec codec) { | |
230 DCHECK(thread_checker_.CalledOnValidThread()); | |
231 | |
232 DVLOG(2) << "TestVideoRenderer::SetDecoder() Called"; | |
233 video_decode_task_runner_->PostTask( | |
234 FROM_HERE, base::Bind(&Core::SetDecoderForDecoding, | |
235 base::Unretained(core_.get()), | |
236 codec)); | |
237 } | |
238 | |
239 scoped_ptr<webrtc::DesktopFrame> TestVideoRenderer::GetBufferForTest() const { | |
240 DCHECK(thread_checker_.CalledOnValidThread()); | |
241 | |
242 return core_->GetBufferForTest(); | |
46 } | 243 } |
47 | 244 |
48 } // namespace test | 245 } // namespace test |
49 } // namespace remoting | 246 } // namespace remoting |
OLD | NEW |