diff --git a/webrtc/modules/video_coding/main/test/normal_test.cc b/webrtc/modules/video_coding/main/test/normal_test.cc index 2eabc1043a..96e5008f8b 100644 --- a/webrtc/modules/video_coding/main/test/normal_test.cc +++ b/webrtc/modules/video_coding/main/test/normal_test.cc @@ -27,7 +27,7 @@ using namespace webrtc; -int NormalTest::RunTest(CmdArgs& args) +int NormalTest::RunTest(const CmdArgs& args) { #if defined(EVENT_DEBUG) printf("SIMULATION TIME\n"); @@ -67,8 +67,8 @@ VCMNTEncodeCompleteCallback::~VCMNTEncodeCompleteCallback() { } -void -VCMNTEncodeCompleteCallback::RegisterTransportCallback(VCMPacketizationCallback* transport) +void VCMNTEncodeCompleteCallback::RegisterTransportCallback( + VCMPacketizationCallback* transport) { } @@ -84,73 +84,73 @@ VCMNTEncodeCompleteCallback::SendData( const webrtc::RTPVideoHeader* videoHdr) { - // will call the VCMReceiver input packet - _frameType = frameType; - // writing encodedData into file - if (fwrite(payloadData, 1, payloadSize, _encodedFile) != payloadSize) { - return -1; - } - WebRtcRTPHeader rtpInfo; - rtpInfo.header.markerBit = true; - rtpInfo.type.Video.width = 0; - rtpInfo.type.Video.height = 0; - switch (_test.VideoType()) - { - case kVideoCodecVP8: - rtpInfo.type.Video.codec = kRTPVideoVP8; - rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8(); - rtpInfo.type.Video.codecHeader.VP8.nonReference = - videoHdr->codecHeader.VP8.nonReference; - rtpInfo.type.Video.codecHeader.VP8.pictureId = - videoHdr->codecHeader.VP8.pictureId; - break; - case kVideoCodecI420: - rtpInfo.type.Video.codec = kRTPVideoI420; - break; - default: - assert(false); - return -1; - } - rtpInfo.header.payloadType = payloadType; - rtpInfo.header.sequenceNumber = _seqNo++; - rtpInfo.header.ssrc = 0; - rtpInfo.header.timestamp = timeStamp; - rtpInfo.frameType = frameType; - rtpInfo.type.Video.isFirstPacket = true; - // Size should also be received from that table, since the payload type - // defines the size. + // will call the VCMReceiver input packet + _frameType = frameType; + // writing encodedData into file + if (fwrite(payloadData, 1, payloadSize, _encodedFile) != payloadSize) { + return -1; + } + WebRtcRTPHeader rtpInfo; + rtpInfo.header.markerBit = true; + rtpInfo.type.Video.width = 0; + rtpInfo.type.Video.height = 0; + switch (_test.VideoType()) + { + case kVideoCodecVP8: + rtpInfo.type.Video.codec = kRTPVideoVP8; + rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8(); + rtpInfo.type.Video.codecHeader.VP8.nonReference = + videoHdr->codecHeader.VP8.nonReference; + rtpInfo.type.Video.codecHeader.VP8.pictureId = + videoHdr->codecHeader.VP8.pictureId; + break; + case kVideoCodecI420: + rtpInfo.type.Video.codec = kRTPVideoI420; + break; + default: + assert(false); + return -1; + } + rtpInfo.header.payloadType = payloadType; + rtpInfo.header.sequenceNumber = _seqNo++; + rtpInfo.header.ssrc = 0; + rtpInfo.header.timestamp = timeStamp; + rtpInfo.frameType = frameType; + rtpInfo.type.Video.isFirstPacket = true; + // Size should also be received from that table, since the payload type + // defines the size. - _encodedBytes += payloadSize; - if (payloadSize < 20) - { - _skipCnt++; - } - _VCMReceiver->IncomingPacket(payloadData, payloadSize, rtpInfo); - return 0; + _encodedBytes += payloadSize; + if (payloadSize < 20) + { + _skipCnt++; + } + _VCMReceiver->IncomingPacket(payloadData, payloadSize, rtpInfo); + return 0; } void VCMNTEncodeCompleteCallback::RegisterReceiverVCM(VideoCodingModule *vcm) { - _VCMReceiver = vcm; - return; + _VCMReceiver = vcm; + return; } WebRtc_Word32 VCMNTEncodeCompleteCallback::EncodedBytes() { - return _encodedBytes; + return _encodedBytes; } WebRtc_UWord32 VCMNTEncodeCompleteCallback::SkipCnt() { - return _skipCnt; + return _skipCnt; } // Decoded Frame Callback Implementation VCMNTDecodeCompleCallback::~VCMNTDecodeCompleCallback() { if (_decodedFile) - fclose(_decodedFile); + fclose(_decodedFile); } WebRtc_Word32 VCMNTDecodeCompleCallback::FrameToRender(webrtc::I420VideoFrame& videoFrame) @@ -178,7 +178,7 @@ VCMNTDecodeCompleCallback::FrameToRender(webrtc::I420VideoFrame& videoFrame) WebRtc_Word32 VCMNTDecodeCompleCallback::DecodedBytes() { - return _decodedBytes; + return _decodedBytes; } //VCM Normal Test Class implementation @@ -207,210 +207,216 @@ NormalTest::~NormalTest() // } void -NormalTest::Setup(CmdArgs& args) +NormalTest::Setup(const CmdArgs& args) { - _inname = args.inputFile; - _encodedName = test::OutputPath() + "encoded_normaltest.yuv"; - _width = args.width; - _height = args.height; - _frameRate = args.frameRate; - _bitRate = args.bitRate; - if (args.outputFile == "") - { - std::ostringstream filename; - filename << test::OutputPath() << "NormalTest_" << - _width << "x" << _height << "_" << _frameRate << "Hz_P420.yuv"; - _outname = filename.str(); - } - else - { - _outname = args.outputFile; - } - _lengthSourceFrame = 3*_width*_height/2; - _videoType = args.codecType; + _inname = args.inputFile; + _encodedName = test::OutputPath() + "encoded_normaltest.yuv"; + _width = args.width; + _height = args.height; + _frameRate = args.frameRate; + _bitRate = args.bitRate; + if (args.outputFile == "") + { + std::ostringstream filename; + filename << test::OutputPath() << "NormalTest_" << + _width << "x" << _height << "_" << _frameRate << "Hz_P420.yuv"; + _outname = filename.str(); + } + else + { + _outname = args.outputFile; + } + _lengthSourceFrame = 3*_width*_height/2; + _videoType = args.codecType; - 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 ((_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); + } - _log.open((test::OutputPath() + "TestLog.txt").c_str(), - std::fstream::out | std::fstream::app); - return; + _log.open((test::OutputPath() + "TestLog.txt").c_str(), + std::fstream::out | std::fstream::app); } WebRtc_Word32 -NormalTest::Perform(CmdArgs& args) +NormalTest::Perform(const CmdArgs& args) { - Setup(args); - EventWrapper* waitEvent = EventWrapper::Create(); - VideoCodec _sendCodec;//, _receiveCodec; // tmp - sendCodecd used as receive codec - _vcm->InitializeReceiver(); - _vcm->InitializeSender(); - TEST(VideoCodingModule::Codec(_videoType, &_sendCodec) == VCM_OK); - _sendCodec.startBitrate = (int)_bitRate; // should be later on changed via the API - _sendCodec.width = static_cast(_width); - _sendCodec.height = static_cast(_height); - _sendCodec.maxFramerate = _frameRate; - TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1400) == VCM_OK);// will also set and init the desired codec - // register a decoder (same codec for decoder and encoder ) - TEST(_vcm->RegisterReceiveCodec(&_sendCodec, 1) == VCM_OK); - /* Callback Settings */ - VCMNTDecodeCompleCallback _decodeCallback(_outname); - _vcm->RegisterReceiveCallback(&_decodeCallback); - VCMNTEncodeCompleteCallback _encodeCompleteCallback(_encodedFile, *this); - _vcm->RegisterTransportCallback(&_encodeCompleteCallback); - // encode and decode with the same vcm - _encodeCompleteCallback.RegisterReceiverVCM(_vcm); - /////////////////////// - /// Start Test - /////////////////////// - I420VideoFrame sourceFrame; - int size_y = _width * _height; - int half_width = (_width + 1) / 2; - int half_height = (_height + 1) / 2; - int size_uv = half_width * half_height; - sourceFrame.CreateEmptyFrame(_width, _height, - _width, half_width, half_width); - WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame]; - double startTime = clock()/(double)CLOCKS_PER_SEC; - _vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 0); + Setup(args); + EventWrapper* waitEvent = EventWrapper::Create(); + VideoCodec _sendCodec; + _vcm->InitializeReceiver(); + _vcm->InitializeSender(); + TEST(VideoCodingModule::Codec(_videoType, &_sendCodec) == VCM_OK); + // should be later on changed via the API + _sendCodec.startBitrate = (int)_bitRate; + _sendCodec.width = static_cast(_width); + _sendCodec.height = static_cast(_height); + _sendCodec.maxFramerate = _frameRate; + // will also set and init the desired codec + TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1400) == VCM_OK); + // register a decoder (same codec for decoder and encoder ) + TEST(_vcm->RegisterReceiveCodec(&_sendCodec, 1) == VCM_OK); + /* Callback Settings */ + VCMNTDecodeCompleCallback _decodeCallback(_outname); + _vcm->RegisterReceiveCallback(&_decodeCallback); + VCMNTEncodeCompleteCallback _encodeCompleteCallback(_encodedFile, *this); + _vcm->RegisterTransportCallback(&_encodeCompleteCallback); + // encode and decode with the same vcm + _encodeCompleteCallback.RegisterReceiverVCM(_vcm); + /////////////////////// + /// Start Test + /////////////////////// + I420VideoFrame sourceFrame; + int size_y = _width * _height; + int half_width = (_width + 1) / 2; + int half_height = (_height + 1) / 2; + int size_uv = half_width * half_height; + sourceFrame.CreateEmptyFrame(_width, _height, + _width, half_width, half_width); + 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(_frameRate)); - _vcm->RegisterSendStatisticsCallback(&sendStats); + SendStatsTest sendStats; + sendStats.SetTargetFrameRate(static_cast(_frameRate)); + _vcm->RegisterSendStatisticsCallback(&sendStats); - while (feof(_sourceFile) == 0) - { + while (feof(_sourceFile) == 0) { #if !defined(EVENT_DEBUG) - WebRtc_Word64 processStartTime = _clock->MillisecondTimestamp(); -#endif - TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0 || - feof(_sourceFile)); - _frameCnt++; - sourceFrame.CreateFrame(size_y, tmpBuffer, - size_uv, tmpBuffer + size_y, - size_uv, tmpBuffer + size_y + size_uv, - _width, _height, - _width, half_width, half_width); - _timeStamp += (WebRtc_UWord32)(9e4 / static_cast(_sendCodec.maxFramerate)); - sourceFrame.set_timestamp(_timeStamp); - _encodeTimes[int(sourceFrame.timestamp())] = - clock()/(double)CLOCKS_PER_SEC; - WebRtc_Word32 ret = _vcm->AddVideoFrame(sourceFrame); - double encodeTime = clock()/(double)CLOCKS_PER_SEC - - _encodeTimes[int(sourceFrame.timestamp())]; - _totalEncodeTime += encodeTime; - if (ret < 0) - { - printf("Error in AddFrame: %d\n", ret); - //exit(1); - } - _decodeTimes[int(sourceFrame.timestamp())] = - clock()/(double)CLOCKS_PER_SEC; - 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(); - } - WebRtc_UWord32 framePeriod = static_cast(1000.0f/static_cast(_sendCodec.maxFramerate) + 0.5f); -#if defined(EVENT_DEBUG) - static_cast(_clock)->IncrementDebugClock(framePeriod); -#else - WebRtc_Word64 timeSpent = _clock->MillisecondTimestamp() - processStartTime; - if (timeSpent < framePeriod) - { - waitEvent->Wait(framePeriod - timeSpent); - } + WebRtc_Word64 processStartTime = _clock->MillisecondTimestamp(); #endif + TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0 || + feof(_sourceFile)); + _frameCnt++; + sourceFrame.CreateFrame(size_y, tmpBuffer, + size_uv, tmpBuffer + size_y, + size_uv, tmpBuffer + size_y + size_uv, + _width, _height, + _width, half_width, half_width); + _timeStamp += + (WebRtc_UWord32)(9e4 / static_cast(_sendCodec.maxFramerate)); + sourceFrame.set_timestamp(_timeStamp); + _encodeTimes[int(sourceFrame.timestamp())] = + clock()/(double)CLOCKS_PER_SEC; + WebRtc_Word32 ret = _vcm->AddVideoFrame(sourceFrame); + double encodeTime = clock()/(double)CLOCKS_PER_SEC - + _encodeTimes[int(sourceFrame.timestamp())]; + _totalEncodeTime += encodeTime; + if (ret < 0) + { + printf("Error in AddFrame: %d\n", ret); + //exit(1); } - double endTime = clock()/(double)CLOCKS_PER_SEC; - _testTotalTime = endTime - startTime; - _sumEncBytes = _encodeCompleteCallback.EncodedBytes(); + _decodeTimes[int(sourceFrame.timestamp())] = + clock()/(double)CLOCKS_PER_SEC; + 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(); + } + WebRtc_UWord32 framePeriod = + static_cast( + 1000.0f / static_cast(_sendCodec.maxFramerate) + 0.5f); - delete [] tmpBuffer; - delete waitEvent; - Teardown(); - Print(); - return 0; +#if defined(EVENT_DEBUG) + static_cast(_clock)->IncrementDebugClock(framePeriod); +#else + WebRtc_Word64 timeSpent = + _clock->MillisecondTimestamp() - processStartTime; + if (timeSpent < framePeriod) + { + waitEvent->Wait(framePeriod - timeSpent); + } +#endif + } + double endTime = clock()/(double)CLOCKS_PER_SEC; + _testTotalTime = endTime - startTime; + _sumEncBytes = _encodeCompleteCallback.EncodedBytes(); + + delete [] tmpBuffer; + delete waitEvent; + Teardown(); + Print(); + return 0; } void NormalTest::FrameEncoded(WebRtc_UWord32 timeStamp) { - _encodeCompleteTime = clock()/(double)CLOCKS_PER_SEC; - _encFrameCnt++; - _totalEncodePipeTime += _encodeCompleteTime - _encodeTimes[int(timeStamp)]; + _encodeCompleteTime = clock()/(double)CLOCKS_PER_SEC; + _encFrameCnt++; + _totalEncodePipeTime += _encodeCompleteTime - _encodeTimes[int(timeStamp)]; } void NormalTest::FrameDecoded(WebRtc_UWord32 timeStamp) { - _decodeCompleteTime = clock()/(double)CLOCKS_PER_SEC; - _decFrameCnt++; - _totalDecodePipeTime += _decodeCompleteTime - _decodeTimes[timeStamp]; + _decodeCompleteTime = clock()/(double)CLOCKS_PER_SEC; + _decFrameCnt++; + _totalDecodePipeTime += _decodeCompleteTime - _decodeTimes[timeStamp]; } void NormalTest::Print() { - std::cout << "Normal Test Completed!" << std::endl; - (_log) << "Normal 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 / _frameRate)); - double actualBitRate = ActualBitRate / 1000.0; - double avgEncTime = _totalEncodeTime / _frameCnt; - double avgDecTime = _totalDecodeTime / _frameCnt; - webrtc::test::QualityMetricsResult psnr, ssim; - I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, - &psnr); - I420SSIMFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, - &ssim); - 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.average); - ( _log) << "PSNR: " << psnr.average << std::endl; - printf("SSIM: %f \n", ssim.average); - ( _log) << "SSIM: " << ssim.average << std::endl; - (_log) << std::endl; + std::cout << "Normal Test Completed!" << std::endl; + (_log) << "Normal 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 / _frameRate)); + double actualBitRate = ActualBitRate / 1000.0; + double avgEncTime = _totalEncodeTime / _frameCnt; + double avgDecTime = _totalDecodeTime / _frameCnt; + webrtc::test::QualityMetricsResult psnr, ssim; + I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, + &psnr); + I420SSIMFromFiles(_inname.c_str(), _outname.c_str(), _width, _height, + &ssim); + 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.average); + ( _log) << "PSNR: " << psnr.average << std::endl; + printf("SSIM: %f \n", ssim.average); + ( _log) << "SSIM: " << ssim.average << std::endl; + (_log) << std::endl; - printf("\nVCM Normal Test: \n\n%i tests completed\n", vcmMacrosTests); - if (vcmMacrosErrors > 0) - { - printf("%i FAILED\n\n", vcmMacrosErrors); - } - else - { - printf("ALL PASSED\n\n"); - } + printf("\nVCM Normal Test: \n\n%i tests completed\n", vcmMacrosTests); + if (vcmMacrosErrors > 0) + { + printf("%i FAILED\n\n", vcmMacrosErrors); + } + else + { + printf("ALL PASSED\n\n"); + } } void NormalTest::Teardown() { - //_log.close(); - fclose(_sourceFile); - fclose(_encodedFile); - return; + //_log.close(); + fclose(_sourceFile); + fclose(_encodedFile); + return; } diff --git a/webrtc/modules/video_coding/main/test/normal_test.h b/webrtc/modules/video_coding/main/test/normal_test.h index c76178b96a..0394d6e568 100644 --- a/webrtc/modules/video_coding/main/test/normal_test.h +++ b/webrtc/modules/video_coding/main/test/normal_test.h @@ -18,42 +18,46 @@ class NormalTest; -//Send Side - Packetization callback - will create and send a packet to the VCMReceiver +//Send Side - Packetization callback - +// will create and send a packet to the VCMReceiver class VCMNTEncodeCompleteCallback : public webrtc::VCMPacketizationCallback { -public: - // constructor input: file in which encoded data will be written - VCMNTEncodeCompleteCallback(FILE* encodedFile, NormalTest& test); - virtual ~VCMNTEncodeCompleteCallback(); - // Register transport callback - void RegisterTransportCallback(webrtc::VCMPacketizationCallback* transport); - // process encoded data received from the encoder, pass stream to the VCMReceiver module - WebRtc_Word32 SendData(const webrtc::FrameType frameType, - const WebRtc_UWord8 payloadType, - const WebRtc_UWord32 timeStamp, - int64_t capture_time_ms, - const WebRtc_UWord8* payloadData, - const WebRtc_UWord32 payloadSize, - const webrtc::RTPFragmentationHeader& fragmentationHeader, - const webrtc::RTPVideoHeader* videoHdr); + public: + // constructor input: file in which encoded data will be written + VCMNTEncodeCompleteCallback(FILE* encodedFile, NormalTest& test); + virtual ~VCMNTEncodeCompleteCallback(); + // Register transport callback + void RegisterTransportCallback(webrtc::VCMPacketizationCallback* transport); + // process encoded data received from the encoder, + // pass stream to the VCMReceiver module + WebRtc_Word32 + SendData(const webrtc::FrameType frameType, + const WebRtc_UWord8 payloadType, + const WebRtc_UWord32 timeStamp, + int64_t capture_time_ms, + const WebRtc_UWord8* payloadData, + const WebRtc_UWord32 payloadSize, + const webrtc::RTPFragmentationHeader& fragmentationHeader, + const webrtc::RTPVideoHeader* videoHdr); - // Register exisitng VCM. Currently - encode and decode with the same vcm module. - void RegisterReceiverVCM(webrtc::VideoCodingModule *vcm); - // Return sum of encoded data (all frames in the sequence) - WebRtc_Word32 EncodedBytes(); - // return number of encoder-skipped frames - WebRtc_UWord32 SkipCnt();; - // conversion function for payload type (needed for the callback function) + // Register exisitng VCM. + // Currently - encode and decode with the same vcm module. + void RegisterReceiverVCM(webrtc::VideoCodingModule *vcm); + // Return sum of encoded data (all frames in the sequence) + WebRtc_Word32 EncodedBytes(); + // return number of encoder-skipped frames + WebRtc_UWord32 SkipCnt();; + // conversion function for payload type (needed for the callback function) // RTPVideoVideoCodecTypes ConvertPayloadType(WebRtc_UWord8 payloadType); -private: - FILE* _encodedFile; - WebRtc_UWord32 _encodedBytes; - WebRtc_UWord32 _skipCnt; - webrtc::VideoCodingModule* _VCMReceiver; - webrtc::FrameType _frameType; - WebRtc_UWord16 _seqNo; - NormalTest& _test; + private: + FILE* _encodedFile; + WebRtc_UWord32 _encodedBytes; + WebRtc_UWord32 _skipCnt; + webrtc::VideoCodingModule* _VCMReceiver; + webrtc::FrameType _frameType; + WebRtc_UWord16 _seqNo; + NormalTest& _test; }; // end of VCMEncodeCompleteCallback class VCMNTDecodeCompleCallback: public webrtc::VCMReceiveCallback @@ -76,18 +80,16 @@ private: int _decodedBytes; int _currentWidth; int _currentHeight; - }; // end of VCMDecodeCompleCallback class - class NormalTest { public: NormalTest(webrtc::VideoCodingModule* vcm, webrtc::TickTimeBase* clock); ~NormalTest(); - static int RunTest(CmdArgs& args); - WebRtc_Word32 Perform(CmdArgs& args); + static int RunTest(const CmdArgs& args); + WebRtc_Word32 Perform(const CmdArgs& args); // option:: turn into private and call from perform int Width() const { return _width; }; int Height() const { return _height; }; @@ -96,7 +98,7 @@ public: protected: // test setup - open files, general initializations - void Setup(CmdArgs& args); + void Setup(const CmdArgs& args); // close open files, delete used memory void Teardown(); // print results to std output and to log file diff --git a/webrtc/modules/video_coding/main/test/quality_modes_test.cc b/webrtc/modules/video_coding/main/test/quality_modes_test.cc index 5ab045994e..358a3776c0 100644 --- a/webrtc/modules/video_coding/main/test/quality_modes_test.cc +++ b/webrtc/modules/video_coding/main/test/quality_modes_test.cc @@ -10,34 +10,34 @@ #include "quality_modes_test.h" +#include #include #include -#include +#include -#include "../source/event.h" #include "common_video/libyuv/include/webrtc_libyuv.h" +#include "modules/video_coding/main/source/event.h" +#include "modules/video_coding/main/source/mock/fake_tick_time.h" #include "modules/video_coding/main/source/tick_time_base.h" -#include "test_callbacks.h" -#include "test_macros.h" +#include "modules/video_coding/main/test/test_callbacks.h" +#include "modules/video_coding/main/test/test_macros.h" +#include "modules/video_coding/main/test/test_util.h" +#include "system_wrappers/interface/data_log.h" +#include "system_wrappers/interface/data_log.h" #include "testsupport/metrics/video_metrics.h" using namespace webrtc; -int qualityModeTest() +int qualityModeTest(const CmdArgs& args) { - // Don't run this test with debug events. -#if defined(EVENT_DEBUG) - return -1; -#endif - TickTimeBase clock; - VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock); - QualityModesTest QMTest(vcm, &clock); - QMTest.Perform(); - VideoCodingModule::Destroy(vcm); - return 0; + FakeTickTime clock(0); + VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock); + QualityModesTest QMTest(vcm, &clock); + QMTest.Perform(args); + VideoCodingModule::Destroy(vcm); + return 0; } - QualityModesTest::QualityModesTest(VideoCodingModule* vcm, TickTimeBase* clock): NormalTest(vcm, clock), @@ -46,320 +46,377 @@ _vpm() // } - QualityModesTest::~QualityModesTest() { // } void -QualityModesTest::Setup() +QualityModesTest::Setup(const CmdArgs& args) { + NormalTest::Setup(args); + _inname = args.inputFile; + _outname = args.outputFile; + fv_outfilename_ = args.fv_outputfile; + filename_testvideo_ = + _inname.substr(_inname.find_last_of("\\/") + 1,_inname.length()); - _inname= test::ProjectRootPath() + "resources/crew_30f_4CIF.yuv"; - _outname = test::OutputPath() + "out_qmtest.yuv"; - _encodedName = test::OutputPath() + "encoded_qmtest.yuv"; + _encodedName = test::OutputPath() + "encoded_qmtest.yuv"; - //NATIVE/SOURCE VALUES - _nativeWidth = 2*352; - _nativeHeight = 2*288; - _nativeFrameRate = 30; + //NATIVE/SOURCE VALUES + _nativeWidth = args.width; + _nativeHeight = args.height; + _nativeFrameRate =args.frameRate; + //TARGET/ENCODER VALUES + _width = args.width; + _height = args.height; + _frameRate = args.frameRate; - //TARGET/ENCODER VALUES - _width = 2*352; - _height = 2*288; - _frameRate = 30; - // - _bitRate = 400; + _bitRate = args.bitRate; - _flagSSIM = false; + _flagSSIM = true; - _lengthSourceFrame = 3*_nativeWidth*_nativeHeight/2; + _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); - } + 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((test::OutputPath() + "TestLog.txt").c_str(), - std::fstream::out | std::fstream::app); - return; + DataLog::CreateLog(); + + feature_table_name_ = fv_outfilename_; + + DataLog::AddTable(feature_table_name_); + + DataLog::AddColumn(feature_table_name_, "motion magnitude", 1); + DataLog::AddColumn(feature_table_name_, "spatial prediction error", 1); + DataLog::AddColumn(feature_table_name_, "spatial pred err horizontal", 1); + DataLog::AddColumn(feature_table_name_, "spatial pred err vertical", 1); + DataLog::AddColumn(feature_table_name_, "width", 1); + DataLog::AddColumn(feature_table_name_, "height", 1); + DataLog::AddColumn(feature_table_name_, "num pixels", 1); + DataLog::AddColumn(feature_table_name_, "frame rate", 1); + DataLog::AddColumn(feature_table_name_, "num frames since drop", 1); + + _log.open((test::OutputPath() + "TestLog.txt").c_str(), + std::fstream::out | std::fstream::app); } - 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; - webrtc::test::QualityMetricsResult psnr,ssim; - I420PSNRFromFiles(_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.average); - printf("**Number of frames dropped in VPM***%d \n",_numFramesDroppedVPM); - ( _log) << "PSNR: " << psnr.average << std::endl; - if (_flagSSIM == 1) - { - printf("***computing SSIM***\n"); - I420SSIMFromFiles(_inname.c_str(), _outname.c_str(), _nativeWidth, - _nativeHeight, &ssim); - printf("SSIM: %f \n", ssim.average); - } - (_log) << std::endl; + 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; + webrtc::test::QualityMetricsResult psnr,ssim; + I420PSNRFromFiles(_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.average); + printf("**Number of frames dropped in VPM***%d \n",_numFramesDroppedVPM); + ( _log) << "PSNR: " << psnr.average << std::endl; + if (_flagSSIM == 1) + { + printf("***computing SSIM***\n"); + I420SSIMFromFiles(_inname.c_str(), _outname.c_str(), _nativeWidth, + _nativeHeight, &ssim); + printf("SSIM: %f \n", ssim.average); + } + (_log) << std::endl; - printf("\nVCM Qualit Modes Test: \n\n%i tests completed\n", vcmMacrosTests); - if (vcmMacrosErrors > 0) - { - printf("%i FAILED\n\n", vcmMacrosErrors); - } - else - { - printf("ALL PASSED\n\n"); - } + printf("\nVCM Quality Modes Test: \n\n%i tests completed\n", vcmMacrosTests); + if (vcmMacrosErrors > 0) + { + printf("%i FAILED\n\n", vcmMacrosErrors); + } + else + { + printf("ALL PASSED\n\n"); + } } void QualityModesTest::Teardown() { - _log.close(); - fclose(_sourceFile); - fclose(_decodedFile); - fclose(_encodedFile); - return; + _log.close(); + fclose(_sourceFile); + fclose(_decodedFile); + fclose(_encodedFile); + return; } - WebRtc_Word32 -QualityModesTest::Perform() +QualityModesTest::Perform(const CmdArgs& args) { - 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 + Setup(args); + // changing bit/frame rate during the test + const float bitRateUpdate[] = {1000}; + const float frameRateUpdate[] = {30}; + // frame num at which an update will occur + const int updateFrameNum[] = {10000}; - WebRtc_UWord32 numChanges = sizeof(updateFrameNum)/sizeof(*updateFrameNum); - WebRtc_UWord8 change = 0;// change counter + 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++) + _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) { - _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; - } + codec.startBitrate = (int)_bitRate; + codec.maxFramerate = (WebRtc_UWord8) _frameRate; + codec.width = (WebRtc_UWord16)_width; + codec.height = (WebRtc_UWord16)_height; + codec.codecSpecific.VP8.frameDroppingOn = false; + + // Will also set and init the desired codec + TEST(_vcm->RegisterSendCodec(&codec, 2, 1440) == VCM_OK); + 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); + // register a decoder (same codec for decoder and encoder ) + TEST(_vcm->RegisterReceiveCodec(&codec, 2) == VCM_OK); + /* Callback Settings */ + VCMQMDecodeCompleCallback _decodeCallback( + _decodedFile, _nativeFrameRate, feature_table_name_); + _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); + //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); + /////////////////////// + /// Start Test + /////////////////////// + _vpm->EnableTemporalDecimation(true); + _vpm->EnableContentAnalysis(true); + _vpm->SetInputFrameResampleMode(kFastRescaling); - // disabling internal VCM frame dropper - _vcm->EnableFrameDropper(false); + // disabling internal VCM frame dropper + _vcm->EnableFrameDropper(false); - I420VideoFrame sourceFrame; - I420VideoFrame *decimatedFrame = NULL; - WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame]; - double startTime = clock()/(double)CLOCKS_PER_SEC; - _vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 0); + I420VideoFrame sourceFrame; + I420VideoFrame *decimatedFrame = NULL; + 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(_frameRate)); - _vcm->RegisterSendStatisticsCallback(&sendStats); + SendStatsTest sendStats; + sendStats.SetTargetFrameRate(static_cast(_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); + 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); + //tmp - disabling VPM frame dropping + _vpm->EnableTemporalDecimation(false); + + WebRtc_Word32 ret = 0; + _numFramesDroppedVPM = 0; + + do { + if (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0) { + _frameCnt++; + int size_y = _nativeWidth * _nativeHeight; + int size_uv = ((_nativeWidth + 1) / 2) * ((_nativeHeight + 1) / 2); + sourceFrame.CreateFrame(size_y, tmpBuffer, + size_uv, tmpBuffer + size_y, + size_uv, tmpBuffer + size_y + size_uv, + _nativeWidth, _nativeHeight, + _nativeWidth, (_nativeWidth + 1) / 2, + (_nativeWidth + 1) / 2); + + _timeStamp += + (WebRtc_UWord32)(9e4 / static_cast(codec.maxFramerate)); + sourceFrame.set_timestamp(_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); + } + // Frame was not re-sampled => use original. + if (decimatedFrame == NULL) + { + decimatedFrame = &sourceFrame; + } + 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); + } + + // Same timestamp value for encode and decode + _decodeTimes[int(sourceFrame.timestamp())] = + clock()/(double)CLOCKS_PER_SEC; + 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); + } + + // 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; + // Will also set and init the desired codec + TEST(_vcm->RegisterSendCodec(&codec, 2, 1440) == VCM_OK); + change++; + } + + DataLog::InsertCell(feature_table_name_, "motion magnitude", + contentMetrics->motion_magnitude); + DataLog::InsertCell(feature_table_name_, "spatial prediction error", + contentMetrics->spatial_pred_err); + DataLog::InsertCell(feature_table_name_, "spatial pred err horizontal", + contentMetrics->spatial_pred_err_h); + DataLog::InsertCell(feature_table_name_, "spatial pred err vertical", + contentMetrics->spatial_pred_err_v); + + DataLog::InsertCell(feature_table_name_, "width", _nativeHeight); + DataLog::InsertCell(feature_table_name_, "height", _nativeWidth); + + DataLog::InsertCell(feature_table_name_, "num pixels", + _nativeHeight * _nativeWidth); + + DataLog::InsertCell(feature_table_name_, "frame rate", _nativeFrameRate); + DataLog::NextRow(feature_table_name_); + + static_cast( + _clock)->IncrementDebugClock(1000 / _nativeFrameRate); + } + + } while (feof(_sourceFile) == 0); + _decodeCallback.WriteEnd(_frameCnt); - WebRtc_Word32 ret = 0; - _numFramesDroppedVPM = 0; - while (feof(_sourceFile)== 0) - { - TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0); - _frameCnt++; - int size_y = _nativeWidth * _nativeHeight; - int size_uv = ((_nativeWidth + 1) / 2) * ((_nativeHeight + 1) / 2); - sourceFrame.CreateFrame(size_y, tmpBuffer, - size_uv, tmpBuffer + size_y, - size_uv, tmpBuffer + size_y + size_uv, - _nativeWidth, _nativeHeight, - _nativeWidth, (_nativeWidth + 1) / 2, - (_nativeWidth + 1) / 2); + double endTime = clock()/(double)CLOCKS_PER_SEC; + _testTotalTime = endTime - startTime; + _sumEncBytes = _encodeCompleteCallback.EncodedBytes(); - _timeStamp += (WebRtc_UWord32)(9e4 / static_cast(codec.maxFramerate)); - sourceFrame.set_timestamp(_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 - _decodeTimes[int(sourceFrame.timestamp())]; - 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); - 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; + 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; + _vpm = vpm; } void QMTestVideoSettingsCallback::RegisterVCM(VideoCodingModule *vcm) { - _vcm = vcm; + _vcm = vcm; } bool QMTestVideoSettingsCallback::Updated() { - if (_updated) - { - _updated = false; - return true; - } - return false; + if (_updated) + { + _updated = false; + return true; + } + return false; } WebRtc_Word32 @@ -367,31 +424,31 @@ 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; + 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; - } + // re-register encoder + retVal = _vcm->RegisterSendCodec(¤tCodec, 2, 1440); + _updated = true; + } - return retVal; + return retVal; } - -// Decoded Frame Callback Implmentation -VCMQMDecodeCompleCallback::VCMQMDecodeCompleCallback(FILE* decodedFile): +// Decoded Frame Callback Implementation +VCMQMDecodeCompleCallback::VCMQMDecodeCompleCallback( + FILE* decodedFile, int frame_rate, std::string feature_table_name): _decodedFile(decodedFile), _decodedBytes(0), //_test(test), @@ -401,7 +458,10 @@ _decWidth(0), _decHeight(0), //_interpolator(NULL), _decBuffer(NULL), -_frameCnt(0) +_frameCnt(0), +frame_rate_(frame_rate), +frames_cnt_since_drop_(0), +feature_table_name_(feature_table_name) { // } @@ -413,69 +473,106 @@ VCMQMDecodeCompleCallback::~VCMQMDecodeCompleCallback() // deleteInterpolator(_interpolator); // _interpolator = NULL; // } - if (_decBuffer != NULL) - { - delete [] _decBuffer; - _decBuffer = NULL; - } + if (_decBuffer != NULL) + { + delete [] _decBuffer; + _decBuffer = NULL; + } } + WebRtc_Word32 VCMQMDecodeCompleCallback::FrameToRender(I420VideoFrame& videoFrame) { - if ((_origWidth == videoFrame.width()) && - (_origHeight == videoFrame.height())) - { - if (PrintI420VideoFrame(videoFrame, _decodedFile) < 0) { - return -1; - } - _frameCnt++; - // no need for interpolator and decBuffer - if (_decBuffer != NULL) - { - delete [] _decBuffer; - _decBuffer = NULL; - } - _decWidth = 0; - _decHeight = 0; - } - else - { - // TODO(mikhal): Add support for scaling. + ++frames_cnt_since_drop_; + + // When receiving the first coded frame the last_frame variable is not set + if (last_frame_.IsZeroSize()) { + last_frame_.CopyFrame(videoFrame); + } + + // Check if there were frames skipped. + int num_frames_skipped = static_cast( 0.5f + + (videoFrame.timestamp() - (last_frame_.timestamp() + (9e4 / frame_rate_))) / + (9e4 / frame_rate_)); + + // If so...put the last frames into the encoded stream to make up for the + // skipped frame(s) + while (num_frames_skipped > 0) { + PrintI420VideoFrame(last_frame_, _decodedFile); + _frameCnt++; + --num_frames_skipped; + frames_cnt_since_drop_ = 1; // Reset counter + + } + + DataLog::InsertCell( + feature_table_name_,"num frames since drop",frames_cnt_since_drop_); + + if (_origWidth == videoFrame.width() && _origHeight == videoFrame.height()) + { + if (PrintI420VideoFrame(videoFrame, _decodedFile) < 0) { return -1; } - - _decodedBytes += CalcBufferSize(kI420, videoFrame.width(), - videoFrame.height()); - 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() -{ - WebRtc_UWord32 decFrameLength = _origWidth*_origHeight*3 >> 1; + _frameCnt++; + // no need for interpolator and decBuffer if (_decBuffer != NULL) { delete [] _decBuffer; + _decBuffer = NULL; } - _decBuffer = new WebRtc_UWord8[decFrameLength]; - if (_decBuffer == NULL) - { - return -1; - } + _decWidth = 0; + _decHeight = 0; + } + else + { + // TODO(mikhal): Add support for scaling. + return -1; + } - return 0; + _decodedBytes += CalcBufferSize(kI420, videoFrame.width(), + videoFrame.height()); + videoFrame.SwapFrame(&last_frame_); + 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() +{ + WebRtc_UWord32 decFrameLength = _origWidth*_origHeight*3 >> 1; + if (_decBuffer != NULL) + { + delete [] _decBuffer; + } + _decBuffer = new WebRtc_UWord8[decFrameLength]; + if (_decBuffer == NULL) + { + return -1; + } + return 0; +} + +// This function checks if the total number of frames processed in the encoding +// process is the same as the number of frames rendered. If not, the last +// frame (or several consecutive frames from the end) must have been dropped. If +// this is the case, the last frame is repeated so that there are as many +// frames rendered as there are number of frames encoded. +void VCMQMDecodeCompleCallback::WriteEnd(int input_frame_count) +{ + int num_missing_frames = input_frame_count - _frameCnt; + + for (int n = num_missing_frames; n > 0; --n) { + PrintI420VideoFrame(last_frame_, _decodedFile); + _frameCnt++; + } } diff --git a/webrtc/modules/video_coding/main/test/quality_modes_test.h b/webrtc/modules/video_coding/main/test/quality_modes_test.h index 5b80c81080..10f023b395 100644 --- a/webrtc/modules/video_coding/main/test/quality_modes_test.h +++ b/webrtc/modules/video_coding/main/test/quality_modes_test.h @@ -13,9 +13,10 @@ #include "video_processing.h" #include "normal_test.h" +#include "system_wrappers/interface/data_log.h" #include "video_coding_defines.h" -int qualityModeTest(); +int qualityModeTest(const CmdArgs& args); class QualityModesTest : public NormalTest { @@ -23,11 +24,11 @@ public: QualityModesTest(webrtc::VideoCodingModule* vcm, webrtc::TickTimeBase* clock); virtual ~QualityModesTest(); - WebRtc_Word32 Perform(); + WebRtc_Word32 Perform(const CmdArgs& args); private: - void Setup(); + void Setup(const CmdArgs& args); void Print(); void Teardown(); void SsimComp(); @@ -43,14 +44,20 @@ private: WebRtc_UWord32 _numFramesDroppedVPM; bool _flagSSIM; + std::string filename_testvideo_; + std::string fv_outfilename_; + + std::string feature_table_name_; }; // end of QualityModesTest class - class VCMQMDecodeCompleCallback: public webrtc::VCMReceiveCallback { public: - VCMQMDecodeCompleCallback(FILE* decodedFile); + VCMQMDecodeCompleCallback( + FILE* decodedFile, + int frame_rate, + std::string feature_table_name); virtual ~VCMQMDecodeCompleCallback(); void SetUserReceiveCallback(webrtc::VCMReceiveCallback* receiveCallback); // will write decoded frame into file @@ -58,6 +65,9 @@ public: WebRtc_Word32 DecodedBytes(); void SetOriginalFrameDimensions(WebRtc_Word32 width, WebRtc_Word32 height); WebRtc_Word32 buildInterpolator(); + // Check if last frame is dropped, if so, repeat the last rendered frame. + void WriteEnd(int input_tot_frame_count); + private: FILE* _decodedFile; WebRtc_UWord32 _decodedBytes; @@ -69,6 +79,12 @@ private: // VideoInterpolator* _interpolator; WebRtc_UWord8* _decBuffer; WebRtc_UWord32 _frameCnt; // debug + webrtc::I420VideoFrame last_frame_; + int frame_rate_; + int frames_cnt_since_drop_; + std::string feature_table_name_; + + }; // end of VCMQMDecodeCompleCallback class diff --git a/webrtc/modules/video_coding/main/test/test_util.h b/webrtc/modules/video_coding/main/test/test_util.h index d705434ce9..c5b8545bb0 100644 --- a/webrtc/modules/video_coding/main/test/test_util.h +++ b/webrtc/modules/video_coding/main/test/test_util.h @@ -41,7 +41,8 @@ class CmdArgs "/resources/foreman_cif.yuv"), outputFile(webrtc::test::OutputPath() + "video_coding_test_output_352x288.yuv"), - testNum(11) {} + fv_outputfile(webrtc::test::OutputPath() + "features.txt"), + testNum(0) {} std::string codecName; webrtc::VideoCodecType codecType; int width; @@ -54,6 +55,7 @@ class CmdArgs int camaEnable; std::string inputFile; std::string outputFile; + std::string fv_outputfile; int testNum; }; diff --git a/webrtc/modules/video_coding/main/test/tester_main.cc b/webrtc/modules/video_coding/main/test/tester_main.cc index e5d7cd37ea..432178a4bf 100644 --- a/webrtc/modules/video_coding/main/test/tester_main.cc +++ b/webrtc/modules/video_coding/main/test/tester_main.cc @@ -37,171 +37,185 @@ int vcmMacrosErrors = 0; int ParseArguments(int argc, char **argv, CmdArgs& args) { int i = 1; + while (i < argc) { - if (argv[i][0] != '-') - { - return -1; - } - switch (argv[i][1]) - { - case 'w': - { - int w = atoi(argv[i+1]); - if (w < 1) - return -1; - args.width = w; - break; - } - case 'h': - { - int h = atoi(argv[i+1]); - if (h < 1) - return -1; - args.height = h; - break; - } - case 'b': - { - int b = atoi(argv[i+1]); - if (b < 1) - return -1; - args.bitRate = b; - break; - } - case 'f': - { - int f = atoi(argv[i+1]); - if (f < 1) - return -1; - args.frameRate = f; - break; - } - case 'c': - { - // TODO(holmer): This should be replaced with a map if more codecs - // are added - args.codecName = argv[i+1]; - if (strncmp(argv[i+1], "VP8", 3) == 0) - { - args.codecType = kVideoCodecVP8; - } - else if (strncmp(argv[i+1], "I420", 4) == 0) - { - args.codecType = kVideoCodecI420; - } - else - return -1; + if (argv[i+1] == '\0') + { + printf( "You did not supply a parameter value\n." ); + return -1; + } - break; - } - case 'i': - { - args.inputFile = argv[i+1]; - break; - } - case 'o': - args.outputFile = argv[i+1]; - break; - case 'n': - { - int n = atoi(argv[i+1]); - if (n < 1) - return -1; - args.testNum = n; - break; - } - case 'p': - { - args.packetLoss = atoi(argv[i+1]); - break; - } - case 'r': - { - args.rtt = atoi(argv[i+1]); - break; - } - case 'm': - { - args.protectionMode = atoi(argv[i+1]); - break; - } - case 'e': - { - args.camaEnable = atoi(argv[i+1]); - break; - } - default: - return -1; - } - i += 2; + if (argv[i][0] != '-') + { + return -1; + } + switch (argv[i][1]) + { + case 'w': + { + int w = atoi(argv[i+1]); + if (w < 1) + return -1; + args.width = w; + break; + } + case 'h': + { + int h = atoi(argv[i+1]); + if (h < 1) + return -1; + args.height = h; + break; + } + case 'b': + { + int b = atoi(argv[i+1]); + if (b < 1) + return -1; + args.bitRate = b; + break; + } + case 'f': + { + int f = atoi(argv[i+1]); + if (f < 1) + return -1; + args.frameRate = f; + break; + } + case 'c': + { + // TODO(holmer): This should be replaced with a map if more codecs + // are added + args.codecName = argv[i+1]; + if (strncmp(argv[i+1], "VP8", 3) == 0) + { + args.codecType = kVideoCodecVP8; + } + else if (strncmp(argv[i+1], "I420", 4) == 0) + { + args.codecType = kVideoCodecI420; + } + else + return -1; + + break; + } + case 'i': + { + args.inputFile = argv[i+1]; + break; + } + case 'o': + args.outputFile = argv[i+1]; + break; + case 'n': + { + int n = atoi(argv[i+1]); + if (n < 1) + return -1; + args.testNum = n; + break; + } + case 'p': + { + args.packetLoss = atoi(argv[i+1]); + break; + } + case 'r': + { + args.rtt = atoi(argv[i+1]); + break; + } + case 'm': + { + args.protectionMode = atoi(argv[i+1]); + break; + } + case 'e': + { + args.camaEnable = atoi(argv[i+1]); + break; + } + case 'v': + { + args.fv_outputfile = argv[i+1]; + break; + } + default: + return -1; + } + i += 2; } return 0; } int main(int argc, char **argv) { - CmdArgs args; + CmdArgs args; - if (ParseArguments(argc, argv, args) != 0) - { - printf("Unable to parse input arguments\n"); - printf("args: -n -w -h -f -b " - "-c -i -o -p " - "-r -e -m \n"); - return -1; - } + if (ParseArguments(argc, argv, args) != 0) + { + printf("Unable to parse input arguments\n"); + printf("args: -n -w -h -f -b " + "-c -i -o -p " + "-r -e -m \n"); + return -1; + } - int ret = 0; - switch (args.testNum) - { + int ret = 0; + switch (args.testNum) { + case 0: + ret = NormalTest::RunTest(args); + ret |= CodecDataBaseTest::RunTest(args); + ret |= ReceiverTimingTests(args); + ret |= JitterBufferTest(args); + break; case 1: - ret = NormalTest::RunTest(args); - break; + ret = NormalTest::RunTest(args); + break; case 2: - ret = MTRxTxTest(args); - break; + ret = MTRxTxTest(args); + break; case 3: - ret = GenericCodecTest::RunTest(args); - break; + ret = GenericCodecTest::RunTest(args); + break; case 4: - ret = CodecDataBaseTest::RunTest(args); - break; + ret = CodecDataBaseTest::RunTest(args); + break; case 5: - // 0- normal, 1-Release test(50 runs) 2- from file - ret = MediaOptTest::RunTest(0, args); - break; + // 0- normal, 1-Release test(50 runs) 2- from file + ret = MediaOptTest::RunTest(0, args); + break; case 6: - ret = ReceiverTimingTests(args); - break; + ret = ReceiverTimingTests(args); + break; case 7: - ret = RtpPlay(args); - break; + ret = RtpPlay(args); + break; case 8: - ret = RtpPlayMT(args); - break; + ret = RtpPlayMT(args); + break; case 9: - ret = JitterBufferTest(args); - break; + ret = JitterBufferTest(args); + break; case 10: - ret = DecodeFromStorageTest(args); - break; + ret = DecodeFromStorageTest(args); + break; case 11: - ret = NormalTest::RunTest(args); - ret |= CodecDataBaseTest::RunTest(args); - ret |= ReceiverTimingTests(args); - ret |= JitterBufferTest(args); - break; + qualityModeTest(args); + break; default: - ret = -1; - break; - } - if (ret != 0) - { - printf("Test failed!\n"); - return -1; - } - return 0; + ret = -1; + break; + } + if (ret != 0) + { + printf("Test failed!\n"); + return -1; + } + return 0; } diff --git a/webrtc/system_wrappers/source/data_log_unittest.cc b/webrtc/system_wrappers/source/data_log_unittest.cc index c64ed94d6c..c4d6772307 100644 --- a/webrtc/system_wrappers/source/data_log_unittest.cc +++ b/webrtc/system_wrappers/source/data_log_unittest.cc @@ -23,7 +23,7 @@ using ::webrtc::DataLog; struct ExpectedValues { public: ExpectedValues() - : values(NULL), + : values(), multi_value_length(1) { }