diff --git a/test/pc/e2e/analyzer/video/default_encoded_image_data_injector.h b/test/pc/e2e/analyzer/video/default_encoded_image_data_injector.h index 6ed87f5ec4..b60c214703 100644 --- a/test/pc/e2e/analyzer/video/default_encoded_image_data_injector.h +++ b/test/pc/e2e/analyzer/video/default_encoded_image_data_injector.h @@ -63,6 +63,8 @@ class DefaultEncodedImageDataInjector : public EncodedImageDataInjector, bool discard, const EncodedImage& source, int /*coding_entity_id*/) override; + + void Start(int expected_receivers_count) override {} EncodedImageExtractionResult ExtractData(const EncodedImage& source, int coding_entity_id) override; }; diff --git a/test/pc/e2e/analyzer/video/default_encoded_image_data_injector_unittest.cc b/test/pc/e2e/analyzer/video/default_encoded_image_data_injector_unittest.cc index 3ad978f66a..045a65520d 100644 --- a/test/pc/e2e/analyzer/video/default_encoded_image_data_injector_unittest.cc +++ b/test/pc/e2e/analyzer/video/default_encoded_image_data_injector_unittest.cc @@ -32,6 +32,7 @@ rtc::Buffer CreateBufferOfSizeNFilledWithValuesFromX(size_t n, uint8_t x) { TEST(DefaultEncodedImageDataInjector, InjectExtractDiscardFalse) { DefaultEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -50,6 +51,7 @@ TEST(DefaultEncodedImageDataInjector, InjectExtractDiscardFalse) { TEST(DefaultEncodedImageDataInjector, InjectExtractDiscardTrue) { DefaultEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -65,6 +67,7 @@ TEST(DefaultEncodedImageDataInjector, InjectExtractDiscardTrue) { TEST(DefaultEncodedImageDataInjector, Inject3Extract3) { DefaultEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); @@ -108,6 +111,7 @@ TEST(DefaultEncodedImageDataInjector, Inject3Extract3) { TEST(DefaultEncodedImageDataInjector, InjectExtractFromConcatenated) { DefaultEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); @@ -151,6 +155,7 @@ TEST(DefaultEncodedImageDataInjector, InjectExtractFromConcatenated) { TEST(DefaultEncodedImageDataInjector, InjectExtractFromConcatenatedAllDiscarded) { DefaultEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); diff --git a/test/pc/e2e/analyzer/video/encoded_image_data_injector.h b/test/pc/e2e/analyzer/video/encoded_image_data_injector.h index 8e218629fc..ddd6959b91 100644 --- a/test/pc/e2e/analyzer/video/encoded_image_data_injector.h +++ b/test/pc/e2e/analyzer/video/encoded_image_data_injector.h @@ -47,6 +47,11 @@ class EncodedImageDataExtractor { public: virtual ~EncodedImageDataExtractor() = default; + // Invoked by framework before any image will come to the extractor. + // |expected_receivers_count| is the expected amount of receivers for each + // encoded image. + virtual void Start(int expected_receivers_count) = 0; + // Returns encoded image id, extracted from payload and also encoded image // with its original payload. For concatenated spatial layers it should be the // same id. |coding_entity_id| is unique id of decoder or encoder. diff --git a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc index 8e7a511878..419a7be07f 100644 --- a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc +++ b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.cc @@ -95,16 +95,17 @@ EncodedImageExtractionResult SingleProcessEncodedImageDataInjector::ExtractData( { MutexLock lock(&lock_); auto ext_vector_it = extraction_cache_.find(next_id); - // TODO(titovartem) add support for receiving single frame multiple times - // when in simulcast key frame for another spatial stream can be received. RTC_CHECK(ext_vector_it != extraction_cache_.end()) << "Unknown frame_id=" << next_id; auto info_it = ext_vector_it->second.infos.find(sub_id); RTC_CHECK(info_it != ext_vector_it->second.infos.end()) << "Unknown sub_id=" << sub_id << " for frame_id=" << next_id; + info_it->second.received_count++; info = info_it->second; - ext_vector_it->second.infos.erase(info_it); + if (info.received_count == expected_receivers_count_) { + ext_vector_it->second.infos.erase(info_it); + } } // We need to discard encoded image only if all concatenated encoded images // have to be discarded. diff --git a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h index c70c25bc7d..8cf1bc4828 100644 --- a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h +++ b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h @@ -50,6 +50,11 @@ class SingleProcessEncodedImageDataInjector : public EncodedImageDataInjector, bool discard, const EncodedImage& source, int coding_entity_id) override; + + void Start(int expected_receivers_count) override { + MutexLock crit(&lock_); + expected_receivers_count_ = expected_receivers_count; + } EncodedImageExtractionResult ExtractData(const EncodedImage& source, int coding_entity_id) override; @@ -67,6 +72,8 @@ class SingleProcessEncodedImageDataInjector : public EncodedImageDataInjector, bool discard; // Data from first 3 bytes of origin encoded image's payload. uint8_t origin_data[ExtractionInfo::kUsedBufferSize]; + // Count of how many times this frame was received. + int received_count = 0; }; struct ExtractionInfoVector { @@ -79,6 +86,7 @@ class SingleProcessEncodedImageDataInjector : public EncodedImageDataInjector, }; Mutex lock_; + int expected_receivers_count_ RTC_GUARDED_BY(lock_); // Stores a mapping from frame id to extraction info for spatial layers // for this frame id. There can be a lot of them, because if frame was // dropped we can't clean it up, because we won't receive a signal on diff --git a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc index e25361e337..00197f32cf 100644 --- a/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc +++ b/test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector_unittest.cc @@ -28,10 +28,9 @@ rtc::Buffer CreateBufferOfSizeNFilledWithValuesFromX(size_t n, uint8_t x) { return buffer; } -} // namespace - TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardFalse) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -52,6 +51,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardFalse) { TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardTrue) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -69,6 +69,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractDiscardTrue) { TEST(SingleProcessEncodedImageDataInjector, InjectWithUnsetSpatialLayerSizes) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -94,6 +95,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectWithUnsetSpatialLayerSizes) { TEST(SingleProcessEncodedImageDataInjector, InjectWithZeroSpatialLayerSizes) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); @@ -122,6 +124,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectWithZeroSpatialLayerSizes) { TEST(SingleProcessEncodedImageDataInjector, Inject3Extract3) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); @@ -171,6 +174,7 @@ TEST(SingleProcessEncodedImageDataInjector, Inject3Extract3) { TEST(SingleProcessEncodedImageDataInjector, InjectExtractFromConcatenated) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); @@ -223,6 +227,7 @@ TEST(SingleProcessEncodedImageDataInjector, InjectExtractFromConcatenated) { TEST(SingleProcessEncodedImageDataInjector, InjectExtractFromConcatenatedAllDiscarded) { SingleProcessEncodedImageDataInjector injector; + injector.Start(1); rtc::Buffer buffer1 = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); rtc::Buffer buffer2 = CreateBufferOfSizeNFilledWithValuesFromX(10, 11); @@ -268,5 +273,72 @@ TEST(SingleProcessEncodedImageDataInjector, } } +TEST(SingleProcessEncodedImageDataInjector, InjectOnceExtractTwice) { + SingleProcessEncodedImageDataInjector injector; + injector.Start(2); + + rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); + + EncodedImage source(buffer.data(), 10, 10); + source.SetTimestamp(123456789); + + EncodedImageExtractionResult out = + injector.ExtractData(injector.InjectData(/*id=*/512, /*discard=*/false, + source, /*coding_entity_id=*/1), + /*coding_entity_id=*/2); + EXPECT_EQ(out.id, 512); + EXPECT_FALSE(out.discard); + EXPECT_EQ(out.image.size(), 10ul); + EXPECT_EQ(out.image.capacity(), 10ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(0).value_or(0), 0ul); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(out.image.data()[i], i + 1); + } + out = + injector.ExtractData(injector.InjectData(/*id=*/512, /*discard=*/false, + source, /*coding_entity_id=*/1), + 2); + EXPECT_EQ(out.id, 512); + EXPECT_FALSE(out.discard); + EXPECT_EQ(out.image.size(), 10ul); + EXPECT_EQ(out.image.capacity(), 10ul); + EXPECT_EQ(out.image.SpatialLayerFrameSize(0).value_or(0), 0ul); + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(out.image.data()[i], i + 1); + } +} + +// Death tests. +// Disabled on Android because death tests misbehave on Android, see +// base/test/gtest_util.h. +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +EncodedImage DeepCopyEncodedImage(const EncodedImage& source) { + EncodedImage copy = source; + copy.SetEncodedData(EncodedImageBuffer::Create(source.size())); + memcpy(copy.data(), source.data(), source.size()); + return copy; +} + +TEST(SingleProcessEncodedImageDataInjector, InjectOnceExtractMoreThenExpected) { + SingleProcessEncodedImageDataInjector injector; + injector.Start(2); + + rtc::Buffer buffer = CreateBufferOfSizeNFilledWithValuesFromX(10, 1); + + EncodedImage source(buffer.data(), 10, 10); + source.SetTimestamp(123456789); + + EncodedImage modified = injector.InjectData(/*id=*/512, /*discard=*/false, + source, /*coding_entity_id=*/1); + + injector.ExtractData(DeepCopyEncodedImage(modified), /*coding_entity_id=*/2); + injector.ExtractData(DeepCopyEncodedImage(modified), /*coding_entity_id=*/2); + EXPECT_DEATH(injector.ExtractData(DeepCopyEncodedImage(modified), + /*coding_entity_id=*/2), + "Unknown sub_id=0 for frame_id=512"); +} +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace } // namespace webrtc_pc_e2e } // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc index 48e65ef686..ebfb41697d 100644 --- a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc +++ b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc @@ -149,6 +149,7 @@ void VideoQualityAnalyzerInjectionHelper::Start( rtc::ArrayView peer_names, int max_threads_count) { analyzer_->Start(std::move(test_case_name), peer_names, max_threads_count); + extractor_->Start(peer_names.size()); } void VideoQualityAnalyzerInjectionHelper::OnStatsReports(