1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 /************************************************* 12 * 13 * Testing multi thread - receive and send sides 14 * 15 **************************************************/ 16 17 #include <string.h> 18 19 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h" 20 #include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h" 21 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" 22 #include "webrtc/modules/video_coding/main/interface/video_coding.h" 23 #include "webrtc/modules/video_coding/main/test/media_opt_test.h" 24 #include "webrtc/modules/video_coding/main/test/mt_test_common.h" 25 #include "webrtc/modules/video_coding/main/test/receiver_tests.h" 26 #include "webrtc/modules/video_coding/main/test/test_macros.h" 27 #include "webrtc/modules/video_coding/main/test/test_util.h" 28 #include "webrtc/system_wrappers/interface/thread_wrapper.h" 29 #include "webrtc/test/testsupport/fileutils.h" 30 31 using namespace webrtc; 32 33 bool 34 MainSenderThread(void* obj) 35 { 36 SendSharedState* state = static_cast<SendSharedState*>(obj); 37 EventWrapper& waitEvent = *EventWrapper::Create(); 38 // preparing a frame for encoding 39 I420VideoFrame sourceFrame; 40 int32_t width = state->_args.width; 41 int32_t height = state->_args.height; 42 float frameRate = state->_args.frameRate; 43 int32_t lengthSourceFrame = 3*width*height/2; 44 uint8_t* tmpBuffer = new uint8_t[lengthSourceFrame]; 45 46 if (state->_sourceFile == NULL) 47 { 48 state->_sourceFile = fopen(state->_args.inputFile.c_str(), "rb"); 49 if (state->_sourceFile == NULL) 50 { 51 printf ("Error when opening file \n"); 52 delete &waitEvent; 53 delete [] tmpBuffer; 54 return false; 55 } 56 } 57 if (feof(state->_sourceFile) == 0) 58 { 59 TEST(fread(tmpBuffer, 1, lengthSourceFrame,state->_sourceFile) > 0 || 60 feof(state->_sourceFile)); 61 state->_frameCnt++; 62 int size_y = width * height; 63 int half_width = (width + 1) / 2; 64 int half_height = (height + 1) / 2; 65 int size_uv = half_width * half_height; 66 sourceFrame.CreateFrame(size_y, tmpBuffer, 67 size_uv, tmpBuffer + size_y, 68 size_uv, tmpBuffer + size_y + size_uv, 69 width, height, 70 width, half_width, half_width); 71 state->_timestamp += (uint32_t)(9e4 / frameRate); 72 sourceFrame.set_timestamp(state->_timestamp); 73 74 int32_t ret = state->_vcm.AddVideoFrame(sourceFrame); 75 if (ret < 0) 76 { 77 printf("Add Frame error: %d\n", ret); 78 delete &waitEvent; 79 delete [] tmpBuffer; 80 return false; 81 } 82 waitEvent.Wait(33); 83 } 84 85 delete &waitEvent; 86 delete [] tmpBuffer; 87 88 return true; 89 } 90 91 bool 92 IntSenderThread(void* obj) 93 { 94 SendSharedState* state = static_cast<SendSharedState*>(obj); 95 state->_vcm.SetChannelParameters(1000000,30,0); 96 97 return true; 98 } 99 100 101 int MTRxTxTest(CmdArgs& args) 102 { 103 /* TEST SETTINGS */ 104 std::string inname = args.inputFile; 105 std::string outname; 106 if (args.outputFile == "") 107 outname = test::OutputPath() + "MTRxTxTest_decoded.yuv"; 108 else 109 outname = args.outputFile; 110 111 uint16_t width = args.width; 112 uint16_t height = args.height; 113 114 float frameRate = args.frameRate; 115 float bitRate = args.bitRate; 116 int32_t numberOfCores = 1; 117 118 // error resilience/network 119 // Nack support is currently not implemented in this test. 120 bool nackEnabled = false; 121 bool fecEnabled = false; 122 uint8_t rttMS = 20; 123 float lossRate = 0.0*255; // no packet loss 124 uint32_t renderDelayMs = 0; 125 uint32_t minPlayoutDelayMs = 0; 126 127 /* TEST SET-UP */ 128 129 // Set up trace 130 Trace::CreateTrace(); 131 Trace::SetTraceFile((test::OutputPath() + "MTRxTxTestTrace.txt").c_str()); 132 Trace::set_level_filter(webrtc::kTraceAll); 133 134 FILE* sourceFile; 135 FILE* decodedFile; 136 137 if ((sourceFile = fopen(inname.c_str(), "rb")) == NULL) 138 { 139 printf("Cannot read file %s.\n", inname.c_str()); 140 return -1; 141 } 142 143 if ((decodedFile = fopen(outname.c_str(), "wb")) == NULL) 144 { 145 printf("Cannot read file %s.\n", outname.c_str()); 146 return -1; 147 } 148 VideoCodingModule* vcm = VideoCodingModule::Create(); 149 RtpDataCallback dataCallback(vcm); 150 151 RTPSendCompleteCallback* outgoingTransport = 152 new RTPSendCompleteCallback(Clock::GetRealTimeClock(), "dump.rtp"); 153 154 RtpRtcp::Configuration configuration; 155 configuration.id = 1; 156 configuration.audio = false; 157 configuration.outgoing_transport = outgoingTransport; 158 RtpRtcp* rtp = RtpRtcp::CreateRtpRtcp(configuration); 159 scoped_ptr<RTPPayloadRegistry> registry(new RTPPayloadRegistry( 160 RTPPayloadStrategy::CreateStrategy(false))); 161 scoped_ptr<RtpReceiver> rtp_receiver( 162 RtpReceiver::CreateVideoReceiver(-1, Clock::GetRealTimeClock(), 163 &dataCallback, NULL, registry.get())); 164 165 // registering codecs for the RTP module 166 VideoCodec video_codec; 167 strncpy(video_codec.plName, "ULPFEC", 32); 168 video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE; 169 TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName, 170 video_codec.plType, 171 90000, 172 0, 173 video_codec.maxBitrate) == 0); 174 175 strncpy(video_codec.plName, "RED", 32); 176 video_codec.plType = VCM_RED_PAYLOAD_TYPE; 177 TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName, 178 video_codec.plType, 179 90000, 180 0, 181 video_codec.maxBitrate) == 0); 182 183 strncpy(video_codec.plName, args.codecName.c_str(), 32); 184 video_codec.plType = VCM_VP8_PAYLOAD_TYPE; 185 video_codec.maxBitrate = 10000; 186 video_codec.codecType = args.codecType; 187 TEST(rtp_receiver->RegisterReceivePayload(video_codec.plName, 188 video_codec.plType, 189 90000, 190 0, 191 video_codec.maxBitrate) == 0); 192 TEST(rtp->RegisterSendPayload(video_codec) == 0); 193 194 // inform RTP Module of error resilience features 195 TEST(rtp->SetGenericFECStatus(fecEnabled, VCM_RED_PAYLOAD_TYPE, 196 VCM_ULPFEC_PAYLOAD_TYPE) == 0); 197 198 //VCM 199 if (vcm->InitializeReceiver() < 0) 200 { 201 return -1; 202 } 203 if (vcm->InitializeSender()) 204 { 205 return -1; 206 } 207 // registering codecs for the VCM module 208 VideoCodec sendCodec; 209 vcm->InitializeSender(); 210 int32_t numberOfCodecs = vcm->NumberOfCodecs(); 211 if (numberOfCodecs < 1) 212 { 213 return -1; 214 } 215 216 if (vcm->Codec(args.codecType, &sendCodec) != 0) 217 { 218 // desired codec unavailable 219 printf("Codec not registered\n"); 220 return -1; 221 } 222 // register codec 223 sendCodec.startBitrate = (int) bitRate; 224 sendCodec.height = height; 225 sendCodec.width = width; 226 sendCodec.maxFramerate = (uint8_t)frameRate; 227 vcm->RegisterSendCodec(&sendCodec, numberOfCores, 1440); 228 vcm->RegisterReceiveCodec(&sendCodec, numberOfCores); // same settings for encode and decode 229 230 vcm->SetRenderDelay(renderDelayMs); 231 vcm->SetMinimumPlayoutDelay(minPlayoutDelayMs); 232 233 // Callback Settings 234 235 PacketRequester packetRequester(*rtp); 236 vcm->RegisterPacketRequestCallback(&packetRequester); 237 238 VCMRTPEncodeCompleteCallback* encodeCompleteCallback = new VCMRTPEncodeCompleteCallback(rtp); 239 vcm->RegisterTransportCallback(encodeCompleteCallback); 240 encodeCompleteCallback->SetCodecType(ConvertCodecType(args.codecName.c_str())); 241 encodeCompleteCallback->SetFrameDimensions(width, height); 242 // frame ready to be sent to network 243 244 VCMDecodeCompleteCallback receiveCallback(decodedFile); 245 vcm->RegisterReceiveCallback(&receiveCallback); 246 247 VideoProtectionCallback protectionCallback; 248 vcm->RegisterProtectionCallback(&protectionCallback); 249 250 outgoingTransport->SetLossPct(lossRate); 251 // Nack support is currently not implemented in this test 252 assert(nackEnabled == false); 253 vcm->SetVideoProtection(kProtectionNack, nackEnabled); 254 vcm->SetVideoProtection(kProtectionFEC, fecEnabled); 255 256 // inform RTP Module of error resilience features 257 FecProtectionParams delta_params = protectionCallback.DeltaFecParameters(); 258 FecProtectionParams key_params = protectionCallback.KeyFecParameters(); 259 rtp->SetFecParameters(&delta_params, &key_params); 260 rtp_receiver->SetNACKStatus(nackEnabled ? kNackRtcp : kNackOff); 261 262 vcm->SetChannelParameters(static_cast<uint32_t>(1000 * bitRate), 263 (uint8_t) lossRate, rttMS); 264 265 SharedRTPState mtState(*vcm, *rtp); // receive side 266 SendSharedState mtSendState(*vcm, *rtp, args); // send side 267 268 /*START TEST*/ 269 270 // Create and start all threads 271 // send side threads 272 ThreadWrapper* mainSenderThread = ThreadWrapper::CreateThread(MainSenderThread, 273 &mtSendState, kNormalPriority, "MainSenderThread"); 274 ThreadWrapper* intSenderThread = ThreadWrapper::CreateThread(IntSenderThread, 275 &mtSendState, kNormalPriority, "IntThread"); 276 277 if (mainSenderThread != NULL) 278 { 279 unsigned int tid; 280 mainSenderThread->Start(tid); 281 } 282 else 283 { 284 printf("Unable to start main sender thread\n"); 285 return -1; 286 } 287 288 if (intSenderThread != NULL) 289 { 290 unsigned int tid; 291 intSenderThread->Start(tid); 292 } 293 else 294 { 295 printf("Unable to start sender interference thread\n"); 296 return -1; 297 } 298 299 // Receive side threads 300 ThreadWrapper* processingThread = ThreadWrapper::CreateThread(ProcessingThread, 301 &mtState, kNormalPriority, "ProcessingThread"); 302 ThreadWrapper* decodeThread = ThreadWrapper::CreateThread(DecodeThread, 303 &mtState, kNormalPriority, "DecodeThread"); 304 305 if (processingThread != NULL) 306 { 307 unsigned int tid; 308 processingThread->Start(tid); 309 } 310 else 311 { 312 printf("Unable to start processing thread\n"); 313 return -1; 314 } 315 316 if (decodeThread != NULL) 317 { 318 unsigned int tid; 319 decodeThread->Start(tid); 320 } 321 else 322 { 323 printf("Unable to start decode thread\n"); 324 return -1; 325 } 326 327 EventWrapper& waitEvent = *EventWrapper::Create(); 328 329 // Decode for 10 seconds and then tear down and exit. 330 waitEvent.Wait(30000); 331 332 // Tear down 333 334 while (!mainSenderThread->Stop()) 335 { 336 ; 337 } 338 339 while (!intSenderThread->Stop()) 340 { 341 ; 342 } 343 344 345 while (!processingThread->Stop()) 346 { 347 ; 348 } 349 350 while (!decodeThread->Stop()) 351 { 352 ; 353 } 354 355 printf("\nVCM MT RX/TX Test: \n\n%i tests completed\n", vcmMacrosTests); 356 if (vcmMacrosErrors > 0) 357 { 358 printf("%i FAILED\n\n", vcmMacrosErrors); 359 } 360 else 361 { 362 printf("ALL PASSED\n\n"); 363 } 364 365 delete &waitEvent; 366 delete mainSenderThread; 367 delete intSenderThread; 368 delete processingThread; 369 delete decodeThread; 370 delete encodeCompleteCallback; 371 delete outgoingTransport; 372 VideoCodingModule::Destroy(vcm); 373 delete rtp; 374 rtp = NULL; 375 vcm = NULL; 376 Trace::ReturnTrace(); 377 fclose(decodedFile); 378 printf("Multi-Thread test Done: View output file \n"); 379 return 0; 380 381 } 382