blob: fa9d925509b2b321498136d46c2d1551df859868 [file] [log] [blame]
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00001/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27#include "talk/app/webrtc/androidvideocapturer.h"
28
29#include "talk/media/webrtc/webrtcvideoframe.h"
30#include "webrtc/base/bind.h"
31#include "webrtc/base/common.h"
32#include "webrtc/base/json.h"
33#include "webrtc/base/timeutils.h"
34#include "webrtc/base/thread.h"
35
36namespace webrtc {
37
38using cricket::WebRtcVideoFrame;
39using rtc::scoped_ptr;
40
41// An implementation of cricket::VideoFrameFactory for frames that are not
42// guaranteed to outlive the created cricket::VideoFrame.
43// A frame is injected using UpdateCapturedFrame, and converted into a
44// cricket::VideoFrame with
45// CreateAliasedFrame. UpdateCapturedFrame should be called before
46// CreateAliasedFrame for every frame.
47class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory {
48 public:
49 FrameFactory(int width, int height) : start_time_(rtc::TimeNanos()) {
50 // Create a CapturedFrame that only contains header information, not the
51 // actual pixel data.
52 captured_frame_.width = width;
53 captured_frame_.height = height;
54 captured_frame_.pixel_height = 1;
55 captured_frame_.pixel_width = 1;
56 captured_frame_.rotation = 0;
57 captured_frame_.data = NULL;
58 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
59 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
60 }
61
62 void UpdateCapturedFrame(signed char* frame_data,
63 int length,
64 int rotation,
65 int64 time_stamp_in_ms) {
66 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_NV21);
67 captured_frame_.data = frame_data;
68 captured_frame_.elapsed_time = rtc::TimeNanos() - start_time_;
69 captured_frame_.time_stamp =
70 time_stamp_in_ms * rtc::kNumNanosecsPerMillisec;
71 captured_frame_.rotation = rotation;
72 captured_frame_.data_size = length;
73 }
74
75 const cricket::CapturedFrame* GetCapturedFrame() const {
76 return &captured_frame_;
77 }
78
79 cricket::VideoFrame* CreateAliasedFrame(
80 const cricket::CapturedFrame* captured_frame,
81 int dst_width,
82 int dst_height) const override {
83 // This override of CreateAliasedFrame creates a copy of the frame since
84 // |captured_frame_.data| is only guaranteed to be valid during the scope
85 // of |AndroidVideoCapturer::OnIncomingFrame_w|.
86 // Check that captured_frame is actually our frame.
87 DCHECK(captured_frame == &captured_frame_);
88 scoped_ptr<WebRtcVideoFrame> frame(new WebRtcVideoFrame());
89 frame->Init(captured_frame, dst_width, dst_height);
90 return frame.release();
91 }
92
93 private:
94 uint64 start_time_;
95 cricket::CapturedFrame captured_frame_;
96};
97
98AndroidVideoCapturer::AndroidVideoCapturer(
99 rtc::scoped_ptr<AndroidVideoCapturerDelegate> delegate)
100 : running_(false),
101 delegate_(delegate.Pass()),
102 worker_thread_(NULL),
103 frame_factory_(NULL) {
104 std::string json_string = delegate_->GetSupportedFormats();
105 LOG(LS_INFO) << json_string;
106
107 Json::Value json_values;
108 Json::Reader reader(Json::Features::strictMode());
109 if (!reader.parse(json_string, json_values)) {
110 LOG(LS_ERROR) << "Failed to parse formats.";
111 }
112
113 std::vector<cricket::VideoFormat> formats;
114 for (Json::ArrayIndex i = 0; i < json_values.size(); ++i) {
115 const Json::Value& json_value = json_values[i];
116 DCHECK(!json_value["width"].isNull() && !json_value["height"].isNull() &&
117 !json_value["framerate"].isNull());
118 cricket::VideoFormat format(
119 json_value["width"].asInt(),
120 json_value["height"].asInt(),
121 cricket::VideoFormat::FpsToInterval(json_value["framerate"].asInt()),
122 cricket::FOURCC_NV21);
123 formats.push_back(format);
124 }
125 SetSupportedFormats(formats);
126}
127
128AndroidVideoCapturer::~AndroidVideoCapturer() {
129 DCHECK(!running_);
130}
131
132cricket::CaptureState AndroidVideoCapturer::Start(
133 const cricket::VideoFormat& capture_format) {
134 DCHECK(!running_);
135 DCHECK(worker_thread_ == nullptr);
136 // TODO(perkj): Better way to get a handle to the worker thread?
137 worker_thread_ = rtc::Thread::Current();
138
139 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width
140 << " h = " << capture_format.height;
141 frame_factory_ = new AndroidVideoCapturer::FrameFactory(
142 capture_format.width, capture_format.height);
143 set_frame_factory(frame_factory_);
144
145 running_ = true;
146 delegate_->Start(
147 capture_format.width, capture_format.height,
148 cricket::VideoFormat::IntervalToFps(capture_format.interval), this);
149 return cricket::CS_STARTING;
150}
151
152void AndroidVideoCapturer::Stop() {
153 DCHECK(worker_thread_->IsCurrent());
154 LOG(LS_INFO) << " AndroidVideoCapturer::Stop ";
155 DCHECK(running_);
156 running_ = false;
157 SetCaptureFormat(NULL);
158
159 delegate_->Stop();
160 SignalStateChange(this, cricket::CS_STOPPED);
161}
162
163bool AndroidVideoCapturer::IsRunning() {
164 return running_;
165}
166
167bool AndroidVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
168 fourccs->push_back(cricket::FOURCC_NV21);
169 return true;
170}
171
172void AndroidVideoCapturer::OnCapturerStarted(bool success) {
173 // This method is called from a Java thread.
174 DCHECK(!worker_thread_->IsCurrent());
175 worker_thread_->Invoke<void>(
176 rtc::Bind(&AndroidVideoCapturer::OnCapturerStarted_w, this, success));
177}
178
179void AndroidVideoCapturer::OnCapturerStarted_w(bool success) {
180 DCHECK(worker_thread_->IsCurrent());
181 cricket::CaptureState new_state =
182 success ? cricket::CS_RUNNING : cricket::CS_FAILED;
183 SetCaptureState(new_state);
184}
185
186void AndroidVideoCapturer::OnIncomingFrame(signed char* videoFrame,
187 int length,
188 int rotation,
189 int64 time_stamp) {
190 // This method is called from a Java thread.
191 DCHECK(!worker_thread_->IsCurrent());
192 worker_thread_->Invoke<void>(
193 rtc::Bind(&AndroidVideoCapturer::OnIncomingFrame_w, this, videoFrame,
194 length, rotation, time_stamp));
195}
196
197void AndroidVideoCapturer::OnIncomingFrame_w(signed char* frame_data,
198 int length,
199 int rotation,
200 int64 time_stamp) {
201 DCHECK(worker_thread_->IsCurrent());
202 frame_factory_->UpdateCapturedFrame(frame_data, length, rotation, time_stamp);
203 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
204}
205
206} // namespace webrtc