Home | History | Annotate | Download | only in test
      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