Delete obsolete class cricket::VideoCapturer

Bug: webrtc:6353
Change-Id: I220aca39319fd6562190f04bc97aa1fa9e523f31
Reviewed-on: https://webrtc-review.googlesource.com/c/119221
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26612}
This commit is contained in:
Niels Möller
2019-02-07 16:42:55 +01:00
committed by Commit Bot
parent 494ff28573
commit 9f3aabb5ad
8 changed files with 0 additions and 1721 deletions

View File

@ -120,7 +120,6 @@ specific_include_rules = {
"peer_connection_interface\.h": [ "peer_connection_interface\.h": [
"+logging/rtc_event_log/rtc_event_log_factory_interface.h", "+logging/rtc_event_log/rtc_event_log_factory_interface.h",
"+media/base/media_config.h", "+media/base/media_config.h",
"+media/base/video_capturer.h",
"+media/base/media_engine.h", "+media/base/media_engine.h",
"+p2p/base/port_allocator.h", "+p2p/base/port_allocator.h",
"+rtc_base/bitrate_allocation_strategy.h", "+rtc_base/bitrate_allocation_strategy.h",

View File

@ -108,8 +108,6 @@ rtc_static_library("rtc_media_base") {
"base/video_adapter.h", "base/video_adapter.h",
"base/video_broadcaster.cc", "base/video_broadcaster.cc",
"base/video_broadcaster.h", "base/video_broadcaster.h",
"base/video_capturer.cc",
"base/video_capturer.h",
"base/video_common.cc", "base/video_common.cc",
"base/video_common.h", "base/video_common.h",
"base/video_source_base.cc", "base/video_source_base.cc",
@ -464,8 +462,6 @@ if (rtc_include_tests) {
"base/fake_network_interface.h", "base/fake_network_interface.h",
"base/fake_rtp.cc", "base/fake_rtp.cc",
"base/fake_rtp.h", "base/fake_rtp.h",
"base/fake_video_capturer.cc",
"base/fake_video_capturer.h",
"base/fake_video_renderer.cc", "base/fake_video_renderer.cc",
"base/fake_video_renderer.h", "base/fake_video_renderer.h",
"base/test_utils.cc", "base/test_utils.cc",
@ -559,7 +555,6 @@ if (rtc_include_tests) {
"base/turn_utils_unittest.cc", "base/turn_utils_unittest.cc",
"base/video_adapter_unittest.cc", "base/video_adapter_unittest.cc",
"base/video_broadcaster_unittest.cc", "base/video_broadcaster_unittest.cc",
"base/video_capturer_unittest.cc",
"base/video_common_unittest.cc", "base/video_common_unittest.cc",
"engine/apm_helpers_unittest.cc", "engine/apm_helpers_unittest.cc",
"engine/encoder_simulcast_proxy_unittest.cc", "engine/encoder_simulcast_proxy_unittest.cc",

View File

@ -1,173 +0,0 @@
/*
* 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

View File

@ -1,80 +0,0 @@
/*
* Copyright (c) 2004 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.
*/
#ifndef MEDIA_BASE_FAKE_VIDEO_CAPTURER_H_
#define MEDIA_BASE_FAKE_VIDEO_CAPTURER_H_
#include <string.h>
#include <memory>
#include <vector>
#include "api/video/i420_buffer.h"
#include "api/video/video_frame.h"
#include "media/base/fake_frame_source.h"
#include "media/base/video_capturer.h"
#include "media/base/video_common.h"
#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/time_utils.h"
namespace cricket {
// Fake video capturer that allows the test to manually pump in frames.
class FakeVideoCapturer : public cricket::VideoCapturer {
public:
explicit FakeVideoCapturer(bool is_screencast);
FakeVideoCapturer();
~FakeVideoCapturer() override;
void ResetSupportedFormats(const std::vector<cricket::VideoFormat>& formats);
virtual bool CaptureFrame();
virtual bool CaptureCustomFrame(int width, int height);
sigslot::signal1<FakeVideoCapturer*> SignalDestroyed;
cricket::CaptureState Start(const cricket::VideoFormat& format) override;
void Stop() override;
bool IsRunning() override;
bool IsScreencast() const override;
bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) override;
void SetRotation(webrtc::VideoRotation rotation);
webrtc::VideoRotation GetRotation();
private:
bool CaptureFrame(const webrtc::VideoFrame& frame);
bool running_;
const bool is_screencast_;
// Duplicates FakeFrameSource::rotation_, but needed to support
// SetRotation before Start.
webrtc::VideoRotation rotation_;
std::unique_ptr<FakeFrameSource> frame_source_;
};
// Inherits from FakeVideoCapturer but adds a TaskQueue so that frames can be
// delivered on a TaskQueue as expected by VideoSinkInterface implementations.
class FakeVideoCapturerWithTaskQueue : public FakeVideoCapturer {
public:
explicit FakeVideoCapturerWithTaskQueue(bool is_screencast);
FakeVideoCapturerWithTaskQueue();
bool CaptureFrame() override;
bool CaptureCustomFrame(int width, int height) override;
protected:
rtc::test::TaskQueueForTest task_queue_{"FakeVideoCapturerWithTaskQueue"};
};
} // namespace cricket
#endif // MEDIA_BASE_FAKE_VIDEO_CAPTURER_H_

View File

@ -1,393 +0,0 @@
/*
* Copyright (c) 2010 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.
*/
// Implementation file of class VideoCapturer.
#include "media/base/video_capturer.h"
#include <cstdint>
#include "api/scoped_refptr.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame.h"
#include "api/video/video_frame_buffer.h"
#include "api/video/video_rotation.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/time_utils.h"
namespace cricket {
namespace {
static const int64_t kMaxDistance = ~(static_cast<int64_t>(1) << 63);
#ifdef WEBRTC_LINUX
static const int kYU12Penalty = 16; // Needs to be higher than MJPG index.
#endif
} // namespace
/////////////////////////////////////////////////////////////////////
// Implementation of class VideoCapturer
/////////////////////////////////////////////////////////////////////
VideoCapturer::VideoCapturer() : apply_rotation_(false) {
thread_checker_.DetachFromThread();
Construct();
}
VideoCapturer::~VideoCapturer() {}
void VideoCapturer::Construct() {
enable_camera_list_ = false;
capture_state_ = CS_STOPPED;
scaled_width_ = 0;
scaled_height_ = 0;
enable_video_adapter_ = true;
}
const std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
return &filtered_supported_formats_;
}
bool VideoCapturer::StartCapturing(const VideoFormat& capture_format) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
CaptureState result = Start(capture_format);
const bool success = (result == CS_RUNNING) || (result == CS_STARTING);
if (!success) {
return false;
}
if (result == CS_RUNNING) {
SetCaptureState(result);
}
return true;
}
bool VideoCapturer::apply_rotation() {
return apply_rotation_;
}
void VideoCapturer::SetSupportedFormats(
const std::vector<VideoFormat>& formats) {
// This method is OK to call during initialization on a separate thread.
RTC_DCHECK(capture_state_ == CS_STOPPED ||
thread_checker_.CalledOnValidThread());
supported_formats_ = formats;
UpdateFilteredSupportedFormats();
}
bool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format,
VideoFormat* best_format) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
// TODO(fbarchard): Directly support max_format.
UpdateFilteredSupportedFormats();
const std::vector<VideoFormat>* supported_formats = GetSupportedFormats();
if (supported_formats->empty()) {
return false;
}
RTC_LOG(LS_INFO) << " Capture Requested " << format.ToString();
int64_t best_distance = kMaxDistance;
std::vector<VideoFormat>::const_iterator best = supported_formats->end();
std::vector<VideoFormat>::const_iterator i;
for (i = supported_formats->begin(); i != supported_formats->end(); ++i) {
int64_t distance = GetFormatDistance(format, *i);
// TODO(fbarchard): Reduce to LS_VERBOSE if/when camera capture is
// relatively bug free.
RTC_LOG(LS_INFO) << " Supported " << i->ToString() << " distance "
<< distance;
if (distance < best_distance) {
best_distance = distance;
best = i;
}
}
if (supported_formats->end() == best) {
RTC_LOG(LS_ERROR) << " No acceptable camera format found";
return false;
}
if (best_format) {
best_format->width = best->width;
best_format->height = best->height;
best_format->fourcc = best->fourcc;
best_format->interval = best->interval;
RTC_LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval "
<< best_format->interval << " distance " << best_distance;
}
return true;
}
void VideoCapturer::ConstrainSupportedFormats(const VideoFormat& max_format) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
max_format_.reset(new VideoFormat(max_format));
RTC_LOG(LS_VERBOSE) << " ConstrainSupportedFormats " << max_format.ToString();
UpdateFilteredSupportedFormats();
}
bool VideoCapturer::GetInputSize(int* width, int* height) {
rtc::CritScope cs(&frame_stats_crit_);
if (!input_size_valid_) {
return false;
}
*width = input_width_;
*height = input_height_;
return true;
}
void VideoCapturer::RemoveSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
broadcaster_.RemoveSink(sink);
OnSinkWantsChanged(broadcaster_.wants());
}
void VideoCapturer::AddOrUpdateSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
broadcaster_.AddOrUpdateSink(sink, wants);
OnSinkWantsChanged(broadcaster_.wants());
}
void VideoCapturer::OnSinkWantsChanged(const rtc::VideoSinkWants& wants) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
apply_rotation_ = wants.rotation_applied;
if (video_adapter()) {
video_adapter()->OnResolutionFramerateRequest(wants.target_pixel_count,
wants.max_pixel_count,
wants.max_framerate_fps);
}
}
bool VideoCapturer::AdaptFrame(int width,
int height,
int64_t camera_time_us,
int64_t system_time_us,
int* out_width,
int* out_height,
int* crop_width,
int* crop_height,
int* crop_x,
int* crop_y,
int64_t* translated_camera_time_us) {
if (translated_camera_time_us) {
*translated_camera_time_us =
timestamp_aligner_.TranslateTimestamp(camera_time_us, system_time_us);
}
if (!broadcaster_.frame_wanted()) {
return false;
}
if (enable_video_adapter_) {
if (!video_adapter_.AdaptFrameResolution(
width, height, camera_time_us * rtc::kNumNanosecsPerMicrosec,
crop_width, crop_height, out_width, out_height)) {
// VideoAdapter dropped the frame.
broadcaster_.OnDiscardedFrame();
return false;
}
*crop_x = (width - *crop_width) / 2;
*crop_y = (height - *crop_height) / 2;
} else {
*out_width = width;
*out_height = height;
*crop_width = width;
*crop_height = height;
*crop_x = 0;
*crop_y = 0;
}
return true;
}
void VideoCapturer::OnFrame(const webrtc::VideoFrame& frame,
int orig_width,
int orig_height) {
// For a child class which implements rotation itself, we should
// always have apply_rotation_ == false or frame.rotation() == 0.
// Except possibly during races where apply_rotation_ is changed
// mid-stream.
if (apply_rotation_ && frame.rotation() != webrtc::kVideoRotation_0) {
rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
frame.video_frame_buffer());
if (buffer->type() != webrtc::VideoFrameBuffer::Type::kI420) {
// Sources producing non-I420 frames must handle apply_rotation
// themselves. But even if they do, we may occasionally end up
// in this case, for frames in flight at the time
// applied_rotation is set to true. In that case, we just drop
// the frame.
RTC_LOG(LS_WARNING) << "Non-I420 frame requiring rotation. Discarding.";
return;
}
webrtc::VideoFrame rotated_frame =
webrtc::VideoFrame::Builder()
.set_video_frame_buffer(webrtc::I420Buffer::Rotate(
*buffer->GetI420(), frame.rotation()))
.set_rotation(webrtc::kVideoRotation_0)
.set_timestamp_us(frame.timestamp_us())
.set_id(frame.id())
.build();
broadcaster_.OnFrame(rotated_frame);
} else {
broadcaster_.OnFrame(frame);
}
UpdateInputSize(orig_width, orig_height);
}
void VideoCapturer::SetCaptureState(CaptureState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
if (state == capture_state_) {
// Don't trigger a state changed callback if the state hasn't changed.
return;
}
capture_state_ = state;
SignalStateChange(this, capture_state_);
}
// Get the distance between the supported and desired formats.
// Prioritization is done according to this algorithm:
// 1) Width closeness. If not same, we prefer wider.
// 2) Height closeness. If not same, we prefer higher.
// 3) Framerate closeness. If not same, we prefer faster.
// 4) Compression. If desired format has a specific fourcc, we need exact match;
// otherwise, we use preference.
int64_t VideoCapturer::GetFormatDistance(const VideoFormat& desired,
const VideoFormat& supported) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
int64_t distance = kMaxDistance;
// Check fourcc.
uint32_t supported_fourcc = CanonicalFourCC(supported.fourcc);
int64_t delta_fourcc = kMaxDistance;
if (FOURCC_ANY == desired.fourcc) {
// Any fourcc is OK for the desired. Use preference to find best fourcc.
std::vector<uint32_t> preferred_fourccs;
if (!GetPreferredFourccs(&preferred_fourccs)) {
return distance;
}
for (size_t i = 0; i < preferred_fourccs.size(); ++i) {
if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) {
delta_fourcc = i;
#ifdef WEBRTC_LINUX
// For HD avoid YU12 which is a software conversion and has 2 bugs
// b/7326348 b/6960899. Reenable when fixed.
if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 ||
supported_fourcc == FOURCC_YV12)) {
delta_fourcc += kYU12Penalty;
}
#endif
break;
}
}
} else if (supported_fourcc == CanonicalFourCC(desired.fourcc)) {
delta_fourcc = 0; // Need exact match.
}
if (kMaxDistance == delta_fourcc) {
// Failed to match fourcc.
return distance;
}
// Check resolution and fps.
int desired_width = desired.width;
int desired_height = desired.height;
int64_t delta_w = supported.width - desired_width;
float supported_fps = VideoFormat::IntervalToFpsFloat(supported.interval);
float delta_fps =
supported_fps - VideoFormat::IntervalToFpsFloat(desired.interval);
// Check height of supported height compared to height we would like it to be.
int64_t aspect_h = desired_width
? supported.width * desired_height / desired_width
: desired_height;
int64_t delta_h = supported.height - aspect_h;
distance = 0;
// Set high penalty if the supported format is lower than the desired format.
// 3x means we would prefer down to down to 3/4, than up to double.
// But we'd prefer up to double than down to 1/2. This is conservative,
// strongly avoiding going down in resolution, similar to
// the old method, but not completely ruling it out in extreme situations.
// It also ignores framerate, which is often very low at high resolutions.
// TODO(fbarchard): Improve logic to use weighted factors.
static const int kDownPenalty = -3;
if (delta_w < 0) {
delta_w = delta_w * kDownPenalty;
}
if (delta_h < 0) {
delta_h = delta_h * kDownPenalty;
}
// Require camera fps to be at least 80% of what is requested if resolution
// matches.
// Require camera fps to be at least 96% of what is requested, or higher,
// if resolution differs. 96% allows for slight variations in fps. e.g. 29.97
if (delta_fps < 0) {
float min_desirable_fps =
delta_w
? VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f
: VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f;
delta_fps = -delta_fps;
if (supported_fps < min_desirable_fps) {
distance |= static_cast<int64_t>(1) << 62;
} else {
distance |= static_cast<int64_t>(1) << 15;
}
}
int64_t idelta_fps = static_cast<int>(delta_fps);
// 12 bits for width and height and 8 bits for fps and fourcc.
distance |=
(delta_w << 28) | (delta_h << 16) | (idelta_fps << 8) | delta_fourcc;
return distance;
}
void VideoCapturer::UpdateFilteredSupportedFormats() {
filtered_supported_formats_.clear();
filtered_supported_formats_ = supported_formats_;
if (!max_format_) {
return;
}
std::vector<VideoFormat>::iterator iter = filtered_supported_formats_.begin();
while (iter != filtered_supported_formats_.end()) {
if (ShouldFilterFormat(*iter)) {
iter = filtered_supported_formats_.erase(iter);
} else {
++iter;
}
}
if (filtered_supported_formats_.empty()) {
// The device only captures at resolutions higher than |max_format_| this
// indicates that |max_format_| should be ignored as it is better to capture
// at too high a resolution than to not capture at all.
filtered_supported_formats_ = supported_formats_;
}
}
bool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
if (!enable_camera_list_) {
return false;
}
return format.width > max_format_->width ||
format.height > max_format_->height;
}
void VideoCapturer::UpdateInputSize(int width, int height) {
// Update stats protected from fetches from different thread.
rtc::CritScope cs(&frame_stats_crit_);
input_size_valid_ = true;
input_width_ = width;
input_height_ = height;
}
} // namespace cricket

