/* * 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 using namespace webrtc; bool ProcessingThread(void* obj) { SharedState* state = static_cast(obj); if (state->_vcm.TimeUntilNextProcess() <= 0) { if (state->_vcm.Process() < 0) { return false; } } return true; } bool RtpReaderThread(void* obj) { SharedState* state = static_cast(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(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(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(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; }