Fix logic reading spatial/temporal id in VideoStreamEncoder.
The temporal id must be read from `EncodedImage` rather than codec specifics for AV1. Furthermore, in some configs the spatial id of `EncodedImage` is populated and set to 0 while the simulcast id can also be simultaneously populated and set to values, including non-zero. To solve this, just take the max of the two. Bug: b/349561566 Change-Id: I46c61b7f0fff7a7ab8d7262c3a8d413f49b3286a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/355904 Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42573}
This commit is contained in:
parent
445d403eca
commit
fe4c1dd6dc
@ -151,6 +151,7 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image,
|
||||
if (qp)
|
||||
encoded.qp_ = *qp;
|
||||
encoded.SetSimulcastIndex(i);
|
||||
encoded.SetTemporalIndex(frame_info.layers[i].temporal_id);
|
||||
CodecSpecificInfo codec_specific = EncodeHook(encoded, buffer);
|
||||
|
||||
if (callback->OnEncodedImage(encoded, &codec_specific).error !=
|
||||
|
||||
@ -2168,7 +2168,10 @@ EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage(
|
||||
image_copy.ClearEncodedData();
|
||||
|
||||
int temporal_index = 0;
|
||||
if (codec_specific_info) {
|
||||
if (encoded_image.TemporalIndex()) {
|
||||
// Give precedence to the metadata on EncodedImage, if available.
|
||||
temporal_index = *encoded_image.TemporalIndex();
|
||||
} else if (codec_specific_info) {
|
||||
if (codec_specific_info->codecType == kVideoCodecVP9) {
|
||||
temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx;
|
||||
} else if (codec_specific_info->codecType == kVideoCodecVP8) {
|
||||
@ -2412,8 +2415,8 @@ void VideoStreamEncoder::RunPostEncode(const EncodedImage& encoded_image,
|
||||
// TODO(https://crbug.com/webrtc/14891): If we want to support a mix of
|
||||
// simulcast and SVC we'll also need to consider the case where we have both
|
||||
// simulcast and spatial indices.
|
||||
int stream_index = encoded_image.SpatialIndex().value_or(
|
||||
encoded_image.SimulcastIndex().value_or(0));
|
||||
int stream_index = std::max(encoded_image.SimulcastIndex().value_or(0),
|
||||
encoded_image.SpatialIndex().value_or(0));
|
||||
bitrate_adjuster_->OnEncodedFrame(frame_size, stream_index, temporal_index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
#include "test/video_encoder_proxy_factory.h"
|
||||
#include "video/config/encoder_stream_factory.h"
|
||||
#include "video/config/video_encoder_config.h"
|
||||
#include "video/encoder_bitrate_adjuster.h"
|
||||
#include "video/frame_cadence_adapter.h"
|
||||
#include "video/send_statistics_proxy.h"
|
||||
|
||||
@ -2583,6 +2584,58 @@ TEST_F(VideoStreamEncoderTest,
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(VideoStreamEncoderTest, CorrectlyAdjustsAv1Bitrate) {
|
||||
ResetEncoder("AV1", /*num_streams*/ 2, /*num_temporal_layers=*/2,
|
||||
/*num_spatial_layers=*/1, /*screenshare*/ false,
|
||||
kDefaultFramerate,
|
||||
VideoStreamEncoder::BitrateAllocationCallbackType::
|
||||
kVideoLayersAllocation);
|
||||
|
||||
// Let link allocation and stable bitrate be 2x the target bitrate.
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
kTargetBitrate, 2 * kTargetBitrate, 2 * kTargetBitrate, 0, 0, 0);
|
||||
|
||||
video_source_.IncomingCapturedFrame(
|
||||
CreateFrame(CurrentTimeMs(), codec_width_, codec_height_));
|
||||
WaitForEncodedFrame(CurrentTimeMs());
|
||||
|
||||
// Before enough data has been gathered, some default pushback is applied.
|
||||
VideoEncoder::RateControlParameters rate_settings =
|
||||
*fake_encoder_.GetAndResetLastRateControlSettings();
|
||||
// Allow 5% diff from target bitrate.
|
||||
const double allowed_error_bps =
|
||||
rate_settings.target_bitrate.get_sum_bps() * 0.05;
|
||||
EXPECT_NEAR(rate_settings.bitrate.get_sum_bps(),
|
||||
rate_settings.target_bitrate.get_sum_bps() /
|
||||
EncoderBitrateAdjuster::kDefaultUtilizationFactor,
|
||||
allowed_error_bps);
|
||||
|
||||
// Insert frames until bitrate adjuster is saturated.
|
||||
const TimeDelta runtime =
|
||||
TimeDelta::Millis(EncoderBitrateAdjuster::kWindowSizeMs);
|
||||
const Timestamp start_time = clock()->CurrentTime();
|
||||
while (clock()->CurrentTime() - start_time < runtime) {
|
||||
video_source_.IncomingCapturedFrame(
|
||||
CreateFrame(CurrentTimeMs(), codec_width_, codec_height_));
|
||||
WaitForEncodedFrame(CurrentTimeMs());
|
||||
}
|
||||
|
||||
// Make sure rate has been reallocated.
|
||||
video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
|
||||
kTargetBitrate - DataRate::BitsPerSec(500), 2 * kTargetBitrate,
|
||||
2 * kTargetBitrate, 0, 0, 0);
|
||||
video_source_.IncomingCapturedFrame(
|
||||
CreateFrame(CurrentTimeMs(), codec_width_, codec_height_));
|
||||
WaitForEncodedFrame(CurrentTimeMs());
|
||||
|
||||
// Pushback should no longer happen.
|
||||
rate_settings = *fake_encoder_.GetAndResetLastRateControlSettings();
|
||||
EXPECT_NEAR(rate_settings.bitrate.get_sum_bps(),
|
||||
rate_settings.target_bitrate.get_sum_bps(), allowed_error_bps);
|
||||
|
||||
video_stream_encoder_->Stop();
|
||||
}
|
||||
|
||||
class ResolutionAlignmentTest
|
||||
: public VideoStreamEncoderTest,
|
||||
public ::testing::WithParamInterface<
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user