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