Upstream version 10.39.233.0
[platform/framework/web/crosswalk.git] / src / remoting / host / cast_video_capturer_adapter.cc
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 NULL;
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.elapsed_time = (current_time - start_time_).InMicroseconds() *
49                                 base::Time::kNanosecondsPerMicrosecond;
50   captured_frame.time_stamp =
51       current_time.ToInternalValue() * base::Time::kNanosecondsPerMicrosecond;
52   captured_frame.data = owned_frame->data();
53
54   // The data_size attribute must be set. If multiple formats are supported,
55   // this should be set appropriately for each one.
56   captured_frame.data_size =
57       (captured_frame.width * webrtc::DesktopFrame::kBytesPerPixel * 8 + 7) /
58       8 * captured_frame.height;
59   captured_frame.fourcc = cricket::FOURCC_ARGB;
60
61   SignalFrameCaptured(this, &captured_frame);
62 }
63
64 bool CastVideoCapturerAdapter::GetBestCaptureFormat(
65     const cricket::VideoFormat& desired,
66     cricket::VideoFormat* best_format) {
67   DCHECK(thread_checker_.CalledOnValidThread());
68
69   // For now, just used the desired width and height.
70   best_format->width = desired.width;
71   best_format->height = desired.height;
72   best_format->fourcc = cricket::FOURCC_ARGB;
73   best_format->interval = FPS_TO_INTERVAL(kFramesPerSec);
74   return true;
75 }
76
77 cricket::CaptureState CastVideoCapturerAdapter::Start(
78     const cricket::VideoFormat& capture_format) {
79   DCHECK(thread_checker_.CalledOnValidThread());
80   DCHECK(!capture_timer_);
81   DCHECK_EQ(capture_format.fourcc, (static_cast<uint32>(cricket::FOURCC_ARGB)));
82
83   if (!desktop_capturer_) {
84     VLOG(1) << "CastVideoCapturerAdapter failed to start.";
85     return cricket::CS_FAILED;
86   }
87
88   // This is required to tell the cricket::VideoCapturer base class what the
89   // capture format will be.
90   SetCaptureFormat(&capture_format);
91
92   desktop_capturer_->Start(this);
93
94   // Save the Start() time of |desktop_capturer_|. This will be used
95   // to estimate the creation time of the frame source, to set the elapsed_time
96   // of future CapturedFrames in OnCaptureCompleted().
97   start_time_ = base::TimeTicks::Now();
98   capture_timer_.reset(new base::RepeatingTimer<CastVideoCapturerAdapter>());
99   capture_timer_->Start(FROM_HERE,
100                         base::TimeDelta::FromMicroseconds(
101                             GetCaptureFormat()->interval /
102                             (base::Time::kNanosecondsPerMicrosecond)),
103                         this,
104                         &CastVideoCapturerAdapter::CaptureNextFrame);
105
106   return cricket::CS_RUNNING;
107 }
108
109 // Similar to the base class implementation with some important differences:
110 // 1. Does not call either Stop() or Start(), as those would affect the state of
111 // |desktop_capturer_|.
112 // 2. Does not support unpausing after stopping the capturer. It is unclear
113 // if that flow needs to be supported.
114 bool CastVideoCapturerAdapter::Pause(bool pause) {
115   DCHECK(thread_checker_.CalledOnValidThread());
116
117   if (pause) {
118     if (capture_state() == cricket::CS_PAUSED)
119       return true;
120
121     bool running = capture_state() == cricket::CS_STARTING ||
122                    capture_state() == cricket::CS_RUNNING;
123
124     DCHECK_EQ(running, IsRunning());
125
126     if (!running) {
127       LOG(ERROR)
128           << "Cannot pause CastVideoCapturerAdapter.";
129       return false;
130     }
131
132     // Stop |capture_timer_| and set capture state to cricket::CS_PAUSED.
133     capture_timer_->Stop();
134     SetCaptureState(cricket::CS_PAUSED);
135
136     VLOG(1) << "CastVideoCapturerAdapter paused.";
137
138     return true;
139   } else {  // Unpausing.
140     if (capture_state() != cricket::CS_PAUSED || !GetCaptureFormat() ||
141         !capture_timer_) {
142       LOG(ERROR) << "Cannot unpause CastVideoCapturerAdapter.";
143       return false;
144     }
145
146     // Restart |capture_timer_| and set capture state to cricket::CS_RUNNING;
147     capture_timer_->Start(FROM_HERE,
148                           base::TimeDelta::FromMicroseconds(
149                               GetCaptureFormat()->interval /
150                               (base::Time::kNanosecondsPerMicrosecond)),
151                           this,
152                           &CastVideoCapturerAdapter::CaptureNextFrame);
153     SetCaptureState(cricket::CS_RUNNING);
154
155     VLOG(1) << "CastVideoCapturerAdapter unpaused.";
156   }
157   return true;
158 }
159
160 void CastVideoCapturerAdapter::Stop() {
161   DCHECK(thread_checker_.CalledOnValidThread());
162   DCHECK_NE(capture_state(), cricket::CS_STOPPED);
163
164   capture_timer_.reset();
165
166   SetCaptureFormat(NULL);
167   SetCaptureState(cricket::CS_STOPPED);
168
169   VLOG(1) << "CastVideoCapturerAdapter stopped.";
170 }
171
172
173 bool CastVideoCapturerAdapter::IsRunning() {
174   DCHECK(thread_checker_.CalledOnValidThread());
175
176   return capture_timer_->IsRunning();
177 }
178
179 bool CastVideoCapturerAdapter::IsScreencast() const {
180   return true;
181 }
182
183 bool CastVideoCapturerAdapter::GetPreferredFourccs(
184     std::vector<uint32>* fourccs) {
185   DCHECK(thread_checker_.CalledOnValidThread());
186   if (!fourccs)
187     return false;
188   fourccs->push_back(cricket::FOURCC_ARGB);
189   return true;
190 }
191
192 void CastVideoCapturerAdapter::CaptureNextFrame() {
193   // If we are paused, then don't capture.
194   if (!IsRunning())
195     return;
196
197   desktop_capturer_->Capture(webrtc::DesktopRegion());
198 }
199
200 }  // namespace remoting
201