git-svn-id: http://webrtc.googlecode.com/svn/trunk@156 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
499
src/modules/video_coding/main/test/quality_modes_test.cc
Normal file
499
src/modules/video_coding/main/test/quality_modes_test.cc
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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 "quality_modes_test.h"
|
||||
#include "../source/event.h"
|
||||
#include "vplib.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
using namespace webrtc;
|
||||
|
||||
int qualityModeTest()
|
||||
{
|
||||
// Don't run this test with debug time
|
||||
#if defined(TICK_TIME_DEBUG) || defined(EVENT_DEBUG)
|
||||
return -1;
|
||||
#endif
|
||||
VideoCodingModule* vcm = VideoCodingModule::Create(1);
|
||||
QualityModesTest QMTest(vcm);
|
||||
QMTest.Perform();
|
||||
VideoCodingModule::Destroy(vcm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
QualityModesTest::QualityModesTest(VideoCodingModule *vcm):
|
||||
NormalTest(vcm),
|
||||
_vpm()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
QualityModesTest::~QualityModesTest()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void
|
||||
QualityModesTest::Setup()
|
||||
{
|
||||
|
||||
|
||||
_inname= "../codecs/testFiles/database/crew_30f_4CIF.yuv";
|
||||
_outname = "../out_qmtest.yuv";
|
||||
_encodedName = "../encoded_qmtest.yuv";
|
||||
|
||||
//NATIVE/SOURCE VALUES
|
||||
_nativeWidth = 2*352;
|
||||
_nativeHeight = 2*288;
|
||||
_nativeFrameRate = 30;
|
||||
|
||||
|
||||
//TARGET/ENCODER VALUES
|
||||
_width = 2*352;
|
||||
_height = 2*288;
|
||||
_frameRate = 30;
|
||||
//
|
||||
_bitRate = 400;
|
||||
|
||||
_flagSSIM = false;
|
||||
|
||||
_lengthSourceFrame = 3*_nativeWidth*_nativeHeight/2;
|
||||
|
||||
if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
|
||||
{
|
||||
printf("Cannot read file %s.\n", _inname.c_str());
|
||||
exit(1);
|
||||
}
|
||||
if ((_encodedFile = fopen(_encodedName.c_str(), "wb")) == NULL)
|
||||
{
|
||||
printf("Cannot write encoded file.\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL)
|
||||
{
|
||||
printf("Cannot write file %s.\n", _outname.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_log.open("../TestLog.txt", std::fstream::out | std::fstream::app);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
QualityModesTest::Print()
|
||||
{
|
||||
std::cout << "Quality Modes Test Completed!" << std::endl;
|
||||
(_log) << "Quality Modes Test Completed!" << std::endl;
|
||||
(_log) << "Input file: " << _inname << std::endl;
|
||||
(_log) << "Output file: " << _outname << std::endl;
|
||||
(_log) << "Total run time: " << _testTotalTime << std::endl;
|
||||
printf("Total run time: %f s \n", _testTotalTime);
|
||||
double ActualBitRate = 8.0 *( _sumEncBytes / (_frameCnt / _nativeFrameRate));
|
||||
double actualBitRate = ActualBitRate / 1000.0;
|
||||
double avgEncTime = _totalEncodeTime / _frameCnt;
|
||||
double avgDecTime = _totalDecodeTime / _frameCnt;
|
||||
double psnr,ssim;
|
||||
PSNRfromFiles(_inname.c_str(), _outname.c_str(), _nativeWidth, _nativeHeight, &psnr);
|
||||
printf("Actual bitrate: %f kbps\n", actualBitRate);
|
||||
printf("Target bitrate: %f kbps\n", _bitRate);
|
||||
( _log) << "Actual bitrate: " << actualBitRate<< " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
|
||||
printf("Average encode time: %f s\n", avgEncTime);
|
||||
( _log) << "Average encode time: " << avgEncTime << " s" << std::endl;
|
||||
printf("Average decode time: %f s\n", avgDecTime);
|
||||
( _log) << "Average decode time: " << avgDecTime << " s" << std::endl;
|
||||
printf("PSNR: %f \n", psnr);
|
||||
printf("**Number of frames dropped in VPM***%d \n",_numFramesDroppedVPM);
|
||||
( _log) << "PSNR: " << psnr << std::endl;
|
||||
if (_flagSSIM == 1)
|
||||
{
|
||||
printf("***computing SSIM***\n");
|
||||
SSIMfromFiles(_inname.c_str(), _outname.c_str(), _nativeWidth, _nativeHeight, &ssim);
|
||||
printf("SSIM: %f \n", ssim);
|
||||
}
|
||||
(_log) << std::endl;
|
||||
}
|
||||
void
|
||||
QualityModesTest::Teardown()
|
||||
{
|
||||
_log.close();
|
||||
fclose(_sourceFile);
|
||||
fclose(_decodedFile);
|
||||
fclose(_encodedFile);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
WebRtc_Word32
|
||||
QualityModesTest::Perform()
|
||||
{
|
||||
Setup();
|
||||
// changing bit/frame rate during the test
|
||||
const float bitRateUpdate[] = {1000};
|
||||
const float frameRateUpdate[] = {30};
|
||||
const int updateFrameNum[] = {10000}; // frame numbers at which an update will occur
|
||||
|
||||
WebRtc_UWord32 numChanges = sizeof(updateFrameNum)/sizeof(*updateFrameNum);
|
||||
WebRtc_UWord8 change = 0;// change counter
|
||||
|
||||
_vpm = VideoProcessingModule::Create(1);
|
||||
|
||||
EventWrapper* waitEvent = EventWrapper::Create();
|
||||
VideoCodec codec;//both send and receive
|
||||
_vcm->InitializeReceiver();
|
||||
_vcm->InitializeSender();
|
||||
WebRtc_Word32 NumberOfCodecs = _vcm->NumberOfCodecs();
|
||||
for (int i = 0; i < NumberOfCodecs; i++)
|
||||
{
|
||||
_vcm->Codec(i, &codec);
|
||||
if(strncmp(codec.plName,"VP8" , 5) == 0)
|
||||
{
|
||||
codec.startBitrate = (int)_bitRate;
|
||||
codec.maxFramerate = (WebRtc_UWord8) _frameRate;
|
||||
codec.width = (WebRtc_UWord16)_width;
|
||||
codec.height = (WebRtc_UWord16)_height;
|
||||
TEST(_vcm->RegisterSendCodec(&codec, 2, 1440) == VCM_OK);// will also set and init the desired codec
|
||||
i = NumberOfCodecs;
|
||||
}
|
||||
}
|
||||
|
||||
// register a decoder (same codec for decoder and encoder )
|
||||
TEST(_vcm->RegisterReceiveCodec(&codec, 2) == VCM_OK);
|
||||
/* Callback Settings */
|
||||
VCMQMDecodeCompleCallback _decodeCallback(_decodedFile);
|
||||
_vcm->RegisterReceiveCallback(&_decodeCallback);
|
||||
VCMNTEncodeCompleteCallback _encodeCompleteCallback(_encodedFile, *this);
|
||||
_vcm->RegisterTransportCallback(&_encodeCompleteCallback);
|
||||
// encode and decode with the same vcm
|
||||
_encodeCompleteCallback.RegisterReceiverVCM(_vcm);
|
||||
|
||||
//quality modes callback
|
||||
QMTestVideoSettingsCallback QMCallback;
|
||||
QMCallback.RegisterVCM(_vcm);
|
||||
QMCallback.RegisterVPM(_vpm);
|
||||
_vcm->RegisterVideoQMCallback(&QMCallback);
|
||||
|
||||
///////////////////////
|
||||
/// Start Test
|
||||
///////////////////////
|
||||
_vpm->EnableTemporalDecimation(true);
|
||||
_vpm->EnableContentAnalysis(true);
|
||||
_vpm->SetInputFrameResampleMode(kFastRescaling);
|
||||
|
||||
// disabling internal VCM frame dropper
|
||||
_vcm->EnableFrameDropper(false);
|
||||
|
||||
VideoFrame sourceFrame;
|
||||
VideoFrame *decimatedFrame = NULL;
|
||||
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
|
||||
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame];
|
||||
double startTime = clock()/(double)CLOCKS_PER_SEC;
|
||||
_vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 0);
|
||||
|
||||
SendStatsTest sendStats;
|
||||
sendStats.SetTargetFrameRate(static_cast<WebRtc_UWord32>(_frameRate));
|
||||
_vcm->RegisterSendStatisticsCallback(&sendStats);
|
||||
|
||||
VideoContentMetrics* contentMetrics = NULL;
|
||||
// setting user frame rate
|
||||
_vpm->SetMaxFrameRate((WebRtc_UWord32)(_nativeFrameRate+ 0.5f));
|
||||
// for starters: keeping native values:
|
||||
_vpm->SetTargetResolution(_width, _height, (WebRtc_UWord32)(_frameRate+ 0.5f));
|
||||
_decodeCallback.SetOriginalFrameDimensions(_nativeWidth, _nativeHeight);
|
||||
|
||||
//tmp - disabling VPM frame dropping
|
||||
_vpm->EnableTemporalDecimation(false);
|
||||
|
||||
|
||||
WebRtc_Word32 ret = 0;
|
||||
_numFramesDroppedVPM = 0;
|
||||
|
||||
while (feof(_sourceFile)== 0)
|
||||
{
|
||||
fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile);
|
||||
_frameCnt++;
|
||||
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
|
||||
sourceFrame.SetHeight(_nativeHeight);
|
||||
sourceFrame.SetWidth(_nativeWidth);
|
||||
|
||||
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(codec.maxFramerate));
|
||||
sourceFrame.SetTimeStamp(_timeStamp);
|
||||
|
||||
ret = _vpm->PreprocessFrame(&sourceFrame, &decimatedFrame);
|
||||
if (ret == 1)
|
||||
{
|
||||
printf("VD: frame drop %d \n",_frameCnt);
|
||||
_numFramesDroppedVPM += 1;
|
||||
continue; // frame drop
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
printf("Error in PreprocessFrame: %d\n", ret);
|
||||
//exit(1);
|
||||
}
|
||||
contentMetrics = _vpm->ContentMetrics();
|
||||
if (contentMetrics == NULL)
|
||||
{
|
||||
printf("error: contentMetrics = NULL\n");
|
||||
}
|
||||
|
||||
// counting only encoding time
|
||||
_encodeTimes[int(sourceFrame.TimeStamp())] = clock()/(double)CLOCKS_PER_SEC;
|
||||
|
||||
WebRtc_Word32 ret = _vcm->AddVideoFrame(*decimatedFrame, contentMetrics);
|
||||
|
||||
_totalEncodeTime += clock()/(double)CLOCKS_PER_SEC - _encodeTimes[int(sourceFrame.TimeStamp())];
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Error in AddFrame: %d\n", ret);
|
||||
//exit(1);
|
||||
}
|
||||
_decodeTimes[int(sourceFrame.TimeStamp())] = clock()/(double)CLOCKS_PER_SEC; // same timestamp value for encode and decode
|
||||
ret = _vcm->Decode();
|
||||
_totalDecodeTime += clock()/(double)CLOCKS_PER_SEC - _decodeTimes[int(sourceFrame.TimeStamp())];
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Error in Decode: %d\n", ret);
|
||||
//exit(1);
|
||||
}
|
||||
if (_vcm->TimeUntilNextProcess() <= 0)
|
||||
{
|
||||
_vcm->Process();
|
||||
}
|
||||
// mimicking setTargetRates - update every 1 sec
|
||||
// this will trigger QMSelect
|
||||
if (_frameCnt%((int)_frameRate) == 0)
|
||||
{
|
||||
_vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 1);
|
||||
waitEvent->Wait(33);
|
||||
}
|
||||
waitEvent->Wait(33);
|
||||
// check for bit rate update
|
||||
if (change < numChanges && _frameCnt == updateFrameNum[change])
|
||||
{
|
||||
_bitRate = bitRateUpdate[change];
|
||||
_frameRate = frameRateUpdate[change];
|
||||
codec.startBitrate = (int)_bitRate;
|
||||
codec.maxFramerate = (WebRtc_UWord8) _frameRate;
|
||||
TEST(_vcm->RegisterSendCodec(&codec, 2, 1440) == VCM_OK);// will also set and init the desired codec
|
||||
change++;
|
||||
}
|
||||
}
|
||||
|
||||
double endTime = clock()/(double)CLOCKS_PER_SEC;
|
||||
_testTotalTime = endTime - startTime;
|
||||
_sumEncBytes = _encodeCompleteCallback.EncodedBytes();
|
||||
|
||||
delete tmpBuffer;
|
||||
delete waitEvent;
|
||||
_vpm->Reset();
|
||||
Teardown();
|
||||
Print();
|
||||
VideoProcessingModule::Destroy(_vpm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// implementing callback to be called from VCM to update VPM of frame rate and size
|
||||
QMTestVideoSettingsCallback::QMTestVideoSettingsCallback():
|
||||
_vpm(NULL),
|
||||
_vcm(NULL)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void
|
||||
QMTestVideoSettingsCallback::RegisterVPM(VideoProcessingModule *vpm)
|
||||
{
|
||||
_vpm = vpm;
|
||||
}
|
||||
void
|
||||
QMTestVideoSettingsCallback::RegisterVCM(VideoCodingModule *vcm)
|
||||
{
|
||||
_vcm = vcm;
|
||||
}
|
||||
|
||||
bool
|
||||
QMTestVideoSettingsCallback::Updated()
|
||||
{
|
||||
if (_updated)
|
||||
{
|
||||
_updated = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
QMTestVideoSettingsCallback::SetVideoQMSettings(const WebRtc_UWord32 frameRate,
|
||||
const WebRtc_UWord32 width,
|
||||
const WebRtc_UWord32 height)
|
||||
{
|
||||
WebRtc_Word32 retVal = 0;
|
||||
printf("QM updates: W = %d, H = %d, FR = %d, \n", width, height, frameRate);
|
||||
retVal = _vpm->SetTargetResolution(width, height, frameRate);
|
||||
//Initialize codec with new values - is this the best place to do it?
|
||||
if (!retVal)
|
||||
{
|
||||
// first get current settings
|
||||
VideoCodec currentCodec;
|
||||
_vcm->SendCodec(¤tCodec);
|
||||
// now set new values:
|
||||
currentCodec.height = (WebRtc_UWord16)height;
|
||||
currentCodec.width = (WebRtc_UWord16)width;
|
||||
currentCodec.maxFramerate = (WebRtc_UWord8)frameRate;
|
||||
|
||||
// re-register encoder
|
||||
retVal = _vcm->RegisterSendCodec(¤tCodec, 2, 1440);
|
||||
_updated = true;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
// Decoded Frame Callback Implmentation
|
||||
VCMQMDecodeCompleCallback::VCMQMDecodeCompleCallback(FILE* decodedFile):
|
||||
_decodedFile(decodedFile),
|
||||
_decodedBytes(0),
|
||||
//_test(test),
|
||||
_origWidth(0),
|
||||
_origHeight(0),
|
||||
_decWidth(0),
|
||||
_decHeight(0),
|
||||
//_interpolator(NULL),
|
||||
_decBuffer(NULL),
|
||||
_frameCnt(0)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
VCMQMDecodeCompleCallback::~VCMQMDecodeCompleCallback()
|
||||
{
|
||||
// if (_interpolator != NULL)
|
||||
// {
|
||||
// deleteInterpolator(_interpolator);
|
||||
// _interpolator = NULL;
|
||||
// }
|
||||
if (_decBuffer != NULL)
|
||||
{
|
||||
delete [] _decBuffer;
|
||||
_decBuffer = NULL;
|
||||
}
|
||||
}
|
||||
WebRtc_Word32
|
||||
VCMQMDecodeCompleCallback::FrameToRender(VideoFrame& videoFrame)
|
||||
{
|
||||
if ((_origWidth == videoFrame.Width()) && (_origHeight == videoFrame.Height()))
|
||||
{
|
||||
fwrite(videoFrame.Buffer(), 1, videoFrame.Length(), _decodedFile);
|
||||
_frameCnt++;
|
||||
//printf("frame dec # %d", _frameCnt);
|
||||
// no need for interpolator and decBuffer
|
||||
if (_decBuffer != NULL)
|
||||
{
|
||||
delete [] _decBuffer;
|
||||
_decBuffer = NULL;
|
||||
}
|
||||
// if (_interpolator != NULL)
|
||||
// {
|
||||
// deleteInterpolator(_interpolator);
|
||||
// _interpolator = NULL;
|
||||
// }
|
||||
_decWidth = 0;
|
||||
_decHeight = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_decWidth != videoFrame.Width()) || (_decHeight != videoFrame.Height()))
|
||||
{
|
||||
_decWidth = videoFrame.Width();
|
||||
_decHeight = videoFrame.Height();
|
||||
buildInterpolator();
|
||||
}
|
||||
|
||||
// interpolateFrame(_interpolator, videoFrame.Buffer(),_decBuffer);
|
||||
fwrite(_decBuffer, 1, _origWidth*_origHeight*3/2, _decodedFile);
|
||||
_frameCnt++;
|
||||
}
|
||||
|
||||
_decodedBytes += videoFrame.Length();
|
||||
return VCM_OK;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
VCMQMDecodeCompleCallback::DecodedBytes()
|
||||
{
|
||||
return _decodedBytes;
|
||||
}
|
||||
|
||||
void
|
||||
VCMQMDecodeCompleCallback::SetOriginalFrameDimensions(WebRtc_Word32 width, WebRtc_Word32 height)
|
||||
{
|
||||
_origWidth = width;
|
||||
_origHeight = height;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
VCMQMDecodeCompleCallback::buildInterpolator()
|
||||
{
|
||||
// if (_interpolator != NULL)
|
||||
// {
|
||||
// deleteInterpolator(_interpolator);
|
||||
// _interpolator = NULL;
|
||||
// }
|
||||
|
||||
// create decimator
|
||||
WebRtc_Word32 filterPar = 4; //Lanczos (assuming sampling ratio is 1, 1.5, 2, 4)
|
||||
|
||||
float HeightRatio = 0;
|
||||
float WidthRatio = 0;
|
||||
|
||||
WidthRatio = (float)_origWidth/(float)_decWidth;
|
||||
HeightRatio = (float)_origHeight/(float)_decHeight;
|
||||
|
||||
if ( (HeightRatio == 1.0 || HeightRatio == 1.5 || HeightRatio == 2 || HeightRatio == 4) &&
|
||||
(WidthRatio == 1.0 || WidthRatio == 1.5 || WidthRatio == 2 || WidthRatio == 4))
|
||||
{
|
||||
filterPar = 4; //Lanczos
|
||||
} else
|
||||
{
|
||||
filterPar = 0; //BiCubic
|
||||
}
|
||||
|
||||
|
||||
// define interpolator here
|
||||
|
||||
// create interpolator here
|
||||
|
||||
// if (_interpolator == NULL)
|
||||
// {
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
WebRtc_UWord32 decFrameLength = _origWidth*_origHeight*3 >> 1;
|
||||
if (_decBuffer != NULL)
|
||||
{
|
||||
delete [] _decBuffer;
|
||||
}
|
||||
_decBuffer = new WebRtc_UWord8[decFrameLength];
|
||||
if (_decBuffer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user