| /* |
| * 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. |
| */ |
| |
| #include "receiver_tests.h" |
| #include "video_coding.h" |
| #include "rtp_rtcp.h" |
| #include "trace.h" |
| #include "thread_wrapper.h" |
| #include "../source/event.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 |
| TickTimeBase clock; |
| if (state->_rtpPlayer.NextPacket(clock.MillisecondTimestamp()) < 0) |
| { |
| return false; |
| } |
| waitEvent.Wait(state->_rtpPlayer.TimeUntilNextPacket()); |
| delete &waitEvent; |
| return true; |
| } |
| |
| bool DecodeThread(void* obj) |
| { |
| SharedState* state = static_cast<SharedState*>(obj); |
| 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 events. |
| #if 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 = test::OutputPath() + "RtpPlayMT_decoded.yuv"; |
| |
| bool nackEnabled = (protectionEnabled && |
| (protection == kProtectionDualDecoder || |
| protection == kProtectionNack || |
| kProtectionNackFEC)); |
| TickTimeBase clock; |
| VideoCodingModule* vcm = |
| VideoCodingModule::Create(1, &clock); |
| 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 = test::OutputPath() + "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, &clock); |
| PayloadTypeList payloadTypes; |
| payloadTypes.push_front(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 |
| for (PayloadTypeList::iterator it = payloadTypes.begin(); |
| it != payloadTypes.end(); ++it) { |
| PayloadCodecTuple* payloadType = *it; |
| if (payloadType != NULL) |
| { |
| VideoCodec codec; |
| VideoCodingModule::Codec(payloadType->codecType, &codec); |
| codec.plType = payloadType->payloadType; |
| if (vcm->RegisterReceiveCodec(&codec, 1) < 0) |
| { |
| return -1; |
| } |
| } |
| } |
| |
| 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 |
| while (!payloadTypes.empty()) |
| { |
| delete payloadTypes.front(); |
| payloadTypes.pop_front(); |
| } |
| 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; |
| } |