| /* |
| * 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; |
| int64_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(nullptr); |
| 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); |
| rtc::scoped_ptr<RTPPayloadRegistry> registry( |
| new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(false))); |
| rtc::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) |
| { |
| mainSenderThread->Start(); |
| } |
| else |
| { |
| printf("Unable to start main sender thread\n"); |
| return -1; |
| } |
| |
| if (intSenderThread != NULL) |
| { |
| intSenderThread->Start(); |
| } |
| 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) |
| { |
| processingThread->Start(); |
| } |
| else |
| { |
| printf("Unable to start processing thread\n"); |
| return -1; |
| } |
| |
| if (decodeThread != NULL) |
| { |
| decodeThread->Start(); |
| } |
| 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; |
| |
| } |