blob: 02f77dbb82c3626715ebcdd826b5485ae1c2c798 [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"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000030#include "webrtc/base/common.h"
31#include "webrtc/base/json.h"
32#include "webrtc/base/timeutils.h"
33#include "webrtc/base/thread.h"
34
35namespace webrtc {
36
37using cricket::WebRtcVideoFrame;
38using rtc::scoped_ptr;
39
40// An implementation of cricket::VideoFrameFactory for frames that are not
41// guaranteed to outlive the created cricket::VideoFrame.
42// A frame is injected using UpdateCapturedFrame, and converted into a
43// cricket::VideoFrame with
44// CreateAliasedFrame. UpdateCapturedFrame should be called before
45// CreateAliasedFrame for every frame.
46class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory {
47 public:
48 FrameFactory(int width, int height) : start_time_(rtc::TimeNanos()) {
49 // Create a CapturedFrame that only contains header information, not the
50 // actual pixel data.
51 captured_frame_.width = width;
52 captured_frame_.height = height;
53 captured_frame_.pixel_height = 1;
54 captured_frame_.pixel_width = 1;
55 captured_frame_.rotation = 0;
56 captured_frame_.data = NULL;
57 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
58 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
59 }
60
61 void UpdateCapturedFrame(signed char* frame_data,
62 int length,
63 int rotation,
64 int64 time_stamp_in_ms) {
perkj@webrtc.org8fbdcfd2015-02-18 15:19:39 +000065 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_NV21);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000066 captured_frame_.data = frame_data;
67 captured_frame_.elapsed_time = rtc::TimeNanos() - start_time_;
68 captured_frame_.time_stamp =
69 time_stamp_in_ms * rtc::kNumNanosecsPerMillisec;
70 captured_frame_.rotation = rotation;
71 captured_frame_.data_size = length;
72 }
73
74 const cricket::CapturedFrame* GetCapturedFrame() const {
75 return &captured_frame_;
76 }
77
78 cricket::VideoFrame* CreateAliasedFrame(
79 const cricket::CapturedFrame* captured_frame,
80 int dst_width,
81 int dst_height) const override {
82 // This override of CreateAliasedFrame creates a copy of the frame since
83 // |captured_frame_.data| is only guaranteed to be valid during the scope
84 // of |AndroidVideoCapturer::OnIncomingFrame_w|.
85 // Check that captured_frame is actually our frame.
86 DCHECK(captured_frame == &captured_frame_);
87 scoped_ptr<WebRtcVideoFrame> frame(new WebRtcVideoFrame());
88 frame->Init(captured_frame, dst_width, dst_height);
89 return frame.release();
90 }
91
92 private:
93 uint64 start_time_;
94 cricket::CapturedFrame captured_frame_;
95};
96
97AndroidVideoCapturer::AndroidVideoCapturer(
98 rtc::scoped_ptr<AndroidVideoCapturerDelegate> delegate)
99 : running_(false),
100 delegate_(delegate.Pass()),
101 worker_thread_(NULL),
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000102 frame_factory_(NULL),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000103 current_state_(cricket::CS_STOPPED) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000104 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()),
perkj@webrtc.org8fbdcfd2015-02-18 15:19:39 +0000122 cricket::FOURCC_NV21);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000123 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_);
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000135 DCHECK(worker_thread_ == nullptr || worker_thread_ == rtc::Thread::Current());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000136 // 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);
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000149 SetCaptureFormat(&capture_format);
150 current_state_ = cricket::CS_STARTING;
151 return current_state_;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000152}
153
154void AndroidVideoCapturer::Stop() {
155 DCHECK(worker_thread_->IsCurrent());
156 LOG(LS_INFO) << " AndroidVideoCapturer::Stop ";
157 DCHECK(running_);
158 running_ = false;
159 SetCaptureFormat(NULL);
160
161 delegate_->Stop();
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000162 current_state_ = cricket::CS_STOPPED;
163 SignalStateChange(this, current_state_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000164}
165
166bool AndroidVideoCapturer::IsRunning() {
167 return running_;
168}
169
170bool AndroidVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
perkj@webrtc.org8fbdcfd2015-02-18 15:19:39 +0000171 fourccs->push_back(cricket::FOURCC_NV21);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000172 return true;
173}
174
175void AndroidVideoCapturer::OnCapturerStarted(bool success) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000176 DCHECK(worker_thread_->IsCurrent());
177 cricket::CaptureState new_state =
178 success ? cricket::CS_RUNNING : cricket::CS_FAILED;
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000179 if (new_state == current_state_)
180 return;
181 current_state_ = new_state;
182
183 // TODO(perkj): SetCaptureState can not be used since it posts to |thread_|.
184 // But |thread_ | is currently just the thread that happened to create the
185 // cricket::VideoCapturer.
186 SignalStateChange(this, new_state);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000187}
188
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000189void AndroidVideoCapturer::OnIncomingFrame(signed char* frame_data,
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000190 int length,
191 int rotation,
192 int64 time_stamp) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000193 DCHECK(worker_thread_->IsCurrent());
194 frame_factory_->UpdateCapturedFrame(frame_data, length, rotation, time_stamp);
195 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
196}
197
198} // namespace webrtc