
The C++ headers define the C functions within the std:: namespace, but we mainly don't use the std:: namespace for C functions. Therefore we should include the C headers. BUG=1833 R=tommi@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1917004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4486 4adac7df-926f-26a2-2b94-8c16560cd09d
305 lines
10 KiB
C++
305 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2012 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/test_framework/benchmark.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#if defined(_WIN32)
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
|
#include "webrtc/modules/video_coding/codecs/test_framework/video_source.h"
|
|
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
|
#include "webrtc/test/testsupport/fileutils.h"
|
|
#include "webrtc/test/testsupport/metrics/video_metrics.h"
|
|
|
|
#define SSIM_CALC 0 // by default, don't compute SSIM
|
|
|
|
using namespace webrtc;
|
|
|
|
Benchmark::Benchmark()
|
|
:
|
|
NormalAsyncTest("Benchmark", "Codec benchmark over a range of test cases", 6),
|
|
_resultsFileName(webrtc::test::OutputPath() + "benchmark.txt"),
|
|
_codecName("Default")
|
|
{
|
|
}
|
|
|
|
Benchmark::Benchmark(std::string name, std::string description)
|
|
:
|
|
NormalAsyncTest(name, description, 6),
|
|
_resultsFileName(webrtc::test::OutputPath() + "benchmark.txt"),
|
|
_codecName("Default")
|
|
{
|
|
}
|
|
|
|
Benchmark::Benchmark(std::string name, std::string description, std::string resultsFileName, std::string codecName)
|
|
:
|
|
NormalAsyncTest(name, description, 6),
|
|
_resultsFileName(resultsFileName),
|
|
_codecName(codecName)
|
|
{
|
|
}
|
|
|
|
void
|
|
Benchmark::Perform()
|
|
{
|
|
std::vector<const VideoSource*> sources;
|
|
std::vector<const VideoSource*>::iterator it;
|
|
|
|
// Configuration --------------------------
|
|
sources.push_back(new const VideoSource(webrtc::test::ProjectRootPath() +
|
|
"resources/foreman_cif.yuv", kCIF));
|
|
// sources.push_back(new const VideoSource(webrtc::test::ProjectRootPath() +
|
|
// "resources/akiyo_cif.yuv", kCIF));
|
|
|
|
const VideoSize size[] = {kQCIF, kCIF};
|
|
const int frameRate[] = {10, 15, 30};
|
|
// Specifies the framerates for which to perform a speed test.
|
|
const bool speedTestMask[] = {false, false, false};
|
|
const int bitRate[] = {50, 100, 200, 300, 400, 500, 600, 1000};
|
|
// Determines the number of iterations to perform to arrive at the speed result.
|
|
enum { kSpeedTestIterations = 10 };
|
|
// ----------------------------------------
|
|
|
|
const int nFrameRates = sizeof(frameRate)/sizeof(*frameRate);
|
|
assert(sizeof(speedTestMask)/sizeof(*speedTestMask) == nFrameRates);
|
|
const int nBitrates = sizeof(bitRate)/sizeof(*bitRate);
|
|
int testIterations = 10;
|
|
|
|
webrtc::test::QualityMetricsResult psnr[nBitrates];
|
|
webrtc::test::QualityMetricsResult ssim[nBitrates];
|
|
double fps[nBitrates];
|
|
double totalEncodeTime[nBitrates];
|
|
double totalDecodeTime[nBitrates];
|
|
|
|
_results.open(_resultsFileName.c_str(), std::fstream::out);
|
|
_results << GetMagicStr() << std::endl;
|
|
_results << _codecName << std::endl;
|
|
|
|
for (it = sources.begin() ; it < sources.end(); it++)
|
|
{
|
|
for (int i = 0; i < static_cast<int>(sizeof(size)/sizeof(*size)); i++)
|
|
{
|
|
for (int j = 0; j < nFrameRates; j++)
|
|
{
|
|
std::stringstream ss;
|
|
std::string strFrameRate;
|
|
std::string outFileName;
|
|
ss << frameRate[j];
|
|
ss >> strFrameRate;
|
|
outFileName = (*it)->GetFilePath() + "/" + (*it)->GetName() + "_" +
|
|
VideoSource::GetSizeString(size[i]) + "_" + strFrameRate + ".yuv";
|
|
|
|
_target = new const VideoSource(outFileName, size[i], frameRate[j]);
|
|
(*it)->Convert(*_target);
|
|
if (VideoSource::FileExists(outFileName.c_str()))
|
|
{
|
|
_inname = outFileName;
|
|
}
|
|
else
|
|
{
|
|
_inname = (*it)->GetFileName();
|
|
}
|
|
|
|
std::cout << (*it)->GetName() << ", " << VideoSource::GetSizeString(size[i])
|
|
<< ", " << frameRate[j] << " fps" << std::endl << "Bitrate [kbps]:";
|
|
_results << (*it)->GetName() << "," << VideoSource::GetSizeString(size[i])
|
|
<< "," << frameRate[j] << " fps" << std::endl << "Bitrate [kbps]";
|
|
|
|
if (speedTestMask[j])
|
|
{
|
|
testIterations = kSpeedTestIterations;
|
|
}
|
|
else
|
|
{
|
|
testIterations = 1;
|
|
}
|
|
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
_bitRate = (bitRate[k]);
|
|
double avgFps = 0.0;
|
|
totalEncodeTime[k] = 0;
|
|
totalDecodeTime[k] = 0;
|
|
|
|
for (int l = 0; l < testIterations; l++)
|
|
{
|
|
PerformNormalTest();
|
|
_appendNext = false;
|
|
|
|
avgFps += _framecnt / (_totalEncodeTime + _totalDecodeTime);
|
|
totalEncodeTime[k] += _totalEncodeTime;
|
|
totalDecodeTime[k] += _totalDecodeTime;
|
|
|
|
}
|
|
avgFps /= testIterations;
|
|
totalEncodeTime[k] /= testIterations;
|
|
totalDecodeTime[k] /= testIterations;
|
|
|
|
double actualBitRate = ActualBitRate(_framecnt) / 1000.0;
|
|
std::cout << " " << actualBitRate;
|
|
_results << "," << actualBitRate;
|
|
webrtc::test::QualityMetricsResult psnr_result;
|
|
I420PSNRFromFiles(_inname.c_str(), _outname.c_str(),
|
|
_inst.width, _inst.height, &psnr[k]);
|
|
if (SSIM_CALC)
|
|
{
|
|
webrtc::test::QualityMetricsResult ssim_result;
|
|
I420SSIMFromFiles(_inname.c_str(), _outname.c_str(),
|
|
_inst.width, _inst.height, &ssim[k]);
|
|
|
|
}
|
|
fps[k] = avgFps;
|
|
}
|
|
std::cout << std::endl << "Y-PSNR [dB]:";
|
|
_results << std::endl << "Y-PSNR [dB]";
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
std::cout << " " << psnr[k].average;
|
|
_results << "," << psnr[k].average;
|
|
|
|
}
|
|
if (SSIM_CALC)
|
|
{
|
|
std::cout << std::endl << "SSIM: ";
|
|
_results << std::endl << "SSIM ";
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
std::cout << " " << ssim[k].average;
|
|
_results << "," << ssim[k].average;
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << std::endl << "Encode Time[ms]:";
|
|
_results << std::endl << "Encode Time[ms]";
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
std::cout << " " << totalEncodeTime[k];
|
|
_results << "," << totalEncodeTime[k];
|
|
|
|
}
|
|
|
|
std::cout << std::endl << "Decode Time[ms]:";
|
|
_results << std::endl << "Decode Time[ms]";
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
std::cout << " " << totalDecodeTime[k];
|
|
_results << "," << totalDecodeTime[k];
|
|
|
|
}
|
|
|
|
if (speedTestMask[j])
|
|
{
|
|
std::cout << std::endl << "Speed [fps]:";
|
|
_results << std::endl << "Speed [fps]";
|
|
for (int k = 0; k < nBitrates; k++)
|
|
{
|
|
std::cout << " " << static_cast<int>(fps[k] + 0.5);
|
|
_results << "," << static_cast<int>(fps[k] + 0.5);
|
|
}
|
|
}
|
|
std::cout << std::endl << std::endl;
|
|
_results << std::endl << std::endl;
|
|
|
|
delete _target;
|
|
}
|
|
}
|
|
delete *it;
|
|
}
|
|
_results.close();
|
|
}
|
|
|
|
void
|
|
Benchmark::PerformNormalTest()
|
|
{
|
|
_encoder = GetNewEncoder();
|
|
_decoder = GetNewDecoder();
|
|
CodecSettings(_target->GetWidth(), _target->GetHeight(), _target->GetFrameRate(), _bitRate);
|
|
Setup();
|
|
EventWrapper* waitEvent = EventWrapper::Create();
|
|
_encoder->InitEncode(&_inst, 4, 1440);
|
|
CodecSpecific_InitBitrate();
|
|
_decoder->InitDecode(&_inst,1);
|
|
|
|
FrameQueue frameQueue;
|
|
VideoEncodeCompleteCallback encCallback(_encodedFile, &frameQueue, *this);
|
|
VideoDecodeCompleteCallback decCallback(_decodedFile, *this);
|
|
_encoder->RegisterEncodeCompleteCallback(&encCallback);
|
|
_decoder->RegisterDecodeCompleteCallback(&decCallback);
|
|
|
|
SetCodecSpecificParameters();
|
|
|
|
_totalEncodeTime = _totalDecodeTime = 0;
|
|
_totalEncodePipeTime = _totalDecodePipeTime = 0;
|
|
bool complete = false;
|
|
_framecnt = 0;
|
|
_encFrameCnt = 0;
|
|
_sumEncBytes = 0;
|
|
_lengthEncFrame = 0;
|
|
while (!complete)
|
|
{
|
|
complete = Encode();
|
|
if (!frameQueue.Empty() || complete)
|
|
{
|
|
while (!frameQueue.Empty())
|
|
{
|
|
_frameToDecode = static_cast<FrameQueueTuple *>(frameQueue.PopFrame());
|
|
DoPacketLoss();
|
|
int ret = Decode();
|
|
delete _frameToDecode;
|
|
_frameToDecode = NULL;
|
|
if (ret < 0)
|
|
{
|
|
fprintf(stderr,"\n\nError in decoder: %d\n\n", ret);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
else if (ret == 0)
|
|
{
|
|
_framecnt++;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "\n\nPositive return value from decode!\n\n");
|
|
}
|
|
}
|
|
}
|
|
waitEvent->Wait(5);
|
|
}
|
|
|
|
_encodedVideoBuffer.Free();
|
|
|
|
_encoder->Release();
|
|
_decoder->Release();
|
|
delete waitEvent;
|
|
delete _encoder;
|
|
delete _decoder;
|
|
Teardown();
|
|
}
|
|
|
|
void
|
|
Benchmark::CodecSpecific_InitBitrate()
|
|
{
|
|
if (_bitRate == 0)
|
|
{
|
|
_encoder->SetRates(600, _inst.maxFramerate);
|
|
}
|
|
else
|
|
{
|
|
_encoder->SetRates(_bitRate, _inst.maxFramerate);
|
|
}
|
|
}
|