Adding temporal layer strategy that keeps base layer framerate at an acceptable value.

R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2272005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4911 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andresp@webrtc.org
2013-10-03 14:06:14 +00:00
parent 70df305760
commit 26f78f7ecb
5 changed files with 383 additions and 47 deletions

View File

@ -11,9 +11,11 @@
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common.h"
#include "webrtc/common_video/test/frame_generator.h"
#include "webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h"
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
#include "webrtc/modules/video_coding/main/interface/mock/mock_vcm_callbacks.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_coding/main/source/video_coding_impl.h"
@ -31,12 +33,40 @@ using ::testing::Field;
using ::testing::NiceMock;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::FloatEq;
using std::vector;
using webrtc::test::FrameGenerator;
namespace webrtc {
namespace vcm {
namespace {
enum {
kMaxNumberOfTemporalLayers = 3
};
struct Vp8StreamInfo {
float framerate_fps[kMaxNumberOfTemporalLayers];
int bitrate_kbps[kMaxNumberOfTemporalLayers];
};
MATCHER_P(MatchesVp8StreamInfo, expected, "") {
bool res = true;
for (int tl = 0; tl < kMaxNumberOfTemporalLayers; ++tl) {
if (abs(expected.framerate_fps[tl] - arg.framerate_fps[tl]) > 0.5) {
*result_listener << " framerate_fps[" << tl
<< "] = " << arg.framerate_fps[tl] << " (expected "
<< expected.framerate_fps[tl] << ") ";
res = false;
}
if (abs(expected.bitrate_kbps[tl] - arg.bitrate_kbps[tl]) > 10) {
*result_listener << " bitrate_kbps[" << tl
<< "] = " << arg.bitrate_kbps[tl] << " (expected "
<< expected.bitrate_kbps[tl] << ") ";
res = false;
}
}
return res;
}
class EmptyFrameGenerator : public FrameGenerator {
public:
@ -81,6 +111,15 @@ class PacketizationCallback : public VCMPacketizationCallback {
interval_ms();
}
Vp8StreamInfo CalculateVp8StreamInfo() {
Vp8StreamInfo info;
for (int tl = 0; tl < 3; ++tl) {
info.framerate_fps[tl] = FramerateFpsWithinTemporalLayer(tl);
info.bitrate_kbps[tl] = BitrateKbpsWithinTemporalLayer(tl);
}
return info;
}
private:
struct FrameData {
FrameData() {}
@ -319,6 +358,18 @@ class TestVideoSenderWithVp8 : public TestVideoSender {
}
}
Vp8StreamInfo SimulateWithFramerate(float framerate) {
const float short_simulation_interval = 5.0;
const float long_simulation_interval = 10.0;
// It appears that this 5 seconds simulation is needed to allow
// bitrate and framerate to stabilize.
InsertFrames(framerate, short_simulation_interval);
packetization_callback_.Reset();
InsertFrames(framerate, long_simulation_interval);
return packetization_callback_.CalculateVp8StreamInfo();
}
protected:
VideoCodec codec_;
int codec_bitrate_kbps_;
@ -327,51 +378,56 @@ class TestVideoSenderWithVp8 : public TestVideoSender {
TEST_F(TestVideoSenderWithVp8,
DISABLED_ON_ANDROID(FixedTemporalLayersStrategy)) {
// It appears that this 5 seconds simulation are need to allow
// bitrate and framerate to stabilize.
// TODO(andresp): the framerate calculation should be improved.
double framerate = 30.0;
InsertFrames(framerate, 5.0);
packetization_callback_.Reset();
const int low_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0];
const int mid_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1];
const int high_b = codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2];
{
Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
}
{
Vp8StreamInfo expected = {{3.75, 7.5, 15.0}, {low_b, mid_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
}
}
// Need to simulate for 10 seconds due to VP8 bitrate controller.
InsertFrames(framerate, 10.0);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(2), 30.0, 0.5);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(1), 15.0, 0.5);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(0), 7.5, 0.5);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(2),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2],
10);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(1),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1],
10);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(0),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0],
10);
TEST_F(TestVideoSenderWithVp8,
DISABLED_ON_ANDROID(RealTimeTemporalLayersStrategy)) {
Config extra_options;
extra_options.Set<TemporalLayers::Factory>(
new RealTimeTemporalLayersFactory());
VideoCodec codec = MakeVp8VideoCodec(352, 288, 3);
codec.extra_options = &extra_options;
codec.minBitrate = 10;
codec.startBitrate = codec_bitrate_kbps_;
codec.maxBitrate = codec_bitrate_kbps_;
EXPECT_EQ(0, sender_->RegisterSendCodec(&codec, 1, 1200));
framerate = 15.0;
InsertFrames(framerate, 5.0);
packetization_callback_.Reset();
const int low_b = codec_bitrate_kbps_ * 0.4;
const int mid_b = codec_bitrate_kbps_ * 0.6;
const int high_b = codec_bitrate_kbps_;
InsertFrames(15.0, 10.0);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(2), 15.0, 0.5);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(1), 7.5, 0.5);
EXPECT_NEAR(
packetization_callback_.FramerateFpsWithinTemporalLayer(0), 3.75, 0.5);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(2),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][2],
10);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(1),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][1],
10);
EXPECT_NEAR(packetization_callback_.BitrateKbpsWithinTemporalLayer(0),
codec_bitrate_kbps_ * kVp8LayerRateAlloction[2][0],
10);
{
Vp8StreamInfo expected = {{7.5, 15.0, 30.0}, {low_b, mid_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(30.0), MatchesVp8StreamInfo(expected));
}
{
Vp8StreamInfo expected = {{5.0, 10.0, 20.0}, {low_b, mid_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(20.0), MatchesVp8StreamInfo(expected));
}
{
Vp8StreamInfo expected = {{7.5, 15.0, 15.0}, {mid_b, high_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(15.0), MatchesVp8StreamInfo(expected));
}
{
Vp8StreamInfo expected = {{5.0, 10.0, 10.0}, {mid_b, high_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(10.0), MatchesVp8StreamInfo(expected));
}
{
// TODO(andresp): Find out why this fails with framerate = 7.5
Vp8StreamInfo expected = {{7.0, 7.0, 7.0}, {high_b, high_b, high_b}};
EXPECT_THAT(SimulateWithFramerate(7.0), MatchesVp8StreamInfo(expected));
}
}
} // namespace
} // namespace vcm