Move src/ -> webrtc/

TBR=niklas.enbom@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2963 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org
2012-10-22 18:19:23 +00:00
parent 24a419c0c7
commit 14b43beb7c
1888 changed files with 23 additions and 23 deletions

View File

@ -0,0 +1,409 @@
/*
* 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 "codec_database_test.h"
#include <assert.h>
#include <stdio.h>
#include "../../../../engine_configurations.h"
#include "../source/event.h"
#include "test_callbacks.h"
#include "test_macros.h"
#include "test_util.h"
#include "testsupport/fileutils.h"
#include "testsupport/metrics/video_metrics.h"
#include "vp8.h" // for external codecs test
using namespace webrtc;
int CodecDataBaseTest::RunTest(CmdArgs& args)
{
VideoCodingModule* vcm = VideoCodingModule::Create(1);
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;
}
WebRtc_Word32
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
VideoFrame sourceFrame;
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame];
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_timeStamp);
// Encoder registration
TEST (VideoCodingModule::NumberOfCodecs() > 0);
TEST(VideoCodingModule::Codec(-1, &sendCodec) < 0);
TEST(VideoCodingModule::Codec(VideoCodingModule::NumberOfCodecs() + 1,
&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(&currentSendCodec);
TEST(currentSendCodec.width == sendCodec.width &&
currentSendCodec.height == sendCodec.height);
sendCodec.width = 352/2;
sendCodec.height = 288/2;
_vcm->RegisterSendCodec(&sendCodec, 1, 1440);
_vcm->SendCodec(&currentSendCodec);
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 += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_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 += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_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 += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_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 += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_timeStamp);
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
TEST(_vcm->Decode() == VCM_OK);
TEST(_vcm->RegisterReceiveCodec(&sendCodec, 1) == VCM_OK);
waitEvent->Wait(33);
_timeStamp += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_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();
sourceFrame.Free();
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;
//double psnr;
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
_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);
for (j=0; j < int(300/VideoCodingModule::NumberOfCodecs()); j++)// assuming 300 frames, NumberOfCodecs <= 10
{
frameCnt++;
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
// building source frame
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
sourceFrame.SetLength(_lengthSourceFrame);
_timeStamp += (WebRtc_UWord32)(9e4 / _frameRate);
sourceFrame.SetTimeStamp(_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);
sourceFrame.Free();
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;
}

View File

@ -0,0 +1,51 @@
/*
* 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 "video_coding.h"
#include "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);
WebRtc_Word32 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;
WebRtc_UWord16 _width;
WebRtc_UWord16 _height;
WebRtc_UWord32 _lengthSourceFrame;
WebRtc_UWord32 _timeStamp;
float _frameRate;
}; // end of codecDBTest class definition
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_CODEC_DATABASE_TEST_H_

View File

@ -0,0 +1,177 @@
/*
* 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 "receiver_tests.h"
#include "video_coding.h"
#include "rtp_rtcp.h"
#include "trace.h"
#include "../source/event.h"
#include "rtp_player.h"
#include "modules/video_coding/main/source/mock/fake_tick_time.h"
using namespace webrtc;
class FrameStorageCallback : public VCMFrameStorageCallback
{
public:
FrameStorageCallback(VideoCodingModule* vcm) : _vcm(vcm) {}
WebRtc_Word32 StoreReceivedFrame(const EncodedVideoData& frameToStore)
{
_vcm->DecodeFromStorage(frameToStore);
return VCM_OK;
}
private:
VideoCodingModule* _vcm;
};
int DecodeFromStorageTest(CmdArgs& args)
{
// Make sure this test isn't executed without simulated events.
#if !defined(EVENT_DEBUG)
return -1;
#endif
// BEGIN Settings
bool protectionEnabled = false;
VCMVideoProtection protectionMethod = kProtectionNack;
WebRtc_UWord32 rttMS = 100;
float lossRate = 0.00f;
bool reordering = false;
WebRtc_UWord32 renderDelayMs = 0;
WebRtc_UWord32 minPlayoutDelayMs = 0;
const WebRtc_Word64 MAX_RUNTIME_MS = -1;
std::string rtpFilename = args.inputFile;
std::string outFilename = args.outputFile;
if (outFilename == "")
outFilename = test::OutputPath() + "DecodeFromStorage.yuv";
FrameReceiveCallback receiveCallback(outFilename.c_str());
// END Settings
Trace::CreateTrace();
Trace::SetTraceFile(
(test::OutputPath() + "decodeFromStorageTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
FakeTickTime clock(0);
// TODO(hlundin): This test was not verified after changing to FakeTickTime.
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
VideoCodingModule* vcmPlayback = VideoCodingModule::Create(2, &clock);
FrameStorageCallback storageCallback(vcmPlayback);
RtpDataCallback dataCallback(vcm);
WebRtc_Word32 ret = vcm->InitializeReceiver();
if (ret < 0)
{
return -1;
}
ret = vcmPlayback->InitializeReceiver();
if (ret < 0)
{
return -1;
}
vcm->RegisterFrameStorageCallback(&storageCallback);
vcmPlayback->RegisterReceiveCallback(&receiveCallback);
RTPPlayer rtpStream(rtpFilename.c_str(), &dataCallback, &clock);
PayloadTypeList payloadTypes;
payloadTypes.push_front(new PayloadCodecTuple(VCM_VP8_PAYLOAD_TYPE, "VP8",
kVideoCodecVP8));
// Register receive codecs in VCM
for (PayloadTypeList::iterator it = payloadTypes.begin();
it != payloadTypes.end(); ++it) {
PayloadCodecTuple* payloadType = *it;
if (payloadType != NULL)
{
VideoCodec codec;
memset(&codec, 0, sizeof(codec));
strncpy(codec.plName, payloadType->name.c_str(), payloadType->name.length());
codec.plName[payloadType->name.length()] = '\0';
codec.plType = payloadType->payloadType;
codec.codecType = payloadType->codecType;
if (vcm->RegisterReceiveCodec(&codec, 1) < 0)
{
return -1;
}
if (vcmPlayback->RegisterReceiveCodec(&codec, 1) < 0)
{
return -1;
}
}
}
if (rtpStream.Initialize(&payloadTypes) < 0)
{
return -1;
}
bool nackEnabled = protectionEnabled && (protectionMethod == kProtectionNack ||
protectionMethod == kProtectionDualDecoder);
rtpStream.SimulatePacketLoss(lossRate, nackEnabled, rttMS);
rtpStream.SetReordering(reordering);
vcm->SetChannelParameters(0, 0, rttMS);
vcm->SetVideoProtection(protectionMethod, protectionEnabled);
vcm->SetRenderDelay(renderDelayMs);
vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
ret = 0;
// RTP stream main loop
while ((ret = rtpStream.NextPacket(clock.MillisecondTimestamp())) == 0)
{
if (clock.MillisecondTimestamp() % 5 == 0)
{
ret = vcm->Decode();
if (ret < 0)
{
return -1;
}
}
if (vcm->TimeUntilNextProcess() <= 0)
{
vcm->Process();
}
if (MAX_RUNTIME_MS > -1 && clock.MillisecondTimestamp() >= MAX_RUNTIME_MS)
{
break;
}
clock.IncrementDebugClock(1);
}
switch (ret)
{
case 1:
printf("Success\n");
break;
case -1:
printf("Failed\n");
break;
case 0:
printf("Timeout\n");
break;
}
rtpStream.Print();
// Tear down
while (!payloadTypes.empty())
{
delete payloadTypes.front();
payloadTypes.pop_front();
}
VideoCodingModule::Destroy(vcm);
vcm = NULL;
VideoCodingModule::Destroy(vcmPlayback);
vcmPlayback = NULL;
Trace::ReturnTrace();
return 0;
}

View File

@ -0,0 +1,592 @@
/*
* 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 "generic_codec_test.h"
#include <cmath>
#include <stdio.h>
#include "../source/event.h"
#include "rtp_rtcp.h"
#include "module_common_types.h"
#include "test_macros.h"
#include "modules/video_coding/main/source/mock/fake_tick_time.h"
using namespace webrtc;
enum { kMaxWaitEncTimeMs = 100 };
int GenericCodecTest::RunTest(CmdArgs& args)
{
#if !defined(EVENT_DEBUG)
printf("\n\nEnable debug events to run this test!\n\n");
return -1;
#endif
FakeTickTime clock(0);
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
GenericCodecTest* get = new GenericCodecTest(vcm, &clock);
Trace::CreateTrace();
Trace::SetTraceFile(
(test::OutputPath() + "genericCodecTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
get->Perform(args);
Trace::ReturnTrace();
delete get;
VideoCodingModule::Destroy(vcm);
return 0;
}
GenericCodecTest::GenericCodecTest(VideoCodingModule* vcm, FakeTickTime* 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;
}
WebRtc_Word32
GenericCodecTest::Perform(CmdArgs& args)
{
WebRtc_Word32 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();
WebRtc_Word32 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
VideoFrame sourceFrame;
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
_vcm->InitializeSender();
TEST(_vcm->Codec(kVideoCodecVP8, &sendCodec) == 0);
TEST(_vcm->RegisterSendCodec(&sendCodec, -1, 1440) < 0); // bad number of cores
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);
sendCodec.startBitrate = -2;
TEST(_vcm->RegisterSendCodec(&sendCodec, 1, 1440) < 0); // bad bit rate
_vcm->Codec(kVideoCodecVP8, &sendCodec);
_vcm->InitializeSender();
TEST(_vcm->SetChannelParameters(100, 0, 0) < 0);// setting rate when encoder uninitialized
// 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);
}
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame];
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
// building source frame
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
sourceFrame.SetTimeStamp(_timeStamp++);
// encode/decode
TEST(_vcm->AddVideoFrame(sourceFrame) < 0 ); // encoder uninitialized
_vcm->InitializeReceiver();
TEST(_vcm->SetChannelParameters(100, 0, 0) < 0);// setting rtt when receiver uninitialized
/**************************************/
/* encoder/decoder individuality test */
/**************************************/
//Register both encoder and decoder, reset decoder - encode, set up decoder, reset encoder - decode.
rewind(_sourceFile);
sourceFrame.Free();
_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 = (WebRtc_UWord8)(_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.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_timeStamp);
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
IncrementDebugClock(_frameRate);
_vcm->Process();
}
sendCodec.maxFramerate = (WebRtc_UWord8)_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 += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_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.Free();
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
const float bitRate[] = {100, 400, 600, 1000, 2000};
const float nBitrates = sizeof(bitRate)/sizeof(*bitRate);
float _bitRate = 0;
int _frameCnt = 0;
float totalBytesOneSec;//, totalBytesTenSec;
float totalBytes, 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((WebRtc_UWord32)_bitRate, 0, 20);
_frameCnt = 0;
totalBytes = 0;
_encodeCompleteCallback->Initialize();
sendStats.SetTargetFrameRate(static_cast<WebRtc_UWord32>(_frameRate));
_vcm->RegisterSendStatisticsCallback(&sendStats);
while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
_lengthSourceFrame)
{
_frameCnt++;
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_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.
//totalBytes = WaitForEncodedFrame();
//currentTime = VCMTickTime::MillisecondTimestamp();//clock()/(double)CLOCKS_PER_SEC;
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();
sourceFrame.Free();
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
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.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_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 DISABLED FOR NOW SINCE VP8 DOESN'T HAVE THIS FEATURE
// sourceFrame.Free();
// sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
// NumberOfCodecs = _vcm->NumberOfCodecs();
// WebRtc_UWord32 targetPayloadSize = 500;
// rtpModule.SetMaxTransferUnit(targetPayloadSize);
// // going over all available codecs
// for (int k = 0; k < NumberOfCodecs; k++)
// {
// _vcm->Codec(k, &_sendCodec);
// if (strncmp(_sendCodec.plName, "VP8", 3) == 0)
// {
// // Only test with VP8
// continue;
// }
// rtpModule.RegisterSendPayload(_sendCodec.plName, _sendCodec.plType);
// // Make sure we only get one NAL unit per packet
// _vcm->InitializeSender();
// _vcm->RegisterSendCodec(&_sendCodec, 4, targetPayloadSize);
// sendCallback.SetMaxPayloadSize(targetPayloadSize);
// _vcm->RegisterTransportCallback(&encCompleteCallback);
// sendCallback.Reset();
// _frameCnt = 0;
// rewind(_sourceFile);
// while (!feof(_sourceFile))
// {
// fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile);
// _frameCnt++;
// sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
// sourceFrame.SetHeight(_height);
// sourceFrame.SetWidth(_width);
// _timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
// sourceFrame.SetTimeStamp(_timeStamp);
// ret = _vcm->AddVideoFrame(sourceFrame);
// } // first frame encoded
// printf ("\n Codec type = %s \n",_sendCodec.plName);
// printf(" Average payload size = %f bytes, target = %u bytes\n", sendCallback.AveragePayloadSize(), targetPayloadSize);
// } // end for all codecs
// 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<WebRtc_UWord8>(_frameRate / 2.0 + 0.5f);
_vcm->RegisterSendCodec(&_sendCodec, 4, 1440);
_vcm->SetChannelParameters(2000, 0, 0);
_vcm->RegisterTransportCallback(_encodeCompleteCallback);
// up to here
_vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 20);
_encodeCompleteCallback->Initialize();
sendStats.SetTargetFrameRate(static_cast<WebRtc_UWord32>(_frameRate));
_vcm->RegisterSendStatisticsCallback(&sendStats);
rewind(_sourceFile);
while (fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) ==
_lengthSourceFrame)
{
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_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");
}
}
float
GenericCodecTest::WaitForEncodedFrame() const
{
WebRtc_Word64 startTime = _clock->MillisecondTimestamp();
while (_clock->MillisecondTimestamp() - startTime < kMaxWaitEncTimeMs*10)
{
if (_encodeCompleteCallback->EncodeComplete())
{
return _encodeCompleteCallback->EncodedBytes();
}
}
return 0;
}
void
GenericCodecTest::IncrementDebugClock(float frameRate)
{
_clock->IncrementDebugClock(1000/frameRate);
}
int
RTPSendCallback_SizeTest::SendPacket(int channel, const void *data, int len)
{
_nPackets++;
_payloadSizeSum += len;
// Make sure no payloads (len - header size) are larger than maxPayloadSize
TEST(len > 0 && static_cast<WebRtc_UWord32>(len - 12) <= _maxPayloadSize);
return 0;
}
void
RTPSendCallback_SizeTest::SetMaxPayloadSize(WebRtc_UWord32 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;
}
WebRtc_Word32
VCMEncComplete_KeyReqTest::SendData(
const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
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(payloadData, payloadSize, rtpInfo);
}

View File

