diff --git a/src/modules/video_coding/main/source/video_coding_test.gyp b/src/modules/video_coding/main/source/video_coding_test.gyp index 706536ebb..84e380cfb 100644 --- a/src/modules/video_coding/main/source/video_coding_test.gyp +++ b/src/modules/video_coding/main/source/video_coding_test.gyp @@ -31,6 +31,7 @@ '../test/generic_codec_test.h', '../test/jitter_estimate_test.h', '../test/media_opt_test.h', + '../test/mt_test_common.h', '../test/normal_test.h', '../test/quality_modes_test.h', '../test/receiver_tests.h', @@ -46,6 +47,7 @@ '../test/generic_codec_test.cc', '../test/jitter_buffer_test.cc', '../test/media_opt_test.cc', + '../test/mt_test_common.cc', '../test/mt_rx_tx_test.cc', '../test/normal_test.cc', '../test/quality_modes_test.cc', diff --git a/src/modules/video_coding/main/test/mt_rx_tx_test.cc b/src/modules/video_coding/main/test/mt_rx_tx_test.cc index 4d391619c..3e5531530 100644 --- a/src/modules/video_coding/main/test/mt_rx_tx_test.cc +++ b/src/modules/video_coding/main/test/mt_rx_tx_test.cc @@ -14,16 +14,17 @@ * **************************************************/ -#include "receiver_tests.h" // shared RTP state and receive side threads -#include "video_coding.h" -#include "rtp_rtcp.h" -#include "thread_wrapper.h" +#include + #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 "media_opt_test.h" - -#include +#include "thread_wrapper.h" +#include "video_coding.h" using namespace webrtc; diff --git a/src/modules/video_coding/main/test/mt_test_common.cc b/src/modules/video_coding/main/test/mt_test_common.cc new file mode 100644 index 000000000..0af731c30 --- /dev/null +++ b/src/modules/video_coding/main/test/mt_test_common.cc @@ -0,0 +1,132 @@ +/* + * 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 "mt_test_common.h" + +#include + +#include "rtp_dump.h" + + +TransportCallback::TransportCallback(webrtc::RtpRtcp* rtp, + const char* filename): +RTPSendCompleteCallback(rtp, 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(); + } + + WebRtc_UWord64 now = VCMTickTime::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.PushBack(newPacket); + } + return 0; +} + +int +TransportCallback::TransportPackets() +{ + // Are we ready to send packets to the receiver? + rtpPacket* packet = NULL; + WebRtc_UWord64 now = VCMTickTime::MillisecondTimestamp(); + + while (!_rtpPackets.Empty()) + { + // Take first packet in list + packet = static_cast((_rtpPackets.First())->GetItem()); + WebRtc_Word64 timeToReceive = packet->receiveTime - now; + if (timeToReceive > 0) + { + // No available packets to send + break; + } + + _rtpPackets.PopFront(); + // 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(obj); + if (state->_vcm.TimeUntilNextProcess() <= 0) + { + if (state->_vcm.Process() < 0) + { + return false; + } + } + return true; +} + + +bool VCMDecodeThread(void* obj) +{ + SharedRTPState* state = static_cast(obj); + state->_vcm.Decode(); + return true; +} + +bool TransportThread(void *obj) +{ + SharedTransportState* state = static_cast(obj); + state->_transport.TransportPackets(); + return true; +} diff --git a/src/modules/video_coding/main/test/mt_test_common.h b/src/modules/video_coding/main/test/mt_test_common.h new file mode 100644 index 000000000..24d7912db --- /dev/null +++ b/src/modules/video_coding/main/test/mt_test_common.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* + * 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_util.h" +#include "video_coding.h" + +using 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(webrtc::RtpRtcp* rtp, + 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); + + +#endif // WEBRTC_MODULES_VIDEO_CODING_TEST_MT_TEST_COMMON_H_ diff --git a/src/modules/video_coding/main/test/receiver_tests.h b/src/modules/video_coding/main/test/receiver_tests.h index c8db7fdaf..33d9f5f68 100644 --- a/src/modules/video_coding/main/test/receiver_tests.h +++ b/src/modules/video_coding/main/test/receiver_tests.h @@ -63,15 +63,6 @@ public: RTPPlayer& _rtpPlayer; }; -class SharedRTPState -{ -public: - SharedRTPState(webrtc::VideoCodingModule& vcm, webrtc::RtpRtcp& rtp) : - _vcm(vcm), - _rtp(rtp) {} - webrtc::VideoCodingModule& _vcm; - webrtc::RtpRtcp& _rtp; -}; int RtpPlay(CmdArgs& args); int RtpPlayMT(CmdArgs& args, diff --git a/src/modules/video_coding/main/test/test_util.cc b/src/modules/video_coding/main/test/test_util.cc index 8e1c192d2..19e7ab90f 100644 --- a/src/modules/video_coding/main/test/test_util.cc +++ b/src/modules/video_coding/main/test/test_util.cc @@ -249,65 +249,6 @@ RTPSendCompleteCallback::SendPacket(int channel, const void *data, int len) { _sendCount++; _totalSentLength += len; - bool transmitPacket = true; - - // Packet Loss - - if (_burstLength <= 1.0) - { - // Random loss: if _burstLength parameter is not set, or <=1 - if (PacketLoss(_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 (PacketLoss(probTrans01)) - { - // drop, update previous state to loss - _prevLossState = 1; - transmitPacket = false; - } - } - else if (_prevLossState == 1) - { - _prevLossState = 0; - // previous packet was lost - if (PacketLoss(probTrans11)) - { - // drop, update previous state to loss - _prevLossState = 1; - transmitPacket = false; - } - } - } if (_rtpDump != NULL) { @@ -317,6 +258,8 @@ RTPSendCompleteCallback::SendPacket(int channel, const void *data, int len) } } + bool transmitPacket = PacketLoss(); + WebRtc_UWord64 now = VCMTickTime::MillisecondTimestamp(); // Insert outgoing packet into list if (transmitPacket) @@ -367,11 +310,8 @@ RTPSendCompleteCallback::SendPacket(int channel, const void *data, int len) int RTPSendCompleteCallback::SendRTCPPacket(int channel, const void *data, int len) { - if (_rtp->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) - { - return len; - } - return -1; + // Incorporate network conditions + return SendPacket(channel, data, len); } void @@ -389,7 +329,70 @@ RTPSendCompleteCallback::SetBurstLength(double burstLength) } bool -RTPSendCompleteCallback::PacketLoss(double lossPct) +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; @@ -402,7 +405,6 @@ PacketRequester::ResendPackets(const WebRtc_UWord16* sequenceNumbers, return _rtp.SendNACK(sequenceNumbers, length); } - RTPVideoCodecTypes ConvertCodecType(const char* plname) { diff --git a/src/modules/video_coding/main/test/test_util.h b/src/modules/video_coding/main/test/test_util.h index 97e305856..c1c1e21d5 100644 --- a/src/modules/video_coding/main/test/test_util.h +++ b/src/modules/video_coding/main/test/test_util.h @@ -51,6 +51,7 @@ public: // forward declaration int MTRxTxTest(CmdArgs& args); +double NormalDist(double mean, double stdDev); namespace webrtc { class RtpDump; @@ -64,7 +65,7 @@ namespace webrtc 2. EncodeComplete callback: 2a. Transfer encoded data directly to the decoder 2b. Pass encoded data via the RTP module - 3. Caluclate PSNR from file function (for now: does not deal with frame drops) + 3. Calculate PSNR from file function (for now: does not deal with frame drops) */ // Send Side - Packetization callback - send an encoded frame to the VCMReceiver @@ -215,9 +216,11 @@ public: int SendCount() {return _sendCount; } // Return accumulated length in bytes of transmitted packets WebRtc_UWord32 TotalSentLength() {return _totalSentLength;} -private: +protected: // Randomly decide whether to drop packets, based on the channel model - bool PacketLoss(double lossPct); + bool PacketLoss(); + // Random uniform loss model + bool UnifomLoss(double lossPct); WebRtc_UWord32 _sendCount; webrtc::RtpRtcp* _rtp; @@ -231,27 +234,6 @@ private: webrtc::RtpDump* _rtpDump; }; -// Used in multi thread test -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; -}; - class PacketRequester: public webrtc::VCMPacketRequestCallback { public: