Index: remoting/test/test_video_renderer.cc |
diff --git a/remoting/test/test_video_renderer.cc b/remoting/test/test_video_renderer.cc |
index 864356a112cb3ac37cd152516ec8cab26ad36ea5..2f474a5987bf40e1a7db27bbff4dad6cdd9ce84a 100644 |
--- a/remoting/test/test_video_renderer.cc |
+++ b/remoting/test/test_video_renderer.cc |
@@ -4,45 +4,242 @@ |
#include "remoting/test/test_video_renderer.h" |
+#include "base/bind.h" |
#include "base/logging.h" |
+#include "base/synchronization/lock.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/threading/thread.h" |
+#include "remoting/codec/video_decoder.h" |
+#include "remoting/codec/video_decoder_verbatim.h" |
+#include "remoting/codec/video_decoder_vpx.h" |
#include "remoting/proto/video.pb.h" |
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
+#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" |
namespace remoting { |
namespace test { |
-TestVideoRenderer::TestVideoRenderer() : video_frames_processed_(0) { |
+// Implements video decoding functionality. |
+class TestVideoRenderer::Core { |
+ public: |
+ Core(); |
+ ~Core(); |
+ |
+ // Initializes the internal structures of the class. |
+ void Initialize(); |
+ |
+ // Used to decode video packets. |
+ void ProcessVideoPacket(scoped_ptr<VideoPacket> packet, |
+ const base::Closure& done); |
+ |
+ // Initialize a decoder to decode video packets. |
+ 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.
|
+ |
+ // Returns a copy of the current buffer. |
+ scoped_ptr<webrtc::DesktopFrame> GetBufferForTest() const; |
+ |
+ private: |
+ // Used to ensure TestVideoRenderer::Core methods are called on the same |
+ // 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.
|
+ base::ThreadChecker thread_checker_; |
+ |
+ // Used to decode video packets. |
+ scoped_ptr<VideoDecoder> decoder_; |
+ |
+ // Updated region of the current desktop frame compared to previous one. |
+ webrtc::DesktopRegion updated_region_; |
+ |
+ // Screen size of the remote host. |
+ webrtc::DesktopSize screen_size_; |
+ |
+ // Used to post tasks back to main thread. |
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; |
+ |
+ // Used to store decoded video frame. |
+ scoped_ptr<webrtc::DesktopFrame> buffer_; |
+ |
+ // Protects access to |buffer_|. |
+ mutable base::Lock lock_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Core); |
+}; |
+ |
+TestVideoRenderer::Core::Core() |
+ : main_task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
+ thread_checker_.DetachFromThread(); |
+} |
+ |
+TestVideoRenderer::Core::~Core() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void TestVideoRenderer::Core::Initialize() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+} |
+ |
+void TestVideoRenderer::Core::SetDecoderForDecoding( |
+ const protocol::ChannelConfig::Codec codec) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (decoder_) { |
+ LOG(WARNING) << "Decoder is set more than once"; |
+ } |
+ |
+ switch (codec) { |
+ case protocol::ChannelConfig::CODEC_VP8: { |
+ DVLOG(2) << "Test Video Renderer will use VP8 decoder"; |
+ decoder_ = VideoDecoderVpx::CreateForVP8(); |
+ break; |
+ } |
+ case protocol::ChannelConfig::CODEC_VP9: { |
+ DVLOG(2) << "Test Video Renderer will use VP9 decoder"; |
+ decoder_ = VideoDecoderVpx::CreateForVP9(); |
+ break; |
+ } |
+ case protocol::ChannelConfig::CODEC_VERBATIM: { |
+ DVLOG(2) << "Test Video Renderer will use VERBATIM decoder"; |
+ decoder_.reset(new VideoDecoderVerbatim()); |
+ break; |
+ } |
+ default: { |
+ NOTREACHED() << "Unsupported codec: " << codec; |
+ } |
+ } |
+} |
+ |
+scoped_ptr<webrtc::DesktopFrame> |
+ TestVideoRenderer::Core::GetBufferForTest() const { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK(buffer_); |
+ return make_scoped_ptr(webrtc::BasicDesktopFrame::CopyOf(*buffer_.get())); |
+} |
+ |
+void TestVideoRenderer::Core::ProcessVideoPacket( |
+ scoped_ptr<VideoPacket> packet, const base::Closure& done) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(decoder_); |
+ DCHECK(packet); |
+ |
+ DVLOG(2) << "TestVideoRenderer::Core::ProcessVideoPacket() Called"; |
+ |
+ // Screen size is attached on the first packet as well as when the |
+ // host screen is resized. |
+ if (packet->format().has_screen_width() && |
+ packet->format().has_screen_height()) { |
+ webrtc::DesktopSize source_size(packet->format().screen_width(), |
+ packet->format().screen_height()); |
+ if (!screen_size_.equals(source_size)) { |
+ screen_size_ = source_size; |
+ decoder_->Initialize(screen_size_); |
+ buffer_.reset(new webrtc::BasicDesktopFrame(screen_size_)); |
+ } |
+ } |
+ |
+ // To make life easier, assume that the desktop shape is a single rectangle. |
+ packet->clear_use_desktop_shape(); |
+ if (!decoder_->DecodePacket(*packet.get())) { |
+ LOG(ERROR) << "Decoder::DecodePacket() failed."; |
+ return; |
+ } |
+ |
+ { |
+ base::AutoLock auto_lock(lock_); |
+ |
+ // Render the decoded packet and write results to the buffer. |
+ // Note that the |updated_region_| maintains the changed regions compared to |
+ // previous video frame. |
+ decoder_->RenderFrame(screen_size_, |
+ webrtc::DesktopRect::MakeWH(screen_size_.width(), |
+ screen_size_.height()), buffer_->data(), |
+ buffer_->stride(), &updated_region_); |
+ } |
+ |
+ main_task_runner_->PostTask(FROM_HERE, done); |
+} |
+ |
+TestVideoRenderer::TestVideoRenderer() |
+ : video_decode_thread_( |
+ new base::Thread("TestVideoRendererVideoDecodingThread")), |
+ weak_factory_(this) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ core_.reset(new Core()); |
+ if (!video_decode_thread_->Start()) { |
+ LOG(ERROR) << "Cannot start TestVideoRenderer"; |
+ } else { |
+ video_decode_task_runner_ = video_decode_thread_->task_runner(); |
+ video_decode_task_runner_->PostTask(FROM_HERE, base::Bind(&Core::Initialize, |
+ base::Unretained(core_.get()))); |
+ } |
} |
TestVideoRenderer::~TestVideoRenderer() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ video_decode_task_runner_->DeleteSoon(FROM_HERE, core_.release()); |
+ |
+ // The thread's message loop will run until it runs out of work. |
+ video_decode_thread_->Stop(); |
} |
void TestVideoRenderer::OnSessionConfig(const protocol::SessionConfig& config) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
DVLOG(2) << "TestVideoRenderer::OnSessionConfig() Called"; |
+ protocol::ChannelConfig::Codec codec = config.video_config().codec; |
+ SetDecoderForDecoding(codec); |
} |
ChromotingStats* TestVideoRenderer::GetStats() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
DVLOG(2) << "TestVideoRenderer::GetStats() Called"; |
return nullptr; |
} |
protocol::VideoStub* TestVideoRenderer::GetVideoStub() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
DVLOG(2) << "TestVideoRenderer::GetVideoStub() Called"; |
return this; |
} |
void TestVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, |
const base::Closure& done) { |
- if (!video_packet->data().empty()) { |
- // If the video frame was not a keep alive frame (i.e. not empty) then |
- // count it. |
- DVLOG(2) << "Video Packet Processed, Total: " << ++video_frames_processed_; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(video_decode_task_runner_) << "Failed to start video decode thread"; |
+ |
+ if (video_packet->has_data() && video_packet->data().size() != 0) { |
+ DVLOG(2) << "process video packet is called!"; |
+ |
+ // Post video process task to the video decode thread. |
+ base::Closure process_video_task = base::Bind( |
+ &TestVideoRenderer::Core::ProcessVideoPacket, |
+ base::Unretained(core_.get()), base::Passed(&video_packet), done); |
+ video_decode_task_runner_->PostTask(FROM_HERE, process_video_task); |
} else { |
// Log at a high verbosity level as we receive empty packets frequently and |
// they can clutter up the debug output if the level is set too low. |
DVLOG(3) << "Empty Video Packet received."; |
+ done.Run(); |
} |
+} |
+ |
+void TestVideoRenderer::SetDecoderForDecoding( |
+ const protocol::ChannelConfig::Codec codec) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ DVLOG(2) << "TestVideoRenderer::SetDecoder() Called"; |
+ video_decode_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Core::SetDecoderForDecoding, |
+ base::Unretained(core_.get()), |
+ codec)); |
+} |
+ |
+scoped_ptr<webrtc::DesktopFrame> TestVideoRenderer::GetBufferForTest() const { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
- done.Run(); |
+ return core_->GetBufferForTest(); |
} |
} // namespace test |