@ -0,0 +1,110 @@
/*
* 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 "video_coding.h"
#include <string.h>
#include <fstream>
#include "test_callbacks.h"
#include "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 FakeTickTime;
class GenericCodecTest
{
public:
GenericCodecTest(webrtc::VideoCodingModule* vcm,
webrtc::FakeTickTime* clock);
~GenericCodecTest();
static int RunTest(CmdArgs& args);
WebRtc_Word32 Perform(CmdArgs& args);
float WaitForEncodedFrame() const;
private:
void Setup(CmdArgs& args);
void Print();
WebRtc_Word32 TearDown();
void IncrementDebugClock(float frameRate);
webrtc::FakeTickTime* _clock;
webrtc::VideoCodingModule* _vcm;
webrtc::VideoCodec _sendCodec;
webrtc::VideoCodec _receiveCodec;
std::string _inname;
std::string _outname;
std::string _encodedName;
WebRtc_Word32 _sumEncBytes;
FILE* _sourceFile;
FILE* _decodedFile;
FILE* _encodedFile;
WebRtc_UWord16 _width;
WebRtc_UWord16 _height;
float _frameRate;
WebRtc_UWord32 _lengthSourceFrame;
WebRtc_UWord32 _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) {}
virtual int SendPacket(int channel, const void *data, int len);
virtual int SendRTCPPacket(int channel, const void *data, int len) {return 0;}
void SetMaxPayloadSize(WebRtc_UWord32 maxPayloadSize);
void Reset();
float AveragePayloadSize() const;
private:
WebRtc_UWord32 _maxPayloadSize;
WebRtc_UWord32 _payloadSizeSum;
WebRtc_UWord32 _nPackets;
};
class VCMEncComplete_KeyReqTest : public webrtc::VCMPacketizationCallback
{
public:
VCMEncComplete_KeyReqTest(webrtc::VideoCodingModule &vcm) : _vcm(vcm), _seqNo(0), _timeStamp(0) {}
WebRtc_Word32 SendData(
const webrtc::FrameType frameType,
const WebRtc_UWord8 payloadType,
WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const webrtc::RTPFragmentationHeader& fragmentationHeader,
const webrtc::RTPVideoHeader* videoHdr);
private:
webrtc::VideoCodingModule& _vcm;
WebRtc_UWord16 _seqNo;
WebRtc_UWord32 _timeStamp;
}; // end of VCMEncodeCompleteCallback
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_GENERIC_CODEC_TEST_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/*
* 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 <stdio.h>
#include <ctime>
#include "JitterEstimateTest.h"
using namespace webrtc;
JitterEstimateTest::JitterEstimateTest(unsigned int frameRate) :
_frameRate(frameRate),
_capacity(2000),
_rate(500),
_jitter(5, 0),
_keyFrameRate(1.0),
_deltaFrameSize(10000, 1e6),
_counter(0),
_lossrate(0.0)
{
// Assign to random value between 0 and max of unsigned int
_seed = static_cast<unsigned>(std::time(0));
std::srand(_seed);
_prevTimestamp = static_cast<unsigned int>((std::rand() + 1.0)/(RAND_MAX + 1.0)*(pow((float) 2, (long) sizeof(unsigned int)*8)-1));
_prevWallClock = VCMTickTime::MillisecondTimestamp();
}
FrameSample
JitterEstimateTest::GenerateFrameSample()
{
double increment = 1.0/_frameRate;
unsigned int frameSize = static_cast<unsigned int>(_deltaFrameSize.RandValue());
bool keyFrame = false;
bool resent = false;
_prevTimestamp += static_cast<unsigned int>(90000*increment + 0.5);
double deltaFrameRate = _frameRate - _keyFrameRate;
double ratio = deltaFrameRate/static_cast<double>(_keyFrameRate);
if (ratio < 1.0)
{
ratio = 1.0/ratio;
if (_counter >= ratio)
_counter = 0;
else
{
_counter++;
frameSize += static_cast<unsigned int>(3*_deltaFrameSize.GetAverage());
keyFrame = true;
}
}
else
{
if (_counter >= ratio)
{
frameSize += static_cast<unsigned int>(3*_deltaFrameSize.GetAverage());
_counter = 0;
keyFrame = true;
}
else
_counter++;
}
WebRtc_Word64 jitter = static_cast<WebRtc_Word64>(_jitter.RandValue() + 1.0/_capacity * frameSize + 0.5);
_prevWallClock += static_cast<WebRtc_Word64>(1000*increment + 0.5);
double rndValue = RandUniform();
resent = (rndValue < _lossrate);
//printf("rndValue = %f\n", rndValue);
return FrameSample(_prevTimestamp, _prevWallClock + jitter, frameSize, keyFrame, resent);
}
void
JitterEstimateTest::SetCapacity(unsigned int c)
{
_capacity = c;
}
void
JitterEstimateTest::SetRate(unsigned int r)
{
_rate = r;
}
void
JitterEstimateTest::SetJitter(double m, double v)
{
_jitter.SetParams(m, v);
}
void
JitterEstimateTest::SetFrameSizeStats(double m, double v)
{
_deltaFrameSize.SetParams(m, v);
}
void
JitterEstimateTest::SetKeyFrameRate(int rate)
{
_keyFrameRate = rate;
}
void
JitterEstimateTest::SetLossRate(double rate)
{
_lossrate = rate;
}

View File

@ -0,0 +1,105 @@
/*
* 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_JITTER_ESTIMATE_TEST_H_
#define WEBRTC_MODULES_VIDEO_CODING_TEST_JITTER_ESTIMATE_TEST_H_
#include "typedefs.h"
#include "jitter_buffer.h"
#include "jitter_estimator.h"
#include <cstdlib>
#include <cmath>
double const pi = 4*std::atan(1.0);
class GaussDist
{
public:
GaussDist(double m, double v): _mu(m), _sigma(sqrt(v)) {}
double RandValue() // returns a single normally distributed number
{
double r1 = (std::rand() + 1.0)/(RAND_MAX + 1.0); // gives equal distribution in (0, 1]
double r2 = (std::rand() + 1.0)/(RAND_MAX + 1.0);
return _mu + _sigma * std::sqrt(-2*std::log(r1))*std::cos(2*pi*r2);
}
double GetAverage()
{
return _mu;
}
double GetVariance()
{
return _sigma*_sigma;
}
void SetParams(double m, double v)
{
_mu = m;
_sigma = sqrt(v);
}
private:
double _mu, _sigma;
};
class JitterEstimateTestWrapper : public webrtc::VCMJitterEstimator
{
public:
JitterEstimateTestWrapper() : VCMJitterEstimator() {}
double GetTheta() { return _theta[0]; }
double GetVarNoise() { return _varNoise; }
};
class FrameSample
{
public:
FrameSample() {FrameSample(0, 0, 0, false, false);}
FrameSample(unsigned int ts, WebRtc_Word64 wallClk, unsigned int fs, bool _keyFrame, bool _resent):
timestamp90Khz(ts), wallClockMs(wallClk), frameSize(fs), keyFrame(_keyFrame), resent(_resent) {}
unsigned int timestamp90Khz;
WebRtc_Word64 wallClockMs;
unsigned int frameSize;
bool keyFrame;
bool resent;
};
class JitterEstimateTest
{
public:
JitterEstimateTest(unsigned int frameRate);
FrameSample GenerateFrameSample();
void SetCapacity(unsigned int c);
void SetRate(unsigned int r);
void SetJitter(double m, double v);
void SetFrameSizeStats(double m, double v);
void SetKeyFrameRate(int rate);
void SetLossRate(double rate);
private:
double RandUniform() { return (std::rand() + 1.0)/(RAND_MAX + 1.0); }
unsigned int _frameRate;
unsigned int _capacity;
unsigned int _rate;
GaussDist _jitter;
//GaussDist _noResend;
GaussDist _deltaFrameSize;
unsigned int _prevTimestamp;
WebRtc_Word64 _prevWallClock;
unsigned int _nextDelay;
double _keyFrameRate;
unsigned int _counter;
unsigned int _seed;
double _lossrate;
};
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_JITTER_ESTIMATE_TEST_H_

View File

@ -0,0 +1,542 @@
/*
* 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 "media_opt_test.h"
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#include "../source/event.h"
#include "test_macros.h"
#include "test_util.h" // send side callback
#include "testsupport/metrics/video_metrics.h"
#include "video_coding.h"
using namespace webrtc;
int MediaOptTest::RunTest(int testNum, CmdArgs& args)
{
Trace::CreateTrace();
Trace::SetTraceFile((test::OutputPath() + "mediaOptTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
TickTimeBase clock;
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
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, TickTimeBase* 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()
{
WebRtc_UWord32 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.incoming_data = _dataCallback;
configuration.outgoing_transport = _outgoingTransport;
_rtp = RtpRtcp::CreateRtpRtcp(configuration);
_outgoingTransport->SetRtpModule(_rtp);
// Registering codecs for the RTP module
// Register receive and send payload
VideoCodec videoCodec;
strncpy(videoCodec.plName, "VP8", 32);
videoCodec.plType = VCM_VP8_PAYLOAD_TYPE;
_rtp->RegisterReceivePayload(videoCodec);
_rtp->RegisterSendPayload(videoCodec);
strncpy(videoCodec.plName, "ULPFEC", 32);
videoCodec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
_rtp->RegisterReceivePayload(videoCodec);
_rtp->RegisterSendPayload(videoCodec);
strncpy(videoCodec.plName, "RED", 32);
videoCodec.plType = VCM_RED_PAYLOAD_TYPE;
_rtp->RegisterReceivePayload(videoCodec);
_rtp->RegisterSendPayload(videoCodec);
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();
WebRtc_Word32 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 = (WebRtc_UWord8)_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
WebRtc_Word32
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
VideoFrame sourceFrame;
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame];
_vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, (WebRtc_UWord8)_lossRate, _rttMS);
_vcm->RegisterReceiveCallback(&receiveCallback);
_frameCnt = 0;
_sumEncBytes = 0.0;
_numFramesDropped = 0;
while (feof(_sourceFile)== 0)
{
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0);
_frameCnt++;
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_frameRate));
sourceFrame.SetTimeStamp(_timeStamp);
TEST(_vcm->AddVideoFrame(sourceFrame) == VCM_OK);
// inform RTP Module of error resilience features
//_rtp->SetFECCodeRate(protectionCallback.FECKeyRate(),protectionCallback.FECDeltaRate());
//_rtp->SetNACKStatus(protectionCallback.NACKMethod());
WebRtc_Word32 ret = _vcm->Decode();
if (ret < 0 )
{
TEST(ret == 0);
printf ("Decode error in frame # %d",_frameCnt);
}
float encBytes = encodeCompleteCallback->EncodedBytes();
if (encBytes == 0)
{
_numFramesDropped += 1;
//printf("frame #%d dropped \n", _frameCnt );
}
else
{
// write frame to file
if (fwrite(sourceFrame.Buffer(), 1, sourceFrame.Length(),
_actualSourceFile) != sourceFrame.Length()) {
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);
}

View File

@ -0,0 +1,98 @@
/*
* 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 "receiver_tests.h" // receive side callbacks
#include "rtp_rtcp.h"
#include "test_callbacks.h"
#include "test_util.h"
#include "video_coding.h"
#include "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::TickTimeBase* clock);
~MediaOptTest();
static int RunTest(int testNum, CmdArgs& args);
// perform encode-decode of an entire sequence
WebRtc_Word32 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::RtpRtcp* _rtp;
webrtc::RTPSendCompleteCallback* _outgoingTransport;
RtpDataCallback* _dataCallback;
webrtc::TickTimeBase* _clock;
std::string _inname;
std::string _outname;
std::string _actualSourcename;
std::fstream _log;
FILE* _sourceFile;
FILE* _decodedFile;
FILE* _actualSourceFile;
FILE* _outputRes;
WebRtc_UWord16 _width;
WebRtc_UWord16 _height;
WebRtc_UWord32 _lengthSourceFrame;
WebRtc_UWord32 _timeStamp;
float _frameRate;
bool _nackEnabled;
bool _fecEnabled;
bool _nackFecEnabled;
WebRtc_UWord8 _rttMS;
float _bitRate;
double _lossRate;
WebRtc_UWord32 _renderDelayMs;
WebRtc_Word32 _frameCnt;
float _sumEncBytes;
WebRtc_Word32 _numFramesDropped;
std::string _codecName;
webrtc::VideoCodecType _sendCodecType;
WebRtc_Word32 _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_

View File

@ -0,0 +1,359 @@
/*
* 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 "../source/event.h"
#include "media_opt_test.h"
#include "mt_test_common.h"
#include "receiver_tests.h" // shared RTP state and receive side threads
#include "rtp_rtcp.h"
#include "test_macros.h"
#include "test_util.h" // send side callback
#include "thread_wrapper.h"
#include "video_coding.h"
using namespace webrtc;
bool
MainSenderThread(void* obj)
{
SendSharedState* state = static_cast<SendSharedState*>(obj);
EventWrapper& waitEvent = *EventWrapper::Create();
// preparing a frame for encoding
VideoFrame sourceFrame;
WebRtc_Word32 width = state->_args.width;
WebRtc_Word32 height = state->_args.height;
float frameRate = state->_args.frameRate;
WebRtc_Word32 lengthSourceFrame = 3*width*height/2;
sourceFrame.VerifyAndAllocate(lengthSourceFrame);
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[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++;
sourceFrame.CopyFrame(lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(height);
sourceFrame.SetWidth(width);
state->_timestamp += (WebRtc_UWord32)(9e4 / frameRate);
sourceFrame.SetTimeStamp(state->_timestamp);
WebRtc_Word32 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(1000,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;
WebRtc_UWord16 width = args.width;
WebRtc_UWord16 height = args.height;
float frameRate = args.frameRate;
float bitRate = args.bitRate;
WebRtc_Word32 numberOfCores = 1;
// error resilience/network
// Nack support is currently not implemented in this test.
bool nackEnabled = false;
bool fecEnabled = false;
WebRtc_UWord8 rttMS = 20;
float lossRate = 0.0*255; // no packet loss
WebRtc_UWord32 renderDelayMs = 0;
WebRtc_UWord32 minPlayoutDelayMs = 0;
/* TEST SET-UP */
// Set up trace
Trace::CreateTrace();
Trace::SetTraceFile((test::OutputPath() + "MTRxTxTestTrace.txt").c_str());
Trace::SetLevelFilter(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;
}
TickTimeBase clock;
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
RtpDataCallback dataCallback(vcm);
RTPSendCompleteCallback* outgoingTransport =
new RTPSendCompleteCallback(&clock, "dump.rtp");
RtpRtcp::Configuration configuration;
configuration.id = 1;
configuration.audio = false;
configuration.incoming_data = &dataCallback;
configuration.outgoing_transport = outgoingTransport;
RtpRtcp* rtp = RtpRtcp::CreateRtpRtcp(configuration);
// registering codecs for the RTP module
VideoCodec videoCodec;
strncpy(videoCodec.plName, "ULPFEC", 32);
videoCodec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
TEST(rtp->RegisterReceivePayload(videoCodec) == 0);
strncpy(videoCodec.plName, "RED", 32);
videoCodec.plType = VCM_RED_PAYLOAD_TYPE;
TEST(rtp->RegisterReceivePayload(videoCodec) == 0);
strncpy(videoCodec.plName, args.codecName.c_str(), 32);
videoCodec.plType = VCM_VP8_PAYLOAD_TYPE;
videoCodec.maxBitrate = 10000;
videoCodec.codecType = args.codecType;
TEST(rtp->RegisterReceivePayload(videoCodec) == 0);
TEST(rtp->RegisterSendPayload(videoCodec) == 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();
WebRtc_Word32 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 = (WebRtc_UWord8)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->SetNACKStatus(nackEnabled ? kNackRtcp : kNackOff);
vcm->SetChannelParameters((WebRtc_UWord32) bitRate,
(WebRtc_UWord8) 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)
{
unsigned int tid;
mainSenderThread->Start(tid);
}
else
{
printf("Unable to start main sender thread\n");
return -1;
}
if (intSenderThread != NULL)
{
unsigned int tid;
intSenderThread->Start(tid);
}
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)
{
unsigned int tid;
processingThread->Start(tid);
}
else
{
printf("Unable to start processing thread\n");
return -1;
}
if (decodeThread != NULL)
{
unsigned int tid;
decodeThread->Start(tid);
}
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;
}

