Remove command-line tool 'video_coding_test'.
Removes a lot of code that prevents refactoring VideoCodingModule. Tests covering the module should be TEST_Fs, and this looks like like fairly unused code in general. Adds a 'rtp_player' binary which performs a small subset. BUG=4391 R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/44559004 Cr-Commit-Position: refs/heads/master@{#8787} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8787 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c4709a2930
commit
d21406d333
@ -17,8 +17,8 @@
|
|||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
||||||
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
|
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
|
||||||
#include "webrtc/modules/video_coding/main/source/timing.h"
|
#include "webrtc/modules/video_coding/main/source/timing.h"
|
||||||
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/clock.h"
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
#include "webrtc/system_wrappers/interface/trace.h"
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
#include "webrtc/test/testsupport/fileutils.h"
|
||||||
|
|
||||||
|
@ -1,411 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Implementation of codec data base test
|
|
||||||
// testing is done via the VCM module, no specific CodecDataBase module functionality.
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/test/codec_database_test.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "webrtc/engine_configurations.h"
|
|
||||||
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
#include "webrtc/test/testsupport/metrics/video_metrics.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
int CodecDataBaseTest::RunTest(CmdArgs& args)
|
|
||||||
{
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(nullptr);
|
|
||||||
CodecDataBaseTest* cdbt = new CodecDataBaseTest(vcm);
|
|
||||||
cdbt->Perform(args);
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
delete cdbt;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CodecDataBaseTest::CodecDataBaseTest(VideoCodingModule* vcm):
|
|
||||||
_vcm(vcm),
|
|
||||||
_width(0),
|
|
||||||
_height(0),
|
|
||||||
_lengthSourceFrame(0),
|
|
||||||
_timeStamp(0)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
CodecDataBaseTest::~CodecDataBaseTest()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
void
|
|
||||||
CodecDataBaseTest::Setup(CmdArgs& args)
|
|
||||||
{
|
|
||||||
_inname= args.inputFile;
|
|
||||||
_width = args.width;
|
|
||||||
_height = args.height;
|
|
||||||
_frameRate = args.frameRate;
|
|
||||||
_lengthSourceFrame = 3*_width*_height/2;
|
|
||||||
if (args.outputFile.compare(""))
|
|
||||||
_outname = test::OutputPath() + "CDBtest_decoded.yuv";
|
|
||||||
else
|
|
||||||
_outname = args.outputFile;
|
|
||||||
_outname = args.outputFile;
|
|
||||||
_encodedName = test::OutputPath() + "CDBtest_encoded.vp8";
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
CodecDataBaseTest::Perform(CmdArgs& args)
|
|
||||||
{
|
|
||||||
#ifndef VIDEOCODEC_VP8
|
|
||||||
assert(false);
|
|
||||||
#endif
|
|
||||||
Setup(args);
|
|
||||||
EventWrapper* waitEvent = EventWrapper::Create();
|
|
||||||
|
|
||||||
/**************************/
|
|
||||||
/* General Sanity Checks */
|
|
||||||
/************************/
|
|
||||||
VideoCodec sendCodec, receiveCodec;
|
|
||||||
TEST(VideoCodingModule::NumberOfCodecs() > 0);
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
VCMDecodeCompleteCallback *_decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
|
|
||||||
VCMEncodeCompleteCallback *_encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
|
|
||||||
_vcm->RegisterReceiveCallback(_decodeCallback);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
_encodeCompleteCallback->SetFrameDimensions(_width, _height);
|
|
||||||
// registering the callback - encode and decode with the same vcm (could be later changed)
|
|
||||||
_encodeCompleteCallback->RegisterReceiverVCM(_vcm);
|
|
||||||
// preparing a frame to be encoded
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
I420VideoFrame sourceFrame;
|
|
||||||
int half_width = (_width + 1) / 2;
|
|
||||||
int half_height = (_height + 1) / 2;
|
|
||||||
int size_y = _width * _height;
|
|
||||||
int size_uv = half_width * half_height;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
// Encoder registration
|
|
||||||
TEST (VideoCodingModule::NumberOfCodecs() > 0);
|
|
||||||
TEST(VideoCodingModule::Codec(VideoCodingModule::NumberOfCodecs() + 1u,
|
|
||||||
&sendCodec) < 0);
|
|
||||||
VideoCodingModule::Codec(1, &sendCodec);
|
|
||||||
sendCodec.plType = 0; // random value
|
|
||||||
TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0);
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_vcm->RegisterReceiveCallback(_decodeCallback);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
printf(" \nNumber of Registered Codecs: %d \n\n", VideoCodingModule::NumberOfCodecs());
|
|
||||||
printf("Registered codec names: ");
|
|
||||||
for (int i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
|
|
||||||
{
|
|
||||||
VideoCodingModule::Codec(i, &sendCodec);
|
|
||||||
printf("%s ", sendCodec.plName);
|
|
||||||
}
|
|
||||||
printf("\n\nVerify that all requested codecs are used\n \n \n");
|
|
||||||
|
|
||||||
// Testing with VP8.
|
|
||||||
VideoCodingModule::Codec(kVideoCodecVP8, &sendCodec);
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 1, 1440);
|
|
||||||
_encodeCompleteCallback->SetCodecType(kRtpVideoVp8);
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK );
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
TEST (_vcm->AddVideoFrame(sourceFrame) < 0 );
|
|
||||||
|
|
||||||
// Test changing frame size while keeping the same payload type
|
|
||||||
VideoCodingModule::Codec(0, &sendCodec);
|
|
||||||
sendCodec.width = 352;
|
|
||||||
sendCodec.height = 288;
|
|
||||||
VideoCodec currentSendCodec;
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 1, 1440);
|
|
||||||
_vcm->SendCodec(¤tSendCodec);
|
|
||||||
TEST(currentSendCodec.width == sendCodec.width &&
|
|
||||||
currentSendCodec.height == sendCodec.height);
|
|
||||||
sendCodec.width = 352/2;
|
|
||||||
sendCodec.height = 288/2;
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 1, 1440);
|
|
||||||
_vcm->SendCodec(¤tSendCodec);
|
|
||||||
TEST(currentSendCodec.width == sendCodec.width &&
|
|
||||||
currentSendCodec.height == sendCodec.height);
|
|
||||||
|
|
||||||
delete _decodeCallback;
|
|
||||||
_decodeCallback = NULL;
|
|
||||||
delete _encodeCompleteCallback;
|
|
||||||
_encodeCompleteCallback = NULL;
|
|
||||||
|
|
||||||
VCMEncodeCompleteCallback *_encodeCallback = new VCMEncodeCompleteCallback(_encodedFile);
|
|
||||||
|
|
||||||
/*************************/
|
|
||||||
/* External codecs */
|
|
||||||
/*************************/
|
|
||||||
|
|
||||||
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
VP8Decoder* decoder = VP8Decoder::Create();
|
|
||||||
VideoCodec vp8DecSettings;
|
|
||||||
VideoCodingModule::Codec(kVideoCodecVP8, &vp8DecSettings);
|
|
||||||
TEST(_vcm->RegisterExternalDecoder(decoder, vp8DecSettings.plType, false) == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&vp8DecSettings, 1, false) == VCM_OK);
|
|
||||||
VP8Encoder* encoder = VP8Encoder::Create();
|
|
||||||
VideoCodec vp8EncSettings;
|
|
||||||
VideoCodingModule::Codec(kVideoCodecVP8, &vp8EncSettings);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
|
|
||||||
_encodeCallback->RegisterReceiverVCM(_vcm);
|
|
||||||
_encodeCallback->SetCodecType(kRtpVideoVp8);
|
|
||||||
TEST(_vcm->RegisterExternalEncoder(encoder, vp8EncSettings.plType) == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterSendCodec(&vp8EncSettings, 4, 1440) == VCM_OK);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
waitEvent->Wait(33);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
|
|
||||||
// De-register and try again.
|
|
||||||
TEST(_vcm->RegisterExternalDecoder(NULL, vp8DecSettings.plType, false) == VCM_OK);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() < 0); // Expect an error since we have de-registered the decoder
|
|
||||||
TEST(_vcm->RegisterExternalEncoder(NULL, vp8DecSettings.plType) == VCM_OK);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) < 0); // No send codec registered
|
|
||||||
|
|
||||||
delete decoder;
|
|
||||||
decoder = NULL;
|
|
||||||
delete encoder;
|
|
||||||
encoder = NULL;
|
|
||||||
|
|
||||||
/***************************************
|
|
||||||
* Test the "require key frame" setting*
|
|
||||||
***************************************/
|
|
||||||
|
|
||||||
TEST(_vcm->InitializeSender() == VCM_OK);
|
|
||||||
TEST(_vcm->InitializeReceiver() == VCM_OK);
|
|
||||||
VideoCodingModule::Codec(kVideoCodecVP8, &receiveCodec);
|
|
||||||
receiveCodec.height = _height;
|
|
||||||
receiveCodec.width = _width;
|
|
||||||
TEST(_vcm->RegisterSendCodec(&receiveCodec, 4, 1440) == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&receiveCodec, 1, true) == VCM_OK); // Require key frame
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCallback); // encode returns error if callback uninitialized
|
|
||||||
_encodeCallback->RegisterReceiverVCM(_vcm);
|
|
||||||
_encodeCallback->SetCodecType(kRtpVideoVp8);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
TEST(_vcm->ResetDecoder() == VCM_OK);
|
|
||||||
waitEvent->Wait(33);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
// Try to decode a delta frame. Should get a warning since we have enabled the "require key frame" setting
|
|
||||||
// and because no frame type request callback has been registered.
|
|
||||||
TEST(_vcm->Decode() == VCM_MISSING_CALLBACK);
|
|
||||||
TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
|
|
||||||
// Make sure we can register another codec with the same
|
|
||||||
// payload type without crash.
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
sendCodec.width = _width;
|
|
||||||
sendCodec.height = _height;
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
|
|
||||||
TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
|
|
||||||
waitEvent->Wait(33);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
|
|
||||||
waitEvent->Wait(33);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->IntraFrameRequest(0) == VCM_OK);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
TEST(_vcm->ResetDecoder() == VCM_OK);
|
|
||||||
|
|
||||||
delete _encodeCallback;
|
|
||||||
|
|
||||||
/*************************/
|
|
||||||
/* Send/Receive Control */
|
|
||||||
/***********************/
|
|
||||||
/*
|
|
||||||
1. check available codecs (N)
|
|
||||||
2. register all corresponding decoders
|
|
||||||
3. encode 300/N frames with each encoder, and hope to properly decode
|
|
||||||
4. encode without a matching decoder - expect an error
|
|
||||||
*/
|
|
||||||
rewind(_sourceFile);
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
VCMDecodeCompleteCallback* decodeCallCDT = new VCMDecodeCompleteCallback(_decodedFile);
|
|
||||||
VCMEncodeCompleteCallback* encodeCallCDT = new VCMEncodeCompleteCallback(_encodedFile);
|
|
||||||
_vcm->RegisterReceiveCallback(decodeCallCDT);
|
|
||||||
_vcm->RegisterTransportCallback(encodeCallCDT);
|
|
||||||
encodeCallCDT->RegisterReceiverVCM(_vcm);
|
|
||||||
if (VideoCodingModule::NumberOfCodecs() > 0)
|
|
||||||
{
|
|
||||||
// Register all available decoders.
|
|
||||||
int i, j;
|
|
||||||
sourceFrame.CreateEmptyFrame(_width, _height, _width,
|
|
||||||
(_width + 1) / 2, (_width + 1) / 2);
|
|
||||||
_vcm->RegisterReceiveCallback(decodeCallCDT);
|
|
||||||
for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
|
|
||||||
{
|
|
||||||
VideoCodingModule::Codec(i, &receiveCodec);
|
|
||||||
if (strcmp(receiveCodec.plName, "I420") == 0)
|
|
||||||
{
|
|
||||||
receiveCodec.height = _height;
|
|
||||||
receiveCodec.width = _width;
|
|
||||||
}
|
|
||||||
_vcm->RegisterReceiveCodec(&receiveCodec, 1);
|
|
||||||
}
|
|
||||||
// start encoding - iterating over available encoders
|
|
||||||
_vcm->RegisterTransportCallback(encodeCallCDT);
|
|
||||||
encodeCallCDT->RegisterReceiverVCM(_vcm);
|
|
||||||
encodeCallCDT->Initialize();
|
|
||||||
int frameCnt = 0;
|
|
||||||
for (i=0; i < VideoCodingModule::NumberOfCodecs(); i++)
|
|
||||||
{
|
|
||||||
encodeCallCDT->ResetByteCount();
|
|
||||||
VideoCodingModule::Codec(i, &sendCodec);
|
|
||||||
sendCodec.height = _height;
|
|
||||||
sendCodec.width = _width;
|
|
||||||
sendCodec.startBitrate = 1000;
|
|
||||||
sendCodec.maxBitrate = 8000;
|
|
||||||
encodeCallCDT->SetFrameDimensions(_width, _height);
|
|
||||||
encodeCallCDT->SetCodecType(ConvertCodecType(sendCodec.plName));
|
|
||||||
TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) == VCM_OK);
|
|
||||||
|
|
||||||
// We disable the frame dropper to avoid dropping frames due to
|
|
||||||
// bad rate control. This isn't a codec performance test, and the
|
|
||||||
// I420 codec is expected to produce too many bits.
|
|
||||||
_vcm->EnableFrameDropper(false);
|
|
||||||
|
|
||||||
printf("Encoding with %s \n\n", sendCodec.plName);
|
|
||||||
// Assuming 300 frames, NumberOfCodecs <= 10.
|
|
||||||
for (j=0; j < int(300/VideoCodingModule::NumberOfCodecs()); j++)
|
|
||||||
{
|
|
||||||
frameCnt++;
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / _frameRate);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
// send frame to the encoder
|
|
||||||
TEST (_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
waitEvent->Wait(33); // was 100
|
|
||||||
|
|
||||||
int ret =_vcm->Decode();
|
|
||||||
TEST(ret >= 0);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
printf("Error #%d in frame number %d \n",ret, frameCnt);
|
|
||||||
}
|
|
||||||
// verifying matching payload types:
|
|
||||||
_vcm->SendCodec(&sendCodec);
|
|
||||||
_vcm->ReceiveCodec(&receiveCodec);
|
|
||||||
TEST(sendCodec.plType == receiveCodec.plType);
|
|
||||||
if (sendCodec.plType != receiveCodec.plType)
|
|
||||||
{
|
|
||||||
printf("frame number:%d\n",frameCnt);
|
|
||||||
}
|
|
||||||
} // end for:encode-decode
|
|
||||||
// byte count for codec specific
|
|
||||||
|
|
||||||
printf("Total bytes encoded: %f \n\n",(8.0/1000)*(encodeCallCDT->EncodedBytes()/((int)10/VideoCodingModule::NumberOfCodecs())));
|
|
||||||
// decode what's left in the buffer....
|
|
||||||
_vcm->Decode();
|
|
||||||
_vcm->Decode();
|
|
||||||
// Don't measure PSNR for I420 since it will be perfect.
|
|
||||||
if (sendCodec.codecType != kVideoCodecI420) {
|
|
||||||
webrtc::test::QualityMetricsResult psnr;
|
|
||||||
I420PSNRFromFiles(_inname.c_str(), _outname.c_str(), _width,
|
|
||||||
_height, &psnr);
|
|
||||||
printf("\n @ %d KBPS: ", sendCodec.startBitrate);
|
|
||||||
printf("PSNR from encoder-decoder send-receive control test"
|
|
||||||
"is %f\n\n", psnr.average);
|
|
||||||
}
|
|
||||||
} // end: iterate codecs
|
|
||||||
rewind(_sourceFile);
|
|
||||||
delete [] tmpBuffer;
|
|
||||||
delete decodeCallCDT;
|
|
||||||
delete encodeCallCDT;
|
|
||||||
// closing and calculating PSNR for prior encoder-decoder test
|
|
||||||
TearDown(); // closing open files
|
|
||||||
} // end of #codecs >1
|
|
||||||
|
|
||||||
delete waitEvent;
|
|
||||||
Print();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void
|
|
||||||
CodecDataBaseTest::Print()
|
|
||||||
{
|
|
||||||
printf("\nVCM Codec DataBase Test: \n\n%i tests completed\n", vcmMacrosTests);
|
|
||||||
if (vcmMacrosErrors > 0)
|
|
||||||
{
|
|
||||||
printf("%i FAILED\n\n", vcmMacrosErrors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("ALL PASSED\n\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CodecDataBaseTest::TearDown()
|
|
||||||
{
|
|
||||||
fclose(_sourceFile);
|
|
||||||
fclose(_decodedFile);
|
|
||||||
fclose(_encodedFile);
|
|
||||||
return;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_CODEC_DATABASE_TEST_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_CODEC_DATABASE_TEST_H_
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Test consists of:
|
|
||||||
1. Sanity chacks: Send and Receive side (bad input, etc. )
|
|
||||||
2. Send-side control (encoder registration etc.)
|
|
||||||
3. Decoder-side control - encode with various encoders, and verify correct decoding
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CodecDataBaseTest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CodecDataBaseTest(webrtc::VideoCodingModule* vcm);
|
|
||||||
~CodecDataBaseTest();
|
|
||||||
static int RunTest(CmdArgs& args);
|
|
||||||
int32_t Perform(CmdArgs& args);
|
|
||||||
private:
|
|
||||||
void TearDown();
|
|
||||||
void Setup(CmdArgs& args);
|
|
||||||
void Print();
|
|
||||||
webrtc::VideoCodingModule* _vcm;
|
|
||||||
std::string _inname;
|
|
||||||
std::string _outname;
|
|
||||||
std::string _encodedName;
|
|
||||||
FILE* _sourceFile;
|
|
||||||
FILE* _decodedFile;
|
|
||||||
FILE* _encodedFile;
|
|
||||||
uint16_t _width;
|
|
||||||
uint16_t _height;
|
|
||||||
uint32_t _lengthSourceFrame;
|
|
||||||
uint32_t _timeStamp;
|
|
||||||
float _frameRate;
|
|
||||||
}; // end of codecDBTest class definition
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_CODEC_DATABASE_TEST_H_
|
|
@ -1,554 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/main/test/generic_codec_test.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "webrtc/common_video/interface/i420_video_frame.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
enum { kMaxWaitEncTimeMs = 100 };
|
|
||||||
|
|
||||||
int GenericCodecTest::RunTest(CmdArgs& args)
|
|
||||||
{
|
|
||||||
SimulatedClock clock(0);
|
|
||||||
NullEventFactory event_factory;
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(&clock, &event_factory);
|
|
||||||
GenericCodecTest* get = new GenericCodecTest(vcm, &clock);
|
|
||||||
Trace::CreateTrace();
|
|
||||||
Trace::SetTraceFile(
|
|
||||||
(test::OutputPath() + "genericCodecTestTrace.txt").c_str());
|
|
||||||
Trace::set_level_filter(webrtc::kTraceAll);
|
|
||||||
get->Perform(args);
|
|
||||||
Trace::ReturnTrace();
|
|
||||||
delete get;
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericCodecTest::GenericCodecTest(VideoCodingModule* vcm,
|
|
||||||
SimulatedClock* clock):
|
|
||||||
_clock(clock),
|
|
||||||
_vcm(vcm),
|
|
||||||
_width(0),
|
|
||||||
_height(0),
|
|
||||||
_frameRate(0),
|
|
||||||
_lengthSourceFrame(0),
|
|
||||||
_timeStamp(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericCodecTest::~GenericCodecTest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GenericCodecTest::Setup(CmdArgs& args)
|
|
||||||
{
|
|
||||||
_timeStamp = 0;
|
|
||||||
|
|
||||||
/* Test Sequence parameters */
|
|
||||||
|
|
||||||
_inname= args.inputFile;
|
|
||||||
if (args.outputFile.compare(""))
|
|
||||||
_outname = test::OutputPath() + "GCTest_decoded.yuv";
|
|
||||||
else
|
|
||||||
_outname = args.outputFile;
|
|
||||||
_encodedName = test::OutputPath() + "GCTest_encoded.vp8";
|
|
||||||
_width = args.width;
|
|
||||||
_height = args.height;
|
|
||||||
_frameRate = args.frameRate;
|
|
||||||
_lengthSourceFrame = 3*_width*_height/2;
|
|
||||||
|
|
||||||
/* File settings */
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int32_t
|
|
||||||
GenericCodecTest::Perform(CmdArgs& args)
|
|
||||||
{
|
|
||||||
int32_t ret;
|
|
||||||
Setup(args);
|
|
||||||
/*
|
|
||||||
1. sanity checks
|
|
||||||
2. encode/decoder individuality
|
|
||||||
3. API testing
|
|
||||||
4. Target bitrate (within a specific timespan)
|
|
||||||
5. Pipeline Delay
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*******************************/
|
|
||||||
/* sanity checks on inputs */
|
|
||||||
/*****************************/
|
|
||||||
VideoCodec sendCodec, receiveCodec;
|
|
||||||
sendCodec.maxBitrate = 8000;
|
|
||||||
TEST(_vcm->NumberOfCodecs() > 0); // This works since we now initialize the list in the constructor
|
|
||||||
TEST(_vcm->Codec(0, &sendCodec) == VCM_OK);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
int32_t NumberOfCodecs = _vcm->NumberOfCodecs();
|
|
||||||
// registration of first codec in the list
|
|
||||||
int i = 0;
|
|
||||||
_vcm->Codec(0, &_sendCodec);
|
|
||||||
TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1440) == VCM_OK);
|
|
||||||
// sanity on encoder registration
|
|
||||||
I420VideoFrame sourceFrame;
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
TEST(_vcm->Codec(kVideoCodecVP8, &sendCodec) == 0);
|
|
||||||
sendCodec.maxBitrate = 8000;
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 1, 1440);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_vcm->Codec(kVideoCodecVP8, &sendCodec);
|
|
||||||
sendCodec.height = 0;
|
|
||||||
TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0); // bad height
|
|
||||||
_vcm->Codec(kVideoCodecVP8, &sendCodec);
|
|
||||||
_vcm->Codec(kVideoCodecVP8, &sendCodec);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
// Setting rate when encoder uninitialized.
|
|
||||||
TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0);
|
|
||||||
// register all availbale decoders -- need to have more for this test
|
|
||||||
for (i=0; i< NumberOfCodecs; i++)
|
|
||||||
{
|
|
||||||
_vcm->Codec(i, &receiveCodec);
|
|
||||||
_vcm->RegisterReceiveCodec(&receiveCodec, 1);
|
|
||||||
}
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
int half_width = (_width + 1) / 2;
|
|
||||||
int half_height = (_height + 1) / 2;
|
|
||||||
int size_y = _width * _height;
|
|
||||||
int size_uv = half_width * half_height;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
sourceFrame.set_timestamp(_timeStamp++);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) < 0 ); // encoder uninitialized
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
// Setting rtt when receiver uninitialized.
|
|
||||||
TEST(_vcm->SetChannelParameters(100000, 0, 0) < 0);
|
|
||||||
|
|
||||||
/**************************************/
|
|
||||||
/* encoder/decoder individuality test */
|
|
||||||
/**************************************/
|
|
||||||
//Register both encoder and decoder, reset decoder - encode, set up decoder, reset encoder - decode.
|
|
||||||
rewind(_sourceFile);
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
NumberOfCodecs = _vcm->NumberOfCodecs();
|
|
||||||
// Register VP8
|
|
||||||
_vcm->Codec(kVideoCodecVP8, &_sendCodec);
|
|
||||||
_vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
|
|
||||||
_vcm->SendCodec(&sendCodec);
|
|
||||||
sendCodec.startBitrate = 2000;
|
|
||||||
|
|
||||||
// Set target frame rate to half of the incoming frame rate
|
|
||||||
// to test the frame rate control in the VCM
|
|
||||||
sendCodec.maxFramerate = (uint8_t)(_frameRate / 2);
|
|
||||||
sendCodec.width = _width;
|
|
||||||
sendCodec.height = _height;
|
|
||||||
TEST(strncmp(_sendCodec.plName, "VP8", 3) == 0); // was VP8
|
|
||||||
|
|
||||||
_decodeCallback = new VCMDecodeCompleteCallback(_decodedFile);
|
|
||||||
_encodeCompleteCallback = new VCMEncodeCompleteCallback(_encodedFile);
|
|
||||||
_vcm->RegisterReceiveCallback(_decodeCallback);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
_encodeCompleteCallback->RegisterReceiverVCM(_vcm);
|
|
||||||
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 4, 1440);
|
|
||||||
_encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName));
|
|
||||||
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->Process();
|
|
||||||
|
|
||||||
//encoding 1 second of video
|
|
||||||
for (i = 0; i < _frameRate; i++)
|
|
||||||
{
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
IncrementDebugClock(_frameRate);
|
|
||||||
_vcm->Process();
|
|
||||||
}
|
|
||||||
sendCodec.maxFramerate = (uint8_t)_frameRate;
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK); // same codec for encode and decode
|
|
||||||
ret = 0;
|
|
||||||
i = 0;
|
|
||||||
while ((i < 25) && (ret == 0) )
|
|
||||||
{
|
|
||||||
ret = _vcm->Decode();
|
|
||||||
TEST(ret == VCM_OK);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
printf("error in frame # %d \n", i);
|
|
||||||
}
|
|
||||||
IncrementDebugClock(_frameRate);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
//TEST((ret == 0) && (i = 50));
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
printf("Encoder/Decoder individuality test complete - View output files \n");
|
|
||||||
}
|
|
||||||
// last frame - not decoded
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
TEST(_vcm->Decode() < 0); // frame to be encoded exists, decoder uninitialized
|
|
||||||
|
|
||||||
|
|
||||||
// Test key frame request on packet loss mode.
|
|
||||||
// This a frame as a key frame and fooling the receiver
|
|
||||||
// that the last packet was lost. The decoding will succeed,
|
|
||||||
// but the VCM will see a packet loss and request a new key frame.
|
|
||||||
VCMEncComplete_KeyReqTest keyReqTest_EncCompleteCallback(*_vcm);
|
|
||||||
KeyFrameReqTest frameTypeCallback;
|
|
||||||
_vcm->RegisterTransportCallback(&keyReqTest_EncCompleteCallback);
|
|
||||||
_encodeCompleteCallback->RegisterReceiverVCM(_vcm);
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, 4, 1440);
|
|
||||||
_encodeCompleteCallback->SetCodecType(ConvertCodecType(sendCodec.plName));
|
|
||||||
TEST(_vcm->SetVideoProtection(kProtectionKeyOnKeyLoss, true) == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterFrameTypeCallback(&frameTypeCallback) == VCM_OK);
|
|
||||||
TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
// First packet of a subsequent frame required before the jitter buffer
|
|
||||||
// will allow decoding an incomplete frame.
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
TEST(_vcm->Decode() == VCM_OK);
|
|
||||||
|
|
||||||
printf("API tests complete \n");
|
|
||||||
|
|
||||||
/*******************/
|
|
||||||
/* Bit Rate Tests */
|
|
||||||
/*****************/
|
|
||||||
/* Requirements:
|
|
||||||
* 1. OneSecReq = 15 % above/below target over a time period of 1s (_frameRate number of frames)
|
|
||||||
* 3. FullReq = 10% for total seq. (for 300 frames/seq. coincides with #1)
|
|
||||||
* 4. Test will go over all registered codecs
|
|
||||||
//NOTE: time requirements are not part of the release tests
|
|
||||||
*/
|
|
||||||
double FullReq = 0.1;
|
|
||||||
//double OneSecReq = 0.15;
|
|
||||||
printf("\n RATE CONTROL TEST\n");
|
|
||||||
// initializing....
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
rewind(_sourceFile);
|
|
||||||
sourceFrame.CreateEmptyFrame(_width, _height, _width,
|
|
||||||
(_width + 1) / 2, (_width + 1) / 2);
|
|
||||||
const float bitRate[] = {100, 400, 600, 1000, 2000};
|
|
||||||
const float nBitrates = sizeof(bitRate)/sizeof(*bitRate);
|
|
||||||
float _bitRate = 0;
|
|
||||||
int _frameCnt = 0;
|
|
||||||
size_t totalBytesOneSec = 0;//, totalBytesTenSec;
|
|
||||||
size_t totalBytes;
|
|
||||||
float actualBitrate;
|
|
||||||
VCMFrameCount frameCount; // testing frame type counters
|
|
||||||
// start test
|
|
||||||
NumberOfCodecs = _vcm->NumberOfCodecs();
|
|
||||||
// going over all available codecs
|
|
||||||
_encodeCompleteCallback->SetFrameDimensions(_width, _height);
|
|
||||||
SendStatsTest sendStats;
|
|
||||||
for (int k = 0; k < NumberOfCodecs; k++)
|
|
||||||
//for (int k = NumberOfCodecs - 1; k >=0; k--)
|
|
||||||
{// static list starts from 0
|
|
||||||
//just checking
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_sendCodec.maxBitrate = 8000;
|
|
||||||
TEST(_vcm->Codec(k, &_sendCodec)== VCM_OK);
|
|
||||||
_vcm->RegisterSendCodec(&_sendCodec, 1, 1440);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
_encodeCompleteCallback->SetCodecType(ConvertCodecType(_sendCodec.plName));
|
|
||||||
printf (" \n\n Codec type = %s \n\n",_sendCodec.plName);
|
|
||||||
for (i = 0; i < nBitrates; i++)
|
|
||||||
{
|
|
||||||
_bitRate = static_cast<float>(bitRate[i]);
|
|
||||||
// just testing
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_sendCodec.startBitrate = (int)_bitRate;
|
|
||||||
_sendCodec.maxBitrate = 8000;
|
|
||||||
_sendCodec.maxFramerate = _frameRate;
|
|
||||||
_vcm->RegisterSendCodec(&_sendCodec, 1, 1440);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
// up to here
|
|
||||||
_vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate),
|
|
||||||
0, 20);
|
|
||||||
_frameCnt = 0;
|
|
||||||
totalBytes = 0;
|
|
||||||
_encodeCompleteCallback->Initialize();
|
|
||||||
sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
|
|
||||||
sendStats.set_bitrate(1000 * _bitRate);
|
|
||||||
_vcm->RegisterSendStatisticsCallback(&sendStats);
|
|
||||||
while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
|
|
||||||
_lengthSourceFrame)
|
|
||||||
{
|
|
||||||
_frameCnt++;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, (_width + 1) / 2,
|
|
||||||
(_width + 1) / 2);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
|
|
||||||
ret = _vcm->AddVideoFrame(sourceFrame);
|
|
||||||
IncrementDebugClock(_frameRate);
|
|
||||||
// The following should be uncommneted for timing tests. Release tests only include
|
|
||||||
// compliance with full sequence bit rate.
|
|
||||||
if (_frameCnt == _frameRate)// @ 1sec
|
|
||||||
{
|
|
||||||
totalBytesOneSec = _encodeCompleteCallback->EncodedBytes();//totalBytes;
|
|
||||||
}
|
|
||||||
TEST(_vcm->TimeUntilNextProcess() >= 0);
|
|
||||||
} // video seq. encode done
|
|
||||||
TEST(_vcm->TimeUntilNextProcess() == 0);
|
|
||||||
_vcm->Process(); // Let the module calculate its send bit rate estimate
|
|
||||||
// estimating rates
|
|
||||||
// complete sequence
|
|
||||||
// bit rate assumes input frame rate is as specified
|
|
||||||
totalBytes = _encodeCompleteCallback->EncodedBytes();
|
|
||||||
actualBitrate = (float)(8.0/1000)*(totalBytes / (_frameCnt / _frameRate));
|
|
||||||
|
|
||||||
printf("Complete Seq.: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate);
|
|
||||||
TEST((fabs(actualBitrate - _bitRate) < FullReq * _bitRate) ||
|
|
||||||
(strncmp(_sendCodec.plName, "I420", 4) == 0));
|
|
||||||
|
|
||||||
// 1 Sec.
|
|
||||||
actualBitrate = (float)(8.0/1000)*(totalBytesOneSec);
|
|
||||||
//actualBitrate = (float)(8.0*totalBytesOneSec)/(oneSecTime - startTime);
|
|
||||||
//printf("First 1Sec: target bitrate: %.0f kbps, actual bitrate: %.1f kbps\n", _bitRate, actualBitrate);
|
|
||||||
//TEST(fabs(actualBitrate - _bitRate) < OneSecReq * _bitRate);
|
|
||||||
rewind(_sourceFile);
|
|
||||||
|
|
||||||
//checking key/delta frame count
|
|
||||||
_vcm->SentFrameCount(frameCount);
|
|
||||||
printf("frame count: %d delta, %d key\n", frameCount.numDeltaFrames, frameCount.numKeyFrames);
|
|
||||||
}// end per codec
|
|
||||||
|
|
||||||
} // end rate control test
|
|
||||||
/********************************/
|
|
||||||
/* Encoder Pipeline Delay Test */
|
|
||||||
/******************************/
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
NumberOfCodecs = _vcm->NumberOfCodecs();
|
|
||||||
bool encodeComplete = false;
|
|
||||||
// going over all available codecs
|
|
||||||
for (int k = 0; k < NumberOfCodecs; k++)
|
|
||||||
{
|
|
||||||
_vcm->Codec(k, &_sendCodec);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_sendCodec.maxBitrate = 8000;
|
|
||||||
_vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
|
|
||||||
_frameCnt = 0;
|
|
||||||
encodeComplete = false;
|
|
||||||
while (encodeComplete == false)
|
|
||||||
{
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
_frameCnt++;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
_vcm->AddVideoFrame(sourceFrame);
|
|
||||||
encodeComplete = _encodeCompleteCallback->EncodeComplete();
|
|
||||||
} // first frame encoded
|
|
||||||
printf ("\n Codec type = %s \n", _sendCodec.plName);
|
|
||||||
printf(" Encoder pipeline delay = %d frames\n", _frameCnt - 1);
|
|
||||||
} // end for all codecs
|
|
||||||
|
|
||||||
/********************************/
|
|
||||||
/* Encoder Packet Size Test */
|
|
||||||
/********************************/
|
|
||||||
RTPSendCallback_SizeTest sendCallback;
|
|
||||||
|
|
||||||
RtpRtcp::Configuration configuration;
|
|
||||||
configuration.id = 1;
|
|
||||||
configuration.audio = false;
|
|
||||||
configuration.outgoing_transport = &sendCallback;
|
|
||||||
|
|
||||||
RtpRtcp& rtpModule = *RtpRtcp::CreateRtpRtcp(configuration);
|
|
||||||
|
|
||||||
VCMRTPEncodeCompleteCallback encCompleteCallback(&rtpModule);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
|
|
||||||
// Test temporal decimation settings
|
|
||||||
for (int k = 0; k < NumberOfCodecs; k++)
|
|
||||||
{
|
|
||||||
_vcm->Codec(k, &_sendCodec);
|
|
||||||
if (strncmp(_sendCodec.plName, "I420", 4) == 0)
|
|
||||||
{
|
|
||||||
// Only test with I420
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST(strncmp(_sendCodec.plName, "I420", 4) == 0);
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_sendCodec.maxFramerate = static_cast<uint8_t>(_frameRate / 2.0 + 0.5f);
|
|
||||||
_vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
|
|
||||||
_vcm->SetChannelParameters(2000000, 0, 0);
|
|
||||||
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
|
|
||||||
// up to here
|
|
||||||
_vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 20);
|
|
||||||
_encodeCompleteCallback->Initialize();
|
|
||||||
sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
|
|
||||||
sendStats.set_bitrate(1000 * _bitRate);
|
|
||||||
_vcm->RegisterSendStatisticsCallback(&sendStats);
|
|
||||||
rewind(_sourceFile);
|
|
||||||
while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
|
|
||||||
_lengthSourceFrame) {
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
ret = _vcm->AddVideoFrame(sourceFrame);
|
|
||||||
if (_vcm->TimeUntilNextProcess() <= 0)
|
|
||||||
{
|
|
||||||
_vcm->Process();
|
|
||||||
}
|
|
||||||
IncrementDebugClock(_frameRate);
|
|
||||||
} // first frame encoded
|
|
||||||
|
|
||||||
delete &rtpModule;
|
|
||||||
Print();
|
|
||||||
delete tmpBuffer;
|
|
||||||
delete _decodeCallback;
|
|
||||||
delete _encodeCompleteCallback;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
GenericCodecTest::Print()
|
|
||||||
{
|
|
||||||
printf(" \n\n VCM Generic Encoder Test: \n\n%i tests completed\n", vcmMacrosTests);
|
|
||||||
if (vcmMacrosErrors > 0)
|
|
||||||
{
|
|
||||||
printf("%i FAILED\n\n", vcmMacrosErrors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("ALL PASSED\n\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
GenericCodecTest::WaitForEncodedFrame() const
|
|
||||||
{
|
|
||||||
int64_t startTime = _clock->TimeInMilliseconds();
|
|
||||||
while (_clock->TimeInMilliseconds() - startTime < kMaxWaitEncTimeMs*10)
|
|
||||||
{
|
|
||||||
if (_encodeCompleteCallback->EncodeComplete())
|
|
||||||
{
|
|
||||||
return _encodeCompleteCallback->EncodedBytes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GenericCodecTest::IncrementDebugClock(float frameRate)
|
|
||||||
{
|
|
||||||
_clock->AdvanceTimeMilliseconds(1000/frameRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
RTPSendCallback_SizeTest::SendPacket(int channel, const void *data, size_t len)
|
|
||||||
{
|
|
||||||
_nPackets++;
|
|
||||||
_payloadSizeSum += len;
|
|
||||||
// Make sure no payloads (len - header size) are larger than maxPayloadSize
|
|
||||||
TEST(len > 0 && len - 12 <= _maxPayloadSize);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RTPSendCallback_SizeTest::SetMaxPayloadSize(size_t maxPayloadSize)
|
|
||||||
{
|
|
||||||
_maxPayloadSize = maxPayloadSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RTPSendCallback_SizeTest::Reset()
|
|
||||||
{
|
|
||||||
_nPackets = 0;
|
|
||||||
_payloadSizeSum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
RTPSendCallback_SizeTest::AveragePayloadSize() const
|
|
||||||
{
|
|
||||||
if (_nPackets > 0)
|
|
||||||
{
|
|
||||||
return _payloadSizeSum / static_cast<float>(_nPackets);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t VCMEncComplete_KeyReqTest::SendData(
|
|
||||||
uint8_t payloadType,
|
|
||||||
const webrtc::EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& /*fragmentationHeader*/,
|
|
||||||
const webrtc::RTPVideoHeader* /*videoHdr*/) {
|
|
||||||
WebRtcRTPHeader rtpInfo;
|
|
||||||
rtpInfo.header.markerBit = true; // end of frame
|
|
||||||
rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8();
|
|
||||||
rtpInfo.type.Video.codec = kRtpVideoVp8;
|
|
||||||
rtpInfo.header.payloadType = payloadType;
|
|
||||||
rtpInfo.header.sequenceNumber = _seqNo;
|
|
||||||
_seqNo += 2;
|
|
||||||
rtpInfo.header.ssrc = 0;
|
|
||||||
rtpInfo.header.timestamp = _timeStamp;
|
|
||||||
_timeStamp += 3000;
|
|
||||||
rtpInfo.type.Video.isFirstPacket = false;
|
|
||||||
rtpInfo.frameType = kVideoFrameKey;
|
|
||||||
return _vcm.IncomingPacket(encoded_image._buffer, encoded_image._length,
|
|
||||||
rtpInfo);
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_GENERIC_CODEC_TEST_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_GENERIC_CODEC_TEST_H_
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
/*
|
|
||||||
Test consists of:
|
|
||||||
1. Sanity checks
|
|
||||||
2. Bit rate validation
|
|
||||||
3. Encoder control test / General API functionality
|
|
||||||
4. Decoder control test / General API functionality
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
int VCMGenericCodecTest(CmdArgs& args);
|
|
||||||
|
|
||||||
class SimulatedClock;
|
|
||||||
|
|
||||||
class GenericCodecTest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericCodecTest(webrtc::VideoCodingModule* vcm,
|
|
||||||
webrtc::SimulatedClock* clock);
|
|
||||||
~GenericCodecTest();
|
|
||||||
static int RunTest(CmdArgs& args);
|
|
||||||
int32_t Perform(CmdArgs& args);
|
|
||||||
size_t WaitForEncodedFrame() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Setup(CmdArgs& args);
|
|
||||||
void Print();
|
|
||||||
int32_t TearDown();
|
|
||||||
void IncrementDebugClock(float frameRate);
|
|
||||||
|
|
||||||
webrtc::SimulatedClock* _clock;
|
|
||||||
webrtc::VideoCodingModule* _vcm;
|
|
||||||
webrtc::VideoCodec _sendCodec;
|
|
||||||
webrtc::VideoCodec _receiveCodec;
|
|
||||||
std::string _inname;
|
|
||||||
std::string _outname;
|
|
||||||
std::string _encodedName;
|
|
||||||
int32_t _sumEncBytes;
|
|
||||||
FILE* _sourceFile;
|
|
||||||
FILE* _decodedFile;
|
|
||||||
FILE* _encodedFile;
|
|
||||||
uint16_t _width;
|
|
||||||
uint16_t _height;
|
|
||||||
float _frameRate;
|
|
||||||
uint32_t _lengthSourceFrame;
|
|
||||||
uint32_t _timeStamp;
|
|
||||||
VCMDecodeCompleteCallback* _decodeCallback;
|
|
||||||
VCMEncodeCompleteCallback* _encodeCompleteCallback;
|
|
||||||
|
|
||||||
}; // end of GenericCodecTest class definition
|
|
||||||
|
|
||||||
class RTPSendCallback_SizeTest : public webrtc::Transport
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// constructor input: (receive side) rtp module to send encoded data to
|
|
||||||
RTPSendCallback_SizeTest() : _maxPayloadSize(0), _payloadSizeSum(0), _nPackets(0) {}
|
|
||||||
int SendPacket(int channel, const void* data, size_t len) override;
|
|
||||||
int SendRTCPPacket(int channel, const void* data, size_t len) override {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void SetMaxPayloadSize(size_t maxPayloadSize);
|
|
||||||
void Reset();
|
|
||||||
float AveragePayloadSize() const;
|
|
||||||
private:
|
|
||||||
size_t _maxPayloadSize;
|
|
||||||
size_t _payloadSizeSum;
|
|
||||||
uint32_t _nPackets;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VCMEncComplete_KeyReqTest : public webrtc::VCMPacketizationCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VCMEncComplete_KeyReqTest(webrtc::VideoCodingModule &vcm) : _vcm(vcm), _seqNo(0), _timeStamp(0) {}
|
|
||||||
int32_t SendData(uint8_t payloadType,
|
|
||||||
const webrtc::EncodedImage& encoded_image,
|
|
||||||
const webrtc::RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const webrtc::RTPVideoHeader* videoHdr) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
webrtc::VideoCodingModule& _vcm;
|
|
||||||
uint16_t _seqNo;
|
|
||||||
uint32_t _timeStamp;
|
|
||||||
}; // end of VCMEncodeCompleteCallback
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_GENERIC_CODEC_TEST_H_
|
|
@ -1,557 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Implementation of Media Optimization Test
|
|
||||||
// testing is done via the VCM module, no specific Media opt functionality.
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/test/media_opt_test.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
#include "webrtc/test/testsupport/metrics/video_metrics.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
int MediaOptTest::RunTest(int testNum, CmdArgs& args)
|
|
||||||
{
|
|
||||||
Trace::CreateTrace();
|
|
||||||
Trace::SetTraceFile((test::OutputPath() + "mediaOptTestTrace.txt").c_str());
|
|
||||||
Trace::set_level_filter(webrtc::kTraceAll);
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(nullptr);
|
|
||||||
Clock* clock = Clock::GetRealTimeClock();
|
|
||||||
MediaOptTest* mot = new MediaOptTest(vcm, clock);
|
|
||||||
if (testNum == 0)
|
|
||||||
{ // regular
|
|
||||||
mot->Setup(0, args);
|
|
||||||
mot->GeneralSetup();
|
|
||||||
mot->Perform();
|
|
||||||
mot->Print(1);// print to screen
|
|
||||||
mot->TearDown();
|
|
||||||
}
|
|
||||||
if (testNum == 1)
|
|
||||||
{ // release test
|
|
||||||
mot->Setup(0, args);
|
|
||||||
mot->RTTest();
|
|
||||||
}
|
|
||||||
if (testNum == 2)
|
|
||||||
{ // release test, running from script
|
|
||||||
mot->Setup(1, args);
|
|
||||||
mot->GeneralSetup();
|
|
||||||
mot->Perform();
|
|
||||||
mot->Print(1);// print to screen
|
|
||||||
mot->TearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
delete mot;
|
|
||||||
Trace::ReturnTrace();
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MediaOptTest::MediaOptTest(VideoCodingModule* vcm, Clock* clock)
|
|
||||||
: _vcm(vcm),
|
|
||||||
_rtp(NULL),
|
|
||||||
_outgoingTransport(NULL),
|
|
||||||
_dataCallback(NULL),
|
|
||||||
_clock(clock),
|
|
||||||
_width(0),
|
|
||||||
_height(0),
|
|
||||||
_lengthSourceFrame(0),
|
|
||||||
_timeStamp(0),
|
|
||||||
_frameRate(30.0f),
|
|
||||||
_nackEnabled(false),
|
|
||||||
_fecEnabled(false),
|
|
||||||
_rttMS(0),
|
|
||||||
_bitRate(300.0f),
|
|
||||||
_lossRate(0.0f),
|
|
||||||
_renderDelayMs(0),
|
|
||||||
_frameCnt(0),
|
|
||||||
_sumEncBytes(0),
|
|
||||||
_numFramesDropped(0),
|
|
||||||
_numberOfCores(4) {
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaOptTest::~MediaOptTest() {
|
|
||||||
delete _rtp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOptTest::Setup(int testType, CmdArgs& args) {
|
|
||||||
/*TEST USER SETTINGS*/
|
|
||||||
// test parameters
|
|
||||||
_inname = args.inputFile;
|
|
||||||
if (args.outputFile == "")
|
|
||||||
_outname = test::OutputPath() + "MOTest_out.vp8";
|
|
||||||
else
|
|
||||||
_outname = args.outputFile;
|
|
||||||
// actual source after frame dropping
|
|
||||||
_actualSourcename = test::OutputPath() + "MOTestSource.yuv";
|
|
||||||
_codecName = args.codecName;
|
|
||||||
_sendCodecType = args.codecType;
|
|
||||||
_width = args.width;
|
|
||||||
_height = args.height;
|
|
||||||
_frameRate = args.frameRate;
|
|
||||||
_bitRate = args.bitRate;
|
|
||||||
_numberOfCores = 4;
|
|
||||||
|
|
||||||
// error resilience
|
|
||||||
_nackEnabled = false;
|
|
||||||
_fecEnabled = true;
|
|
||||||
_nackFecEnabled = false;
|
|
||||||
|
|
||||||
_rttMS = 100;
|
|
||||||
_lossRate = 0.00*255; // no packet loss
|
|
||||||
|
|
||||||
_testType = testType;
|
|
||||||
|
|
||||||
//For multiple runs with script
|
|
||||||
if (_testType == 1)
|
|
||||||
{
|
|
||||||
float rateTest,lossTest;
|
|
||||||
int numRuns;
|
|
||||||
_fpinp = fopen("dat_inp","rb");
|
|
||||||
_fpout = fopen("test_runs/dat_out","ab");
|
|
||||||
_fpout2 = fopen("test_runs/dat_out2","ab");
|
|
||||||
TEST(fscanf(_fpinp,"%f %f %d \n",&rateTest,&lossTest,&numRuns) > 0);
|
|
||||||
_bitRate = rateTest;
|
|
||||||
_lossRate = lossTest;
|
|
||||||
_testNum = 0;
|
|
||||||
|
|
||||||
// for bit rates: 500, 1000, 2000, 3000,4000
|
|
||||||
// for loss rates: 0, 1, 3, 5, 10%
|
|
||||||
_numParRuns = 25;
|
|
||||||
|
|
||||||
_testNum = numRuns + 1;
|
|
||||||
if (rateTest == 0.0) _lossRate = 0.0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rateTest == 4000) //final bit rate
|
|
||||||
{
|
|
||||||
if (lossTest == 0.1*255) _lossRate = 0.0; //start at 1%
|
|
||||||
else
|
|
||||||
if (lossTest == 0.05*255) _lossRate = 0.1*255; //final loss rate
|
|
||||||
else
|
|
||||||
if (lossTest == 0.0) _lossRate = 0.01*255;
|
|
||||||
else _lossRate = lossTest + 0.02*255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rateTest == 0.0 || rateTest == 4000) _bitRate = 500; //starting bit rate
|
|
||||||
else
|
|
||||||
if (rateTest == 500) _bitRate = 1000;
|
|
||||||
else _bitRate = rateTest + 1000;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
_renderDelayMs = 0;
|
|
||||||
/* test settings end*/
|
|
||||||
|
|
||||||
_lengthSourceFrame = 3*_width*_height/2;
|
|
||||||
_log.open((test::OutputPath() + "VCM_MediaOptLog.txt").c_str(),
|
|
||||||
std::fstream::out | std::fstream::app);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaOptTest::GeneralSetup()
|
|
||||||
{
|
|
||||||
uint32_t minPlayoutDelayMs = 0;
|
|
||||||
|
|
||||||
if ((_sourceFile = fopen(_inname.c_str(), "rb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("Cannot read file %s.\n", _inname.c_str());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_decodedFile = fopen(_outname.c_str(), "wb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("Cannot read file %s.\n", _outname.c_str());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_actualSourceFile = fopen(_actualSourcename.c_str(), "wb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("Cannot read file %s.\n", _actualSourcename.c_str());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (_vcm->InitializeReceiver() < 0)
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (_vcm->InitializeSender())
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
_outgoingTransport = new RTPSendCompleteCallback(_clock);
|
|
||||||
_dataCallback = new RtpDataCallback(_vcm);
|
|
||||||
|
|
||||||
RtpRtcp::Configuration configuration;
|
|
||||||
configuration.id = 1;
|
|
||||||
configuration.audio = false;
|
|
||||||
configuration.outgoing_transport = _outgoingTransport;
|
|
||||||
_rtp = RtpRtcp::CreateRtpRtcp(configuration);
|
|
||||||
|
|
||||||
_outgoingTransport->SetRtpModule(_rtp);
|
|
||||||
|
|
||||||
// Registering codecs for the RTP module
|
|
||||||
|
|
||||||
// Register receive and send payload
|
|
||||||
VideoCodec video_codec;
|
|
||||||
strncpy(video_codec.plName, "VP8", 32);
|
|
||||||
video_codec.plType = VCM_VP8_PAYLOAD_TYPE;
|
|
||||||
rtp_receiver_->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate);
|
|
||||||
_rtp->RegisterSendPayload(video_codec);
|
|
||||||
|
|
||||||
strncpy(video_codec.plName, "ULPFEC", 32);
|
|
||||||
video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
|
|
||||||
rtp_receiver_->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate);
|
|
||||||
_rtp->RegisterSendPayload(video_codec);
|
|
||||||
|
|
||||||
strncpy(video_codec.plName, "RED", 32);
|
|
||||||
video_codec.plType = VCM_RED_PAYLOAD_TYPE;
|
|
||||||
rtp_receiver_->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate);
|
|
||||||
_rtp->RegisterSendPayload(video_codec);
|
|
||||||
|
|
||||||
if (_nackFecEnabled == 1)
|
|
||||||
_rtp->SetGenericFECStatus(_nackFecEnabled, VCM_RED_PAYLOAD_TYPE,
|
|
||||||
VCM_ULPFEC_PAYLOAD_TYPE);
|
|
||||||
else
|
|
||||||
_rtp->SetGenericFECStatus(_fecEnabled, VCM_RED_PAYLOAD_TYPE,
|
|
||||||
VCM_ULPFEC_PAYLOAD_TYPE);
|
|
||||||
|
|
||||||
// VCM: Registering codecs
|
|
||||||
VideoCodec sendCodec;
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
int32_t numberOfCodecs = _vcm->NumberOfCodecs();
|
|
||||||
if (numberOfCodecs < 1)
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_vcm->Codec(_sendCodecType, &sendCodec) != 0)
|
|
||||||
{
|
|
||||||
printf("Unknown codec\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
// register codec
|
|
||||||
sendCodec.startBitrate = (int) _bitRate;
|
|
||||||
sendCodec.height = _height;
|
|
||||||
sendCodec.width = _width;
|
|
||||||
sendCodec.maxFramerate = (uint8_t)_frameRate;
|
|
||||||
_vcm->RegisterSendCodec(&sendCodec, _numberOfCores, 1440);
|
|
||||||
_vcm->RegisterReceiveCodec(&sendCodec, _numberOfCores); // same settings for encode and decode
|
|
||||||
|
|
||||||
_vcm->SetRenderDelay(_renderDelayMs);
|
|
||||||
_vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
|
|
||||||
}
|
|
||||||
// The following test shall be conducted under release tests
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
MediaOptTest::Perform()
|
|
||||||
{
|
|
||||||
VCMDecodeCompleteCallback receiveCallback(_decodedFile);
|
|
||||||
|
|
||||||
VCMRTPEncodeCompleteCallback* encodeCompleteCallback = new VCMRTPEncodeCompleteCallback(_rtp);
|
|
||||||
_vcm->RegisterTransportCallback(encodeCompleteCallback);
|
|
||||||
encodeCompleteCallback->SetCodecType(ConvertCodecType(_codecName.c_str()));
|
|
||||||
encodeCompleteCallback->SetFrameDimensions(_width, _height);
|
|
||||||
|
|
||||||
// callback settings
|
|
||||||
VideoProtectionCallback protectionCallback;
|
|
||||||
protectionCallback.RegisterRtpModule(_rtp);
|
|
||||||
_vcm->RegisterProtectionCallback(&protectionCallback);
|
|
||||||
|
|
||||||
// set error resilience / test parameters:
|
|
||||||
_outgoingTransport->SetLossPct(_lossRate);
|
|
||||||
if (_nackFecEnabled == 1) {
|
|
||||||
_vcm->SetVideoProtection(kProtectionNackFEC, _nackFecEnabled);
|
|
||||||
} else {
|
|
||||||
_vcm->SetVideoProtection(kProtectionNack, _nackEnabled);
|
|
||||||
_vcm->SetVideoProtection(kProtectionFEC, _fecEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// START TEST
|
|
||||||
I420VideoFrame sourceFrame;
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
|
|
||||||
_vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate),
|
|
||||||
(uint8_t)_lossRate, _rttMS);
|
|
||||||
_vcm->RegisterReceiveCallback(&receiveCallback);
|
|
||||||
|
|
||||||
_frameCnt = 0;
|
|
||||||
_sumEncBytes = 0;
|
|
||||||
_numFramesDropped = 0;
|
|
||||||
int half_width = (_width + 1) / 2;
|
|
||||||
int half_height = (_height + 1) / 2;
|
|
||||||
int size_y = _width * _height;
|
|
||||||
int size_uv = half_width * half_height;
|
|
||||||
|
|
||||||
while (feof(_sourceFile)== 0)
|
|
||||||
{
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
|
|
||||||
_frameCnt++;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp += (uint32_t)(9e4 / static_cast<float>(_frameRate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
|
|
||||||
// inform RTP Module of error resilience features
|
|
||||||
//_rtp->SetFECCodeRate(protectionCallback.FECKeyRate(),protectionCallback.FECDeltaRate());
|
|
||||||
//_rtp->SetNACKStatus(protectionCallback.NACKMethod());
|
|
||||||
|
|
||||||
int32_t ret = _vcm->Decode();
|
|
||||||
if (ret < 0 )
|
|
||||||
{
|
|
||||||
TEST(ret == 0);
|
|
||||||
printf ("Decode error in frame # %d",_frameCnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t encBytes = encodeCompleteCallback->EncodedBytes();
|
|
||||||
if (encBytes == 0)
|
|
||||||
{
|
|
||||||
_numFramesDropped += 1;
|
|
||||||
//printf("frame #%d dropped \n", _frameCnt );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// write frame to file
|
|
||||||
if (PrintI420VideoFrame(sourceFrame, _actualSourceFile) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_sumEncBytes += encBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//END TEST
|
|
||||||
delete encodeCompleteCallback;
|
|
||||||
delete tmpBuffer;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaOptTest::RTTest()
|
|
||||||
{
|
|
||||||
// will only calculate PSNR - not create output files for all
|
|
||||||
// SET UP
|
|
||||||
// Set bit rates
|
|
||||||
const float bitRateVec[] = {500, 1000, 2000,3000, 4000};
|
|
||||||
//const float bitRateVec[] = {1000};
|
|
||||||
// Set Packet loss values ([0,255])
|
|
||||||
const double lossPctVec[] = {0.0*255, 0.0*255, 0.01*255, 0.01*255, 0.03*255, 0.03*255, 0.05*255, 0.05*255, 0.1*255, 0.1*255};
|
|
||||||
const bool nackEnabledVec[] = {false , false, false, false, false, false, false, false , false, false};
|
|
||||||
const bool fecEnabledVec[] = {false , true, false, true , false, true , false, true , false, true};
|
|
||||||
// fec and nack are set according to the packet loss values
|
|
||||||
|
|
||||||
const float nBitrates = sizeof(bitRateVec)/sizeof(*bitRateVec);
|
|
||||||
const float nlossPct = sizeof(lossPctVec)/sizeof(*lossPctVec);
|
|
||||||
|
|
||||||
std::vector<const VideoSource*> sources;
|
|
||||||
std::vector<const VideoSource*>::iterator it;
|
|
||||||
|
|
||||||
sources.push_back(new const VideoSource(_inname, _width, _height));
|
|
||||||
int numOfSrc = 1;
|
|
||||||
|
|
||||||
// constant settings (valid for entire run time)
|
|
||||||
_rttMS = 20;
|
|
||||||
_renderDelayMs = 0;
|
|
||||||
|
|
||||||
// same out name for all
|
|
||||||
_outname = test::OutputPath() + "RTMOTest_out.yuv";
|
|
||||||
// actual source after frame dropping
|
|
||||||
_actualSourcename = test::OutputPath() + "RTMOTestSource.yuv";
|
|
||||||
|
|
||||||
_codecName = "VP8"; // for now just this one - later iterate over all codec types
|
|
||||||
_log.open((test::OutputPath() + "/VCM_RTMediaOptLog.txt").c_str(),
|
|
||||||
std::fstream::out | std::fstream::app);
|
|
||||||
_outputRes=fopen((test::OutputPath() + "VCM_MediaOptResults.txt").c_str(),
|
|
||||||
"ab");
|
|
||||||
|
|
||||||
//char filename[128];
|
|
||||||
/* test settings end*/
|
|
||||||
|
|
||||||
// START TEST
|
|
||||||
// iterate over test sequences
|
|
||||||
printf("\n****START TEST OVER ALL RUNS ****\n");
|
|
||||||
int runCnt = 0;
|
|
||||||
for (it = sources.begin() ; it < sources.end(); it++)
|
|
||||||
{
|
|
||||||
|
|
||||||
// test set up
|
|
||||||
_inname = (*it)->GetFileName();
|
|
||||||
_width = (*it)->GetWidth();
|
|
||||||
_height = (*it)->GetHeight();
|
|
||||||
_lengthSourceFrame = 3*_width*_height/2;
|
|
||||||
_frameRate = (*it)->GetFrameRate();
|
|
||||||
//GeneralSetup();
|
|
||||||
|
|
||||||
|
|
||||||
// iterate over all bit rates
|
|
||||||
for (int i = 0; i < nBitrates; i++)
|
|
||||||
{
|
|
||||||
_bitRate = static_cast<float>(bitRateVec[i]);
|
|
||||||
// iterate over all packet loss values
|
|
||||||
for (int j = 0; j < nlossPct; j++)
|
|
||||||
{
|
|
||||||
_lossRate = static_cast<float>(lossPctVec[j]);
|
|
||||||
_nackEnabled = static_cast<bool>(nackEnabledVec[j]);
|
|
||||||
_fecEnabled = static_cast<bool>(fecEnabledVec[j]);
|
|
||||||
|
|
||||||
runCnt++;
|
|
||||||
printf("run #%d out of %d \n", runCnt,(int)(nlossPct*nBitrates*numOfSrc));
|
|
||||||
|
|
||||||
//printf("**FOR RUN: **%d %d %d %d \n",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
|
|
||||||
|
|
||||||
/*
|
|
||||||
int ch = sprintf(filename,"../test_mediaOpt/RTMOTest_%d_%d_%d_%d.yuv",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
|
|
||||||
_outname = filename;
|
|
||||||
|
|
||||||
printf("**FOR RUN: **%d %d %d %d \n",_nackEnabled,_fecEnabled,int(lossPctVec[j]),int(_bitRate));
|
|
||||||
*/
|
|
||||||
GeneralSetup();
|
|
||||||
Perform();
|
|
||||||
Print(1);
|
|
||||||
TearDown();
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
//printf("**DONE WITH RUN: **%d %d %f %d \n",_nackEnabled,_fecEnabled,lossPctVec[j],int(_bitRate));
|
|
||||||
//
|
|
||||||
|
|
||||||
}// end of packet loss loop
|
|
||||||
}// end of bit rate loop
|
|
||||||
delete *it;
|
|
||||||
}// end of video sequence loop
|
|
||||||
// at end of sequence
|
|
||||||
fclose(_outputRes);
|
|
||||||
printf("\nVCM Media Optimization Test: \n\n%i tests completed\n", vcmMacrosTests);
|
|
||||||
if (vcmMacrosErrors > 0)
|
|
||||||
{
|
|
||||||
printf("%i FAILED\n\n", vcmMacrosErrors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("ALL PASSED\n\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaOptTest::Print(int mode)
|
|
||||||
{
|
|
||||||
double ActualBitRate = 8.0 *( _sumEncBytes / (_frameCnt / _frameRate));
|
|
||||||
double actualBitRate = ActualBitRate / 1000.0;
|
|
||||||
webrtc::test::QualityMetricsResult psnr;
|
|
||||||
I420PSNRFromFiles(_actualSourcename.c_str(), _outname.c_str(), _width,
|
|
||||||
_height, &psnr);
|
|
||||||
|
|
||||||
(_log) << "VCM: Media Optimization Test Cycle Completed!" << std::endl;
|
|
||||||
(_log) << "Input file: " << _inname << std::endl;
|
|
||||||
(_log) << "Output file:" << _outname << std::endl;
|
|
||||||
( _log) << "Actual bitrate: " << actualBitRate<< " kbps\tTarget: " << _bitRate << " kbps" << std::endl;
|
|
||||||
(_log) << "Error Reslience: NACK:" << _nackEnabled << "; FEC: " << _fecEnabled << std::endl;
|
|
||||||
(_log) << "Packet Loss applied= %f " << _lossRate << std::endl;
|
|
||||||
(_log) << _numFramesDropped << " FRames were dropped" << std::endl;
|
|
||||||
( _log) << "PSNR: " << psnr.average << std::endl;
|
|
||||||
(_log) << std::endl;
|
|
||||||
|
|
||||||
if (_testType == 2)
|
|
||||||
{
|
|
||||||
fprintf(_outputRes,"************\n");
|
|
||||||
fprintf(_outputRes,"\n\n\n");
|
|
||||||
fprintf(_outputRes,"Actual bitrate: %f kbps\n", actualBitRate);
|
|
||||||
fprintf(_outputRes,"Target bitrate: %f kbps\n", _bitRate);
|
|
||||||
fprintf(_outputRes,"NACK: %s ",(_nackEnabled)?"true":"false");
|
|
||||||
fprintf(_outputRes,"FEC: %s \n ",(_fecEnabled)?"true":"false");
|
|
||||||
fprintf(_outputRes,"Packet loss applied = %f\n", _lossRate);
|
|
||||||
fprintf(_outputRes,"%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
|
|
||||||
fprintf(_outputRes,"PSNR: %f \n", psnr.average);
|
|
||||||
fprintf(_outputRes,"************\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
if (_testType == 1)
|
|
||||||
{
|
|
||||||
fprintf(_fpout,"************\n");
|
|
||||||
fprintf(_fpout,"\n\n\n");
|
|
||||||
fprintf(_fpout,"Actual bitrate: %f kbps\n", actualBitRate);
|
|
||||||
fprintf(_fpout,"Target bitrate: %f kbps\n", _bitRate);
|
|
||||||
fprintf(_fpout,"NACK: %s ",(_nackEnabled)?"true":"false");
|
|
||||||
fprintf(_fpout,"FEC: %s \n ",(_fecEnabled)?"true":"false");
|
|
||||||
fprintf(_fpout,"Packet loss applied = %f\n", _lossRate);
|
|
||||||
fprintf(_fpout,"%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
|
|
||||||
fprintf(_fpout,"PSNR: %f \n", psnr.average);
|
|
||||||
fprintf(_fpout,"************\n");
|
|
||||||
|
|
||||||
int testNum1 = _testNum/(_numParRuns +1) + 1;
|
|
||||||
int testNum2 = _testNum%_numParRuns;
|
|
||||||
if (testNum2 == 0) testNum2 = _numParRuns;
|
|
||||||
fprintf(_fpout2,"%d %d %f %f %f %f \n",testNum1,testNum2,_bitRate,actualBitRate,_lossRate,psnr.average);
|
|
||||||
fclose(_fpinp);
|
|
||||||
_fpinp = fopen("dat_inp","wb");
|
|
||||||
fprintf(_fpinp,"%f %f %d \n",_bitRate,_lossRate,_testNum);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
if (mode == 1)
|
|
||||||
{
|
|
||||||
// print to screen
|
|
||||||
printf("\n\n\n");
|
|
||||||
printf("Actual bitrate: %f kbps\n", actualBitRate);
|
|
||||||
printf("Target bitrate: %f kbps\n", _bitRate);
|
|
||||||
printf("NACK: %s ",(_nackEnabled)?"true":"false");
|
|
||||||
printf("FEC: %s \n",(_fecEnabled)?"true":"false");
|
|
||||||
printf("Packet loss applied = %f\n", _lossRate);
|
|
||||||
printf("%d frames were dropped, and total number of frames processed %d \n",_numFramesDropped,_frameCnt);
|
|
||||||
printf("PSNR: %f \n", psnr.average);
|
|
||||||
}
|
|
||||||
TEST(psnr.average > 10); // low becuase of possible frame dropping (need to verify that OK for all packet loss values/ rates)
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaOptTest::TearDown() {
|
|
||||||
delete _rtp;
|
|
||||||
_rtp = NULL;
|
|
||||||
delete _outgoingTransport;
|
|
||||||
_outgoingTransport = NULL;
|
|
||||||
delete _dataCallback;
|
|
||||||
_dataCallback = NULL;
|
|
||||||
_log.close();
|
|
||||||
fclose(_sourceFile);
|
|
||||||
fclose(_decodedFile);
|
|
||||||
fclose(_actualSourceFile);
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// VCM Media Optimization Test
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_MEDIA_OPT_TEST_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_MEDIA_OPT_TEST_H_
|
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/receiver_tests.h" // receive side callbacks
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/video_source.h"
|
|
||||||
|
|
||||||
// media optimization test
|
|
||||||
// This test simulates a complete encode-decode cycle via the RTP module.
|
|
||||||
// allows error resilience tests, packet loss tests, etc.
|
|
||||||
// Does not test the media optimization deirectly, but via the VCM API only.
|
|
||||||
// The test allows two modes:
|
|
||||||
// 1 - Standard, basic settings, one run
|
|
||||||
// 2 - Release test - iterates over a number of video sequences, bit rates, packet loss values ,etc.
|
|
||||||
|
|
||||||
class MediaOptTest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MediaOptTest(webrtc::VideoCodingModule* vcm,
|
|
||||||
webrtc::Clock* clock);
|
|
||||||
~MediaOptTest();
|
|
||||||
|
|
||||||
static int RunTest(int testNum, CmdArgs& args);
|
|
||||||
// perform encode-decode of an entire sequence
|
|
||||||
int32_t Perform();
|
|
||||||
// Set up for a single mode test
|
|
||||||
void Setup(int testType, CmdArgs& args);
|
|
||||||
// General set up - applicable for both modes
|
|
||||||
void GeneralSetup();
|
|
||||||
// Run release testing
|
|
||||||
void RTTest();
|
|
||||||
void TearDown();
|
|
||||||
// mode = 1; will print to screen, otherwise only to log file
|
|
||||||
void Print(int mode);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
webrtc::VideoCodingModule* _vcm;
|
|
||||||
webrtc::RtpReceiver* rtp_receiver_;
|
|
||||||
webrtc::RtpRtcp* _rtp;
|
|
||||||
webrtc::RTPSendCompleteCallback* _outgoingTransport;
|
|
||||||
RtpDataCallback* _dataCallback;
|
|
||||||
|
|
||||||
webrtc::Clock* _clock;
|
|
||||||
std::string _inname;
|
|
||||||
std::string _outname;
|
|
||||||
std::string _actualSourcename;
|
|
||||||
std::fstream _log;
|
|
||||||
FILE* _sourceFile;
|
|
||||||
FILE* _decodedFile;
|
|
||||||
FILE* _actualSourceFile;
|
|
||||||
FILE* _outputRes;
|
|
||||||
uint16_t _width;
|
|
||||||
uint16_t _height;
|
|
||||||
uint32_t _lengthSourceFrame;
|
|
||||||
uint32_t _timeStamp;
|
|
||||||
float _frameRate;
|
|
||||||
bool _nackEnabled;
|
|
||||||
bool _fecEnabled;
|
|
||||||
bool _nackFecEnabled;
|
|
||||||
int64_t _rttMS;
|
|
||||||
float _bitRate;
|
|
||||||
double _lossRate;
|
|
||||||
uint32_t _renderDelayMs;
|
|
||||||
int32_t _frameCnt;
|
|
||||||
size_t _sumEncBytes;
|
|
||||||
int32_t _numFramesDropped;
|
|
||||||
std::string _codecName;
|
|
||||||
webrtc::VideoCodecType _sendCodecType;
|
|
||||||
int32_t _numberOfCores;
|
|
||||||
|
|
||||||
//for release test#2
|
|
||||||
FILE* _fpinp;
|
|
||||||
FILE* _fpout;
|
|
||||||
FILE* _fpout2;
|
|
||||||
int _testType;
|
|
||||||
int _testNum;
|
|
||||||
int _numParRuns;
|
|
||||||
|
|
||||||
}; // end of MediaOptTest class definition
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_MEDIA_OPT_TEST_H_
|
|
@ -1,376 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*************************************************
|
|
||||||
*
|
|
||||||
* Testing multi thread - receive and send sides
|
|
||||||
*
|
|
||||||
**************************************************/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/media_opt_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/mt_test_common.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
bool
|
|
||||||
MainSenderThread(void* obj)
|
|
||||||
{
|
|
||||||
SendSharedState* state = static_cast<SendSharedState*>(obj);
|
|
||||||
EventWrapper& waitEvent = *EventWrapper::Create();
|
|
||||||
// preparing a frame for encoding
|
|
||||||
I420VideoFrame sourceFrame;
|
|
||||||
int32_t width = state->_args.width;
|
|
||||||
int32_t height = state->_args.height;
|
|
||||||
float frameRate = state->_args.frameRate;
|
|
||||||
int32_t lengthSourceFrame = 3*width*height/2;
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[lengthSourceFrame];
|
|
||||||
|
|
||||||
if (state->_sourceFile == NULL)
|
|
||||||
{
|
|
||||||
state->_sourceFile = fopen(state->_args.inputFile.c_str(), "rb");
|
|
||||||
if (state->_sourceFile == NULL)
|
|
||||||
{
|
|
||||||
printf ("Error when opening file \n");
|
|
||||||
delete &waitEvent;
|
|
||||||
delete [] tmpBuffer;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (feof(state->_sourceFile) == 0)
|
|
||||||
{
|
|
||||||
TEST(fread(tmpBuffer, 1, lengthSourceFrame,state->_sourceFile) > 0 ||
|
|
||||||
feof(state->_sourceFile));
|
|
||||||
state->_frameCnt++;
|
|
||||||
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.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
width, height,
|
|
||||||
width, half_width, half_width);
|
|
||||||
state->_timestamp += (uint32_t)(9e4 / frameRate);
|
|
||||||
sourceFrame.set_timestamp(state->_timestamp);
|
|
||||||
|
|
||||||
int32_t ret = state->_vcm.AddVideoFrame(sourceFrame);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
printf("Add Frame error: %d\n", ret);
|
|
||||||
delete &waitEvent;
|
|
||||||
delete [] tmpBuffer;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
waitEvent.Wait(33);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete &waitEvent;
|
|
||||||
delete [] tmpBuffer;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IntSenderThread(void* obj)
|
|
||||||
{
|
|
||||||
SendSharedState* state = static_cast<SendSharedState*>(obj);
|
|
||||||
state->_vcm.SetChannelParameters(1000000,30,0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int MTRxTxTest(CmdArgs& args)
|
|
||||||
{
|
|
||||||
/* TEST SETTINGS */
|
|
||||||
std::string inname = args.inputFile;
|
|
||||||
std::string outname;
|
|
||||||
if (args.outputFile == "")
|
|
||||||
outname = test::OutputPath() + "MTRxTxTest_decoded.yuv";
|
|
||||||
else
|
|
||||||
outname = args.outputFile;
|
|
||||||
|
|
||||||
uint16_t width = args.width;
|
|
||||||
uint16_t height = args.height;
|
|
||||||
|
|
||||||
float frameRate = args.frameRate;
|
|
||||||
float bitRate = args.bitRate;
|
|
||||||
int32_t numberOfCores = 1;
|
|
||||||
|
|
||||||
// error resilience/network
|
|
||||||
// Nack support is currently not implemented in this test.
|
|
||||||
bool nackEnabled = false;
|
|
||||||
bool fecEnabled = false;
|
|
||||||
int64_t rttMS = 20;
|
|
||||||
float lossRate = 0.0*255; // no packet loss
|
|
||||||
uint32_t renderDelayMs = 0;
|
|
||||||
uint32_t minPlayoutDelayMs = 0;
|
|
||||||
|
|
||||||
/* TEST SET-UP */
|
|
||||||
|
|
||||||
// Set up trace
|
|
||||||
Trace::CreateTrace();
|
|
||||||
Trace::SetTraceFile((test::OutputPath() + "MTRxTxTestTrace.txt").c_str());
|
|
||||||
Trace::set_level_filter(webrtc::kTraceAll);
|
|
||||||
|
|
||||||
FILE* sourceFile;
|
|
||||||
FILE* decodedFile;
|
|
||||||
|
|
||||||
if ((sourceFile = fopen(inname.c_str(), "rb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("Cannot read file %s.\n", inname.c_str());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((decodedFile = fopen(outname.c_str(), "wb")) == NULL)
|
|
||||||
{
|
|
||||||
printf("Cannot read file %s.\n", outname.c_str());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(nullptr);
|
|
||||||
RtpDataCallback dataCallback(vcm);
|
|
||||||
|
|
||||||
RTPSendCompleteCallback* outgoingTransport =
|
|
||||||
new RTPSendCompleteCallback(Clock::GetRealTimeClock(), "dump.rtp");
|
|
||||||
|
|
||||||
RtpRtcp::Configuration configuration;
|
|
||||||
configuration.id = 1;
|
|
||||||
configuration.audio = false;
|
|
||||||
configuration.outgoing_transport = outgoingTransport;
|
|
||||||
RtpRtcp* rtp = RtpRtcp::CreateRtpRtcp(configuration);
|
|
||||||
rtc::scoped_ptr<RTPPayloadRegistry> registry(
|
|
||||||
new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(false)));
|
|
||||||
rtc::scoped_ptr<RtpReceiver> rtp_receiver(RtpReceiver::CreateVideoReceiver(
|
|
||||||
-1, Clock::GetRealTimeClock(), &dataCallback, NULL, registry.get()));
|
|
||||||
|
|
||||||
// registering codecs for the RTP module
|
|
||||||
VideoCodec video_codec;
|
|
||||||
strncpy(video_codec.plName, "ULPFEC", 32);
|
|
||||||
video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
|
|
||||||
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate) == 0);
|
|
||||||
|
|
||||||
strncpy(video_codec.plName, "RED", 32);
|
|
||||||
video_codec.plType = VCM_RED_PAYLOAD_TYPE;
|
|
||||||
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate) == 0);
|
|
||||||
|
|
||||||
strncpy(video_codec.plName, args.codecName.c_str(), 32);
|
|
||||||
video_codec.plType = VCM_VP8_PAYLOAD_TYPE;
|
|
||||||
video_codec.maxBitrate = 10000;
|
|
||||||
video_codec.codecType = args.codecType;
|
|
||||||
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
|
|
||||||
video_codec.plType,
|
|
||||||
90000,
|
|
||||||
0,
|
|
||||||
video_codec.maxBitrate) == 0);
|
|
||||||
TEST(rtp->RegisterSendPayload(video_codec) == 0);
|
|
||||||
|
|
||||||
// inform RTP Module of error resilience features
|
|
||||||
TEST(rtp->SetGenericFECStatus(fecEnabled, VCM_RED_PAYLOAD_TYPE,
|
|
||||||
VCM_ULPFEC_PAYLOAD_TYPE) == 0);
|
|
||||||
|
|
||||||
//VCM
|
|
||||||
if (vcm->InitializeReceiver() < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (vcm->InitializeSender())
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// registering codecs for the VCM module
|
|
||||||
VideoCodec sendCodec;
|
|
||||||
vcm->InitializeSender();
|
|
||||||
int32_t numberOfCodecs = vcm->NumberOfCodecs();
|
|
||||||
if (numberOfCodecs < 1)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vcm->Codec(args.codecType, &sendCodec) != 0)
|
|
||||||
{
|
|
||||||
// desired codec unavailable
|
|
||||||
printf("Codec not registered\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// register codec
|
|
||||||
sendCodec.startBitrate = (int) bitRate;
|
|
||||||
sendCodec.height = height;
|
|
||||||
sendCodec.width = width;
|
|
||||||
sendCodec.maxFramerate = (uint8_t)frameRate;
|
|
||||||
vcm->RegisterSendCodec(&sendCodec, numberOfCores, 1440);
|
|
||||||
vcm->RegisterReceiveCodec(&sendCodec, numberOfCores); // same settings for encode and decode
|
|
||||||
|
|
||||||
vcm->SetRenderDelay(renderDelayMs);
|
|
||||||
vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
|
|
||||||
|
|
||||||
// Callback Settings
|
|
||||||
|
|
||||||
PacketRequester packetRequester(*rtp);
|
|
||||||
vcm->RegisterPacketRequestCallback(&packetRequester);
|
|
||||||
|
|
||||||
VCMRTPEncodeCompleteCallback* encodeCompleteCallback = new VCMRTPEncodeCompleteCallback(rtp);
|
|
||||||
vcm->RegisterTransportCallback(encodeCompleteCallback);
|
|
||||||
encodeCompleteCallback->SetCodecType(ConvertCodecType(args.codecName.c_str()));
|
|
||||||
encodeCompleteCallback->SetFrameDimensions(width, height);
|
|
||||||
// frame ready to be sent to network
|
|
||||||
|
|
||||||
VCMDecodeCompleteCallback receiveCallback(decodedFile);
|
|
||||||
vcm->RegisterReceiveCallback(&receiveCallback);
|
|
||||||
|
|
||||||
VideoProtectionCallback protectionCallback;
|
|
||||||
vcm->RegisterProtectionCallback(&protectionCallback);
|
|
||||||
|
|
||||||
outgoingTransport->SetLossPct(lossRate);
|
|
||||||
// Nack support is currently not implemented in this test
|
|
||||||
assert(nackEnabled == false);
|
|
||||||
vcm->SetVideoProtection(kProtectionNack, nackEnabled);
|
|
||||||
vcm->SetVideoProtection(kProtectionFEC, fecEnabled);
|
|
||||||
|
|
||||||
// inform RTP Module of error resilience features
|
|
||||||
FecProtectionParams delta_params = protectionCallback.DeltaFecParameters();
|
|
||||||
FecProtectionParams key_params = protectionCallback.KeyFecParameters();
|
|
||||||
rtp->SetFecParameters(&delta_params, &key_params);
|
|
||||||
rtp_receiver->SetNACKStatus(nackEnabled ? kNackRtcp : kNackOff);
|
|
||||||
|
|
||||||
vcm->SetChannelParameters(static_cast<uint32_t>(1000 * bitRate),
|
|
||||||
(uint8_t) lossRate, rttMS);
|
|
||||||
|
|
||||||
SharedRTPState mtState(*vcm, *rtp); // receive side
|
|
||||||
SendSharedState mtSendState(*vcm, *rtp, args); // send side
|
|
||||||
|
|
||||||
/*START TEST*/
|
|
||||||
|
|
||||||
// Create and start all threads
|
|
||||||
// send side threads
|
|
||||||
ThreadWrapper* mainSenderThread = ThreadWrapper::CreateThread(MainSenderThread,
|
|
||||||
&mtSendState, kNormalPriority, "MainSenderThread");
|
|
||||||
ThreadWrapper* intSenderThread = ThreadWrapper::CreateThread(IntSenderThread,
|
|
||||||
&mtSendState, kNormalPriority, "IntThread");
|
|
||||||
|
|
||||||
if (mainSenderThread != NULL)
|
|
||||||
{
|
|
||||||
mainSenderThread->Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Unable to start main sender thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intSenderThread != NULL)
|
|
||||||
{
|
|
||||||
intSenderThread->Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Unable to start sender interference thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive side threads
|
|
||||||
ThreadWrapper* processingThread = ThreadWrapper::CreateThread(ProcessingThread,
|
|
||||||
&mtState, kNormalPriority, "ProcessingThread");
|
|
||||||
ThreadWrapper* decodeThread = ThreadWrapper::CreateThread(DecodeThread,
|
|
||||||
&mtState, kNormalPriority, "DecodeThread");
|
|
||||||
|
|
||||||
if (processingThread != NULL)
|
|
||||||
{
|
|
||||||
processingThread->Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Unable to start processing thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decodeThread != NULL)
|
|
||||||
{
|
|
||||||
decodeThread->Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Unable to start decode thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
EventWrapper& waitEvent = *EventWrapper::Create();
|
|
||||||
|
|
||||||
// Decode for 10 seconds and then tear down and exit.
|
|
||||||
waitEvent.Wait(30000);
|
|
||||||
|
|
||||||
// Tear down
|
|
||||||
|
|
||||||
while (!mainSenderThread->Stop())
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!intSenderThread->Stop())
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
while (!processingThread->Stop())
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!decodeThread->Stop())
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nVCM MT RX/TX Test: \n\n%i tests completed\n", vcmMacrosTests);
|
|
||||||
if (vcmMacrosErrors > 0)
|
|
||||||
{
|
|
||||||
printf("%i FAILED\n\n", vcmMacrosErrors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("ALL PASSED\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
delete &waitEvent;
|
|
||||||
delete mainSenderThread;
|
|
||||||
delete intSenderThread;
|
|
||||||
delete processingThread;
|
|
||||||
delete decodeThread;
|
|
||||||
delete encodeCompleteCallback;
|
|
||||||
delete outgoingTransport;
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
delete rtp;
|
|
||||||
rtp = NULL;
|
|
||||||
vcm = NULL;
|
|
||||||
Trace::ReturnTrace();
|
|
||||||
fclose(decodedFile);
|
|
||||||
printf("Multi-Thread test Done: View output file \n");
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/main/test/mt_test_common.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
|
|
||||||
#include "webrtc/modules/utility/interface/rtp_dump.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
TransportCallback::TransportCallback(Clock* clock, const char* filename)
|
|
||||||
: RTPSendCompleteCallback(clock, filename) {
|
|
||||||
}
|
|
||||||
|
|
||||||
TransportCallback::~TransportCallback()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
TransportCallback::SendPacket(int channel, const void *data, size_t len)
|
|
||||||
{
|
|
||||||
_sendCount++;
|
|
||||||
_totalSentLength += len;
|
|
||||||
|
|
||||||
if (_rtpDump != NULL)
|
|
||||||
{
|
|
||||||
if (_rtpDump->DumpPacket((const uint8_t*)data, len) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool transmitPacket = true;
|
|
||||||
// Off-line tests, don't drop first Key frame (approx.)
|
|
||||||
if (_sendCount > 20)
|
|
||||||
{
|
|
||||||
transmitPacket = PacketLoss();
|
|
||||||
}
|
|
||||||
|
|
||||||
Clock* clock = Clock::GetRealTimeClock();
|
|
||||||
int64_t now = clock->TimeInMilliseconds();
|
|
||||||
// Insert outgoing packet into list
|
|
||||||
if (transmitPacket)
|
|
||||||
{
|
|
||||||
RtpPacket* newPacket = new RtpPacket();
|
|
||||||
memcpy(newPacket->data, data, len);
|
|
||||||
newPacket->length = len;
|
|
||||||
// Simulate receive time = network delay + packet jitter
|
|
||||||
// simulated as a Normal distribution random variable with
|
|
||||||
// mean = networkDelay and variance = jitterVar
|
|
||||||
int32_t
|
|
||||||
simulatedDelay = (int32_t)NormalDist(_networkDelayMs,
|
|
||||||
sqrt(_jitterVar));
|
|
||||||
newPacket->receiveTime = now + simulatedDelay;
|
|
||||||
_rtpPackets.push_back(newPacket);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
TransportCallback::TransportPackets()
|
|
||||||
{
|
|
||||||
// Are we ready to send packets to the receiver?
|
|
||||||
RtpPacket* packet = NULL;
|
|
||||||
Clock* clock = Clock::GetRealTimeClock();
|
|
||||||
int64_t now = clock->TimeInMilliseconds();
|
|
||||||
|
|
||||||
while (!_rtpPackets.empty())
|
|
||||||
{
|
|
||||||
// Take first packet in list
|
|
||||||
packet = _rtpPackets.front();
|
|
||||||
int64_t timeToReceive = packet->receiveTime - now;
|
|
||||||
if (timeToReceive > 0)
|
|
||||||
{
|
|
||||||
// No available packets to send
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_rtpPackets.pop_front();
|
|
||||||
// Send to receive side
|
|
||||||
RTPHeader header;
|
|
||||||
rtc::scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
|
|
||||||
if (!parser->Parse(packet->data, packet->length, &header)) {
|
|
||||||
delete packet;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
PayloadUnion payload_specific;
|
|
||||||
if (!rtp_payload_registry_->GetPayloadSpecifics(
|
|
||||||
header.payloadType, &payload_specific)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!rtp_receiver_->IncomingRtpPacket(header, packet->data,
|
|
||||||
packet->length, payload_specific,
|
|
||||||
true))
|
|
||||||
{
|
|
||||||
delete packet;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
delete packet;
|
|
||||||
packet = NULL;
|
|
||||||
}
|
|
||||||
return 0; // OK
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool VCMProcessingThread(void* obj)
|
|
||||||
{
|
|
||||||
SharedRTPState* state = static_cast<SharedRTPState*>(obj);
|
|
||||||
if (state->_vcm.TimeUntilNextProcess() <= 0)
|
|
||||||
{
|
|
||||||
if (state->_vcm.Process() < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool VCMDecodeThread(void* obj)
|
|
||||||
{
|
|
||||||
SharedRTPState* state = static_cast<SharedRTPState*>(obj);
|
|
||||||
state->_vcm.Decode();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TransportThread(void *obj)
|
|
||||||
{
|
|
||||||
SharedTransportState* state = static_cast<SharedTransportState*>(obj);
|
|
||||||
state->_transport.TransportPackets();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Common multi-thread functionality across video coding module tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_MT_TEST_COMMON_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_MT_TEST_COMMON_H_
|
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/video_source.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class SendSharedState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SendSharedState(webrtc::VideoCodingModule& vcm, webrtc::RtpRtcp& rtp,
|
|
||||||
CmdArgs args) :
|
|
||||||
_vcm(vcm),
|
|
||||||
_rtp(rtp),
|
|
||||||
_args(args),
|
|
||||||
_sourceFile(NULL),
|
|
||||||
_frameCnt(0),
|
|
||||||
_timestamp(0) {}
|
|
||||||
|
|
||||||
webrtc::VideoCodingModule& _vcm;
|
|
||||||
webrtc::RtpRtcp& _rtp;
|
|
||||||
CmdArgs _args;
|
|
||||||
FILE* _sourceFile;
|
|
||||||
int32_t _frameCnt;
|
|
||||||
int32_t _timestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
// MT implementation of the RTPSendCompleteCallback (Transport)
|
|
||||||
class TransportCallback:public RTPSendCompleteCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// constructor input: (receive side) rtp module to send encoded data to
|
|
||||||
TransportCallback(Clock* clock, const char* filename = NULL);
|
|
||||||
virtual ~TransportCallback();
|
|
||||||
// Add packets to list
|
|
||||||
// Incorporate network conditions - delay and packet loss
|
|
||||||
// Actual transmission will occur on a separate thread
|
|
||||||
int SendPacket(int channel, const void* data, size_t len) override;
|
|
||||||
// Send to the receiver packets which are ready to be submitted
|
|
||||||
int TransportPackets();
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedRTPState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SharedRTPState(webrtc::VideoCodingModule& vcm, webrtc::RtpRtcp& rtp) :
|
|
||||||
_vcm(vcm),
|
|
||||||
_rtp(rtp) {}
|
|
||||||
webrtc::VideoCodingModule& _vcm;
|
|
||||||
webrtc::RtpRtcp& _rtp;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SharedTransportState
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SharedTransportState(webrtc::RtpRtcp& rtp, TransportCallback& transport):
|
|
||||||
_rtp(rtp),
|
|
||||||
_transport(transport) {}
|
|
||||||
webrtc::RtpRtcp& _rtp;
|
|
||||||
TransportCallback& _transport;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool VCMProcessingThread(void* obj);
|
|
||||||
bool VCMDecodeThread(void* obj);
|
|
||||||
bool TransportThread(void *obj);
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_MT_TEST_COMMON_H_
|
|
@ -1,404 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/main/test/normal_test.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "webrtc/common_types.h"
|
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/source/encoded_frame.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
#include "webrtc/test/testsupport/metrics/video_metrics.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
int NormalTest::RunTest(const CmdArgs& args)
|
|
||||||
{
|
|
||||||
SimulatedClock sim_clock(0);
|
|
||||||
SimulatedClock* clock = &sim_clock;
|
|
||||||
NullEventFactory event_factory;
|
|
||||||
Trace::CreateTrace();
|
|
||||||
Trace::SetTraceFile(
|
|
||||||
(test::OutputPath() + "VCMNormalTestTrace.txt").c_str());
|
|
||||||
Trace::set_level_filter(webrtc::kTraceAll);
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(clock, &event_factory);
|
|
||||||
NormalTest VCMNTest(vcm, clock);
|
|
||||||
VCMNTest.Perform(args);
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
Trace::ReturnTrace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////
|
|
||||||
// Callback Implementation
|
|
||||||
//////////////
|
|
||||||
|
|
||||||
VCMNTEncodeCompleteCallback::VCMNTEncodeCompleteCallback(FILE* encodedFile,
|
|
||||||
NormalTest& test):
|
|
||||||
_encodedFile(encodedFile),
|
|
||||||
_encodedBytes(0),
|
|
||||||
_skipCnt(0),
|
|
||||||
_VCMReceiver(NULL),
|
|
||||||
_seqNo(0),
|
|
||||||
_test(test)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
VCMNTEncodeCompleteCallback::~VCMNTEncodeCompleteCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCMNTEncodeCompleteCallback::RegisterTransportCallback(
|
|
||||||
VCMPacketizationCallback* transport)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t VCMNTEncodeCompleteCallback::SendData(
|
|
||||||
uint8_t payloadType,
|
|
||||||
const webrtc::EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& /*fragmentationHeader*/,
|
|
||||||
const webrtc::RTPVideoHeader* videoHdr)
|
|
||||||
{
|
|
||||||
// will call the VCMReceiver input packet
|
|
||||||
_frameType = VCMEncodedFrame::ConvertFrameType(encoded_image._frameType);
|
|
||||||
// writing encodedData into file
|
|
||||||
if (fwrite(encoded_image._buffer, 1, encoded_image._length, _encodedFile) !=
|
|
||||||
encoded_image._length) {
|
|
||||||
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 kVideoCodecVP9:
|
|
||||||
// Leave for now, until we add kRtpVideoVp9 to RTP.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
rtpInfo.header.payloadType = payloadType;
|
|
||||||
rtpInfo.header.sequenceNumber = _seqNo++;
|
|
||||||
rtpInfo.header.ssrc = 0;
|
|
||||||
rtpInfo.header.timestamp = encoded_image._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 += encoded_image._length;
|
|
||||||
if (encoded_image._length < 20)
|
|
||||||
{
|
|
||||||
_skipCnt++;
|
|
||||||
}
|
|
||||||
_VCMReceiver->IncomingPacket(
|
|
||||||
encoded_image._buffer, encoded_image._length, rtpInfo);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void
|
|
||||||
VCMNTEncodeCompleteCallback::RegisterReceiverVCM(VideoCodingModule *vcm)
|
|
||||||
{
|
|
||||||
_VCMReceiver = vcm;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t
|
|
||||||
VCMNTEncodeCompleteCallback::EncodedBytes()
|
|
||||||
{
|
|
||||||
return _encodedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
|
||||||
VCMNTEncodeCompleteCallback::SkipCnt()
|
|
||||||
{
|
|
||||||
return _skipCnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoded Frame Callback Implementation
|
|
||||||
VCMNTDecodeCompleteCallback::~VCMNTDecodeCompleteCallback()
|
|
||||||
{
|
|
||||||
if (_decodedFile)
|
|
||||||
fclose(_decodedFile);
|
|
||||||
}
|
|
||||||
int32_t
|
|
||||||
VCMNTDecodeCompleteCallback::FrameToRender(webrtc::I420VideoFrame& videoFrame)
|
|
||||||
{
|
|
||||||
if (videoFrame.width() != _currentWidth ||
|
|
||||||
videoFrame.height() != _currentHeight)
|
|
||||||
{
|
|
||||||
_currentWidth = videoFrame.width();
|
|
||||||
_currentHeight = videoFrame.height();
|
|
||||||
if (_decodedFile != NULL)
|
|
||||||
{
|
|
||||||
fclose(_decodedFile);
|
|
||||||
_decodedFile = NULL;
|
|
||||||
}
|
|
||||||
_decodedFile = fopen(_outname.c_str(), "wb");
|
|
||||||
}
|
|
||||||
if (PrintI420VideoFrame(videoFrame, _decodedFile) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_decodedBytes += webrtc::CalcBufferSize(webrtc::kI420, videoFrame.width(),
|
|
||||||
videoFrame.height());
|
|
||||||
return VCM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
VCMNTDecodeCompleteCallback::DecodedBytes()
|
|
||||||
{
|
|
||||||
return _decodedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//VCM Normal Test Class implementation
|
|
||||||
|
|
||||||
NormalTest::NormalTest(VideoCodingModule* vcm, Clock* clock)
|
|
||||||
:
|
|
||||||
_clock(clock),
|
|
||||||
_vcm(vcm),
|
|
||||||
_sumEncBytes(0),
|
|
||||||
_timeStamp(0),
|
|
||||||
_totalEncodeTime(0),
|
|
||||||
_totalDecodeTime(0),
|
|
||||||
_decodeCompleteTime(0),
|
|
||||||
_encodeCompleteTime(0),
|
|
||||||
_totalEncodePipeTime(0),
|
|
||||||
_totalDecodePipeTime(0),
|
|
||||||
_frameCnt(0),
|
|
||||||
_encFrameCnt(0),
|
|
||||||
_decFrameCnt(0)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
NormalTest::~NormalTest()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
void
|
|
||||||
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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
NormalTest::Perform(const CmdArgs& args)
|
|
||||||
{
|
|
||||||
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<uint16_t>(_width);
|
|
||||||
_sendCodec.height = static_cast<uint16_t>(_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 */
|
|
||||||
VCMNTDecodeCompleteCallback _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);
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
|
|
||||||
double startTime = clock()/(double)CLOCKS_PER_SEC;
|
|
||||||
_vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 0);
|
|
||||||
|
|
||||||
SendStatsTest sendStats;
|
|
||||||
sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
|
|
||||||
sendStats.set_bitrate(1000 * _bitRate);
|
|
||||||
_vcm->RegisterSendStatisticsCallback(&sendStats);
|
|
||||||
|
|
||||||
while (feof(_sourceFile) == 0) {
|
|
||||||
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0 ||
|
|
||||||
feof(_sourceFile));
|
|
||||||
_frameCnt++;
|
|
||||||
sourceFrame.CreateFrame(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_width, _height,
|
|
||||||
_width, half_width, half_width);
|
|
||||||
_timeStamp +=
|
|
||||||
(uint32_t)(9e4 / static_cast<float>(_sendCodec.maxFramerate));
|
|
||||||
sourceFrame.set_timestamp(_timeStamp);
|
|
||||||
_encodeTimes[int(sourceFrame.timestamp())] =
|
|
||||||
clock()/(double)CLOCKS_PER_SEC;
|
|
||||||
int32_t 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();
|
|
||||||
}
|
|
||||||
uint32_t framePeriod =
|
|
||||||
static_cast<uint32_t>(
|
|
||||||
1000.0f / static_cast<float>(_sendCodec.maxFramerate) + 0.5f);
|
|
||||||
static_cast<SimulatedClock*>(_clock)->AdvanceTimeMilliseconds(framePeriod);
|
|
||||||
}
|
|
||||||
double endTime = clock()/(double)CLOCKS_PER_SEC;
|
|
||||||
_testTotalTime = endTime - startTime;
|
|
||||||
_sumEncBytes = _encodeCompleteCallback.EncodedBytes();
|
|
||||||
|
|
||||||
delete [] tmpBuffer;
|
|
||||||
delete waitEvent;
|
|
||||||
Teardown();
|
|
||||||
Print();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NormalTest::FrameEncoded(uint32_t timeStamp)
|
|
||||||
{
|
|
||||||
_encodeCompleteTime = clock()/(double)CLOCKS_PER_SEC;
|
|
||||||
_encFrameCnt++;
|
|
||||||
_totalEncodePipeTime += _encodeCompleteTime - _encodeTimes[int(timeStamp)];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NormalTest::FrameDecoded(uint32_t 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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_NORMAL_TEST_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_NORMAL_TEST_H_
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/video_source.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class NormalTest;
|
|
||||||
|
|
||||||
//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
|
|
||||||
int32_t SendData(uint8_t payloadType,
|
|
||||||
const webrtc::EncodedImage& encoded_image,
|
|
||||||
const webrtc::RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const webrtc::RTPVideoHeader* videoHdr) override;
|
|
||||||
|
|
||||||
// Register existing 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)
|
|
||||||
size_t EncodedBytes();
|
|
||||||
// return number of encoder-skipped frames
|
|
||||||
uint32_t SkipCnt();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE* _encodedFile;
|
|
||||||
size_t _encodedBytes;
|
|
||||||
uint32_t _skipCnt;
|
|
||||||
webrtc::VideoCodingModule* _VCMReceiver;
|
|
||||||
webrtc::FrameType _frameType;
|
|
||||||
uint16_t _seqNo;
|
|
||||||
NormalTest& _test;
|
|
||||||
}; // end of VCMEncodeCompleteCallback
|
|
||||||
|
|
||||||
class VCMNTDecodeCompleteCallback: public webrtc::VCMReceiveCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VCMNTDecodeCompleteCallback(std::string outname) // or should it get a name?
|
|
||||||
: _decodedFile(NULL),
|
|
||||||
_outname(outname),
|
|
||||||
_decodedBytes(0),
|
|
||||||
_currentWidth(0),
|
|
||||||
_currentHeight(0) {}
|
|
||||||
virtual ~VCMNTDecodeCompleteCallback();
|
|
||||||
void SetUserReceiveCallback(webrtc::VCMReceiveCallback* receiveCallback);
|
|
||||||
|
|
||||||
// will write decoded frame into file
|
|
||||||
int32_t FrameToRender(webrtc::I420VideoFrame& videoFrame) override;
|
|
||||||
|
|
||||||
size_t DecodedBytes();
|
|
||||||
private:
|
|
||||||
FILE* _decodedFile;
|
|
||||||
std::string _outname;
|
|
||||||
size_t _decodedBytes;
|
|
||||||
int _currentWidth;
|
|
||||||
int _currentHeight;
|
|
||||||
}; // end of VCMNTDecodeCompleteCallback class
|
|
||||||
|
|
||||||
class NormalTest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NormalTest(webrtc::VideoCodingModule* vcm,
|
|
||||||
webrtc::Clock* clock);
|
|
||||||
~NormalTest();
|
|
||||||
static int RunTest(const CmdArgs& args);
|
|
||||||
int32_t Perform(const CmdArgs& args);
|
|
||||||
// option:: turn into private and call from perform
|
|
||||||
int Width() const { return _width; };
|
|
||||||
int Height() const { return _height; };
|
|
||||||
webrtc::VideoCodecType VideoType() const { return _videoType; };
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// test setup - open files, general initializations
|
|
||||||
void Setup(const CmdArgs& args);
|
|
||||||
// close open files, delete used memory
|
|
||||||
void Teardown();
|
|
||||||
// print results to std output and to log file
|
|
||||||
void Print();
|
|
||||||
// calculating pipeline delay, and encoding time
|
|
||||||
void FrameEncoded(uint32_t timeStamp);
|
|
||||||
// calculating pipeline delay, and decoding time
|
|
||||||
void FrameDecoded(uint32_t timeStamp);
|
|
||||||
|
|
||||||
webrtc::Clock* _clock;
|
|
||||||
webrtc::VideoCodingModule* _vcm;
|
|
||||||
webrtc::VideoCodec _sendCodec;
|
|
||||||
webrtc::VideoCodec _receiveCodec;
|
|
||||||
std::string _inname;
|
|
||||||
std::string _outname;
|
|
||||||
std::string _encodedName;
|
|
||||||
size_t _sumEncBytes;
|
|
||||||
FILE* _sourceFile;
|
|
||||||
FILE* _decodedFile;
|
|
||||||
FILE* _encodedFile;
|
|
||||||
std::fstream _log;
|
|
||||||
int _width;
|
|
||||||
int _height;
|
|
||||||
float _frameRate;
|
|
||||||
float _bitRate;
|
|
||||||
uint32_t _lengthSourceFrame;
|
|
||||||
uint32_t _timeStamp;
|
|
||||||
webrtc::VideoCodecType _videoType;
|
|
||||||
double _totalEncodeTime;
|
|
||||||
double _totalDecodeTime;
|
|
||||||
double _decodeCompleteTime;
|
|
||||||
double _encodeCompleteTime;
|
|
||||||
double _totalEncodePipeTime;
|
|
||||||
double _totalDecodePipeTime;
|
|
||||||
double _testTotalTime;
|
|
||||||
std::map<int, double> _encodeTimes;
|
|
||||||
std::map<int, double> _decodeTimes;
|
|
||||||
int32_t _frameCnt;
|
|
||||||
int32_t _encFrameCnt;
|
|
||||||
int32_t _decFrameCnt;
|
|
||||||
|
|
||||||
}; // end of VCMNormalTestClass
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_NORMAL_TEST_H_
|
|
@ -1,580 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/main/test/quality_modes_test.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_callbacks.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/data_log.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/data_log.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
#include "webrtc/test/testsupport/metrics/video_metrics.h"
|
|
||||||
|
|
||||||
using namespace webrtc;
|
|
||||||
|
|
||||||
int qualityModeTest(const CmdArgs& args)
|
|
||||||
{
|
|
||||||
SimulatedClock clock(0);
|
|
||||||
NullEventFactory event_factory;
|
|
||||||
VideoCodingModule* vcm = VideoCodingModule::Create(&clock, &event_factory);
|
|
||||||
QualityModesTest QMTest(vcm, &clock);
|
|
||||||
QMTest.Perform(args);
|
|
||||||
VideoCodingModule::Destroy(vcm);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QualityModesTest::QualityModesTest(VideoCodingModule* vcm,
|
|
||||||
Clock* clock):
|
|
||||||
NormalTest(vcm, clock),
|
|
||||||
_vpm()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
QualityModesTest::~QualityModesTest()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
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());
|
|
||||||
|
|
||||||
_encodedName = test::OutputPath() + "encoded_qmtest.yuv";
|
|
||||||
|
|
||||||
//NATIVE/SOURCE VALUES
|
|
||||||
_nativeWidth = args.width;
|
|
||||||
_nativeHeight = args.height;
|
|
||||||
_nativeFrameRate =args.frameRate;
|
|
||||||
|
|
||||||
//TARGET/ENCODER VALUES
|
|
||||||
_width = args.width;
|
|
||||||
_height = args.height;
|
|
||||||
_frameRate = args.frameRate;
|
|
||||||
|
|
||||||
_bitRate = args.bitRate;
|
|
||||||
|
|
||||||
_flagSSIM = true;
|
|
||||||
|
|
||||||
_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
QualityModesTest::Perform(const CmdArgs& args)
|
|
||||||
{
|
|
||||||
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};
|
|
||||||
|
|
||||||
uint32_t numChanges = sizeof(updateFrameNum)/sizeof(*updateFrameNum);
|
|
||||||
uint8_t change = 0;// change counter
|
|
||||||
|
|
||||||
_vpm = VideoProcessingModule::Create(1);
|
|
||||||
EventWrapper* waitEvent = EventWrapper::Create();
|
|
||||||
VideoCodec codec;//both send and receive
|
|
||||||
_vcm->InitializeReceiver();
|
|
||||||
_vcm->InitializeSender();
|
|
||||||
int32_t 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 = (uint8_t) _frameRate;
|
|
||||||
codec.width = (uint16_t)_width;
|
|
||||||
codec.height = (uint16_t)_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 */
|
|
||||||
VCMQMDecodeCompleteCallback _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);
|
|
||||||
|
|
||||||
///////////////////////
|
|
||||||
/// Start Test
|
|
||||||
///////////////////////
|
|
||||||
_vpm->EnableTemporalDecimation(true);
|
|
||||||
_vpm->EnableContentAnalysis(true);
|
|
||||||
_vpm->SetInputFrameResampleMode(kFastRescaling);
|
|
||||||
|
|
||||||
// disabling internal VCM frame dropper
|
|
||||||
_vcm->EnableFrameDropper(false);
|
|
||||||
|
|
||||||
I420VideoFrame sourceFrame;
|
|
||||||
I420VideoFrame *decimatedFrame = NULL;
|
|
||||||
uint8_t* tmpBuffer = new uint8_t[_lengthSourceFrame];
|
|
||||||
double startTime = clock()/(double)CLOCKS_PER_SEC;
|
|
||||||
_vcm->SetChannelParameters(static_cast<uint32_t>(1000 * _bitRate), 0, 0);
|
|
||||||
|
|
||||||
SendStatsTest sendStats;
|
|
||||||
sendStats.set_framerate(static_cast<uint32_t>(_frameRate));
|
|
||||||
sendStats.set_bitrate(1000 * _bitRate);
|
|
||||||
_vcm->RegisterSendStatisticsCallback(&sendStats);
|
|
||||||
|
|
||||||
VideoContentMetrics* contentMetrics = NULL;
|
|
||||||
// setting user frame rate
|
|
||||||
// for starters: keeping native values:
|
|
||||||
_vpm->SetTargetResolution(_width, _height,
|
|
||||||
(uint32_t)(_frameRate+ 0.5f));
|
|
||||||
_decodeCallback.SetOriginalFrameDimensions(_nativeWidth, _nativeHeight);
|
|
||||||
|
|
||||||
//tmp - disabling VPM frame dropping
|
|
||||||
_vpm->EnableTemporalDecimation(false);
|
|
||||||
|
|
||||||
int32_t 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(tmpBuffer,
|
|
||||||
tmpBuffer + size_y,
|
|
||||||
tmpBuffer + size_y + size_uv,
|
|
||||||
_nativeWidth, _nativeHeight,
|
|
||||||
_nativeWidth, (_nativeWidth + 1) / 2,
|
|
||||||
(_nativeWidth + 1) / 2);
|
|
||||||
|
|
||||||
_timeStamp +=
|
|
||||||
(uint32_t)(9e4 / static_cast<float>(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;
|
|
||||||
|
|
||||||
int32_t 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(static_cast<uint32_t>(1000 * _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 = (uint8_t) _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<SimulatedClock*>(_clock)->AdvanceTimeMilliseconds(
|
|
||||||
1000 / _nativeFrameRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (feof(_sourceFile) == 0);
|
|
||||||
_decodeCallback.WriteEnd(_frameCnt);
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
QMTestVideoSettingsCallback::SetVideoQMSettings(const uint32_t frameRate,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height)
|
|
||||||
{
|
|
||||||
int32_t 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 = (uint16_t)height;
|
|
||||||
currentCodec.width = (uint16_t)width;
|
|
||||||
currentCodec.maxFramerate = (uint8_t)frameRate;
|
|
||||||
|
|
||||||
// re-register encoder
|
|
||||||
retVal = _vcm->RegisterSendCodec(¤tCodec, 2, 1440);
|
|
||||||
_updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoded Frame Callback Implementation
|
|
||||||
VCMQMDecodeCompleteCallback::VCMQMDecodeCompleteCallback(
|
|
||||||
FILE* decodedFile, int frame_rate, std::string feature_table_name):
|
|
||||||
_decodedFile(decodedFile),
|
|
||||||
_decodedBytes(0),
|
|
||||||
//_test(test),
|
|
||||||
_origWidth(0),
|
|
||||||
_origHeight(0),
|
|
||||||
_decWidth(0),
|
|
||||||
_decHeight(0),
|
|
||||||
//_interpolator(NULL),
|
|
||||||
_decBuffer(NULL),
|
|
||||||
_frameCnt(0),
|
|
||||||
frame_rate_(frame_rate),
|
|
||||||
frames_cnt_since_drop_(0),
|
|
||||||
feature_table_name_(feature_table_name)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
VCMQMDecodeCompleteCallback::~VCMQMDecodeCompleteCallback()
|
|
||||||
{
|
|
||||||
// if (_interpolator != NULL)
|
|
||||||
// {
|
|
||||||
// deleteInterpolator(_interpolator);
|
|
||||||
// _interpolator = NULL;
|
|
||||||
// }
|
|
||||||
if (_decBuffer != NULL)
|
|
||||||
{
|
|
||||||
delete [] _decBuffer;
|
|
||||||
_decBuffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
VCMQMDecodeCompleteCallback::FrameToRender(I420VideoFrame& videoFrame)
|
|
||||||
{
|
|
||||||
++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<int>( 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;
|
|
||||||
}
|
|
||||||
_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.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_decodedBytes += CalcBufferSize(kI420, videoFrame.width(),
|
|
||||||
videoFrame.height());
|
|
||||||
videoFrame.SwapFrame(&last_frame_);
|
|
||||||
return VCM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t VCMQMDecodeCompleteCallback::DecodedBytes()
|
|
||||||
{
|
|
||||||
return _decodedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCMQMDecodeCompleteCallback::SetOriginalFrameDimensions(int32_t width,
|
|
||||||
int32_t height)
|
|
||||||
{
|
|
||||||
_origWidth = width;
|
|
||||||
_origHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t VCMQMDecodeCompleteCallback::buildInterpolator()
|
|
||||||
{
|
|
||||||
uint32_t decFrameLength = _origWidth*_origHeight*3 >> 1;
|
|
||||||
if (_decBuffer != NULL)
|
|
||||||
{
|
|
||||||
delete [] _decBuffer;
|
|
||||||
}
|
|
||||||
_decBuffer = new uint8_t[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 VCMQMDecodeCompleteCallback::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++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_QUALITY_MODSE_TEST_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_QUALITY_MODSE_TEST_H_
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/normal_test.h"
|
|
||||||
#include "webrtc/modules/video_processing/main/interface/video_processing.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/data_log.h"
|
|
||||||
|
|
||||||
int qualityModeTest(const CmdArgs& args);
|
|
||||||
|
|
||||||
class QualityModesTest : public NormalTest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QualityModesTest(webrtc::VideoCodingModule* vcm,
|
|
||||||
webrtc::Clock* clock);
|
|
||||||
virtual ~QualityModesTest();
|
|
||||||
int32_t Perform(const CmdArgs& args);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void Setup(const CmdArgs& args);
|
|
||||||
void Print();
|
|
||||||
void Teardown();
|
|
||||||
void SsimComp();
|
|
||||||
|
|
||||||
webrtc::VideoProcessingModule* _vpm;
|
|
||||||
|
|
||||||
int _width;
|
|
||||||
int _height;
|
|
||||||
float _frameRate;
|
|
||||||
int _nativeWidth;
|
|
||||||
int _nativeHeight;
|
|
||||||
float _nativeFrameRate;
|
|
||||||
|
|
||||||
uint32_t _numFramesDroppedVPM;
|
|
||||||
bool _flagSSIM;
|
|
||||||
std::string filename_testvideo_;
|
|
||||||
std::string fv_outfilename_;
|
|
||||||
|
|
||||||
std::string feature_table_name_;
|
|
||||||
|
|
||||||
}; // end of QualityModesTest class
|
|
||||||
|
|
||||||
class VCMQMDecodeCompleteCallback: public webrtc::VCMReceiveCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VCMQMDecodeCompleteCallback(
|
|
||||||
FILE* decodedFile,
|
|
||||||
int frame_rate,
|
|
||||||
std::string feature_table_name);
|
|
||||||
virtual ~VCMQMDecodeCompleteCallback();
|
|
||||||
void SetUserReceiveCallback(webrtc::VCMReceiveCallback* receiveCallback);
|
|
||||||
// will write decoded frame into file
|
|
||||||
int32_t FrameToRender(webrtc::I420VideoFrame& videoFrame);
|
|
||||||
size_t DecodedBytes();
|
|
||||||
void SetOriginalFrameDimensions(int32_t width, int32_t height);
|
|
||||||
int32_t buildInterpolator();
|
|
||||||
// Check if last frame is dropped, if so, repeat the last rendered frame.
|
|
||||||
void WriteEnd(int input_tot_frame_count);
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE* _decodedFile;
|
|
||||||
size_t _decodedBytes;
|
|
||||||
// QualityModesTest& _test;
|
|
||||||
int _origWidth;
|
|
||||||
int _origHeight;
|
|
||||||
int _decWidth;
|
|
||||||
int _decHeight;
|
|
||||||
// VideoInterpolator* _interpolator;
|
|
||||||
uint8_t* _decBuffer;
|
|
||||||
uint32_t _frameCnt; // debug
|
|
||||||
webrtc::I420VideoFrame last_frame_;
|
|
||||||
int frame_rate_;
|
|
||||||
int frames_cnt_since_drop_;
|
|
||||||
std::string feature_table_name_;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}; // end of VCMQMDecodeCompleteCallback class
|
|
||||||
|
|
||||||
class QMTestVideoSettingsCallback : public webrtc::VCMQMSettingsCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QMTestVideoSettingsCallback();
|
|
||||||
// update VPM with QM settings
|
|
||||||
int32_t SetVideoQMSettings(const uint32_t frameRate,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height);
|
|
||||||
// register VPM used by test
|
|
||||||
void RegisterVPM(webrtc::VideoProcessingModule* vpm);
|
|
||||||
void RegisterVCM(webrtc::VideoCodingModule* vcm);
|
|
||||||
bool Updated();
|
|
||||||
|
|
||||||
private:
|
|
||||||
webrtc::VideoProcessingModule* _vpm;
|
|
||||||
webrtc::VideoCodingModule* _vcm;
|
|
||||||
bool _updated;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_QUALITY_MODSE_TEST_H_
|
|
@ -39,15 +39,5 @@ class RtpDataCallback : public webrtc::NullRtpData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int RtpPlay(const CmdArgs& args);
|
int RtpPlay(const CmdArgs& args);
|
||||||
int RtpPlayMT(const CmdArgs& args);
|
|
||||||
int ReceiverTimingTests(CmdArgs& args);
|
|
||||||
int JitterBufferTest(CmdArgs& args);
|
|
||||||
int DecodeFromStorageTest(const CmdArgs& args);
|
|
||||||
|
|
||||||
// Thread functions:
|
|
||||||
bool ProcessingThread(void* obj);
|
|
||||||
bool RtpReaderThread(void* obj);
|
|
||||||
bool DecodeThread(void* obj);
|
|
||||||
bool NackThread(void* obj);
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_RECEIVER_TESTS_H_
|
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_RECEIVER_TESTS_H_
|
||||||
|
@ -1,479 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/main/test/test_callbacks.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
|
|
||||||
#include "webrtc/modules/utility/interface/rtp_dump.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/source/encoded_frame.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_macros.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/clock.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
/******************************
|
|
||||||
* VCMEncodeCompleteCallback
|
|
||||||
*****************************/
|
|
||||||
// Basic callback implementation
|
|
||||||
// passes the encoded frame directly to the encoder
|
|
||||||
// Packetization callback implementation
|
|
||||||
VCMEncodeCompleteCallback::VCMEncodeCompleteCallback(FILE* encodedFile):
|
|
||||||
_encodedFile(encodedFile),
|
|
||||||
_encodedBytes(0),
|
|
||||||
_VCMReceiver(NULL),
|
|
||||||
_seqNo(0),
|
|
||||||
_encodeComplete(false),
|
|
||||||
_width(0),
|
|
||||||
_height(0),
|
|
||||||
_codecType(kRtpVideoNone)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
VCMEncodeCompleteCallback::~VCMEncodeCompleteCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VCMEncodeCompleteCallback::RegisterTransportCallback(
|
|
||||||
VCMPacketizationCallback* transport) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
VCMEncodeCompleteCallback::SendData(
|
|
||||||
const uint8_t payloadType,
|
|
||||||
const EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const RTPVideoHeader* videoHdr)
|
|
||||||
{
|
|
||||||
// will call the VCMReceiver input packet
|
|
||||||
_frameType = VCMEncodedFrame::ConvertFrameType(encoded_image._frameType);
|
|
||||||
// writing encodedData into file
|
|
||||||
if (fwrite(encoded_image._buffer, 1, encoded_image._length, _encodedFile) !=
|
|
||||||
encoded_image._length) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
WebRtcRTPHeader rtpInfo;
|
|
||||||
rtpInfo.header.markerBit = true; // end of frame
|
|
||||||
rtpInfo.type.Video.isFirstPacket = true;
|
|
||||||
rtpInfo.type.Video.codec = _codecType;
|
|
||||||
rtpInfo.type.Video.height = (uint16_t)_height;
|
|
||||||
rtpInfo.type.Video.width = (uint16_t)_width;
|
|
||||||
switch (_codecType)
|
|
||||||
{
|
|
||||||
case webrtc::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 webrtc::kRtpVideoGeneric:
|
|
||||||
// Leave for now, until we add kRtpVideoVp9 to RTP.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpInfo.header.payloadType = payloadType;
|
|
||||||
rtpInfo.header.sequenceNumber = _seqNo++;
|
|
||||||
rtpInfo.header.ssrc = 0;
|
|
||||||
rtpInfo.header.timestamp = encoded_image._timeStamp;
|
|
||||||
rtpInfo.frameType = _frameType;
|
|
||||||
// Size should also be received from that table, since the payload type
|
|
||||||
// defines the size.
|
|
||||||
|
|
||||||
_encodedBytes += encoded_image._length;
|
|
||||||
// directly to receiver
|
|
||||||
int ret = _VCMReceiver->IncomingPacket(encoded_image._buffer,
|
|
||||||
encoded_image._length, rtpInfo);
|
|
||||||
_encodeComplete = true;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
VCMEncodeCompleteCallback::EncodedBytes()
|
|
||||||
{
|
|
||||||
return _encodedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
VCMEncodeCompleteCallback::EncodeComplete()
|
|
||||||
{
|
|
||||||
if (_encodeComplete)
|
|
||||||
{
|
|
||||||
_encodeComplete = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
VCMEncodeCompleteCallback::Initialize()
|
|
||||||
{
|
|
||||||
_encodeComplete = false;
|
|
||||||
_encodedBytes = 0;
|
|
||||||
_seqNo = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
VCMEncodeCompleteCallback::ResetByteCount()
|
|
||||||
{
|
|
||||||
_encodedBytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************/
|
|
||||||
/* VCMRTPEncodeCompleteCallback */
|
|
||||||
/***********************************/
|
|
||||||
// Encode Complete callback implementation
|
|
||||||
// passes the encoded frame via the RTP module to the decoder
|
|
||||||
// Packetization callback implementation
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
VCMRTPEncodeCompleteCallback::SendData(
|
|
||||||
uint8_t payloadType,
|
|
||||||
const EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const RTPVideoHeader* videoHdr)
|
|
||||||
{
|
|
||||||
_frameType = VCMEncodedFrame::ConvertFrameType(encoded_image._frameType);
|
|
||||||
_encodedBytes+= encoded_image._length;
|
|
||||||
_encodeComplete = true;
|
|
||||||
return _RTPModule->SendOutgoingData(_frameType,
|
|
||||||
payloadType,
|
|
||||||
encoded_image._timeStamp,
|
|
||||||
encoded_image.capture_time_ms_,
|
|
||||||
encoded_image._buffer,
|
|
||||||
encoded_image._length,
|
|
||||||
&fragmentationHeader,
|
|
||||||
videoHdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
VCMRTPEncodeCompleteCallback::EncodedBytes()
|
|
||||||
{
|
|
||||||
// only good for one call - after which will reset value;
|
|
||||||
size_t tmp = _encodedBytes;
|
|
||||||
_encodedBytes = 0;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
VCMRTPEncodeCompleteCallback::EncodeComplete()
|
|
||||||
{
|
|
||||||
if (_encodeComplete)
|
|
||||||
{
|
|
||||||
_encodeComplete = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoded Frame Callback Implementation
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
VCMDecodeCompleteCallback::FrameToRender(I420VideoFrame& videoFrame)
|
|
||||||
{
|
|
||||||
if (PrintI420VideoFrame(videoFrame, _decodedFile) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_decodedBytes += CalcBufferSize(kI420, videoFrame.width(),
|
|
||||||
videoFrame.height());
|
|
||||||
return VCM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
VCMDecodeCompleteCallback::DecodedBytes()
|
|
||||||
{
|
|
||||||
return _decodedBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
RTPSendCompleteCallback::RTPSendCompleteCallback(Clock* clock,
|
|
||||||
const char* filename):
|
|
||||||
_clock(clock),
|
|
||||||
_sendCount(0),
|
|
||||||
rtp_payload_registry_(NULL),
|
|
||||||
rtp_receiver_(NULL),
|
|
||||||
_rtp(NULL),
|
|
||||||
_lossPct(0),
|
|
||||||
_burstLength(0),
|
|
||||||
_networkDelayMs(0),
|
|
||||||
_jitterVar(0),
|
|
||||||
_prevLossState(0),
|
|
||||||
_totalSentLength(0),
|
|
||||||
_rtpPackets(),
|
|
||||||
_rtpDump(NULL)
|
|
||||||
{
|
|
||||||
if (filename != NULL)
|
|
||||||
{
|
|
||||||
_rtpDump = RtpDump::CreateRtpDump();
|
|
||||||
_rtpDump->Start(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RTPSendCompleteCallback::~RTPSendCompleteCallback()
|
|
||||||
{
|
|
||||||
if (_rtpDump != NULL)
|
|
||||||
{
|
|
||||||
_rtpDump->Stop();
|
|
||||||
RtpDump::DestroyRtpDump(_rtpDump);
|
|
||||||
}
|
|
||||||
// Delete remaining packets
|
|
||||||
while (!_rtpPackets.empty())
|
|
||||||
{
|
|
||||||
// Take first packet in list
|
|
||||||
delete _rtpPackets.front();
|
|
||||||
_rtpPackets.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
RTPSendCompleteCallback::SendPacket(int channel, const void *data, size_t len)
|
|
||||||
{
|
|
||||||
_sendCount++;
|
|
||||||
_totalSentLength += len;
|
|
||||||
|
|
||||||
if (_rtpDump != NULL)
|
|
||||||
{
|
|
||||||
if (_rtpDump->DumpPacket((const uint8_t*)data, len) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool transmitPacket = true;
|
|
||||||
transmitPacket = PacketLoss();
|
|
||||||
|
|
||||||
int64_t now = _clock->TimeInMilliseconds();
|
|
||||||
// Insert outgoing packet into list
|
|
||||||
if (transmitPacket)
|
|
||||||
{
|
|
||||||
RtpPacket* newPacket = new RtpPacket();
|
|
||||||
memcpy(newPacket->data, data, len);
|
|
||||||
newPacket->length = len;
|
|
||||||
// Simulate receive time = network delay + packet jitter
|
|
||||||
// simulated as a Normal distribution random variable with
|
|
||||||
// mean = networkDelay and variance = jitterVar
|
|
||||||
int32_t
|
|
||||||
simulatedDelay = (int32_t)NormalDist(_networkDelayMs,
|
|
||||||
sqrt(_jitterVar));
|
|
||||||
newPacket->receiveTime = now + simulatedDelay;
|
|
||||||
_rtpPackets.push_back(newPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Are we ready to send packets to the receiver?
|
|
||||||
RtpPacket* packet = NULL;
|
|
||||||
|
|
||||||
while (!_rtpPackets.empty())
|
|
||||||
{
|
|
||||||
// Take first packet in list
|
|
||||||
packet = _rtpPackets.front();
|
|
||||||
int64_t timeToReceive = packet->receiveTime - now;
|
|
||||||
if (timeToReceive > 0)
|
|
||||||
{
|
|
||||||
// No available packets to send
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_rtpPackets.pop_front();
|
|
||||||
assert(_rtp); // We must have a configured RTP module for this test.
|
|
||||||
// Send to receive side
|
|
||||||
RTPHeader header;
|
|
||||||
rtc::scoped_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
|
|
||||||
if (!parser->Parse(packet->data, packet->length, &header)) {
|
|
||||||
delete packet;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
PayloadUnion payload_specific;
|
|
||||||
if (!rtp_payload_registry_->GetPayloadSpecifics(
|
|
||||||
header.payloadType, &payload_specific)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!rtp_receiver_->IncomingRtpPacket(header, packet->data,
|
|
||||||
packet->length, payload_specific,
|
|
||||||
true))
|
|
||||||
{
|
|
||||||
delete packet;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
delete packet;
|
|
||||||
packet = NULL;
|
|
||||||
}
|
|
||||||
return static_cast<int>(len); // OK
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
RTPSendCompleteCallback::SendRTCPPacket(int channel,
|
|
||||||
const void *data,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
// Incorporate network conditions
|
|
||||||
return SendPacket(channel, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RTPSendCompleteCallback::SetLossPct(double lossPct)
|
|
||||||
{
|
|
||||||
_lossPct = lossPct;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
RTPSendCompleteCallback::SetBurstLength(double burstLength)
|
|
||||||
{
|
|
||||||
_burstLength = burstLength;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
RTPSendCompleteCallback::PacketLoss()
|
|
||||||
{
|
|
||||||
bool transmitPacket = true;
|
|
||||||
if (_burstLength <= 1.0)
|
|
||||||
{
|
|
||||||
// Random loss: if _burstLength parameter is not set, or <=1
|
|
||||||
if (UnifomLoss(_lossPct))
|
|
||||||
{
|
|
||||||
// drop
|
|
||||||
transmitPacket = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Simulate bursty channel (Gilbert model)
|
|
||||||
// (1st order) Markov chain model with memory of the previous/last
|
|
||||||
// packet state (loss or received)
|
|
||||||
|
|
||||||
// 0 = received state
|
|
||||||
// 1 = loss state
|
|
||||||
|
|
||||||
// probTrans10: if previous packet is lost, prob. to -> received state
|
|
||||||
// probTrans11: if previous packet is lost, prob. to -> loss state
|
|
||||||
|
|
||||||
// probTrans01: if previous packet is received, prob. to -> loss state
|
|
||||||
// probTrans00: if previous packet is received, prob. to -> received
|
|
||||||
|
|
||||||
// Map the two channel parameters (average loss rate and burst length)
|
|
||||||
// to the transition probabilities:
|
|
||||||
double probTrans10 = 100 * (1.0 / _burstLength);
|
|
||||||
double probTrans11 = (100.0 - probTrans10);
|
|
||||||
double probTrans01 = (probTrans10 * ( _lossPct / (100.0 - _lossPct)));
|
|
||||||
|
|
||||||
// Note: Random loss (Bernoulli) model is a special case where:
|
|
||||||
// burstLength = 100.0 / (100.0 - _lossPct) (i.e., p10 + p01 = 100)
|
|
||||||
|
|
||||||
if (_prevLossState == 0 )
|
|
||||||
{
|
|
||||||
// previous packet was received
|
|
||||||
if (UnifomLoss(probTrans01))
|
|
||||||
{
|
|
||||||
// drop, update previous state to loss
|
|
||||||
_prevLossState = 1;
|
|
||||||
transmitPacket = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_prevLossState == 1)
|
|
||||||
{
|
|
||||||
_prevLossState = 0;
|
|
||||||
// previous packet was lost
|
|
||||||
if (UnifomLoss(probTrans11))
|
|
||||||
{
|
|
||||||
// drop, update previous state to loss
|
|
||||||
_prevLossState = 1;
|
|
||||||
transmitPacket = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return transmitPacket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
RTPSendCompleteCallback::UnifomLoss(double lossPct)
|
|
||||||
{
|
|
||||||
double randVal = (rand() + 1.0) / (RAND_MAX + 1.0);
|
|
||||||
return randVal < lossPct/100;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
PacketRequester::ResendPackets(const uint16_t* sequenceNumbers,
|
|
||||||
uint16_t length)
|
|
||||||
{
|
|
||||||
return _rtp.SendNACK(sequenceNumbers, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
SendStatsTest::SendStatistics(const uint32_t bitRate,
|
|
||||||
const uint32_t frameRate)
|
|
||||||
{
|
|
||||||
TEST(frameRate <= _framerate);
|
|
||||||
TEST(bitRate > _bitrate / 2 && bitRate < 3 * _bitrate / 2);
|
|
||||||
printf("VCM 1 sec: Bit rate: %u\tFrame rate: %u\n", bitRate, frameRate);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t KeyFrameReqTest::RequestKeyFrame() {
|
|
||||||
printf("Key frame requested\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VideoProtectionCallback::VideoProtectionCallback():
|
|
||||||
delta_fec_params_(),
|
|
||||||
key_fec_params_()
|
|
||||||
{
|
|
||||||
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
|
|
||||||
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoProtectionCallback::~VideoProtectionCallback()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
VideoProtectionCallback::ProtectionRequest(
|
|
||||||
const FecProtectionParams* delta_fec_params,
|
|
||||||
const FecProtectionParams* key_fec_params,
|
|
||||||
uint32_t* sent_video_rate_bps,
|
|
||||||
uint32_t* sent_nack_rate_bps,
|
|
||||||
uint32_t* sent_fec_rate_bps)
|
|
||||||
{
|
|
||||||
key_fec_params_ = *key_fec_params;
|
|
||||||
delta_fec_params_ = *delta_fec_params;
|
|
||||||
|
|
||||||
// Update RTP
|
|
||||||
if (_rtp->SetFecParameters(&delta_fec_params_,
|
|
||||||
&key_fec_params_) != 0)
|
|
||||||
{
|
|
||||||
printf("Error in Setting FEC rate\n");
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
FecProtectionParams VideoProtectionCallback::DeltaFecParameters() const
|
|
||||||
{
|
|
||||||
return delta_fec_params_;
|
|
||||||
}
|
|
||||||
|
|
||||||
FecProtectionParams VideoProtectionCallback::KeyFecParameters() const
|
|
||||||
{
|
|
||||||
return key_fec_params_;
|
|
||||||
}
|
|
||||||
} // namespace webrtc
|
|
@ -1,254 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_VIDEO_CODING_TEST_TEST_CALLBACKS_H_
|
|
||||||
#define WEBRTC_MODULES_VIDEO_CODING_TEST_TEST_CALLBACKS_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Declaration of general callbacks that are used throughout VCM's offline tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "webrtc/modules/interface/module_common_types.h"
|
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
|
||||||
|
|
||||||
namespace webrtc
|
|
||||||
{
|
|
||||||
class RTPPayloadRegistry;
|
|
||||||
class RtpDump;
|
|
||||||
|
|
||||||
// Send Side - Packetization callback - send an encoded frame to the VCMReceiver
|
|
||||||
class VCMEncodeCompleteCallback: public VCMPacketizationCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Constructor input: file in which encoded data will be written
|
|
||||||
VCMEncodeCompleteCallback(FILE* encodedFile);
|
|
||||||
virtual ~VCMEncodeCompleteCallback();
|
|
||||||
// Register transport callback
|
|
||||||
void RegisterTransportCallback(VCMPacketizationCallback* transport);
|
|
||||||
// Process encoded data received from the encoder, pass stream to the
|
|
||||||
// VCMReceiver module
|
|
||||||
int32_t SendData(uint8_t payloadType,
|
|
||||||
const EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const RTPVideoHeader* videoHdr) override;
|
|
||||||
// Register exisitng VCM. Currently - encode and decode under same module.
|
|
||||||
void RegisterReceiverVCM(VideoCodingModule *vcm) {_VCMReceiver = vcm;}
|
|
||||||
// Return size of last encoded frame data (all frames in the sequence)
|
|
||||||
// Good for only one call - after which will reset value
|
|
||||||
// (to allow detection of frame drop)
|
|
||||||
size_t EncodedBytes();
|
|
||||||
// Return encode complete (true/false)
|
|
||||||
bool EncodeComplete();
|
|
||||||
// Inform callback of codec used
|
|
||||||
void SetCodecType(RtpVideoCodecTypes codecType)
|
|
||||||
{_codecType = codecType;}
|
|
||||||
// Inform callback of frame dimensions
|
|
||||||
void SetFrameDimensions(int32_t width, int32_t height)
|
|
||||||
{
|
|
||||||
_width = width;
|
|
||||||
_height = height;
|
|
||||||
}
|
|
||||||
// Initialize callback data
|
|
||||||
void Initialize();
|
|
||||||
void ResetByteCount();
|
|
||||||
|
|
||||||
// Conversion function for payload type (needed for the callback function)
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE* _encodedFile;
|
|
||||||
size_t _encodedBytes;
|
|
||||||
VideoCodingModule* _VCMReceiver;
|
|
||||||
FrameType _frameType;
|
|
||||||
uint16_t _seqNo;
|
|
||||||
bool _encodeComplete;
|
|
||||||
int32_t _width;
|
|
||||||
int32_t _height;
|
|
||||||
RtpVideoCodecTypes _codecType;
|
|
||||||
|
|
||||||
}; // end of VCMEncodeCompleteCallback
|
|
||||||
|
|
||||||
// Send Side - Packetization callback - packetize an encoded frame via the
|
|
||||||
// RTP module
|
|
||||||
class VCMRTPEncodeCompleteCallback: public VCMPacketizationCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VCMRTPEncodeCompleteCallback(RtpRtcp* rtp) :
|
|
||||||
_encodedBytes(0),
|
|
||||||
_encodeComplete(false),
|
|
||||||
_RTPModule(rtp) {}
|
|
||||||
|
|
||||||
virtual ~VCMRTPEncodeCompleteCallback() {}
|
|
||||||
// Process encoded data received from the encoder, pass stream to the
|
|
||||||
// RTP module
|
|
||||||
int32_t SendData(uint8_t payloadType,
|
|
||||||
const EncodedImage& encoded_image,
|
|
||||||
const RTPFragmentationHeader& fragmentationHeader,
|
|
||||||
const RTPVideoHeader* videoHdr) override;
|
|
||||||
// Return size of last encoded frame. Value good for one call
|
|
||||||
// (resets to zero after call to inform test of frame drop)
|
|
||||||
size_t EncodedBytes();
|
|
||||||
// Return encode complete (true/false)
|
|
||||||
bool EncodeComplete();
|
|
||||||
// Inform callback of codec used
|
|
||||||
void SetCodecType(RtpVideoCodecTypes codecType)
|
|
||||||
{_codecType = codecType;}
|
|
||||||
|
|
||||||
// Inform callback of frame dimensions
|
|
||||||
void SetFrameDimensions(int16_t width, int16_t height)
|
|
||||||
{
|
|
||||||
_width = width;
|
|
||||||
_height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t _encodedBytes;
|
|
||||||
FrameType _frameType;
|
|
||||||
bool _encodeComplete;
|
|
||||||
RtpRtcp* _RTPModule;
|
|
||||||
int16_t _width;
|
|
||||||
int16_t _height;
|
|
||||||
RtpVideoCodecTypes _codecType;
|
|
||||||
}; // end of VCMEncodeCompleteCallback
|
|
||||||
|
|
||||||
// Decode Complete callback
|
|
||||||
// Writes the decoded frames to a given file.
|
|
||||||
class VCMDecodeCompleteCallback: public VCMReceiveCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VCMDecodeCompleteCallback(FILE* decodedFile) :
|
|
||||||
_decodedFile(decodedFile), _decodedBytes(0) {}
|
|
||||||
virtual ~VCMDecodeCompleteCallback() {}
|
|
||||||
// Write decoded frame into file
|
|
||||||
int32_t FrameToRender(webrtc::I420VideoFrame& videoFrame) override;
|
|
||||||
size_t DecodedBytes();
|
|
||||||
private:
|
|
||||||
FILE* _decodedFile;
|
|
||||||
size_t _decodedBytes;
|
|
||||||
}; // end of VCMDecodeCompleCallback class
|
|
||||||
|
|
||||||
// Transport callback
|
|
||||||
// Called by the RTP Sender - simulates sending packets through a network to the
|
|
||||||
// RTP receiver. User can set network conditions as: RTT, packet loss,
|
|
||||||
// burst length and jitter.
|
|
||||||
class RTPSendCompleteCallback: public Transport
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Constructor input: (receive side) rtp module to send encoded data to
|
|
||||||
RTPSendCompleteCallback(Clock* clock,
|
|
||||||
const char* filename = NULL);
|
|
||||||
virtual ~RTPSendCompleteCallback();
|
|
||||||
|
|
||||||
void SetRtpModule(RtpRtcp* rtp_module) { _rtp = rtp_module; }
|
|
||||||
// Send Packet to receive side RTP module
|
|
||||||
int SendPacket(int channel, const void* data, size_t len) override;
|
|
||||||
// Send RTCP Packet to receive side RTP module
|
|
||||||
int SendRTCPPacket(int channel, const void* data, size_t len) override;
|
|
||||||
// Set percentage of channel loss in the network
|
|
||||||
void SetLossPct(double lossPct);
|
|
||||||
// Set average size of burst loss
|
|
||||||
void SetBurstLength(double burstLength);
|
|
||||||
// Set network delay in the network
|
|
||||||
void SetNetworkDelay(uint32_t networkDelayMs)
|
|
||||||
{_networkDelayMs = networkDelayMs;};
|
|
||||||
// Set Packet jitter delay
|
|
||||||
void SetJitterVar(uint32_t jitterVar)
|
|
||||||
{_jitterVar = jitterVar;};
|
|
||||||
// Return send count
|
|
||||||
int SendCount() {return _sendCount; }
|
|
||||||
// Return accumulated length in bytes of transmitted packets
|
|
||||||
size_t TotalSentLength() {return _totalSentLength;}
|
|
||||||
protected:
|
|
||||||
// Randomly decide whether to drop packets, based on the channel model
|
|
||||||
bool PacketLoss();
|
|
||||||
// Random uniform loss model
|
|
||||||
bool UnifomLoss(double lossPct);
|
|
||||||
|
|
||||||
Clock* _clock;
|
|
||||||
uint32_t _sendCount;
|
|
||||||
RTPPayloadRegistry* rtp_payload_registry_;
|
|
||||||
RtpReceiver* rtp_receiver_;
|
|
||||||
RtpRtcp* _rtp;
|
|
||||||
double _lossPct;
|
|
||||||
double _burstLength;
|
|
||||||
uint32_t _networkDelayMs;
|
|
||||||
double _jitterVar;
|
|
||||||
bool _prevLossState;
|
|
||||||
size_t _totalSentLength;
|
|
||||||
std::list<RtpPacket*> _rtpPackets;
|
|
||||||
RtpDump* _rtpDump;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Request re-transmission of packets (NACK)
|
|
||||||
class PacketRequester: public VCMPacketRequestCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PacketRequester(RtpRtcp& rtp) :
|
|
||||||
_rtp(rtp) {}
|
|
||||||
int32_t ResendPackets(const uint16_t* sequenceNumbers,
|
|
||||||
uint16_t length) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
webrtc::RtpRtcp& _rtp;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Key frame request
|
|
||||||
class KeyFrameReqTest: public VCMFrameTypeCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
int32_t RequestKeyFrame() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// VCM statistics
|
|
||||||
class SendStatsTest: public webrtc::VCMSendStatisticsCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SendStatsTest() : _framerate(15), _bitrate(500) {}
|
|
||||||
int32_t SendStatistics(const uint32_t bitRate,
|
|
||||||
const uint32_t frameRate) override;
|
|
||||||
void set_framerate(uint32_t frameRate) {_framerate = frameRate;}
|
|
||||||
void set_bitrate(uint32_t bitrate) {_bitrate = bitrate;}
|
|
||||||
private:
|
|
||||||
uint32_t _framerate;
|
|
||||||
uint32_t _bitrate;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Protection callback - allows the VCM (media optimization) to inform the RTP
|
|
||||||
// module of the required protection(FEC rates/settings and NACK mode).
|
|
||||||
class VideoProtectionCallback: public VCMProtectionCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VideoProtectionCallback();
|
|
||||||
virtual ~VideoProtectionCallback();
|
|
||||||
void RegisterRtpModule(RtpRtcp* rtp) {_rtp = rtp;}
|
|
||||||
int32_t ProtectionRequest(const FecProtectionParams* delta_fec_params,
|
|
||||||
const FecProtectionParams* key_fec_params,
|
|
||||||
uint32_t* sent_video_rate_bps,
|
|
||||||
uint32_t* sent_nack_rate_bps,
|
|
||||||
uint32_t* sent_fec_rate_bps) override;
|
|
||||||
FecProtectionParams DeltaFecParameters() const;
|
|
||||||
FecProtectionParams KeyFecParameters() const;
|
|
||||||
private:
|
|
||||||
RtpRtcp* _rtp;
|
|
||||||
FecProtectionParams delta_fec_params_;
|
|
||||||
FecProtectionParams key_fec_params_;
|
|
||||||
};
|
|
||||||
} // namespace webrtc
|
|
||||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef VCM_TEST_MACROS_H
|
|
||||||
#define VCM_TEST_MACROS_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
extern int vcmMacrosTests;
|
|
||||||
extern int vcmMacrosErrors;
|
|
||||||
|
|
||||||
#define PRINT_ERR_MSG(msg) \
|
|
||||||
do { \
|
|
||||||
fprintf(stderr, "Error at line %i of %s\n%s", \
|
|
||||||
__LINE__, __FILE__, msg); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define TEST(expr) \
|
|
||||||
do { \
|
|
||||||
vcmMacrosTests++; \
|
|
||||||
if (!(expr)) { \
|
|
||||||
PRINT_ERR_MSG("Assertion failed: " #expr "\n\n"); \
|
|
||||||
vcmMacrosErrors++; \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define TEST_EXIT_ON_FAIL(expr) \
|
|
||||||
do { \
|
|
||||||
vcmMacrosTests++; \
|
|
||||||
if (!(expr)) { \
|
|
||||||
PRINT_ERR_MSG("Assertion failed: " #expr "\nExiting...\n\n"); \
|
|
||||||
vcmMacrosErrors++; \
|
|
||||||
exit(EXIT_FAILURE); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#endif
|
|
@ -25,28 +25,10 @@ CmdArgs::CmdArgs()
|
|||||||
codecType(webrtc::kVideoCodecVP8),
|
codecType(webrtc::kVideoCodecVP8),
|
||||||
width(352),
|
width(352),
|
||||||
height(288),
|
height(288),
|
||||||
bitRate(500),
|
|
||||||
frameRate(30),
|
|
||||||
packetLoss(0),
|
|
||||||
rtt(0),
|
rtt(0),
|
||||||
protectionMode(0),
|
|
||||||
camaEnable(0),
|
|
||||||
inputFile(webrtc::test::ProjectRootPath() + "/resources/foreman_cif.yuv"),
|
inputFile(webrtc::test::ProjectRootPath() + "/resources/foreman_cif.yuv"),
|
||||||
outputFile(webrtc::test::OutputPath() +
|
outputFile(webrtc::test::OutputPath() +
|
||||||
"video_coding_test_output_352x288.yuv"),
|
"video_coding_test_output_352x288.yuv") {
|
||||||
fv_outputfile(webrtc::test::OutputPath() + "features.txt"),
|
|
||||||
testNum(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal Distribution
|
|
||||||
#define PI 3.14159265
|
|
||||||
double NormalDist(double mean, double stdDev)
|
|
||||||
{
|
|
||||||
// Creating a Normal distribution variable from two independent uniform
|
|
||||||
// variables based on the Box-Muller transform
|
|
||||||
double uniform1 = (rand() + 1.0) / (RAND_MAX + 1.0);
|
|
||||||
double uniform2 = (rand() + 1.0) / (RAND_MAX + 1.0);
|
|
||||||
return (mean + stdDev * sqrt(-2 * log(uniform1)) * cos(2 * PI * uniform2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -25,36 +25,6 @@
|
|||||||
enum { kMaxNackListSize = 250 };
|
enum { kMaxNackListSize = 250 };
|
||||||
enum { kMaxPacketAgeToNack = 450 };
|
enum { kMaxPacketAgeToNack = 450 };
|
||||||
|
|
||||||
// Class used for passing command line arguments to tests
|
|
||||||
class CmdArgs {
|
|
||||||
public:
|
|
||||||
CmdArgs();
|
|
||||||
|
|
||||||
std::string codecName;
|
|
||||||
webrtc::VideoCodecType codecType;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int bitRate;
|
|
||||||
int frameRate;
|
|
||||||
int packetLoss;
|
|
||||||
int rtt;
|
|
||||||
int protectionMode;
|
|
||||||
int camaEnable;
|
|
||||||
std::string inputFile;
|
|
||||||
std::string outputFile;
|
|
||||||
std::string fv_outputfile;
|
|
||||||
int testNum;
|
|
||||||
};
|
|
||||||
|
|
||||||
int MTRxTxTest(CmdArgs& args);
|
|
||||||
double NormalDist(double mean, double stdDev);
|
|
||||||
|
|
||||||
struct RtpPacket {
|
|
||||||
uint8_t data[1650]; // max packet size
|
|
||||||
size_t length;
|
|
||||||
int64_t receiveTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NullEvent : public webrtc::EventWrapper {
|
class NullEvent : public webrtc::EventWrapper {
|
||||||
public:
|
public:
|
||||||
virtual ~NullEvent() {}
|
virtual ~NullEvent() {}
|
||||||
@ -101,7 +71,17 @@ class FileOutputFrameReceiver : public webrtc::VCMReceiveCallback {
|
|||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FileOutputFrameReceiver);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(FileOutputFrameReceiver);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Codec type conversion
|
class CmdArgs {
|
||||||
webrtc::RtpVideoCodecTypes ConvertCodecType(const char* plname);
|
public:
|
||||||
|
CmdArgs();
|
||||||
|
|
||||||
|
std::string codecName;
|
||||||
|
webrtc::VideoCodecType codecType;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int rtt;
|
||||||
|
std::string inputFile;
|
||||||
|
std::string outputFile;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,32 +14,17 @@
|
|||||||
|
|
||||||
#include "gflags/gflags.h"
|
#include "gflags/gflags.h"
|
||||||
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
|
||||||
#include "webrtc/modules/video_coding/main/test/codec_database_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/generic_codec_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/media_opt_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/normal_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/quality_modes_test.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
|
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
|
||||||
#include "webrtc/modules/video_coding/main/test/test_util.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
#include "webrtc/test/testsupport/fileutils.h"
|
||||||
|
|
||||||
DEFINE_string(codec, "VP8", "Codec to use (VP8 or I420).");
|
DEFINE_string(codec, "VP8", "Codec to use (VP8 or I420).");
|
||||||
DEFINE_int32(width, 352, "Width in pixels of the frames in the input file.");
|
DEFINE_int32(width, 352, "Width in pixels of the frames in the input file.");
|
||||||
DEFINE_int32(height, 288, "Height in pixels of the frames in the input file.");
|
DEFINE_int32(height, 288, "Height in pixels of the frames in the input file.");
|
||||||
DEFINE_int32(bitrate, 500, "Bit rate in kilobits/second.");
|
|
||||||
DEFINE_int32(framerate, 30, "Frame rate of the input file, in FPS "
|
|
||||||
"(frames-per-second). ");
|
|
||||||
DEFINE_int32(packet_loss_percent, 0, "Packet loss probability, in percent.");
|
|
||||||
DEFINE_int32(rtt, 0, "RTT (round-trip time), in milliseconds.");
|
DEFINE_int32(rtt, 0, "RTT (round-trip time), in milliseconds.");
|
||||||
DEFINE_int32(protection_mode, 0, "Protection mode.");
|
|
||||||
DEFINE_int32(cama_enable, 0, "Cama enable.");
|
|
||||||
DEFINE_string(input_filename, webrtc::test::ProjectRootPath() +
|
DEFINE_string(input_filename, webrtc::test::ProjectRootPath() +
|
||||||
"/resources/foreman_cif.yuv", "Input file.");
|
"/resources/foreman_cif.yuv", "Input file.");
|
||||||
DEFINE_string(output_filename, webrtc::test::OutputPath() +
|
DEFINE_string(output_filename, webrtc::test::OutputPath() +
|
||||||
"video_coding_test_output_352x288.yuv", "Output file.");
|
"video_coding_test_output_352x288.yuv", "Output file.");
|
||||||
DEFINE_string(fv_output_filename, webrtc::test::OutputPath() +
|
|
||||||
"features.txt", "FV output file.");
|
|
||||||
DEFINE_int32(test_number, 0, "Test number.");
|
|
||||||
|
|
||||||
using namespace webrtc;
|
using namespace webrtc;
|
||||||
|
|
||||||
@ -54,10 +39,7 @@ int vcmMacrosErrors = 0;
|
|||||||
int ParseArguments(CmdArgs& args) {
|
int ParseArguments(CmdArgs& args) {
|
||||||
args.width = FLAGS_width;
|
args.width = FLAGS_width;
|
||||||
args.height = FLAGS_height;
|
args.height = FLAGS_height;
|
||||||
args.bitRate = FLAGS_bitrate;
|
if (args.width < 1 || args.height < 1) {
|
||||||
args.frameRate = FLAGS_framerate;
|
|
||||||
if (args.width < 1 || args.height < 1 || args.bitRate < 1 ||
|
|
||||||
args.frameRate < 1) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
args.codecName = FLAGS_codec;
|
args.codecName = FLAGS_codec;
|
||||||
@ -73,12 +55,7 @@ int ParseArguments(CmdArgs& args) {
|
|||||||
}
|
}
|
||||||
args.inputFile = FLAGS_input_filename;
|
args.inputFile = FLAGS_input_filename;
|
||||||
args.outputFile = FLAGS_output_filename;
|
args.outputFile = FLAGS_output_filename;
|
||||||
args.testNum = FLAGS_test_number;
|
|
||||||
args.packetLoss = FLAGS_packet_loss_percent;
|
|
||||||
args.rtt = FLAGS_rtt;
|
args.rtt = FLAGS_rtt;
|
||||||
args.protectionMode = FLAGS_protection_mode;
|
|
||||||
args.camaEnable = FLAGS_cama_enable;
|
|
||||||
args.fv_outputfile = FLAGS_fv_output_filename;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,40 +71,5 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("Running video coding tests...\n");
|
printf("Running video coding tests...\n");
|
||||||
int ret = 0;
|
return RtpPlay(args);
|
||||||
switch (args.testNum) {
|
|
||||||
case 0:
|
|
||||||
ret = NormalTest::RunTest(args);
|
|
||||||
ret |= CodecDataBaseTest::RunTest(args);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ret = NormalTest::RunTest(args);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ret = MTRxTxTest(args);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
ret = GenericCodecTest::RunTest(args);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
ret = CodecDataBaseTest::RunTest(args);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// 0- normal, 1-Release test(50 runs) 2- from file
|
|
||||||
ret = MediaOptTest::RunTest(0, args);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
ret = RtpPlay(args);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
ret = RtpPlayMT(args);
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
qualityModeTest(args);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <assert.h>
|
|
||||||
|
|
||||||
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
|
|
||||||
#include "webrtc/modules/video_coding/main/test/vcm_payload_sink_factory.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
|
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
|
|
||||||
using webrtc::rtpplayer::RtpPlayerInterface;
|
|
||||||
using webrtc::rtpplayer::VcmPayloadSinkFactory;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const bool kConfigProtectionEnabled = true;
|
|
||||||
const webrtc::VCMVideoProtection kConfigProtectionMethod =
|
|
||||||
webrtc::kProtectionNack;
|
|
||||||
const float kConfigLossRate = 0.05f;
|
|
||||||
const int64_t kConfigRttMs = 50;
|
|
||||||
const bool kConfigReordering = false;
|
|
||||||
const uint32_t kConfigRenderDelayMs = 0;
|
|
||||||
const uint32_t kConfigMinPlayoutDelayMs = 0;
|
|
||||||
const int64_t kConfigMaxRuntimeMs = 10000;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool PlayerThread(void* obj) {
|
|
||||||
assert(obj);
|
|
||||||
RtpPlayerInterface* rtp_player = static_cast<RtpPlayerInterface*>(obj);
|
|
||||||
|
|
||||||
rtc::scoped_ptr<webrtc::EventWrapper> wait_event(
|
|
||||||
webrtc::EventWrapper::Create());
|
|
||||||
if (wait_event.get() == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
webrtc::Clock* clock = webrtc::Clock::GetRealTimeClock();
|
|
||||||
if (rtp_player->NextPacket(clock->TimeInMilliseconds()) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
wait_event->Wait(rtp_player->TimeUntilNextPacket());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessingThread(void* obj) {
|
|
||||||
assert(obj);
|
|
||||||
return static_cast<VcmPayloadSinkFactory*>(obj)->ProcessAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodeThread(void* obj) {
|
|
||||||
assert(obj);
|
|
||||||
return static_cast<VcmPayloadSinkFactory*>(obj)->DecodeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
int RtpPlayMT(const CmdArgs& args) {
|
|
||||||
std::string trace_file = webrtc::test::OutputPath() + "receiverTestTrace.txt";
|
|
||||||
webrtc::Trace::CreateTrace();
|
|
||||||
webrtc::Trace::SetTraceFile(trace_file.c_str());
|
|
||||||
webrtc::Trace::set_level_filter(webrtc::kTraceAll);
|
|
||||||
|
|
||||||
webrtc::rtpplayer::PayloadTypes payload_types;
|
|
||||||
payload_types.push_back(webrtc::rtpplayer::PayloadCodecTuple(
|
|
||||||
VCM_VP8_PAYLOAD_TYPE, "VP8", webrtc::kVideoCodecVP8));
|
|
||||||
|
|
||||||
std::string output_file = args.outputFile;
|
|
||||||
if (output_file == "") {
|
|
||||||
output_file = webrtc::test::OutputPath() + "RtpPlayMT_decoded.yuv";
|
|
||||||
}
|
|
||||||
|
|
||||||
webrtc::Clock* clock = webrtc::Clock::GetRealTimeClock();
|
|
||||||
VcmPayloadSinkFactory factory(output_file, clock, kConfigProtectionEnabled,
|
|
||||||
kConfigProtectionMethod, kConfigRttMs, kConfigRenderDelayMs,
|
|
||||||
kConfigMinPlayoutDelayMs);
|
|
||||||
rtc::scoped_ptr<RtpPlayerInterface> rtp_player(webrtc::rtpplayer::Create(
|
|
||||||
args.inputFile, &factory, clock, payload_types, kConfigLossRate,
|
|
||||||
kConfigRttMs, kConfigReordering));
|
|
||||||
if (rtp_player.get() == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
rtc::scoped_ptr<webrtc::ThreadWrapper> player_thread(
|
|
||||||
webrtc::ThreadWrapper::CreateThread(PlayerThread, rtp_player.get(),
|
|
||||||
webrtc::kNormalPriority,
|
|
||||||
"PlayerThread"));
|
|
||||||
if (player_thread.get() == NULL) {
|
|
||||||
printf("Unable to start RTP reader thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::scoped_ptr<webrtc::ThreadWrapper> processing_thread(
|
|
||||||
webrtc::ThreadWrapper::CreateThread(ProcessingThread, &factory,
|
|
||||||
webrtc::kNormalPriority,
|
|
||||||
"ProcessingThread"));
|
|
||||||
if (processing_thread.get() == NULL) {
|
|
||||||
printf("Unable to start processing thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::scoped_ptr<webrtc::ThreadWrapper> decode_thread(
|
|
||||||
webrtc::ThreadWrapper::CreateThread(
|
|
||||||
DecodeThread, &factory, webrtc::kNormalPriority, "DecodeThread"));
|
|
||||||
if (decode_thread.get() == NULL) {
|
|
||||||
printf("Unable to start decode thread\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::scoped_ptr<webrtc::EventWrapper> wait_event(
|
|
||||||
webrtc::EventWrapper::Create());
|
|
||||||
if (wait_event.get() == NULL) {
|
|
||||||
printf("Unable to create wait event\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
player_thread->Start();
|
|
||||||
processing_thread->Start();
|
|
||||||
decode_thread->Start();
|
|
||||||
|
|
||||||
wait_event->Wait(kConfigMaxRuntimeMs);
|
|
||||||
|
|
||||||
while (!player_thread->Stop()) {
|
|
||||||
}
|
|
||||||
while (!processing_thread->Stop()) {
|
|
||||||
}
|
|
||||||
while (!decode_thread->Stop()) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rtp_player->Print();
|
|
||||||
|
|
||||||
webrtc::Trace::ReturnTrace();
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "webrtc/modules/video_coding/main/test/video_source.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "webrtc/test/testsupport/fileutils.h"
|
|
||||||
|
|
||||||
VideoSource::VideoSource()
|
|
||||||
:
|
|
||||||
_fileName(webrtc::test::ProjectRootPath() + "resources/foreman_cif.yuv"),
|
|
||||||
_width(352),
|
|
||||||
_height(288),
|
|
||||||
_type(webrtc::kI420),
|
|
||||||
_frameRate(30)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoSource::VideoSource(std::string fileName, VideoSize size,
|
|
||||||
float frameRate, webrtc::VideoType type /*= webrtc::kI420*/)
|
|
||||||
:
|
|
||||||
_fileName(fileName),
|
|
||||||
_width(0),
|
|
||||||
_height(0),
|
|
||||||
_type(type),
|
|
||||||
_frameRate(frameRate)
|
|
||||||
{
|
|
||||||
assert(size != kUndefined && size != kNumberOfVideoSizes);
|
|
||||||
assert(type != webrtc::kUnknown);
|
|
||||||
assert(frameRate > 0);
|
|
||||||
GetWidthHeight(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoSource::VideoSource(std::string fileName, uint16_t width, uint16_t height,
|
|
||||||
float frameRate /*= 30*/, webrtc::VideoType type /*= webrtc::kI420*/)
|
|
||||||
:
|
|
||||||
_fileName(fileName),
|
|
||||||
_width(width),
|
|
||||||
_height(height),
|
|
||||||
_type(type),
|
|
||||||
_frameRate(frameRate)
|
|
||||||
{
|
|
||||||
assert(width > 0);
|
|
||||||
assert(height > 0);
|
|
||||||
assert(type != webrtc::kUnknown);
|
|
||||||
assert(frameRate > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
VideoSource::GetFrameLength() const
|
|
||||||
{
|
|
||||||
return webrtc::CalcBufferSize(_type, _width, _height);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
|
||||||
VideoSource::GetName() const
|
|
||||||
{
|
|
||||||
// Remove path.
|
|
||||||
size_t slashPos = _fileName.find_last_of("/\\");
|
|
||||||
if (slashPos == std::string::npos)
|
|
||||||
{
|
|
||||||
slashPos = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
slashPos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove extension and underscored suffix if it exists.
|
|
||||||
//return _fileName.substr(slashPos, std::min(_fileName.find_last_of("_"),
|
|
||||||
// _fileName.find_last_of(".")) - slashPos);
|
|
||||||
// MS: Removing suffix, not underscore....keeping full file name
|
|
||||||
return _fileName.substr(slashPos, _fileName.find_last_of(".") - slashPos);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
VideoSource::GetWidthHeight( VideoSize size)
|
|
||||||
{
|
|
||||||
switch(size)
|
|
||||||
{
|
|
||||||
case kSQCIF:
|
|
||||||
_width = 128;
|
|
||||||
_height = 96;
|
|
||||||
return 0;
|
|
||||||
case kQQVGA:
|
|
||||||
_width = 160;
|
|
||||||
_height = 120;
|
|
||||||
return 0;
|
|
||||||
case kQCIF:
|
|
||||||
_width = 176;
|
|
||||||
_height = 144;
|
|
||||||
return 0;
|
|
||||||
case kCGA:
|
|
||||||
_width = 320;
|
|
||||||
_height = 200;
|
|
||||||
return 0;
|
|
||||||
case kQVGA:
|
|
||||||
_width = 320;
|
|
||||||
_height = 240;
|
|
||||||
return 0;
|
|
||||||
case kSIF:
|
|
||||||
_width = 352;
|
|
||||||
_height = 240;
|
|
||||||
return 0;
|
|
||||||
case kWQVGA:
|
|
||||||
_width = 400;
|
|
||||||
_height = 240;
|
|
||||||
return 0;
|
|
||||||
case kCIF:
|
|
||||||
_width = 352;
|
|
||||||
_height = 288;
|
|
||||||
return 0;
|
|
||||||
case kW288p:
|
|
||||||
_width = 512;
|
|
||||||
_height = 288;
|
|
||||||
return 0;
|
|
||||||
case k448p:
|
|
||||||
_width = 576;
|
|
||||||
_height = 448;
|
|
||||||
return 0;
|
|
||||||
case kVGA:
|
|
||||||
_width = 640;
|
|
||||||
_height = 480;
|
|
||||||
return 0;
|
|
||||||
case k432p:
|
|
||||||
_width = 720;
|
|
||||||
_height = 432;
|
|
||||||
return 0;
|
|
||||||
case kW432p:
|
|
||||||
_width = 768;
|
|
||||||
_height = 432;
|
|
||||||
return 0;
|
|
||||||
case k4SIF:
|
|
||||||
_width = 704;
|
|
||||||
_height = 480;
|
|
||||||
return 0;
|
|
||||||
case kW448p:
|
|
||||||
_width = 768;
|
|
||||||
_height = 448;
|
|
||||||
return 0;
|
|
||||||
case kNTSC:
|
|
||||||
_width = 720;
|
|
||||||
_height = 480;
|
|
||||||
return 0;
|
|
||||||
case kFW448p:
|
|
||||||
_width = 800;
|
|
||||||
_height = 448;
|
|
||||||
return 0;
|
|
||||||
case kWVGA:
|
|
||||||
_width = 800;
|
|
||||||
_height = 480;
|
|
||||||
return 0;
|
|
||||||
case k4CIF:
|
|
||||||
_width = 704;
|
|
||||||
_height = 576;
|
|
||||||
return 0;
|
|
||||||
case kSVGA:
|
|
||||||
_width = 800;
|
|
||||||
_height = 600;
|
|
||||||
return 0;
|
|
||||||
case kW544p:
|
|
||||||
_width = 960;
|
|
||||||
_height = 544;
|
|
||||||
return 0;
|
|
||||||
case kW576p:
|
|
||||||
_width = 1024;
|
|
||||||
_height = 576;
|
|
||||||
return 0;
|
|
||||||
case kHD:
|
|
||||||
_width = 960;
|
|
||||||
_height = 720;
|
|
||||||
return 0;
|
|
||||||
case kXGA:
|
|
||||||
_width = 1024;
|
|
||||||
_height = 768;
|
|
||||||
return 0;
|
|
||||||
case kFullHD:
|
|
||||||
_width = 1440;
|
|
||||||
_height = 1080;
|
|
||||||
return 0;
|
|
||||||
case kWHD:
|
|
||||||
_width = 1280;
|
|
||||||
_height = 720;
|
|
||||||
return 0;
|
|
||||||
case kWFullHD:
|
|
||||||
_width = 1920;
|
|
||||||
_height = 1080;
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,54 +8,27 @@
|
|||||||
{
|
{
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
{
|
||||||
'target_name': 'video_coding_test',
|
'target_name': 'rtp_player',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'rtp_rtcp',
|
'rtp_rtcp',
|
||||||
'video_processing',
|
|
||||||
'webrtc_video_coding',
|
'webrtc_video_coding',
|
||||||
'webrtc_utility',
|
|
||||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
|
||||||
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
|
||||||
'<(webrtc_root)/common.gyp:webrtc_common',
|
|
||||||
'<(webrtc_root)/test/test.gyp:test_support',
|
|
||||||
'<(webrtc_root)/test/metrics.gyp:metrics',
|
|
||||||
'<(webrtc_root)/common_video/common_video.gyp:common_video',
|
|
||||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers_default',
|
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers_default',
|
||||||
'<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common',
|
'<(webrtc_root)/test/webrtc_test_common.gyp:webrtc_test_common',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
# headers
|
# headers
|
||||||
'main/test/codec_database_test.h',
|
|
||||||
'main/test/generic_codec_test.h',
|
|
||||||
'main/test/media_opt_test.h',
|
|
||||||
'main/test/mt_test_common.h',
|
|
||||||
'main/test/normal_test.h',
|
|
||||||
'main/test/quality_modes_test.h',
|
|
||||||
'main/test/receiver_tests.h',
|
'main/test/receiver_tests.h',
|
||||||
'main/test/release_test.h',
|
|
||||||
'main/test/rtp_player.h',
|
'main/test/rtp_player.h',
|
||||||
'main/test/test_callbacks.h',
|
|
||||||
'main/test/test_util.h',
|
|
||||||
'main/test/vcm_payload_sink_factory.h',
|
'main/test/vcm_payload_sink_factory.h',
|
||||||
'main/test/video_source.h',
|
|
||||||
|
|
||||||
# sources
|
# sources
|
||||||
'main/test/codec_database_test.cc',
|
|
||||||
'main/test/generic_codec_test.cc',
|
|
||||||
'main/test/media_opt_test.cc',
|
|
||||||
'main/test/mt_rx_tx_test.cc',
|
|
||||||
'main/test/mt_test_common.cc',
|
|
||||||
'main/test/normal_test.cc',
|
|
||||||
'main/test/quality_modes_test.cc',
|
|
||||||
'main/test/rtp_player.cc',
|
'main/test/rtp_player.cc',
|
||||||
'main/test/test_callbacks.cc',
|
|
||||||
'main/test/test_util.cc',
|
'main/test/test_util.cc',
|
||||||
'main/test/tester_main.cc',
|
'main/test/tester_main.cc',
|
||||||
'main/test/vcm_payload_sink_factory.cc',
|
'main/test/vcm_payload_sink_factory.cc',
|
||||||
'main/test/video_rtp_play.cc',
|
'main/test/video_rtp_play.cc',
|
||||||
'main/test/video_rtp_play_mt.cc',
|
|
||||||
'main/test/video_source.cc',
|
|
||||||
], # sources
|
], # sources
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user