From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- third_party/libwebrtc/test/BUILD.gn | 11 +- third_party/libwebrtc/test/OWNERS | 1 - third_party/libwebrtc/test/call_test.cc | 2 +- third_party/libwebrtc/test/fake_decoder.cc | 2 +- .../libwebrtc/test/frame_generator_capturer.cc | 10 +- .../libwebrtc/test/frame_generator_capturer.h | 6 +- third_party/libwebrtc/test/fuzzers/BUILD.gn | 38 +- .../fuzzers/audio_processing_configs_fuzzer.cc | 17 +- .../receive-side-cc/testcase-5414098152390656 | Bin 0 -> 87 bytes .../test/fuzzers/rtp_format_h264_fuzzer.cc | 75 +++ .../test/fuzzers/rtp_format_vp8_fuzzer.cc | 73 +++ .../test/fuzzers/rtp_format_vp9_fuzzer.cc | 73 +++ third_party/libwebrtc/test/network/BUILD.gn | 4 +- .../test/network/cross_traffic_unittest.cc | 2 +- .../libwebrtc/test/network/network_emulation.cc | 17 +- .../libwebrtc/test/network/network_emulation.h | 16 +- .../test/network/network_emulation_manager.cc | 19 +- .../test/network/network_emulation_manager.h | 4 +- .../test/network/network_emulation_pc_unittest.cc | 3 +- third_party/libwebrtc/test/pc/e2e/BUILD.gn | 3 +- .../audio/default_audio_quality_analyzer.cc | 24 +- .../video/video_quality_metrics_reporter.cc | 16 +- .../test/pc/e2e/cross_media_metrics_reporter.cc | 12 +- .../pc/e2e/network_quality_metrics_reporter.cc | 9 +- .../test/pc/e2e/peer_connection_quality_test.cc | 2 +- ...stats_based_network_quality_metrics_reporter.cc | 18 +- .../libwebrtc/test/pc/e2e/test_peer_factory.cc | 9 +- .../libwebrtc/test/pc/e2e/test_peer_factory.h | 6 +- .../test/peer_scenario/peer_scenario_client.cc | 3 +- third_party/libwebrtc/test/run_loop_unittest.cc | 2 +- .../libwebrtc/test/scenario/audio_stream.cc | 2 +- .../libwebrtc/test/scenario/video_stream.cc | 3 +- .../libwebrtc/test/time_controller/BUILD.gn | 3 +- .../external_time_controller_unittest.cc | 42 +- .../test/time_controller/real_time_controller.cc | 5 +- .../test/time_controller/real_time_controller.h | 3 +- .../time_controller/simulated_time_controller.cc | 3 - .../time_controller/simulated_time_controller.h | 1 - .../simulated_time_controller_unittest.cc | 38 +- third_party/libwebrtc/test/video_codec_tester.cc | 338 ++++++++++++-- .../libwebrtc/test/video_codec_tester_unittest.cc | 513 ++++++++++++++------- 41 files changed, 1054 insertions(+), 374 deletions(-) create mode 100644 third_party/libwebrtc/test/fuzzers/corpora/receive-side-cc/testcase-5414098152390656 create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_h264_fuzzer.cc create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_vp8_fuzzer.cc create mode 100644 third_party/libwebrtc/test/fuzzers/rtp_format_vp9_fuzzer.cc (limited to 'third_party/libwebrtc/test') diff --git a/third_party/libwebrtc/test/BUILD.gn b/third_party/libwebrtc/test/BUILD.gn index 854530c01e..75d8d9f3a8 100644 --- a/third_party/libwebrtc/test/BUILD.gn +++ b/third_party/libwebrtc/test/BUILD.gn @@ -167,7 +167,6 @@ rtc_library("frame_generator_capturer") { "../rtc_base:checks", "../rtc_base:logging", "../rtc_base:macromagic", - "../rtc_base:rtc_task_queue", "../rtc_base/synchronization:mutex", "../rtc_base/task_utils:repeating_task", "../system_wrappers", @@ -215,7 +214,6 @@ rtc_library("video_test_common") { "../rtc_base:criticalsection", "../rtc_base:logging", "../rtc_base:refcount", - "../rtc_base:rtc_task_queue", "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../rtc_base/task_utils:repeating_task", @@ -737,13 +735,17 @@ if (rtc_include_tests) { "../api:mock_video_encoder", "../api:scoped_refptr", "../api:simulcast_test_fixture_api", + "../api/task_queue", "../api/task_queue:task_queue_test", "../api/test/video:function_video_factory", "../api/test/video:video_frame_writer", "../api/units:data_rate", + "../api/units:data_size", + "../api/units:frequency", "../api/units:time_delta", "../api/video:encoded_image", "../api/video:video_frame", + "../api/video_codecs:scalability_mode", "../api/video_codecs:video_codecs_api", "../call:video_stream_api", "../common_video", @@ -760,7 +762,6 @@ if (rtc_include_tests) { "../modules/video_coding/svc:scalability_mode_util", "../rtc_base:criticalsection", "../rtc_base:rtc_event", - "../rtc_base:rtc_task_queue", "../rtc_base/synchronization:mutex", "../rtc_base/system:file_wrapper", "jitter:jitter_unittests", @@ -1022,7 +1023,6 @@ rtc_library("fake_video_codecs") { "../rtc_base:checks", "../rtc_base:criticalsection", "../rtc_base:macromagic", - "../rtc_base:rtc_task_queue", "../rtc_base:timeutils", "../rtc_base/synchronization:mutex", "../system_wrappers", @@ -1395,6 +1395,7 @@ rtc_library("video_codec_tester") { "video_codec_tester.h", ] deps = [ + ":scoped_key_value_config", "../api:array_view", "../api/numerics:numerics", "../api/test/metrics:metric", @@ -1413,6 +1414,7 @@ rtc_library("video_codec_tester") { "../media:media_constants", "../modules/video_coding:video_codec_interface", "../modules/video_coding:video_coding_utility", + "../modules/video_coding:webrtc_h264", "../modules/video_coding:webrtc_vp9_helpers", "../modules/video_coding/codecs/av1:av1_svc_config", "../modules/video_coding/svc:scalability_mode_util", @@ -1426,6 +1428,7 @@ rtc_library("video_codec_tester") { "../system_wrappers", "../test:fileutils", "../test:video_test_support", + "../video/config:streams_config", "//third_party/libyuv", ] diff --git a/third_party/libwebrtc/test/OWNERS b/third_party/libwebrtc/test/OWNERS index a1bd812244..f747873741 100644 --- a/third_party/libwebrtc/test/OWNERS +++ b/third_party/libwebrtc/test/OWNERS @@ -2,6 +2,5 @@ sprang@webrtc.org srte@webrtc.org stefan@webrtc.org titovartem@webrtc.org -landrey@webrtc.org mbonadei@webrtc.org jleconte@webrtc.org diff --git a/third_party/libwebrtc/test/call_test.cc b/third_party/libwebrtc/test/call_test.cc index 09099cccd6..6cdd8da133 100644 --- a/third_party/libwebrtc/test/call_test.cc +++ b/third_party/libwebrtc/test/call_test.cc @@ -572,7 +572,7 @@ void CallTest::CreateVideoSendStreams() { if (fec_controller_factory_.get()) { video_send_streams_[i] = sender_call_->CreateVideoSendStream( video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(), - fec_controller_factory_->CreateFecController()); + fec_controller_factory_->CreateFecController(send_env_)); } else { video_send_streams_[i] = sender_call_->CreateVideoSendStream( video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy()); diff --git a/third_party/libwebrtc/test/fake_decoder.cc b/third_party/libwebrtc/test/fake_decoder.cc index 01d95bfeb4..12bff8d36c 100644 --- a/third_party/libwebrtc/test/fake_decoder.cc +++ b/third_party/libwebrtc/test/fake_decoder.cc @@ -15,13 +15,13 @@ #include #include "api/scoped_refptr.h" +#include "api/task_queue/task_queue_factory.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 "modules/video_coding/include/video_error_codes.h" #include "rtc_base/checks.h" -#include "rtc_base/task_queue.h" #include "rtc_base/time_utils.h" namespace webrtc { diff --git a/third_party/libwebrtc/test/frame_generator_capturer.cc b/third_party/libwebrtc/test/frame_generator_capturer.cc index 6ba0807a74..7cdfec2cc2 100644 --- a/third_party/libwebrtc/test/frame_generator_capturer.cc +++ b/third_party/libwebrtc/test/frame_generator_capturer.cc @@ -29,7 +29,6 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" #include "system_wrappers/include/clock.h" #include "test/test_video_capturer.h" @@ -58,6 +57,9 @@ FrameGeneratorCapturer::FrameGeneratorCapturer( FrameGeneratorCapturer::~FrameGeneratorCapturer() { Stop(); + // Deconstruct first as tasks in the TaskQueue access other fields of the + // instance of this class. + task_queue_ = nullptr; } void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) { @@ -78,7 +80,7 @@ bool FrameGeneratorCapturer::Init() { return false; frame_task_ = RepeatingTaskHandle::DelayedStart( - task_queue_.Get(), + task_queue_.get(), TimeDelta::Seconds(1) / GetCurrentConfiguredFramerate(), [this] { InsertFrame(); @@ -131,7 +133,7 @@ void FrameGeneratorCapturer::Start() { } if (!frame_task_.Running()) { frame_task_ = RepeatingTaskHandle::Start( - task_queue_.Get(), + task_queue_.get(), [this] { InsertFrame(); return TimeDelta::Seconds(1) / GetCurrentConfiguredFramerate(); @@ -219,7 +221,7 @@ void FrameGeneratorCapturer::UpdateFps(int max_fps) { void FrameGeneratorCapturer::ForceFrame() { // One-time non-repeating task, - task_queue_.PostTask([this] { InsertFrame(); }); + task_queue_->PostTask([this] { InsertFrame(); }); } int FrameGeneratorCapturer::GetCurrentConfiguredFramerate() { diff --git a/third_party/libwebrtc/test/frame_generator_capturer.h b/third_party/libwebrtc/test/frame_generator_capturer.h index 6824ba681e..bb0c445c53 100644 --- a/third_party/libwebrtc/test/frame_generator_capturer.h +++ b/third_party/libwebrtc/test/frame_generator_capturer.h @@ -15,6 +15,7 @@ #include #include "absl/types/optional.h" +#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_factory.h" #include "api/test/frame_generator_interface.h" #include "api/video/color_space.h" @@ -23,7 +24,6 @@ #include "api/video/video_sink_interface.h" #include "api/video/video_source_interface.h" #include "rtc_base/synchronization/mutex.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/thread_annotations.h" #include "system_wrappers/include/clock.h" @@ -106,9 +106,7 @@ class FrameGeneratorCapturer : public TestVideoCapturer { int64_t first_frame_capture_time_; - // Must be the last field, so it will be deconstructed first as tasks - // in the TaskQueue access other fields of the instance of this class. - rtc::TaskQueue task_queue_; + std::unique_ptr task_queue_; }; } // namespace test } // namespace webrtc diff --git a/third_party/libwebrtc/test/fuzzers/BUILD.gn b/third_party/libwebrtc/test/fuzzers/BUILD.gn index 43e9a5e922..083c20c6f4 100644 --- a/third_party/libwebrtc/test/fuzzers/BUILD.gn +++ b/third_party/libwebrtc/test/fuzzers/BUILD.gn @@ -238,6 +238,36 @@ webrtc_fuzzer_test("rtp_packetizer_av1_fuzzer") { ] } +webrtc_fuzzer_test("rtp_format_h264_fuzzer") { + sources = [ "rtp_format_h264_fuzzer.cc" ] + deps = [ + "../../api/video:video_frame_type", + "../../modules/rtp_rtcp:rtp_rtcp", + "../../modules/rtp_rtcp:rtp_rtcp_format", + "../../rtc_base:checks", + ] +} + +webrtc_fuzzer_test("rtp_format_vp8_fuzzer") { + sources = [ "rtp_format_vp8_fuzzer.cc" ] + deps = [ + "../../api/video:video_frame_type", + "../../modules/rtp_rtcp:rtp_rtcp", + "../../modules/rtp_rtcp:rtp_rtcp_format", + "../../rtc_base:checks", + ] +} + +webrtc_fuzzer_test("rtp_format_vp9_fuzzer") { + sources = [ "rtp_format_vp9_fuzzer.cc" ] + deps = [ + "../../api/video:video_frame_type", + "../../modules/rtp_rtcp:rtp_rtcp", + "../../modules/rtp_rtcp:rtp_rtcp_format", + "../../rtc_base:checks", + ] +} + webrtc_fuzzer_test("receive_side_congestion_controller_fuzzer") { sources = [ "receive_side_congestion_controller_fuzzer.cc" ] deps = [ @@ -248,6 +278,7 @@ webrtc_fuzzer_test("receive_side_congestion_controller_fuzzer") { "../../modules/rtp_rtcp:rtp_rtcp_format", "../../system_wrappers", ] + seed_corpus = "corpora/receive-side-cc" } rtc_library("audio_decoder_fuzzer") { @@ -469,6 +500,7 @@ webrtc_fuzzer_test("audio_processing_fuzzer") { "../../api:scoped_refptr", "../../api/audio:aec3_factory", "../../api/audio:echo_detector_creator", + "../../api/task_queue", "../../api/task_queue:default_task_queue_factory", "../../modules/audio_processing", "../../modules/audio_processing:api", @@ -478,11 +510,13 @@ webrtc_fuzzer_test("audio_processing_fuzzer") { "../../modules/audio_processing/aec_dump", "../../modules/audio_processing/aec_dump:aec_dump_impl", "../../rtc_base:macromagic", - "../../rtc_base:rtc_task_queue", "../../rtc_base:safe_minmax", "../../system_wrappers:field_trial", ] - absl_deps = [ "//third_party/abseil-cpp/absl/memory" ] + absl_deps = [ + "//third_party/abseil-cpp/absl/base:nullability", + "//third_party/abseil-cpp/absl/memory", + ] seed_corpus = "corpora/audio_processing-corpus" } diff --git a/third_party/libwebrtc/test/fuzzers/audio_processing_configs_fuzzer.cc b/third_party/libwebrtc/test/fuzzers/audio_processing_configs_fuzzer.cc index 331a373f4e..93bce2f2e7 100644 --- a/third_party/libwebrtc/test/fuzzers/audio_processing_configs_fuzzer.cc +++ b/third_party/libwebrtc/test/fuzzers/audio_processing_configs_fuzzer.cc @@ -11,16 +11,17 @@ #include #include +#include "absl/base/nullability.h" #include "absl/memory/memory.h" #include "api/audio/echo_canceller3_factory.h" #include "api/audio/echo_detector_creator.h" #include "api/task_queue/default_task_queue_factory.h" +#include "api/task_queue/task_queue_base.h" #include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/test/audio_processing_builder_for_testing.h" #include "rtc_base/arraysize.h" #include "rtc_base/numerics/safe_minmax.h" -#include "rtc_base/task_queue.h" #include "system_wrappers/include/field_trial.h" #include "test/fuzzers/audio_processing_fuzzer_helper.h" #include "test/fuzzers/fuzz_data_helper.h" @@ -33,9 +34,10 @@ const std::string kFieldTrialNames[] = { "WebRTC-Aec3ShortHeadroomKillSwitch", }; -rtc::scoped_refptr CreateApm(test::FuzzDataHelper* fuzz_data, - std::string* field_trial_string, - rtc::TaskQueue* worker_queue) { +rtc::scoped_refptr CreateApm( + test::FuzzDataHelper* fuzz_data, + std::string* field_trial_string, + absl::Nonnull worker_queue) { // Parse boolean values for optionally enabling different // configurable public components of APM. bool use_ts = fuzz_data->ReadOrDefaultValue(true); @@ -134,9 +136,10 @@ void FuzzOneInput(const uint8_t* data, size_t size) { // for field_trial.h. Hence it's created here and not in CreateApm. std::string field_trial_string = ""; - rtc::TaskQueue worker_queue(GetTaskQueueFactory()->CreateTaskQueue( - "rtc-low-prio", rtc::TaskQueue::Priority::LOW)); - auto apm = CreateApm(&fuzz_data, &field_trial_string, &worker_queue); + std::unique_ptr worker_queue = + GetTaskQueueFactory()->CreateTaskQueue("rtc-low-prio", + TaskQueueFactory::Priority::LOW); + auto apm = CreateApm(&fuzz_data, &field_trial_string, worker_queue.get()); if (apm) { FuzzAudioProcessing(&fuzz_data, std::move(apm)); diff --git a/third_party/libwebrtc/test/fuzzers/corpora/receive-side-cc/testcase-5414098152390656 b/third_party/libwebrtc/test/fuzzers/corpora/receive-side-cc/testcase-5414098152390656 new file mode 100644 index 0000000000..98c423cdc2 Binary files /dev/null and b/third_party/libwebrtc/test/fuzzers/corpora/receive-side-cc/testcase-5414098152390656 differ diff --git a/third_party/libwebrtc/test/fuzzers/rtp_format_h264_fuzzer.cc b/third_party/libwebrtc/test/fuzzers/rtp_format_h264_fuzzer.cc new file mode 100644 index 0000000000..ddf2ca9d3d --- /dev/null +++ b/third_party/libwebrtc/test/fuzzers/rtp_format_h264_fuzzer.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 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 +#include + +#include "api/video/video_frame_type.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_format_h264.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzDataHelper fuzz_input(rtc::MakeArrayView(data, size)); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 1200; + // Read uint8_t to be sure reduction_lens are much smaller than + // max_payload_len and thus limits structure is valid. + limits.first_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.last_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.single_packet_reduction_len = + fuzz_input.ReadOrDefaultValue(0); + const H264PacketizationMode kPacketizationModes[] = { + H264PacketizationMode::NonInterleaved, + H264PacketizationMode::SingleNalUnit}; + + H264PacketizationMode packetization_mode = + fuzz_input.SelectOneOf(kPacketizationModes); + + // Main function under test: RtpPacketizerH264's constructor. + RtpPacketizerH264 packetizer(fuzz_input.ReadByteArray(fuzz_input.BytesLeft()), + limits, packetization_mode); + + size_t num_packets = packetizer.NumPackets(); + if (num_packets == 0) { + return; + } + // When packetization was successful, validate NextPacket function too. + // While at it, check that packets respect the payload size limits. + RtpPacketToSend rtp_packet(nullptr); + // Single packet. + if (num_packets == 1) { + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.single_packet_reduction_len); + return; + } + // First packet. + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.first_packet_reduction_len); + // Middle packets. + for (size_t i = 1; i < num_packets - 1; ++i) { + rtp_packet.Clear(); + RTC_CHECK(packetizer.NextPacket(&rtp_packet)) + << "Failed to get packet#" << i; + RTC_CHECK_LE(rtp_packet.payload_size(), limits.max_payload_len) + << "Packet #" << i << " exceeds it's limit"; + } + // Last packet. + rtp_packet.Clear(); + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.last_packet_reduction_len); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/test/fuzzers/rtp_format_vp8_fuzzer.cc b/third_party/libwebrtc/test/fuzzers/rtp_format_vp8_fuzzer.cc new file mode 100644 index 0000000000..c3c055de0f --- /dev/null +++ b/third_party/libwebrtc/test/fuzzers/rtp_format_vp8_fuzzer.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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 +#include + +#include "api/video/video_frame_type.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_format_vp8.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzDataHelper fuzz_input(rtc::MakeArrayView(data, size)); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 1200; + // Read uint8_t to be sure reduction_lens are much smaller than + // max_payload_len and thus limits structure is valid. + limits.first_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.last_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.single_packet_reduction_len = + fuzz_input.ReadOrDefaultValue(0); + + RTPVideoHeaderVP8 hdr_info; + hdr_info.InitRTPVideoHeaderVP8(); + uint16_t picture_id = fuzz_input.ReadOrDefaultValue(0); + hdr_info.pictureId = + picture_id >= 0x8000 ? kNoPictureId : picture_id & 0x7fff; + + // Main function under test: RtpPacketizerVp8's constructor. + RtpPacketizerVp8 packetizer(fuzz_input.ReadByteArray(fuzz_input.BytesLeft()), + limits, hdr_info); + + size_t num_packets = packetizer.NumPackets(); + if (num_packets == 0) { + return; + } + // When packetization was successful, validate NextPacket function too. + // While at it, check that packets respect the payload size limits. + RtpPacketToSend rtp_packet(nullptr); + // Single packet. + if (num_packets == 1) { + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.single_packet_reduction_len); + return; + } + // First packet. + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.first_packet_reduction_len); + // Middle packets. + for (size_t i = 1; i < num_packets - 1; ++i) { + RTC_CHECK(packetizer.NextPacket(&rtp_packet)) + << "Failed to get packet#" << i; + RTC_CHECK_LE(rtp_packet.payload_size(), limits.max_payload_len) + << "Packet #" << i << " exceeds it's limit"; + } + // Last packet. + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.last_packet_reduction_len); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/test/fuzzers/rtp_format_vp9_fuzzer.cc b/third_party/libwebrtc/test/fuzzers/rtp_format_vp9_fuzzer.cc new file mode 100644 index 0000000000..3b5e67f697 --- /dev/null +++ b/third_party/libwebrtc/test/fuzzers/rtp_format_vp9_fuzzer.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 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 +#include + +#include "api/video/video_frame_type.h" +#include "modules/rtp_rtcp/source/rtp_format.h" +#include "modules/rtp_rtcp/source/rtp_format_vp9.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/checks.h" +#include "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzDataHelper fuzz_input(rtc::MakeArrayView(data, size)); + + RtpPacketizer::PayloadSizeLimits limits; + limits.max_payload_len = 1200; + // Read uint8_t to be sure reduction_lens are much smaller than + // max_payload_len and thus limits structure is valid. + limits.first_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.last_packet_reduction_len = fuzz_input.ReadOrDefaultValue(0); + limits.single_packet_reduction_len = + fuzz_input.ReadOrDefaultValue(0); + + RTPVideoHeaderVP9 hdr_info; + hdr_info.InitRTPVideoHeaderVP9(); + uint16_t picture_id = fuzz_input.ReadOrDefaultValue(0); + hdr_info.picture_id = + picture_id >= 0x8000 ? kNoPictureId : picture_id & 0x7fff; + + // Main function under test: RtpPacketizerVp9's constructor. + RtpPacketizerVp9 packetizer(fuzz_input.ReadByteArray(fuzz_input.BytesLeft()), + limits, hdr_info); + + size_t num_packets = packetizer.NumPackets(); + if (num_packets == 0) { + return; + } + // When packetization was successful, validate NextPacket function too. + // While at it, check that packets respect the payload size limits. + RtpPacketToSend rtp_packet(nullptr); + // Single packet. + if (num_packets == 1) { + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.single_packet_reduction_len); + return; + } + // First packet. + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.first_packet_reduction_len); + // Middle packets. + for (size_t i = 1; i < num_packets - 1; ++i) { + RTC_CHECK(packetizer.NextPacket(&rtp_packet)) + << "Failed to get packet#" << i; + RTC_CHECK_LE(rtp_packet.payload_size(), limits.max_payload_len) + << "Packet #" << i << " exceeds it's limit"; + } + // Last packet. + RTC_CHECK(packetizer.NextPacket(&rtp_packet)); + RTC_CHECK_LE(rtp_packet.payload_size(), + limits.max_payload_len - limits.last_packet_reduction_len); +} +} // namespace webrtc diff --git a/third_party/libwebrtc/test/network/BUILD.gn b/third_party/libwebrtc/test/network/BUILD.gn index b8255d35fd..6df563d31d 100644 --- a/third_party/libwebrtc/test/network/BUILD.gn +++ b/third_party/libwebrtc/test/network/BUILD.gn @@ -47,6 +47,7 @@ rtc_library("emulated_network") { "../../api:simulated_network_api", "../../api:time_controller", "../../api/numerics", + "../../api/task_queue", "../../api/task_queue:pending_task_safety_flag", "../../api/test/network_emulation", "../../api/transport:stun_types", @@ -67,7 +68,6 @@ rtc_library("emulated_network") { "../../rtc_base:random", "../../rtc_base:rtc_base_tests_utils", "../../rtc_base:rtc_event", - "../../rtc_base:rtc_task_queue", "../../rtc_base:safe_minmax", "../../rtc_base:socket", "../../rtc_base:socket_address", @@ -87,6 +87,7 @@ rtc_library("emulated_network") { ] absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container", + "//third_party/abseil-cpp/absl/base:nullability", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/strings", "//third_party/abseil-cpp/absl/types:optional", @@ -117,7 +118,6 @@ if (rtc_include_tests && !build_with_chromium) { deps = [ ":emulated_network", "../:test_support", - "../../api:callfactory_api", "../../api:enable_media_with_defaults", "../../api:libjingle_peerconnection_api", "../../api:scoped_refptr", diff --git a/third_party/libwebrtc/test/network/cross_traffic_unittest.cc b/third_party/libwebrtc/test/network/cross_traffic_unittest.cc index 36aff67bb2..0f98fc9e72 100644 --- a/third_party/libwebrtc/test/network/cross_traffic_unittest.cc +++ b/third_party/libwebrtc/test/network/cross_traffic_unittest.cc @@ -55,7 +55,7 @@ struct TrafficCounterFixture { EmulatedEndpointConfig(), EmulatedNetworkStatsGatheringMode::kDefault, }, - /*is_enabled=*/true, &task_queue_, &clock}; + /*is_enabled=*/true, task_queue_.Get(), &clock}; }; } // namespace diff --git a/third_party/libwebrtc/test/network/network_emulation.cc b/third_party/libwebrtc/test/network/network_emulation.cc index f1c9ca80dd..642bf6fc7a 100644 --- a/third_party/libwebrtc/test/network/network_emulation.cc +++ b/third_party/libwebrtc/test/network/network_emulation.cc @@ -15,9 +15,11 @@ #include #include +#include "absl/base/nullability.h" #include "absl/types/optional.h" #include "api/numerics/samples_stats_counter.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "api/test/network_emulation/network_emulation_interfaces.h" #include "api/test/network_emulation_manager.h" #include "api/units/data_size.h" @@ -330,7 +332,7 @@ void LinkEmulation::OnPacketReceived(EmulatedIpPacket packet) { return; Timestamp current_time = clock_->CurrentTime(); process_task_ = RepeatingTaskHandle::DelayedStart( - task_queue_->Get(), + task_queue_, std::max(TimeDelta::Zero(), Timestamp::Micros(*next_time_us) - current_time), [this]() { @@ -383,7 +385,7 @@ void LinkEmulation::Process(Timestamp at_time) { } } -NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue) +NetworkRouterNode::NetworkRouterNode(absl::Nonnull task_queue) : task_queue_(task_queue) {} void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) { @@ -459,7 +461,7 @@ void NetworkRouterNode::SetFilter( EmulatedNetworkNode::EmulatedNetworkNode( Clock* clock, - rtc::TaskQueue* task_queue, + absl::Nonnull task_queue, std::unique_ptr network_behavior, EmulatedNetworkStatsGatheringMode stats_gathering_mode) : router_(task_queue), @@ -510,10 +512,11 @@ EmulatedEndpointImpl::Options::Options( config.allow_receive_packets_with_different_dest_ip), log_name(ip.ToString() + " (" + config.name.value_or("") + ")") {} -EmulatedEndpointImpl::EmulatedEndpointImpl(const Options& options, - bool is_enabled, - rtc::TaskQueue* task_queue, - Clock* clock) +EmulatedEndpointImpl::EmulatedEndpointImpl( + const Options& options, + bool is_enabled, + absl::Nonnull task_queue, + Clock* clock) : options_(options), is_enabled_(is_enabled), clock_(clock), diff --git a/third_party/libwebrtc/test/network/network_emulation.h b/third_party/libwebrtc/test/network/network_emulation.h index dffabafa7c..20705197be 100644 --- a/third_party/libwebrtc/test/network/network_emulation.h +++ b/third_party/libwebrtc/test/network/network_emulation.h @@ -19,10 +19,12 @@ #include #include +#include "absl/base/nullability.h" #include "absl/types/optional.h" #include "api/array_view.h" #include "api/numerics/samples_stats_counter.h" #include "api/sequence_checker.h" +#include "api/task_queue/task_queue_base.h" #include "api/test/network_emulation/network_emulation_interfaces.h" #include "api/test/network_emulation_manager.h" #include "api/test/simulated_network.h" @@ -145,7 +147,7 @@ class EmulatedNetworkNodeStatsBuilder { class LinkEmulation : public EmulatedNetworkReceiverInterface { public: LinkEmulation(Clock* clock, - rtc::TaskQueue* task_queue, + absl::Nonnull task_queue, std::unique_ptr network_behavior, EmulatedNetworkReceiverInterface* receiver, EmulatedNetworkStatsGatheringMode stats_gathering_mode) @@ -168,7 +170,7 @@ class LinkEmulation : public EmulatedNetworkReceiverInterface { void Process(Timestamp at_time) RTC_RUN_ON(task_queue_); Clock* const clock_; - rtc::TaskQueue* const task_queue_; + const absl::Nonnull task_queue_; const std::unique_ptr network_behavior_ RTC_GUARDED_BY(task_queue_); EmulatedNetworkReceiverInterface* const receiver_; @@ -186,7 +188,7 @@ class LinkEmulation : public EmulatedNetworkReceiverInterface { // the packet will be silently dropped. class NetworkRouterNode : public EmulatedNetworkReceiverInterface { public: - explicit NetworkRouterNode(rtc::TaskQueue* task_queue); + explicit NetworkRouterNode(absl::Nonnull task_queue); void OnPacketReceived(EmulatedIpPacket packet) override; void SetReceiver(const rtc::IPAddress& dest_ip, @@ -200,7 +202,7 @@ class NetworkRouterNode : public EmulatedNetworkReceiverInterface { void SetFilter(std::function filter); private: - rtc::TaskQueue* const task_queue_; + const absl::Nonnull task_queue_; absl::optional default_receiver_ RTC_GUARDED_BY(task_queue_); std::map routing_ @@ -224,7 +226,7 @@ class EmulatedNetworkNode : public EmulatedNetworkReceiverInterface { // they are ready. EmulatedNetworkNode( Clock* clock, - rtc::TaskQueue* task_queue, + absl::Nonnull task_queue, std::unique_ptr network_behavior, EmulatedNetworkStatsGatheringMode stats_gathering_mode); ~EmulatedNetworkNode() override; @@ -283,7 +285,7 @@ class EmulatedEndpointImpl : public EmulatedEndpoint { EmulatedEndpointImpl(const Options& options, bool is_enabled, - rtc::TaskQueue* task_queue, + absl::Nonnull task_queue, Clock* clock); ~EmulatedEndpointImpl() override; @@ -341,7 +343,7 @@ class EmulatedEndpointImpl : public EmulatedEndpoint { const Options options_; bool is_enabled_ RTC_GUARDED_BY(enabled_state_checker_); Clock* const clock_; - rtc::TaskQueue* const task_queue_; + const absl::Nonnull task_queue_; std::unique_ptr network_; NetworkRouterNode router_; diff --git a/third_party/libwebrtc/test/network/network_emulation_manager.cc b/third_party/libwebrtc/test/network/network_emulation_manager.cc index 97c0bc1ba8..dd0e93d8ee 100644 --- a/third_party/libwebrtc/test/network/network_emulation_manager.cc +++ b/third_party/libwebrtc/test/network/network_emulation_manager.cc @@ -13,6 +13,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "call/simulated_network.h" @@ -30,10 +31,12 @@ constexpr uint32_t kMinIPv4Address = 0xC0A80000; // uint32_t representation of 192.168.255.255 address constexpr uint32_t kMaxIPv4Address = 0xC0A8FFFF; -std::unique_ptr CreateTimeController(TimeMode mode) { +std::unique_ptr CreateTimeController( + TimeMode mode, + const FieldTrialsView* field_trials) { switch (mode) { case TimeMode::kRealTime: - return std::make_unique(); + return std::make_unique(field_trials); case TimeMode::kSimulated: // Using an offset of 100000 to get nice fixed width and readable // timestamps in typical test scenarios. @@ -46,10 +49,11 @@ std::unique_ptr CreateTimeController(TimeMode mode) { NetworkEmulationManagerImpl::NetworkEmulationManagerImpl( TimeMode mode, - EmulatedNetworkStatsGatheringMode stats_gathering_mode) + EmulatedNetworkStatsGatheringMode stats_gathering_mode, + const FieldTrialsView* field_trials) : time_mode_(mode), stats_gathering_mode_(stats_gathering_mode), - time_controller_(CreateTimeController(mode)), + time_controller_(CreateTimeController(mode, field_trials)), clock_(time_controller_->GetClock()), next_node_id_(1), next_ip4_address_(kMinIPv4Address), @@ -75,8 +79,9 @@ EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode( EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode( std::unique_ptr network_behavior) { - auto node = std::make_unique( - clock_, &task_queue_, std::move(network_behavior), stats_gathering_mode_); + auto node = std::make_unique(clock_, task_queue_.Get(), + std::move(network_behavior), + stats_gathering_mode_); EmulatedNetworkNode* out = node.get(); task_queue_.PostTask([this, node = std::move(node)]() mutable { network_nodes_.push_back(std::move(node)); @@ -111,7 +116,7 @@ EmulatedEndpointImpl* NetworkEmulationManagerImpl::CreateEndpoint( auto node = std::make_unique( EmulatedEndpointImpl::Options(next_node_id_++, *ip, config, stats_gathering_mode_), - config.start_as_enabled, &task_queue_, clock_); + config.start_as_enabled, task_queue_.Get(), clock_); EmulatedEndpointImpl* out = node.get(); endpoints_.push_back(std::move(node)); return out; diff --git a/third_party/libwebrtc/test/network/network_emulation_manager.h b/third_party/libwebrtc/test/network/network_emulation_manager.h index 29debca693..4b0a76494f 100644 --- a/third_party/libwebrtc/test/network/network_emulation_manager.h +++ b/third_party/libwebrtc/test/network/network_emulation_manager.h @@ -18,6 +18,7 @@ #include #include "api/array_view.h" +#include "api/field_trials_view.h" #include "api/test/network_emulation_manager.h" #include "api/test/simulated_network.h" #include "api/test/time_controller.h" @@ -38,7 +39,8 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager { public: NetworkEmulationManagerImpl( TimeMode mode, - EmulatedNetworkStatsGatheringMode stats_gathering_mode); + EmulatedNetworkStatsGatheringMode stats_gathering_mode, + const FieldTrialsView* field_trials = nullptr); ~NetworkEmulationManagerImpl(); EmulatedNetworkNode* CreateEmulatedNode(BuiltInNetworkBehaviorConfig config, diff --git a/third_party/libwebrtc/test/network/network_emulation_pc_unittest.cc b/third_party/libwebrtc/test/network/network_emulation_pc_unittest.cc index 09d3946747..73ac54e7ef 100644 --- a/third_party/libwebrtc/test/network/network_emulation_pc_unittest.cc +++ b/third_party/libwebrtc/test/network/network_emulation_pc_unittest.cc @@ -56,8 +56,7 @@ rtc::scoped_refptr CreatePeerConnectionFactory( rtc::Thread* network_thread) { PeerConnectionFactoryDependencies pcf_deps; pcf_deps.task_queue_factory = CreateDefaultTaskQueueFactory(); - pcf_deps.event_log_factory = - std::make_unique(pcf_deps.task_queue_factory.get()); + pcf_deps.event_log_factory = std::make_unique(); pcf_deps.network_thread = network_thread; pcf_deps.signaling_thread = signaling_thread; pcf_deps.trials = std::make_unique(); diff --git a/third_party/libwebrtc/test/pc/e2e/BUILD.gn b/third_party/libwebrtc/test/pc/e2e/BUILD.gn index 9d1c1d437f..0eb7aa2c68 100644 --- a/third_party/libwebrtc/test/pc/e2e/BUILD.gn +++ b/third_party/libwebrtc/test/pc/e2e/BUILD.gn @@ -99,6 +99,7 @@ if (!build_with_chromium) { "../../../api:enable_media_with_defaults", "../../../api:time_controller", "../../../api/rtc_event_log:rtc_event_log_factory", + "../../../api/task_queue", "../../../api/task_queue:default_task_queue_factory", "../../../api/test/pclf:media_configuration", "../../../api/test/pclf:media_quality_test_params", @@ -109,7 +110,6 @@ if (!build_with_chromium) { "../../../modules/audio_device:test_audio_device_module", "../../../modules/audio_processing/aec_dump", "../../../p2p:rtc_p2p", - "../../../rtc_base:rtc_task_queue", "../../../rtc_base:threading", "analyzer/video:quality_analyzing_video_encoder", "analyzer/video:video_quality_analyzer_injection_helper", @@ -286,7 +286,6 @@ if (!build_with_chromium) { ":default_audio_quality_analyzer", ":network_quality_metrics_reporter", ":stats_based_network_quality_metrics_reporter", - "../../../api:callfactory_api", "../../../api:create_network_emulation_manager", "../../../api:create_peer_connection_quality_test_frame_generator", "../../../api:create_peerconnection_quality_test_fixture", diff --git a/third_party/libwebrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc b/third_party/libwebrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc index bca52d9bfc..93d8906d6a 100644 --- a/third_party/libwebrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc +++ b/third_party/libwebrtc/test/pc/e2e/analyzer/audio/default_audio_quality_analyzer.cc @@ -42,29 +42,27 @@ void DefaultAudioQualityAnalyzer::OnStatsReports( auto stats = report->GetStatsOfType(); for (auto& stat : stats) { - if (!stat->kind.is_defined() || !(*stat->kind == "audio")) { + if (!stat->kind.has_value() || !(*stat->kind == "audio")) { continue; } StatsSample sample; - sample.total_samples_received = - stat->total_samples_received.ValueOrDefault(0ul); - sample.concealed_samples = stat->concealed_samples.ValueOrDefault(0ul); + sample.total_samples_received = stat->total_samples_received.value_or(0ul); + sample.concealed_samples = stat->concealed_samples.value_or(0ul); sample.removed_samples_for_acceleration = - stat->removed_samples_for_acceleration.ValueOrDefault(0ul); + stat->removed_samples_for_acceleration.value_or(0ul); sample.inserted_samples_for_deceleration = - stat->inserted_samples_for_deceleration.ValueOrDefault(0ul); + stat->inserted_samples_for_deceleration.value_or(0ul); sample.silent_concealed_samples = - stat->silent_concealed_samples.ValueOrDefault(0ul); + stat->silent_concealed_samples.value_or(0ul); sample.jitter_buffer_delay = - TimeDelta::Seconds(stat->jitter_buffer_delay.ValueOrDefault(0.)); + TimeDelta::Seconds(stat->jitter_buffer_delay.value_or(0.)); sample.jitter_buffer_target_delay = - TimeDelta::Seconds(stat->jitter_buffer_target_delay.ValueOrDefault(0.)); + TimeDelta::Seconds(stat->jitter_buffer_target_delay.value_or(0.)); sample.jitter_buffer_emitted_count = - stat->jitter_buffer_emitted_count.ValueOrDefault(0ul); - sample.total_samples_duration = - stat->total_samples_duration.ValueOrDefault(0.); - sample.total_audio_energy = stat->total_audio_energy.ValueOrDefault(0.); + stat->jitter_buffer_emitted_count.value_or(0ul); + sample.total_samples_duration = stat->total_samples_duration.value_or(0.); + sample.total_audio_energy = stat->total_audio_energy.value_or(0.); TrackIdStreamInfoMap::StreamInfo stream_info = analyzer_helper_->GetStreamInfoFromTrackId(*stat->track_identifier); diff --git a/third_party/libwebrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc b/third_party/libwebrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc index 817b3caad0..87f1590cb0 100644 --- a/third_party/libwebrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc +++ b/third_party/libwebrtc/test/pc/e2e/analyzer/video/video_quality_metrics_reporter.cc @@ -58,12 +58,14 @@ void VideoQualityMetricsReporter::OnStatsReports( auto transport_stats = report->GetStatsOfType(); if (transport_stats.size() == 0u || - !transport_stats[0]->selected_candidate_pair_id.is_defined()) { + !transport_stats[0]->selected_candidate_pair_id.has_value()) { return; } RTC_DCHECK_EQ(transport_stats.size(), 1); std::string selected_ice_id = - transport_stats[0]->selected_candidate_pair_id.ValueToString(); + transport_stats[0] + ->GetAttribute(transport_stats[0]->selected_candidate_pair_id) + .ToString(); // Use the selected ICE candidate pair ID to get the appropriate ICE stats. const RTCIceCandidatePairStats ice_candidate_pair_stats = report->Get(selected_ice_id)->cast_to(); @@ -71,7 +73,7 @@ void VideoQualityMetricsReporter::OnStatsReports( auto outbound_rtp_stats = report->GetStatsOfType(); StatsSample sample; for (auto& s : outbound_rtp_stats) { - if (!s->kind.is_defined()) { + if (!s->kind.has_value()) { continue; } if (!(*s->kind == "video")) { @@ -81,15 +83,15 @@ void VideoQualityMetricsReporter::OnStatsReports( sample.sample_time = s->timestamp(); } sample.retransmitted_bytes_sent += - DataSize::Bytes(s->retransmitted_bytes_sent.ValueOrDefault(0ul)); - sample.bytes_sent += DataSize::Bytes(s->bytes_sent.ValueOrDefault(0ul)); + DataSize::Bytes(s->retransmitted_bytes_sent.value_or(0ul)); + sample.bytes_sent += DataSize::Bytes(s->bytes_sent.value_or(0ul)); sample.header_bytes_sent += - DataSize::Bytes(s->header_bytes_sent.ValueOrDefault(0ul)); + DataSize::Bytes(s->header_bytes_sent.value_or(0ul)); } MutexLock lock(&video_bwe_stats_lock_); VideoBweStats& video_bwe_stats = video_bwe_stats_[std::string(pc_label)]; - if (ice_candidate_pair_stats.available_outgoing_bitrate.is_defined()) { + if (ice_candidate_pair_stats.available_outgoing_bitrate.has_value()) { video_bwe_stats.available_send_bandwidth.AddSample( DataRate::BitsPerSec( *ice_candidate_pair_stats.available_outgoing_bitrate) diff --git a/third_party/libwebrtc/test/pc/e2e/cross_media_metrics_reporter.cc b/third_party/libwebrtc/test/pc/e2e/cross_media_metrics_reporter.cc index aad5946c9f..c1536018d2 100644 --- a/third_party/libwebrtc/test/pc/e2e/cross_media_metrics_reporter.cc +++ b/third_party/libwebrtc/test/pc/e2e/cross_media_metrics_reporter.cc @@ -47,8 +47,8 @@ void CrossMediaMetricsReporter::OnStatsReports( std::map> sync_group_stats; for (const auto& stat : inbound_stats) { - if (stat->estimated_playout_timestamp.ValueOrDefault(0.) > 0 && - stat->track_identifier.is_defined()) { + if (stat->estimated_playout_timestamp.value_or(0.) > 0 && + stat->track_identifier.has_value()) { sync_group_stats[reporter_helper_ ->GetStreamInfoFromTrackId(*stat->track_identifier) .sync_group] @@ -66,8 +66,8 @@ void CrossMediaMetricsReporter::OnStatsReports( const RTCInboundRtpStreamStats* audio_stat = pair.second[0]; const RTCInboundRtpStreamStats* video_stat = pair.second[1]; - RTC_CHECK(pair.second.size() == 2 && audio_stat->kind.is_defined() && - video_stat->kind.is_defined() && + RTC_CHECK(pair.second.size() == 2 && audio_stat->kind.has_value() && + video_stat->kind.has_value() && *audio_stat->kind != *video_stat->kind) << "Sync group should consist of one audio and one video stream."; @@ -77,8 +77,8 @@ void CrossMediaMetricsReporter::OnStatsReports( // Stream labels of a sync group are same for all polls, so we need it add // it only once. if (stats_info_.find(sync_group) == stats_info_.end()) { - RTC_CHECK(audio_stat->track_identifier.is_defined()); - RTC_CHECK(video_stat->track_identifier.is_defined()); + RTC_CHECK(audio_stat->track_identifier.has_value()); + RTC_CHECK(video_stat->track_identifier.has_value()); stats_info_[sync_group].audio_stream_info = reporter_helper_->GetStreamInfoFromTrackId( *audio_stat->track_identifier); diff --git a/third_party/libwebrtc/test/pc/e2e/network_quality_metrics_reporter.cc b/third_party/libwebrtc/test/pc/e2e/network_quality_metrics_reporter.cc index 2d6aa597ce..257fecf309 100644 --- a/third_party/libwebrtc/test/pc/e2e/network_quality_metrics_reporter.cc +++ b/third_party/libwebrtc/test/pc/e2e/network_quality_metrics_reporter.cc @@ -79,15 +79,14 @@ void NetworkQualityMetricsReporter::OnStatsReports( auto inbound_stats = report->GetStatsOfType(); for (const auto& stat : inbound_stats) { payload_received += - DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) + - stat->header_bytes_received.ValueOrDefault(0ul)); + DataSize::Bytes(stat->bytes_received.value_or(0ul) + + stat->header_bytes_received.value_or(0ul)); } auto outbound_stats = report->GetStatsOfType(); for (const auto& stat : outbound_stats) { - payload_sent += - DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) + - stat->header_bytes_sent.ValueOrDefault(0ul)); + payload_sent += DataSize::Bytes(stat->bytes_sent.value_or(0ul) + + stat->header_bytes_sent.value_or(0ul)); } MutexLock lock(&lock_); diff --git a/third_party/libwebrtc/test/pc/e2e/peer_connection_quality_test.cc b/third_party/libwebrtc/test/pc/e2e/peer_connection_quality_test.cc index 5eb47b4682..90f201facd 100644 --- a/third_party/libwebrtc/test/pc/e2e/peer_connection_quality_test.cc +++ b/third_party/libwebrtc/test/pc/e2e/peer_connection_quality_test.cc @@ -277,7 +277,7 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { TestPeerFactory test_peer_factory( signaling_thread.get(), time_controller_, - video_quality_analyzer_injection_helper_.get(), task_queue_.get()); + video_quality_analyzer_injection_helper_.get(), task_queue_->Get()); alice_ = test_peer_factory.CreateTestPeer( std::move(alice_configurer), std::make_unique( diff --git a/third_party/libwebrtc/test/pc/e2e/stats_based_network_quality_metrics_reporter.cc b/third_party/libwebrtc/test/pc/e2e/stats_based_network_quality_metrics_reporter.cc index eb5f29287e..b965a7acd8 100644 --- a/third_party/libwebrtc/test/pc/e2e/stats_based_network_quality_metrics_reporter.cc +++ b/third_party/libwebrtc/test/pc/e2e/stats_based_network_quality_metrics_reporter.cc @@ -299,25 +299,23 @@ void StatsBasedNetworkQualityMetricsReporter::OnStatsReports( auto inbound_stats = report->GetStatsOfType(); for (const auto& stat : inbound_stats) { cur_stats.payload_received += - DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) + - stat->header_bytes_received.ValueOrDefault(0ul)); + DataSize::Bytes(stat->bytes_received.value_or(0ul) + + stat->header_bytes_received.value_or(0ul)); } auto outbound_stats = report->GetStatsOfType(); for (const auto& stat : outbound_stats) { - cur_stats.payload_sent += - DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) + - stat->header_bytes_sent.ValueOrDefault(0ul)); + cur_stats.payload_sent += DataSize::Bytes( + stat->bytes_sent.value_or(0ul) + stat->header_bytes_sent.value_or(0ul)); } auto candidate_pairs_stats = report->GetStatsOfType(); for (const auto& stat : candidate_pairs_stats) { cur_stats.total_received += - DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul)); - cur_stats.total_sent += - DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul)); - cur_stats.packets_received += stat->packets_received.ValueOrDefault(0ul); - cur_stats.packets_sent += stat->packets_sent.ValueOrDefault(0ul); + DataSize::Bytes(stat->bytes_received.value_or(0ul)); + cur_stats.total_sent += DataSize::Bytes(stat->bytes_sent.value_or(0ul)); + cur_stats.packets_received += stat->packets_received.value_or(0ul); + cur_stats.packets_sent += stat->packets_sent.value_or(0ul); } MutexLock lock(&mutex_); diff --git a/third_party/libwebrtc/test/pc/e2e/test_peer_factory.cc b/third_party/libwebrtc/test/pc/e2e/test_peer_factory.cc index dd900027ee..a184c5db3c 100644 --- a/third_party/libwebrtc/test/pc/e2e/test_peer_factory.cc +++ b/third_party/libwebrtc/test/pc/e2e/test_peer_factory.cc @@ -43,16 +43,14 @@ constexpr int kDefaultSamplingFrequencyInHz = 48000; // and `pc_dependencies` if they are omitted. Also setup required // dependencies, that won't be specially provided by factory and will be just // transferred to peer connection creation code. -void SetMandatoryEntities(InjectableComponents* components, - TimeController& time_controller) { +void SetMandatoryEntities(InjectableComponents* components) { RTC_DCHECK(components->pcf_dependencies); RTC_DCHECK(components->pc_dependencies); // Setup required peer connection factory dependencies. if (components->pcf_dependencies->event_log_factory == nullptr) { components->pcf_dependencies->event_log_factory = - std::make_unique( - time_controller.GetTaskQueueFactory()); + std::make_unique(); } if (!components->pcf_dependencies->trials) { components->pcf_dependencies->trials = @@ -286,7 +284,7 @@ std::unique_ptr TestPeerFactory::CreateTestPeer( RTC_DCHECK(configurable_params); RTC_DCHECK_EQ(configurable_params->video_configs.size(), video_sources.size()); - SetMandatoryEntities(components.get(), time_controller_); + SetMandatoryEntities(components.get()); params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan; // Create peer connection factory. @@ -329,6 +327,7 @@ std::unique_ptr TestPeerFactory::CreateTestPeer( components->worker_thread, components->network_thread); rtc::scoped_refptr peer_connection_factory = CreateModularPeerConnectionFactory(std::move(pcf_deps)); + peer_connection_factory->SetOptions(params->peer_connection_factory_options); // Create peer connection. PeerConnectionDependencies pc_deps = diff --git a/third_party/libwebrtc/test/pc/e2e/test_peer_factory.h b/third_party/libwebrtc/test/pc/e2e/test_peer_factory.h index f2698e2a15..cc61b04ae1 100644 --- a/third_party/libwebrtc/test/pc/e2e/test_peer_factory.h +++ b/third_party/libwebrtc/test/pc/e2e/test_peer_factory.h @@ -18,12 +18,12 @@ #include "absl/strings/string_view.h" #include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/task_queue/task_queue_base.h" #include "api/test/pclf/media_configuration.h" #include "api/test/pclf/media_quality_test_params.h" #include "api/test/pclf/peer_configurer.h" #include "api/test/time_controller.h" #include "modules/audio_device/include/test_audio_device.h" -#include "rtc_base/task_queue.h" #include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h" #include "test/pc/e2e/test_peer.h" @@ -55,7 +55,7 @@ class TestPeerFactory { TestPeerFactory(rtc::Thread* signaling_thread, TimeController& time_controller, VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, - rtc::TaskQueue* task_queue) + TaskQueueBase* task_queue) : signaling_thread_(signaling_thread), time_controller_(time_controller), video_analyzer_helper_(video_analyzer_helper), @@ -75,7 +75,7 @@ class TestPeerFactory { rtc::Thread* signaling_thread_; TimeController& time_controller_; VideoQualityAnalyzerInjectionHelper* video_analyzer_helper_; - rtc::TaskQueue* task_queue_; + TaskQueueBase* const task_queue_; }; } // namespace webrtc_pc_e2e diff --git a/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc index 60f2ea7f2e..1397b32fe3 100644 --- a/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc +++ b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc @@ -248,8 +248,7 @@ PeerScenarioClient::PeerScenarioClient( pcf_deps.worker_thread = worker_thread_.get(); pcf_deps.task_queue_factory = net->time_controller()->CreateTaskQueueFactory(); - pcf_deps.event_log_factory = - std::make_unique(task_queue_factory_); + pcf_deps.event_log_factory = std::make_unique(); pcf_deps.trials = std::make_unique(); pcf_deps.adm = TestAudioDeviceModule::Create( diff --git a/third_party/libwebrtc/test/run_loop_unittest.cc b/third_party/libwebrtc/test/run_loop_unittest.cc index 80f0bcbdcc..e6c747ac4f 100644 --- a/third_party/libwebrtc/test/run_loop_unittest.cc +++ b/third_party/libwebrtc/test/run_loop_unittest.cc @@ -10,8 +10,8 @@ #include "test/run_loop.h" +#include "api/task_queue/task_queue_base.h" #include "api/units/time_delta.h" -#include "rtc_base/task_queue.h" #include "test/gtest.h" namespace webrtc { diff --git a/third_party/libwebrtc/test/scenario/audio_stream.cc b/third_party/libwebrtc/test/scenario/audio_stream.cc index 5f7db7acdf..232f7382bd 100644 --- a/third_party/libwebrtc/test/scenario/audio_stream.cc +++ b/third_party/libwebrtc/test/scenario/audio_stream.cc @@ -89,7 +89,7 @@ SendAudioStream::SendAudioStream( AudioSendStream::Config send_config(send_transport); ssrc_ = sender->GetNextAudioSsrc(); send_config.rtp.ssrc = ssrc_; - SdpAudioFormat::Parameters sdp_params; + CodecParameterMap sdp_params; if (config.source.channels == 2) sdp_params["stereo"] = "1"; if (config.encoder.initial_frame_length != TimeDelta::Millis(20)) diff --git a/third_party/libwebrtc/test/scenario/video_stream.cc b/third_party/libwebrtc/test/scenario/video_stream.cc index eb20f8dbc7..654aed7c6c 100644 --- a/third_party/libwebrtc/test/scenario/video_stream.cc +++ b/third_party/libwebrtc/test/scenario/video_stream.cc @@ -430,7 +430,8 @@ SendVideoStream::SendVideoStream(CallClient* sender, if (config.stream.fec_controller_factory) { send_stream_ = sender_->call_->CreateVideoSendStream( std::move(send_config), std::move(encoder_config), - config.stream.fec_controller_factory->CreateFecController()); + config.stream.fec_controller_factory->CreateFecController( + sender_->env_)); } else { send_stream_ = sender_->call_->CreateVideoSendStream( std::move(send_config), std::move(encoder_config)); diff --git a/third_party/libwebrtc/test/time_controller/BUILD.gn b/third_party/libwebrtc/test/time_controller/BUILD.gn index b4b368a42a..6686528345 100644 --- a/third_party/libwebrtc/test/time_controller/BUILD.gn +++ b/third_party/libwebrtc/test/time_controller/BUILD.gn @@ -24,6 +24,7 @@ rtc_library("time_controller") { ] deps = [ + "../../api:field_trials_view", "../../api:sequence_checker", "../../api:time_controller", "../../api/task_queue", @@ -57,10 +58,10 @@ if (rtc_include_tests) { ":time_controller", "../:test_support", "../../api:time_controller", + "../../api/task_queue", "../../api/units:time_delta", "../../rtc_base:macromagic", "../../rtc_base:rtc_event", - "../../rtc_base:rtc_task_queue", "../../rtc_base:task_queue_for_test", "../../rtc_base:threading", "../../rtc_base/synchronization:mutex", diff --git a/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc b/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc index 13d63fe8ed..302055999a 100644 --- a/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc +++ b/third_party/libwebrtc/test/time_controller/external_time_controller_unittest.cc @@ -14,8 +14,8 @@ #include #include +#include "api/task_queue/task_queue_base.h" #include "rtc_base/event.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" #include "test/gmock.h" #include "test/gtest.h" @@ -88,11 +88,11 @@ TEST(ExternalTimeControllerTest, TaskIsStoppedOnStop) { const int kMargin = 1; FakeAlarm alarm(kStartTime); ExternalTimeController time_simulation(&alarm); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); std::atomic_int counter(0); - auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] { + auto handle = RepeatingTaskHandle::Start(task_queue.get(), [&] { if (++counter >= kShortIntervalCount) return kLongInterval; return kShortInterval; @@ -101,7 +101,7 @@ TEST(ExternalTimeControllerTest, TaskIsStoppedOnStop) { time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin)); EXPECT_EQ(counter.load(), kShortIntervalCount); - task_queue.PostTask( + task_queue->PostTask( [handle = std::move(handle)]() mutable { handle.Stop(); }); // Sleep long enough that the task would run at least once more if not @@ -114,13 +114,13 @@ TEST(ExternalTimeControllerTest, TaskCanStopItself) { std::atomic_int counter(0); FakeAlarm alarm(kStartTime); ExternalTimeController time_simulation(&alarm); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); RepeatingTaskHandle handle; - task_queue.PostTask([&] { - handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] { + task_queue->PostTask([&] { + handle = RepeatingTaskHandle::Start(task_queue.get(), [&] { ++counter; handle.Stop(); return TimeDelta::Millis(2); @@ -134,12 +134,12 @@ TEST(ExternalTimeControllerTest, YieldForTask) { FakeAlarm alarm(kStartTime); ExternalTimeController time_simulation(&alarm); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); rtc::Event event; - task_queue.PostTask([&] { event.Set(); }); + task_queue->PostTask([&] { event.Set(); }); EXPECT_TRUE(event.Wait(TimeDelta::Millis(200))); } @@ -147,16 +147,16 @@ TEST(ExternalTimeControllerTest, TasksYieldToEachOther) { FakeAlarm alarm(kStartTime); ExternalTimeController time_simulation(&alarm); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); - rtc::TaskQueue other_queue( + "TestQueue", TaskQueueFactory::Priority::NORMAL); + std::unique_ptr other_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "OtherQueue", TaskQueueFactory::Priority::NORMAL)); + "OtherQueue", TaskQueueFactory::Priority::NORMAL); - task_queue.PostTask([&] { + task_queue->PostTask([&] { rtc::Event event; - other_queue.PostTask([&] { event.Set(); }); + other_queue->PostTask([&] { event.Set(); }); EXPECT_TRUE(event.Wait(TimeDelta::Millis(200))); }); @@ -167,11 +167,11 @@ TEST(ExternalTimeControllerTest, CurrentTaskQueue) { FakeAlarm alarm(kStartTime); ExternalTimeController time_simulation(&alarm); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); - task_queue.PostTask([&] { EXPECT_TRUE(task_queue.IsCurrent()); }); + task_queue->PostTask([&] { EXPECT_TRUE(task_queue->IsCurrent()); }); time_simulation.AdvanceTime(TimeDelta::Millis(10)); } diff --git a/third_party/libwebrtc/test/time_controller/real_time_controller.cc b/third_party/libwebrtc/test/time_controller/real_time_controller.cc index 7cc750d6d4..537532d20f 100644 --- a/third_party/libwebrtc/test/time_controller/real_time_controller.cc +++ b/third_party/libwebrtc/test/time_controller/real_time_controller.cc @@ -9,6 +9,7 @@ */ #include "test/time_controller/real_time_controller.h" +#include "api/field_trials_view.h" #include "api/task_queue/default_task_queue_factory.h" #include "rtc_base/null_socket_server.h" @@ -30,8 +31,8 @@ class MainThread : public rtc::Thread { CurrentThreadSetter current_setter_; }; } // namespace -RealTimeController::RealTimeController() - : task_queue_factory_(CreateDefaultTaskQueueFactory()), +RealTimeController::RealTimeController(const FieldTrialsView* field_trials) + : task_queue_factory_(CreateDefaultTaskQueueFactory(field_trials)), main_thread_(std::make_unique()) { main_thread_->SetName("Main", this); } diff --git a/third_party/libwebrtc/test/time_controller/real_time_controller.h b/third_party/libwebrtc/test/time_controller/real_time_controller.h index 5f02eaf85f..0085732e63 100644 --- a/third_party/libwebrtc/test/time_controller/real_time_controller.h +++ b/third_party/libwebrtc/test/time_controller/real_time_controller.h @@ -13,6 +13,7 @@ #include #include +#include "api/field_trials_view.h" #include "api/task_queue/task_queue_factory.h" #include "api/test/time_controller.h" #include "api/units/time_delta.h" @@ -21,7 +22,7 @@ namespace webrtc { class RealTimeController : public TimeController { public: - RealTimeController(); + RealTimeController(const FieldTrialsView* field_trials = nullptr); Clock* GetClock() override; TaskQueueFactory* GetTaskQueueFactory() override; diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc b/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc index dbb36fdfcc..ce666c4bf5 100644 --- a/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc +++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller.cc @@ -218,9 +218,6 @@ void GlobalSimulatedTimeController::SkipForwardBy(TimeDelta duration) { impl_.AdvanceTime(target_time); sim_clock_.AdvanceTimeMicroseconds(duration.us()); global_clock_.AdvanceTime(duration); - - // Run tasks that were pending during the skip. - impl_.RunReadyRunners(); } void GlobalSimulatedTimeController::Register( diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller.h b/third_party/libwebrtc/test/time_controller/simulated_time_controller.h index f3f0da9274..df7f866b14 100644 --- a/third_party/libwebrtc/test/time_controller/simulated_time_controller.h +++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller.h @@ -139,7 +139,6 @@ class GlobalSimulatedTimeController : public TimeController { void AdvanceTime(TimeDelta duration) override; // Advances time by `duration`and do not run delayed tasks in the meantime. - // Runs any pending tasks at the end. // Useful for simulating contention on destination queues. void SkipForwardBy(TimeDelta duration); diff --git a/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc b/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc index f223ffe85d..c1c0ac2c0e 100644 --- a/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc +++ b/third_party/libwebrtc/test/time_controller/simulated_time_controller_unittest.cc @@ -13,9 +13,9 @@ #include #include +#include "api/task_queue/task_queue_base.h" #include "api/units/time_delta.h" #include "rtc_base/event.h" -#include "rtc_base/task_queue.h" #include "rtc_base/task_queue_for_test.h" #include "rtc_base/task_utils/repeating_task.h" #include "test/gmock.h" @@ -39,11 +39,11 @@ TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) { const int kShortIntervalCount = 4; const int kMargin = 1; GlobalSimulatedTimeController time_simulation(kStartTime); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); std::atomic_int counter(0); - auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] { + auto handle = RepeatingTaskHandle::Start(task_queue.get(), [&] { if (++counter >= kShortIntervalCount) return kLongInterval; return kShortInterval; @@ -52,7 +52,7 @@ TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) { time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin)); EXPECT_EQ(counter.load(), kShortIntervalCount); - task_queue.PostTask( + task_queue->PostTask( [handle = std::move(handle)]() mutable { handle.Stop(); }); // Sleep long enough that the task would run at least once more if not @@ -64,13 +64,13 @@ TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) { TEST(SimulatedTimeControllerTest, TaskCanStopItself) { std::atomic_int counter(0); GlobalSimulatedTimeController time_simulation(kStartTime); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); RepeatingTaskHandle handle; - task_queue.PostTask([&] { - handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] { + task_queue->PostTask([&] { + handle = RepeatingTaskHandle::Start(task_queue.get(), [&] { ++counter; handle.Stop(); return TimeDelta::Millis(2); @@ -86,29 +86,29 @@ TEST(SimulatedTimeControllerTest, Example) { void DoPeriodicTask() {} TimeDelta TimeUntilNextRun() { return TimeDelta::Millis(100); } void StartPeriodicTask(RepeatingTaskHandle* handle, - rtc::TaskQueue* task_queue) { - *handle = RepeatingTaskHandle::Start(task_queue->Get(), [this] { + TaskQueueBase* task_queue) { + *handle = RepeatingTaskHandle::Start(task_queue, [this] { DoPeriodicTask(); return TimeUntilNextRun(); }); } }; GlobalSimulatedTimeController time_simulation(kStartTime); - rtc::TaskQueue task_queue( + std::unique_ptr task_queue = time_simulation.GetTaskQueueFactory()->CreateTaskQueue( - "TestQueue", TaskQueueFactory::Priority::NORMAL)); + "TestQueue", TaskQueueFactory::Priority::NORMAL); auto object = std::make_unique(); // Create and start the periodic task. RepeatingTaskHandle handle; - object->StartPeriodicTask(&handle, &task_queue); + object->StartPeriodicTask(&handle, task_queue.get()); // Restart the task - task_queue.PostTask( + task_queue->PostTask( [handle = std::move(handle)]() mutable { handle.Stop(); }); - object->StartPeriodicTask(&handle, &task_queue); - task_queue.PostTask( + object->StartPeriodicTask(&handle, task_queue.get()); + task_queue->PostTask( [handle = std::move(handle)]() mutable { handle.Stop(); }); - task_queue.PostTask([object = std::move(object)] {}); + task_queue->PostTask([object = std::move(object)] {}); } TEST(SimulatedTimeControllerTest, DelayTaskRunOnTime) { @@ -159,6 +159,8 @@ TEST(SimulatedTimeControllerTest, SkipsDelayedTaskForward) { })); main_thread->PostDelayedTask(fun.AsStdFunction(), shorter_duration); sim.SkipForwardBy(duration_during_which_nothing_runs); + // Run tasks that were pending during the skip. + sim.AdvanceTime(TimeDelta::Zero()); } } // namespace webrtc diff --git a/third_party/libwebrtc/test/video_codec_tester.cc b/third_party/libwebrtc/test/video_codec_tester.cc index 9453c3a7ef..f5fdc07a6b 100644 --- a/third_party/libwebrtc/test/video_codec_tester.cc +++ b/third_party/libwebrtc/test/video_codec_tester.cc @@ -23,10 +23,13 @@ #include "api/video/video_bitrate_allocator.h" #include "api/video/video_codec_type.h" #include "api/video/video_frame.h" +#include "api/video_codecs/h264_profile_level_id.h" +#include "api/video_codecs/simulcast_stream.h" #include "api/video_codecs/video_decoder.h" #include "api/video_codecs/video_encoder.h" #include "media/base/media_constants.h" #include "modules/video_coding/codecs/av1/av1_svc_config.h" +#include "modules/video_coding/codecs/h264/include/h264.h" #include "modules/video_coding/codecs/vp9/svc_config.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_error_codes.h" @@ -39,10 +42,12 @@ #include "rtc_base/task_queue_for_test.h" #include "rtc_base/time_utils.h" #include "system_wrappers/include/sleep.h" +#include "test/scoped_key_value_config.h" #include "test/testsupport/file_utils.h" #include "test/testsupport/frame_reader.h" #include "test/testsupport/video_frame_writer.h" #include "third_party/libyuv/include/libyuv/compare.h" +#include "video/config/simulcast.h" namespace webrtc { namespace test { @@ -260,9 +265,10 @@ class TesterIvfWriter { task_queue_.SendTask([] {}); } - void Write(const EncodedImage& encoded_frame) { - task_queue_.PostTask([this, encoded_frame] { - int spatial_idx = encoded_frame.SimulcastIndex().value_or(0); + void Write(const EncodedImage& encoded_frame, VideoCodecType codec_type) { + task_queue_.PostTask([this, encoded_frame, codec_type] { + int spatial_idx = encoded_frame.SpatialIndex().value_or( + encoded_frame.SimulcastIndex().value_or(0)); if (ivf_file_writers_.find(spatial_idx) == ivf_file_writers_.end()) { std::string ivf_path = base_path_ + "-s" + std::to_string(spatial_idx) + ".ivf"; @@ -277,8 +283,7 @@ class TesterIvfWriter { } // To play: ffplay -vcodec vp8|vp9|av1|hevc|h264 filename - ivf_file_writers_.at(spatial_idx) - ->WriteFrame(encoded_frame, VideoCodecType::kVideoCodecGeneric); + ivf_file_writers_.at(spatial_idx)->WriteFrame(encoded_frame, codec_type); }); } @@ -344,7 +349,8 @@ class VideoCodecAnalyzer : public VideoCodecTester::VideoCodecStats { int64_t encode_finished_us = rtc::TimeMicros(); task_queue_.PostTask( [this, timestamp_rtp = encoded_frame.RtpTimestamp(), - spatial_idx = encoded_frame.SpatialIndex().value_or(0), + spatial_idx = encoded_frame.SpatialIndex().value_or( + encoded_frame.SimulcastIndex().value_or(0)), temporal_idx = encoded_frame.TemporalIndex().value_or(0), width = encoded_frame._encodedWidth, height = encoded_frame._encodedHeight, @@ -378,17 +384,30 @@ class VideoCodecAnalyzer : public VideoCodecTester::VideoCodecStats { int64_t decode_start_us = rtc::TimeMicros(); task_queue_.PostTask( [this, timestamp_rtp = encoded_frame.RtpTimestamp(), - spatial_idx = encoded_frame.SpatialIndex().value_or(0), + spatial_idx = encoded_frame.SpatialIndex().value_or( + encoded_frame.SimulcastIndex().value_or(0)), + temporal_idx = encoded_frame.TemporalIndex().value_or(0), + width = encoded_frame._encodedWidth, + height = encoded_frame._encodedHeight, + frame_type = encoded_frame._frameType, qp = encoded_frame.qp_, frame_size_bytes = encoded_frame.size(), decode_start_us]() { - if (frames_.find(timestamp_rtp) == frames_.end() || - frames_.at(timestamp_rtp).find(spatial_idx) == - frames_.at(timestamp_rtp).end()) { + bool decode_only = frames_.find(timestamp_rtp) == frames_.end(); + if (decode_only || frames_.at(timestamp_rtp).find(spatial_idx) == + frames_.at(timestamp_rtp).end()) { Frame frame; frame.timestamp_rtp = timestamp_rtp; - frame.layer_id = {.spatial_idx = spatial_idx}; - frame.frame_size = DataSize::Bytes(frame_size_bytes); - frames_.emplace(timestamp_rtp, - std::map{{spatial_idx, frame}}); + frame.layer_id = {.spatial_idx = spatial_idx, + .temporal_idx = temporal_idx}; + frame.width = width; + frame.height = height; + frame.keyframe = frame_type == VideoFrameType::kVideoFrameKey; + frame.qp = qp; + if (decode_only) { + frame.frame_size = DataSize::Bytes(frame_size_bytes); + frames_[timestamp_rtp] = {{spatial_idx, frame}}; + } else { + frames_[timestamp_rtp][spatial_idx] = frame; + } } Frame& frame = frames_.at(timestamp_rtp).at(spatial_idx); @@ -485,6 +504,8 @@ class VideoCodecAnalyzer : public VideoCodecTester::VideoCodecStats { Frame superframe = subframes.back(); for (const Frame& frame : rtc::ArrayView(subframes).subview(0, subframes.size() - 1)) { + superframe.decoded |= frame.decoded; + superframe.encoded |= frame.encoded; superframe.frame_size += frame.frame_size; superframe.keyframe |= frame.keyframe; superframe.encode_time = @@ -775,11 +796,13 @@ class Decoder : public DecodedImageCallback { RTC_CHECK(decoder_) << "Could not create decoder for video format " << sdp_video_format.ToString(); - task_queue_.PostTaskAndWait([this, &sdp_video_format] { + codec_type_ = PayloadStringToCodecType(sdp_video_format.name); + + task_queue_.PostTaskAndWait([this] { decoder_->RegisterDecodeCompleteCallback(this); VideoDecoder::Settings ds; - ds.set_codec_type(PayloadStringToCodecType(sdp_video_format.name)); + ds.set_codec_type(*codec_type_); ds.set_number_of_cores(1); ds.set_max_render_resolution({1280, 720}); bool result = decoder_->Configure(ds); @@ -788,6 +811,16 @@ class Decoder : public DecodedImageCallback { } void Decode(const EncodedImage& encoded_frame) { + int spatial_idx = encoded_frame.SpatialIndex().value_or( + encoded_frame.SimulcastIndex().value_or(0)); + { + MutexLock lock(&mutex_); + RTC_CHECK_EQ(spatial_idx_.value_or(spatial_idx), spatial_idx) + << "Spatial index changed from " << *spatial_idx_ << " to " + << spatial_idx; + spatial_idx_ = spatial_idx; + } + Timestamp pts = Timestamp::Micros((encoded_frame.RtpTimestamp() / k90kHz).us()); @@ -804,7 +837,7 @@ class Decoder : public DecodedImageCallback { pacer_.Schedule(pts)); if (ivf_writer_) { - ivf_writer_->Write(encoded_frame); + ivf_writer_->Write(encoded_frame, *codec_type_); } } @@ -815,10 +848,16 @@ class Decoder : public DecodedImageCallback { private: int Decoded(VideoFrame& decoded_frame) override { - analyzer_->FinishDecode(decoded_frame, /*spatial_idx=*/0); + int spatial_idx; + { + MutexLock lock(&mutex_); + spatial_idx = *spatial_idx_; + } + + analyzer_->FinishDecode(decoded_frame, spatial_idx); if (y4m_writer_) { - y4m_writer_->Write(decoded_frame, /*spatial_idx=*/0); + y4m_writer_->Write(decoded_frame, spatial_idx); } return WEBRTC_VIDEO_CODEC_OK; @@ -831,6 +870,9 @@ class Decoder : public DecodedImageCallback { LimitedTaskQueue task_queue_; std::unique_ptr ivf_writer_; std::unique_ptr y4m_writer_; + absl::optional codec_type_; + absl::optional spatial_idx_ RTC_GUARDED_BY(mutex_); + Mutex mutex_; }; class Encoder : public EncodedImageCallback { @@ -863,6 +905,9 @@ class Encoder : public EncodedImageCallback { RTC_CHECK(encoder_) << "Could not create encoder for video format " << encoding_settings.sdp_video_format.ToString(); + codec_type_ = + PayloadStringToCodecType(encoding_settings.sdp_video_format.name); + task_queue_.PostTaskAndWait([this, encoding_settings] { encoder_->RegisterEncodeCompleteCallback(this); Configure(encoding_settings); @@ -888,14 +933,13 @@ class Encoder : public EncodedImageCallback { !IsSameRate(encoding_settings, *last_encoding_settings_)) { SetRates(encoding_settings); } + last_encoding_settings_ = encoding_settings; int error = encoder_->Encode(input_frame, /*frame_types=*/nullptr); if (error != 0) { RTC_LOG(LS_WARNING) << "Encode failed with error code " << error << " RTP timestamp " << input_frame.timestamp(); } - - last_encoding_settings_ = encoding_settings; }, pacer_.Schedule(pts)); @@ -906,13 +950,54 @@ class Encoder : public EncodedImageCallback { void Flush() { task_queue_.PostTaskAndWait([this] { encoder_->Release(); }); + if (last_superframe_) { + int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(last_superframe_->scalability_mode); + for (int sidx = *last_superframe_->encoded_frame.SpatialIndex() + 1; + sidx < num_spatial_layers; ++sidx) { + last_superframe_->encoded_frame.SetSpatialIndex(sidx); + DeliverEncodedFrame(last_superframe_->encoded_frame); + } + last_superframe_.reset(); + } } private: + struct Superframe { + EncodedImage encoded_frame; + rtc::scoped_refptr encoded_data; + ScalabilityMode scalability_mode; + }; + Result OnEncodedImage(const EncodedImage& encoded_frame, const CodecSpecificInfo* codec_specific_info) override { analyzer_->FinishEncode(encoded_frame); + if (last_superframe_ && last_superframe_->encoded_frame.RtpTimestamp() != + encoded_frame.RtpTimestamp()) { + // New temporal unit. We have frame of previous temporal unit (TU) stored + // which means that the previous TU used spatial prediction. If encoder + // dropped a frame of layer X in the previous TU, mark the stored frame + // as a frame belonging to layer >X and deliver it such that decoders of + // layer >X receive encoded lower layers. + int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(last_superframe_->scalability_mode); + for (int sidx = *last_superframe_->encoded_frame.SpatialIndex() + 1; + sidx < num_spatial_layers; ++sidx) { + last_superframe_->encoded_frame.SetSpatialIndex(sidx); + DeliverEncodedFrame(last_superframe_->encoded_frame); + } + last_superframe_.reset(); + } + + const EncodedImage& superframe = + MakeSuperFrame(encoded_frame, codec_specific_info); + DeliverEncodedFrame(superframe); + + return Result(Result::Error::OK); + } + + void DeliverEncodedFrame(const EncodedImage& encoded_frame) { { MutexLock lock(&mutex_); auto it = callbacks_.find(encoded_frame.RtpTimestamp()); @@ -922,23 +1007,30 @@ class Encoder : public EncodedImageCallback { } if (ivf_writer_ != nullptr) { - ivf_writer_->Write(encoded_frame); + ivf_writer_->Write(encoded_frame, codec_type_); } - - return Result(Result::Error::OK); } void Configure(const EncodingSettings& es) { - const LayerSettings& layer_settings = es.layers_settings.rbegin()->second; - const DataRate& bitrate = layer_settings.bitrate; + const LayerSettings& top_layer_settings = + es.layers_settings.rbegin()->second; + const int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(es.scalability_mode); + const int num_temporal_layers = + ScalabilityModeToNumTemporalLayers(es.scalability_mode); + DataRate total_bitrate = std::accumulate( + es.layers_settings.begin(), es.layers_settings.end(), DataRate::Zero(), + [](DataRate acc, const std::pair layer) { + return acc + layer.second.bitrate; + }); VideoCodec vc; - vc.width = layer_settings.resolution.width; - vc.height = layer_settings.resolution.height; - vc.startBitrate = bitrate.kbps(); - vc.maxBitrate = bitrate.kbps(); + vc.width = top_layer_settings.resolution.width; + vc.height = top_layer_settings.resolution.height; + vc.startBitrate = total_bitrate.kbps(); + vc.maxBitrate = total_bitrate.kbps(); vc.minBitrate = 0; - vc.maxFramerate = layer_settings.framerate.hertz(); + vc.maxFramerate = top_layer_settings.framerate.hertz(); vc.active = true; vc.numberOfSimulcastStreams = 0; vc.mode = webrtc::VideoCodecMode::kRealtimeVideo; @@ -950,10 +1042,11 @@ class Encoder : public EncodedImageCallback { switch (vc.codecType) { case kVideoCodecVP8: *(vc.VP8()) = VideoEncoder::GetDefaultVp8Settings(); - vc.VP8()->SetNumberOfTemporalLayers( - ScalabilityModeToNumTemporalLayers(es.scalability_mode)); + vc.VP8()->SetNumberOfTemporalLayers(num_temporal_layers); + vc.SetScalabilityMode(std::vector{ + ScalabilityMode::kL1T1, ScalabilityMode::kL1T2, + ScalabilityMode::kL1T3}[num_temporal_layers - 1]); vc.qpMax = cricket::kDefaultVideoMaxQpVpx; - // TODO(webrtc:14852): Configure simulcast. break; case kVideoCodecVP9: *(vc.VP9()) = VideoEncoder::GetDefaultVp9Settings(); @@ -966,6 +1059,7 @@ class Encoder : public EncodedImageCallback { break; case kVideoCodecH264: *(vc.H264()) = VideoEncoder::GetDefaultH264Settings(); + vc.H264()->SetNumberOfTemporalLayers(num_temporal_layers); vc.qpMax = cricket::kDefaultVideoMaxQpH26x; break; case kVideoCodecH265: @@ -977,6 +1071,36 @@ class Encoder : public EncodedImageCallback { break; } + bool is_simulcast = + num_spatial_layers > 1 && + (vc.codecType == kVideoCodecVP8 || vc.codecType == kVideoCodecH264 || + vc.codecType == kVideoCodecH265); + if (is_simulcast) { + vc.numberOfSimulcastStreams = num_spatial_layers; + for (int sidx = 0; sidx < num_spatial_layers; ++sidx) { + auto tl0_settings = es.layers_settings.find( + LayerId{.spatial_idx = sidx, .temporal_idx = 0}); + auto tlx_settings = es.layers_settings.find(LayerId{ + .spatial_idx = sidx, .temporal_idx = num_temporal_layers - 1}); + DataRate total_bitrate = std::accumulate( + tl0_settings, tlx_settings, DataRate::Zero(), + [](DataRate acc, + const std::pair layer) { + return acc + layer.second.bitrate; + }); + SimulcastStream& ss = vc.simulcastStream[sidx]; + ss.width = tl0_settings->second.resolution.width; + ss.height = tl0_settings->second.resolution.height; + ss.numberOfTemporalLayers = num_temporal_layers; + ss.maxBitrate = total_bitrate.kbps(); + ss.targetBitrate = total_bitrate.kbps(); + ss.minBitrate = 0; + ss.maxFramerate = vc.maxFramerate; + ss.qpMax = vc.qpMax; + ss.active = true; + } + } + VideoEncoder::Settings ves( VideoEncoder::Capabilities(/*loss_notification=*/false), /*number_of_cores=*/1, @@ -1021,6 +1145,52 @@ class Encoder : public EncodedImageCallback { return true; } + static bool IsSvc(const EncodedImage& encoded_frame, + const CodecSpecificInfo& codec_specific_info) { + if (!codec_specific_info.scalability_mode) { + return false; + } + ScalabilityMode scalability_mode = *codec_specific_info.scalability_mode; + return (kFullSvcScalabilityModes.count(scalability_mode) || + (kKeySvcScalabilityModes.count(scalability_mode) && + encoded_frame.FrameType() == VideoFrameType::kVideoFrameKey)); + } + + const EncodedImage& MakeSuperFrame( + const EncodedImage& encoded_frame, + const CodecSpecificInfo* codec_specific_info) { + if (last_superframe_) { + // Append to base spatial layer frame(s). + RTC_CHECK_EQ(*encoded_frame.SpatialIndex(), + *last_superframe_->encoded_frame.SpatialIndex() + 1) + << "Inter-layer frame drops are not supported."; + size_t current_size = last_superframe_->encoded_data->size(); + last_superframe_->encoded_data->Realloc(current_size + + encoded_frame.size()); + memcpy(last_superframe_->encoded_data->data() + current_size, + encoded_frame.data(), encoded_frame.size()); + last_superframe_->encoded_frame.SetEncodedData( + last_superframe_->encoded_data); + last_superframe_->encoded_frame.SetSpatialIndex( + encoded_frame.SpatialIndex()); + return last_superframe_->encoded_frame; + } + + RTC_CHECK(codec_specific_info != nullptr); + if (IsSvc(encoded_frame, *codec_specific_info)) { + last_superframe_ = Superframe{ + .encoded_frame = EncodedImage(encoded_frame), + .encoded_data = EncodedImageBuffer::Create(encoded_frame.data(), + encoded_frame.size()), + .scalability_mode = *codec_specific_info->scalability_mode}; + last_superframe_->encoded_frame.SetEncodedData( + last_superframe_->encoded_data); + return last_superframe_->encoded_frame; + } + + return encoded_frame; + } + VideoEncoderFactory* const encoder_factory_; std::unique_ptr encoder_; VideoCodecAnalyzer* const analyzer_; @@ -1032,9 +1202,62 @@ class Encoder : public EncodedImageCallback { std::unique_ptr ivf_writer_; std::map sidx_ RTC_GUARDED_BY(mutex_); std::map callbacks_ RTC_GUARDED_BY(mutex_); + VideoCodecType codec_type_; + absl::optional last_superframe_; Mutex mutex_; }; +void ConfigureSimulcast(VideoCodec* vc) { + int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(*vc->GetScalabilityMode()); + int num_temporal_layers = + ScalabilityModeToNumTemporalLayers(*vc->GetScalabilityMode()); + + if (num_spatial_layers == 1) { + SimulcastStream* ss = &vc->simulcastStream[0]; + ss->width = vc->width; + ss->height = vc->height; + ss->numberOfTemporalLayers = num_temporal_layers; + ss->maxBitrate = vc->maxBitrate; + ss->targetBitrate = vc->maxBitrate; + ss->minBitrate = vc->minBitrate; + ss->qpMax = vc->qpMax; + ss->active = true; + return; + } + + ScopedKeyValueConfig field_trials((rtc::StringBuilder() + << "WebRTC-VP8ConferenceTemporalLayers/" + << num_temporal_layers << "/") + .str()); + + const std::vector streams = cricket::GetSimulcastConfig( + /*min_layer=*/1, num_spatial_layers, vc->width, vc->height, + /*bitrate_priority=*/1.0, cricket::kDefaultVideoMaxQpVpx, + /*is_screenshare=*/false, /*temporal_layers_supported=*/true, + field_trials); + + vc->numberOfSimulcastStreams = streams.size(); + RTC_CHECK_LE(vc->numberOfSimulcastStreams, num_spatial_layers); + if (vc->numberOfSimulcastStreams < num_spatial_layers) { + vc->SetScalabilityMode(LimitNumSpatialLayers(*vc->GetScalabilityMode(), + vc->numberOfSimulcastStreams)); + } + + for (int i = 0; i < vc->numberOfSimulcastStreams; ++i) { + SimulcastStream* ss = &vc->simulcastStream[i]; + ss->width = streams[i].width; + ss->height = streams[i].height; + RTC_CHECK_EQ(*streams[i].num_temporal_layers, num_temporal_layers); + ss->numberOfTemporalLayers = *streams[i].num_temporal_layers; + ss->maxBitrate = streams[i].max_bitrate_bps / 1000; + ss->targetBitrate = streams[i].target_bitrate_bps / 1000; + ss->minBitrate = streams[i].min_bitrate_bps / 1000; + ss->qpMax = streams[i].max_qp; + ss->active = true; + } +} + std::tuple, ScalabilityMode> SplitBitrateAndUpdateScalabilityMode(std::string codec_type, ScalabilityMode scalability_mode, @@ -1075,8 +1298,7 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type, // TODO(webrtc:14852): Configure simulcast. *(vc.VP8()) = VideoEncoder::GetDefaultVp8Settings(); vc.VP8()->SetNumberOfTemporalLayers(num_temporal_layers); - vc.simulcastStream[0].width = vc.width; - vc.simulcastStream[0].height = vc.height; + ConfigureSimulcast(&vc); break; case kVideoCodecVP9: { *(vc.VP9()) = VideoEncoder::GetDefaultVp9Settings(); @@ -1095,6 +1317,7 @@ SplitBitrateAndUpdateScalabilityMode(std::string codec_type, case kVideoCodecH264: { *(vc.H264()) = VideoEncoder::GetDefaultH264Settings(); vc.H264()->SetNumberOfTemporalLayers(num_temporal_layers); + ConfigureSimulcast(&vc); } break; case kVideoCodecH265: break; @@ -1227,14 +1450,24 @@ std::map VideoCodecTester::CreateEncodingSettings( } } + SdpVideoFormat sdp_video_format = SdpVideoFormat(codec_type); + if (codec_type == "H264") { + const std::string packetization_mode = + "1"; // H264PacketizationMode::SingleNalUnit + sdp_video_format.parameters = + CreateH264Format(H264Profile::kProfileConstrainedBaseline, + H264Level::kLevel3_1, packetization_mode, + /*add_scalability_modes=*/false) + .parameters; + } + std::map frames_settings; uint32_t timestamp_rtp = first_timestamp_rtp; for (int frame_num = 0; frame_num < num_frames; ++frame_num) { frames_settings.emplace( - timestamp_rtp, - EncodingSettings{.sdp_video_format = SdpVideoFormat(codec_type), - .scalability_mode = scalability_mode, - .layers_settings = layers_settings}); + timestamp_rtp, EncodingSettings{.sdp_video_format = sdp_video_format, + .scalability_mode = scalability_mode, + .layers_settings = layers_settings}); timestamp_rtp += k90kHz / Frequency::MilliHertz(1000 * framerate_fps); } @@ -1298,10 +1531,19 @@ VideoCodecTester::RunEncodeDecodeTest( VideoSource video_source(source_settings); std::unique_ptr analyzer = std::make_unique(&video_source); - Decoder decoder(decoder_factory, decoder_settings, analyzer.get()); + const EncodingSettings& frame_settings = encoding_settings.begin()->second; Encoder encoder(encoder_factory, encoder_settings, analyzer.get()); - encoder.Initialize(encoding_settings.begin()->second); - decoder.Initialize(encoding_settings.begin()->second.sdp_video_format); + encoder.Initialize(frame_settings); + + int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(frame_settings.scalability_mode); + std::vector> decoders; + for (int sidx = 0; sidx < num_spatial_layers; ++sidx) { + auto decoder = std::make_unique(decoder_factory, decoder_settings, + analyzer.get()); + decoder->Initialize(frame_settings.sdp_video_format); + decoders.push_back(std::move(decoder)); + } for (const auto& [timestamp_rtp, frame_settings] : encoding_settings) { const EncodingSettings::LayerSettings& top_layer = @@ -1309,13 +1551,17 @@ VideoCodecTester::RunEncodeDecodeTest( VideoFrame source_frame = video_source.PullFrame( timestamp_rtp, top_layer.resolution, top_layer.framerate); encoder.Encode(source_frame, frame_settings, - [&decoder](const EncodedImage& encoded_frame) { - decoder.Decode(encoded_frame); + [&decoders](const EncodedImage& encoded_frame) { + int sidx = encoded_frame.SpatialIndex().value_or( + encoded_frame.SimulcastIndex().value_or(0)); + decoders.at(sidx)->Decode(encoded_frame); }); } encoder.Flush(); - decoder.Flush(); + for (auto& decoder : decoders) { + decoder->Flush(); + } analyzer->Flush(); return std::move(analyzer); } diff --git a/third_party/libwebrtc/test/video_codec_tester_unittest.cc b/third_party/libwebrtc/test/video_codec_tester_unittest.cc index af31fe2c13..df5dca90a2 100644 --- a/third_party/libwebrtc/test/video_codec_tester_unittest.cc +++ b/third_party/libwebrtc/test/video_codec_tester_unittest.cc @@ -22,9 +22,14 @@ #include "api/test/mock_video_encoder.h" #include "api/test/mock_video_encoder_factory.h" #include "api/units/data_rate.h" +#include "api/units/data_size.h" +#include "api/units/frequency.h" #include "api/units/time_delta.h" #include "api/video/i420_buffer.h" #include "api/video/video_frame.h" +#include "api/video_codecs/scalability_mode.h" +#include "api/video_codecs/video_decoder.h" +#include "api/video_codecs/video_encoder.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/svc/scalability_mode_util.h" #include "test/gmock.h" @@ -44,6 +49,8 @@ using ::testing::InvokeWithoutArgs; using ::testing::NiceMock; using ::testing::Return; using ::testing::SizeIs; +using ::testing::UnorderedElementsAreArray; +using ::testing::Values; using VideoCodecStats = VideoCodecTester::VideoCodecStats; using VideoSourceSettings = VideoCodecTester::VideoSourceSettings; @@ -77,14 +84,19 @@ rtc::scoped_refptr CreateYuvBuffer(uint8_t y = 0, return buffer; } +// TODO(ssilkin): Wrap this into a class that removes file in dtor. std::string CreateYuvFile(int width, int height, int num_frames) { std::string path = webrtc::test::TempFilename(webrtc::test::OutputPath(), "video_codec_tester_unittest"); FILE* file = fopen(path.c_str(), "wb"); for (int frame_num = 0; frame_num < num_frames; ++frame_num) { - uint8_t y = (frame_num + 0) & 255; - uint8_t u = (frame_num + 1) & 255; - uint8_t v = (frame_num + 2) & 255; + // For purposes of testing quality estimation, we need Y, U, V values in + // source and decoded video to be unique and deterministic. In source video + // we make them functions of frame number. The test decoder makes them + // functions of encoded frame size in decoded video. + uint8_t y = (frame_num * 3 + 0) & 255; + uint8_t u = (frame_num * 3 + 1) & 255; + uint8_t v = (frame_num * 3 + 2) & 255; rtc::scoped_refptr buffer = CreateYuvBuffer(y, u, v); fwrite(buffer->DataY(), 1, width * height, file); int chroma_size_bytes = (width + 1) / 2 * (height + 1) / 2; @@ -95,115 +107,161 @@ std::string CreateYuvFile(int width, int height, int num_frames) { return path; } -std::unique_ptr RunTest(std::vector> frames, - ScalabilityMode scalability_mode) { - int num_frames = static_cast(frames.size()); - std::string source_yuv_path = CreateYuvFile(kWidth, kHeight, num_frames); - VideoSourceSettings source_settings{ - .file_path = source_yuv_path, - .resolution = {.width = kWidth, .height = kHeight}, - .framerate = kTargetFramerate}; +class TestVideoEncoder : public MockVideoEncoder { + public: + TestVideoEncoder(ScalabilityMode scalability_mode, + std::vector> encoded_frames) + : scalability_mode_(scalability_mode), encoded_frames_(encoded_frames) {} + int32_t Encode(const VideoFrame& input_frame, + const std::vector*) override { + for (const Frame& frame : encoded_frames_[num_encoded_frames_]) { + if (frame.frame_size.IsZero()) { + continue; // Frame drop. + } + EncodedImage encoded_frame; + encoded_frame._encodedWidth = frame.width; + encoded_frame._encodedHeight = frame.height; + encoded_frame.SetFrameType(frame.keyframe + ? VideoFrameType::kVideoFrameKey + : VideoFrameType::kVideoFrameDelta); + encoded_frame.SetRtpTimestamp(input_frame.timestamp()); + encoded_frame.SetSpatialIndex(frame.layer_id.spatial_idx); + encoded_frame.SetTemporalIndex(frame.layer_id.temporal_idx); + encoded_frame.SetEncodedData( + EncodedImageBuffer::Create(frame.frame_size.bytes())); + CodecSpecificInfo codec_specific_info; + codec_specific_info.scalability_mode = scalability_mode_; + callback_->OnEncodedImage(encoded_frame, &codec_specific_info); + } + ++num_encoded_frames_; + return WEBRTC_VIDEO_CODEC_OK; + } - int num_encoded_frames = 0; - EncodedImageCallback* encoded_frame_callback; - NiceMock encoder_factory; - ON_CALL(encoder_factory, CreateVideoEncoder) - .WillByDefault([&](const SdpVideoFormat&) { - auto encoder = std::make_unique>(); - ON_CALL(*encoder, RegisterEncodeCompleteCallback) - .WillByDefault([&](EncodedImageCallback* callback) { - encoded_frame_callback = callback; - return WEBRTC_VIDEO_CODEC_OK; - }); - ON_CALL(*encoder, Encode) - .WillByDefault([&](const VideoFrame& input_frame, - const std::vector*) { - for (const Frame& frame : frames[num_encoded_frames]) { - EncodedImage encoded_frame; - encoded_frame._encodedWidth = frame.width; - encoded_frame._encodedHeight = frame.height; - encoded_frame.SetFrameType( - frame.keyframe ? VideoFrameType::kVideoFrameKey - : VideoFrameType::kVideoFrameDelta); - encoded_frame.SetRtpTimestamp(input_frame.timestamp()); - encoded_frame.SetSpatialIndex(frame.layer_id.spatial_idx); - encoded_frame.SetTemporalIndex(frame.layer_id.temporal_idx); - encoded_frame.SetEncodedData( - EncodedImageBuffer::Create(frame.frame_size.bytes())); - encoded_frame_callback->OnEncodedImage( - encoded_frame, - /*codec_specific_info=*/nullptr); - } - ++num_encoded_frames; - return WEBRTC_VIDEO_CODEC_OK; - }); - return encoder; - }); + int32_t RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) override { + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; + } - int num_decoded_frames = 0; - DecodedImageCallback* decode_callback; - NiceMock decoder_factory; - ON_CALL(decoder_factory, CreateVideoDecoder) - .WillByDefault([&](const SdpVideoFormat&) { - auto decoder = std::make_unique>(); - ON_CALL(*decoder, RegisterDecodeCompleteCallback) - .WillByDefault([&](DecodedImageCallback* callback) { - decode_callback = callback; - return WEBRTC_VIDEO_CODEC_OK; - }); - ON_CALL(*decoder, Decode(_, _)) - .WillByDefault([&](const EncodedImage& encoded_frame, int64_t) { - // Make values to be different from source YUV generated in - // `CreateYuvFile`. - uint8_t y = ((num_decoded_frames + 1) * 2) & 255; - uint8_t u = ((num_decoded_frames + 2) * 2) & 255; - uint8_t v = ((num_decoded_frames + 3) * 2) & 255; - rtc::scoped_refptr frame_buffer = - CreateYuvBuffer(y, u, v); - VideoFrame decoded_frame = - VideoFrame::Builder() - .set_video_frame_buffer(frame_buffer) - .set_timestamp_rtp(encoded_frame.RtpTimestamp()) - .build(); - decode_callback->Decoded(decoded_frame); - ++num_decoded_frames; - return WEBRTC_VIDEO_CODEC_OK; - }); - return decoder; - }); + private: + ScalabilityMode scalability_mode_; + std::vector> encoded_frames_; + int num_encoded_frames_ = 0; + EncodedImageCallback* callback_; +}; + +class TestVideoDecoder : public MockVideoDecoder { + public: + int32_t Decode(const EncodedImage& encoded_frame, int64_t) { + uint8_t y = (encoded_frame.size() + 0) & 255; + uint8_t u = (encoded_frame.size() + 2) & 255; + uint8_t v = (encoded_frame.size() + 4) & 255; + rtc::scoped_refptr frame_buffer = CreateYuvBuffer(y, u, v); + VideoFrame decoded_frame = + VideoFrame::Builder() + .set_video_frame_buffer(frame_buffer) + .set_timestamp_rtp(encoded_frame.RtpTimestamp()) + .build(); + callback_->Decoded(decoded_frame); + frame_sizes_.push_back(DataSize::Bytes(encoded_frame.size())); + return WEBRTC_VIDEO_CODEC_OK; + } - int num_spatial_layers = ScalabilityModeToNumSpatialLayers(scalability_mode); - int num_temporal_layers = - ScalabilityModeToNumTemporalLayers(scalability_mode); + int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback) { + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; + } - std::map encoding_settings; - for (int frame_num = 0; frame_num < num_frames; ++frame_num) { - std::map layers_settings; - for (int sidx = 0; sidx < num_spatial_layers; ++sidx) { - for (int tidx = 0; tidx < num_temporal_layers; ++tidx) { - layers_settings.emplace( - LayerId{.spatial_idx = sidx, .temporal_idx = tidx}, - LayerSettings{.resolution = {.width = kWidth, .height = kHeight}, - .framerate = kTargetFramerate / - (1 << (num_temporal_layers - 1 - tidx)), - .bitrate = kTargetLayerBitrate}); + const std::vector& frame_sizes() const { return frame_sizes_; } + + private: + DecodedImageCallback* callback_; + std::vector frame_sizes_; +}; + +class VideoCodecTesterTest : public ::testing::Test { + public: + std::unique_ptr RunEncodeDecodeTest( + std::string codec_type, + ScalabilityMode scalability_mode, + std::vector> encoded_frames) { + int num_frames = encoded_frames.size(); + std::string yuv_path = CreateYuvFile(kWidth, kHeight, num_frames); + VideoSourceSettings video_source_settings{ + .file_path = yuv_path, + .resolution = {.width = kWidth, .height = kHeight}, + .framerate = kTargetFramerate}; + + NiceMock encoder_factory; + ON_CALL(encoder_factory, CreateVideoEncoder) + .WillByDefault([&](const SdpVideoFormat&) { + return std::make_unique>(scalability_mode, + encoded_frames); + }); + + NiceMock decoder_factory; + ON_CALL(decoder_factory, CreateVideoDecoder) + .WillByDefault([&](const SdpVideoFormat&) { + // Video codec tester destroyes decoder at the end of test. Test + // decoder collects stats which we need to access after test. To keep + // the decode alive we wrap it into a wrapper and pass the wrapper to + // the tester. + class DecoderWrapper : public TestVideoDecoder { + public: + explicit DecoderWrapper(TestVideoDecoder* decoder) + : decoder_(decoder) {} + int32_t Decode(const EncodedImage& encoded_frame, + int64_t render_time_ms) { + return decoder_->Decode(encoded_frame, render_time_ms); + } + int32_t RegisterDecodeCompleteCallback( + DecodedImageCallback* callback) { + return decoder_->RegisterDecodeCompleteCallback(callback); + } + TestVideoDecoder* decoder_; + }; + decoders_.push_back(std::make_unique>()); + return std::make_unique>( + decoders_.back().get()); + }); + + int num_spatial_layers = + ScalabilityModeToNumSpatialLayers(scalability_mode); + int num_temporal_layers = + ScalabilityModeToNumTemporalLayers(scalability_mode); + std::map encoding_settings; + for (int frame_num = 0; frame_num < num_frames; ++frame_num) { + std::map layers_settings; + for (int sidx = 0; sidx < num_spatial_layers; ++sidx) { + for (int tidx = 0; tidx < num_temporal_layers; ++tidx) { + layers_settings.emplace( + LayerId{.spatial_idx = sidx, .temporal_idx = tidx}, + LayerSettings{ + .resolution = {.width = kWidth, .height = kHeight}, + .framerate = kTargetFramerate / + (1 << (num_temporal_layers - 1 - tidx)), + .bitrate = kTargetLayerBitrate}); + } } + encoding_settings.emplace( + encoded_frames[frame_num].front().timestamp_rtp, + EncodingSettings{.sdp_video_format = SdpVideoFormat(codec_type), + .scalability_mode = scalability_mode, + .layers_settings = layers_settings}); } - encoding_settings.emplace( - frames[frame_num][0].timestamp_rtp, - EncodingSettings{.scalability_mode = scalability_mode, - .layers_settings = layers_settings}); + + std::unique_ptr stats = + VideoCodecTester::RunEncodeDecodeTest( + video_source_settings, &encoder_factory, &decoder_factory, + EncoderSettings{}, DecoderSettings{}, encoding_settings); + + remove(yuv_path.c_str()); + return stats; } - EncoderSettings encoder_settings; - DecoderSettings decoder_settings; - std::unique_ptr stats = - VideoCodecTester::RunEncodeDecodeTest( - source_settings, &encoder_factory, &decoder_factory, encoder_settings, - decoder_settings, encoding_settings); - remove(source_yuv_path.c_str()); - return stats; -} + protected: + std::vector> decoders_; +}; EncodedImage CreateEncodedImage(uint32_t timestamp_rtp) { EncodedImage encoded_image; @@ -233,52 +291,63 @@ class MockCodedVideoSource : public CodedVideoSource { } // namespace -TEST(VideoCodecTester, Slice) { - std::unique_ptr stats = RunTest( - {{{.timestamp_rtp = 0, .layer_id = {.spatial_idx = 0, .temporal_idx = 0}}, - {.timestamp_rtp = 0, - .layer_id = {.spatial_idx = 1, .temporal_idx = 0}}}, - {{.timestamp_rtp = 1, - .layer_id = {.spatial_idx = 0, .temporal_idx = 1}}}}, - ScalabilityMode::kL2T2); +TEST_F(VideoCodecTesterTest, Slice) { + std::unique_ptr stats = + RunEncodeDecodeTest("VP9", ScalabilityMode::kL2T2, + {{{.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(1)}, + {.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 1, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(2)}}, + {{.timestamp_rtp = 1, + .layer_id = {.spatial_idx = 0, .temporal_idx = 1}, + .frame_size = DataSize::Bytes(3)}}}); std::vector slice = stats->Slice(Filter{}, /*merge=*/false); - EXPECT_THAT(slice, ElementsAre(Field(&Frame::timestamp_rtp, 0), - Field(&Frame::timestamp_rtp, 0), - Field(&Frame::timestamp_rtp, 1))); + EXPECT_THAT(slice, + ElementsAre(Field(&Frame::frame_size, DataSize::Bytes(1)), + Field(&Frame::frame_size, DataSize::Bytes(2)), + Field(&Frame::frame_size, DataSize::Bytes(3)), + Field(&Frame::frame_size, DataSize::Bytes(0)))); slice = stats->Slice({.min_timestamp_rtp = 1}, /*merge=*/false); - EXPECT_THAT(slice, ElementsAre(Field(&Frame::timestamp_rtp, 1))); + EXPECT_THAT(slice, + ElementsAre(Field(&Frame::frame_size, DataSize::Bytes(3)), + Field(&Frame::frame_size, DataSize::Bytes(0)))); slice = stats->Slice({.max_timestamp_rtp = 0}, /*merge=*/false); - EXPECT_THAT(slice, ElementsAre(Field(&Frame::timestamp_rtp, 0), - Field(&Frame::timestamp_rtp, 0))); + EXPECT_THAT(slice, + ElementsAre(Field(&Frame::frame_size, DataSize::Bytes(1)), + Field(&Frame::frame_size, DataSize::Bytes(2)))); slice = stats->Slice({.layer_id = {{.spatial_idx = 0, .temporal_idx = 0}}}, /*merge=*/false); - EXPECT_THAT(slice, ElementsAre(Field(&Frame::timestamp_rtp, 0))); + EXPECT_THAT(slice, + ElementsAre(Field(&Frame::frame_size, DataSize::Bytes(1)))); slice = stats->Slice({.layer_id = {{.spatial_idx = 0, .temporal_idx = 1}}}, /*merge=*/false); - EXPECT_THAT(slice, ElementsAre(Field(&Frame::timestamp_rtp, 0), - Field(&Frame::timestamp_rtp, 1))); + EXPECT_THAT(slice, + ElementsAre(Field(&Frame::frame_size, DataSize::Bytes(1)), + Field(&Frame::frame_size, DataSize::Bytes(3)))); } -TEST(VideoCodecTester, Merge) { +TEST_F(VideoCodecTesterTest, Merge) { std::unique_ptr stats = - RunTest({{{.timestamp_rtp = 0, - .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, - .frame_size = DataSize::Bytes(1), - .keyframe = true}, - {.timestamp_rtp = 0, - .layer_id = {.spatial_idx = 1, .temporal_idx = 0}, - .frame_size = DataSize::Bytes(2)}}, - {{.timestamp_rtp = 1, - .layer_id = {.spatial_idx = 0, .temporal_idx = 1}, - .frame_size = DataSize::Bytes(4)}, - {.timestamp_rtp = 1, - .layer_id = {.spatial_idx = 1, .temporal_idx = 1}, - .frame_size = DataSize::Bytes(8)}}}, - ScalabilityMode::kL2T2_KEY); + RunEncodeDecodeTest("VP8", ScalabilityMode::kL2T2_KEY, + {{{.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(1), + .keyframe = true}, + {.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 1, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(2)}}, + {{.timestamp_rtp = 1, + .layer_id = {.spatial_idx = 0, .temporal_idx = 1}, + .frame_size = DataSize::Bytes(4)}, + {.timestamp_rtp = 1, + .layer_id = {.spatial_idx = 1, .temporal_idx = 1}, + .frame_size = DataSize::Bytes(8)}}}); std::vector slice = stats->Slice(Filter{}, /*merge=*/true); EXPECT_THAT( @@ -300,33 +369,34 @@ struct AggregationTestParameters { }; class VideoCodecTesterTestAggregation - : public ::testing::TestWithParam {}; + : public VideoCodecTesterTest, + public ::testing::WithParamInterface {}; TEST_P(VideoCodecTesterTestAggregation, Aggregate) { AggregationTestParameters test_params = GetParam(); std::unique_ptr stats = - RunTest({{// L0T0 - {.timestamp_rtp = 0, - .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, - .frame_size = DataSize::Bytes(1), - .keyframe = true}, - // L1T0 - {.timestamp_rtp = 0, - .layer_id = {.spatial_idx = 1, .temporal_idx = 0}, - .frame_size = DataSize::Bytes(2)}}, - // Emulate frame drop (frame_size = 0). - {{.timestamp_rtp = 3000, - .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, - .frame_size = DataSize::Zero()}}, - {// L0T1 - {.timestamp_rtp = 87000, - .layer_id = {.spatial_idx = 0, .temporal_idx = 1}, - .frame_size = DataSize::Bytes(4)}, - // L1T1 - {.timestamp_rtp = 87000, - .layer_id = {.spatial_idx = 1, .temporal_idx = 1}, - .frame_size = DataSize::Bytes(8)}}}, - ScalabilityMode::kL2T2_KEY); + RunEncodeDecodeTest("VP8", ScalabilityMode::kL2T2_KEY, + {{// L0T0 + {.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(1), + .keyframe = true}, + // L1T0 + {.timestamp_rtp = 0, + .layer_id = {.spatial_idx = 1, .temporal_idx = 0}, + .frame_size = DataSize::Bytes(2)}}, + // Emulate frame drop (frame_size = 0). + {{.timestamp_rtp = 3000, + .layer_id = {.spatial_idx = 0, .temporal_idx = 0}, + .frame_size = DataSize::Zero()}}, + {// L0T1 + {.timestamp_rtp = 87000, + .layer_id = {.spatial_idx = 0, .temporal_idx = 1}, + .frame_size = DataSize::Bytes(4)}, + // L1T1 + {.timestamp_rtp = 87000, + .layer_id = {.spatial_idx = 1, .temporal_idx = 1}, + .frame_size = DataSize::Bytes(8)}}}); Stream stream = stats->Aggregate(test_params.filter); EXPECT_EQ(stream.keyframe.GetSum(), test_params.expected_keyframe_sum); @@ -343,7 +413,7 @@ TEST_P(VideoCodecTesterTestAggregation, Aggregate) { INSTANTIATE_TEST_SUITE_P( All, VideoCodecTesterTestAggregation, - ::testing::Values( + Values( // No filtering. AggregationTestParameters{ .filter = {}, @@ -400,11 +470,11 @@ INSTANTIATE_TEST_SUITE_P( .expected_framerate_mismatch_pct = 100 * (2.0 / kTargetFramerate.hertz() - 1)})); -TEST(VideoCodecTester, Psnr) { - std::unique_ptr stats = - RunTest({{{.timestamp_rtp = 0, .frame_size = DataSize::Bytes(1)}}, - {{.timestamp_rtp = 3000, .frame_size = DataSize::Bytes(1)}}}, - ScalabilityMode::kL1T1); +TEST_F(VideoCodecTesterTest, Psnr) { + std::unique_ptr stats = RunEncodeDecodeTest( + "VP8", ScalabilityMode::kL1T1, + {{{.timestamp_rtp = 0, .frame_size = DataSize::Bytes(2)}}, + {{.timestamp_rtp = 3000, .frame_size = DataSize::Bytes(6)}}}); std::vector slice = stats->Slice(Filter{}, /*merge=*/false); ASSERT_THAT(slice, SizeIs(2)); @@ -418,6 +488,107 @@ TEST(VideoCodecTester, Psnr) { EXPECT_NEAR(slice[1].psnr->v, 34, 1); } +struct ScalabilityTestParameters { + std::string codec_type; + ScalabilityMode scalability_mode; + // Temporal unit -> spatial layer -> frame size. + std::vector> encoded_frame_sizes; + std::vector expected_decode_frame_sizes; +}; + +class VideoCodecTesterTestScalability + : public VideoCodecTesterTest, + public ::testing::WithParamInterface {}; + +TEST_P(VideoCodecTesterTestScalability, EncodeDecode) { + ScalabilityTestParameters test_params = GetParam(); + std::vector> frames; + for (size_t frame_num = 0; frame_num < test_params.encoded_frame_sizes.size(); + ++frame_num) { + std::vector temporal_unit; + for (auto [sidx, frame_size] : test_params.encoded_frame_sizes[frame_num]) { + temporal_unit.push_back( + Frame{.timestamp_rtp = static_cast(3000 * frame_num), + .layer_id = {.spatial_idx = sidx, .temporal_idx = 0}, + .frame_size = frame_size, + .keyframe = (frame_num == 0 && sidx == 0)}); + } + frames.push_back(temporal_unit); + } + RunEncodeDecodeTest(test_params.codec_type, test_params.scalability_mode, + frames); + + size_t num_spatial_layers = + ScalabilityModeToNumSpatialLayers(test_params.scalability_mode); + EXPECT_EQ(num_spatial_layers, decoders_.size()); + + // Collect input frame sizes from all decoders. + std::vector decode_frame_sizes; + for (const auto& decoder : decoders_) { + const auto& frame_sizes = decoder->frame_sizes(); + decode_frame_sizes.insert(decode_frame_sizes.end(), frame_sizes.begin(), + frame_sizes.end()); + } + EXPECT_THAT(decode_frame_sizes, UnorderedElementsAreArray( + test_params.expected_decode_frame_sizes)); +} + +INSTANTIATE_TEST_SUITE_P( + All, + VideoCodecTesterTestScalability, + Values( + ScalabilityTestParameters{ + .codec_type = "VP8", + .scalability_mode = ScalabilityMode::kS2T1, + .encoded_frame_sizes = {{{0, DataSize::Bytes(1)}, + {1, DataSize::Bytes(2)}}, + {{0, DataSize::Bytes(4)}, + // Emulate frame drop. + {1, DataSize::Bytes(0)}}}, + .expected_decode_frame_sizes = {DataSize::Bytes(1), + DataSize::Bytes(2), + DataSize::Bytes(4)}, + }, + ScalabilityTestParameters{ + .codec_type = "VP9", + .scalability_mode = ScalabilityMode::kL2T1, + .encoded_frame_sizes = + {{{0, DataSize::Bytes(1)}, {1, DataSize::Bytes(2)}}, + {{0, DataSize::Bytes(4)}, {1, DataSize::Bytes(8)}}, + {{0, DataSize::Bytes(16)}, + // Emulate frame drop. + {1, DataSize::Bytes(0)}}}, + .expected_decode_frame_sizes = + {DataSize::Bytes(1), DataSize::Bytes(3), DataSize::Bytes(4), + DataSize::Bytes(12), DataSize::Bytes(16), DataSize::Bytes(16)}, + }, + ScalabilityTestParameters{ + .codec_type = "VP9", + .scalability_mode = ScalabilityMode::kL2T1_KEY, + .encoded_frame_sizes = + {{{0, DataSize::Bytes(1)}, {1, DataSize::Bytes(2)}}, + {{0, DataSize::Bytes(4)}, {1, DataSize::Bytes(8)}}, + {{0, DataSize::Bytes(16)}, + // Emulate frame drop. + {1, DataSize::Bytes(0)}}}, + .expected_decode_frame_sizes = + {DataSize::Bytes(1), DataSize::Bytes(3), DataSize::Bytes(4), + DataSize::Bytes(8), DataSize::Bytes(16)}, + }, + ScalabilityTestParameters{ + .codec_type = "VP9", + .scalability_mode = ScalabilityMode::kS2T1, + .encoded_frame_sizes = + {{{0, DataSize::Bytes(1)}, {1, DataSize::Bytes(2)}}, + {{0, DataSize::Bytes(4)}, {1, DataSize::Bytes(8)}}, + {{0, DataSize::Bytes(16)}, + // Emulate frame drop. + {1, DataSize::Bytes(0)}}}, + .expected_decode_frame_sizes = + {DataSize::Bytes(1), DataSize::Bytes(2), DataSize::Bytes(4), + DataSize::Bytes(8), DataSize::Bytes(16)}, + })); + class VideoCodecTesterTestPacing : public ::testing::TestWithParam> { public: @@ -428,15 +599,11 @@ class VideoCodecTesterTestPacing const Frequency kTargetFramerate = Frequency::Hertz(10); void SetUp() override { - source_yuv_file_path_ = webrtc::test::TempFilename( - webrtc::test::OutputPath(), "video_codec_tester_impl_unittest"); - FILE* file = fopen(source_yuv_file_path_.c_str(), "wb"); - for (int i = 0; i < 3 * kSourceWidth * kSourceHeight / 2; ++i) { - fwrite("x", 1, 1, file); - } - fclose(file); + source_yuv_file_path_ = CreateYuvFile(kSourceWidth, kSourceHeight, 1); } + void TearDown() override { remove(source_yuv_file_path_.c_str()); } + protected: std::string source_yuv_file_path_; }; @@ -498,7 +665,7 @@ TEST_P(VideoCodecTesterTestPacing, PaceDecode) { INSTANTIATE_TEST_SUITE_P( DISABLED_All, VideoCodecTesterTestPacing, - ::testing::Values( + Values( // No pacing. std::make_tuple(PacingSettings{.mode = PacingMode::kNoPacing}, /*expected_delta_ms=*/0), -- cgit v1.2.3