| 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 // TODO(magjed): Change CreateAliasedFrame() to return a rtc::scoped_ptr. |
| 114 // Android guarantees that the stride is a multiple of 16. | 92 return apply_rotation_ ? frame->GetCopyWithRotationApplied()->Copy() |
| 115 // http://developer.android.com/reference/android/hardware/Camera.Paramete
rs.html#setPreviewFormat%28int%29 | 93 : frame.release(); |
| 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 } | 94 } |
| 154 | 95 |
| 155 private: | 96 private: |
| 156 uint64 start_time_; | 97 uint64 start_time_; |
| 157 // |captured_frame_| is mutable as a hacky way to modify it inside | 98 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer_; |
| 158 // CreateAliasedframe(). | 99 cricket::CapturedFrame captured_frame_; |
| 159 mutable cricket::CapturedFrame captured_frame_; | 100 rtc::scoped_refptr<AndroidVideoCapturerDelegate> delegate_; |
| 160 scoped_refptr<AndroidVideoCapturerDelegate> delegate_; | |
| 161 }; | 101 }; |
| 162 | 102 |
| 163 AndroidVideoCapturer::AndroidVideoCapturer( | 103 AndroidVideoCapturer::AndroidVideoCapturer( |
| 164 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate) | 104 const rtc::scoped_refptr<AndroidVideoCapturerDelegate>& delegate) |
| 165 : running_(false), | 105 : running_(false), |
| 166 delegate_(delegate), | 106 delegate_(delegate), |
| 167 frame_factory_(NULL), | 107 frame_factory_(NULL), |
| 168 current_state_(cricket::CS_STOPPED) { | 108 current_state_(cricket::CS_STOPPED) { |
| 169 thread_checker_.DetachFromThread(); | 109 thread_checker_.DetachFromThread(); |
| 170 std::string json_string = delegate_->GetSupportedFormats(); | 110 std::string json_string = delegate_->GetSupportedFormats(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 195 CHECK(!running_); | 135 CHECK(!running_); |
| 196 } | 136 } |
| 197 | 137 |
| 198 cricket::CaptureState AndroidVideoCapturer::Start( | 138 cricket::CaptureState AndroidVideoCapturer::Start( |
| 199 const cricket::VideoFormat& capture_format) { | 139 const cricket::VideoFormat& capture_format) { |
| 200 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width | 140 LOG(LS_INFO) << " AndroidVideoCapturer::Start w = " << capture_format.width |
| 201 << " h = " << capture_format.height; | 141 << " h = " << capture_format.height; |
| 202 CHECK(thread_checker_.CalledOnValidThread()); | 142 CHECK(thread_checker_.CalledOnValidThread()); |
| 203 CHECK(!running_); | 143 CHECK(!running_); |
| 204 | 144 |
| 205 frame_factory_ = new AndroidVideoCapturer::FrameFactory( | 145 frame_factory_ = new AndroidVideoCapturer::FrameFactory(delegate_.get()); |
| 206 capture_format.width, capture_format.height, delegate_.get()); | |
| 207 set_frame_factory(frame_factory_); | 146 set_frame_factory(frame_factory_); |
| 208 | 147 |
| 209 running_ = true; | 148 running_ = true; |
| 210 delegate_->Start( | 149 delegate_->Start( |
| 211 capture_format.width, capture_format.height, | 150 capture_format.width, capture_format.height, |
| 212 cricket::VideoFormat::IntervalToFps(capture_format.interval), this); | 151 cricket::VideoFormat::IntervalToFps(capture_format.interval), this); |
| 213 SetCaptureFormat(&capture_format); | 152 SetCaptureFormat(&capture_format); |
| 214 current_state_ = cricket::CS_STARTING; | 153 current_state_ = cricket::CS_STARTING; |
| 215 return current_state_; | 154 return current_state_; |
| 216 } | 155 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 245 if (new_state == current_state_) | 184 if (new_state == current_state_) |
| 246 return; | 185 return; |
| 247 current_state_ = new_state; | 186 current_state_ = new_state; |
| 248 | 187 |
| 249 // TODO(perkj): SetCaptureState can not be used since it posts to |thread_|. | 188 // 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 | 189 // But |thread_ | is currently just the thread that happened to create the |
| 251 // cricket::VideoCapturer. | 190 // cricket::VideoCapturer. |
| 252 SignalStateChange(this, new_state); | 191 SignalStateChange(this, new_state); |
| 253 } | 192 } |
| 254 | 193 |
| 255 void AndroidVideoCapturer::OnIncomingFrame(void* frame_data, | 194 void AndroidVideoCapturer::OnIncomingFrame( |
| 256 int length, | 195 rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer, |
| 257 int width, | 196 int rotation, |
| 258 int height, | 197 int64 time_stamp) { |
| 259 int rotation, | |
| 260 int64 time_stamp) { | |
| 261 CHECK(thread_checker_.CalledOnValidThread()); | 198 CHECK(thread_checker_.CalledOnValidThread()); |
| 262 frame_factory_->UpdateCapturedFrame(frame_data, length, width, height, | 199 frame_factory_->UpdateCapturedFrame(buffer, rotation, time_stamp); |
| 263 rotation, time_stamp); | |
| 264 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame()); | 200 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame()); |
| 265 if (frame_factory_->GetCapturedFrame()->data == nullptr) { | 201 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 } | 202 } |
| 274 | 203 |
| 275 void AndroidVideoCapturer::OnOutputFormatRequest( | 204 void AndroidVideoCapturer::OnOutputFormatRequest( |
| 276 int width, int height, int fps) { | 205 int width, int height, int fps) { |
| 277 CHECK(thread_checker_.CalledOnValidThread()); | 206 CHECK(thread_checker_.CalledOnValidThread()); |
| 278 const cricket::VideoFormat& current = video_adapter()->output_format(); | 207 const cricket::VideoFormat& current = video_adapter()->output_format(); |
| 279 cricket::VideoFormat format( | 208 cricket::VideoFormat format( |
| 280 width, height, cricket::VideoFormat::FpsToInterval(fps), current.fourcc); | 209 width, height, cricket::VideoFormat::FpsToInterval(fps), current.fourcc); |
| 281 video_adapter()->OnOutputFormatRequest(format); | 210 video_adapter()->OnOutputFormatRequest(format); |
| 282 } | 211 } |
| 283 | 212 |
| 284 } // namespace webrtc | 213 } // namespace webrtc |
| OLD | NEW |