/* * Copyright (c) 2013 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.
*/
void ResetObservedSsrcs() {
MutexLock lock(&mutex_); // Do not clear the timestamp and picture_id, to ensure that we check // consistency between reinits and recreations.
num_packets_sent_.clear();
observed_ssrcs_.clear();
}
void SetMaxExpectedPictureIdGap(int max_expected_picture_id_gap) {
MutexLock lock(&mutex_);
max_expected_picture_id_gap_ = max_expected_picture_id_gap; // Expect smaller gap for `tl0_pic_idx` (running index for temporal_idx 0).
max_expected_tl0_idx_gap_ = max_expected_picture_id_gap_ / 2;
}
// Verify continuity and monotonicity of picture_id sequence. void VerifyPictureId(const ParsedPacket& current, const ParsedPacket& last) const
RTC_EXCLUSIVE_LOCKS_REQUIRED(&mutex_) { if (current.timestamp == last.timestamp) {
EXPECT_EQ(last.picture_id, current.picture_id); return; // Same frame.
}
// Packet belongs to a new frame. // Picture id should be increasing.
EXPECT_TRUE((AheadOf<uint16_t, kPictureIdWraparound>(current.picture_id,
last.picture_id)));
// Expect continuously increasing picture id. int diff = ForwardDiff<uint16_t, kPictureIdWraparound>(last.picture_id,
current.picture_id);
EXPECT_LE(diff - 1, max_expected_picture_id_gap_); if (diff > 2) { // If the VideoSendStream is destroyed, any frames still in queue is lost. // This can result in a two-frame gap, which will result in logs like // "packet transmission failed, no matching RTP module found, or // transmission error". // A larger gap is only possible for first frame after a recreation, i.e. // key frames.
EXPECT_EQ(VideoFrameType::kVideoFrameKey, current.frame_type);
}
}
// New frame with `temporal_idx` 0. // `tl0_pic_idx` should be increasing.
EXPECT_TRUE(AheadOf<uint8_t>(current.tl0_pic_idx, last.tl0_pic_idx));
// Expect continuously increasing idx. int diff = ForwardDiff<uint8_t>(last.tl0_pic_idx, current.tl0_pic_idx); if (diff > 1) { // If the VideoSendStream is destroyed, any frames still in queue is lost. // Gaps only possible for first frame after a recreation, i.e. key frames.
EXPECT_EQ(VideoFrameType::kVideoFrameKey, current.frame_type);
EXPECT_LE(diff - 1, max_expected_tl0_idx_gap_);
}
}
ParsedPacket parsed; if (!ParsePayload(packet.data(), packet.size(), &parsed)) return SEND_PACKET;
uint32_t ssrc = parsed.ssrc; if (last_observed_packet_.find(ssrc) != last_observed_packet_.end()) { // Compare to last packet.
VerifyPictureId(parsed, last_observed_packet_[ssrc]);
VerifyTl0Idx(parsed, last_observed_packet_[ssrc]);
}
last_observed_packet_[ssrc] = parsed;
// Pass the test when enough media packets have been received on all // streams. if (++num_packets_sent_[ssrc] >= kMinPacketsToObserve &&
observed_ssrcs_.find(ssrc) == observed_ssrcs_.end()) {
observed_ssrcs_.insert(ssrc); if (observed_ssrcs_.size() == num_ssrcs_to_observe_) {
observation_complete_.Set();
}
} return SEND_PACKET;
}
class PictureIdTest : public test::CallTest, public ::testing::WithParamInterface<size_t> { public:
PictureIdTest() : num_temporal_layers_(GetParam()) {}
// Always divide the same total bitrate across all streams so that sending a // single stream avoids lowering the bitrate estimate and requiring a // subsequent rampup. constint encoder_stream_bps = kEncoderBitrateBps / num_streams; double scale_factor = 1.0; for (int i = num_streams - 1; i >= 0; --i) {
VideoStream& stream = GetVideoEncoderConfig()->simulcast_layers[i]; // Reduce the min bitrate by 10% to account for overhead that might // otherwise cause streams to not be enabled.
stream.min_bitrate_bps = static_cast<int>(encoder_stream_bps * 0.9);
stream.target_bitrate_bps = encoder_stream_bps;
stream.max_bitrate_bps = encoder_stream_bps;
stream.num_temporal_layers = num_temporal_layers_;
stream.scale_resolution_down_by = scale_factor;
scale_factor *= 2.0;
}
}
// Initial test with a single stream.
Start();
});
EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
// Reconfigure VideoEncoder and test picture id increase. // Expect continuously increasing picture id, equivalent to no gaps.
observer_->SetMaxExpectedPictureIdGap(0); for (int ssrc_count : ssrc_counts) {
SetVideoEncoderConfig(ssrc_count);
observer_->SetExpectedSsrcs(ssrc_count);
observer_->ResetObservedSsrcs(); // Make sure the picture_id sequence is continuous on reinit and recreate.
SendTask(task_queue(), [this]() {
GetVideoSendStream()->ReconfigureVideoEncoder(
GetVideoEncoderConfig()->Copy());
});
EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
}
// Initial test with a single stream.
Start();
});
EXPECT_TRUE(observer_->Wait()) << "Timed out waiting for packets.";
// Recreate VideoSendStream and test picture id increase. // When the VideoSendStream is destroyed, any frames still in queue is lost // with it, therefore it is expected that some frames might be lost.
observer_->SetMaxExpectedPictureIdGap(kMaxFramesLost); for (int ssrc_count : ssrc_counts) {
SendTask(task_queue(), [this, &ssrc_count]() {
DestroyVideoSendStreams();
TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeVp8) {
test::FunctionVideoEncoderFactory encoder_factory(
[](const Environment& env, const SdpVideoFormat& format) { return CreateVp8Encoder(env);
}); // Make sure that the picture id is not reset if the stream count goes // down and then up.
SetupEncoder(&encoder_factory, "VP8");
TestPictureIdContinuousAfterReconfigure({3, 1, 3});
}
TEST_P(PictureIdTest, ContinuousAfterStreamCountChangeSimulcastEncoderAdapter) {
InternalEncoderFactory internal_encoder_factory;
test::FunctionVideoEncoderFactory encoder_factory(
[&internal_encoder_factory](const Environment& env, const SdpVideoFormat& format) { return std::make_unique<SimulcastEncoderAdapter>(
env, &internal_encoder_factory, nullptr, SdpVideoFormat::VP8());
}); // Make sure that the picture id is not reset if the stream count goes // down and then up.
SetupEncoder(&encoder_factory, "VP8");
TestPictureIdContinuousAfterReconfigure({3, 1, 3});
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.