- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / media / rtc_video_capturer.cc
1 // Copyright (c) 2012 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 "content/renderer/media/rtc_video_capturer.h"
6
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9
10 namespace content {
11
12 RtcVideoCapturer::RtcVideoCapturer(const media::VideoCaptureSessionId id,
13                                    VideoCaptureImplManager* vc_manager,
14                                    bool is_screencast)
15     : is_screencast_(is_screencast),
16       delegate_(new RtcVideoCaptureDelegate(id, vc_manager)),
17       state_(VIDEO_CAPTURE_STATE_STOPPED) {}
18
19 RtcVideoCapturer::~RtcVideoCapturer() {
20   DCHECK(VIDEO_CAPTURE_STATE_STOPPED);
21   DVLOG(3) << " RtcVideoCapturer::dtor";
22 }
23
24 cricket::CaptureState RtcVideoCapturer::Start(
25     const cricket::VideoFormat& capture_format) {
26   DVLOG(3) << " RtcVideoCapturer::Start ";
27   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
28     DVLOG(1) << "Got a StartCapture when already started!!! ";
29     return cricket::CS_FAILED;
30   }
31
32   media::VideoCaptureParams request;
33   request.requested_format =
34       media::VideoCaptureFormat(capture_format.width,
35                                 capture_format.height,
36                                 capture_format.framerate(),
37                                 media::ConstantResolutionVideoCaptureDevice);
38
39   SetCaptureFormat(&capture_format);
40
41   state_ = VIDEO_CAPTURE_STATE_STARTED;
42   first_frame_timestamp_ = media::kNoTimestamp();
43   delegate_->StartCapture(
44       request,
45       base::Bind(&RtcVideoCapturer::OnFrameCaptured, base::Unretained(this)),
46       base::Bind(&RtcVideoCapturer::OnStateChange, base::Unretained(this)));
47   // Update the desired aspect ratio so that later the video frame can be
48   // cropped to meet the requirement if the camera returns a different
49   // resolution than the |request|.
50   UpdateAspectRatio(capture_format.width, capture_format.height);
51   return cricket::CS_STARTING;
52 }
53
54 void RtcVideoCapturer::Stop() {
55   DVLOG(3) << " RtcVideoCapturer::Stop ";
56   if (state_ == VIDEO_CAPTURE_STATE_STOPPED) {
57     DVLOG(1) << "Got a StopCapture while not started.";
58     return;
59   }
60
61   SetCaptureFormat(NULL);
62   state_ = VIDEO_CAPTURE_STATE_STOPPED;
63   delegate_->StopCapture();
64   SignalStateChange(this, cricket::CS_STOPPED);
65 }
66
67 bool RtcVideoCapturer::IsRunning() {
68   return state_ == VIDEO_CAPTURE_STATE_STARTED;
69 }
70
71 bool RtcVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
72   if (!fourccs)
73     return false;
74   fourccs->push_back(cricket::FOURCC_I420);
75   return true;
76 }
77
78 bool RtcVideoCapturer::IsScreencast() const {
79   return is_screencast_;
80 }
81
82 bool RtcVideoCapturer::GetBestCaptureFormat(const cricket::VideoFormat& desired,
83                                             cricket::VideoFormat* best_format) {
84   if (!best_format) {
85     return false;
86   }
87
88   // Chrome does not support capability enumeration.
89   // Use the desired format as the best format.
90   best_format->width = desired.width;
91   best_format->height = desired.height;
92   best_format->fourcc = cricket::FOURCC_I420;
93   best_format->interval = desired.interval;
94   return true;
95 }
96
97 void RtcVideoCapturer::OnFrameCaptured(
98     const scoped_refptr<media::VideoFrame>& frame) {
99   if (first_frame_timestamp_ == media::kNoTimestamp())
100     first_frame_timestamp_ = frame->GetTimestamp();
101
102   // Currently, |fourcc| is always I420.
103   cricket::CapturedFrame captured_frame;
104   captured_frame.width = frame->coded_size().width();
105   captured_frame.height = frame->coded_size().height();
106   captured_frame.fourcc = cricket::FOURCC_I420;
107   // cricket::CapturedFrame time is in nanoseconds.
108   captured_frame.elapsed_time =
109       (frame->GetTimestamp() - first_frame_timestamp_).InMicroseconds() *
110       base::Time::kNanosecondsPerMicrosecond;
111   captured_frame.time_stamp = frame->GetTimestamp().InMicroseconds() *
112                               base::Time::kNanosecondsPerMicrosecond;
113   // TODO(sheu): we assume contiguous layout of image planes.
114   captured_frame.data = frame->data(0);
115   captured_frame.data_size =
116       media::VideoFrame::AllocationSize(frame->format(), frame->coded_size());
117   captured_frame.pixel_height = 1;
118   captured_frame.pixel_width = 1;
119
120   TRACE_EVENT_INSTANT2(
121       "rtc_video_capturer",
122       "OnFrameCaptured",
123       TRACE_EVENT_SCOPE_THREAD,
124       "elapsed time",
125       captured_frame.elapsed_time,
126       "timestamp_ms",
127       captured_frame.time_stamp / talk_base::kNumNanosecsPerMillisec);
128
129   // This signals to libJingle that a new VideoFrame is available.
130   // libJingle have no assumptions on what thread this signal come from.
131   SignalFrameCaptured(this, &captured_frame);
132 }
133
134 void RtcVideoCapturer::OnStateChange(
135     RtcVideoCaptureDelegate::CaptureState state) {
136   cricket::CaptureState converted_state = cricket::CS_FAILED;
137   DVLOG(3) << " RtcVideoCapturer::OnStateChange " << state;
138   switch (state) {
139     case RtcVideoCaptureDelegate::CAPTURE_STOPPED:
140       converted_state = cricket::CS_STOPPED;
141       break;
142     case RtcVideoCaptureDelegate::CAPTURE_RUNNING:
143       converted_state = cricket::CS_RUNNING;
144       break;
145     case RtcVideoCaptureDelegate::CAPTURE_FAILED:
146       // TODO(perkj): Update the comments in the the definition of
147       // cricket::CS_FAILED. According to the comments, cricket::CS_FAILED
148       // means that the capturer failed to start. But here and in libjingle it
149       // is also used if an error occur during capturing.
150       converted_state = cricket::CS_FAILED;
151       break;
152     default:
153       NOTREACHED();
154       break;
155   }
156   SignalStateChange(this, converted_state);
157 }
158
159 }  // namespace content