View File

@ -1,283 +0,0 @@
/*
* Copyright (c) 2010 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.
*/
// Declaration of abstract class VideoCapturer
#ifndef MEDIA_BASE_VIDEO_CAPTURER_H_
#define MEDIA_BASE_VIDEO_CAPTURER_H_
#include <stdint.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "api/video/video_source_interface.h"
#include "media/base/video_adapter.h"
#include "media/base/video_broadcaster.h"
#include "media/base/video_common.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread_checker.h"
#include "rtc_base/timestamp_aligner.h"
namespace webrtc {
class VideoFrame;
}
namespace cricket {
// Current state of the capturer.
enum CaptureState {
CS_STOPPED, // The capturer has been stopped or hasn't started yet.
CS_STARTING, // The capturer is in the process of starting. Note, it may
// still fail to start.
CS_RUNNING, // The capturer has been started successfully and is now
// capturing.
CS_FAILED, // The capturer failed to start.
};
// VideoCapturer is an abstract class that defines the interfaces for video
// capturing. The subclasses implement the video capturer for various types of
// capturers and various platforms.
//
// The captured frames may need to be adapted (for example, cropping).
// Video adaptation is built into and enabled by default. After a frame has
// been captured from the device, it is sent to the video adapter, then out to
// the sinks.
//
// Programming model:
// Create an object of a subclass of VideoCapturer
// Initialize
// SignalStateChange.connect()
// AddOrUpdateSink()
// Find the capture format for Start() by either calling GetSupportedFormats()
// and selecting one of the supported or calling GetBestCaptureFormat().
// video_adapter()->OnOutputFormatRequest(desired_encoding_format)
// Start()
// GetCaptureFormat() optionally
// Stop()
//
// Assumption:
// The Start() and Stop() methods are called by a single thread (E.g., the
// media engine thread). Hence, the VideoCapture subclasses dont need to be
// thread safe.
//
class RTC_EXPORT VideoCapturer
: public sigslot::has_slots<>,
public rtc::VideoSourceInterface<webrtc::VideoFrame> {
public:
VideoCapturer();
~VideoCapturer() override;
// Gets the id of the underlying device, which is available after the capturer
// is initialized. Can be used to determine if two capturers reference the
// same device.
const std::string& GetId() const { return id_; }
// Get the capture formats supported by the video capturer. The supported
// formats are non empty after the device has been opened successfully.
const std::vector<VideoFormat>* GetSupportedFormats() const;
// Get the best capture format for the desired format. The best format is the
// same as one of the supported formats except that the frame interval may be
// different. If the application asks for 16x9 and the camera does not support
// 16x9 HD or the application asks for 16x10, we find the closest 4x3 and then
// crop; Otherwise, we find what the application asks for. Note that we assume
// that for HD, the desired format is always 16x9. The subclasses can override
// the default implementation.
// Parameters
// desired: the input desired format. If desired.fourcc is not kAnyFourcc,
// the best capture format has the exactly same fourcc. Otherwise,
// the best capture format uses a fourcc in GetPreferredFourccs().
// best_format: the output of the best capture format.
// Return false if there is no such a best format, that is, the desired format
// is not supported.
virtual bool GetBestCaptureFormat(const VideoFormat& desired,
VideoFormat* best_format);
// TODO(hellner): deprecate (make private) the Start API in favor of this one.
// Also remove CS_STARTING as it is implied by the return
// value of StartCapturing().
bool StartCapturing(const VideoFormat& capture_format);
// Start the video capturer with the specified capture format.
// Parameter
// capture_format: The caller got this parameter by either calling
// GetSupportedFormats() and selecting one of the supported
// or calling GetBestCaptureFormat().
// Return
// CS_STARTING: The capturer is trying to start. Success or failure will
// be notified via the |SignalStateChange| callback.
// CS_RUNNING: if the capturer is started and capturing.
// CS_FAILED: if the capturer failes to start..
// CS_NO_DEVICE: if the capturer has no device and fails to start.
virtual CaptureState Start(const VideoFormat& capture_format) = 0;
// Get the current capture format, which is set by the Start() call.
// Note that the width and height of the captured frames may differ from the
// capture format. For example, the capture format is HD but the captured
// frames may be smaller than HD.
const VideoFormat* GetCaptureFormat() const { return capture_format_.get(); }
// Stop the video capturer.
virtual void Stop() = 0;
// Check if the video capturer is running.
virtual bool IsRunning() = 0;
CaptureState capture_state() const { return capture_state_; }
virtual bool apply_rotation();
// Returns true if the capturer is screencasting. This can be used to
// implement screencast specific behavior.
virtual bool IsScreencast() const = 0;
// Caps the VideoCapturer's format according to max_format. It can e.g. be
// used to prevent cameras from capturing at a resolution or framerate that
// the capturer is capable of but not performing satisfactorily at.
// The capping is an upper bound for each component of the capturing format.
// The fourcc component is ignored.
void ConstrainSupportedFormats(const VideoFormat& max_format);
void set_enable_camera_list(bool enable_camera_list) {
enable_camera_list_ = enable_camera_list;
}
bool enable_camera_list() { return enable_camera_list_; }
// Signal all capture state changes that are not a direct result of calling
// Start().
sigslot::signal2<VideoCapturer*, CaptureState> SignalStateChange;
// If true, run video adaptation. By default, video adaptation is enabled
// and users must call video_adapter()->OnOutputFormatRequest()
// to receive frames.
bool enable_video_adapter() const { return enable_video_adapter_; }
void set_enable_video_adapter(bool enable_video_adapter) {
enable_video_adapter_ = enable_video_adapter;
}
bool GetInputSize(int* width, int* height);
// Implements VideoSourceInterface
void AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink,
const rtc::VideoSinkWants& wants) override;
void RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) override;
protected:
// OnSinkWantsChanged can be overridden to change the default behavior
// when a sink changes its VideoSinkWants by calling AddOrUpdateSink.
virtual void OnSinkWantsChanged(const rtc::VideoSinkWants& wants);
// Reports the appropriate frame size after adaptation. Returns true
// if a frame is wanted. Returns false if there are no interested
// sinks, or if the VideoAdapter decides to drop the frame.
// This function also implements timestamp translation/filtering.
// |camera_time_ns| is the camera's timestamp for the captured
// frame; it is expected to have good accuracy, but it may use an
// arbitrary epoch and a small possibly free-running with a frequency
// slightly different from the system clock. |system_time_us| is the
// monotonic system time (in the same scale as rtc::TimeMicros) when
// the frame was captured; the application is expected to read the
// system time as soon as possible after frame capture, but it may
// suffer scheduling jitter or poor system clock resolution. The
// output |translated_camera_time_us| is a combined timestamp,
// taking advantage of the supposedly higher accuracy in the camera
// timestamp, but using the same epoch and frequency as system time.
bool AdaptFrame(int width,
int height,
int64_t camera_time_us,
int64_t system_time_us,
int* out_width,
int* out_height,
int* crop_width,
int* crop_height,
int* crop_x,
int* crop_y,
int64_t* translated_camera_time_us);
// Called when a frame has been captured and converted to a
// VideoFrame. OnFrame can be called directly by an implementation
// that does not use SignalFrameCaptured or OnFrameCaptured. The
// orig_width and orig_height are used only to produce stats.
void OnFrame(const webrtc::VideoFrame& frame,
int orig_width,
int orig_height);
VideoAdapter* video_adapter() { return &video_adapter_; }
void SetCaptureState(CaptureState state);
// subclasses override this virtual method to provide a vector of fourccs, in
// order of preference, that are expected by the media engine.
virtual bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) = 0;
// mutators to set private attributes
void SetId(const std::string& id) { id_ = id; }
void SetCaptureFormat(const VideoFormat* format) {
capture_format_.reset(format ? new VideoFormat(*format) : NULL);
}
void SetSupportedFormats(const std::vector<VideoFormat>& formats);
private:
void Construct();
// Get the distance between the desired format and the supported format.
// Return the max distance if they mismatch. See the implementation for
// details.
int64_t GetFormatDistance(const VideoFormat& desired,
const VideoFormat& supported);
// Updates filtered_supported_formats_ so that it contains the formats in
// supported_formats_ that fulfill all applied restrictions.
void UpdateFilteredSupportedFormats();
// Returns true if format doesn't fulfill all applied restrictions.
bool ShouldFilterFormat(const VideoFormat& format) const;
void UpdateInputSize(int width, int height);
rtc::ThreadChecker thread_checker_;
std::string id_;
CaptureState capture_state_;
std::unique_ptr<VideoFormat> capture_format_;
std::vector<VideoFormat> supported_formats_;
std::unique_ptr<VideoFormat> max_format_;
std::vector<VideoFormat> filtered_supported_formats_;
bool enable_camera_list_;
int scaled_width_; // Current output size from ComputeScale.
int scaled_height_;
rtc::VideoBroadcaster broadcaster_;
bool enable_video_adapter_;
VideoAdapter video_adapter_;
rtc::CriticalSection frame_stats_crit_;
// The captured frame size before potential adapation.
bool input_size_valid_ RTC_GUARDED_BY(frame_stats_crit_) = false;
int input_width_ RTC_GUARDED_BY(frame_stats_crit_);
int input_height_ RTC_GUARDED_BY(frame_stats_crit_);
// Whether capturer should apply rotation to the frame before
// passing it on to the registered sinks.
bool apply_rotation_;
// State for the timestamp translation.
rtc::TimestampAligner timestamp_aligner_;
RTC_DISALLOW_COPY_AND_ASSIGN(VideoCapturer);
};
} // namespace cricket
#endif // MEDIA_BASE_VIDEO_CAPTURER_H_