View File

@ -0,0 +1,135 @@
/*
* 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 "mt_test_common.h"
#include <cmath>
#include "modules/video_coding/main/source/tick_time_base.h"
#include "rtp_dump.h"
namespace webrtc {
TransportCallback::TransportCallback(TickTimeBase* clock, const char* filename)
: RTPSendCompleteCallback(clock, filename) {
}
TransportCallback::~TransportCallback()
{
//
}
int
TransportCallback::SendPacket(int channel, const void *data, int len)
{
_sendCount++;
_totalSentLength += len;
if (_rtpDump != NULL)
{
if (_rtpDump->DumpPacket((const WebRtc_UWord8*)data, len) != 0)
{
return -1;
}
}
bool transmitPacket = true;
// Off-line tests, don't drop first Key frame (approx.)
if (_sendCount > 20)
{
transmitPacket = PacketLoss();
}
TickTimeBase clock;
int64_t now = clock.MillisecondTimestamp();
// 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
WebRtc_Word32
simulatedDelay = (WebRtc_Word32)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;
TickTimeBase clock;
int64_t now = clock.MillisecondTimestamp();
while (!_rtpPackets.empty())
{
// Take first packet in list
packet = _rtpPackets.front();
WebRtc_Word64 timeToReceive = packet->receiveTime - now;
if (timeToReceive > 0)
{
// No available packets to send
break;
}
_rtpPackets.pop_front();
// Send to receive side
if (_rtp->IncomingPacket((const WebRtc_UWord8*)packet->data,
packet->length) < 0)
{
delete packet;
packet = NULL;
// Will return an error after the first packet that goes wrong
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

View File

@ -0,0 +1,87 @@
/*
* 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 "rtp_rtcp.h"
#include "test_callbacks.h"
#include "test_util.h"
#include "video_coding.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;
WebRtc_Word32 _frameCnt;
WebRtc_Word32 _timestamp;
};
// MT implementation of the RTPSendCompleteCallback (Transport)
class TransportCallback:public RTPSendCompleteCallback
{
public:
// constructor input: (receive side) rtp module to send encoded data to
TransportCallback(TickTimeBase* 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, int len);
// 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_

View File

@ -0,0 +1,404 @@
/*
* 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 "normal_test.h"
#include <assert.h>
#include <iostream>
#include <sstream>
#include <time.h>
#include "../source/event.h"
#include "common_types.h"
#include "modules/video_coding/main/source/mock/fake_tick_time.h"
#include "test_callbacks.h"
#include "test_macros.h"
#include "test_util.h"
#include "trace.h"
#include "testsupport/metrics/video_metrics.h"
using namespace webrtc;
int NormalTest::RunTest(CmdArgs& args)
{
#if defined(EVENT_DEBUG)
printf("SIMULATION TIME\n");
FakeTickTime clock(0);
#else
printf("REAL-TIME\n");
TickTimeBase clock;
#endif
Trace::CreateTrace();
Trace::SetTraceFile(
(test::OutputPath() + "VCMNormalTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
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)
{
}
WebRtc_Word32
VCMNTEncodeCompleteCallback::SendData(
const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader& /*fragmentationHeader*/,
const webrtc::RTPVideoHeader* videoHdr)
{
// will call the VCMReceiver input packet
_frameType = frameType;
// writing encodedData into file
if (fwrite(payloadData, 1, payloadSize, _encodedFile) != payloadSize) {
return -1;
}
WebRtcRTPHeader rtpInfo;
rtpInfo.header.markerBit = true;
rtpInfo.type.Video.width = 0;
rtpInfo.type.Video.height = 0;
switch (_test.VideoType())
{
case kVideoCodecVP8:
rtpInfo.type.Video.codec = kRTPVideoVP8;
rtpInfo.type.Video.codecHeader.VP8.InitRTPVideoHeaderVP8();
rtpInfo.type.Video.codecHeader.VP8.nonReference =
videoHdr->codecHeader.VP8.nonReference;
rtpInfo.type.Video.codecHeader.VP8.pictureId =
videoHdr->codecHeader.VP8.pictureId;
break;
case kVideoCodecI420:
rtpInfo.type.Video.codec = kRTPVideoI420;
break;
default:
assert(false);
return -1;
}
rtpInfo.header.payloadType = payloadType;
rtpInfo.header.sequenceNumber = _seqNo++;
rtpInfo.header.ssrc = 0;
rtpInfo.header.timestamp = timeStamp;
rtpInfo.frameType = frameType;
rtpInfo.type.Video.isFirstPacket = true;
// Size should also be received from that table, since the payload type
// defines the size.
_encodedBytes += payloadSize;
if (payloadSize < 20)
{
_skipCnt++;
}
_VCMReceiver->IncomingPacket(payloadData, payloadSize, rtpInfo);
return 0;
}
void
VCMNTEncodeCompleteCallback::RegisterReceiverVCM(VideoCodingModule *vcm)
{
_VCMReceiver = vcm;
return;
}
WebRtc_Word32
VCMNTEncodeCompleteCallback::EncodedBytes()
{
return _encodedBytes;
}
WebRtc_UWord32
VCMNTEncodeCompleteCallback::SkipCnt()
{
return _skipCnt;
}
// Decoded Frame Callback Implementation
VCMNTDecodeCompleCallback::~VCMNTDecodeCompleCallback()
{
if (_decodedFile)
fclose(_decodedFile);
}
WebRtc_Word32
VCMNTDecodeCompleCallback::FrameToRender(webrtc::VideoFrame& 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 (fwrite(videoFrame.Buffer(), 1, videoFrame.Length(),
_decodedFile) != videoFrame.Length()) {
return -1;
}
_decodedBytes+= videoFrame.Length();
return VCM_OK;
}
WebRtc_Word32
VCMNTDecodeCompleCallback::DecodedBytes()
{
return _decodedBytes;
}
//VCM Normal Test Class implementation
NormalTest::NormalTest(VideoCodingModule* vcm, TickTimeBase* 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(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);
return;
}
WebRtc_Word32
NormalTest::Perform(CmdArgs& args)
{
Setup(args);
EventWrapper* waitEvent = EventWrapper::Create();
VideoCodec _sendCodec;//, _receiveCodec; // tmp - sendCodecd used as receive codec
_vcm->InitializeReceiver();
_vcm->InitializeSender();
TEST(VideoCodingModule::Codec(_videoType, &_sendCodec) == VCM_OK);
_sendCodec.startBitrate = (int)_bitRate; // should be later on changed via the API
_sendCodec.width = static_cast<WebRtc_UWord16>(_width);
_sendCodec.height = static_cast<WebRtc_UWord16>(_height);
_sendCodec.maxFramerate = _frameRate;
TEST(_vcm->RegisterSendCodec(&_sendCodec, 4, 1400) == VCM_OK);// will also set and init the desired codec
// register a decoder (same codec for decoder and encoder )
TEST(_vcm->RegisterReceiveCodec(&_sendCodec, 1) == VCM_OK);
/* Callback Settings */
VCMNTDecodeCompleCallback _decodeCallback(_outname);
_vcm->RegisterReceiveCallback(&_decodeCallback);
VCMNTEncodeCompleteCallback _encodeCompleteCallback(_encodedFile, *this);
_vcm->RegisterTransportCallback(&_encodeCompleteCallback);
// encode and decode with the same vcm
_encodeCompleteCallback.RegisterReceiverVCM(_vcm);
///////////////////////
/// Start Test
///////////////////////
VideoFrame sourceFrame;
sourceFrame.VerifyAndAllocate(_lengthSourceFrame);
WebRtc_UWord8* tmpBuffer = new WebRtc_UWord8[_lengthSourceFrame];
double startTime = clock()/(double)CLOCKS_PER_SEC;
_vcm->SetChannelParameters((WebRtc_UWord32)_bitRate, 0, 0);
SendStatsTest sendStats;
sendStats.SetTargetFrameRate(static_cast<WebRtc_UWord32>(_frameRate));
_vcm->RegisterSendStatisticsCallback(&sendStats);
while (feof(_sourceFile) == 0)
{
#if !defined(EVENT_DEBUG)
WebRtc_Word64 processStartTime = _clock->MillisecondTimestamp();
#endif
TEST(fread(tmpBuffer, 1, _lengthSourceFrame, _sourceFile) > 0 ||
feof(_sourceFile));
_frameCnt++;
sourceFrame.CopyFrame(_lengthSourceFrame, tmpBuffer);
sourceFrame.SetHeight(_height);
sourceFrame.SetWidth(_width);
_timeStamp += (WebRtc_UWord32)(9e4 / static_cast<float>(_sendCodec.maxFramerate));
sourceFrame.SetTimeStamp(_timeStamp);
_encodeTimes[int(sourceFrame.TimeStamp())] = clock()/(double)CLOCKS_PER_SEC;
WebRtc_Word32 ret = _vcm->AddVideoFrame(sourceFrame);
double encodeTime = clock()/(double)CLOCKS_PER_SEC - _encodeTimes[int(sourceFrame.TimeStamp())];
_totalEncodeTime += encodeTime;
if (ret < 0)
{
printf("Error in AddFrame: %d\n", ret);
//exit(1);
}
_decodeTimes[int(sourceFrame.TimeStamp())] = clock()/(double)CLOCKS_PER_SEC; // same timestamp value for encode and decode
ret = _vcm->Decode();
_totalDecodeTime += clock()/(double)CLOCKS_PER_SEC - _decodeTimes[int(sourceFrame.TimeStamp())];
if (ret < 0)
{
printf("Error in Decode: %d\n", ret);
//exit(1);
}
if (_vcm->TimeUntilNextProcess() <= 0)
{
_vcm->Process();
}
WebRtc_UWord32 framePeriod = static_cast<WebRtc_UWord32>(1000.0f/static_cast<float>(_sendCodec.maxFramerate) + 0.5f);
#if defined(EVENT_DEBUG)
static_cast<FakeTickTime*>(_clock)->IncrementDebugClock(framePeriod);
#else
WebRtc_Word64 timeSpent = _clock->MillisecondTimestamp() - processStartTime;
if (timeSpent < framePeriod)
{
waitEvent->Wait(framePeriod - timeSpent);
}
#endif
}
double endTime = clock()/(double)CLOCKS_PER_SEC;
_testTotalTime = endTime - startTime;
_sumEncBytes = _encodeCompleteCallback.EncodedBytes();
delete [] tmpBuffer;
delete waitEvent;
Teardown();
Print();
return 0;
}
void
NormalTest::FrameEncoded(WebRtc_UWord32 timeStamp)
{
_encodeCompleteTime = clock()/(double)CLOCKS_PER_SEC;
_encFrameCnt++;
_totalEncodePipeTime += _encodeCompleteTime - _encodeTimes[int(timeStamp)];
}
void
NormalTest::FrameDecoded(WebRtc_UWord32 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;
}

View File

