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