blob: 24602ac821c8506d493ce2ea59cc168d2ee49732 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <cstdlib>
#include <memory>
#include "base/macros.h"
#include "base/time/time.h"
#include "media/cast/cast_config.h"
#include "media/cast/sender/sender_encoded_frame.h"
#include "media/cast/sender/vpx_encoder.h"
#include "media/cast/sender/vpx_quantizer_parser.h"
#include "media/cast/test/receiver/video_decoder.h"
#include "media/cast/test/utility/default_config.h"
#include "media/cast/test/utility/video_utility.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace cast {
namespace {
const int kWidth = 32;
const int kHeight = 32;
const int kFrameRate = 10;
const int kQp = 20;
FrameSenderConfig GetVideoConfigForTest() {
FrameSenderConfig config = GetDefaultVideoSenderConfig();
config.codec = CODEC_VIDEO_VP8;
config.use_external_encoder = false;
config.max_frame_rate = kFrameRate;
config.video_codec_params.min_qp = kQp;
config.video_codec_params.max_qp = kQp;
config.video_codec_params.max_cpu_saver_qp = kQp;
return config;
}
} // unnamed namespace
class VpxQuantizerParserTest : public ::testing::Test {
public:
VpxQuantizerParserTest() : video_config_(GetVideoConfigForTest()) {}
// Call vp8 software encoder to encode one randomly generated frame.
void EncodeOneFrame(SenderEncodedFrame* encoded_frame) {
const gfx::Size frame_size = gfx::Size(kWidth, kHeight);
const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
PIXEL_FORMAT_I420, frame_size, gfx::Rect(frame_size), frame_size,
next_frame_timestamp_);
const base::TimeTicks reference_time =
base::TimeTicks::UnixEpoch() + next_frame_timestamp_;
next_frame_timestamp_ += base::Seconds(1) / kFrameRate;
PopulateVideoFrameWithNoise(video_frame.get());
vp8_encoder_->Encode(video_frame, reference_time, encoded_frame);
}
// Update the vp8 encoder with the new quantizer.
void UpdateQuantizer(int qp) {
DCHECK((qp > 3) && (qp < 64));
video_config_.video_codec_params.min_qp = qp;
video_config_.video_codec_params.max_qp = qp;
video_config_.video_codec_params.max_cpu_saver_qp = qp;
RecreateVp8Encoder();
}
protected:
void SetUp() final {
next_frame_timestamp_ = base::TimeDelta();
RecreateVp8Encoder();
}
private:
// Reconstruct a vp8 encoder with new config since the Vp8Encoder
// class has no interface to update the config.
void RecreateVp8Encoder() {
vp8_encoder_ = std::make_unique<VpxEncoder>(video_config_);
vp8_encoder_->Initialize();
}
base::TimeDelta next_frame_timestamp_;
FrameSenderConfig video_config_;
std::unique_ptr<VpxEncoder> vp8_encoder_;
};
// Encode 3 frames to test the cases with insufficient data input.
TEST_F(VpxQuantizerParserTest, InsufficientData) {
for (int i = 0; i < 3; ++i) {
std::unique_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame());
const uint8_t* encoded_data =
reinterpret_cast<const uint8_t*>(encoded_frame->data.data());
// Null input.
int decoded_quantizer =
ParseVpxHeaderQuantizer(encoded_data, encoded_frame->data.size());
EXPECT_EQ(-1, decoded_quantizer);
EncodeOneFrame(encoded_frame.get());
encoded_data = reinterpret_cast<const uint8_t*>(encoded_frame->data.data());
// Zero bytes should not be enough to decode the quantizer value.
decoded_quantizer = ParseVpxHeaderQuantizer(encoded_data, 0);
EXPECT_EQ(-1, decoded_quantizer);
// Three bytes should not be enough to decode the quantizer value..
decoded_quantizer = ParseVpxHeaderQuantizer(encoded_data, 3);
EXPECT_EQ(-1, decoded_quantizer);
unsigned int first_partition_size =
(encoded_data[0] | (encoded_data[1] << 8) | (encoded_data[2] << 16)) >>
5;
if (encoded_frame->dependency == EncodedFrame::KEY) {
// Ten bytes should not be enough to decode the quanitizer value
// for a Key frame.
decoded_quantizer = ParseVpxHeaderQuantizer(encoded_data, 10);
EXPECT_EQ(-1, decoded_quantizer);
// One byte less than needed to decode the quantizer value.
decoded_quantizer =
ParseVpxHeaderQuantizer(encoded_data, 10 + first_partition_size - 1);
EXPECT_EQ(-1, decoded_quantizer);
// Minimum number of bytes to decode the quantizer value.
decoded_quantizer =
ParseVpxHeaderQuantizer(encoded_data, 10 + first_partition_size);
EXPECT_EQ(kQp, decoded_quantizer);
} else {
// One byte less than needed to decode the quantizer value.
decoded_quantizer =
ParseVpxHeaderQuantizer(encoded_data, 3 + first_partition_size - 1);
EXPECT_EQ(-1, decoded_quantizer);
// Minimum number of bytes to decode the quantizer value.
decoded_quantizer =
ParseVpxHeaderQuantizer(encoded_data, 3 + first_partition_size);
EXPECT_EQ(kQp, decoded_quantizer);
}
}
}
// Encode 3 fames for every quantizer value in the range of [4,63].
TEST_F(VpxQuantizerParserTest, VariedQuantizer) {
int decoded_quantizer = -1;
for (int qp = 4; qp <= 63; qp += 10) {
UpdateQuantizer(qp);
for (int i = 0; i < 3; ++i) {
std::unique_ptr<SenderEncodedFrame> encoded_frame(
new SenderEncodedFrame());
EncodeOneFrame(encoded_frame.get());
decoded_quantizer = ParseVpxHeaderQuantizer(
reinterpret_cast<const uint8_t*>(encoded_frame->data.data()),
encoded_frame->data.size());
EXPECT_EQ(qp, decoded_quantizer);
}
}
}
} // namespace cast
} // namespace media