272 lines
7.4 KiB
C++
272 lines
7.4 KiB
C++
|
/*
|
||
|
* 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 "rtp_rtcp.h"
|
||
|
#include "trace.h"
|
||
|
#include "thread_wrapper.h"
|
||
|
#include "../source/event.h"
|
||
|
#include "tick_time.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
|
||
|
WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp();
|
||
|
if (state->_rtpPlayer.NextPacket(nowMs) < 0)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
waitEvent.Wait(state->_rtpPlayer.TimeUntilNextPacket());
|
||
|
delete &waitEvent;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool DecodeThread(void* obj)
|
||
|
{
|
||
|
SharedState* state = static_cast<SharedState*>(obj);
|
||
|
WebRtc_Word32 ret = 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 time
|
||
|
#if defined(TICK_TIME_DEBUG) || 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 = "RtpPlayMT_decoded.yuv";
|
||
|
|
||
|
bool nackEnabled = (protectionEnabled &&
|
||
|
(protection == kProtectionDualDecoder ||
|
||
|
protection == kProtectionNack ||
|
||
|
kProtectionNackFEC));
|
||
|
VideoCodingModule* vcm =
|
||
|
VideoCodingModule::Create(1);
|
||
|
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 = "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);
|
||
|
ListWrapper payloadTypes;
|
||
|
payloadTypes.PushFront(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
|
||
|
ListItem* item = payloadTypes.First();
|
||
|
while (item != NULL)
|
||
|
{
|
||
|
PayloadCodecTuple* payloadType = static_cast<PayloadCodecTuple*>(item->GetItem());
|
||
|
if (payloadType != NULL)
|
||
|
{
|
||
|
VideoCodec codec;
|
||
|
VideoCodingModule::Codec(payloadType->codecType, &codec);
|
||
|
codec.plType = payloadType->payloadType;
|
||
|
if (vcm->RegisterReceiveCodec(&codec, 1) < 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
item = payloadTypes.Next(item);
|
||
|
}
|
||
|
|
||
|
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
|
||
|
item = payloadTypes.First();
|
||
|
while (item != NULL)
|
||
|
{
|
||
|
PayloadCodecTuple* payloadType = static_cast<PayloadCodecTuple*>(item->GetItem());
|
||
|
if (payloadType != NULL)
|
||
|
{
|
||
|
delete payloadType;
|
||
|
}
|
||
|
ListItem* itemToRemove = item;
|
||
|
item = payloadTypes.Next(item);
|
||
|
payloadTypes.Erase(itemToRemove);
|
||
|
}
|
||
|
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;
|
||
|
}
|