video_capture_impl.cc (10993B)
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 "modules/video_capture/video_capture_impl.h" 12 13 #include <cstdint> 14 #include <cstdlib> 15 #include <cstring> 16 17 #include "api/scoped_refptr.h" 18 #include "api/sequence_checker.h" 19 #include "api/video/i420_buffer.h" 20 #include "api/video/video_frame.h" 21 #include "api/video/video_rotation.h" 22 #include "api/video/video_sink_interface.h" 23 #include "common_video/libyuv/include/webrtc_libyuv.h" 24 #include "modules/video_capture/raw_video_sink_interface.h" 25 #include "modules/video_capture/video_capture_config.h" 26 #include "modules/video_capture/video_capture_defines.h" 27 #include "rtc_base/checks.h" 28 #include "rtc_base/logging.h" 29 #include "rtc_base/race_checker.h" 30 #include "rtc_base/synchronization/mutex.h" 31 #include "rtc_base/time_utils.h" 32 #include "rtc_base/trace_event.h" 33 #include "system_wrappers/include/clock.h" 34 #include "third_party/libyuv/include/libyuv/convert.h" 35 #include "third_party/libyuv/include/libyuv/rotate.h" 36 37 namespace webrtc { 38 namespace videocapturemodule { 39 40 const char* VideoCaptureImpl::CurrentDeviceName() const { 41 RTC_DCHECK_RUN_ON(&api_checker_); 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 67 // static 68 int32_t VideoCaptureImpl::RotationInDegrees(VideoRotation rotation, 69 int* degrees) { 70 switch (rotation) { 71 case kVideoRotation_0: 72 *degrees = 0; 73 return 0; 74 case kVideoRotation_90: 75 *degrees = 90; 76 return 0; 77 case kVideoRotation_180: 78 *degrees = 180; 79 return 0; 80 case kVideoRotation_270: 81 *degrees = 270; 82 return 0; 83 } 84 return -1; 85 } 86 87 VideoCaptureImpl::VideoCaptureImpl(Clock* clock) 88 : _deviceUniqueId(nullptr), 89 _requestedCapability(), 90 _lastProcessTimeNanos(clock->TimeInMicroseconds() * 1000), 91 _lastFrameRateCallbackTimeNanos(clock->TimeInMicroseconds() * 1000), 92 _rawDataCallBack(nullptr), 93 _lastProcessFrameTimeNanos(clock->TimeInMicroseconds() * 1000), 94 _rotateFrame(kVideoRotation_0), 95 apply_rotation_(false), 96 clock_(clock) { 97 _requestedCapability.width = kDefaultWidth; 98 _requestedCapability.height = kDefaultHeight; 99 _requestedCapability.maxFPS = 30; 100 _requestedCapability.videoType = VideoType::kI420; 101 memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos)); 102 } 103 104 VideoCaptureImpl::~VideoCaptureImpl() { 105 RTC_DCHECK_RUN_ON(&api_checker_); 106 if (_deviceUniqueId) 107 delete[] _deviceUniqueId; 108 } 109 110 void VideoCaptureImpl::RegisterCaptureDataCallback( 111 VideoSinkInterface<VideoFrame>* dataCallBack) { 112 MutexLock lock(&api_lock_); 113 RTC_DCHECK(!_rawDataCallBack); 114 _dataCallBacks.insert(dataCallBack); 115 } 116 117 void VideoCaptureImpl::RegisterCaptureDataCallback( 118 RawVideoSinkInterface* dataCallBack) { 119 MutexLock lock(&api_lock_); 120 RTC_DCHECK(_dataCallBacks.empty()); 121 _rawDataCallBack = dataCallBack; 122 } 123 124 void VideoCaptureImpl::DeRegisterCaptureDataCallback( 125 webrtc::VideoSinkInterface<VideoFrame>* dataCallBack) { 126 MutexLock lock(&api_lock_); 127 auto it = _dataCallBacks.find(dataCallBack); 128 if (it != _dataCallBacks.end()) { 129 _dataCallBacks.erase(it); 130 } 131 _rawDataCallBack = nullptr; 132 } 133 134 int32_t VideoCaptureImpl::StopCaptureIfAllClientsClose() { 135 RTC_DCHECK_RUN_ON(&api_checker_); 136 { 137 MutexLock lock(&api_lock_); 138 if (!_dataCallBacks.empty()) { 139 return 0; 140 } 141 } 142 return StopCapture(); 143 } 144 145 int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) { 146 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 147 148 UpdateFrameCount(); // frame count used for local frame rate callback. 149 150 for (auto* dataCallBack : _dataCallBacks) { 151 dataCallBack->OnFrame(captureFrame); 152 } 153 154 return 0; 155 } 156 157 void VideoCaptureImpl::DeliverRawFrame(uint8_t* videoFrame, 158 size_t videoFrameLength, 159 const VideoCaptureCapability& frameInfo, 160 int64_t captureTime) { 161 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 162 163 UpdateFrameCount(); 164 _rawDataCallBack->OnRawFrame(videoFrame, videoFrameLength, frameInfo, 165 _rotateFrame, captureTime); 166 } 167 168 int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, 169 size_t videoFrameLength, 170 const VideoCaptureCapability& frameInfo, 171 int64_t captureTime /*=0*/) { 172 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 173 MutexLock lock(&api_lock_); 174 175 const int32_t width = frameInfo.width; 176 const int32_t height = frameInfo.height; 177 178 TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime); 179 180 if (_rawDataCallBack) { 181 DeliverRawFrame(videoFrame, videoFrameLength, frameInfo, captureTime); 182 return 0; 183 } 184 185 // Not encoded, convert to I420. 186 if (frameInfo.videoType != VideoType::kMJPEG) { 187 // Allow buffers larger than expected. On linux gstreamer allocates buffers 188 // page-aligned and v4l2loopback passes us the buffer size verbatim which 189 // for most cases is larger than expected. 190 // See https://github.com/umlaeute/v4l2loopback/issues/190. 191 if (auto size = CalcBufferSize(frameInfo.videoType, width, abs(height)); 192 videoFrameLength < size) { 193 RTC_LOG(LS_ERROR) << "Wrong incoming frame length. Expected " << size 194 << ", Got " << videoFrameLength << "."; 195 return -1; 196 } 197 } 198 199 int target_width = width; 200 int target_height = abs(height); 201 202 if (apply_rotation_) { 203 // Rotating resolution when for 90/270 degree rotations. 204 if (_rotateFrame == kVideoRotation_90 || 205 _rotateFrame == kVideoRotation_270) { 206 target_width = abs(height); 207 target_height = width; 208 } 209 } 210 211 int stride_y = target_width; 212 int stride_uv = (target_width + 1) / 2; 213 214 // Setting absolute height (in case it was negative). 215 // In Windows, the image starts bottom left, instead of top left. 216 // Setting a negative source height, inverts the image (within LibYuv). 217 scoped_refptr<I420Buffer> buffer = I420Buffer::Create( 218 target_width, target_height, stride_y, stride_uv, stride_uv); 219 220 libyuv::RotationMode rotation_mode = libyuv::kRotate0; 221 if (apply_rotation_) { 222 switch (_rotateFrame) { 223 case kVideoRotation_0: 224 rotation_mode = libyuv::kRotate0; 225 break; 226 case kVideoRotation_90: 227 rotation_mode = libyuv::kRotate90; 228 break; 229 case kVideoRotation_180: 230 rotation_mode = libyuv::kRotate180; 231 break; 232 case kVideoRotation_270: 233 rotation_mode = libyuv::kRotate270; 234 break; 235 } 236 } 237 238 int dst_width = buffer->width(); 239 int dst_height = buffer->height(); 240 241 // LibYuv expects pre-rotation_mode values for dst. 242 // Stride values should correspond to the destination values. 243 if (rotation_mode == libyuv::kRotate90 || rotation_mode == libyuv::kRotate270) { 244 std::swap(dst_width, dst_height); 245 } 246 247 const int conversionResult = libyuv::ConvertToI420( 248 videoFrame, videoFrameLength, buffer->MutableDataY(), buffer->StrideY(), 249 buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(), 250 buffer->StrideV(), 0, 0, // No Cropping 251 width, height, dst_width, dst_height, rotation_mode, 252 ConvertVideoType(frameInfo.videoType)); 253 if (conversionResult != 0) { 254 RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type " 255 << static_cast<int>(frameInfo.videoType) << "to I420."; 256 return -1; 257 } 258 259 VideoFrame captureFrame = 260 VideoFrame::Builder() 261 .set_video_frame_buffer(buffer) 262 .set_rtp_timestamp(0) 263 .set_timestamp_ms(clock_->TimeInMilliseconds()) 264 .set_rotation(!apply_rotation_ ? _rotateFrame : kVideoRotation_0) 265 .build(); 266 captureFrame.set_ntp_time_ms(captureTime); 267 268 // This is one ugly hack to let CamerasParent know what rotation 269 // the frame was captured at. Note that this goes against the intended 270 // meaning of rotation of the frame (how to rotate it before rendering). 271 // We do this so CamerasChild can scale to the proper dimensions 272 // later on in the pipe. 273 captureFrame.set_rotation(_rotateFrame); 274 275 DeliverCapturedFrame(captureFrame); 276 277 return 0; 278 } 279 280 int32_t VideoCaptureImpl::StartCapture( 281 const VideoCaptureCapability& capability) { 282 RTC_DCHECK_RUN_ON(&api_checker_); 283 _requestedCapability = capability; 284 return -1; 285 } 286 287 int32_t VideoCaptureImpl::StopCapture() { 288 return -1; 289 } 290 291 bool VideoCaptureImpl::CaptureStarted() { 292 return false; 293 } 294 295 int32_t VideoCaptureImpl::CaptureSettings( 296 VideoCaptureCapability& /*settings*/) { 297 return -1; 298 } 299 300 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) { 301 MutexLock lock(&api_lock_); 302 _rotateFrame = rotation; 303 return 0; 304 } 305 306 bool VideoCaptureImpl::SetApplyRotation(bool enable) { 307 MutexLock lock(&api_lock_); 308 apply_rotation_ = enable; 309 return true; 310 } 311 312 bool VideoCaptureImpl::GetApplyRotation() { 313 MutexLock lock(&api_lock_); 314 return apply_rotation_; 315 } 316 317 void VideoCaptureImpl::UpdateFrameCount() { 318 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 319 320 if (_incomingFrameTimesNanos[0] / kNumNanosecsPerMicrosec == 0) { 321 // first no shift 322 } else { 323 // shift 324 for (int i = (kFrameRateCountHistorySize - 2); i >= 0; --i) { 325 _incomingFrameTimesNanos[i + 1] = _incomingFrameTimesNanos[i]; 326 } 327 } 328 _incomingFrameTimesNanos[0] = clock_->TimeInMicroseconds() * 1000; 329 } 330 331 uint32_t VideoCaptureImpl::CalculateFrameRate(int64_t now_ns) { 332 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 333 334 int32_t num = 0; 335 int32_t nrOfFrames = 0; 336 for (num = 1; num < (kFrameRateCountHistorySize - 1); ++num) { 337 if (_incomingFrameTimesNanos[num] <= 0 || 338 (now_ns - _incomingFrameTimesNanos[num]) / kNumNanosecsPerMillisec > 339 kFrameRateHistoryWindowMs) { // don't use data older than 2sec 340 break; 341 } else { 342 nrOfFrames++; 343 } 344 } 345 if (num > 1) { 346 int64_t diff = 347 (now_ns - _incomingFrameTimesNanos[num - 1]) / kNumNanosecsPerMillisec; 348 if (diff > 0) { 349 return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f); 350 } 351 } 352 353 return nrOfFrames; 354 } 355 } // namespace videocapturemodule 356 } // namespace webrtc