blob: 2c9c0310240d6f7553e304a7eed6001d1b9f3fa6 [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"
Per33544192015-04-02 12:30:51 +020030#include "webrtc/base/bind.h"
31#include "webrtc/base/callback.h"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000032#include "webrtc/base/common.h"
33#include "webrtc/base/json.h"
34#include "webrtc/base/timeutils.h"
35#include "webrtc/base/thread.h"
Henrik Boström09a9ea82015-04-17 17:31:53 +020036#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000037
38namespace webrtc {
39
40using cricket::WebRtcVideoFrame;
41using rtc::scoped_ptr;
Per33544192015-04-02 12:30:51 +020042using rtc::scoped_refptr;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000043
44// An implementation of cricket::VideoFrameFactory for frames that are not
45// guaranteed to outlive the created cricket::VideoFrame.
46// A frame is injected using UpdateCapturedFrame, and converted into a
47// cricket::VideoFrame with
48// CreateAliasedFrame. UpdateCapturedFrame should be called before
49// CreateAliasedFrame for every frame.
50class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory {
51 public:
Per33544192015-04-02 12:30:51 +020052 FrameFactory(int width,
53 int height,
54 const scoped_refptr<AndroidVideoCapturerDelegate>& delegate)
55 : start_time_(rtc::TimeNanos()), delegate_(delegate) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000056 // Create a CapturedFrame that only contains header information, not the
57 // actual pixel data.
58 captured_frame_.width = width;
59 captured_frame_.height = height;
60 captured_frame_.pixel_height = 1;
61 captured_frame_.pixel_width = 1;
62 captured_frame_.rotation = 0;
63 captured_frame_.data = NULL;
64 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
65 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
66 }
67
perkj@webrtc.org112f1272015-02-25 09:20:07 +000068 void UpdateCapturedFrame(void* frame_data,
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000069 int length,
70 int rotation,
Per33544192015-04-02 12:30:51 +020071 int64 time_stamp_in_ns) {
perkj@webrtc.org2ad3bb12015-02-23 11:14:57 +000072 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_YV12);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000073 captured_frame_.data = frame_data;
74 captured_frame_.elapsed_time = rtc::TimeNanos() - start_time_;
Per33544192015-04-02 12:30:51 +020075 captured_frame_.time_stamp = time_stamp_in_ns;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000076 captured_frame_.rotation = rotation;
77 captured_frame_.data_size = length;
78 }
79
80 const cricket::CapturedFrame* GetCapturedFrame() const {
81 return &captured_frame_;
82 }
83
84 cricket::VideoFrame* CreateAliasedFrame(
85 const cricket::CapturedFrame* captured_frame,
86 int dst_width,
87 int dst_height) const override {
88 // This override of CreateAliasedFrame creates a copy of the frame since
89 // |captured_frame_.data| is only guaranteed to be valid during the scope
90 // of |AndroidVideoCapturer::OnIncomingFrame_w|.
91 // Check that captured_frame is actually our frame.
Alex Glaznev2f5be9a2015-05-19 10:56:32 -070092 CHECK(captured_frame == &captured_frame_);
Per33544192015-04-02 12:30:51 +020093
94 if (!apply_rotation_ || captured_frame->rotation == kVideoRotation_0) {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -070095 CHECK(captured_frame->fourcc == cricket::FOURCC_YV12);
Per33544192015-04-02 12:30:51 +020096 const uint8_t* y_plane = static_cast<uint8_t*>(captured_frame_.data);
Henrik Boström09a9ea82015-04-17 17:31:53 +020097
98 // Android guarantees that the stride is a multiple of 16.
99 // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29
100 int y_stride;
101 int uv_stride;
102 webrtc::Calc16ByteAlignedStride(captured_frame->width, &y_stride,
103 &uv_stride);
104 const uint8_t* v_plane = y_plane + y_stride * captured_frame->height;
105 const uint8_t* u_plane =
106 v_plane + uv_stride * webrtc::AlignInt(captured_frame->height, 2) / 2;
Per33544192015-04-02 12:30:51 +0200107
108 // Create a WrappedI420Buffer and bind the |no_longer_used| callback
109 // to the static method ReturnFrame. The |delegate_| is bound as an
110 // argument which means that the callback will hold a reference to
111 // |delegate_|.
112 rtc::scoped_refptr<WrappedI420Buffer> buffer(
113 new rtc::RefCountedObject<webrtc::WrappedI420Buffer>(
114 dst_width, dst_height, captured_frame->width,
115 captured_frame->height, y_plane, y_stride, u_plane, uv_stride,
116 v_plane, uv_stride,
117 rtc::Bind(&AndroidVideoCapturer::FrameFactory::ReturnFrame,
118 delegate_,
119 captured_frame->time_stamp)));
120 return new WebRtcVideoFrame(
121 buffer, captured_frame->elapsed_time,
122 captured_frame->time_stamp, captured_frame->GetRotation());
123 }
124
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000125 scoped_ptr<WebRtcVideoFrame> frame(new WebRtcVideoFrame());
perkj@webrtc.org1d828132015-03-03 06:44:06 +0000126 frame->Init(captured_frame, dst_width, dst_height, apply_rotation_);
Per33544192015-04-02 12:30:51 +0200127 // frame->Init copies the data in |captured_frame| so it is safe to return
128 // the buffer immediately.
129 delegate_->ReturnBuffer(captured_frame->time_stamp);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000130 return frame.release();
131 }
132
Per33544192015-04-02 12:30:51 +0200133 static void ReturnFrame(scoped_refptr<AndroidVideoCapturerDelegate> delegate,
134 int64 time_stamp) {
135 delegate->ReturnBuffer(time_stamp);
136 }
137
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000138 private:
139 uint64 start_time_;
140 cricket::CapturedFrame captured_frame_;
Per33544192015-04-02 12:30:51 +0200141 scoped_refptr<AndroidVideoCapturerDelegate> delegate_;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000142};
143
144AndroidVideoCapturer::AndroidVideoCapturer(
Per33544192015-04-02 12:30:51 +0200145 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate)
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000146 : running_(false),
Per33544192015-04-02 12:30:51 +0200147 delegate_(delegate),
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000148 frame_factory_(NULL),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000149 current_state_(cricket::CS_STOPPED) {
Per33544192015-04-02 12:30:51 +0200150 thread_checker_.DetachFromThread();
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000151 std::string json_string = delegate_->GetSupportedFormats();
152 LOG(LS_INFO) << json_string;
153
154 Json::Value json_values;
155 Json::Reader reader(Json::Features::strictMode());
156 if (!reader.parse(json_string, json_values)) {
157 LOG(LS_ERROR) << "Failed to parse formats.";
158 }
159
160 std::vector<cricket::VideoFormat> formats;
161 for (Json::ArrayIndex i = 0; i < json_values.size(); ++i) {
162 const Json::Value& json_value = json_values[i];
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700163 CHECK(!json_value["width"].isNull() && !json_value["height"].isNull() &&
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000164 !json_value["framerate"].isNull());
165 cricket::VideoFormat format(
166 json_value["width"].asInt(),
167 json_value["height"].asInt(),
168 cricket::VideoFormat::FpsToInterval(json_value["framerate"].asInt()),
perkj@webrtc.org2ad3bb12015-02-23 11:14:57 +0000169 cricket::FOURCC_YV12);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000170 formats.push_back(format);
171 }
172 SetSupportedFormats(formats);
173}
174
175AndroidVideoCapturer::~AndroidVideoCapturer() {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700176 CHECK(!running_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000177}
178
179cricket::CaptureState AndroidVideoCapturer::Start(
180 const cricket::VideoFormat& capture_format) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000181 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width
182 << " h = " << capture_format.height;
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700183 CHECK(thread_checker_.CalledOnValidThread());
184 CHECK(!running_);
185
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000186 frame_factory_ = new AndroidVideoCapturer::FrameFactory(
Per33544192015-04-02 12:30:51 +0200187 capture_format.width, capture_format.height, delegate_.get());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000188 set_frame_factory(frame_factory_);
189
190 running_ = true;
191 delegate_->Start(
192 capture_format.width, capture_format.height,
193 cricket::VideoFormat::IntervalToFps(capture_format.interval), this);
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000194 SetCaptureFormat(&capture_format);
195 current_state_ = cricket::CS_STARTING;
196 return current_state_;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000197}
198
199void AndroidVideoCapturer::Stop() {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000200 LOG(LS_INFO) << " AndroidVideoCapturer::Stop ";
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700201 CHECK(thread_checker_.CalledOnValidThread());
202 CHECK(running_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000203 running_ = false;
204 SetCaptureFormat(NULL);
205
206 delegate_->Stop();
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000207 current_state_ = cricket::CS_STOPPED;
208 SignalStateChange(this, current_state_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000209}
210
211bool AndroidVideoCapturer::IsRunning() {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700212 CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000213 return running_;
214}
215
216bool AndroidVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700217 CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org2ad3bb12015-02-23 11:14:57 +0000218 fourccs->push_back(cricket::FOURCC_YV12);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000219 return true;
220}
221
222void AndroidVideoCapturer::OnCapturerStarted(bool success) {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700223 CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000224 cricket::CaptureState new_state =
225 success ? cricket::CS_RUNNING : cricket::CS_FAILED;
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000226 if (new_state == current_state_)
227 return;
228 current_state_ = new_state;
229
230 // TODO(perkj): SetCaptureState can not be used since it posts to |thread_|.
231 // But |thread_ | is currently just the thread that happened to create the
232 // cricket::VideoCapturer.
233 SignalStateChange(this, new_state);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000234}
235
perkj@webrtc.org112f1272015-02-25 09:20:07 +0000236void AndroidVideoCapturer::OnIncomingFrame(void* frame_data,
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000237 int length,
238 int rotation,
239 int64 time_stamp) {
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700240 CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000241 frame_factory_->UpdateCapturedFrame(frame_data, length, rotation, time_stamp);
242 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000243}
244
245} // namespace webrtc