| /* |
| * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "media/base/fake_video_capturer.h" |
| |
| #include <string.h> |
| #include <cstdint> |
| |
| #include "absl/memory/memory.h" |
| #include "api/scoped_refptr.h" |
| #include "api/video/i420_buffer.h" |
| #include "api/video/video_frame_buffer.h" |
| #include "rtc_base/arraysize.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/time_utils.h" |
| |
| namespace cricket { |
| |
| FakeVideoCapturer::FakeVideoCapturer(bool is_screencast) |
| : running_(false), |
| is_screencast_(is_screencast), |
| rotation_(webrtc::kVideoRotation_0) { |
| // Default supported formats. Use ResetSupportedFormats to over write. |
| using cricket::VideoFormat; |
| static const VideoFormat formats[] = { |
| {1280, 720, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, |
| {640, 480, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, |
| {320, 240, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, |
| {160, 120, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, |
| {1280, 720, VideoFormat::FpsToInterval(60), cricket::FOURCC_I420}, |
| }; |
| ResetSupportedFormats({&formats[0], &formats[arraysize(formats)]}); |
| } |
| |
| FakeVideoCapturer::FakeVideoCapturer() : FakeVideoCapturer(false) {} |
| |
| FakeVideoCapturer::~FakeVideoCapturer() { |
| SignalDestroyed(this); |
| } |
| |
| void FakeVideoCapturer::ResetSupportedFormats( |
| const std::vector<cricket::VideoFormat>& formats) { |
| SetSupportedFormats(formats); |
| } |
| |
| bool FakeVideoCapturer::CaptureFrame() { |
| if (!GetCaptureFormat()) { |
| return false; |
| } |
| RTC_CHECK_EQ(GetCaptureFormat()->fourcc, FOURCC_I420); |
| return CaptureFrame(frame_source_->GetFrame()); |
| } |
| |
| bool FakeVideoCapturer::CaptureCustomFrame(int width, int height) { |
| // Default to 30fps. |
| // TODO(nisse): Would anything break if we always stick to |
| // the configure frame interval? |
| return CaptureFrame(frame_source_->GetFrame(width, height, rotation_, |
| rtc::kNumMicrosecsPerSec / 30)); |
| } |
| |
| bool FakeVideoCapturer::CaptureFrame(const webrtc::VideoFrame& frame) { |
| if (!running_) { |
| return false; |
| } |
| |
| int adapted_width; |
| int adapted_height; |
| int crop_width; |
| int crop_height; |
| int crop_x; |
| int crop_y; |
| |
| // TODO(nisse): It's a bit silly to have this logic in a fake |
| // class. Child classes of VideoCapturer are expected to call |
| // AdaptFrame, and the test case |
| // VideoCapturerTest.SinkWantsMaxPixelAndMaxPixelCountStepUp |
| // depends on this. |
| if (AdaptFrame(frame.width(), frame.height(), frame.timestamp_us(), |
| frame.timestamp_us(), &adapted_width, &adapted_height, |
| &crop_width, &crop_height, &crop_x, &crop_y, nullptr)) { |
| rtc::scoped_refptr<webrtc::I420Buffer> buffer( |
| webrtc::I420Buffer::Create(adapted_width, adapted_height)); |
| buffer->InitializeData(); |
| |
| webrtc::VideoFrame adapted_frame = |
| webrtc::VideoFrame::Builder() |
| .set_video_frame_buffer(buffer) |
| .set_rotation(frame.rotation()) |
| .set_timestamp_us(frame.timestamp_us()) |
| .set_id(frame.id()) |
| .build(); |
| OnFrame(adapted_frame, frame.width(), frame.height()); |
| } |
| |
| return true; |
| } |
| |
| cricket::CaptureState FakeVideoCapturer::Start( |
| const cricket::VideoFormat& format) { |
| SetCaptureFormat(&format); |
| running_ = true; |
| SetCaptureState(cricket::CS_RUNNING); |
| frame_source_ = absl::make_unique<FakeFrameSource>( |
| format.width, format.height, |
| format.interval / rtc::kNumNanosecsPerMicrosec, rtc::TimeMicros()); |
| frame_source_->SetRotation(rotation_); |
| return cricket::CS_RUNNING; |
| } |
| |
| void FakeVideoCapturer::Stop() { |
| running_ = false; |
| SetCaptureFormat(NULL); |
| SetCaptureState(cricket::CS_STOPPED); |
| } |
| |
| bool FakeVideoCapturer::IsRunning() { |
| return running_; |
| } |
| |
| bool FakeVideoCapturer::IsScreencast() const { |
| return is_screencast_; |
| } |
| |
| bool FakeVideoCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) { |
| fourccs->push_back(cricket::FOURCC_I420); |
| fourccs->push_back(cricket::FOURCC_MJPG); |
| return true; |
| } |
| |
| void FakeVideoCapturer::SetRotation(webrtc::VideoRotation rotation) { |
| rotation_ = rotation; |
| if (frame_source_) |
| frame_source_->SetRotation(rotation_); |
| } |
| |
| webrtc::VideoRotation FakeVideoCapturer::GetRotation() { |
| return rotation_; |
| } |
| |
| FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue( |
| bool is_screencast) |
| : FakeVideoCapturer(is_screencast) {} |
| |
| FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue() {} |
| |
| bool FakeVideoCapturerWithTaskQueue::CaptureFrame() { |
| if (task_queue_.IsCurrent()) |
| return FakeVideoCapturer::CaptureFrame(); |
| bool ret = false; |
| task_queue_.SendTask( |
| [this, &ret]() { ret = FakeVideoCapturer::CaptureFrame(); }); |
| return ret; |
| } |
| |
| bool FakeVideoCapturerWithTaskQueue::CaptureCustomFrame(int width, int height) { |
| if (task_queue_.IsCurrent()) |
| return FakeVideoCapturer::CaptureCustomFrame(width, height); |
| bool ret = false; |
| task_queue_.SendTask([this, &ret, width, height]() { |
| ret = FakeVideoCapturer::CaptureCustomFrame(width, height); |
| }); |
| return ret; |
| } |
| |
| } // namespace cricket |