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