• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
MainSenderThread(void * obj)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
IntSenderThread(void * obj)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 
MTRxTxTest(CmdArgs & args)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