diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 427ddb6d52..8cb4849a47 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -695,6 +695,7 @@ if (is_linux || is_win) { "../rtc_base/third_party/sigslot", "../system_wrappers:field_trial", "../test:field_trial", + "../test:platform_video_capturer", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ] @@ -847,6 +848,7 @@ if (is_win || is_android) { "../pc:libjingle_peerconnection", "../pc:peerconnection", "../rtc_base:rtc_base", + "../test:platform_video_capturer", "../test:video_test_common", "//third_party/abseil-cpp/absl/memory", ] diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 03cf0c4133..464276c40d 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -366,6 +366,7 @@ if (is_ios || is_mac) { "..:common_objc", ":used_from_extension", ] + libs = [ "VideoToolbox.framework" ] } rtc_static_library("video_objc") { diff --git a/test/BUILD.gn b/test/BUILD.gn index c1e6362521..c0b3f17dec 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -49,8 +49,6 @@ rtc_source_set("video_test_common") { "frame_utils.h", "test_video_capturer.cc", "test_video_capturer.h", - "vcm_capturer.cc", - "vcm_capturer.h", "video_codec_settings.h", ] @@ -67,7 +65,6 @@ rtc_source_set("video_test_common") { "../call:video_stream_api", "../common_video", "../media:rtc_media_base", - "../modules/video_capture:video_capture_module", "../rtc_base:checks", "../rtc_base:rtc_base", "../rtc_base:rtc_task_queue", @@ -78,6 +75,55 @@ rtc_source_set("video_test_common") { ] } +if (!build_with_chromium) { + if (is_mac || is_ios) { + rtc_source_set("video_test_mac") { + testonly = true + sources = [ + "mac_capturer.h", + "mac_capturer.mm", + ] + deps = [ + ":video_test_common", + "../api:libjingle_peerconnection_api", + "../api:scoped_refptr", + "../modules/video_capture:video_capture_module", + "../rtc_base:rtc_base", + "../sdk:base_objc", + "../sdk:native_api", + "../sdk:native_video", + "../sdk:videocapture_objc", + ] + } + } + + rtc_source_set("platform_video_capturer") { + testonly = true + sources = [ + "platform_video_capturer.cc", + "platform_video_capturer.h", + ] + deps = [ + ":video_test_common", + "//third_party/abseil-cpp/absl/memory", + ] + if (is_mac || is_ios) { + deps += [ ":video_test_mac" ] + } else { + sources += [ + "vcm_capturer.cc", + "vcm_capturer.h", + ] + deps += [ + "../api:scoped_refptr", + "../modules/video_capture:video_capture_module", + "../rtc_base:checks", + "../rtc_base:logging", + ] + } + } +} + rtc_source_set("rtp_test_utils") { testonly = true sources = [ @@ -185,9 +231,9 @@ rtc_source_set("test_support") { "gtest.h", ] - public_deps = [] + public_deps = [] # no-presubmit-check TODO(webrtc:8603) if (is_ios) { - public_deps += [ ":test_support_objc" ] + public_deps += [ ":test_support_objc" ] # no-presubmit-check TODO(webrtc:8603) } public_configs = [ ":test_main_direct_config" ] @@ -485,11 +531,11 @@ rtc_source_set("fileutils_override_impl") { rtc_source_set("run_test") { testonly = true if (is_mac) { - public_deps = [ + public_deps = [ # no-presubmit-check TODO(webrtc:8603) ":run_test_objc", ] } else { - public_deps = [ + public_deps = [ # no-presubmit-check TODO(webrtc:8603) ":run_test_generic", ] } @@ -560,7 +606,7 @@ rtc_source_set("direct_transport") { "../system_wrappers", "//third_party/abseil-cpp/absl/memory", ] - public_deps = [ + public_deps = [ # no-presubmit-check TODO(webrtc:8603) ":single_threaded_task_queue", "../call:fake_network", ] @@ -719,12 +765,12 @@ rtc_source_set("test_common") { } rtc_source_set("test_renderer") { - public_deps = [ + public_deps = [ # no-presubmit-check TODO(webrtc:8603) ":test_renderer_generic", ] testonly = true if (is_mac) { - public_deps += [ ":test_renderer_objc" ] + public_deps += [ ":test_renderer_objc" ] # no-presubmit-check TODO(webrtc:8603) } } diff --git a/test/mac/Info.plist b/test/mac/Info.plist new file mode 100644 index 0000000000..8a2b5cf0a0 --- /dev/null +++ b/test/mac/Info.plist @@ -0,0 +1,16 @@ + + + + + CFBundleIdentifier + org.webrtc.video_loopback + CFBundleName + video_loopback + CFBundlePackageType + APPL + NSCameraUsageDescription + Camera access needed for video calling + NSMicrophoneUsageDescription + Microphone access needed for video calling + + diff --git a/test/mac_capturer.h b/test/mac_capturer.h new file mode 100644 index 0000000000..3d7ee77b45 --- /dev/null +++ b/test/mac_capturer.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 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 TEST_MAC_CAPTURER_H_ +#define TEST_MAC_CAPTURER_H_ + +#include +#include + +#include "api/media_stream_interface.h" +#include "api/scoped_refptr.h" +#include "modules/video_capture/video_capture.h" +#include "rtc_base/thread.h" +#include "test/test_video_capturer.h" + +namespace webrtc { +namespace test { + +class MacCapturer : public TestVideoCapturer, + public rtc::VideoSinkInterface { + public: + static MacCapturer* Create(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index); + ~MacCapturer() override; + + void OnFrame(const VideoFrame& frame) override; + + private: + MacCapturer(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index); + void Destroy(); + + void* capturer_; + void* adapter_; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_MAC_CAPTURER_H_ diff --git a/test/mac_capturer.mm b/test/mac_capturer.mm new file mode 100644 index 0000000000..004900a42e --- /dev/null +++ b/test/mac_capturer.mm @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 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 "test/mac_capturer.h" + +#import "sdk/objc/base/RTCVideoCapturer.h" +#import "sdk/objc/components/capturer/RTCCameraVideoCapturer.h" +#import "sdk/objc/native/api/video_capturer.h" +#import "sdk/objc/native/src/objc_frame_buffer.h" + +@interface RTCTestVideoSourceAdapter : NSObject +@property(nonatomic) webrtc::test::MacCapturer *capturer; +@end + +@implementation RTCTestVideoSourceAdapter +@synthesize capturer = _capturer; + +- (void)capturer:(RTCVideoCapturer *)capturer didCaptureVideoFrame:(RTCVideoFrame *)frame { + const int64_t timestamp_us = frame.timeStampNs / rtc::kNumNanosecsPerMicrosec; + rtc::scoped_refptr buffer = + new rtc::RefCountedObject(frame.buffer); + _capturer->OnFrame(webrtc::VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_rotation(webrtc::kVideoRotation_0) + .set_timestamp_us(timestamp_us) + .build()); +} + +@end + +namespace webrtc { +namespace test { + +MacCapturer::MacCapturer(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index) { + RTCTestVideoSourceAdapter *adapter = [[RTCTestVideoSourceAdapter alloc] init]; + adapter_ = (__bridge_retained void *)adapter; + adapter.capturer = this; + + RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:adapter]; + capturer_ = (__bridge_retained void *)capturer; + + AVCaptureDevice *device = + [[RTCCameraVideoCapturer captureDevices] objectAtIndex:capture_device_index]; + AVCaptureDeviceFormat *format = + [[RTCCameraVideoCapturer supportedFormatsForDevice:device] objectAtIndex:0]; + [capturer startCaptureWithDevice:device format:format fps:target_fps]; +} + +MacCapturer *MacCapturer::Create(size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index) { + return new MacCapturer(width, height, target_fps, capture_device_index); +} + +void MacCapturer::Destroy() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" + RTCTestVideoSourceAdapter *adapter = (__bridge_transfer RTCTestVideoSourceAdapter *)adapter_; + RTCCameraVideoCapturer *capturer = (__bridge_transfer RTCCameraVideoCapturer *)capturer_; + [capturer stopCapture]; +#pragma clang diagnostic pop +} + +MacCapturer::~MacCapturer() { + Destroy(); +} + +void MacCapturer::OnFrame(const VideoFrame &frame) { + TestVideoCapturer::OnFrame(frame); +} + +} // namespace test +} // namespace webrtc diff --git a/test/platform_video_capturer.cc b/test/platform_video_capturer.cc new file mode 100644 index 0000000000..fb3392a052 --- /dev/null +++ b/test/platform_video_capturer.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 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 "test/platform_video_capturer.h" + +#include "absl/memory/memory.h" +#if defined(WEBRTC_MAC) +#include "test/mac_capturer.h" +#else +#include "test/vcm_capturer.h" +#endif + +namespace webrtc { +namespace test { + +std::unique_ptr CreateVideoCapturer( + size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index) { +#if defined(WEBRTC_MAC) + return absl::WrapUnique(test::MacCapturer::Create( + width, height, target_fps, capture_device_index)); +#else + return absl::WrapUnique(test::VcmCapturer::Create( + width, height, target_fps, capture_device_index)); +#endif +} + +} // namespace test +} // namespace webrtc diff --git a/test/platform_video_capturer.h b/test/platform_video_capturer.h new file mode 100644 index 0000000000..241ba87df8 --- /dev/null +++ b/test/platform_video_capturer.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 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 TEST_PLATFORM_VIDEO_CAPTURER_H_ +#define TEST_PLATFORM_VIDEO_CAPTURER_H_ + +#include + +#include "test/test_video_capturer.h" + +namespace webrtc { +namespace test { + +std::unique_ptr CreateVideoCapturer( + size_t width, + size_t height, + size_t target_fps, + size_t capture_device_index); + +} // namespace test +} // namespace webrtc + +#endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ diff --git a/test/test_video_capturer.h b/test/test_video_capturer.h index 9c5b498f9f..0f1886bb44 100644 --- a/test/test_video_capturer.h +++ b/test/test_video_capturer.h @@ -25,7 +25,7 @@ namespace test { class TestVideoCapturer : public rtc::VideoSourceInterface { public: TestVideoCapturer(); - virtual ~TestVideoCapturer(); + ~TestVideoCapturer() override; void AddOrUpdateSink(rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) override; diff --git a/video/BUILD.gn b/video/BUILD.gn index 17b05de4c2..5bb0411466 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -271,6 +271,7 @@ if (rtc_include_tests) { "../test:fake_video_codecs", "../test:fileutils", "../test:perf_test", + "../test:platform_video_capturer", "../test:rtp_test_utils", "../test:test_common", "../test:test_renderer", @@ -280,6 +281,10 @@ if (rtc_include_tests) { "../test:video_test_support", "//third_party/abseil-cpp/absl/memory:memory", ] + + if (is_mac || is_ios) { + deps += [ "../test:video_test_mac" ] + } } rtc_source_set("video_full_stack_tests") { @@ -309,10 +314,11 @@ if (rtc_include_tests) { ] } - rtc_executable("video_loopback") { + rtc_static_library("video_loopback_lib") { testonly = true sources = [ "video_loopback.cc", + "video_loopback.h", ] deps = [ ":video_quality_test", @@ -335,6 +341,29 @@ if (rtc_include_tests) { ] } + if (is_mac) { + mac_app_bundle("video_loopback") { + testonly = true + sources = [ + "video_loopback_main.mm", + ] + info_plist = "../test/mac/Info.plist" + deps = [ + ":video_loopback_lib", + ] + } + } else { + rtc_executable("video_loopback") { + testonly = true + sources = [ + "video_loopback_main.cc", + ] + deps = [ + ":video_loopback_lib", + ] + } + } + rtc_executable("screenshare_loopback") { testonly = true sources = [ diff --git a/video/video_loopback.cc b/video/video_loopback.cc index ef32ae64dd..9ceb124ba1 100644 --- a/video/video_loopback.cc +++ b/video/video_loopback.cc @@ -7,6 +7,7 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ +#include "video/video_loopback.h" #include #include @@ -389,9 +390,8 @@ void Loopback() { fixture->RunWithRenderers(params); } } -} // namespace webrtc -int main(int argc, char* argv[]) { +int RunLoopbackTest(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); if (webrtc::flags::FLAG_help) { @@ -411,3 +411,4 @@ int main(int argc, char* argv[]) { webrtc::test::RunTest(webrtc::Loopback); return 0; } +} // namespace webrtc diff --git a/video/video_loopback.h b/video/video_loopback.h new file mode 100644 index 0000000000..51c7707640 --- /dev/null +++ b/video/video_loopback.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 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 VIDEO_VIDEO_LOOPBACK_H_ +#define VIDEO_VIDEO_LOOPBACK_H_ + +namespace webrtc { +// Expose the main test method. +int RunLoopbackTest(int argc, char* argv[]); +} // namespace webrtc + +#endif // VIDEO_VIDEO_LOOPBACK_H_ diff --git a/video/video_loopback_main.cc b/video/video_loopback_main.cc new file mode 100644 index 0000000000..f4e5cdd8a5 --- /dev/null +++ b/video/video_loopback_main.cc @@ -0,0 +1,15 @@ +/* + * Copyright 2019 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 "video/video_loopback.h" + +int main(int argc, char* argv[]) { + webrtc::RunLoopbackTest(argc, argv); +} diff --git a/video/video_loopback_main.mm b/video/video_loopback_main.mm new file mode 100644 index 0000000000..61b47a54da --- /dev/null +++ b/video/video_loopback_main.mm @@ -0,0 +1,17 @@ +/* + * Copyright 2019 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. + */ + +#import "video/video_loopback.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + webrtc::RunLoopbackTest(argc, argv); + } +} diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc index 2b20a8dca2..bdb1035589 100644 --- a/video/video_quality_test.cc +++ b/video/video_quality_test.cc @@ -35,9 +35,9 @@ #include "modules/video_coding/codecs/vp9/include/vp9.h" #include "modules/video_coding/utility/ivf_file_writer.h" #include "rtc_base/strings/string_builder.h" +#include "test/platform_video_capturer.h" #include "test/run_loop.h" #include "test/testsupport/file_utils.h" -#include "test/vcm_capturer.h" #include "test/video_renderer.h" #include "video/frame_dumping_decoder.h" #ifdef WEBRTC_WIN @@ -1076,10 +1076,10 @@ void VideoQualityTest::CreateCapturers() { test::FrameGenerator::OutputType::I010, absl::nullopt, params_.video[video_idx].fps, clock_)); } else if (params_.video[video_idx].clip_name.empty()) { - video_sources_[video_idx].reset(test::VcmCapturer::Create( + video_sources_[video_idx] = test::CreateVideoCapturer( params_.video[video_idx].width, params_.video[video_idx].height, params_.video[video_idx].fps, - params_.video[video_idx].capture_device_index)); + params_.video[video_idx].capture_device_index); if (!video_sources_[video_idx]) { // Failed to get actual camera, use chroma generator as backup. video_sources_[video_idx].reset(test::FrameGeneratorCapturer::Create(