OLD | NEW |
---|---|
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
11 * this list of conditions and the following disclaimer in the documentation | 11 * this list of conditions and the following disclaimer in the documentation |
12 * and/or other materials provided with the distribution. | 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 | 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. | 14 * derived from this software without specific prior written permission. |
15 * | 15 * |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | 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 | 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | 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, | 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 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 | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 #include "talk/app/webrtc/androidvideocapturer.h" | 27 #include "talk/app/webrtc/androidvideocapturer.h" |
28 | 28 |
29 #include "talk/media/webrtc/webrtcvideoframe.h" | 29 #include "talk/media/webrtc/webrtcvideoframe.h" |
30 #include "webrtc/base/bind.h" | |
31 #include "webrtc/base/callback.h" | |
32 #include "webrtc/base/common.h" | 30 #include "webrtc/base/common.h" |
33 #include "webrtc/base/json.h" | 31 #include "webrtc/base/json.h" |
34 #include "webrtc/base/timeutils.h" | 32 #include "webrtc/base/timeutils.h" |
35 #include "webrtc/base/thread.h" | |
36 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | |
37 | 33 |
38 namespace webrtc { | 34 namespace webrtc { |
39 | 35 |
40 using cricket::WebRtcVideoFrame; | 36 // A hack for avoiding deep frame copies in |
41 using rtc::scoped_ptr; | 37 // cricket::VideoCapturer.SignalFrameCaptured() using a custom FrameFactory. |
42 using rtc::scoped_refptr; | 38 // A frame is injected using UpdateCapturedFrame(), and converted into a |
43 | 39 // cricket::VideoFrame with CreateAliasedFrame(). UpdateCapturedFrame() should |
44 // An implementation of cricket::VideoFrameFactory for frames that are not | 40 // be called before CreateAliasedFrame() for every frame. |
45 // guaranteed to outlive the created cricket::VideoFrame. | 41 // TODO(magjed): Add an interface cricket::VideoCapturer::OnFrameCaptured() |
46 // A frame is injected using UpdateCapturedFrame, and converted into a | 42 // for ref counted I420 frames instead of this hack. |
47 // cricket::VideoFrame with | |
48 // CreateAliasedFrame. UpdateCapturedFrame should be called before | |
49 // CreateAliasedFrame for every frame. | |
50 class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory { | 43 class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory { |
51 public: | 44 public: |
52 FrameFactory(int width, | 45 FrameFactory(const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate) |
53 int height, | 46 : start_time_(rtc::TimeNanos()), delegate_(delegate) { |
54 const scoped_refptr<AndroidVideoCapturerDelegate>& delegate) | |
55 : start_time_(rtc::TimeNanos()), delegate_(delegate) { | |
56 // Create a CapturedFrame that only contains header information, not the | 47 // Create a CapturedFrame that only contains header information, not the |
57 // actual pixel data. | 48 // actual pixel data. |
58 captured_frame_.width = width; | |
59 captured_frame_.height = height; | |
60 captured_frame_.pixel_height = 1; | 49 captured_frame_.pixel_height = 1; |
61 captured_frame_.pixel_width = 1; | 50 captured_frame_.pixel_width = 1; |
62 captured_frame_.rotation = 0; | 51 captured_frame_.data = nullptr; |
63 captured_frame_.data = NULL; | |
64 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize; | 52 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize; |
65 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY); | 53 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY); |
66 } | 54 } |
67 | 55 |
68 void UpdateCapturedFrame(void* frame_data, | 56 void UpdateCapturedFrame( |
69 int length, | 57 const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer, |
70 int width, | 58 int rotation, |
71 int height, | 59 int64 time_stamp_in_ns) { |
72 int rotation, | 60 buffer_ = buffer; |
73 int64 time_stamp_in_ns) { | 61 captured_frame_.width = buffer->width(); |
74 // Make sure we don't overwrite the previous frame. | 62 captured_frame_.height = buffer->height(); |
75 CHECK(captured_frame_.data == nullptr); | |
76 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_YV12); | |
77 captured_frame_.data = frame_data; | |
78 captured_frame_.width = width; | |
79 captured_frame_.height = height; | |
80 captured_frame_.elapsed_time = rtc::TimeNanos() - start_time_; | 63 captured_frame_.elapsed_time = rtc::TimeNanos() - start_time_; |
81 captured_frame_.time_stamp = time_stamp_in_ns; | 64 captured_frame_.time_stamp = time_stamp_in_ns; |
82 captured_frame_.rotation = rotation; | 65 captured_frame_.rotation = rotation; |
83 captured_frame_.data_size = length; | |
84 } | 66 } |
85 | 67 |
86 void ClearCapturedFrame() const { | 68 void ClearCapturedFrame() { |
87 captured_frame_.data = nullptr; | 69 buffer_ = nullptr; |
88 captured_frame_.width = 0; | 70 captured_frame_.width = 0; |
89 captured_frame_.height = 0; | 71 captured_frame_.height = 0; |
90 captured_frame_.elapsed_time = 0; | 72 captured_frame_.elapsed_time = 0; |
91 captured_frame_.time_stamp = 0; | 73 captured_frame_.time_stamp = 0; |
92 captured_frame_.data_size = 0; | |
93 } | 74 } |
94 | 75 |
95 const cricket::CapturedFrame* GetCapturedFrame() const { | 76 const cricket::CapturedFrame* GetCapturedFrame() const { |
96 return &captured_frame_; | 77 return &captured_frame_; |
97 } | 78 } |
98 | 79 |
99 cricket::VideoFrame* CreateAliasedFrame( | 80 cricket::VideoFrame* CreateAliasedFrame( |
100 const cricket::CapturedFrame* captured_frame, | 81 const cricket::CapturedFrame* captured_frame, |
101 int dst_width, | 82 int dst_width, |
102 int dst_height) const override { | 83 int dst_height) const override { |
103 // This override of CreateAliasedFrame creates a copy of the frame since | |
104 // |captured_frame_.data| is only guaranteed to be valid during the scope | |
105 // of |AndroidVideoCapturer::OnIncomingFrame_w|. | |
106 // Check that captured_frame is actually our frame. | 84 // Check that captured_frame is actually our frame. |
107 CHECK(captured_frame == &captured_frame_); | 85 CHECK(captured_frame == &captured_frame_); |
108 CHECK(captured_frame->data != nullptr); | 86 rtc::scoped_ptr<cricket::VideoFrame> frame(new cricket::WebRtcVideoFrame( |
109 | 87 ShallowCenterCrop(buffer_, dst_width, dst_height), |
110 if (!apply_rotation_ || captured_frame->rotation == kVideoRotation_0) { | 88 captured_frame->elapsed_time, captured_frame->time_stamp, |
111 CHECK(captured_frame->fourcc == cricket::FOURCC_YV12); | 89 captured_frame->GetRotation())); |
112 const uint8_t* y_plane = static_cast<uint8_t*>(captured_frame_.data); | 90 // Caller takes ownership. |
113 | 91 return apply_rotation_ ? frame->GetCopyWithRotationApplied()->Copy() |
114 // Android guarantees that the stride is a multiple of 16. | 92 : frame.release(); |
tommi
2015/08/24 09:14:42
can we at some point change CreateAliasedFrame to
magjed_webrtc
2015/08/24 11:27:19
rtc::scoped_ptr supports rvalue references so it i
| |
115 // http://developer.android.com/reference/android/hardware/Camera.Paramete rs.html#setPreviewFormat%28int%29 | |
116 int y_stride; | |
117 int uv_stride; | |
118 webrtc::Calc16ByteAlignedStride(captured_frame->width, &y_stride, | |
119 &uv_stride); | |
120 const uint8_t* v_plane = y_plane + y_stride * captured_frame->height; | |
121 const uint8_t* u_plane = | |
122 v_plane + uv_stride * webrtc::AlignInt(captured_frame->height, 2) / 2; | |
123 | |
124 // Create a WrappedI420Buffer and bind the |no_longer_used| callback | |
125 // to the static method ReturnFrame. The |delegate_| is bound as an | |
126 // argument which means that the callback will hold a reference to | |
127 // |delegate_|. | |
128 rtc::scoped_refptr<WrappedI420Buffer> buffer( | |
129 new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( | |
130 dst_width, dst_height, captured_frame->width, | |
131 captured_frame->height, y_plane, y_stride, u_plane, uv_stride, | |
132 v_plane, uv_stride, | |
133 rtc::Bind(&AndroidVideoCapturer::FrameFactory::ReturnFrame, | |
134 delegate_, | |
135 captured_frame->time_stamp))); | |
136 cricket::VideoFrame* cricket_frame = new WebRtcVideoFrame( | |
137 buffer, captured_frame->elapsed_time, | |
138 captured_frame->time_stamp, captured_frame->GetRotation()); | |
139 // |cricket_frame| is now responsible for returning the frame. Clear | |
140 // |captured_frame_| so the frame isn't returned twice. | |
141 ClearCapturedFrame(); | |
142 return cricket_frame; | |
143 } | |
144 | |
145 scoped_ptr<WebRtcVideoFrame> frame(new WebRtcVideoFrame()); | |
146 frame->Init(captured_frame, dst_width, dst_height, apply_rotation_); | |
147 return frame.release(); | |
148 } | |
149 | |
150 static void ReturnFrame(scoped_refptr<AndroidVideoCapturerDelegate> delegate, | |
151 int64 time_stamp) { | |
152 delegate->ReturnBuffer(time_stamp); | |
153 } | 93 } |
154 | 94 |
155 private: | 95 private: |
156 uint64 start_time_; | 96 uint64 start_time_; |
157 // |captured_frame_| is mutable as a hacky way to modify it inside | 97 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer_; |
158 // CreateAliasedframe(). | 98 cricket::CapturedFrame captured_frame_; |
159 mutable cricket::CapturedFrame captured_frame_; | 99 rtc::scoped_refptr<AndroidVideoCapturerDelegate> delegate_; |
160 scoped_refptr<AndroidVideoCapturerDelegate> delegate_; | |
161 }; | 100 }; |
162 | 101 |
163 AndroidVideoCapturer::AndroidVideoCapturer( | 102 AndroidVideoCapturer::AndroidVideoCapturer( |
164 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate) | 103 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate) |
165 : running_(false), | 104 : running_(false), |
166 delegate_(delegate), | 105 delegate_(delegate), |
167 frame_factory_(NULL), | 106 frame_factory_(NULL), |
168 current_state_(cricket::CS_STOPPED) { | 107 current_state_(cricket::CS_STOPPED) { |
169 thread_checker_.DetachFromThread(); | 108 thread_checker_.DetachFromThread(); |
170 std::string json_string = delegate_->GetSupportedFormats(); | 109 std::string json_string = delegate_->GetSupportedFormats(); |
(...skipping 24 matching lines...) Expand all Loading... | |
195 CHECK(!running_); | 134 CHECK(!running_); |
196 } | 135 } |
197 | 136 |
198 cricket::CaptureState AndroidVideoCapturer::Start( | 137 cricket::CaptureState AndroidVideoCapturer::Start( |
199 const cricket::VideoFormat& capture_format) { | 138 const cricket::VideoFormat& capture_format) { |
200 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width | 139 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width |
201 << " h = " << capture_format.height; | 140 << " h = " << capture_format.height; |
202 CHECK(thread_checker_.CalledOnValidThread()); | 141 CHECK(thread_checker_.CalledOnValidThread()); |
203 CHECK(!running_); | 142 CHECK(!running_); |
204 | 143 |
205 frame_factory_ = new AndroidVideoCapturer::FrameFactory( | 144 frame_factory_ = new AndroidVideoCapturer::FrameFactory(delegate_.get()); |
206 capture_format.width, capture_format.height, delegate_.get()); | |
207 set_frame_factory(frame_factory_); | 145 set_frame_factory(frame_factory_); |
208 | 146 |
209 running_ = true; | 147 running_ = true; |
210 delegate_->Start( | 148 delegate_->Start( |
211 capture_format.width, capture_format.height, | 149 capture_format.width, capture_format.height, |
212 cricket::VideoFormat::IntervalToFps(capture_format.interval), this); | 150 cricket::VideoFormat::IntervalToFps(capture_format.interval), this); |
213 SetCaptureFormat(&capture_format); | 151 SetCaptureFormat(&capture_format); |
214 current_state_ = cricket::CS_STARTING; | 152 current_state_ = cricket::CS_STARTING; |
215 return current_state_; | 153 return current_state_; |
216 } | 154 } |
(...skipping 28 matching lines...) Expand all Loading... | |
245 if (new_state == current_state_) | 183 if (new_state == current_state_) |
246 return; | 184 return; |
247 current_state_ = new_state; | 185 current_state_ = new_state; |
248 | 186 |
249 // TODO(perkj): SetCaptureState can not be used since it posts to |thread_|. | 187 // TODO(perkj): SetCaptureState can not be used since it posts to |thread_|. |
250 // But |thread_ | is currently just the thread that happened to create the | 188 // But |thread_ | is currently just the thread that happened to create the |
251 // cricket::VideoCapturer. | 189 // cricket::VideoCapturer. |
252 SignalStateChange(this, new_state); | 190 SignalStateChange(this, new_state); |
253 } | 191 } |
254 | 192 |
255 void AndroidVideoCapturer::OnIncomingFrame(void* frame_data, | 193 void AndroidVideoCapturer::OnIncomingFrame( |
256 int length, | 194 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer, |
257 int width, | 195 int rotation, |
258 int height, | 196 int64 time_stamp) { |
259 int rotation, | |
260 int64 time_stamp) { | |
261 CHECK(thread_checker_.CalledOnValidThread()); | 197 CHECK(thread_checker_.CalledOnValidThread()); |
262 frame_factory_->UpdateCapturedFrame(frame_data, length, width, height, | 198 frame_factory_->UpdateCapturedFrame(buffer, rotation, time_stamp); |
263 rotation, time_stamp); | |
264 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame()); | 199 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame()); |
265 if (frame_factory_->GetCapturedFrame()->data == nullptr) { | 200 frame_factory_->ClearCapturedFrame(); |
266 // Ownership has been passed to a WrappedI420Buffer. Do nothing. | |
267 } else { | |
268 // |captured_frame_| has either been copied or dropped, return it | |
269 // immediately. | |
270 delegate_->ReturnBuffer(time_stamp); | |
271 frame_factory_->ClearCapturedFrame(); | |
272 } | |
273 } | 201 } |
274 | 202 |
275 void AndroidVideoCapturer::OnOutputFormatRequest( | 203 void AndroidVideoCapturer::OnOutputFormatRequest( |
276 int width, int height, int fps) { | 204 int width, int height, int fps) { |
277 CHECK(thread_checker_.CalledOnValidThread()); | 205 CHECK(thread_checker_.CalledOnValidThread()); |
278 const cricket::VideoFormat& current = video_adapter()->output_format(); | 206 const cricket::VideoFormat& current = video_adapter()->output_format(); |
279 cricket::VideoFormat format( | 207 cricket::VideoFormat format( |
280 width, height, cricket::VideoFormat::FpsToInterval(fps), current.fourcc); | 208 width, height, cricket::VideoFormat::FpsToInterval(fps), current.fourcc); |
281 video_adapter()->OnOutputFormatRequest(format); | 209 video_adapter()->OnOutputFormatRequest(format); |
282 } | 210 } |
283 | 211 |
284 } // namespace webrtc | 212 } // namespace webrtc |
OLD | NEW |