diff --git a/remoting/host/video_frame_recorder.cc b/remoting/host/video_frame_recorder.cc deleted file mode 100644 index cccfe7cd90b5d..0000000000000 --- a/remoting/host/video_frame_recorder.cc +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/video_frame_recorder.h" - -#include "base/bind.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/stl_util.h" -#include "base/thread_task_runner_handle.h" -#include "remoting/codec/video_encoder.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_geometry.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" - -namespace remoting { - -static int64_t FrameContentSize(const webrtc::DesktopFrame* frame) { - DCHECK_GT(frame->stride(), 0); - return frame->stride() * frame->size().height(); -} - -// VideoEncoder wrapper used to intercept frames passed to a real VideoEncoder. -class VideoFrameRecorder::RecordingVideoEncoder : public VideoEncoder { - public: - RecordingVideoEncoder(scoped_ptr encoder, - scoped_refptr recorder_task_runner, - base::WeakPtr recorder) - : encoder_(encoder.Pass()), - recorder_task_runner_(recorder_task_runner), - recorder_(recorder), - enable_recording_(false), - weak_factory_(this) { - DCHECK(encoder_); - DCHECK(recorder_task_runner_); - } - - base::WeakPtr AsWeakPtr() { - return weak_factory_.GetWeakPtr(); - } - - void SetEnableRecording(bool enable_recording) { - DCHECK(!encoder_task_runner_ || - encoder_task_runner_->BelongsToCurrentThread()); - enable_recording_ = enable_recording; - } - - // remoting::VideoEncoder interface. - virtual void SetLosslessEncode(bool want_lossless) OVERRIDE { - encoder_->SetLosslessEncode(want_lossless); - } - virtual void SetLosslessColor(bool want_lossless) OVERRIDE { - encoder_->SetLosslessColor(want_lossless); - } - virtual scoped_ptr Encode( - const webrtc::DesktopFrame& frame) OVERRIDE { - // If this is the first Encode() then store the TaskRunner and inform the - // VideoFrameRecorder so it can post SetEnableRecording() on it. - if (!encoder_task_runner_) { - encoder_task_runner_ = base::ThreadTaskRunnerHandle::Get(); - recorder_task_runner_->PostTask(FROM_HERE, - base::Bind(&VideoFrameRecorder::SetEncoderTaskRunner, - recorder_, - encoder_task_runner_)); - } - - DCHECK(encoder_task_runner_->BelongsToCurrentThread()); - - if (enable_recording_) { - // Copy the frame and post it to the VideoFrameRecorder to store. - scoped_ptr frame_copy( - new webrtc::BasicDesktopFrame(frame.size())); - *frame_copy->mutable_updated_region() = frame.updated_region(); - frame_copy->set_dpi(frame.dpi()); - frame_copy->CopyPixelsFrom(frame.data(), - frame.stride(), - webrtc::DesktopRect::MakeSize(frame.size())); - recorder_task_runner_->PostTask(FROM_HERE, - base::Bind(&VideoFrameRecorder::RecordFrame, - recorder_, - base::Passed(&frame_copy))); - } - - return encoder_->Encode(frame); - } - - private: - scoped_ptr encoder_; - scoped_refptr recorder_task_runner_; - base::WeakPtr recorder_; - - bool enable_recording_; - scoped_refptr encoder_task_runner_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(RecordingVideoEncoder); -}; - -VideoFrameRecorder::VideoFrameRecorder() - : content_bytes_(0), - max_content_bytes_(0), - enable_recording_(false), - weak_factory_(this) { -} - -VideoFrameRecorder::~VideoFrameRecorder() { - SetEnableRecording(false); - STLDeleteElements(&recorded_frames_); -} - -scoped_ptr VideoFrameRecorder::WrapVideoEncoder( - scoped_ptr encoder) { - DCHECK(!caller_task_runner_); - caller_task_runner_ = base::ThreadTaskRunnerHandle::Get(); - - scoped_ptr recording_encoder( - new RecordingVideoEncoder(encoder.Pass(), - caller_task_runner_, - weak_factory_.GetWeakPtr())); - recording_encoder_ = recording_encoder->AsWeakPtr(); - - return recording_encoder.PassAs(); -} - -void VideoFrameRecorder::SetEnableRecording(bool enable_recording) { - DCHECK(!caller_task_runner_ || caller_task_runner_->BelongsToCurrentThread()); - - if (enable_recording_ == enable_recording) { - return; - } - enable_recording_ = enable_recording; - - if (encoder_task_runner_) { - encoder_task_runner_->PostTask(FROM_HERE, - base::Bind(&RecordingVideoEncoder::SetEnableRecording, - recording_encoder_, - enable_recording_)); - } -} - -void VideoFrameRecorder::SetMaxContentBytes(int64_t max_content_bytes) { - DCHECK(!caller_task_runner_ || caller_task_runner_->BelongsToCurrentThread()); - DCHECK_GE(max_content_bytes, 0); - - max_content_bytes_ = max_content_bytes; -} - -scoped_ptr VideoFrameRecorder::NextFrame() { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - scoped_ptr frame; - if (!recorded_frames_.empty()) { - frame.reset(recorded_frames_.front()); - recorded_frames_.pop_front(); - content_bytes_ -= FrameContentSize(frame.get()); - DCHECK_GE(content_bytes_, 0); - } - - return frame.Pass(); -} - -void VideoFrameRecorder::SetEncoderTaskRunner( - scoped_refptr task_runner) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - DCHECK(!encoder_task_runner_); - DCHECK(task_runner); - - encoder_task_runner_ = task_runner; - - // If the caller already enabled recording, inform the recording encoder. - if (enable_recording_ && encoder_task_runner_) { - encoder_task_runner_->PostTask(FROM_HERE, - base::Bind(&RecordingVideoEncoder::SetEnableRecording, - recording_encoder_, - enable_recording_)); - } -} - -void VideoFrameRecorder::RecordFrame(scoped_ptr frame) { - DCHECK(caller_task_runner_->BelongsToCurrentThread()); - - int64_t frame_bytes = FrameContentSize(frame.get()); - DCHECK_GE(frame_bytes, 0); - - // Purge existing frames until there is space for the new one. - while (content_bytes_ + frame_bytes > max_content_bytes_ && - !recorded_frames_.empty()) { - scoped_ptr drop_frame(recorded_frames_.front()); - recorded_frames_.pop_front(); - content_bytes_ -= FrameContentSize(drop_frame.get()); - DCHECK_GE(content_bytes_, 0); - } - - // If the frame is still too big, ignore it. - if (content_bytes_ + frame_bytes > max_content_bytes_) { - return; - } - - // Store the frame and update the content byte count. - recorded_frames_.push_back(frame.release()); - content_bytes_ += frame_bytes; -} - -} // namespace remoting diff --git a/remoting/host/video_frame_recorder.h b/remoting/host/video_frame_recorder.h deleted file mode 100644 index c204c9ac39cdb..0000000000000 --- a/remoting/host/video_frame_recorder.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_HOST_VIDEO_FRAME_RECORDER_H_ -#define REMOTING_HOST_VIDEO_FRAME_RECORDER_H_ - -#include -#include - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" - -namespace webrtc { -class DesktopFrame; -} - -namespace remoting { - -class VideoEncoder; - -// Allows sequences of DesktopFrames passed to a VideoEncoder to be recorded. -// -// VideoFrameRecorder is design to support applications which use a dedicated -// thread for video encoding, but need to manage that process from a "main" -// or "control" thread. -// -// On the control thread: -// 1. Create the VideoFrameRecorder on the controlling thread. -// 2. Specify the amount of memory that may be used for recording. -// 3. Call WrapVideoEncoder(), passing the actual VideoEncoder that will be -// used to encode frames. -// 4. Hand the returned wrapper VideoEncoder of to the video encoding thread, -// to call in place of the actual VideoEncoder. -// 5. Start/stop frame recording as necessary. -// 6. Use NextFrame() to read each recorded frame in sequence. -// -// The wrapper VideoEncoder is designed to be handed off to the video encoding -// thread, and used and torn down there. -// -// The VideoFrameRecorder and VideoEncoder may be torn down in any order; frame -// recording will stop as soon as either is destroyed. - -class VideoFrameRecorder { - public: - VideoFrameRecorder(); - virtual ~VideoFrameRecorder(); - - // Wraps the supplied VideoEncoder, returning a replacement VideoEncoder that - // will route frames to the recorder, as well as passing them for encoding. - // This may be called at most once on each VideoFrameRecorder instance. - scoped_ptr WrapVideoEncoder(scoped_ptr encoder); - - // Enables/disables frame recording. Frame recording is initially disabled. - void SetEnableRecording(bool enable_recording); - - // Sets the maximum number of bytes of pixel data that may be recorded. - // When this maximum is reached older frames will be discard to make space - // for new ones. - void SetMaxContentBytes(int64_t max_content_bytes); - - // Pops the next recorded frame in the sequence, and returns it. - scoped_ptr NextFrame(); - - private: - class RecordingVideoEncoder; - friend class RecordingVideoEncoder; - - void SetEncoderTaskRunner(scoped_refptr task_runner); - void RecordFrame(scoped_ptr frame); - - // The recorded frames, in sequence. - std::list recorded_frames_; - - // Size of the recorded frames' content, in bytes. - int64_t content_bytes_; - - // Size that recorded frames' content must not exceed. - int64_t max_content_bytes_; - - // True if recording is started, false otherwise. - bool enable_recording_; - - // Task runner on which the wrapper VideoEncoder is being run. - scoped_refptr encoder_task_runner_; - - // Weak reference to the wrapper VideoEncoder, to use to control it. - base::WeakPtr recording_encoder_; - - scoped_refptr caller_task_runner_; - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(VideoFrameRecorder); -}; - -} // namespace remoting - -#endif // REMOTING_HOST_VIDEO_FRAME_RECORDER_H_ diff --git a/remoting/host/video_frame_recorder_unittest.cc b/remoting/host/video_frame_recorder_unittest.cc deleted file mode 100644 index 907c4a9aa58b0..0000000000000 --- a/remoting/host/video_frame_recorder_unittest.cc +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/video_frame_recorder.h" - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "remoting/codec/video_encoder_verbatim.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" - -namespace webrtc { - -// Define equality operator for DesktopFrame to allow use of EXPECT_EQ(). -static bool operator==(const DesktopFrame& a, - const DesktopFrame& b) { - if ((a.size().equals(b.size())) && - (a.updated_region().Equals(b.updated_region())) && - (a.dpi().equals(b.dpi()))) { - for (int i = 0; i < a.size().height(); ++i) { - if (memcmp(a.data() + a.stride() * i, - b.data() + b.stride() * i, - a.size().width() * DesktopFrame::kBytesPerPixel) != 0) { - return false; - } - } - return true; - } - return false; -} - -} // namespace - -namespace remoting { - -const int64_t kMaxContentBytes = 10 * 1024 * 1024; -const int kWidth = 640; -const int kHeight = 480; -const int kTestFrameCount = 6; - -class VideoFrameRecorderTest : public testing::Test { - public: - VideoFrameRecorderTest(); - - virtual void SetUp() OVERRIDE; - virtual void TearDown() OVERRIDE; - - void CreateAndWrapEncoder(); - scoped_ptr CreateNextFrame(); - void CreateTestFrames(); - void EncodeTestFrames(); - void EncodeDummyFrame(); - void StartRecording(); - void VerifyTestFrames(); - - protected: - base::MessageLoop message_loop_; - - scoped_ptr recorder_; - scoped_ptr encoder_; - - std::list test_frames_; - int frame_count_; -}; - -VideoFrameRecorderTest::VideoFrameRecorderTest() : frame_count_(0) {} - -void VideoFrameRecorderTest::SetUp() { - recorder_.reset(new VideoFrameRecorder()); - recorder_->SetMaxContentBytes(kMaxContentBytes); -} - -void VideoFrameRecorderTest::TearDown() { - // Allow events posted to the recorder_, if still valid, to be processed. - base::RunLoop().RunUntilIdle(); - - // Tear down the recorder, if necessary. - recorder_.reset(); - - // Process any events resulting from recorder teardown. - base::RunLoop().RunUntilIdle(); -} - -void VideoFrameRecorderTest::CreateAndWrapEncoder() { - scoped_ptr encoder(new VideoEncoderVerbatim()); - encoder_ = recorder_->WrapVideoEncoder(encoder.Pass()); - - // Encode a dummy frame to bind the wrapper to the TaskRunner. - EncodeDummyFrame(); -} - -scoped_ptr VideoFrameRecorderTest::CreateNextFrame() { - scoped_ptr frame( - new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight))); - - // Fill content, DPI and updated-region based on |frame_count_| so that each - // generated frame is different. - memset(frame->data(), frame_count_, frame->stride() * kHeight); - frame->set_dpi(webrtc::DesktopVector(frame_count_, frame_count_)); - frame->mutable_updated_region()->SetRect( - webrtc::DesktopRect::MakeWH(frame_count_, frame_count_)); - ++frame_count_; - - return frame.Pass(); -} - -void VideoFrameRecorderTest::CreateTestFrames() { - for (int i=0; i < kTestFrameCount; ++i) { - test_frames_.push_back(CreateNextFrame().release()); - } -} - -void VideoFrameRecorderTest::EncodeTestFrames() { - std::list::iterator i; - for (i = test_frames_.begin(); i != test_frames_.end(); ++i) { - scoped_ptr packet = encoder_->Encode(*(*i)); - - // Process tasks to let the recorder pick up the frame. - base::RunLoop().RunUntilIdle(); - } -} - -void VideoFrameRecorderTest::EncodeDummyFrame() { - webrtc::BasicDesktopFrame dummy_frame(webrtc::DesktopSize(kWidth, kHeight)); - scoped_ptr packet = encoder_->Encode(dummy_frame); - base::RunLoop().RunUntilIdle(); -} - -void VideoFrameRecorderTest::StartRecording() { - // Start the recorder and pump events to let things initialize. - recorder_->SetEnableRecording(true); - base::RunLoop().RunUntilIdle(); -} - -void VideoFrameRecorderTest::VerifyTestFrames() { - // Verify that the recorded frames match the ones passed to the encoder. - while (!test_frames_.empty()) { - scoped_ptr recorded_frame(recorder_->NextFrame()); - ASSERT_TRUE(recorded_frame); - - scoped_ptr expected_frame(test_frames_.front()); - test_frames_.pop_front(); - - EXPECT_EQ(*recorded_frame, *expected_frame); - } - - EXPECT_FALSE(recorder_->NextFrame()); -} - -// Basic test that creating & tearing down VideoFrameRecorder doesn't crash. -TEST_F(VideoFrameRecorderTest, CreateDestroy) { -} - -// Basic test that creating, starting, stopping and destroying a -// VideoFrameRecorder don't end the world. -TEST_F(VideoFrameRecorderTest, StartStop) { - StartRecording(); - recorder_->SetEnableRecording(false); -} - -// Test that tearing down the VideoFrameRecorder while the VideoEncoder -// wrapper exists doesn't crash. -TEST_F(VideoFrameRecorderTest, DestroyVideoFrameRecorderFirst) { - CreateAndWrapEncoder(); - - // Start the recorder, so that the wrapper will push frames to it. - StartRecording(); - - // Tear down the recorder. - recorder_.reset(); - - // Encode a dummy frame via the wrapper to ensure we don't crash. - EncodeDummyFrame(); -} - -// Test that creating & tearing down the wrapper while the -// VideoFrameRecorder still exists doesn't crash. -TEST_F(VideoFrameRecorderTest, DestroyVideoEncoderWrapperFirst) { - CreateAndWrapEncoder(); - - // Start the recorder, so that the wrapper will push frames to it. - StartRecording(); - - // Encode a dummy frame via the wrapper to ensure we don't crash. - EncodeDummyFrame(); - - // Tear down the encoder wrapper. - encoder_.reset(); - - // Test teardown will stop the recorder and process pending events. -} - -// Test that when asked to encode a short sequence of frames, those frames are -// all recorded, in sequence. -TEST_F(VideoFrameRecorderTest, RecordFrames) { - CreateAndWrapEncoder(); - - // Start the recorder, so that the wrapper will push frames to it. - StartRecording(); - - // Create frames, store them and pass them to the encoder. - CreateTestFrames(); - EncodeTestFrames(); - - // Verify that the recorded frames match the ones passed to the encoder. - VerifyTestFrames(); -} - -// Test that when asked to record more frames than the maximum content bytes -// limit allows, the first encoded frames are dropped. -TEST_F(VideoFrameRecorderTest, MaxContentBytesEnforced) { - CreateAndWrapEncoder(); - - // Configure a maximum content size sufficient for five and a half frames. - int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; - recorder_->SetMaxContentBytes((frame_bytes * 11) / 2); - - // Start the recorder, so that the wrapper will push frames to it. - StartRecording(); - - // Create frames, store them and pass them to the encoder. - CreateTestFrames(); - EncodeTestFrames(); - - // Only five of the supplied frames should have been recorded. - while (test_frames_.size() > 5) { - scoped_ptr frame(test_frames_.front()); - test_frames_.pop_front(); - } - - // Verify that the recorded frames match the ones passed to the encoder. - VerifyTestFrames(); -} - -// Test that when asked to record more frames than the maximum content bytes -// limit allows, the first encoded frames are dropped. -TEST_F(VideoFrameRecorderTest, ContentBytesUpdatedByNextFrame) { - CreateAndWrapEncoder(); - - // Configure a maximum content size sufficient for kTestFrameCount frames. - int64 frame_bytes = kWidth * kHeight * webrtc::DesktopFrame::kBytesPerPixel; - recorder_->SetMaxContentBytes(frame_bytes * kTestFrameCount); - - // Start the recorder, so that the wrapper will push frames to it. - StartRecording(); - - // Encode a frame, to record it, and consume it from the recorder. - EncodeDummyFrame(); - scoped_ptr frame = recorder_->NextFrame(); - EXPECT_TRUE(frame); - - // Create frames, store them and pass them to the encoder. - CreateTestFrames(); - EncodeTestFrames(); - - // Verify that the recorded frames match the ones passed to the encoder. - VerifyTestFrames(); -} - -// Test that when asked to encode a short sequence of frames, none are recorded -// if recording was not enabled. -TEST_F(VideoFrameRecorderTest, EncodeButDontRecord) { - CreateAndWrapEncoder(); - - // Create frames, store them and pass them to the encoder. - CreateTestFrames(); - EncodeTestFrames(); - - // Clear the list of expected test frames, since none should be recorded. - test_frames_.clear(); - - // Verify that the recorded frames match the ones passed to the encoder. - VerifyTestFrames(); -} - -} // namespace remoting diff --git a/remoting/remoting_host.gypi b/remoting/remoting_host.gypi index d7d87ec02af33..47d60fac7872c 100644 --- a/remoting/remoting_host.gypi +++ b/remoting/remoting_host.gypi @@ -244,8 +244,6 @@ 'host/usage_stats_consent_win.cc', 'host/username.cc', 'host/username.h', - 'host/video_frame_recorder.cc', - 'host/video_frame_recorder.h', 'host/video_scheduler.cc', 'host/video_scheduler.h', 'host/win/com_imported_mstscax.tlh', diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 35111b4161a87..7fef1c39d4661 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi @@ -114,7 +114,6 @@ 'host/setup/pin_validator_unittest.cc', 'host/shaped_screen_capturer_unittest.cc', 'host/token_validator_factory_impl_unittest.cc', - 'host/video_frame_recorder_unittest.cc', 'host/video_scheduler_unittest.cc', 'host/win/rdp_client_unittest.cc', 'host/win/worker_process_launcher.cc',