| OLD | NEW |
| (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/cast_video_capturer_adapter.h" | |
| 6 | |
| 7 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
| 8 | |
| 9 namespace remoting { | |
| 10 | |
| 11 // Number of frames to be captured per second. | |
| 12 const int kFramesPerSec = 10; | |
| 13 | |
| 14 CastVideoCapturerAdapter::CastVideoCapturerAdapter( | |
| 15 scoped_ptr<webrtc::DesktopCapturer> capturer) | |
| 16 : desktop_capturer_(capturer.Pass()) { | |
| 17 DCHECK(desktop_capturer_); | |
| 18 | |
| 19 thread_checker_.DetachFromThread(); | |
| 20 | |
| 21 // Disable video adaptation since we don't intend to use it. | |
| 22 set_enable_video_adapter(false); | |
| 23 } | |
| 24 | |
| 25 CastVideoCapturerAdapter::~CastVideoCapturerAdapter() { | |
| 26 DCHECK(!capture_timer_); | |
| 27 } | |
| 28 | |
| 29 webrtc::SharedMemory* CastVideoCapturerAdapter::CreateSharedMemory( | |
| 30 size_t size) { | |
| 31 return nullptr; | |
| 32 } | |
| 33 | |
| 34 void CastVideoCapturerAdapter::OnCaptureCompleted(webrtc::DesktopFrame* frame) { | |
| 35 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); | |
| 36 | |
| 37 // Drop the owned_frame if there were no changes. | |
| 38 if (!owned_frame || owned_frame->updated_region().is_empty()) { | |
| 39 owned_frame.reset(); | |
| 40 return; | |
| 41 } | |
| 42 | |
| 43 // Convert the webrtc::DesktopFrame to a cricket::CapturedFrame. | |
| 44 cricket::CapturedFrame captured_frame; | |
| 45 captured_frame.width = owned_frame->size().width(); | |
| 46 captured_frame.height = owned_frame->size().height(); | |
| 47 base::TimeTicks current_time = base::TimeTicks::Now(); | |
| 48 captured_frame.time_stamp = | |
| 49 current_time.ToInternalValue() * base::Time::kNanosecondsPerMicrosecond; | |
| 50 captured_frame.data = owned_frame->data(); | |
| 51 | |
| 52 // The data_size attribute must be set. If multiple formats are supported, | |
| 53 // this should be set appropriately for each one. | |
| 54 captured_frame.data_size = | |
| 55 (captured_frame.width * webrtc::DesktopFrame::kBytesPerPixel * 8 + 7) / | |
| 56 8 * captured_frame.height; | |
| 57 captured_frame.fourcc = cricket::FOURCC_ARGB; | |
| 58 | |
| 59 SignalFrameCaptured(this, &captured_frame); | |
| 60 } | |
| 61 | |
| 62 bool CastVideoCapturerAdapter::GetBestCaptureFormat( | |
| 63 const cricket::VideoFormat& desired, | |
| 64 cricket::VideoFormat* best_format) { | |
| 65 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 66 | |
| 67 // For now, just used the desired width and height. | |
| 68 best_format->width = desired.width; | |
| 69 best_format->height = desired.height; | |
| 70 best_format->fourcc = cricket::FOURCC_ARGB; | |
| 71 best_format->interval = FPS_TO_INTERVAL(kFramesPerSec); | |
| 72 return true; | |
| 73 } | |
| 74 | |
| 75 cricket::CaptureState CastVideoCapturerAdapter::Start( | |
| 76 const cricket::VideoFormat& capture_format) { | |
| 77 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 78 DCHECK(!capture_timer_); | |
| 79 DCHECK_EQ(capture_format.fourcc, (static_cast<uint32>(cricket::FOURCC_ARGB))); | |
| 80 | |
| 81 if (!desktop_capturer_) { | |
| 82 VLOG(1) << "CastVideoCapturerAdapter failed to start."; | |
| 83 return cricket::CS_FAILED; | |
| 84 } | |
| 85 | |
| 86 // This is required to tell the cricket::VideoCapturer base class what the | |
| 87 // capture format will be. | |
| 88 SetCaptureFormat(&capture_format); | |
| 89 | |
| 90 desktop_capturer_->Start(this); | |
| 91 | |
| 92 capture_timer_.reset(new base::RepeatingTimer()); | |
| 93 capture_timer_->Start(FROM_HERE, | |
| 94 base::TimeDelta::FromMicroseconds( | |
| 95 GetCaptureFormat()->interval / | |
| 96 (base::Time::kNanosecondsPerMicrosecond)), | |
| 97 this, | |
| 98 &CastVideoCapturerAdapter::CaptureNextFrame); | |
| 99 | |
| 100 return cricket::CS_RUNNING; | |
| 101 } | |
| 102 | |
| 103 // Similar to the base class implementation with some important differences: | |
| 104 // 1. Does not call either Stop() or Start(), as those would affect the state of | |
| 105 // |desktop_capturer_|. | |
| 106 // 2. Does not support unpausing after stopping the capturer. It is unclear | |
| 107 // if that flow needs to be supported. | |
| 108 bool CastVideoCapturerAdapter::Pause(bool pause) { | |
| 109 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 110 | |
| 111 if (pause) { | |
| 112 if (capture_state() == cricket::CS_PAUSED) | |
| 113 return true; | |
| 114 | |
| 115 bool running = capture_state() == cricket::CS_STARTING || | |
| 116 capture_state() == cricket::CS_RUNNING; | |
| 117 | |
| 118 DCHECK_EQ(running, IsRunning()); | |
| 119 | |
| 120 if (!running) { | |
| 121 LOG(ERROR) | |
| 122 << "Cannot pause CastVideoCapturerAdapter."; | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 // Stop |capture_timer_| and set capture state to cricket::CS_PAUSED. | |
| 127 capture_timer_->Stop(); | |
| 128 SetCaptureState(cricket::CS_PAUSED); | |
| 129 | |
| 130 VLOG(1) << "CastVideoCapturerAdapter paused."; | |
| 131 | |
| 132 return true; | |
| 133 } else { // Unpausing. | |
| 134 if (capture_state() != cricket::CS_PAUSED || !GetCaptureFormat() || | |
| 135 !capture_timer_) { | |
| 136 LOG(ERROR) << "Cannot unpause CastVideoCapturerAdapter."; | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 // Restart |capture_timer_| and set capture state to cricket::CS_RUNNING; | |
| 141 capture_timer_->Start(FROM_HERE, | |
| 142 base::TimeDelta::FromMicroseconds( | |
| 143 GetCaptureFormat()->interval / | |
| 144 (base::Time::kNanosecondsPerMicrosecond)), | |
| 145 this, | |
| 146 &CastVideoCapturerAdapter::CaptureNextFrame); | |
| 147 SetCaptureState(cricket::CS_RUNNING); | |
| 148 | |
| 149 VLOG(1) << "CastVideoCapturerAdapter unpaused."; | |
| 150 } | |
| 151 return true; | |
| 152 } | |
| 153 | |
| 154 void CastVideoCapturerAdapter::Stop() { | |
| 155 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 156 DCHECK_NE(capture_state(), cricket::CS_STOPPED); | |
| 157 | |
| 158 capture_timer_.reset(); | |
| 159 | |
| 160 SetCaptureFormat(nullptr); | |
| 161 SetCaptureState(cricket::CS_STOPPED); | |
| 162 | |
| 163 VLOG(1) << "CastVideoCapturerAdapter stopped."; | |
| 164 } | |
| 165 | |
| 166 | |
| 167 bool CastVideoCapturerAdapter::IsRunning() { | |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 169 | |
| 170 return capture_timer_->IsRunning(); | |
| 171 } | |
| 172 | |
| 173 bool CastVideoCapturerAdapter::IsScreencast() const { | |
| 174 return true; | |
| 175 } | |
| 176 | |
| 177 bool CastVideoCapturerAdapter::GetPreferredFourccs( | |
| 178 std::vector<uint32>* fourccs) { | |
| 179 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 180 if (!fourccs) | |
| 181 return false; | |
| 182 fourccs->push_back(cricket::FOURCC_ARGB); | |
| 183 return true; | |
| 184 } | |
| 185 | |
| 186 void CastVideoCapturerAdapter::CaptureNextFrame() { | |
| 187 // If we are paused, then don't capture. | |
| 188 if (!IsRunning()) | |
| 189 return; | |
| 190 | |
| 191 desktop_capturer_->Capture(webrtc::DesktopRegion()); | |
| 192 } | |
| 193 | |
| 194 } // namespace remoting | |
| 195 | |
| OLD | NEW |