Modify NetEqQualityTest

- Take input sample rate as parameter - provides resampling when needed.
- Add support for wav output.

BUG=2692
R=minyue@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#9158}
This commit is contained in:
Henrik Lundin 2015-05-08 10:33:57 +02:00
parent cb05b72eb2
commit 83b5c053b9
8 changed files with 130 additions and 105 deletions

View File

@ -81,7 +81,7 @@ class NetEq {
background_noise_mode(kBgnOff),
playout_mode(kPlayoutOn) {}
int sample_rate_hz; // Initial vale. Will change with input data.
int sample_rate_hz; // Initial value. Will change with input data.
bool enable_audio_classifier;
int max_packets_in_buffer;
int max_delay_ms;

View File

@ -10,7 +10,6 @@
#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/test/testsupport/fileutils.h"
using google::RegisterFlagValidator;
using google::ParseCommandLineFlags;
@ -19,47 +18,12 @@ using testing::InitGoogleTest;
namespace webrtc {
namespace test {
namespace {
static const int kIsacBlockDurationMs = 30;
static const int kIsacInputSamplingKhz = 16;
static const int kIsacOutputSamplingKhz = 16;
// Define switch for input file name.
static bool ValidateInFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "rb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid input filename.");
return false;
}
DEFINE_string(in_filename,
ResourcePath("audio_coding/speech_mono_16kHz", "pcm"),
"Filename for input audio (should be 16 kHz sampled mono).");
static const bool in_filename_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "wb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid output filename.");
return false;
}
DEFINE_string(out_filename, OutputPath() + "neteq4_isac_quality_test.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
// Define switch for bir rate.
// Define switch for bit rate.
static bool ValidateBitRate(const char* flagname, int32_t value) {
if (value >= 10 && value <= 32)
return true;
@ -85,6 +49,8 @@ DEFINE_int32(runtime_ms, 10000, "Simulated runtime (milliseconds).");
static const bool runtime_dummy =
RegisterFlagValidator(&FLAGS_runtime_ms, &ValidateRuntime);
} // namespace
class NetEqIsacQualityTest : public NetEqQualityTest {
protected:
NetEqIsacQualityTest();
@ -98,12 +64,11 @@ class NetEqIsacQualityTest : public NetEqQualityTest {
};
NetEqIsacQualityTest::NetEqIsacQualityTest()
: NetEqQualityTest(kIsacBlockDurationMs, kIsacInputSamplingKhz,
: NetEqQualityTest(kIsacBlockDurationMs,
kIsacInputSamplingKhz,
kIsacOutputSamplingKhz,
kDecoderISAC,
1,
FLAGS_in_filename,
FLAGS_out_filename),
1),
isac_encoder_(NULL),
bit_rate_kbps_(FLAGS_bit_rate_kbps) {
}

View File

@ -11,7 +11,6 @@
#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/test/testsupport/fileutils.h"
using google::RegisterFlagValidator;
using google::ParseCommandLineFlags;
@ -20,44 +19,25 @@ using testing::InitGoogleTest;
namespace webrtc {
namespace test {
namespace {
static const int kOpusBlockDurationMs = 20;
static const int kOpusSamplingKhz = 48;
// Define switch for input file name.
static bool ValidateInFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "rb");
if (fid != NULL) {
fclose(fid);
// Define switch for sample rate.
static bool ValidateSampleRate(const char* flagname, int32_t value) {
if (value == 8000 || value == 16000 || value == 32000 || value == 48000)
return true;
}
printf("Invalid input filename.");
printf("Invalid sample rate should be 8000, 16000, 32000 or 48000 Hz.");
return false;
}
DEFINE_string(in_filename,
ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm"),
"Filename for input audio (should be 48 kHz sampled raw data).");
DEFINE_int32(input_sample_rate,
kOpusSamplingKhz * 1000,
"Sample rate of input file.");
static const bool in_filename_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "wb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid output filename.");
return false;
}
DEFINE_string(out_filename, OutputPath() + "neteq_opus_quality_test.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
static const bool sample_rate_dummy =
RegisterFlagValidator(&FLAGS_input_sample_rate, &ValidateSampleRate);
// Define switch for channels.
static bool ValidateChannels(const char* flagname, int32_t value) {
@ -125,6 +105,8 @@ DEFINE_int32(sub_packets, 1, "Number of sub packets to repacketize.");
static const bool sub_packets_dummy =
RegisterFlagValidator(&FLAGS_sub_packets, &ValidateSubPackets);
} // namepsace
class NetEqOpusQualityTest : public NetEqQualityTest {
protected:
NetEqOpusQualityTest();
@ -149,9 +131,7 @@ NetEqOpusQualityTest::NetEqOpusQualityTest()
kOpusSamplingKhz,
kOpusSamplingKhz,
(FLAGS_channels == 1) ? kDecoderOpus : kDecoderOpus_2ch,
FLAGS_channels,
FLAGS_in_filename,
FLAGS_out_filename),
FLAGS_channels),
opus_encoder_(NULL),
repacketizer_(NULL),
sub_block_size_samples_(kOpusBlockDurationMs * kOpusSamplingKhz),

View File

@ -32,7 +32,7 @@ class InputAudioFile {
// if the read was successful, otherwise false. If the file end is reached,
// the file is rewound and reading continues from the beginning.
// The output |destination| must have the capacity to hold |samples| elements.
bool Read(size_t samples, int16_t* destination);
virtual bool Read(size_t samples, int16_t* destination);
// Creates a multi-channel signal from a mono signal. Each sample is repeated
// |channels| times to create an interleaved multi-channel signal where all

View File

@ -10,7 +10,14 @@
#include <math.h>
#include <stdio.h>
#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "webrtc/test/testsupport/fileutils.h"
using std::string;
namespace webrtc {
namespace test {
@ -20,6 +27,61 @@ const int kOutputSizeMs = 10;
const int kInitSeed = 0x12345678;
const int kPacketLossTimeUnitMs = 10;
// Common validator for file names.
static bool ValidateFilename(const string& value, bool write) {
FILE* fid = write ? fopen(value.c_str(), "wb") : fopen(value.c_str(), "rb");
if (fid == nullptr)
return false;
fclose(fid);
return true;
}
// Define switch for input file name.
static bool ValidateInFilename(const char* flagname, const string& value) {
if (!ValidateFilename(value, false)) {
printf("Invalid input filename.");
return false;
}
return true;
}
DEFINE_string(
in_filename,
ResourcePath("audio_coding/speech_mono_16kHz", "pcm"),
"Filename for input audio (specify sample rate with --input_sample_rate).");
static const bool in_filename_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
// Define switch for sample rate.
static bool ValidateSampleRate(const char* flagname, int32_t value) {
if (value == 8000 || value == 16000 || value == 32000 || value == 48000)
return true;
printf("Invalid sample rate should be 8000, 16000, 32000 or 48000 Hz.");
return false;
}
DEFINE_int32(input_sample_rate, 16000, "Sample rate of input file in Hz.");
static const bool sample_rate_dummy =
RegisterFlagValidator(&FLAGS_input_sample_rate, &ValidateSampleRate);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
if (!ValidateFilename(value, true)) {
printf("Invalid output filename.");
return false;
}
return true;
}
DEFINE_string(out_filename,
OutputPath() + "neteq_quality_test_out.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
// Define switch for packet loss rate.
static bool ValidatePacketLossRate(const char* /* flag_name */, int32_t value) {
if (value >= 0 && value <= 100)
@ -120,9 +182,7 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms,
int in_sampling_khz,
int out_sampling_khz,
enum NetEqDecoder decoder_type,
int channels,
std::string in_filename,
std::string out_filename)
int channels)
: decoded_time_ms_(0),
decodable_time_ms_(0),
drift_factor_(FLAGS_drift_factor),
@ -132,19 +192,32 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms,
out_sampling_khz_(out_sampling_khz),
decoder_type_(decoder_type),
channels_(channels),
in_filename_(in_filename),
out_filename_(out_filename),
log_filename_(out_filename + ".log"),
in_size_samples_(in_sampling_khz_ * block_duration_ms_),
out_size_samples_(out_sampling_khz_ * kOutputSizeMs),
payload_size_bytes_(0),
max_payload_bytes_(0),
in_file_(new InputAudioFile(in_filename_)),
out_file_(NULL),
in_file_(new ResampleInputAudioFile(FLAGS_in_filename,
FLAGS_input_sample_rate,
in_sampling_khz * 1000)),
log_file_(NULL),
rtp_generator_(new RtpGenerator(in_sampling_khz_, 0, 0,
decodable_time_ms_)),
rtp_generator_(
new RtpGenerator(in_sampling_khz_, 0, 0, decodable_time_ms_)),
total_payload_size_bytes_(0) {
const std::string out_filename = FLAGS_out_filename;
const std::string log_filename = out_filename + ".log";
log_file_ = fopen(log_filename.c_str(), "wt");
CHECK(log_file_);
if (out_filename.size() >= 4 &&
out_filename.substr(out_filename.size() - 4) == ".wav") {
// Open a wav file.
output_.reset(
new webrtc::test::OutputWavFile(out_filename, 1000 * out_sampling_khz));
} else {
// Open a pcm file.
output_.reset(new webrtc::test::OutputAudioFile(out_filename));
}
NetEq::Config config;
config.sample_rate_hz = out_sampling_khz_ * 1000;
neteq_.reset(NetEq::Create(config));
@ -189,9 +262,6 @@ bool GilbertElliotLoss::Lost() {
}
void NetEqQualityTest::SetUp() {
out_file_ = fopen(out_filename_.c_str(), "wb");
log_file_ = fopen(log_filename_.c_str(), "wt");
ASSERT_TRUE(out_file_ != NULL);
ASSERT_EQ(0, neteq_->RegisterPayloadType(decoder_type_, kPayloadType));
rtp_generator_->set_drift_factor(drift_factor_);
@ -245,10 +315,6 @@ void NetEqQualityTest::SetUp() {
srand(kInitSeed);
}
void NetEqQualityTest::TearDown() {
fclose(out_file_);
}
bool NetEqQualityTest::PacketLost() {
int cycles = block_duration_ms_ / kPacketLossTimeUnitMs;
@ -297,7 +363,7 @@ int NetEqQualityTest::DecodeBlock() {
} else {
assert(channels == channels_);
assert(samples == kOutputSizeMs * out_sampling_khz_);
fwrite(&out_data_[0], sizeof(int16_t), samples * channels, out_file_);
CHECK(output_->WriteArray(out_data_.get(), samples * channels));
return samples;
}
}

View File

@ -12,10 +12,10 @@
#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_QUALITY_TEST_H_
#include <gflags/gflags.h>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_sink.h"
#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h"
#include "webrtc/typedefs.h"
@ -66,11 +66,8 @@ class NetEqQualityTest : public ::testing::Test {
int in_sampling_khz,
int out_sampling_khz,
enum NetEqDecoder decoder_type,
int channels,
std::string in_filename,
std::string out_filename);
int channels);
void SetUp() override;
void TearDown() override;
// EncodeBlock(...) does the following:
// 1. encodes a block of audio, saved in |in_data| and has a length of
@ -108,9 +105,6 @@ class NetEqQualityTest : public ::testing::Test {
const int out_sampling_khz_;
const enum NetEqDecoder decoder_type_;
const int channels_;
const std::string in_filename_;
const std::string out_filename_;
const std::string log_filename_;
// Number of samples per channel in a frame.
const int in_size_samples_;
@ -122,7 +116,7 @@ class NetEqQualityTest : public ::testing::Test {
int max_payload_bytes_;
rtc::scoped_ptr<InputAudioFile> in_file_;
FILE* out_file_;
rtc::scoped_ptr<AudioSink> output_;
FILE* log_file_;
rtc::scoped_ptr<RtpGenerator> rtp_generator_;

View File

@ -37,5 +37,14 @@ bool ResampleInputAudioFile::Read(size_t samples,
return true;
}
bool ResampleInputAudioFile::Read(size_t samples, int16_t* destination) {
CHECK_GT(output_rate_hz_, 0) << "Output rate not set.";
return Read(samples, output_rate_hz_, destination);
}
void ResampleInputAudioFile::set_output_rate_hz(int rate_hz) {
output_rate_hz_ = rate_hz;
}
} // namespace test
} // namespace webrtc

View File

@ -25,12 +25,23 @@ namespace test {
class ResampleInputAudioFile : public InputAudioFile {
public:
ResampleInputAudioFile(const std::string file_name, int file_rate_hz)
: InputAudioFile(file_name), file_rate_hz_(file_rate_hz) {}
: InputAudioFile(file_name),
file_rate_hz_(file_rate_hz),
output_rate_hz_(-1) {}
ResampleInputAudioFile(const std::string file_name,
int file_rate_hz,
int output_rate_hz)
: InputAudioFile(file_name),
file_rate_hz_(file_rate_hz),
output_rate_hz_(output_rate_hz) {}
bool Read(size_t samples, int output_rate_hz, int16_t* destination);
bool Read(size_t samples, int16_t* destination) override;
void set_output_rate_hz(int rate_hz);
private:
const int file_rate_hz_;
int output_rate_hz_;
Resampler resampler_;
DISALLOW_COPY_AND_ASSIGN(ResampleInputAudioFile);
};