1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 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 11 #include "webrtc/modules/video_capture/video_capture_impl.h" 12 13 #include <stdlib.h> 14 15 #include "webrtc/base/trace_event.h" 16 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" 17 #include "webrtc/modules/include/module_common_types.h" 18 #include "webrtc/modules/video_capture/video_capture_config.h" 19 #include "webrtc/system_wrappers/include/clock.h" 20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" 21 #include "webrtc/system_wrappers/include/logging.h" 22 #include "webrtc/system_wrappers/include/ref_count.h" 23 #include "webrtc/system_wrappers/include/tick_util.h" 24 25 namespace webrtc 26 { 27 28 namespace videocapturemodule 29 { 30 VideoCaptureModule* VideoCaptureImpl::Create( 31 const int32_t id, 32 VideoCaptureExternal*& externalCapture) 33 { 34 RefCountImpl<VideoCaptureImpl>* implementation = 35 new RefCountImpl<VideoCaptureImpl>(id); 36 externalCapture = implementation; 37 return implementation; 38 } 39 40 const char* VideoCaptureImpl::CurrentDeviceName() const 41 { 42 return _deviceUniqueId; 43 } 44 45 // static 46 int32_t VideoCaptureImpl::RotationFromDegrees(int degrees, 47 VideoRotation* rotation) { 48 switch (degrees) { 49 case 0: 50 *rotation = kVideoRotation_0; 51 return 0; 52 case 90: 53 *rotation = kVideoRotation_90; 54 return 0; 55 case 180: 56 *rotation = kVideoRotation_180; 57 return 0; 58 case 270: 59 *rotation = kVideoRotation_270; 60 return 0; 61 default: 62 return -1;; 63 } 64 } 65 66 // static 67 int32_t VideoCaptureImpl::RotationInDegrees(VideoRotation rotation, 68 int* degrees) { 69 switch (rotation) { 70 case kVideoRotation_0: 71 *degrees = 0; 72 return 0; 73 case kVideoRotation_90: 74 *degrees = 90; 75 return 0; 76 case kVideoRotation_180: 77 *degrees = 180; 78 return 0; 79 case kVideoRotation_270: 80 *degrees = 270; 81 return 0; 82 } 83 return -1; 84 } 85 86 // returns the number of milliseconds until the module want a worker thread to call Process 87 int64_t VideoCaptureImpl::TimeUntilNextProcess() 88 { 89 CriticalSectionScoped cs(&_callBackCs); 90 const int64_t kProcessIntervalMs = 300; 91 return kProcessIntervalMs - 92 (TickTime::Now() - _lastProcessTime).Milliseconds(); 93 } 94 95 // Process any pending tasks such as timeouts 96 int32_t VideoCaptureImpl::Process() 97 { 98 CriticalSectionScoped cs(&_callBackCs); 99 100 const TickTime now = TickTime::Now(); 101 _lastProcessTime = TickTime::Now(); 102 103 // Handle No picture alarm 104 105 if (_lastProcessFrameCount.Ticks() == _incomingFrameTimes[0].Ticks() && 106 _captureAlarm != Raised) 107 { 108 if (_noPictureAlarmCallBack && _captureCallBack) 109 { 110 _captureAlarm = Raised; 111 _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm); 112 } 113 } 114 else if (_lastProcessFrameCount.Ticks() != _incomingFrameTimes[0].Ticks() && 115 _captureAlarm != Cleared) 116 { 117 if (_noPictureAlarmCallBack && _captureCallBack) 118 { 119 _captureAlarm = Cleared; 120 _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm); 121 122 } 123 } 124 125 // Handle frame rate callback 126 if ((now - _lastFrameRateCallbackTime).Milliseconds() 127 > kFrameRateCallbackInterval) 128 { 129 if (_frameRateCallBack && _captureCallBack) 130 { 131 const uint32_t frameRate = CalculateFrameRate(now); 132 _captureCallBack->OnCaptureFrameRate(_id, frameRate); 133 } 134 _lastFrameRateCallbackTime = now; // Can be set by EnableFrameRateCallback 135 136 } 137 138 _lastProcessFrameCount = _incomingFrameTimes[0]; 139 140 return 0; 141 } 142 143 VideoCaptureImpl::VideoCaptureImpl(const int32_t id) 144 : _id(id), 145 _deviceUniqueId(NULL), 146 _apiCs(*CriticalSectionWrapper::CreateCriticalSection()), 147 _captureDelay(0), 148 _requestedCapability(), 149 _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()), 150 _lastProcessTime(TickTime::Now()), 151 _lastFrameRateCallbackTime(TickTime::Now()), 152 _frameRateCallBack(false), 153 _noPictureAlarmCallBack(false), 154 _captureAlarm(Cleared), 155 _setCaptureDelay(0), 156 _dataCallBack(NULL), 157 _captureCallBack(NULL), 158 _lastProcessFrameCount(TickTime::Now()), 159 _rotateFrame(kVideoRotation_0), 160 apply_rotation_(true) { 161 _requestedCapability.width = kDefaultWidth; 162 _requestedCapability.height = kDefaultHeight; 163 _requestedCapability.maxFPS = 30; 164 _requestedCapability.rawType = kVideoI420; 165 _requestedCapability.codecType = kVideoCodecUnknown; 166 memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes)); 167 } 168 169 VideoCaptureImpl::~VideoCaptureImpl() 170 { 171 DeRegisterCaptureDataCallback(); 172 DeRegisterCaptureCallback(); 173 delete &_callBackCs; 174 delete &_apiCs; 175 176 if (_deviceUniqueId) 177 delete[] _deviceUniqueId; 178 } 179 180 void VideoCaptureImpl::RegisterCaptureDataCallback( 181 VideoCaptureDataCallback& dataCallBack) { 182 CriticalSectionScoped cs(&_apiCs); 183 CriticalSectionScoped cs2(&_callBackCs); 184 _dataCallBack = &dataCallBack; 185 } 186 187 void VideoCaptureImpl::DeRegisterCaptureDataCallback() { 188 CriticalSectionScoped cs(&_apiCs); 189 CriticalSectionScoped cs2(&_callBackCs); 190 _dataCallBack = NULL; 191 } 192 void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) { 193 194 CriticalSectionScoped cs(&_apiCs); 195 CriticalSectionScoped cs2(&_callBackCs); 196 _captureCallBack = &callBack; 197 } 198 void VideoCaptureImpl::DeRegisterCaptureCallback() { 199 200 CriticalSectionScoped cs(&_apiCs); 201 CriticalSectionScoped cs2(&_callBackCs); 202 _captureCallBack = NULL; 203 } 204 void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) { 205 CriticalSectionScoped cs(&_apiCs); 206 _captureDelay = delayMS; 207 } 208 int32_t VideoCaptureImpl::CaptureDelay() 209 { 210 CriticalSectionScoped cs(&_apiCs); 211 return _setCaptureDelay; 212 } 213 214 int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) { 215 UpdateFrameCount(); // frame count used for local frame rate callback. 216 217 const bool callOnCaptureDelayChanged = _setCaptureDelay != _captureDelay; 218 // Capture delay changed 219 if (_setCaptureDelay != _captureDelay) { 220 _setCaptureDelay = _captureDelay; 221 } 222 223 if (_dataCallBack) { 224 if (callOnCaptureDelayChanged) { 225 _dataCallBack->OnCaptureDelayChanged(_id, _captureDelay); 226 } 227 _dataCallBack->OnIncomingCapturedFrame(_id, captureFrame); 228 } 229 230 return 0; 231 } 232 233 int32_t VideoCaptureImpl::IncomingFrame( 234 uint8_t* videoFrame, 235 size_t videoFrameLength, 236 const VideoCaptureCapability& frameInfo, 237 int64_t captureTime/*=0*/) 238 { 239 CriticalSectionScoped cs(&_apiCs); 240 CriticalSectionScoped cs2(&_callBackCs); 241 242 const int32_t width = frameInfo.width; 243 const int32_t height = frameInfo.height; 244 245 TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime); 246 247 if (frameInfo.codecType == kVideoCodecUnknown) 248 { 249 // Not encoded, convert to I420. 250 const VideoType commonVideoType = 251 RawVideoTypeToCommonVideoVideoType(frameInfo.rawType); 252 253 if (frameInfo.rawType != kVideoMJPEG && 254 CalcBufferSize(commonVideoType, width, 255 abs(height)) != videoFrameLength) 256 { 257 LOG(LS_ERROR) << "Wrong incoming frame length."; 258 return -1; 259 } 260 261 int stride_y = width; 262 int stride_uv = (width + 1) / 2; 263 int target_width = width; 264 int target_height = height; 265 266 // SetApplyRotation doesn't take any lock. Make a local copy here. 267 bool apply_rotation = apply_rotation_; 268 269 if (apply_rotation) { 270 // Rotating resolution when for 90/270 degree rotations. 271 if (_rotateFrame == kVideoRotation_90 || 272 _rotateFrame == kVideoRotation_270) { 273 target_width = abs(height); 274 target_height = width; 275 } 276 } 277 278 // TODO(mikhal): Update correct aligned stride values. 279 //Calc16ByteAlignedStride(target_width, &stride_y, &stride_uv); 280 // Setting absolute height (in case it was negative). 281 // In Windows, the image starts bottom left, instead of top left. 282 // Setting a negative source height, inverts the image (within LibYuv). 283 int ret = _captureFrame.CreateEmptyFrame(target_width, 284 abs(target_height), 285 stride_y, 286 stride_uv, stride_uv); 287 if (ret < 0) 288 { 289 LOG(LS_ERROR) << "Failed to create empty frame, this should only " 290 "happen due to bad parameters."; 291 return -1; 292 } 293 const int conversionResult = ConvertToI420( 294 commonVideoType, videoFrame, 0, 0, // No cropping 295 width, height, videoFrameLength, 296 apply_rotation ? _rotateFrame : kVideoRotation_0, &_captureFrame); 297 if (conversionResult < 0) 298 { 299 LOG(LS_ERROR) << "Failed to convert capture frame from type " 300 << frameInfo.rawType << "to I420."; 301 return -1; 302 } 303 304 if (!apply_rotation) { 305 _captureFrame.set_rotation(_rotateFrame); 306 } else { 307 _captureFrame.set_rotation(kVideoRotation_0); 308 } 309 _captureFrame.set_ntp_time_ms(captureTime); 310 _captureFrame.set_render_time_ms(TickTime::MillisecondTimestamp()); 311 312 DeliverCapturedFrame(_captureFrame); 313 } 314 else // Encoded format 315 { 316 assert(false); 317 return -1; 318 } 319 320 return 0; 321 } 322 323 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) { 324 CriticalSectionScoped cs(&_apiCs); 325 CriticalSectionScoped cs2(&_callBackCs); 326 _rotateFrame = rotation; 327 return 0; 328 } 329 330 void VideoCaptureImpl::EnableFrameRateCallback(const bool enable) { 331 CriticalSectionScoped cs(&_apiCs); 332 CriticalSectionScoped cs2(&_callBackCs); 333 _frameRateCallBack = enable; 334 if (enable) 335 { 336 _lastFrameRateCallbackTime = TickTime::Now(); 337 } 338 } 339 340 bool VideoCaptureImpl::SetApplyRotation(bool enable) { 341 // We can't take any lock here as it'll cause deadlock with IncomingFrame. 342 343 // The effect of this is the last caller wins. 344 apply_rotation_ = enable; 345 return true; 346 } 347 348 void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) { 349 CriticalSectionScoped cs(&_apiCs); 350 CriticalSectionScoped cs2(&_callBackCs); 351 _noPictureAlarmCallBack = enable; 352 } 353 354 void VideoCaptureImpl::UpdateFrameCount() 355 { 356 if (_incomingFrameTimes[0].MicrosecondTimestamp() == 0) 357 { 358 // first no shift 359 } 360 else 361 { 362 // shift 363 for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--) 364 { 365 _incomingFrameTimes[i + 1] = _incomingFrameTimes[i]; 366 } 367 } 368 _incomingFrameTimes[0] = TickTime::Now(); 369 } 370 371 uint32_t VideoCaptureImpl::CalculateFrameRate(const TickTime& now) 372 { 373 int32_t num = 0; 374 int32_t nrOfFrames = 0; 375 for (num = 1; num < (kFrameRateCountHistorySize - 1); num++) 376 { 377 if (_incomingFrameTimes[num].Ticks() <= 0 378 || (now - _incomingFrameTimes[num]).Milliseconds() > kFrameRateHistoryWindowMs) // don't use data older than 2sec 379 { 380 break; 381 } 382 else 383 { 384 nrOfFrames++; 385 } 386 } 387 if (num > 1) 388 { 389 int64_t diff = (now - _incomingFrameTimes[num - 1]).Milliseconds(); 390 if (diff > 0) 391 { 392 return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f); 393 } 394 } 395 396 return nrOfFrames; 397 } 398 } // namespace videocapturemodule 399 } // namespace webrtc 400