mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00

by updating flag that T1 frame can be referenced when it is encoded rather than when it is sent for encoding. Otherwise when encoder drops T1 frame, configuration for following T2 frame would still try to reference that absent T1 frame leading to invalid references. Bug: None Change-Id: I6398275971596b0618bcf9c926f0282f74120976 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/202030 Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33002}
151 lines
5.8 KiB
C++
151 lines
5.8 KiB
C++
/*
|
|
* Copyright (c) 2020 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 "modules/video_coding/svc/scalability_structure_key_svc.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "api/array_view.h"
|
|
#include "api/transport/rtp/dependency_descriptor.h"
|
|
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
|
|
#include "modules/video_coding/svc/scalability_structure_test_helpers.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
using ::testing::ElementsAre;
|
|
using ::testing::IsEmpty;
|
|
using ::testing::SizeIs;
|
|
|
|
TEST(ScalabilityStructureL3T3KeyTest,
|
|
SkipingT1FrameOnOneSpatialLayerKeepsStructureValid) {
|
|
ScalabilityStructureL3T3Key structure;
|
|
ScalabilityStructureWrapper wrapper(structure);
|
|
std::vector<GenericFrameInfo> frames;
|
|
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/3, /*s1=*/3));
|
|
wrapper.GenerateFrames(/*num_temporal_units=*/2, frames);
|
|
EXPECT_THAT(frames, SizeIs(4));
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/3, /*s1=*/1));
|
|
wrapper.GenerateFrames(/*num_temporal_units=*/1, frames);
|
|
EXPECT_THAT(frames, SizeIs(5));
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/3, /*s1=*/3));
|
|
wrapper.GenerateFrames(/*num_temporal_units=*/1, frames);
|
|
ASSERT_THAT(frames, SizeIs(7));
|
|
|
|
EXPECT_EQ(frames[0].temporal_id, 0);
|
|
EXPECT_EQ(frames[1].temporal_id, 0);
|
|
EXPECT_EQ(frames[2].temporal_id, 2);
|
|
EXPECT_EQ(frames[3].temporal_id, 2);
|
|
EXPECT_EQ(frames[4].temporal_id, 1);
|
|
EXPECT_EQ(frames[5].temporal_id, 2);
|
|
EXPECT_EQ(frames[6].temporal_id, 2);
|
|
EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames));
|
|
}
|
|
|
|
TEST(ScalabilityStructureL3T3KeyTest,
|
|
SkipT1FrameByEncoderKeepsReferencesValid) {
|
|
std::vector<GenericFrameInfo> frames;
|
|
ScalabilityStructureL3T3Key structure;
|
|
ScalabilityStructureWrapper wrapper(structure);
|
|
|
|
// 1st 2 temporal units (T0 and T2)
|
|
wrapper.GenerateFrames(/*num_temporal_units=*/2, frames);
|
|
// Simulate T1 frame dropped by the encoder,
|
|
// i.e. retrieve config, but skip calling OnEncodeDone.
|
|
structure.NextFrameConfig(/*restart=*/false);
|
|
// one more temporal units (T2)
|
|
wrapper.GenerateFrames(/*num_temporal_units=*/1, frames);
|
|
|
|
ASSERT_THAT(frames, SizeIs(9));
|
|
EXPECT_EQ(frames[0].temporal_id, 0);
|
|
EXPECT_EQ(frames[3].temporal_id, 2);
|
|
// T1 frames were dropped by the encoder.
|
|
EXPECT_EQ(frames[6].temporal_id, 2);
|
|
|
|
EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames));
|
|
}
|
|
|
|
TEST(ScalabilityStructureL3T3KeyTest,
|
|
ReenablingSpatialLayerBeforeMissedT0FrameDoesntTriggerAKeyFrame) {
|
|
ScalabilityStructureL3T3Key structure;
|
|
ScalabilityStructureWrapper wrapper(structure);
|
|
std::vector<GenericFrameInfo> frames;
|
|
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/2));
|
|
wrapper.GenerateFrames(1, frames);
|
|
EXPECT_THAT(frames, SizeIs(2));
|
|
// Drop a spatial layer.
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/0));
|
|
wrapper.GenerateFrames(1, frames);
|
|
EXPECT_THAT(frames, SizeIs(3));
|
|
// Reenable a spatial layer before T0 frame is encoded.
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/2));
|
|
wrapper.GenerateFrames(1, frames);
|
|
EXPECT_THAT(frames, SizeIs(5));
|
|
|
|
EXPECT_EQ(frames[0].temporal_id, 0);
|
|
EXPECT_EQ(frames[1].temporal_id, 0);
|
|
EXPECT_EQ(frames[2].temporal_id, 1);
|
|
EXPECT_EQ(frames[3].temporal_id, 0);
|
|
EXPECT_EQ(frames[4].temporal_id, 0);
|
|
EXPECT_THAT(frames[3].frame_diffs, SizeIs(1));
|
|
EXPECT_THAT(frames[4].frame_diffs, SizeIs(1));
|
|
EXPECT_TRUE(wrapper.FrameReferencesAreValid(frames));
|
|
}
|
|
|
|
TEST(ScalabilityStructureL3T3KeyTest, ReenablingSpatialLayerTriggersKeyFrame) {
|
|
ScalabilityStructureL3T3Key structure;
|
|
ScalabilityStructureWrapper wrapper(structure);
|
|
std::vector<GenericFrameInfo> frames;
|
|
|
|
// Start with all spatial layers enabled.
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/2, /*s2=*/2));
|
|
wrapper.GenerateFrames(3, frames);
|
|
EXPECT_THAT(frames, SizeIs(9));
|
|
// Drop a spatial layer. Two remaining spatial layers should just continue.
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/0, /*s2=*/2));
|
|
wrapper.GenerateFrames(2, frames);
|
|
EXPECT_THAT(frames, SizeIs(13));
|
|
// Reenable spatial layer, expect a full restart.
|
|
structure.OnRatesUpdated(EnableTemporalLayers(/*s0=*/2, /*s1=*/2, /*s2=*/2));
|
|
wrapper.GenerateFrames(1, frames);
|
|
ASSERT_THAT(frames, SizeIs(16));
|
|
|
|
// First 3 temporal units with all spatial layers enabled.
|
|
EXPECT_EQ(frames[0].temporal_id, 0);
|
|
EXPECT_EQ(frames[3].temporal_id, 1);
|
|
EXPECT_EQ(frames[6].temporal_id, 0);
|
|
// 2 temporal units with spatial layer 1 disabled.
|
|
EXPECT_EQ(frames[9].spatial_id, 0);
|
|
EXPECT_EQ(frames[9].temporal_id, 1);
|
|
EXPECT_EQ(frames[10].spatial_id, 2);
|
|
EXPECT_EQ(frames[10].temporal_id, 1);
|
|
// T0 frames were encoded while spatial layer 1 is disabled.
|
|
EXPECT_EQ(frames[11].spatial_id, 0);
|
|
EXPECT_EQ(frames[11].temporal_id, 0);
|
|
EXPECT_EQ(frames[12].spatial_id, 2);
|
|
EXPECT_EQ(frames[12].temporal_id, 0);
|
|
// Key frame to reenable spatial layer 1.
|
|
EXPECT_THAT(frames[13].frame_diffs, IsEmpty());
|
|
EXPECT_THAT(frames[14].frame_diffs, ElementsAre(1));
|
|
EXPECT_THAT(frames[15].frame_diffs, ElementsAre(1));
|
|
EXPECT_EQ(frames[13].temporal_id, 0);
|
|
EXPECT_EQ(frames[14].temporal_id, 0);
|
|
EXPECT_EQ(frames[15].temporal_id, 0);
|
|
auto all_frames = rtc::MakeArrayView(frames.data(), frames.size());
|
|
EXPECT_TRUE(wrapper.FrameReferencesAreValid(all_frames.subview(0, 13)));
|
|
// Frames starting from the frame#13 should not reference any earlier frames.
|
|
EXPECT_TRUE(wrapper.FrameReferencesAreValid(all_frames.subview(13)));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace webrtc
|