@ -0,0 +1,143 @@
/*
* 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 "video_coding.h"
#include "test_util.h"
#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
WebRtc_Word32 SendData(const webrtc::FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const webrtc::RTPFragmentationHeader& fragmentationHeader,
const webrtc::RTPVideoHeader* videoHdr);
// Register exisitng VCM. Currently - encode and decode with the same vcm module.
void RegisterReceiverVCM(webrtc::VideoCodingModule *vcm);
// Return sum of encoded data (all frames in the sequence)
WebRtc_Word32 EncodedBytes();
// return number of encoder-skipped frames
WebRtc_UWord32 SkipCnt();;
// conversion function for payload type (needed for the callback function)
// RTPVideoVideoCodecTypes ConvertPayloadType(WebRtc_UWord8 payloadType);
private:
FILE* _encodedFile;
WebRtc_UWord32 _encodedBytes;
WebRtc_UWord32 _skipCnt;
webrtc::VideoCodingModule* _VCMReceiver;
webrtc::FrameType _frameType;
WebRtc_UWord16 _seqNo;
NormalTest& _test;
}; // end of VCMEncodeCompleteCallback
class VCMNTDecodeCompleCallback: public webrtc::VCMReceiveCallback
{
public:
VCMNTDecodeCompleCallback(std::string outname): // or should it get a name?
_decodedFile(NULL),
_outname(outname),
_decodedBytes(0),
_currentWidth(0),
_currentHeight(0) {}
virtual ~VCMNTDecodeCompleCallback();
void SetUserReceiveCallback(webrtc::VCMReceiveCallback* receiveCallback);
// will write decoded frame into file
WebRtc_Word32 FrameToRender(webrtc::VideoFrame& videoFrame);
WebRtc_Word32 DecodedBytes();
private:
FILE* _decodedFile;
std::string _outname;
WebRtc_UWord32 _decodedBytes;
WebRtc_UWord32 _currentWidth;
WebRtc_UWord32 _currentHeight;
}; // end of VCMDecodeCompleCallback class
class NormalTest
{
public:
NormalTest(webrtc::VideoCodingModule* vcm,
webrtc::TickTimeBase* clock);
~NormalTest();
static int RunTest(CmdArgs& args);
WebRtc_Word32 Perform(CmdArgs& args);
// option:: turn into private and call from perform
WebRtc_UWord32 Width() const { return _width; };
WebRtc_UWord32 Height() const { return _height; };
webrtc::VideoCodecType VideoType() const { return _videoType; };
protected:
// test setup - open files, general initializations
void Setup(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(WebRtc_UWord32 timeStamp);
// calculating pipeline delay, and decoding time
void FrameDecoded(WebRtc_UWord32 timeStamp);
webrtc::TickTimeBase* _clock;
webrtc::VideoCodingModule* _vcm;
webrtc::VideoCodec _sendCodec;
webrtc::VideoCodec _receiveCodec;
std::string _inname;
std::string _outname;
std::string _encodedName;
WebRtc_Word32 _sumEncBytes;
FILE* _sourceFile;
FILE* _decodedFile;
FILE* _encodedFile;
std::fstream _log;
WebRtc_UWord32 _width;
WebRtc_UWord32 _height;
float _frameRate;
float _bitRate;
WebRtc_UWord32 _lengthSourceFrame;
WebRtc_UWord32 _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;
WebRtc_Word32 _frameCnt;
WebRtc_Word32 _encFrameCnt;
WebRtc_Word32 _decFrameCnt;
}; // end of VCMNormalTestClass
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_NORMAL_TEST_H_

View File

@ -0,0 +1,52 @@
function plotJitterEstimate(filename)
[timestamps, framedata, slopes, randJitters, framestats, timetable, filtjitter, rtt, rttStatsVec] = jitterBufferTraceParser(filename);
x = 1:size(framestats, 1);
%figure(2);
subfigure(3, 2, 1);
hold on;
plot(x, slopes(x, 1).*(framestats(x, 1) - framestats(x, 2)) + 3*sqrt(randJitters(x,2)), 'b'); title('Estimate ms');
plot(x, filtjitter, 'r');
plot(x, slopes(x, 1).*(framestats(x, 1) - framestats(x, 2)), 'g');
subfigure(3, 2, 2);
%subplot(211);
plot(x, slopes(x, 1)); title('Line slope');
%subplot(212);
%plot(x, slopes(x, 2)); title('Line offset');
subfigure(3, 2, 3); hold on;
plot(x, framestats); plot(x, framedata(x, 1)); title('frame size and average frame size');
subfigure(3, 2, 4);
plot(x, framedata(x, 2)); title('Delay');
subfigure(3, 2, 5);
hold on;
plot(x, randJitters(x,1),'r');
plot(x, randJitters(x,2)); title('Random jitter');
subfigure(3, 2, 6);
delays = framedata(:,2);
dL = [0; framedata(2:end, 1) - framedata(1:end-1, 1)];
hold on;
plot(dL, delays, '.');
s = [min(dL) max(dL)];
plot(s, slopes(end, 1)*s + slopes(end, 2), 'g');
plot(s, slopes(end, 1)*s + slopes(end, 2) + 3*sqrt(randJitters(end,2)), 'r');
plot(s, slopes(end, 1)*s + slopes(end, 2) - 3*sqrt(randJitters(end,2)), 'r');
title('theta(1)*x+theta(2), (dT-dTS)/dL');
if sum(size(rttStatsVec)) > 0
figure; hold on;
rttNstdDevsDrift = 3.5;
rttNstdDevsJump = 2.5;
rttSamples = rttStatsVec(:, 1);
rttAvgs = rttStatsVec(:, 2);
rttStdDevs = sqrt(rttStatsVec(:, 3));
rttMax = rttStatsVec(:, 4);
plot(rttSamples, 'ko-');
plot(rttAvgs, 'g');
plot(rttAvgs + rttNstdDevsDrift*rttStdDevs, 'b--');
plot(rttAvgs + rttNstdDevsJump*rttStdDevs, 'b');
plot(rttAvgs - rttNstdDevsJump*rttStdDevs, 'b');
plot(rttMax, 'r');
%plot(driftRestarts*max(maxRtts), '.');
%plot(jumpRestarts*max(maxRtts), '.');
end

View File

@ -0,0 +1,213 @@
function [t, TS] = plotReceiveTrace(filename, flat)
fid=fopen(filename);
%DEBUG ; ( 8:32:33:375 | 0) VIDEO:1 ; 5260; First packet of frame 1869537938
%DEBUG ; ( 8:32:33:375 | 0) VIDEO CODING:1 ; 5260; Decoding timestamp 1869534934
%DEBUG ; ( 8:32:33:375 | 0) VIDEO:1 ; 5260; Render frame 1869534934 at 20772610
%DEBUG ; ( 8:32:33:375 | 0) VIDEO CODING:-1 ; 5260; Frame decoded: timeStamp=1870511259 decTime=0 maxDecTime=0, at 19965
%DEBUG ; ( 7:59:42:500 | 0) VIDEO:-1 ; 2500; Received complete frame timestamp 1870514263 frame type 1 frame size 7862 at time 19965, jitter estimate was 130
%DEBUG ; ( 8: 5:51:774 | 0) VIDEO:-1 ; 3968; ExtrapolateLocalTime(1870967878)=24971 ms
if nargin == 1
flat = 0;
end
line = fgetl(fid);
estimatedArrivalTime = [];
packetTime = [];
firstPacketTime = [];
decodeTime = [];
decodeCompleteTime = [];
renderTime = [];
completeTime = [];
while ischar(line)%line ~= -1
if length(line) == 0
line = fgetl(fid);
continue;
end
% Parse the trace line header
[tempres, count] = sscanf(line, 'DEBUG ; (%u:%u:%u:%u |%*lu)%13c:');
if count < 5
line = fgetl(fid);
continue;
end
hr=tempres(1);
mn=tempres(2);
sec=tempres(3);
ms=tempres(4);
timeInMs=hr*60*60*1000 + mn*60*1000 + sec*1000 + ms;
label = tempres(5:end);
I = find(label ~= 32);
label = label(I(1):end); % remove white spaces
if ~strncmp(char(label), 'VIDEO', 5) & ~strncmp(char(label), 'VIDEO CODING', 12)
line = fgetl(fid);
continue;
end
message = line(72:end);
% Parse message
[p, count] = sscanf(message, 'ExtrapolateLocalTime(%lu)=%lu ms');
if count == 2
estimatedArrivalTime = [estimatedArrivalTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'Packet seqNo %u of frame %lu at %lu');
if count == 3
packetTime = [packetTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'First packet of frame %lu at %lu');
if count == 2
firstPacketTime = [firstPacketTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'Decoding timestamp %lu at %lu');
if count == 2
decodeTime = [decodeTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'Render frame %lu at %lu. Render delay %lu, required delay %lu, max decode time %lu, min total delay %lu');
if count == 6
renderTime = [renderTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'Frame decoded: timeStamp=%lu decTime=%d maxDecTime=%lu, at %lu');
if count == 4
decodeCompleteTime = [decodeCompleteTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(message, 'Received complete frame timestamp %lu frame type %u frame size %*u at time %lu, jitter estimate was %lu');
if count == 4
completeTime = [completeTime; p'];
line = fgetl(fid);
continue;
end
line = fgetl(fid);
end
fclose(fid);
t = completeTime(:,3);
TS = completeTime(:,1);
figure;
subplot(211);
hold on;
slope = 0;
if sum(size(packetTime)) > 0
% Plot the time when each packet arrives
firstTimeStamp = packetTime(1,2);
x = (packetTime(:,2) - firstTimeStamp)/90;
if flat
slope = x;
end
firstTime = packetTime(1,3);
plot(x, packetTime(:,3) - firstTime - slope, 'b.');
else
% Plot the time when the first packet of a frame arrives
firstTimeStamp = firstPacketTime(1,1);
x = (firstPacketTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
firstTime = firstPacketTime(1,2);
plot(x, firstPacketTime(:,2) - firstTime - slope, 'b.');
end
% Plot the frame complete time
if prod(size(completeTime)) > 0
x = (completeTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, completeTime(:,3) - firstTime - slope, 'ks');
end
% Plot the time the decode starts
if prod(size(decodeTime)) > 0
x = (decodeTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, decodeTime(:,2) - firstTime - slope, 'r.');
end
% Plot the decode complete time
if prod(size(decodeCompleteTime)) > 0
x = (decodeCompleteTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, decodeCompleteTime(:,4) - firstTime - slope, 'g.');
end
if prod(size(renderTime)) > 0
% Plot the wanted render time in ms
x = (renderTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, renderTime(:,2) - firstTime - slope, 'c-');
% Plot the render time if there were no render delay or decoding delay.
x = (renderTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, renderTime(:,2) - firstTime - slope - renderTime(:, 3) - renderTime(:, 5), 'c--');
% Plot the render time if there were no render delay.
x = (renderTime(:,1) - firstTimeStamp)/90;
if flat
slope = x;
end
plot(x, renderTime(:,2) - firstTime - slope - renderTime(:, 3) - renderTime(:, 5), 'b-');
end
%plot(x, 90*x, 'r-');
xlabel('RTP timestamp (in ms)');
ylabel('Time (ms)');
legend('Packet arrives', 'Frame complete', 'Decode', 'Decode complete', 'Time to render', 'Only jitter', 'Must decode');
% subplot(312);
% hold on;
% completeTs = completeTime(:, 1);
% arrivalTs = estimatedArrivalTime(:, 1);
% [c, completeIdx, arrivalIdx] = intersect(completeTs, arrivalTs);
% %plot(completeTs(completeIdx), completeTime(completeIdx, 3) - estimatedArrivalTime(arrivalIdx, 2));
% timeUntilComplete = completeTime(completeIdx, 3) - estimatedArrivalTime(arrivalIdx, 2);
% devFromAvgCompleteTime = timeUntilComplete - mean(timeUntilComplete);
% plot(completeTs(completeIdx) - completeTs(completeIdx(1)), devFromAvgCompleteTime);
% plot(completeTime(:, 1) - completeTime(1, 1), completeTime(:, 4), 'r');
% plot(decodeCompleteTime(:, 1) - decodeCompleteTime(1, 1), decodeCompleteTime(:, 2), 'g');
% plot(decodeCompleteTime(:, 1) - decodeCompleteTime(1, 1), decodeCompleteTime(:, 3), 'k');
% xlabel('RTP timestamp');
% ylabel('Time (ms)');
% legend('Complete time - Estimated arrival time', 'Desired jitter buffer level', 'Actual decode time', 'Max decode time', 0);
if prod(size(renderTime)) > 0
subplot(212);
hold on;
firstTime = renderTime(1, 1);
targetDelay = max(renderTime(:, 3) + renderTime(:, 4) + renderTime(:, 5), renderTime(:, 6));
plot(renderTime(:, 1) - firstTime, renderTime(:, 3), 'r-');
plot(renderTime(:, 1) - firstTime, renderTime(:, 4), 'b-');
plot(renderTime(:, 1) - firstTime, renderTime(:, 5), 'g-');
plot(renderTime(:, 1) - firstTime, renderTime(:, 6), 'k-');
plot(renderTime(:, 1) - firstTime, targetDelay, 'c-');
xlabel('RTP timestamp');
ylabel('Time (ms)');
legend('Render delay', 'Jitter delay', 'Decode delay', 'Extra delay', 'Min total delay');
end

View File

@ -0,0 +1,62 @@
function plotTimingTest(filename)
fid=fopen(filename);
%DEBUG ; ( 9:53:33:859 | 0) VIDEO:-1 ; 7132; Stochastic test 1
%DEBUG ; ( 9:53:33:859 | 0) VIDEO CODING:-1 ; 7132; Frame decoded: timeStamp=3000 decTime=10 at 10012
%DEBUG ; ( 9:53:33:859 | 0) VIDEO:-1 ; 7132; timeStamp=3000 clock=10037 maxWaitTime=0
%DEBUG ; ( 9:53:33:859 | 0) VIDEO:-1 ; 7132; timeStampMs=33 renderTime=54
line = fgetl(fid);
decTime = [];
waitTime = [];
renderTime = [];
foundStart = 0;
testName = 'Stochastic test 1';
while ischar(line)
if length(line) == 0
line = fgetl(fid);
continue;
end
lineOrig = line;
line = line(72:end);
if ~foundStart
if strncmp(line, testName, length(testName))
foundStart = 1;
end
line = fgetl(fid);
continue;
end
[p, count] = sscanf(line, 'Frame decoded: timeStamp=%lu decTime=%d maxDecTime=%d, at %lu');
if count == 4
decTime = [decTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(line, 'timeStamp=%u clock=%u maxWaitTime=%u');
if count == 3
waitTime = [waitTime; p'];
line = fgetl(fid);
continue;
end
[p, count] = sscanf(line, 'timeStamp=%u renderTime=%u');
if count == 2
renderTime = [renderTime; p'];
line = fgetl(fid);
continue;
end
line = fgetl(fid);
end
fclose(fid);
% Compensate for wrap arounds and start counting from zero.
timeStamps = waitTime(:, 1);
tsDiff = diff(timeStamps);
wrapIdx = find(tsDiff < 0);
timeStamps(wrapIdx+1:end) = hex2dec('ffffffff') + timeStamps(wrapIdx+1:end);
timeStamps = timeStamps - timeStamps(1);
figure;
hold on;
plot(timeStamps, decTime(:, 2), 'r');
plot(timeStamps, waitTime(:, 3), 'g');
plot(timeStamps(2:end), diff(renderTime(:, 2)), 'b');
legend('Decode time', 'Max wait time', 'Render time diff');

View File

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

View File

@ -0,0 +1,95 @@
/*
* 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 "video_processing.h"
#include "normal_test.h"
#include "video_coding_defines.h"
int qualityModeTest();
class QualityModesTest : public NormalTest
{
public:
QualityModesTest(webrtc::VideoCodingModule* vcm,
webrtc::TickTimeBase* clock);
virtual ~QualityModesTest();
WebRtc_Word32 Perform();
private:
void Setup();
void Print();
void Teardown();
void SsimComp();
webrtc::VideoProcessingModule* _vpm;
WebRtc_UWord32 _width;
WebRtc_UWord32 _height;
float _frameRate;
WebRtc_UWord32 _nativeWidth;
WebRtc_UWord32 _nativeHeight;
float _nativeFrameRate;
WebRtc_UWord32 _numFramesDroppedVPM;
bool _flagSSIM;
}; // end of QualityModesTest class
class VCMQMDecodeCompleCallback: public webrtc::VCMReceiveCallback
{
public:
VCMQMDecodeCompleCallback(FILE* decodedFile);
virtual ~VCMQMDecodeCompleCallback();
void SetUserReceiveCallback(webrtc::VCMReceiveCallback* receiveCallback);
// will write decoded frame into file
WebRtc_Word32 FrameToRender(webrtc::VideoFrame& videoFrame);
WebRtc_Word32 DecodedBytes();
void SetOriginalFrameDimensions(WebRtc_Word32 width, WebRtc_Word32 height);
WebRtc_Word32 buildInterpolator();
private:
FILE* _decodedFile;
WebRtc_UWord32 _decodedBytes;
// QualityModesTest& _test;
WebRtc_UWord32 _origWidth;
WebRtc_UWord32 _origHeight;
WebRtc_UWord32 _decWidth;
WebRtc_UWord32 _decHeight;
// VideoInterpolator* _interpolator;
WebRtc_UWord8* _decBuffer;
WebRtc_UWord32 _frameCnt; // debug
}; // end of VCMQMDecodeCompleCallback class
class QMTestVideoSettingsCallback : public webrtc::VCMQMSettingsCallback
{
public:
QMTestVideoSettingsCallback();
// update VPM with QM settings
WebRtc_Word32 SetVideoQMSettings(const WebRtc_UWord32 frameRate,
const WebRtc_UWord32 width,
const WebRtc_UWord32 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_

View File

@ -0,0 +1,90 @@
/*
* 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_RECEIVER_TESTS_H_
#define WEBRTC_MODULES_VIDEO_CODING_TEST_RECEIVER_TESTS_H_
#include "video_coding.h"
#include "module_common_types.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "typedefs.h"
#include "rtp_player.h"
#include "test_util.h"
#include <string>
#include <stdio.h>
class RtpDataCallback : public webrtc::RtpData
{
public:
RtpDataCallback(webrtc::VideoCodingModule* vcm)
: _vcm(vcm) {};
virtual WebRtc_Word32 OnReceivedPayloadData(const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadSize,
const webrtc::WebRtcRTPHeader* rtpHeader);
private:
webrtc::VideoCodingModule* _vcm;
};
class FrameReceiveCallback : public webrtc::VCMReceiveCallback
{
public:
FrameReceiveCallback(std::string outFilename) :
_outFilename(outFilename),
_outFile(NULL),
_timingFile(NULL),
width_(0),
height_(0) {}
virtual ~FrameReceiveCallback();
WebRtc_Word32 FrameToRender(webrtc::VideoFrame& videoFrame);
private:
static void SplitFilename(std::string filename, std::string* basename,
std::string* ending);
static std::string AppendWidthAndHeight(std::string basename,
unsigned int width,
unsigned int height);
std::string _outFilename;
FILE* _outFile;
FILE* _timingFile;
unsigned int width_;
unsigned int height_;
};
class SharedState
{
public:
SharedState(webrtc::VideoCodingModule& vcm, RTPPlayer& rtpPlayer) :
_vcm(vcm),
_rtpPlayer(rtpPlayer) {}
webrtc::VideoCodingModule& _vcm;
RTPPlayer& _rtpPlayer;
};
int RtpPlay(CmdArgs& args);
int RtpPlayMT(CmdArgs& args,
int releaseTest = 0,
webrtc::VideoCodecType releaseTestVideoType = webrtc::kVideoCodecVP8);
int ReceiverTimingTests(CmdArgs& args);
int JitterBufferTest(CmdArgs& args);
int DecodeFromStorageTest(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_

View File

@ -0,0 +1,235 @@
/*
* 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 "receiver_tests.h"
#include "video_coding.h"
#include "trace.h"
#include "../source/event.h"
#include "../source/internal_defines.h"
#include "timing.h"
#include "test_macros.h"
#include "test_util.h"
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace webrtc;
float vcmFloatMax(float a, float b)
{
return a > b ? a : b;
}
float vcmFloatMin(float a, float b)
{
return a < b ? a : b;
}
double const pi = 4*std::atan(1.0);
class GaussDist
{
public:
static float RandValue(float m, float stdDev) // returns a single normally distributed number
{
float r1 = static_cast<float>((std::rand() + 1.0)/(RAND_MAX + 1.0)); // gives equal distribution in (0, 1]
float r2 = static_cast<float>((std::rand() + 1.0)/(RAND_MAX + 1.0));
return m + stdDev * static_cast<float>(std::sqrt(-2*std::log(r1))*std::cos(2*pi*r2));
}
};
int ReceiverTimingTests(CmdArgs& args)
{
// Make sure this test is never executed with simulated events.
#if defined(EVENT_DEBUG)
return -1;
#endif
// Set up trace
Trace::CreateTrace();
Trace::SetTraceFile((test::OutputPath() + "receiverTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
// A static random seed
srand(0);
TickTimeBase clock;
VCMTiming timing(&clock);
float clockInMs = 0.0;
WebRtc_UWord32 waitTime = 0;
WebRtc_UWord32 jitterDelayMs = 0;
WebRtc_UWord32 maxDecodeTimeMs = 0;
WebRtc_UWord32 timeStamp = 0;
timing.Reset(static_cast<WebRtc_Word64>(clockInMs + 0.5));
timing.UpdateCurrentDelay(timeStamp);
timing.Reset(static_cast<WebRtc_Word64>(clockInMs + 0.5));
timing.IncomingTimestamp(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5));
jitterDelayMs = 20;
timing.SetRequiredDelay(jitterDelayMs);
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
// First update initializes the render time. Since we have no decode delay
// we get waitTime = renderTime - now - renderDelay = jitter
TEST(waitTime == jitterDelayMs);
jitterDelayMs += VCMTiming::kDelayMaxChangeMsPerS + 10;
timeStamp += 90000;
clockInMs += 1000.0f;
timing.SetRequiredDelay(jitterDelayMs);
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
// Since we gradually increase the delay we only get
// 100 ms every second.
TEST(waitTime == jitterDelayMs - 10);
timeStamp += 90000;
clockInMs += 1000.0;
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
TEST(waitTime == jitterDelayMs);
// 300 incoming frames without jitter, verify that this gives the exact wait time
for (int i=0; i < 300; i++)
{
clockInMs += 1000.0f/30.0f;
timeStamp += 3000;
timing.IncomingTimestamp(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5));
}
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
TEST(waitTime == jitterDelayMs);
// Add decode time estimates
for (int i=0; i < 10; i++)
{
WebRtc_Word64 startTimeMs = static_cast<WebRtc_Word64>(clockInMs + 0.5);
clockInMs += 10.0f;
timing.StopDecodeTimer(timeStamp, startTimeMs, static_cast<WebRtc_Word64>(clockInMs + 0.5));
timeStamp += 3000;
clockInMs += 1000.0f/30.0f - 10.0f;
timing.IncomingTimestamp(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5));
}
maxDecodeTimeMs = 10;
timing.SetRequiredDelay(jitterDelayMs);
clockInMs += 1000.0f;
timeStamp += 90000;
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
TEST(waitTime == jitterDelayMs);
WebRtc_UWord32 totalDelay1 = timing.TargetVideoDelay();
WebRtc_UWord32 minTotalDelayMs = 200;
timing.SetMinimumTotalDelay(minTotalDelayMs);
clockInMs += 5000.0f;
timeStamp += 5*90000;
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
WebRtc_UWord32 totalDelay2 = timing.TargetVideoDelay();
// We should at least have minTotalDelayMs - decodeTime (10) - renderTime (10) to wait
TEST(waitTime == minTotalDelayMs - maxDecodeTimeMs - 10);
// The total video delay should not increase with the extra delay,
// the extra delay should be independent.
TEST(totalDelay1 == totalDelay2);
// Reset min total delay
timing.SetMinimumTotalDelay(0);
clockInMs += 5000.0f;
timeStamp += 5*90000;
timing.UpdateCurrentDelay(timeStamp);
// A sudden increase in timestamp of 2.1 seconds
clockInMs += 1000.0f/30.0f;
timeStamp += static_cast<WebRtc_UWord32>(2.1*90000 + 0.5);
WebRtc_Word64 ret = timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5));
TEST(ret == -1);
timing.Reset();
// This test produces a trace which can be parsed with plotTimingTest.m. The plot
// can be used to see that the timing is reasonable under noise, and that the
// gradual transition between delays works as expected.
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1, "Stochastic test 1");
jitterDelayMs = 60;
maxDecodeTimeMs = 10;
timeStamp = static_cast<WebRtc_UWord32>(-10000); // To produce a wrap
clockInMs = 10000.0f;
timing.Reset(static_cast<WebRtc_Word64>(clockInMs + 0.5));
float noise = 0.0f;
for (int i=0; i < 1400; i++)
{
if (i == 400)
{
jitterDelayMs = 30;
}
else if (i == 700)
{
jitterDelayMs = 100;
}
else if (i == 1000)
{
minTotalDelayMs = 200;
timing.SetMinimumTotalDelay(minTotalDelayMs);
}
else if (i == 1200)
{
minTotalDelayMs = 0;
timing.SetMinimumTotalDelay(minTotalDelayMs);
}
WebRtc_Word64 startTimeMs = static_cast<WebRtc_Word64>(clockInMs + 0.5);
noise = vcmFloatMin(vcmFloatMax(GaussDist::RandValue(0, 2), -10.0f), 30.0f);
clockInMs += 10.0f;
timing.StopDecodeTimer(timeStamp, startTimeMs, static_cast<WebRtc_Word64>(clockInMs + noise + 0.5));
timeStamp += 3000;
clockInMs += 1000.0f/30.0f - 10.0f;
noise = vcmFloatMin(vcmFloatMax(GaussDist::RandValue(0, 8), -15.0f), 15.0f);
timing.IncomingTimestamp(timeStamp, static_cast<WebRtc_Word64>(clockInMs + noise + 0.5));
timing.SetRequiredDelay(jitterDelayMs);
timing.UpdateCurrentDelay(timeStamp);
waitTime = timing.MaxWaitingTime(timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5)),
static_cast<WebRtc_Word64>(clockInMs + 0.5));
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1, "timeStamp=%u clock=%u maxWaitTime=%u", timeStamp,
static_cast<WebRtc_UWord32>(clockInMs + 0.5), waitTime);
WebRtc_Word64 renderTimeMs = timing.RenderTimeMs(timeStamp, static_cast<WebRtc_Word64>(clockInMs + 0.5));
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
"timeStamp=%u renderTime=%u",
timeStamp,
MaskWord64ToUWord32(renderTimeMs));
}
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1, "End Stochastic test 1");
printf("\nVCM Timing Test: \n\n%i tests completed\n", vcmMacrosTests);
if (vcmMacrosErrors > 0)
{
printf("%i FAILED\n\n", vcmMacrosErrors);
}
else
{
printf("ALL PASSED\n\n");
}
Trace::ReturnTrace();
return 0;
}

View File

@ -0,0 +1,46 @@
/*
* 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 "ReleaseTest.h"
#include "ReceiverTests.h"
#include "TestMacros.h"
#include "MediaOptTest.h"
#include "CodecDataBaseTest.h"
#include "GenericCodecTest.h"
int ReleaseTest()
{
printf("VCM RELEASE TESTS \n\n");
// Automatic tests
printf("Testing receive side timing...\n");
TEST(ReceiverTimingTests() == 0);
printf("Testing jitter buffer...\n");
TEST(JitterBufferTest() == 0);
printf("Testing Codec Data Base...\n");
TEST(CodecDBTest() == 0);
printf("Testing Media Optimization....\n");
TEST(VCMMediaOptTest(1) == 0);
// Tests requiring verification
printf("Testing Multi thread send-receive....\n");
TEST(MTRxTxTest() == 0);
printf("Verify by viewing output file MTRxTx_out.yuv \n");
return 0;
}

View File

@ -0,0 +1,17 @@
/*
* 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 RELEASE_TEST_H
#define RELEASE_TEST_H
int ReleaseTest();
int ReleaseTestPart2();
#endif

View File

@ -0,0 +1,31 @@
/*
* 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 "ReleaseTest.h"
#include "ReceiverTests.h"
#include "TestMacros.h"
#include "MediaOptTest.h"
#include "CodecDataBaseTest.h"
#include "GenericCodecTest.h"
int ReleaseTestPart2()
{
printf("Verify that TICK_TIME_DEBUG and EVENT_DEBUG are uncommented");
// Tests requiring verification
printf("Testing Generic Codecs...\n");
TEST(VCMGenericCodecTest() == 0);
printf("Verify by viewing output file GCTest_out.yuv \n");
return 0;
}

View File

@ -0,0 +1,441 @@
/*
* 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 "rtp_player.h"
#include <cstdlib>
#ifdef WIN32
#include <windows.h>
#include <Winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "../source/internal_defines.h"
#include "gtest/gtest.h"
#include "modules/video_coding/main/source/tick_time_base.h"
#include "rtp_rtcp.h"
using namespace webrtc;
RawRtpPacket::RawRtpPacket(uint8_t* rtp_data, uint16_t rtp_length)
: data(rtp_data),
length(rtp_length),
resend_time_ms(-1) {
data = new uint8_t[length];
memcpy(data, rtp_data, length);
}
RawRtpPacket::~RawRtpPacket() {
delete [] data;
}
LostPackets::LostPackets()
: crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
loss_count_(0),
debug_file_(NULL),
packets_() {
debug_file_ = fopen("PacketLossDebug.txt", "w");
}
LostPackets::~LostPackets() {
if (debug_file_) {
fclose(debug_file_);
}
while (!packets_.empty()) {
delete packets_.front();
packets_.pop_front();
}
delete crit_sect_;
}
void LostPackets::AddPacket(RawRtpPacket* packet) {
CriticalSectionScoped cs(crit_sect_);
packets_.push_back(packet);
uint16_t seq_num = (packet->data[2] << 8) + packet->data[3];
if (debug_file_ != NULL) {
fprintf(debug_file_, "%u Lost packet: %u\n", loss_count_, seq_num);
}
++loss_count_;
}
void LostPackets::SetResendTime(uint16_t resend_seq_num,
int64_t resend_time_ms,
int64_t now_ms) {
CriticalSectionScoped cs(crit_sect_);
for (RtpPacketIterator it = packets_.begin(); it != packets_.end(); ++it) {
const uint16_t seq_num = ((*it)->data[2] << 8) +
(*it)->data[3];
if (resend_seq_num == seq_num) {
if ((*it)->resend_time_ms + 10 < now_ms) {
if (debug_file_ != NULL) {
fprintf(debug_file_, "Resend %u at %u\n", seq_num,
MaskWord64ToUWord32(resend_time_ms));
}
(*it)->resend_time_ms = resend_time_ms;
}
return;
}
}
assert(false);
}
RawRtpPacket* LostPackets::NextPacketToResend(int64_t timeNow) {
CriticalSectionScoped cs(crit_sect_);
for (RtpPacketIterator it = packets_.begin(); it != packets_.end(); ++it) {
if (timeNow >= (*it)->resend_time_ms && (*it)->resend_time_ms != -1) {
RawRtpPacket* packet = *it;
it = packets_.erase(it);
return packet;
}
}
return NULL;
}
int LostPackets::NumberOfPacketsToResend() const {
CriticalSectionScoped cs(crit_sect_);
int count = 0;
for (ConstRtpPacketIterator it = packets_.begin(); it != packets_.end();
++it) {
if ((*it)->resend_time_ms >= 0) {
count++;
}
}
return count;
}
void LostPackets::SetPacketResent(uint16_t seq_num, int64_t now_ms) {
CriticalSectionScoped cs(crit_sect_);
if (debug_file_ != NULL) {
fprintf(debug_file_, "Resent %u at %u\n", seq_num,
MaskWord64ToUWord32(now_ms));
}
}
void LostPackets::Print() const {
CriticalSectionScoped cs(crit_sect_);
printf("Lost packets: %u\n", loss_count_);
printf("Packets waiting to be resent: %u\n",
NumberOfPacketsToResend());
printf("Packets still lost: %u\n",
static_cast<unsigned int>(packets_.size()));
printf("Sequence numbers:\n");
for (ConstRtpPacketIterator it = packets_.begin(); it != packets_.end();
++it) {
uint16_t seq_num = ((*it)->data[2] << 8) + (*it)->data[3];
printf("%u, ", seq_num);
}
printf("\n");
}
RTPPlayer::RTPPlayer(const char* filename,
RtpData* callback,
TickTimeBase* clock)
:
_clock(clock),
_rtpModule(NULL),
_nextRtpTime(0),
_dataCallback(callback),
_firstPacket(true),
_lossRate(0.0f),
_nackEnabled(false),
_resendPacketCount(0),
_noLossStartup(100),
_endOfFile(false),
_rttMs(0),
_firstPacketRtpTime(0),
_firstPacketTimeMs(0),
_reorderBuffer(NULL),
_reordering(false),
_nextPacket(),
_nextPacketLength(0),
_randVec(),
_randVecPos(0)
{
_rtpFile = fopen(filename, "rb");
memset(_nextPacket, 0, sizeof(_nextPacket));
}
RTPPlayer::~RTPPlayer()
{
delete _rtpModule;
if (_rtpFile != NULL)
{
fclose(_rtpFile);
}
if (_reorderBuffer != NULL)
{
delete _reorderBuffer;
_reorderBuffer = NULL;
}
}
WebRtc_Word32 RTPPlayer::Initialize(const PayloadTypeList* payloadList)
{
RtpRtcp::Configuration configuration;
configuration.id = 1;
configuration.audio = false;
configuration.incoming_data = _dataCallback;
_rtpModule = RtpRtcp::CreateRtpRtcp(configuration);
std::srand(321);
for (int i=0; i < RAND_VEC_LENGTH; i++)
{
_randVec[i] = rand();
}
_randVecPos = 0;
WebRtc_Word32 ret = _rtpModule->SetNACKStatus(kNackOff);
if (ret < 0)
{
return -1;
}
_rtpModule->SetRTCPStatus(kRtcpNonCompound);
_rtpModule->SetTMMBRStatus(true);
if (ret < 0)
{
return -1;
}
// Register payload types
for (PayloadTypeList::const_iterator it = payloadList->begin();
it != payloadList->end(); ++it) {
PayloadCodecTuple* payloadType = *it;
if (payloadType != NULL)
{
VideoCodec videoCodec;
strncpy(videoCodec.plName, payloadType->name.c_str(), 32);
videoCodec.plType = payloadType->payloadType;
if (_rtpModule->RegisterReceivePayload(videoCodec) < 0)
{
return -1;
}
}
}
if (ReadHeader() < 0)
{
return -1;
}
memset(_nextPacket, 0, sizeof(_nextPacket));
_nextPacketLength = ReadPacket(_nextPacket, &_nextRtpTime);
return 0;
}
WebRtc_Word32 RTPPlayer::ReadHeader()
{
char firstline[FIRSTLINELEN];
if (_rtpFile == NULL)
{
return -1;
}
EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, _rtpFile) != NULL);
if(strncmp(firstline,"#!rtpplay",9) == 0) {
if(strncmp(firstline,"#!rtpplay1.0",12) != 0){
printf("ERROR: wrong rtpplay version, must be 1.0\n");
return -1;
}
}
else if (strncmp(firstline,"#!RTPencode",11) == 0) {
if(strncmp(firstline,"#!RTPencode1.0",14) != 0){
printf("ERROR: wrong RTPencode version, must be 1.0\n");
return -1;
}
}
else {
printf("ERROR: wrong file format of input file\n");
return -1;
}
WebRtc_UWord32 start_sec;
WebRtc_UWord32 start_usec;
WebRtc_UWord32 source;
WebRtc_UWord16 port;
WebRtc_UWord16 padding;
EXPECT_GT(fread(&start_sec, 4, 1, _rtpFile), 0u);
start_sec=ntohl(start_sec);
EXPECT_GT(fread(&start_usec, 4, 1, _rtpFile), 0u);
start_usec=ntohl(start_usec);
EXPECT_GT(fread(&source, 4, 1, _rtpFile), 0u);
source=ntohl(source);
EXPECT_GT(fread(&port, 2, 1, _rtpFile), 0u);
port=ntohs(port);
EXPECT_GT(fread(&padding, 2, 1, _rtpFile), 0u);
padding=ntohs(padding);
return 0;
}
WebRtc_UWord32 RTPPlayer::TimeUntilNextPacket() const
{
WebRtc_Word64 timeLeft = (_nextRtpTime - _firstPacketRtpTime) - (_clock->MillisecondTimestamp() - _firstPacketTimeMs);
if (timeLeft < 0)
{
return 0;
}
return static_cast<WebRtc_UWord32>(timeLeft);
}
WebRtc_Word32 RTPPlayer::NextPacket(const WebRtc_Word64 timeNow)
{
// Send any packets ready to be resent,
RawRtpPacket* resend_packet = _lostPackets.NextPacketToResend(timeNow);
while (resend_packet != NULL) {
const uint16_t seqNo = (resend_packet->data[2] << 8) +
resend_packet->data[3];
printf("Resend: %u\n", seqNo);
int ret = SendPacket(resend_packet->data, resend_packet->length);
delete resend_packet;
_resendPacketCount++;
if (ret > 0) {
_lostPackets.SetPacketResent(seqNo, _clock->MillisecondTimestamp());
} else if (ret < 0) {
return ret;
}
resend_packet = _lostPackets.NextPacketToResend(timeNow);
}
// Send any packets from rtp file
if (!_endOfFile && (TimeUntilNextPacket() == 0 || _firstPacket))
{
_rtpModule->Process();
if (_firstPacket)
{
_firstPacketRtpTime = static_cast<WebRtc_Word64>(_nextRtpTime);
_firstPacketTimeMs = _clock->MillisecondTimestamp();
}
if (_reordering && _reorderBuffer == NULL)
{
_reorderBuffer = new RawRtpPacket(reinterpret_cast<WebRtc_UWord8*>(_nextPacket), static_cast<WebRtc_UWord16>(_nextPacketLength));
return 0;
}
WebRtc_Word32 ret = SendPacket(reinterpret_cast<WebRtc_UWord8*>(_nextPacket), static_cast<WebRtc_UWord16>(_nextPacketLength));
if (_reordering && _reorderBuffer != NULL)
{
RawRtpPacket* rtpPacket = _reorderBuffer;
_reorderBuffer = NULL;
SendPacket(rtpPacket->data, rtpPacket->length);
delete rtpPacket;
}
_firstPacket = false;
if (ret < 0)
{
return ret;
}
_nextPacketLength = ReadPacket(_nextPacket, &_nextRtpTime);
if (_nextPacketLength < 0)
{
_endOfFile = true;
return 0;
}
else if (_nextPacketLength == 0)
{
return 0;
}
}
if (_endOfFile && _lostPackets.NumberOfPacketsToResend() == 0)
{
return 1;
}
return 0;
}
WebRtc_Word32 RTPPlayer::SendPacket(WebRtc_UWord8* rtpData, WebRtc_UWord16 rtpLen)
{
if ((_randVec[(_randVecPos++) % RAND_VEC_LENGTH] + 1.0)/(RAND_MAX + 1.0) < _lossRate &&
_noLossStartup < 0)
{
if (_nackEnabled)
{
const WebRtc_UWord16 seqNo = (rtpData[2] << 8) + rtpData[3];
printf("Throw: %u\n", seqNo);
_lostPackets.AddPacket(new RawRtpPacket(rtpData, rtpLen));
return 0;
}
}
else if (rtpLen > 0)
{
WebRtc_Word32 ret = _rtpModule->IncomingPacket(rtpData, rtpLen);
if (ret < 0)
{
return -1;
}
}
if (_noLossStartup >= 0)
{
_noLossStartup--;
}
return 1;
}
WebRtc_Word32 RTPPlayer::ReadPacket(WebRtc_Word16* rtpdata, WebRtc_UWord32* offset)
{
WebRtc_UWord16 length, plen;
if (fread(&length,2,1,_rtpFile)==0)
return(-1);
length=ntohs(length);
if (fread(&plen,2,1,_rtpFile)==0)
return(-1);
plen=ntohs(plen);
if (fread(offset,4,1,_rtpFile)==0)
return(-1);
*offset=ntohl(*offset);
// Use length here because a plen of 0 specifies rtcp
length = (WebRtc_UWord16) (length - HDR_SIZE);
if (fread((unsigned short *) rtpdata,1,length,_rtpFile) != length)
return(-1);
#ifdef JUNK_DATA
// destroy the RTP payload with random data
if (plen > 12) { // ensure that we have more than just a header
for ( int ix = 12; ix < plen; ix=ix+2 ) {
rtpdata[ix>>1] = (short) (rtpdata[ix>>1] + (short) rand());
}
}
#endif
return plen;
}
WebRtc_Word32 RTPPlayer::SimulatePacketLoss(float lossRate, bool enableNack, WebRtc_UWord32 rttMs)
{
_nackEnabled = enableNack;
_lossRate = lossRate;
_rttMs = rttMs;
return 0;
}
WebRtc_Word32 RTPPlayer::SetReordering(bool enabled)
{
_reordering = enabled;
return 0;
}
WebRtc_Word32 RTPPlayer::ResendPackets(const WebRtc_UWord16* sequenceNumbers, WebRtc_UWord16 length)
{
if (sequenceNumbers == NULL)
{
return 0;
}
for (int i=0; i < length; i++)
{
_lostPackets.SetResendTime(sequenceNumbers[i],
_clock->MillisecondTimestamp() + _rttMs,
_clock->MillisecondTimestamp());
}
return 0;
}
void RTPPlayer::Print() const
{
printf("Resent packets: %u\n", _resendPacketCount);
_lostPackets.Print();
}

View File

@ -0,0 +1,119 @@
/*
* 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_RTP_PLAYER_H_
#define WEBRTC_MODULES_VIDEO_CODING_TEST_RTP_PLAYER_H_
#include "typedefs.h"
#include "rtp_rtcp.h"
#include "critical_section_wrapper.h"
#include "video_coding_defines.h"
#include "modules/video_coding/main/source/tick_time_base.h"
#include <stdio.h>
#include <list>
#include <string>
#define HDR_SIZE 8 // rtpplay packet header size in bytes
#define FIRSTLINELEN 40
#define RAND_VEC_LENGTH 4096
struct PayloadCodecTuple;
struct RawRtpPacket
{
public:
RawRtpPacket(WebRtc_UWord8* rtp_data, WebRtc_UWord16 rtp_length);
~RawRtpPacket();
uint8_t* data;
uint16_t length;
int64_t resend_time_ms;
};
typedef std::list<PayloadCodecTuple*> PayloadTypeList;
typedef std::list<RawRtpPacket*> RtpPacketList;
typedef RtpPacketList::iterator RtpPacketIterator;
typedef RtpPacketList::const_iterator ConstRtpPacketIterator;
class LostPackets {
public:
LostPackets();
~LostPackets();
void AddPacket(RawRtpPacket* packet);
void SetResendTime(uint16_t sequenceNumber,
int64_t resendTime,
int64_t nowMs);
RawRtpPacket* NextPacketToResend(int64_t timeNow);
int NumberOfPacketsToResend() const;
void SetPacketResent(uint16_t seqNo, int64_t nowMs);
void Print() const;
private:
webrtc::CriticalSectionWrapper* crit_sect_;
int loss_count_;
FILE* debug_file_;
RtpPacketList packets_;
};
struct PayloadCodecTuple
{
PayloadCodecTuple(WebRtc_UWord8 plType, std::string codecName, webrtc::VideoCodecType type) :
name(codecName), payloadType(plType), codecType(type) {};
const std::string name;
const WebRtc_UWord8 payloadType;
const webrtc::VideoCodecType codecType;
};
class RTPPlayer : public webrtc::VCMPacketRequestCallback
{
public:
RTPPlayer(const char* filename,
webrtc::RtpData* callback,
webrtc::TickTimeBase* clock);
virtual ~RTPPlayer();
WebRtc_Word32 Initialize(const PayloadTypeList* payloadList);
WebRtc_Word32 NextPacket(const WebRtc_Word64 timeNow);
WebRtc_UWord32 TimeUntilNextPacket() const;
WebRtc_Word32 SimulatePacketLoss(float lossRate, bool enableNack = false, WebRtc_UWord32 rttMs = 0);
WebRtc_Word32 SetReordering(bool enabled);
WebRtc_Word32 ResendPackets(const WebRtc_UWord16* sequenceNumbers, WebRtc_UWord16 length);
void Print() const;
private:
WebRtc_Word32 SendPacket(WebRtc_UWord8* rtpData, WebRtc_UWord16 rtpLen);
WebRtc_Word32 ReadPacket(WebRtc_Word16* rtpdata, WebRtc_UWord32* offset);
WebRtc_Word32 ReadHeader();
webrtc::TickTimeBase* _clock;
FILE* _rtpFile;
webrtc::RtpRtcp* _rtpModule;
WebRtc_UWord32 _nextRtpTime;
webrtc::RtpData* _dataCallback;
bool _firstPacket;
float _lossRate;
bool _nackEnabled;
LostPackets _lostPackets;
WebRtc_UWord32 _resendPacketCount;
WebRtc_Word32 _noLossStartup;
bool _endOfFile;
WebRtc_UWord32 _rttMs;
WebRtc_Word64 _firstPacketRtpTime;
WebRtc_Word64 _firstPacketTimeMs;
RawRtpPacket* _reorderBuffer;
bool _reordering;
WebRtc_Word16 _nextPacket[8000];
WebRtc_Word32 _nextPacketLength;
int _randVec[RAND_VEC_LENGTH];
int _randVecPos;
};
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_RTP_PLAYER_H_

View File

@ -0,0 +1,30 @@
function H = subfigure(m, n, p)
%
% H = SUBFIGURE(m, n, p)
%
% Create a new figure window and adjust position and size such that it will
% become the p-th tile in an m-by-n matrix of windows. (The interpretation of
% m, n, and p is the same as for SUBPLOT.
%
% Henrik Lundin, 2009-01-19
%
h = figure;
[j, i] = ind2sub([n m], p);
scrsz = get(0,'ScreenSize'); % get screen size
%scrsz = [1, 1, 1600, 1200];
taskbarSize = 58;
windowbarSize = 68;
windowBorder = 4;
scrsz(2) = scrsz(2) + taskbarSize;
scrsz(4) = scrsz(4) - taskbarSize;
set(h, 'position', [(j-1)/n * scrsz(3) + scrsz(1) + windowBorder,...
(m-i)/m * scrsz(4) + scrsz(2) + windowBorder, ...
scrsz(3)/n - (windowBorder + windowBorder),...
scrsz(4)/m - (windowbarSize + windowBorder + windowBorder)]);

View File

@ -0,0 +1,467 @@
/*
* 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 "test_callbacks.h"
#include <cmath>
#include "modules/video_coding/main/source/tick_time_base.h"
#include "rtp_dump.h"
#include "test_macros.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(kRTPVideoNoVideo)
{
//
}
VCMEncodeCompleteCallback::~VCMEncodeCompleteCallback()
{
}
void
VCMEncodeCompleteCallback::RegisterTransportCallback(
VCMPacketizationCallback* transport)
{
}
WebRtc_Word32
VCMEncodeCompleteCallback::SendData(
const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader& fragmentationHeader,
const RTPVideoHeader* videoHdr)
{
// will call the VCMReceiver input packet
_frameType = frameType;
// writing encodedData into file
if (fwrite(payloadData, 1, payloadSize, _encodedFile) != payloadSize) {
return -1;
}
WebRtcRTPHeader rtpInfo;
rtpInfo.header.markerBit = true; // end of frame
rtpInfo.type.Video.isFirstPacket = true;
rtpInfo.type.Video.codec = _codecType;
rtpInfo.type.Video.height = (WebRtc_UWord16)_height;
rtpInfo.type.Video.width = (WebRtc_UWord16)_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::kRTPVideoI420:
break;
default:
assert(false);
return -1;
}
rtpInfo.header.payloadType = payloadType;
rtpInfo.header.sequenceNumber = _seqNo++;
rtpInfo.header.ssrc = 0;
rtpInfo.header.timestamp = timeStamp;
rtpInfo.frameType = frameType;
// Size should also be received from that table, since the payload type
// defines the size.
_encodedBytes += payloadSize;
// directly to receiver
int ret = _VCMReceiver->IncomingPacket(payloadData, payloadSize, rtpInfo);
_encodeComplete = true;
return ret;
}
float
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
WebRtc_Word32
VCMRTPEncodeCompleteCallback::SendData(
const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader& fragmentationHeader,
const RTPVideoHeader* videoHdr)
{
_frameType = frameType;
_encodedBytes+= payloadSize;
_encodeComplete = true;
return _RTPModule->SendOutgoingData(frameType,
payloadType,
timeStamp,
capture_time_ms,
payloadData,
payloadSize,
&fragmentationHeader,
videoHdr);
}
float
VCMRTPEncodeCompleteCallback::EncodedBytes()
{
// only good for one call - after which will reset value;
float tmp = _encodedBytes;
_encodedBytes = 0;
return tmp;
}
bool
VCMRTPEncodeCompleteCallback::EncodeComplete()
{
if (_encodeComplete)
{
_encodeComplete = false;
return true;
}
return false;
}
// Decoded Frame Callback Implementation
WebRtc_Word32
VCMDecodeCompleteCallback::FrameToRender(VideoFrame& videoFrame)
{
if (fwrite(videoFrame.Buffer(), 1, videoFrame.Length(),
_decodedFile) != videoFrame.Length()) {
return -1;
}
_decodedBytes+= videoFrame.Length();
return VCM_OK;
}
WebRtc_Word32
VCMDecodeCompleteCallback::DecodedBytes()
{
return _decodedBytes;
}
RTPSendCompleteCallback::RTPSendCompleteCallback(TickTimeBase* clock,
const char* filename):
_clock(clock),
_sendCount(0),
_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, int len)
{
_sendCount++;
_totalSentLength += len;
if (_rtpDump != NULL)
{
if (_rtpDump->DumpPacket((const WebRtc_UWord8*)data, len) != 0)
{
return -1;
}
}
bool transmitPacket = true;
transmitPacket = PacketLoss();
WebRtc_UWord64 now = _clock->MillisecondTimestamp();
// 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
WebRtc_Word32
simulatedDelay = (WebRtc_Word32)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();
WebRtc_Word64 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
if (_rtp->IncomingPacket((const WebRtc_UWord8*)packet->data,
packet->length) < 0)
{
delete packet;
packet = NULL;
// Will return an error after the first packet that goes wrong
return -1;
}
delete packet;
packet = NULL;
}
return len; // OK
}
int
RTPSendCompleteCallback::SendRTCPPacket(int channel, const void *data, int 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 = (std::rand() + 1.0)/(RAND_MAX + 1.0);
return randVal < lossPct/100;
}
WebRtc_Word32
PacketRequester::ResendPackets(const WebRtc_UWord16* sequenceNumbers,
WebRtc_UWord16 length)
{
return _rtp.SendNACK(sequenceNumbers, length);
}
WebRtc_Word32
SendStatsTest::SendStatistics(const WebRtc_UWord32 bitRate,
const WebRtc_UWord32 frameRate)
{
TEST(frameRate <= _frameRate);
TEST(bitRate > 0 && bitRate < 100000);
printf("VCM 1 sec: Bit rate: %u\tFrame rate: %u\n", bitRate, frameRate);
return 0;
}
WebRtc_Word32 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()
{
//
}
WebRtc_Word32
VideoProtectionCallback::ProtectionRequest(
const FecProtectionParams* delta_fec_params,
const FecProtectionParams* key_fec_params,
WebRtc_UWord32* sent_video_rate_bps,
WebRtc_UWord32* sent_nack_rate_bps,
WebRtc_UWord32* 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

View File

@ -0,0 +1,256 @@
/*
* 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 <string.h>
#include <cstdlib>
#include <fstream>
#include <list>
#include "module_common_types.h"
#include "rtp_rtcp.h"
#include "test_util.h"
#include "trace.h"
#include "video_coding.h"
namespace webrtc
{
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
WebRtc_Word32 SendData(const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader& fragmentationHeader,
const RTPVideoHeader* videoHdr);
// 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)
float 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(WebRtc_Word32 width, WebRtc_Word32 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;
float _encodedBytes;
VideoCodingModule* _VCMReceiver;
FrameType _frameType;
WebRtc_UWord16 _seqNo;
bool _encodeComplete;
WebRtc_Word32 _width;
WebRtc_Word32 _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
WebRtc_Word32 SendData(const FrameType frameType,
const WebRtc_UWord8 payloadType,
const WebRtc_UWord32 timeStamp,
int64_t capture_time_ms,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader& fragmentationHeader,
const RTPVideoHeader* videoHdr);
// Return size of last encoded frame. Value good for one call
// (resets to zero after call to inform test of frame drop)
float 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(WebRtc_Word16 width, WebRtc_Word16 height)
{
_width = width;
_height = height;
}
private:
float _encodedBytes;
FrameType _frameType;
bool _encodeComplete;
RtpRtcp* _RTPModule;
WebRtc_Word16 _width;
WebRtc_Word16 _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
WebRtc_Word32 FrameToRender(webrtc::VideoFrame& videoFrame);
WebRtc_Word32 DecodedBytes();
private:
FILE* _decodedFile;
WebRtc_UWord32 _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(TickTimeBase* clock,
const char* filename = NULL);
virtual ~RTPSendCompleteCallback();
void SetRtpModule(RtpRtcp* rtp_module) { _rtp = rtp_module; }
// Send Packet to receive side RTP module
virtual int SendPacket(int channel, const void *data, int len);
// Send RTCP Packet to receive side RTP module
virtual int SendRTCPPacket(int channel, const void *data, int len);
// 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(WebRtc_UWord32 networkDelayMs)
{_networkDelayMs = networkDelayMs;};
// Set Packet jitter delay
void SetJitterVar(WebRtc_UWord32 jitterVar)
{_jitterVar = jitterVar;};
// Return send count
int SendCount() {return _sendCount; }
// Return accumulated length in bytes of transmitted packets
WebRtc_UWord32 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);
TickTimeBase* _clock;
WebRtc_UWord32 _sendCount;
RtpRtcp* _rtp;
double _lossPct;
double _burstLength;
WebRtc_UWord32 _networkDelayMs;
double _jitterVar;
bool _prevLossState;
WebRtc_UWord32 _totalSentLength;
std::list<RtpPacket*> _rtpPackets;
RtpDump* _rtpDump;
};
// Request re-transmission of packets (NACK)
class PacketRequester: public VCMPacketRequestCallback
{
public:
PacketRequester(RtpRtcp& rtp) :
_rtp(rtp) {}
WebRtc_Word32 ResendPackets(const WebRtc_UWord16* sequenceNumbers,
WebRtc_UWord16 length);
private:
webrtc::RtpRtcp& _rtp;
};
// Key frame request
class KeyFrameReqTest: public VCMFrameTypeCallback
{
public:
WebRtc_Word32 RequestKeyFrame();
};
// VCM statistics
class SendStatsTest: public webrtc::VCMSendStatisticsCallback
{
public:
SendStatsTest() : _frameRate(15) {}
WebRtc_Word32 SendStatistics(const WebRtc_UWord32 bitRate,
const WebRtc_UWord32 frameRate);
void SetTargetFrameRate(WebRtc_UWord32 frameRate) {_frameRate = frameRate;}
private:
WebRtc_UWord32 _frameRate;
};
// 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;}
WebRtc_Word32 ProtectionRequest(
const FecProtectionParams* delta_fec_params,
const FecProtectionParams* key_fec_params,
WebRtc_UWord32* sent_video_rate_bps,
WebRtc_UWord32* sent_nack_rate_bps,
WebRtc_UWord32* sent_fec_rate_bps);
FecProtectionParams DeltaFecParameters() const;
FecProtectionParams KeyFecParameters() const;
private:
RtpRtcp* _rtp;
FecProtectionParams delta_fec_params_;
FecProtectionParams key_fec_params_;
};
} // namespace webrtc
#endif

View File

@ -0,0 +1,45 @@
/*
* 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 <cstdio>
#include <cstdlib>
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

View File

@ -0,0 +1,46 @@
/*
* 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 "test_util.h"
#include "test_macros.h"
#include "rtp_dump.h"
#include <cmath>
using namespace webrtc;
// 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 = (std::rand() + 1.0) / (RAND_MAX + 1.0);
double uniform2 = (std::rand() + 1.0) / (RAND_MAX + 1.0);
return (mean + stdDev * sqrt(-2 * log(uniform1)) * cos(2 * PI * uniform2));
}
RTPVideoCodecTypes
ConvertCodecType(const char* plname)
{
if (strncmp(plname,"VP8" , 3) == 0)
{
return kRTPVideoVP8;
}
else if (strncmp(plname,"I420" , 5) == 0)
{
return kRTPVideoI420;
}
else
{
return kRTPVideoNoVideo; // Default value
}
}

View File

@ -0,0 +1,75 @@
/*
* 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_UTIL_H_
#define WEBRTC_MODULES_VIDEO_CODING_TEST_TEST_UTIL_H_
/*
* General declarations used through out VCM offline tests.
*/
#include <string.h>
#include <fstream>
#include <cstdlib>
#include "module_common_types.h"
#include "testsupport/fileutils.h"
// Class used for passing command line arguments to tests
class CmdArgs
{
public:
CmdArgs()
: codecName("VP8"),
codecType(webrtc::kVideoCodecVP8),
width(352),
height(288),
bitRate(500),
frameRate(30),
packetLoss(0),
rtt(0),
protectionMode(0),
camaEnable(0),
inputFile(webrtc::test::ProjectRootPath() +
"/resources/foreman_cif.yuv"),
outputFile(webrtc::test::OutputPath() +
"video_coding_test_output_352x288.yuv"),
testNum(11) {}
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;
int testNum;
};
// forward declaration
int MTRxTxTest(CmdArgs& args);
double NormalDist(double mean, double stdDev);
struct RtpPacket {
WebRtc_Word8 data[1650]; // max packet size
WebRtc_Word32 length;
WebRtc_Word64 receiveTime;
};
// Codec type conversion
webrtc::RTPVideoCodecTypes
ConvertCodecType(const char* plname);
#endif