View File

@ -1,785 +0,0 @@
/*
* Copyright (c) 2008 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 <stdio.h>
#include <memory>
#include <vector>
#include "absl/types/optional.h"
#include "api/video/video_rotation.h"
#include "media/base/fake_video_capturer.h"
#include "media/base/fake_video_renderer.h"
#include "media/base/video_capturer.h"
#include "rtc_base/gunit.h"
#include "rtc_base/thread.h"
#include "test/gtest.h"
using cricket::FakeVideoCapturerWithTaskQueue;
namespace {
const int kMsCallbackWait = 500;
// For HD only the height matters.
const int kMinHdHeight = 720;
} // namespace
class VideoCapturerTest : public sigslot::has_slots<>, public testing::Test {
public:
VideoCapturerTest()
: capture_state_(cricket::CS_STOPPED), num_state_changes_(0) {
InitCapturer(false);
}
protected:
void InitCapturer(bool is_screencast) {
capturer_ = std::unique_ptr<FakeVideoCapturerWithTaskQueue>(
new FakeVideoCapturerWithTaskQueue(is_screencast));
capturer_->SignalStateChange.connect(this,
&VideoCapturerTest::OnStateChange);
capturer_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants());
}
void InitScreencast() { InitCapturer(true); }
void OnStateChange(cricket::VideoCapturer*,
cricket::CaptureState capture_state) {
capture_state_ = capture_state;
++num_state_changes_;
}
cricket::CaptureState capture_state() { return capture_state_; }
int num_state_changes() { return num_state_changes_; }
std::unique_ptr<FakeVideoCapturerWithTaskQueue> capturer_;
cricket::CaptureState capture_state_;
int num_state_changes_;
cricket::FakeVideoRenderer renderer_;
bool expects_rotation_applied_;
};
TEST_F(VideoCapturerTest, CaptureState) {
EXPECT_TRUE(capturer_->enable_video_adapter());
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
EXPECT_EQ(1, num_state_changes());
capturer_->Stop();
EXPECT_EQ_WAIT(cricket::CS_STOPPED, capture_state(), kMsCallbackWait);
EXPECT_EQ(2, num_state_changes());
capturer_->Stop();
rtc::Thread::Current()->ProcessMessages(100);
EXPECT_EQ(2, num_state_changes());
}
TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) {
InitScreencast();
int kWidth = 1281;
int kHeight = 720;
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(kWidth, kHeight,
cricket::VideoFormat::FpsToInterval(5),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(formats);
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
kWidth, kHeight, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ(0, renderer_.num_rendered_frames());
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(1, renderer_.num_rendered_frames());
EXPECT_EQ(kWidth, renderer_.width());
EXPECT_EQ(kHeight, renderer_.height());
}
TEST_F(VideoCapturerTest, TestRotationAppliedBySource) {
int kWidth = 800;
int kHeight = 400;
int frame_count = 0;
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(kWidth, kHeight,
cricket::VideoFormat::FpsToInterval(5),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(formats);
rtc::VideoSinkWants wants;
// |capturer_| should compensate rotation.
wants.rotation_applied = true;
capturer_->AddOrUpdateSink(&renderer_, wants);
// capturer_ should compensate rotation as default.
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
kWidth, kHeight, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ(0, renderer_.num_rendered_frames());
// If the frame's rotation is compensated anywhere in the pipeline based on
// the rotation information, the renderer should be given the right dimension
// such that the frame could be rendered.
capturer_->SetRotation(webrtc::kVideoRotation_90);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
// Swapped width and height
EXPECT_EQ(kWidth, renderer_.height());
EXPECT_EQ(kHeight, renderer_.width());
EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation());
capturer_->SetRotation(webrtc::kVideoRotation_270);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
// Swapped width and height
EXPECT_EQ(kWidth, renderer_.height());
EXPECT_EQ(kHeight, renderer_.width());
EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation());
capturer_->SetRotation(webrtc::kVideoRotation_180);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
// Back to normal width and height
EXPECT_EQ(kWidth, renderer_.width());
EXPECT_EQ(kHeight, renderer_.height());
EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation());
}
TEST_F(VideoCapturerTest, TestRotationAppliedBySinkByDefault) {
int kWidth = 800;
int kHeight = 400;
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(kWidth, kHeight,
cricket::VideoFormat::FpsToInterval(5),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(formats);
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
kWidth, kHeight, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ(0, renderer_.num_rendered_frames());
// If the frame's rotation is compensated anywhere in the pipeline, the frame
// won't have its original dimension out from capturer. Since the renderer
// here has the same dimension as the capturer, it will skip that frame as the
// resolution won't match anymore.
int frame_count = 0;
capturer_->SetRotation(webrtc::kVideoRotation_0);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(capturer_->GetRotation(), renderer_.rotation());
capturer_->SetRotation(webrtc::kVideoRotation_90);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(capturer_->GetRotation(), renderer_.rotation());
capturer_->SetRotation(webrtc::kVideoRotation_180);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(capturer_->GetRotation(), renderer_.rotation());
capturer_->SetRotation(webrtc::kVideoRotation_270);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(capturer_->GetRotation(), renderer_.rotation());
}
TEST_F(VideoCapturerTest, TestRotationAppliedBySourceWhenDifferentWants) {
int kWidth = 800;
int kHeight = 400;
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(kWidth, kHeight,
cricket::VideoFormat::FpsToInterval(5),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(formats);
rtc::VideoSinkWants wants;
// capturer_ should not compensate rotation.
wants.rotation_applied = false;
capturer_->AddOrUpdateSink(&renderer_, wants);
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
kWidth, kHeight, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ(0, renderer_.num_rendered_frames());
int frame_count = 0;
capturer_->SetRotation(webrtc::kVideoRotation_90);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(capturer_->GetRotation(), renderer_.rotation());
// Add another sink that wants frames to be rotated.
cricket::FakeVideoRenderer renderer2;
wants.rotation_applied = true;
capturer_->AddOrUpdateSink(&renderer2, wants);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(++frame_count, renderer_.num_rendered_frames());
EXPECT_EQ(1, renderer2.num_rendered_frames());
EXPECT_EQ(webrtc::kVideoRotation_0, renderer_.rotation());
EXPECT_EQ(webrtc::kVideoRotation_0, renderer2.rotation());
}
// TODO(nisse): This test doesn't quite fit here. It tests two things:
// Aggregation of VideoSinkWants, which is the responsibility of
// VideoBroadcaster, and translation of VideoSinkWants to actual
// resolution, which is the responsibility of the VideoAdapter.
TEST_F(VideoCapturerTest, SinkWantsMaxPixelAndMaxPixelCountStepUp) {
EXPECT_EQ(cricket::CS_RUNNING,
capturer_->Start(cricket::VideoFormat(
1280, 720, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420)));
EXPECT_TRUE(capturer_->IsRunning());
EXPECT_EQ(0, renderer_.num_rendered_frames());
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(1, renderer_.num_rendered_frames());
EXPECT_EQ(1280, renderer_.width());
EXPECT_EQ(720, renderer_.height());
// Request a lower resolution. The output resolution will have a resolution
// with less than or equal to |wants.max_pixel_count| depending on how the
// capturer can scale the input frame size.
rtc::VideoSinkWants wants;
wants.max_pixel_count = 1280 * 720 * 3 / 5;
capturer_->AddOrUpdateSink(&renderer_, wants);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(2, renderer_.num_rendered_frames());
EXPECT_EQ(960, renderer_.width());
EXPECT_EQ(540, renderer_.height());
// Request a lower resolution.
wants.max_pixel_count = (renderer_.width() * renderer_.height() * 3) / 5;
capturer_->AddOrUpdateSink(&renderer_, wants);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(3, renderer_.num_rendered_frames());
EXPECT_EQ(640, renderer_.width());
EXPECT_EQ(360, renderer_.height());
// Adding a new renderer should not affect resolution.
cricket::FakeVideoRenderer renderer2;
capturer_->AddOrUpdateSink(&renderer2, rtc::VideoSinkWants());
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(4, renderer_.num_rendered_frames());
EXPECT_EQ(640, renderer_.width());
EXPECT_EQ(360, renderer_.height());
EXPECT_EQ(1, renderer2.num_rendered_frames());
EXPECT_EQ(640, renderer2.width());
EXPECT_EQ(360, renderer2.height());
// Request higher resolution.
wants.target_pixel_count.emplace((wants.max_pixel_count * 5) / 3);
wants.max_pixel_count = wants.max_pixel_count * 4;
capturer_->AddOrUpdateSink(&renderer_, wants);
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(5, renderer_.num_rendered_frames());
EXPECT_EQ(960, renderer_.width());
EXPECT_EQ(540, renderer_.height());
EXPECT_EQ(2, renderer2.num_rendered_frames());
EXPECT_EQ(960, renderer2.width());
EXPECT_EQ(540, renderer2.height());
// Updating with no wants should not affect resolution.
capturer_->AddOrUpdateSink(&renderer2, rtc::VideoSinkWants());
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(6, renderer_.num_rendered_frames());
EXPECT_EQ(960, renderer_.width());
EXPECT_EQ(540, renderer_.height());
EXPECT_EQ(3, renderer2.num_rendered_frames());
EXPECT_EQ(960, renderer2.width());
EXPECT_EQ(540, renderer2.height());
// But resetting the wants should reset the resolution to what the camera is
// opened with.
capturer_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants());
EXPECT_TRUE(capturer_->CaptureFrame());
EXPECT_EQ(7, renderer_.num_rendered_frames());
EXPECT_EQ(1280, renderer_.width());
EXPECT_EQ(720, renderer_.height());
EXPECT_EQ(4, renderer2.num_rendered_frames());
EXPECT_EQ(1280, renderer2.width());
EXPECT_EQ(720, renderer2.height());
}
TEST_F(VideoCapturerTest, TestFourccMatch) {
cricket::VideoFormat desired(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY);
cricket::VideoFormat best;
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.fourcc = cricket::FOURCC_MJPG;
EXPECT_FALSE(capturer_->GetBestCaptureFormat(desired, &best));
desired.fourcc = cricket::FOURCC_I420;
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
}
TEST_F(VideoCapturerTest, TestResolutionMatch) {
cricket::VideoFormat desired(
1920, 1080, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY);
cricket::VideoFormat best;
// Ask for 1920x1080. Get HD 1280x720 which is the highest.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(1280, best.width);
EXPECT_EQ(720, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 360;
desired.height = 250;
// Ask for a little higher than QVGA. Get QVGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 480;
desired.height = 270;
// Ask for HVGA. Get VGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 320;
desired.height = 240;
// Ask for QVGA. Get QVGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 80;
desired.height = 60;
// Ask for lower than QQVGA. Get QQVGA, which is the lowest.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(160, best.width);
EXPECT_EQ(120, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
}
TEST_F(VideoCapturerTest, TestHDResolutionMatch) {
// Add some HD formats typical of a mediocre HD webcam.
std::vector<cricket::VideoFormat> formats;
formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(
960, 544, cricket::VideoFormat::FpsToInterval(24), cricket::FOURCC_I420));
formats.push_back(
cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(15),
cricket::FOURCC_I420));
formats.push_back(cricket::VideoFormat(2592, 1944,
cricket::VideoFormat::FpsToInterval(7),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(formats);
cricket::VideoFormat desired(
960, 720, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY);
cricket::VideoFormat best;
// Ask for 960x720 30 fps. Get qHD 24 fps
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(960, best.width);
EXPECT_EQ(544, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(24), best.interval);
desired.width = 960;
desired.height = 544;
desired.interval = cricket::VideoFormat::FpsToInterval(30);
// Ask for qHD 30 fps. Get qHD 24 fps
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(960, best.width);
EXPECT_EQ(544, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(24), best.interval);
desired.width = 360;
desired.height = 250;
desired.interval = cricket::VideoFormat::FpsToInterval(30);
// Ask for a little higher than QVGA. Get QVGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 480;
desired.height = 270;
// Ask for HVGA. Get VGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 320;
desired.height = 240;
// Ask for QVGA. Get QVGA.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 160;
desired.height = 120;
// Ask for lower than QVGA. Get QVGA, which is the lowest.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 1280;
desired.height = 720;
// Ask for HD. 720p fps is too low. Get VGA which has 30 fps.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
desired.width = 1280;
desired.height = 720;
desired.interval = cricket::VideoFormat::FpsToInterval(15);
// Ask for HD 15 fps. Fps matches. Get HD
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(1280, best.width);
EXPECT_EQ(720, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
desired.width = 1920;
desired.height = 1080;
desired.interval = cricket::VideoFormat::FpsToInterval(30);
// Ask for 1080p. Fps of HD formats is too low. Get VGA which can do 30 fps.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
}
// Some cameras support 320x240 and 320x640. Verify we choose 320x240.
TEST_F(VideoCapturerTest, TestStrangeFormats) {
std::vector<cricket::VideoFormat> supported_formats;
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
320, 640, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
std::vector<cricket::VideoFormat> required_formats;
required_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
required_formats.push_back(cricket::VideoFormat(
320, 200, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
required_formats.push_back(cricket::VideoFormat(
320, 180, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
cricket::VideoFormat best;
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
}
supported_formats.clear();
supported_formats.push_back(cricket::VideoFormat(
320, 640, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
}
}
// Some cameras only have very low fps. Verify we choose something sensible.
TEST_F(VideoCapturerTest, TestPoorFpsFormats) {
// all formats are low framerate
std::vector<cricket::VideoFormat> supported_formats;
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
1280, 720, cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
std::vector<cricket::VideoFormat> required_formats;
required_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
required_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
cricket::VideoFormat best;
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(required_formats[i].width, best.width);
EXPECT_EQ(required_formats[i].height, best.height);
}
// Increase framerate of 320x240. Expect low fps VGA avoided.
supported_formats.clear();
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
1280, 720, cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
}
}
// Some cameras support same size with different frame rates. Verify we choose
// the frame rate properly.
TEST_F(VideoCapturerTest, TestSameSizeDifferentFpsFormats) {
std::vector<cricket::VideoFormat> supported_formats;
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
std::vector<cricket::VideoFormat> required_formats = supported_formats;
cricket::VideoFormat best;
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(320, best.width);
EXPECT_EQ(240, best.height);
EXPECT_EQ(required_formats[i].interval, best.interval);
}
}
// Some cameras support the correct resolution but at a lower fps than
// we'd like. This tests we get the expected resolution and fps.
TEST_F(VideoCapturerTest, TestFpsFormats) {
// We have VGA but low fps. Choose VGA, not HD
std::vector<cricket::VideoFormat> supported_formats;
supported_formats.push_back(
cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
std::vector<cricket::VideoFormat> required_formats;
required_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY));
required_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_ANY));
required_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY));
cricket::VideoFormat best;
// Expect 30 fps to choose 30 fps format.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[0], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(400, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
// Expect 20 fps to choose 30 fps format.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[1], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(400, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
// Expect 10 fps to choose 15 fps format and set fps to 15.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[2], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
// We have VGA 60 fps and 15 fps. Choose best fps.
supported_formats.clear();
supported_formats.push_back(
cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_MJPG));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
// Expect 30 fps to choose 60 fps format and will set best fps to 60.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[0], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
// Expect 20 fps to choose 60 fps format, and will set best fps to 60.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[1], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
// Expect 10 fps to choose 15 fps.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[2], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(480, best.height);
EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
}
TEST_F(VideoCapturerTest, TestRequest16x10_9) {
std::vector<cricket::VideoFormat> supported_formats;
// We do not support HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
std::vector<cricket::VideoFormat> required_formats = supported_formats;
cricket::VideoFormat best;
// Expect 4x3, 16x10, and 16x9 requests are respected.
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(required_formats[i].width, best.width);
EXPECT_EQ(required_formats[i].height, best.height);
}
// We do not support 16x9 HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
supported_formats.clear();
supported_formats.push_back(cricket::VideoFormat(
960, 720, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
// Expect 4x3, 16x10, and 16x9 requests are respected.
for (size_t i = 0; i < required_formats.size(); ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(required_formats[i].width, best.width);
EXPECT_EQ(required_formats[i].height, best.height);
}
// We support 16x9HD, Expect 4x3, 16x10, and 16x9 requests are respected.
supported_formats.clear();
supported_formats.push_back(
cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
supported_formats.push_back(cricket::VideoFormat(
640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
// Expect 4x3 for 4x3 and 16x10 requests.
for (size_t i = 0; i < required_formats.size() - 1; ++i) {
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best));
EXPECT_EQ(required_formats[i].width, best.width);
EXPECT_EQ(required_formats[i].height, best.height);
}
// Expect 16x9 for 16x9 request.
EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[2], &best));
EXPECT_EQ(640, best.width);
EXPECT_EQ(360, best.height);
}
bool HdFormatInList(const std::vector<cricket::VideoFormat>& formats) {
for (std::vector<cricket::VideoFormat>::const_iterator found =
formats.begin();
found != formats.end(); ++found) {
if (found->height >= kMinHdHeight) {
return true;
}
}
return false;
}
TEST_F(VideoCapturerTest, Whitelist) {
// The definition of HD only applies to the height. Set the HD width to the
// smallest legal number to document this fact in this test.
const int kMinHdWidth = 1;
cricket::VideoFormat hd_format(kMinHdWidth, kMinHdHeight,
cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420);
cricket::VideoFormat vga_format(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420);
std::vector<cricket::VideoFormat> formats = *capturer_->GetSupportedFormats();
formats.push_back(hd_format);
// Enable whitelist. Expect HD not in list.
capturer_->set_enable_camera_list(true);
capturer_->ResetSupportedFormats(formats);
EXPECT_TRUE(HdFormatInList(*capturer_->GetSupportedFormats()));
capturer_->ConstrainSupportedFormats(vga_format);
EXPECT_FALSE(HdFormatInList(*capturer_->GetSupportedFormats()));
// Disable whitelist. Expect HD in list.
capturer_->set_enable_camera_list(false);
capturer_->ResetSupportedFormats(formats);
EXPECT_TRUE(HdFormatInList(*capturer_->GetSupportedFormats()));
capturer_->ConstrainSupportedFormats(vga_format);
EXPECT_TRUE(HdFormatInList(*capturer_->GetSupportedFormats()));
}
TEST_F(VideoCapturerTest, BlacklistAllFormats) {
cricket::VideoFormat vga_format(
640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420);
std::vector<cricket::VideoFormat> supported_formats;
// Mock a device that only supports HD formats.
supported_formats.push_back(
cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420));
supported_formats.push_back(
cricket::VideoFormat(1920, 1080, cricket::VideoFormat::FpsToInterval(30),
cricket::FOURCC_I420));
capturer_->ResetSupportedFormats(supported_formats);
EXPECT_EQ(2u, capturer_->GetSupportedFormats()->size());
// Now, enable the list, which would exclude both formats. However, since
// only HD formats are available, we refuse to filter at all, so we don't
// break this camera.
capturer_->set_enable_camera_list(true);
capturer_->ConstrainSupportedFormats(vga_format);
EXPECT_EQ(2u, capturer_->GetSupportedFormats()->size());
// To make sure it's not just the camera list being broken, add in VGA and
// try again. This time, only the VGA format should be there.
supported_formats.push_back(vga_format);
capturer_->ResetSupportedFormats(supported_formats);
ASSERT_EQ(1u, capturer_->GetSupportedFormats()->size());
EXPECT_EQ(vga_format.height, capturer_->GetSupportedFormats()->at(0).height);
}

View File

@ -49,7 +49,6 @@
#include "media/base/media_config.h" #include "media/base/media_config.h"
#include "media/base/media_engine.h" #include "media/base/media_engine.h"
#include "media/base/stream_params.h" #include "media/base/stream_params.h"
#include "media/base/video_capturer.h"
#include "media/engine/webrtc_media_engine.h" #include "media/engine/webrtc_media_engine.h"
#include "media/sctp/sctp_transport_internal.h" #include "media/sctp/sctp_transport_internal.h"
#include "modules/audio_device/include/audio_device.h" #include "modules/audio_device/include/audio_device.h"