blob: d0a39ad67fcf44bfa6cf95556fbd25f31d866ac1 [file] [log] [blame]
/*
* 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.
*/
/*************************************************
*
* 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;
}
//RTP
RtpRtcp* rtp = RtpRtcp::CreateRtpRtcp(1, false);
if (rtp->InitReceiver() < 0)
{
return -1;
}
if (rtp->InitSender() < 0)
{
return -1;
}
// 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
TickTimeBase clock;
VideoCodingModule* vcm = VideoCodingModule::Create(1, &clock);
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
RTPSendCompleteCallback* outgoingTransport =
new RTPSendCompleteCallback(rtp, &clock, "dump.rtp");
rtp->RegisterSendTransport(outgoingTransport);
// FrameReceiveCallback
VCMDecodeCompleteCallback receiveCallback(decodedFile);
RtpDataCallback dataCallback(vcm);
rtp->RegisterIncomingDataCallback(&dataCallback);
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
rtp->SetFECCodeRate(protectionCallback.FECKeyRate(),
protectionCallback.FECDeltaRate());
rtp->SetNACKStatus(protectionCallback.NACKMethod());
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);
RtpRtcp::DestroyRtpRtcp(rtp);
rtp = NULL;
vcm = NULL;
Trace::ReturnTrace();
fclose(decodedFile);
printf("Multi-Thread test Done: View output file \n");
return 0;
}