blob: fd4bf527b4a1327a5697f04bc88099e224723035 [file] [log] [blame]
/*
* Copyright (c) 2011 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 "webrtc/modules/video_coding/codecs/vp8/default_temporal_layers.h"
#include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h"
#include "webrtc/modules/video_coding/codecs/vp8/vp8_impl.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
enum {
kTemporalUpdateLast = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF |
VP8_EFLAG_NO_REF_ARF,
kTemporalUpdateGoldenWithoutDependency =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateGolden =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateAltrefWithoutDependency =
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateAltref = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateNone = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY,
kTemporalUpdateNoneNoRefAltRef = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY,
kTemporalUpdateNoneNoRefGolden = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY,
kTemporalUpdateGoldenWithoutDependencyRefAltRef =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateGoldenRefAltRef = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST,
kTemporalUpdateLastRefAltRef =
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF,
kTemporalUpdateLastAndGoldenRefAltRef =
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_REF_GF,
};
TEST(TemporalLayersTest, 2Layers) {
DefaultTemporalLayers tl(2, 0);
vpx_codec_enc_cfg_t cfg;
CodecSpecificInfoVP8 vp8_info;
tl.OnRatesUpdated(500, 500, 30);
tl.UpdateConfiguration(&cfg);
int expected_flags[16] = {
kTemporalUpdateLastAndGoldenRefAltRef,
kTemporalUpdateGoldenWithoutDependencyRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateLastAndGoldenRefAltRef,
kTemporalUpdateGoldenWithoutDependencyRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateNone,
};
int expected_temporal_idx[16] = {0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1};
bool expected_layer_sync[16] = {false, true, false, false, false, false,
false, false, false, true, false, false,
false, false, false, false};
uint32_t timestamp = 0;
for (int i = 0; i < 16; ++i) {
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], VP8EncoderImpl::EncodeFlags(tl_config));
tl.PopulateCodecSpecific(false, tl_config, &vp8_info, 0);
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
}
TEST(TemporalLayersTest, 3Layers) {
DefaultTemporalLayers tl(3, 0);
vpx_codec_enc_cfg_t cfg;
CodecSpecificInfoVP8 vp8_info;
tl.OnRatesUpdated(500, 500, 30);
tl.UpdateConfiguration(&cfg);
int expected_flags[16] = {
kTemporalUpdateLastAndGoldenRefAltRef,
kTemporalUpdateNoneNoRefGolden,
kTemporalUpdateGoldenWithoutDependencyRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateLastAndGoldenRefAltRef,
kTemporalUpdateNoneNoRefGolden,
kTemporalUpdateGoldenWithoutDependencyRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateNone,
};
int expected_temporal_idx[16] = {0, 2, 1, 2, 0, 2, 1, 2,
0, 2, 1, 2, 0, 2, 1, 2};
bool expected_layer_sync[16] = {false, true, true, false, false, false,
false, false, false, true, true, false,
false, false, false, false};
unsigned int timestamp = 0;
for (int i = 0; i < 16; ++i) {
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], VP8EncoderImpl::EncodeFlags(tl_config));
tl.PopulateCodecSpecific(false, tl_config, &vp8_info, 0);
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
}
TEST(TemporalLayersTest, 4Layers) {
DefaultTemporalLayers tl(4, 0);
vpx_codec_enc_cfg_t cfg;
CodecSpecificInfoVP8 vp8_info;
tl.OnRatesUpdated(500, 500, 30);
tl.UpdateConfiguration(&cfg);
int expected_flags[16] = {
kTemporalUpdateLast,
kTemporalUpdateNone,
kTemporalUpdateAltrefWithoutDependency,
kTemporalUpdateNone,
kTemporalUpdateGoldenWithoutDependency,
kTemporalUpdateNone,
kTemporalUpdateAltref,
kTemporalUpdateNone,
kTemporalUpdateLast,
kTemporalUpdateNone,
kTemporalUpdateAltref,
kTemporalUpdateNone,
kTemporalUpdateGolden,
kTemporalUpdateNone,
kTemporalUpdateAltref,
kTemporalUpdateNone,
};
int expected_temporal_idx[16] = {0, 3, 2, 3, 1, 3, 2, 3,
0, 3, 2, 3, 1, 3, 2, 3};
bool expected_layer_sync[16] = {false, true, true, true, true, true,
false, true, false, true, false, true,
false, true, false, true};
uint32_t timestamp = 0;
for (int i = 0; i < 16; ++i) {
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], VP8EncoderImpl::EncodeFlags(tl_config));
tl.PopulateCodecSpecific(false, tl_config, &vp8_info, 0);
EXPECT_EQ(expected_temporal_idx[i], vp8_info.temporalIdx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(expected_layer_sync[i], vp8_info.layerSync);
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
timestamp += 3000;
}
}
TEST(TemporalLayersTest, KeyFrame) {
DefaultTemporalLayers tl(3, 0);
vpx_codec_enc_cfg_t cfg;
CodecSpecificInfoVP8 vp8_info;
tl.OnRatesUpdated(500, 500, 30);
tl.UpdateConfiguration(&cfg);
int expected_flags[8] = {
kTemporalUpdateLastAndGoldenRefAltRef,
kTemporalUpdateNoneNoRefGolden,
kTemporalUpdateGoldenWithoutDependencyRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateLastRefAltRef,
kTemporalUpdateNone,
kTemporalUpdateGoldenRefAltRef,
kTemporalUpdateNone,
};
int expected_temporal_idx[8] = {0, 2, 1, 2, 0, 2, 1, 2};
bool expected_layer_sync[8] = {false, true, true, false,
false, false, false, false};
uint32_t timestamp = 0;
for (int i = 0; i < 7; ++i) {
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[i], VP8EncoderImpl::EncodeFlags(tl_config));
tl.PopulateCodecSpecific(true, tl_config, &vp8_info, 0);
EXPECT_EQ(expected_temporal_idx[i], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[i], tl_config.encoder_layer_id);
EXPECT_EQ(0, vp8_info.temporalIdx)
<< "Key frame should always be packetized as layer 0";
EXPECT_EQ(expected_layer_sync[i], tl_config.layer_sync);
EXPECT_TRUE(vp8_info.layerSync) << "Key frame should be marked layer sync.";
timestamp += 3000;
}
TemporalLayers::FrameConfig tl_config = tl.UpdateLayerConfig(timestamp);
EXPECT_EQ(expected_flags[7], VP8EncoderImpl::EncodeFlags(tl_config));
tl.PopulateCodecSpecific(false, tl_config, &vp8_info, 0);
EXPECT_NE(0, vp8_info.temporalIdx)
<< "To test something useful, this frame should not use layer 0.";
EXPECT_EQ(expected_temporal_idx[7], vp8_info.temporalIdx)
<< "Non-keyframe, should use frame temporal index.";
EXPECT_EQ(expected_temporal_idx[7], tl_config.packetizer_temporal_idx);
EXPECT_EQ(expected_temporal_idx[7], tl_config.encoder_layer_id);
EXPECT_FALSE(tl_config.layer_sync);
EXPECT_TRUE(vp8_info.layerSync) << "Frame after keyframe should always be "
"marked layer sync since it only depends "
"on the base layer.";
}
} // namespace webrtc