View File

@ -0,0 +1,208 @@
/*
* 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 "receiver_tests.h"
#include "normal_test.h"
#include "codec_database_test.h"
#include "generic_codec_test.h"
#include "../source/event.h"
#include "media_opt_test.h"
#include "quality_modes_test.h"
#include "test_util.h"
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
//#include "vld.h"
#endif
using namespace webrtc;
/*
* Build with EVENT_DEBUG defined
* to build the tests with simulated events.
*/
int vcmMacrosTests = 0;
int vcmMacrosErrors = 0;
int ParseArguments(int argc, char **argv, CmdArgs& args)
{
int i = 1;
while (i < argc)
{
if (argv[i][0] != '-')
{
return -1;
}
switch (argv[i][1])
{
case 'w':
{
int w = atoi(argv[i+1]);
if (w < 1)
return -1;
args.width = w;
break;
}
case 'h':
{
int h = atoi(argv[i+1]);
if (h < 1)
return -1;
args.height = h;
break;
}
case 'b':
{
int b = atoi(argv[i+1]);
if (b < 1)
return -1;
args.bitRate = b;
break;
}
case 'f':
{
int f = atoi(argv[i+1]);
if (f < 1)
return -1;
args.frameRate = f;
break;
}
case 'c':
{
// TODO(holmer): This should be replaced with a map if more codecs
// are added
args.codecName = argv[i+1];
if (strncmp(argv[i+1], "VP8", 3) == 0)
{
args.codecType = kVideoCodecVP8;
}
else if (strncmp(argv[i+1], "I420", 4) == 0)
{
args.codecType = kVideoCodecI420;
}
else
return -1;
break;
}
case 'i':
{
args.inputFile = argv[i+1];
break;
}
case 'o':
args.outputFile = argv[i+1];
break;
case 'n':
{
int n = atoi(argv[i+1]);
if (n < 1)
return -1;
args.testNum = n;
break;
}
case 'p':
{
args.packetLoss = atoi(argv[i+1]);
break;
}
case 'r':
{
args.rtt = atoi(argv[i+1]);
break;
}
case 'm':
{
args.protectionMode = atoi(argv[i+1]);
break;
}
case 'e':
{
args.camaEnable = atoi(argv[i+1]);
break;
}
default:
return -1;
}
i += 2;
}
return 0;
}
int main(int argc, char **argv)
{
CmdArgs args;
if (ParseArguments(argc, argv, args) != 0)
{
printf("Unable to parse input arguments\n");
printf("args: -n <test #> -w <width> -h <height> -f <fps> -b <bps> "
"-c <codec> -i <input file> -o <output file> -p <packet loss> "
"-r <round-trip-time> -e <cama enable> -m <protection mode> \n");
return -1;
}
int ret = 0;
switch (args.testNum)
{
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 6:
ret = ReceiverTimingTests(args);
break;
case 7:
ret = RtpPlay(args);
break;
case 8:
ret = RtpPlayMT(args);
break;
case 9:
ret = JitterBufferTest(args);
break;
case 10:
ret = DecodeFromStorageTest(args);
break;
case 11:
ret = NormalTest::RunTest(args);
ret |= CodecDataBaseTest::RunTest(args);
ret |= ReceiverTimingTests(args);
ret |= JitterBufferTest(args);
break;
default:
ret = -1;
break;
}
if (ret != 0)
{
printf("Test failed!\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,247 @@
/*
* 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 "receiver_tests.h"
#include "video_coding.h"
#include "rtp_rtcp.h"
#include "trace.h"
#include "../source/event.h"
#include "../source/internal_defines.h"
#include "test_macros.h"
#include "rtp_player.h"
#include "modules/video_coding/main/source/mock/fake_tick_time.h"
#include <stdio.h>
#include <string.h>
#include <sstream>
using namespace webrtc;
WebRtc_Word32
RtpDataCallback::OnReceivedPayloadData(const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadSize,
const WebRtcRTPHeader* rtpHeader)
{
return _vcm->IncomingPacket(payloadData, payloadSize, *rtpHeader);
}
FrameReceiveCallback::~FrameReceiveCallback()
{
if (_timingFile != NULL)
{
fclose(_timingFile);
}
if (_outFile != NULL)
{
fclose(_outFile);
}
}
WebRtc_Word32
FrameReceiveCallback::FrameToRender(VideoFrame& videoFrame)
{
if (_timingFile == NULL)
{
_timingFile = fopen((test::OutputPath() + "renderTiming.txt").c_str(),
"w");
if (_timingFile == NULL)
{
return -1;
}
}
if (_outFile == NULL || videoFrame.Width() != width_ ||
videoFrame.Height() != height_)
{
if (_outFile) {
fclose(_outFile);
}
printf("New size: %ux%u\n", videoFrame.Width(), videoFrame.Height());
width_ = videoFrame.Width();
height_ = videoFrame.Height();
std::string filename_with_width_height = AppendWidthAndHeight(
_outFilename, width_, height_);
_outFile = fopen(filename_with_width_height.c_str(), "wb");
if (_outFile == NULL)
{
return -1;
}
}
fprintf(_timingFile, "%u, %u\n",
videoFrame.TimeStamp(),
MaskWord64ToUWord32(videoFrame.RenderTimeMs()));
if (fwrite(videoFrame.Buffer(), 1, videoFrame.Length(),
_outFile) != videoFrame.Length()) {
return -1;
}
return 0;
}
void FrameReceiveCallback::SplitFilename(std::string filename,
std::string* basename,
std::string* ending) {
std::string::size_type idx;
idx = filename.rfind('.');
if(idx != std::string::npos) {
*ending = filename.substr(idx + 1);
*basename = filename.substr(0, idx);
} else {
*basename = filename;
*ending = "";
}
}
std::string FrameReceiveCallback::AppendWidthAndHeight(
std::string filename, unsigned int width, unsigned int height) {
std::string basename;
std::string ending;
SplitFilename(filename, &basename, &ending);
std::stringstream ss;
ss << basename << "." << width << "_" << height << "." << ending;
return ss.str();
}
int RtpPlay(CmdArgs& args)
{
// Make sure this test isn't executed without simulated events.
#if !defined(EVENT_DEBUG)
return -1;
#endif
// BEGIN Settings
bool protectionEnabled = true;
VCMVideoProtection protectionMethod = kProtectionNack;
WebRtc_UWord32 rttMS = 0;
float lossRate = 0.0f;
bool reordering = false;
WebRtc_UWord32 renderDelayMs = 0;
WebRtc_UWord32 minPlayoutDelayMs = 0;
const WebRtc_Word64 MAX_RUNTIME_MS = -1;
std::string outFile = args.outputFile;
if (outFile == "")
outFile = test::OutputPath() + "RtpPlay_decoded.yuv";
FrameReceiveCallback receiveCallback(outFile);
FakeTickTime clock(0);
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
RtpDataCallback dataCallback(vcm);
RTPPlayer rtpStream(args.inputFile.c_str(), &dataCallback, &clock);
PayloadTypeList payloadTypes;
payloadTypes.push_front(new PayloadCodecTuple(VCM_VP8_PAYLOAD_TYPE, "VP8",
kVideoCodecVP8));
payloadTypes.push_front(new PayloadCodecTuple(VCM_RED_PAYLOAD_TYPE, "RED",
kVideoCodecRED));
payloadTypes.push_front(new PayloadCodecTuple(VCM_ULPFEC_PAYLOAD_TYPE,
"ULPFEC", kVideoCodecULPFEC));
Trace::CreateTrace();
Trace::SetTraceFile((test::OutputPath() + "receiverTestTrace.txt").c_str());
Trace::SetLevelFilter(webrtc::kTraceAll);
// END Settings
// Set up
WebRtc_Word32 ret = vcm->InitializeReceiver();
if (ret < 0)
{
return -1;
}
vcm->RegisterReceiveCallback(&receiveCallback);
vcm->RegisterPacketRequestCallback(&rtpStream);
// Register receive codecs in VCM
for (PayloadTypeList::iterator it = payloadTypes.begin();
it != payloadTypes.end(); ++it) {
PayloadCodecTuple* payloadType = *it;
if (payloadType != NULL)
{
VideoCodec codec;
if (payloadType->codecType != kVideoCodecULPFEC &&
payloadType->codecType != kVideoCodecRED) {
if (VideoCodingModule::Codec(payloadType->codecType, &codec) < 0)
{
return -1;
}
codec.plType = payloadType->payloadType;
if (vcm->RegisterReceiveCodec(&codec, 1) < 0)
{
return -1;
}
}
}
}
if (rtpStream.Initialize(&payloadTypes) < 0)
{
return -1;
}
bool nackEnabled = protectionEnabled &&
(protectionMethod == kProtectionNack ||
protectionMethod == kProtectionDualDecoder);
rtpStream.SimulatePacketLoss(lossRate, nackEnabled, rttMS);
rtpStream.SetReordering(reordering);
vcm->SetChannelParameters(0, 0, rttMS);
vcm->SetVideoProtection(protectionMethod, protectionEnabled);
vcm->SetRenderDelay(renderDelayMs);
vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
ret = 0;
// RTP stream main loop
while ((ret = rtpStream.NextPacket(clock.MillisecondTimestamp())) == 0)
{
if (clock.MillisecondTimestamp() % 5 == 0)
{
ret = vcm->Decode();
if (ret < 0)
{
return -1;
}
}
while (vcm->DecodeDualFrame(0) == 1) {
}
if (vcm->TimeUntilNextProcess() <= 0)
{
vcm->Process();
}
if (MAX_RUNTIME_MS > -1 && clock.MillisecondTimestamp() >=
MAX_RUNTIME_MS)
{
break;
}
clock.IncrementDebugClock(1);
}
switch (ret)
{
case 1:
printf("Success\n");
break;
case -1:
printf("Failed\n");
break;
case 0:
printf("Timeout\n");
break;
}
rtpStream.Print();
// Tear down
while (!payloadTypes.empty())
{
delete payloadTypes.front();
payloadTypes.pop_front();
}
delete vcm;
vcm = NULL;
Trace::ReturnTrace();
return 0;
}

View File

@ -0,0 +1,262 @@
/*
* 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 "receiver_tests.h"
#include "video_coding.h"
#include "rtp_rtcp.h"
#include "trace.h"
#include "thread_wrapper.h"
#include "../source/event.h"
#include "test_macros.h"
#include "rtp_player.h"
#include <string.h>
using namespace webrtc;
bool ProcessingThread(void* obj)
{
SharedState* state = static_cast<SharedState*>(obj);
if (state->_vcm.TimeUntilNextProcess() <= 0)
{
if (state->_vcm.Process() < 0)
{
return false;
}
}
return true;
}
bool RtpReaderThread(void* obj)
{
SharedState* state = static_cast<SharedState*>(obj);
EventWrapper& waitEvent = *EventWrapper::Create();
// RTP stream main loop
TickTimeBase clock;
if (state->_rtpPlayer.NextPacket(clock.MillisecondTimestamp()) < 0)
{
return false;
}
waitEvent.Wait(state->_rtpPlayer.TimeUntilNextPacket());
delete &waitEvent;
return true;
}
bool DecodeThread(void* obj)
{
SharedState* state = static_cast<SharedState*>(obj);
state->_vcm.Decode(10000);
while (state->_vcm.DecodeDualFrame(0) == 1) {
}
return true;
}
int RtpPlayMT(CmdArgs& args, int releaseTestNo, webrtc::VideoCodecType releaseTestVideoType)
{
// Don't run these tests with debug events.
#if defined(EVENT_DEBUG)
return -1;
#endif
// BEGIN Settings
bool protectionEnabled = true;
VCMVideoProtection protection = kProtectionDualDecoder;
WebRtc_UWord8 rttMS = 50;
float lossRate = 0.05f;
WebRtc_UWord32 renderDelayMs = 0;
WebRtc_UWord32 minPlayoutDelayMs = 0;
const WebRtc_Word64 MAX_RUNTIME_MS = 10000;
std::string outFilename = args.outputFile;
if (outFilename == "")
outFilename = test::OutputPath() + "RtpPlayMT_decoded.yuv";
bool nackEnabled = (protectionEnabled &&
(protection == kProtectionDualDecoder ||
protection == kProtectionNack ||
kProtectionNackFEC));
TickTimeBase clock;
VideoCodingModule* vcm =
VideoCodingModule::Create(1, &clock);
RtpDataCallback dataCallback(vcm);
std::string rtpFilename;
rtpFilename = args.inputFile;
if (releaseTestNo > 0)
{
// Setup a release test
switch (releaseTestVideoType)
{
case webrtc::kVideoCodecVP8:
rtpFilename = args.inputFile;
outFilename = test::OutputPath() + "MTReceiveTest_VP8";
break;
default:
return -1;
}
switch (releaseTestNo)
{
case 1:
// Normal execution
protectionEnabled = false;
nackEnabled = false;
rttMS = 0;
lossRate = 0.0f;
outFilename += "_Normal.yuv";
break;
case 2:
// Packet loss
protectionEnabled = false;
nackEnabled = false;
rttMS = 0;
lossRate = 0.05f;
outFilename += "_0.05.yuv";
break;
case 3:
// Packet loss and NACK
protection = kProtectionNack;
nackEnabled = true;
protectionEnabled = true;
rttMS = 100;
lossRate = 0.05f;
outFilename += "_0.05_NACK_100ms.yuv";
break;
case 4:
// Packet loss and dual decoder
// Not implemented
return 0;
break;
default:
return -1;
}
printf("Watch %s to verify that the output is reasonable\n", outFilename.c_str());
}
RTPPlayer rtpStream(rtpFilename.c_str(), &dataCallback, &clock);
PayloadTypeList payloadTypes;
payloadTypes.push_front(new PayloadCodecTuple(VCM_VP8_PAYLOAD_TYPE, "VP8",
kVideoCodecVP8));
Trace::CreateTrace();
Trace::SetTraceFile("receiverTestTrace.txt");
Trace::SetLevelFilter(webrtc::kTraceAll);
// END Settings
// Set up
SharedState mtState(*vcm, rtpStream);
if (rtpStream.Initialize(&payloadTypes) < 0)
{
return -1;
}
rtpStream.SimulatePacketLoss(lossRate, nackEnabled, rttMS);
WebRtc_Word32 ret = vcm->InitializeReceiver();
if (ret < 0)
{
return -1;
}
// Create and start all threads
ThreadWrapper* processingThread = ThreadWrapper::CreateThread(ProcessingThread,
&mtState, kNormalPriority, "ProcessingThread");
ThreadWrapper* rtpReaderThread = ThreadWrapper::CreateThread(RtpReaderThread,
&mtState, kNormalPriority, "RtpReaderThread");
ThreadWrapper* decodeThread = ThreadWrapper::CreateThread(DecodeThread,
&mtState, kNormalPriority, "DecodeThread");
// Register receive codecs in VCM
for (PayloadTypeList::iterator it = payloadTypes.begin();
it != payloadTypes.end(); ++it) {
PayloadCodecTuple* payloadType = *it;
if (payloadType != NULL)
{
VideoCodec codec;
VideoCodingModule::Codec(payloadType->codecType, &codec);
codec.plType = payloadType->payloadType;
if (vcm->RegisterReceiveCodec(&codec, 1) < 0)
{
return -1;
}
}
}
if (processingThread != NULL)
{
unsigned int tid;
processingThread->Start(tid);
}
else
{
printf("Unable to start processing thread\n");
return -1;
}
if (rtpReaderThread != NULL)
{
unsigned int tid;
rtpReaderThread->Start(tid);
}
else
{
printf("Unable to start RTP reader thread\n");
return -1;
}
if (decodeThread != NULL)
{
unsigned int tid;
decodeThread->Start(tid);
}
else
{
printf("Unable to start decode thread\n");
return -1;
}
FrameReceiveCallback receiveCallback(outFilename);
vcm->RegisterReceiveCallback(&receiveCallback);
vcm->RegisterPacketRequestCallback(&rtpStream);
vcm->SetChannelParameters(0, 0, rttMS);
vcm->SetVideoProtection(protection, protectionEnabled);
vcm->SetRenderDelay(renderDelayMs);
vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs);
EventWrapper& waitEvent = *EventWrapper::Create();
// Decode for 10 seconds and then tear down and exit.
waitEvent.Wait(MAX_RUNTIME_MS);
// Tear down
while (!payloadTypes.empty())
{
delete payloadTypes.front();
payloadTypes.pop_front();
}
while (!processingThread->Stop())
{
;
}
while (!rtpReaderThread->Stop())
{
;
}
while (!decodeThread->Stop())
{
;
}
VideoCodingModule::Destroy(vcm);
vcm = NULL;
delete &waitEvent;
delete processingThread;
delete decodeThread;
delete rtpReaderThread;
rtpStream.Print();
Trace::ReturnTrace();
return 0;
}

View File

@ -0,0 +1,202 @@
/*
* 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 "video_source.h"
#include <cassert>
#include "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, WebRtc_UWord16 width, WebRtc_UWord16 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);
}
WebRtc_Word32
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;
}
}

View File

@ -0,0 +1,83 @@
/*
* 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_VIDEO_SOURCE_H_
#define WEBRTC_MODULES_VIDEO_CODING_TEST_VIDEO_SOURCE_H_
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "typedefs.h"
#include <string>
enum VideoSize
{
kUndefined,
kSQCIF, // 128*96 = 12 288
kQQVGA, // 160*120 = 19 200
kQCIF, // 176*144 = 25 344
kCGA, // 320*200 = 64 000
kQVGA, // 320*240 = 76 800
kSIF, // 352*240 = 84 480
kWQVGA, // 400*240 = 96 000
kCIF, // 352*288 = 101 376
kW288p, // 512*288 = 147 456 (WCIF)
k448p, // 576*448 = 281 088
kVGA, // 640*480 = 307 200
k432p, // 720*432 = 311 040
kW432p, // 768*432 = 331 776
k4SIF, // 704*480 = 337 920
kW448p, // 768*448 = 344 064
kNTSC, // 720*480 = 345 600
kFW448p, // 800*448 = 358 400
kWVGA, // 800*480 = 384 000
k4CIF, // 704*576 = 405 504
kSVGA, // 800*600 = 480 000
kW544p, // 960*544 = 522 240
kW576p, // 1024*576 = 589 824 (W4CIF)
kHD, // 960*720 = 691 200
kXGA, // 1024*768 = 786 432
kWHD, // 1280*720 = 921 600
kFullHD, // 1440*1080 = 1 555 200
kWFullHD, // 1920*1080 = 2 073 600
kNumberOfVideoSizes
};
class VideoSource
{
public:
VideoSource();
VideoSource(std::string fileName, VideoSize size, float frameRate, webrtc::VideoType type = webrtc::kI420);
VideoSource(std::string fileName, WebRtc_UWord16 width, WebRtc_UWord16 height,
float frameRate = 30, webrtc::VideoType type = webrtc::kI420);
std::string GetFileName() const { return _fileName; }
WebRtc_UWord16 GetWidth() const { return _width; }
WebRtc_UWord16 GetHeight() const { return _height; }
webrtc::VideoType GetType() const { return _type; }
float GetFrameRate() const { return _frameRate; }
int GetWidthHeight( VideoSize size);
// Returns the filename with the path (including the leading slash) removed.
std::string GetName() const;
WebRtc_Word32 GetFrameLength() const;
private:
std::string _fileName;
WebRtc_UWord16 _width;
WebRtc_UWord16 _height;
webrtc::VideoType _type;
float _frameRate;
};
#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_VIDEO_SOURCE_H_