blob: 21b9f737bb88beaebefca9711a9e084396eded05 [file] [log] [blame]
/*
* 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;
}