blob: e3c78f18ef0be2a6d8891948aea12a942b121f80 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mallinath@webrtc.org12984f02012-02-16 18:18:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * 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.
9 */
10
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000011#include "webrtc/modules/video_capture/video_capture_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
elham@webrtc.org5f49dba2012-04-23 21:24:02 +000013#include <stdlib.h>
14
Peter Boström1d194412016-03-21 16:44:31 +010015#include "webrtc/base/refcount.h"
Niels Möllerd28db7f2016-05-10 16:31:47 +020016#include "webrtc/base/timeutils.h"
tommie4f96502015-10-20 23:00:48 -070017#include "webrtc/base/trace_event.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000018#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010019#include "webrtc/modules/include/module_common_types.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000020#include "webrtc/modules/video_capture/video_capture_config.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/clock.h"
22#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
23#include "webrtc/system_wrappers/include/logging.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000024
Peter Boström1d194412016-03-21 16:44:31 +010025namespace webrtc {
26namespace videocapturemodule {
27rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
Peter Boström1d194412016-03-21 16:44:31 +010028 VideoCaptureExternal*& externalCapture) {
29 rtc::scoped_refptr<VideoCaptureImpl> implementation(
nisseb29b9c82016-12-12 00:22:56 -080030 new rtc::RefCountedObject<VideoCaptureImpl>());
Peter Boström1d194412016-03-21 16:44:31 +010031 externalCapture = implementation.get();
32 return implementation;
niklase@google.com470e71d2011-07-07 08:21:25 +000033}
34
leozwang@webrtc.org1745e932012-03-01 16:30:40 +000035const char* VideoCaptureImpl::CurrentDeviceName() const
niklase@google.com470e71d2011-07-07 08:21:25 +000036{
37 return _deviceUniqueId;
38}
39
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000040// static
41int32_t VideoCaptureImpl::RotationFromDegrees(int degrees,
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000042 VideoRotation* rotation) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000043 switch (degrees) {
44 case 0:
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000045 *rotation = kVideoRotation_0;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000046 return 0;
47 case 90:
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000048 *rotation = kVideoRotation_90;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000049 return 0;
50 case 180:
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000051 *rotation = kVideoRotation_180;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000052 return 0;
53 case 270:
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000054 *rotation = kVideoRotation_270;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000055 return 0;
56 default:
57 return -1;;
58 }
59}
60
61// static
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000062int32_t VideoCaptureImpl::RotationInDegrees(VideoRotation rotation,
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000063 int* degrees) {
64 switch (rotation) {
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000065 case kVideoRotation_0:
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000066 *degrees = 0;
67 return 0;
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000068 case kVideoRotation_90:
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000069 *degrees = 90;
70 return 0;
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000071 case kVideoRotation_180:
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000072 *degrees = 180;
73 return 0;
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +000074 case kVideoRotation_270:
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000075 *degrees = 270;
76 return 0;
77 }
78 return -1;
79}
80
nisseb29b9c82016-12-12 00:22:56 -080081VideoCaptureImpl::VideoCaptureImpl()
82 : _deviceUniqueId(NULL),
pbos@webrtc.org504af452013-07-02 10:15:43 +000083 _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
84 _captureDelay(0),
85 _requestedCapability(),
Niels Möllerd28db7f2016-05-10 16:31:47 +020086 _lastProcessTimeNanos(rtc::TimeNanos()),
87 _lastFrameRateCallbackTimeNanos(rtc::TimeNanos()),
pbos@webrtc.org504af452013-07-02 10:15:43 +000088 _dataCallBack(NULL),
Niels Möllerd28db7f2016-05-10 16:31:47 +020089 _lastProcessFrameTimeNanos(rtc::TimeNanos()),
guoweis@webrtc.org59140d62015-03-09 17:07:31 +000090 _rotateFrame(kVideoRotation_0),
deadbeeff5629ad2016-03-18 11:38:26 -070091 apply_rotation_(false) {
niklase@google.com470e71d2011-07-07 08:21:25 +000092 _requestedCapability.width = kDefaultWidth;
93 _requestedCapability.height = kDefaultHeight;
94 _requestedCapability.maxFPS = 30;
95 _requestedCapability.rawType = kVideoI420;
96 _requestedCapability.codecType = kVideoCodecUnknown;
Niels Möllerd28db7f2016-05-10 16:31:47 +020097 memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos));
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
100VideoCaptureImpl::~VideoCaptureImpl()
101{
102 DeRegisterCaptureDataCallback();
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 delete &_apiCs;
104
105 if (_deviceUniqueId)
106 delete[] _deviceUniqueId;
107}
108
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000109void VideoCaptureImpl::RegisterCaptureDataCallback(
nisseb29b9c82016-12-12 00:22:56 -0800110 rtc::VideoSinkInterface<VideoFrame>* dataCallBack) {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000111 CriticalSectionScoped cs(&_apiCs);
nisseb29b9c82016-12-12 00:22:56 -0800112 _dataCallBack = dataCallBack;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
114
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000115void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000116 CriticalSectionScoped cs(&_apiCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 _dataCallBack = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118}
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700119int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) {
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000120 UpdateFrameCount(); // frame count used for local frame rate callback.
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000121
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000122 if (_dataCallBack) {
nisseb29b9c82016-12-12 00:22:56 -0800123 _dataCallBack->OnFrame(captureFrame);
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000124 }
125
126 return 0;
127}
128
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000129int32_t VideoCaptureImpl::IncomingFrame(
130 uint8_t* videoFrame,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000131 size_t videoFrameLength,
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000132 const VideoCaptureCapability& frameInfo,
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000133 int64_t captureTime/*=0*/)
niklase@google.com470e71d2011-07-07 08:21:25 +0000134{
fischman@webrtc.org42694c52014-06-06 18:28:28 +0000135 CriticalSectionScoped cs(&_apiCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000137 const int32_t width = frameInfo.width;
138 const int32_t height = frameInfo.height;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000140 TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
141
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000142 if (frameInfo.codecType == kVideoCodecUnknown)
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 {
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000144 // Not encoded, convert to I420.
mikhal@webrtc.orge39de162011-12-27 23:45:30 +0000145 const VideoType commonVideoType =
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000146 RawVideoTypeToCommonVideoVideoType(frameInfo.rawType);
147
148 if (frameInfo.rawType != kVideoMJPEG &&
elham@webrtc.org5f49dba2012-04-23 21:24:02 +0000149 CalcBufferSize(commonVideoType, width,
150 abs(height)) != videoFrameLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 {
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +0000152 LOG(LS_ERROR) << "Wrong incoming frame length.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 return -1;
154 }
155
mikhal@webrtc.org4c4d01d2012-11-21 22:18:32 +0000156 int stride_y = width;
157 int stride_uv = (width + 1) / 2;
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000158 int target_width = width;
159 int target_height = height;
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000160
Guo-wei Shieh64c1e8c2015-04-01 15:33:06 -0700161 // SetApplyRotation doesn't take any lock. Make a local copy here.
162 bool apply_rotation = apply_rotation_;
163
164 if (apply_rotation) {
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000165 // Rotating resolution when for 90/270 degree rotations.
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000166 if (_rotateFrame == kVideoRotation_90 ||
167 _rotateFrame == kVideoRotation_270) {
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000168 target_width = abs(height);
169 target_height = width;
170 }
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000171 }
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000172
mikhal@webrtc.org2f4ff892012-09-24 21:09:54 +0000173 // Setting absolute height (in case it was negative).
174 // In Windows, the image starts bottom left, instead of top left.
175 // Setting a negative source height, inverts the image (within LibYuv).
nisse64ec8f82016-09-27 00:17:25 -0700176
177 // TODO(nisse): Use a pool?
178 rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(
179 target_width, abs(target_height), stride_y, stride_uv, stride_uv);
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000180 const int conversionResult = ConvertToI420(
181 commonVideoType, videoFrame, 0, 0, // No cropping
182 width, height, videoFrameLength,
nisse64ec8f82016-09-27 00:17:25 -0700183 apply_rotation ? _rotateFrame : kVideoRotation_0, buffer.get());
mikhal@webrtc.org2ab104e2011-12-09 02:46:22 +0000184 if (conversionResult < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 {
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +0000186 LOG(LS_ERROR) << "Failed to convert capture frame from type "
187 << frameInfo.rawType << "to I420.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 return -1;
189 }
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000190
nisse64ec8f82016-09-27 00:17:25 -0700191 VideoFrame captureFrame(
192 buffer, 0, rtc::TimeMillis(),
193 !apply_rotation ? _rotateFrame : kVideoRotation_0);
194 captureFrame.set_ntp_time_ms(captureTime);
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000195
nisse64ec8f82016-09-27 00:17:25 -0700196 DeliverCapturedFrame(captureFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
198 else // Encoded format
199 {
mflodman@webrtc.org3ba883f2013-06-07 13:57:57 +0000200 assert(false);
201 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 }
203
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 return 0;
wu@webrtc.orgf10ea312011-10-14 17:16:04 +0000205}
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +0000207int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000208 CriticalSectionScoped cs(&_apiCs);
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000209 _rotateFrame = rotation;
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000210 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000211}
212
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000213bool VideoCaptureImpl::SetApplyRotation(bool enable) {
Guo-wei Shieh64c1e8c2015-04-01 15:33:06 -0700214 // We can't take any lock here as it'll cause deadlock with IncomingFrame.
215
guoweis@webrtc.org1226e922015-02-11 18:37:54 +0000216 // The effect of this is the last caller wins.
217 apply_rotation_ = enable;
218 return true;
219}
220
niklase@google.com470e71d2011-07-07 08:21:25 +0000221void VideoCaptureImpl::UpdateFrameCount()
222{
Niels Möllerd28db7f2016-05-10 16:31:47 +0200223 if (_incomingFrameTimesNanos[0] / rtc::kNumNanosecsPerMicrosec == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 {
225 // first no shift
226 }
227 else
228 {
229 // shift
230 for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--)
231 {
Niels Möllerd28db7f2016-05-10 16:31:47 +0200232 _incomingFrameTimesNanos[i + 1] = _incomingFrameTimesNanos[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 }
234 }
Niels Möllerd28db7f2016-05-10 16:31:47 +0200235 _incomingFrameTimesNanos[0] = rtc::TimeNanos();
niklase@google.com470e71d2011-07-07 08:21:25 +0000236}
237
Niels Möllerd28db7f2016-05-10 16:31:47 +0200238uint32_t VideoCaptureImpl::CalculateFrameRate(int64_t now_ns)
niklase@google.com470e71d2011-07-07 08:21:25 +0000239{
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000240 int32_t num = 0;
241 int32_t nrOfFrames = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 for (num = 1; num < (kFrameRateCountHistorySize - 1); num++)
243 {
Niels Möllerd28db7f2016-05-10 16:31:47 +0200244 if (_incomingFrameTimesNanos[num] <= 0 ||
245 (now_ns - _incomingFrameTimesNanos[num]) /
246 rtc::kNumNanosecsPerMillisec >
247 kFrameRateHistoryWindowMs) // don't use data older than 2sec
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 {
249 break;
250 }
251 else
252 {
253 nrOfFrames++;
254 }
255 }
256 if (num > 1)
257 {
Niels Möllerd28db7f2016-05-10 16:31:47 +0200258 int64_t diff = (now_ns - _incomingFrameTimesNanos[num - 1]) /
259 rtc::kNumNanosecsPerMillisec;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 if (diff > 0)
261 {
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000262 return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 }
264 }
265
266 return nrOfFrames;
267}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000268} // namespace videocapturemodule
269} // namespace webrtc