blob: 35cd1f3850fb93d5cbe6a1370d68d7e7069d1bd1 [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.
*/
/*************************************************
*
* Testing multi thread - receive and send sides
*
**************************************************/
#include <string.h>
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_coding/main/test/media_opt_test.h"
#include "webrtc/modules/video_coding/main/test/mt_test_common.h"
#include "webrtc/modules/video_coding/main/test/receiver_tests.h"
#include "webrtc/modules/video_coding/main/test/test_macros.h"
#include "webrtc/modules/video_coding/main/test/test_util.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/test/testsupport/fileutils.h"
using namespace webrtc;
bool
MainSenderThread(void* obj)
{
SendSharedState* state = static_cast<SendSharedState*>(obj);
EventWrapper& waitEvent = *EventWrapper::Create();
// preparing a frame for encoding
I420VideoFrame sourceFrame;
int32_t width = state->_args.width;
int32_t height = state->_args.height;
float frameRate = state->_args.frameRate;
int32_t lengthSourceFrame = 3*width*height/2;
uint8_t* tmpBuffer = new uint8_t[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++;
int size_y = width * height;
int half_width = (width + 1) / 2;
int half_height = (height + 1) / 2;
int size_uv = half_width * half_height;
sourceFrame.CreateFrame(size_y, tmpBuffer,
size_uv, tmpBuffer + size_y,
size_uv, tmpBuffer + size_y + size_uv,
width, height,
width, half_width, half_width);
state->_timestamp += (uint32_t)(9e4 / frameRate);
sourceFrame.set_timestamp(state->_timestamp);
int32_t 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(1000000,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;
uint16_t width = args.width;
uint16_t height = args.height;
float frameRate = args.frameRate;
float bitRate = args.bitRate;
int32_t numberOfCores = 1;
// error resilience/network
// Nack support is currently not implemented in this test.
bool nackEnabled = false;
bool fecEnabled = false;
uint8_t rttMS = 20;
float lossRate = 0.0*255; // no packet loss
uint32_t renderDelayMs = 0;
uint32_t minPlayoutDelayMs = 0;
/* TEST SET-UP */
// Set up trace
Trace::CreateTrace();
Trace::SetTraceFile((test::OutputPath() + "MTRxTxTestTrace.txt").c_str());
Trace::set_level_filter(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;
}
VideoCodingModule* vcm = VideoCodingModule::Create();
RtpDataCallback dataCallback(vcm);
RTPSendCompleteCallback* outgoingTransport =
new RTPSendCompleteCallback(Clock::GetRealTimeClock(), "dump.rtp");
RtpRtcp::Configuration configuration;
configuration.id = 1;
configuration.audio = false;
configuration.outgoing_transport = outgoingTransport;
RtpRtcp* rtp = RtpRtcp::CreateRtpRtcp(configuration);
scoped_ptr<RTPPayloadRegistry> registry(new RTPPayloadRegistry(
RTPPayloadStrategy::CreateStrategy(false)));
scoped_ptr<RtpReceiver> rtp_receiver(
RtpReceiver::CreateVideoReceiver(-1, Clock::GetRealTimeClock(),
&dataCallback, NULL, registry.get()));
// registering codecs for the RTP module
VideoCodec video_codec;
strncpy(video_codec.plName, "ULPFEC", 32);
video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
video_codec.plType,
90000,
0,
video_codec.maxBitrate) == 0);
strncpy(video_codec.plName, "RED", 32);
video_codec.plType = VCM_RED_PAYLOAD_TYPE;
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
video_codec.plType,
90000,
0,
video_codec.maxBitrate) == 0);
strncpy(video_codec.plName, args.codecName.c_str(), 32);
video_codec.plType = VCM_VP8_PAYLOAD_TYPE;
video_codec.maxBitrate = 10000;
video_codec.codecType = args.codecType;
TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName,
video_codec.plType,
90000,
0,
video_codec.maxBitrate) == 0);
TEST(rtp->RegisterSendPayload(video_codec) == 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();
int32_t 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 = (uint8_t)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_receiver->SetNACKStatus(nackEnabled ? kNackRtcp : kNackOff);
vcm->SetChannelParameters(static_cast<uint32_t>(1000 * bitRate),
(uint8_t) 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;
}