blob: ee5ef665d97c37247929f170def89192679220d7 [file] [log] [blame]
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00009 */
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000010
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/androidvideocapturer.h"
12
kwibergd1fe2812016-04-27 06:47:29 -070013#include <memory>
14
Henrik Kjellander15583c12016-02-10 10:53:12 +010015#include "webrtc/api/java/jni/native_handle_impl.h"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000016#include "webrtc/base/common.h"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000017#include "webrtc/base/timeutils.h"
kjellander@webrtc.org5ad12972016-02-12 06:39:40 +010018#include "webrtc/media/engine/webrtcvideoframe.h"
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000019
20namespace webrtc {
21
Magnus Jedvertc464f502015-08-25 23:22:08 +020022// A hack for avoiding deep frame copies in
23// cricket::VideoCapturer.SignalFrameCaptured() using a custom FrameFactory.
24// A frame is injected using UpdateCapturedFrame(), and converted into a
25// cricket::VideoFrame with CreateAliasedFrame(). UpdateCapturedFrame() should
26// be called before CreateAliasedFrame() for every frame.
27// TODO(magjed): Add an interface cricket::VideoCapturer::OnFrameCaptured()
28// for ref counted I420 frames instead of this hack.
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000029class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory {
30 public:
Pera5092412016-02-12 13:30:57 +010031 explicit FrameFactory(
32 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate)
magjedb09b6602015-10-01 03:02:44 -070033 : delegate_(delegate) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000034 // Create a CapturedFrame that only contains header information, not the
35 // actual pixel data.
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000036 captured_frame_.pixel_height = 1;
37 captured_frame_.pixel_width = 1;
Magnus Jedvertc464f502015-08-25 23:22:08 +020038 captured_frame_.data = nullptr;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000039 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
Peter Boström0c4e06b2015-10-07 12:23:21 +020040 captured_frame_.fourcc = static_cast<uint32_t>(cricket::FOURCC_ANY);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000041 }
42
Magnus Jedvertc464f502015-08-25 23:22:08 +020043 void UpdateCapturedFrame(
44 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer,
45 int rotation,
Peter Boström0c4e06b2015-10-07 12:23:21 +020046 int64_t time_stamp_in_ns) {
perkj7755e202015-11-19 12:02:21 -080047 RTC_DCHECK(rotation == 0 || rotation == 90 || rotation == 180 ||
48 rotation == 270);
Magnus Jedvertc464f502015-08-25 23:22:08 +020049 buffer_ = buffer;
50 captured_frame_.width = buffer->width();
51 captured_frame_.height = buffer->height();
Per33544192015-04-02 12:30:51 +020052 captured_frame_.time_stamp = time_stamp_in_ns;
perkj7755e202015-11-19 12:02:21 -080053 captured_frame_.rotation = static_cast<webrtc::VideoRotation>(rotation);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000054 }
55
Magnus Jedvertc464f502015-08-25 23:22:08 +020056 void ClearCapturedFrame() {
57 buffer_ = nullptr;
magjedfcf8ece2015-08-06 04:00:16 -070058 captured_frame_.width = 0;
59 captured_frame_.height = 0;
magjedfcf8ece2015-08-06 04:00:16 -070060 captured_frame_.time_stamp = 0;
magjedfcf8ece2015-08-06 04:00:16 -070061 }
62
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000063 const cricket::CapturedFrame* GetCapturedFrame() const {
64 return &captured_frame_;
65 }
66
67 cricket::VideoFrame* CreateAliasedFrame(
68 const cricket::CapturedFrame* captured_frame,
69 int dst_width,
70 int dst_height) const override {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000071 // Check that captured_frame is actually our frame.
henrikg91d6ede2015-09-17 00:24:34 -070072 RTC_CHECK(captured_frame == &captured_frame_);
perkjac306422015-10-08 15:32:38 +020073 RTC_CHECK(buffer_->native_handle() == nullptr);
74
kwibergd1fe2812016-04-27 06:47:29 -070075 std::unique_ptr<cricket::VideoFrame> frame(new cricket::WebRtcVideoFrame(
Magnus Jedvertc464f502015-08-25 23:22:08 +020076 ShallowCenterCrop(buffer_, dst_width, dst_height),
perkj7755e202015-11-19 12:02:21 -080077 captured_frame->time_stamp, captured_frame->rotation));
Magnus Jedvertc464f502015-08-25 23:22:08 +020078 // Caller takes ownership.
kwibergd1fe2812016-04-27 06:47:29 -070079 // TODO(magjed): Change CreateAliasedFrame() to return a std::unique_ptr.
Magnus Jedvertc464f502015-08-25 23:22:08 +020080 return apply_rotation_ ? frame->GetCopyWithRotationApplied()->Copy()
81 : frame.release();
Per33544192015-04-02 12:30:51 +020082 }
83
perkjac306422015-10-08 15:32:38 +020084 cricket::VideoFrame* CreateAliasedFrame(
85 const cricket::CapturedFrame* input_frame,
86 int cropped_input_width,
87 int cropped_input_height,
88 int output_width,
89 int output_height) const override {
90 if (buffer_->native_handle() != nullptr) {
Per71f5a9a2015-12-11 09:32:37 +010091 // TODO(perkj) Implement cropping.
92 RTC_CHECK_EQ(cropped_input_width, buffer_->width());
93 RTC_CHECK_EQ(cropped_input_height, buffer_->height());
Pera3c20bb2015-11-26 13:41:44 +010094 rtc::scoped_refptr<webrtc::VideoFrameBuffer> scaled_buffer(
95 static_cast<webrtc_jni::AndroidTextureBuffer*>(buffer_.get())
Per71f5a9a2015-12-11 09:32:37 +010096 ->ScaleAndRotate(output_width, output_height,
97 apply_rotation_ ? input_frame->rotation :
98 webrtc::kVideoRotation_0));
Pera3c20bb2015-11-26 13:41:44 +010099 return new cricket::WebRtcVideoFrame(
Per71f5a9a2015-12-11 09:32:37 +0100100 scaled_buffer, input_frame->time_stamp,
101 apply_rotation_ ? webrtc::kVideoRotation_0 : input_frame->rotation);
perkjac306422015-10-08 15:32:38 +0200102 }
103 return VideoFrameFactory::CreateAliasedFrame(input_frame,
104 cropped_input_width,
105 cropped_input_height,
106 output_width,
107 output_height);
108 }
109
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000110 private:
Magnus Jedvertc464f502015-08-25 23:22:08 +0200111 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer_;
112 cricket::CapturedFrame captured_frame_;
113 rtc::scoped_refptr<AndroidVideoCapturerDelegate> delegate_;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000114};
115
116AndroidVideoCapturer::AndroidVideoCapturer(
Per33544192015-04-02 12:30:51 +0200117 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate)
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000118 : running_(false),
Per33544192015-04-02 12:30:51 +0200119 delegate_(delegate),
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000120 frame_factory_(NULL),
perkj@webrtc.org3db042e2015-02-19 08:43:38 +0000121 current_state_(cricket::CS_STOPPED) {
Per33544192015-04-02 12:30:51 +0200122 thread_checker_.DetachFromThread();
Magnus Jedvert5199c742016-02-18 13:09:54 +0100123 SetSupportedFormats(delegate_->GetSupportedFormats());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000124}
125
126AndroidVideoCapturer::~AndroidVideoCapturer() {
henrikg91d6ede2015-09-17 00:24:34 -0700127 RTC_CHECK(!running_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000128}
129
130cricket::CaptureState AndroidVideoCapturer::Start(
131 const cricket::VideoFormat& capture_format) {
henrikg91d6ede2015-09-17 00:24:34 -0700132 RTC_CHECK(thread_checker_.CalledOnValidThread());
133 RTC_CHECK(!running_);
Magnus Jedvert6ec1f922015-08-28 11:40:59 +0200134 const int fps = cricket::VideoFormat::IntervalToFps(capture_format.interval);
135 LOG(LS_INFO) << " AndroidVideoCapturer::Start " << capture_format.width << "x"
136 << capture_format.height << "@" << fps;
Alex Glaznev2f5be9a2015-05-19 10:56:32 -0700137
Magnus Jedvertc464f502015-08-25 23:22:08 +0200138 frame_factory_ = new AndroidVideoCapturer::FrameFactory(delegate_.get());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000139 set_frame_factory(frame_factory_);
140
141 running_ = true;
Magnus Jedvert6ec1f922015-08-28 11:40:59 +0200142 delegate_->Start(capture_format.width, capture_format.height, fps, this);
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000143 SetCaptureFormat(&capture_format);
144 current_state_ = cricket::CS_STARTING;
145 return current_state_;
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000146}
147
148void AndroidVideoCapturer::Stop() {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000149 LOG(LS_INFO) << " AndroidVideoCapturer::Stop ";
henrikg91d6ede2015-09-17 00:24:34 -0700150 RTC_CHECK(thread_checker_.CalledOnValidThread());
151 RTC_CHECK(running_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000152 running_ = false;
153 SetCaptureFormat(NULL);
154
155 delegate_->Stop();
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000156 current_state_ = cricket::CS_STOPPED;
Perfb45d172016-02-29 12:07:35 +0100157 SetCaptureState(current_state_);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000158}
159
160bool AndroidVideoCapturer::IsRunning() {
henrikg91d6ede2015-09-17 00:24:34 -0700161 RTC_CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000162 return running_;
163}
164
Peter Boström0c4e06b2015-10-07 12:23:21 +0200165bool AndroidVideoCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) {
henrikg91d6ede2015-09-17 00:24:34 -0700166 RTC_CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org2ad3bb12015-02-23 11:14:57 +0000167 fourccs->push_back(cricket::FOURCC_YV12);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000168 return true;
169}
170
171void AndroidVideoCapturer::OnCapturerStarted(bool success) {
henrikg91d6ede2015-09-17 00:24:34 -0700172 RTC_CHECK(thread_checker_.CalledOnValidThread());
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000173 cricket::CaptureState new_state =
174 success ? cricket::CS_RUNNING : cricket::CS_FAILED;
perkj@webrtc.org8f605e82015-02-17 13:53:56 +0000175 if (new_state == current_state_)
176 return;
177 current_state_ = new_state;
Perfb45d172016-02-29 12:07:35 +0100178 SetCaptureState(new_state);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000179}
180
Magnus Jedvertc464f502015-08-25 23:22:08 +0200181void AndroidVideoCapturer::OnIncomingFrame(
olka30a5b5e2015-10-20 11:04:56 -0700182 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer,
Magnus Jedvertc464f502015-08-25 23:22:08 +0200183 int rotation,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200184 int64_t time_stamp) {
henrikg91d6ede2015-09-17 00:24:34 -0700185 RTC_CHECK(thread_checker_.CalledOnValidThread());
Magnus Jedvertc464f502015-08-25 23:22:08 +0200186 frame_factory_->UpdateCapturedFrame(buffer, rotation, time_stamp);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000187 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
Magnus Jedvertc464f502015-08-25 23:22:08 +0200188 frame_factory_->ClearCapturedFrame();
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000189}
190
Åsa Persson2b679252015-06-15 09:53:05 +0200191void AndroidVideoCapturer::OnOutputFormatRequest(
192 int width, int height, int fps) {
henrikg91d6ede2015-09-17 00:24:34 -0700193 RTC_CHECK(thread_checker_.CalledOnValidThread());
Per766ad3b2016-04-05 15:23:49 +0200194 cricket::VideoFormat format(width, height,
195 cricket::VideoFormat::FpsToInterval(fps), 0);
Åsa Persson2b679252015-06-15 09:53:05 +0200196 video_adapter()->OnOutputFormatRequest(format);
197}
198
Magnus Jedvert6ec1f922015-08-28 11:40:59 +0200199bool AndroidVideoCapturer::GetBestCaptureFormat(
200 const cricket::VideoFormat& desired,
201 cricket::VideoFormat* best_format) {
Magnus Jedvert5e7834e2016-02-12 17:05:29 +0100202 // Delegate this choice to VideoCapturer.startCapture().
Magnus Jedvert6ec1f922015-08-28 11:40:59 +0200203 *best_format = desired;
204 return true;
205}
206
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000207} // namespace webrtc