2
* GPAC - Multimedia Framework C SDK
4
* Copyright (c) Cyril Concolato / Jean Le Feuvre 2000-2005
7
* This file is part of GPAC / mp4 simple streamer application
9
* GPAC is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU Lesser General Public License as published by
11
* the Free Software Foundation; either version 2, or (at your option)
14
* GPAC is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU Lesser General Public License for more details.
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with this library; see the file COPYING. If not, write to
21
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25
//------------------------------------------------------------
27
//------------------------------------------------------------
31
#include <gpac/constants.h>
32
#include <gpac/isomedia.h>
33
#include <gpac/ietf.h>
34
#include <gpac/internal/ietf_dev.h>
35
#include <gpac/config.h>
36
#include <gpac/thread.h>
39
//------------------------------------------------------------
41
//------------------------------------------------------------
43
#define RTP_HEADER_SIZE 12 // in bytes (octets)
45
//------------------------------------------------------------
46
// Declaration of static variables
47
//------------------------------------------------------------
48
u32 sov_numberBurstSent = 0; // toutes sessions confondues
49
u32 sov_timeOffset = 0; // time when the first burts was sent. this time <=> (CTS=0)
51
//------------------------------------------------------------
53
//------------------------------------------------------------
57
u32 sov_burstDuration;
59
u32 sov_delay_offtime;
61
char * sop_ip; // destination ip
62
u32 *sop_portTable; // port of each session
63
char **sop_fileTable; // filename of each session
64
u32 *sop_trackNbTable; // track id of each session
65
u32 *sop_looping; // 1 play in a loop, 0 play once
69
u32 ov_timeOrigin; // origin of main.c ( = 0)
72
u32 sov_numberPacketSent;
85
u32 bitRate; // of the media
89
u32 maxSizeBurst; // max size to fill the burst with the media bitRate
90
u32 physicalBitRate; // cf definition in checkConfiguration
91
u32 looping; // 1: play the media in a loop, 0 play once
94
u32 accessUnitProcess; // number of the AU to process. set to 0 at the beginnning
96
u32 dataLengthInBurst; // total length filled in current burst
97
u64 totalLengthSent; // total length sent to channel
100
GF_RTPChannel *channel;
101
GP_RTPPacketizer *packetizer;
102
GF_List *packets_to_send;
103
GF_ISOSample *accessUnit; // the AU
106
/* The current packet being formed */
110
u32 payload_valid_len;
114
GF_Thread *thread; // thread of session 1 is not used
118
//------------------------------------------------------------
122
//------------------------------------------------------------
126
* sets the offset time, ie the time when the very first burst was sent
127
* ==> allows to syncrhonise the CTS time unit to the system time
130
void setOffsetTime(u32 av_offsetTime)
132
sov_timeOffset = av_offsetTime;
137
* is called when the first burst of the session 1 is sent
138
* sets the nextBurstTime
139
* -> session 1: offset + offTime
140
* -> other: offset + (id -1) * offTime
143
void initTimeManagement(RTP_Caller *ap_caller)
144
{ // set the time when CTS = 0
145
if(ap_caller->id == 1)
147
ap_caller->nextBurstTime = sov_timeOffset +ap_caller->global->sov_burstDuration + ap_caller->global->sov_delay_offtime;
151
ap_caller->nextBurstTime = sov_timeOffset + (ap_caller->id - 1)* ap_caller->global->sov_burstDuration;
153
//fprintf(stdout,"mp4 streamer: [initMgtTime] _id %u _currentTime %u _nextBurstTime %u\n",ap_caller->id, gf_sys_clock(),ap_caller->nextBurstTime);
159
* is called in OnPacketDone just before the burst is sent
160
* sets the nextBurstTime of the given session
163
void setNextBurstTime(RTP_Caller *ap_caller)
165
ap_caller->nextBurstTime = gf_sys_clock() + ap_caller->global->sov_burstDuration + ap_caller->global->sov_delay_offtime;
166
//fprintf(stdout,"mp4 streamer: [setNextBurstTime] _id %u _currentTime %u _nextBurstTime %u\n",ap_caller->id, gf_sys_clock(),ap_caller->nextBurstTime);
176
static void OnNewPacket(void *cbk, GF_RTPHeader *header)
178
RTP_Caller *caller = cbk;
180
memcpy(&caller->header, header, sizeof(GF_RTPHeader));
181
//fprintf(stdout, "mp4 streamer: [ONP] _session %u\n", caller->id);
184
static void OnPacketDone(void *cbk, GF_RTPHeader *header)
186
RTP_Caller *caller = cbk;
187
u32 lv_nextBurstTime; // date du prochain envoie du burst normalement
188
u32 lv_sizeSent; // taille totale des paquets envoy�s pour le burst courant (bits)
191
lv_nextBurstTime = caller->nextBurstTime; // time of next burst to play
192
caller->global->ov_currentTime = gf_sys_clock();// gets system clock (current time)
194
//fprintf(stdout,"[OPD] _id %u _AU %u _currentTime %u _nextBursTime %u\n",caller->id, caller->accessUnitProcess, caller->global->ov_currentTime, lv_nextBurstTime);
197
* Check for the first burst sending
198
* ==> allows to set the time of the first sending and start threads
202
if(sov_numberBurstSent == 0 && (caller->id == 1))
204
u32 lv_totalLengthFilled =0; // in bits
206
u32 lv_packetCount=0;
207
u32 lv_currentPacketSize; // in bits
210
GF_SAFEALLOC(tmp, sizeof(RTP_Packet));
211
memcpy(&tmp->header, header, sizeof(GF_RTPHeader));
212
tmp->payload = caller->payload;
213
caller->payload = NULL;
214
tmp->payload_len = caller->payload_len;
215
caller->payload_len = 0;
216
caller->payload_valid_len = 0;
218
lv_packetCount = gf_list_count(caller->packets_to_send);
219
lv_currentPacketSize = (tmp->payload_len + RTP_HEADER_SIZE) * 8; // in bits
221
if(lv_packetCount == 0)
223
lv_totalLengthFilled += lv_currentPacketSize;
227
for (i=0;i< lv_packetCount;i++)
229
RTP_Packet *lp_buffer;
230
lp_buffer = gf_list_get(caller->packets_to_send, i);
231
lv_totalLengthFilled += (lp_buffer->payload_len + RTP_HEADER_SIZE) * 8;
233
lv_totalLengthFilled += lv_currentPacketSize;
236
if( lv_totalLengthFilled >= caller->maxSizeBurst )
237
{ // send the RTP packets in gf_list
238
setOffsetTime(caller->global->ov_currentTime ); /* SPECIFIC TO THE FIRST SESSION */
239
if(lv_packetCount == 0) // hardly ever happens...
241
caller->totalLengthSent += (tmp->payload_len * 8);
242
gf_rtp_send_packet(caller->channel, &tmp->header, 0, 0, tmp->payload, tmp->payload_len);
247
for (i=0;i<= lv_packetCount -1 ;i++)
249
RTP_Packet *rtp = gf_list_get(caller->packets_to_send, i);
250
caller->totalLengthSent += (rtp->payload_len * 8) ; // update the total length
251
gf_rtp_send_packet(caller->channel, &rtp->header, 0, 0, rtp->payload, rtp->payload_len);
254
gf_list_reset(caller->packets_to_send);
256
sov_numberBurstSent++;
257
fprintf(stdout, "[OPD SEN] 1st burstSent _pktSize %u _totSize %u _nbBurstSent %u _offtime %u\n", lv_currentPacketSize, lv_totalLengthFilled, sov_numberBurstSent, gf_sys_clock() );
262
//fprintf(stdout, "[OPD STO] 1st rtp store _pktSize %u _totSize %u\n", lv_currentPacketSize, lv_totalLengthFilled);
264
gf_list_add(caller->packets_to_send, tmp); // store the last packet not sent
266
} // end if first packet of session n�1
269
u32 lv_totalLengthFilled =0; // in bits
271
u32 lv_packetCount=0;
272
u32 lv_currentPacketSize; // in bits
275
GF_SAFEALLOC(tmp, sizeof(RTP_Packet));
276
memcpy(&tmp->header, header, sizeof(GF_RTPHeader));
277
tmp->payload = caller->payload;
278
caller->payload = NULL;
279
tmp->payload_len = caller->payload_len;
280
caller->payload_len = 0;
281
caller->payload_valid_len = 0;
283
lv_packetCount = gf_list_count(caller->packets_to_send);
284
lv_currentPacketSize = (tmp->payload_len + RTP_HEADER_SIZE )*8;
285
if(lv_packetCount == 0)
287
lv_totalLengthFilled += lv_currentPacketSize;
291
for (i=0;i< lv_packetCount;i++)
293
RTP_Packet *lp_buffer;
294
lp_buffer = gf_list_get(caller->packets_to_send, i);
295
lv_totalLengthFilled += (lp_buffer->payload_len + RTP_HEADER_SIZE)*8 ;
297
lv_totalLengthFilled += lv_currentPacketSize;
300
if( lv_totalLengthFilled >= caller->maxSizeBurst )
301
{ // send the RTP packets in gf_list
304
lv_sleep = caller->nextBurstTime - caller->global->ov_currentTime;
305
if ((int)lv_sleep <0)
308
fprintf(stdout,"mp4 streamer: ERROR sleep <0: nextBurstTime %u CurrentTime %u Offset %u\n",caller->nextBurstTime, caller->global->ov_currentTime, sov_timeOffset );
311
gf_sleep(lv_sleep); // sleep and send the burst
313
setNextBurstTime(caller); // time management
315
if(lv_packetCount == 0)
317
caller->totalLengthSent += (tmp->payload_len)*8;
318
gf_rtp_send_packet(caller->channel, &tmp->header, 0, 0, tmp->payload, tmp->payload_len);
323
for (i=0;i<= lv_packetCount -1 ;i++)
325
RTP_Packet *rtp = gf_list_get(caller->packets_to_send, i);
326
caller->totalLengthSent += (rtp->payload_len)*8; // update the total length
327
gf_rtp_send_packet(caller->channel, &rtp->header, 0, 0, rtp->payload, rtp->payload_len);
330
gf_list_reset(caller->packets_to_send);
332
sov_numberBurstSent++;
333
fprintf(stdout, "[OPD SEN] _id %u _pktSize %u _totSize %u _nbBurstSent %u _nbPkt in Burst %u\n", caller->id, lv_currentPacketSize, lv_totalLengthFilled, sov_numberBurstSent,lv_packetCount);
338
//fprintf(stdout, "[OPD STO] _id %u _pktSize %u _totSize %u _nbPkt in Burst %u \n", caller->id, lv_currentPacketSize, lv_totalLengthFilled, lv_packetCount);
340
gf_list_add(caller->packets_to_send, tmp); // store the last packet not sent
345
static void OnData(void *cbk, char *data, u32 data_size, Bool is_head)
347
RTP_Caller *caller = cbk;
348
if (!data ||!data_size) return;
350
if (!caller->payload_len) {
351
caller->payload = malloc(data_size);
352
memcpy(caller->payload, data, data_size);
353
caller->payload_len = caller->payload_valid_len = data_size;
355
if (caller->payload_valid_len + data_size > caller->payload_len) {
356
caller->payload = realloc(caller->payload, caller->payload_valid_len + data_size);
357
caller->payload_len = caller->payload_valid_len + data_size;
360
memcpy(caller->payload+caller->payload_valid_len, data, data_size);
362
memmove(caller->payload+data_size, caller->payload, caller->payload_valid_len);
363
memcpy(caller->payload, data, data_size);
365
caller->payload_valid_len += data_size;
370
static u32 payload_type = 96;
372
GF_Err rtp_init_packetizer(RTP_Caller *caller)
376
caller->packetizer = gf_rtp_builder_new(GP_RTP_PAYT_MPEG4, NULL, GP_RTP_PCK_SIGNAL_RAP, caller, OnNewPacket, OnPacketDone, NULL, OnData);
377
gf_rtp_builder_init(caller->packetizer, payload_type, 1500, 0,
378
/*stream type*/5, /*objecttypeindication */107,
379
0, 0, 0, 0, 0, 0, 0, NULL);
382
/* regarder hint_track.c pour cr�er un SDP entier */
383
gf_rtp_builder_format_sdp(caller->packetizer, "mpeg4-generic", sdp_fmt, NULL, 0);
384
//fprintf(stdout, "init_packetizer [SDP]: %s\n", sdp_fmt);
386
caller->packetizer->rtp_header.Version = 2;
387
caller->packetizer->rtp_header.SSRC = rand();//RandomNumber identifiant la source
390
} /* rtp_init_packetizer */
392
GF_Err rtp_init_channel(GF_RTPChannel **chan, char * dest, int port)
398
*chan = gf_rtp_new();
399
gf_rtp_set_ports(*chan);
402
tr.Profile="RTP/AVP";//RTSP_PROFILE_RTP_AVP;
403
tr.destination = dest;
404
tr.source = "0.0.0.0";
409
tr.client_port_first = port; //RTP
410
tr.client_port_last = port+1; //RTCP (not used a priori)
412
tr.port_first = (*chan)->net_info.port_first; //RTP other end
413
tr.port_last = (*chan)->net_info.port_last; //RTCP other end (not used a priori)
415
res = gf_rtp_setup_transport(*chan, &tr, dest);
416
if (res !=0) return res;
418
gf_rtp_initialize(*chan, 0, 1, 1500, 0, 0, NULL);
419
if (res !=0) return res;
424
} /* rtp_init_channel */
426
// ---------------------------------------------------------------------------------------------------
429
* paquetization of a burst
430
* process the AUs till the burst size is reached.
434
void paquetisation(RTP_Caller *ap_caller, GF_ISOFile *ap_mp4)
437
u32 lv_accesUnitLength; // in bits
438
u32 lv_totalLengthFilled; // in bits
440
u32 lv_sampleDuration;
441
u8 lv_sampleDescIndex;
445
lv_accesUnitLength = 0;
446
lv_totalLengthFilled = 0;
447
lv_idSession = ap_caller->id;
448
lv_timescale = gf_isom_get_media_timescale(ap_mp4, ap_caller->global->sop_trackNbTable[lv_idSession-1]);
449
lv_auCount= gf_isom_get_sample_count(ap_mp4, ap_caller->global->sop_trackNbTable[lv_idSession-1]);
451
while (lv_totalLengthFilled <= ap_caller->maxSizeBurst)
453
if(ap_caller->accessUnitProcess + 1 <= lv_auCount) // attention overflow acceUnit number <= get_sample_count
455
ap_caller->accessUnit = gf_isom_get_sample(ap_mp4, ap_caller->global->sop_trackNbTable[lv_idSession-1], ap_caller->accessUnitProcess + 1, &lv_sampleDescIndex);
456
lv_accesUnitLength = ap_caller->accessUnit->dataLength * 8;
460
if( (lv_totalLengthFilled + lv_accesUnitLength) <= ap_caller->maxSizeBurst ) // OK
462
lv_totalLengthFilled += lv_accesUnitLength;
466
lv_totalLengthFilled += ap_caller->maxSizeBurst; // to quit the loop
469
// process AU till burst size + 1 AU
470
ap_caller->accessUnitProcess ++;
471
lv_sampleDuration = gf_isom_get_sample_duration(ap_mp4, ap_caller->global->sop_trackNbTable[lv_idSession-1], ap_caller->accessUnitProcess + 1);
473
lv_ts = (u64) ((90000 * (s64) (ap_caller->accessUnit->DTS + ap_caller->accessUnit->CTS_Offset)) / lv_timescale);
474
ap_caller->packetizer->sl_header.compositionTimeStamp = lv_ts;
476
lv_ts = (u64) ((90000 * ap_caller->accessUnit->DTS) / lv_timescale);
477
ap_caller->packetizer->sl_header.decodingTimeStamp = lv_ts;
479
ap_caller->packetizer->sl_header.randomAccessPointFlag = ap_caller->accessUnit->IsRAP;
481
gf_rtp_builder_process(ap_caller->packetizer, ap_caller->accessUnit->data, ap_caller->accessUnit->dataLength, 1,
482
ap_caller->accessUnit->dataLength, lv_sampleDuration, lv_sampleDescIndex);
483
gf_isom_sample_del(&ap_caller->accessUnit);
485
if( (lv_totalLengthFilled + lv_accesUnitLength) <= ap_caller->maxSizeBurst ) // OK
487
lv_totalLengthFilled += lv_accesUnitLength;
489
// process AU till burst size + 1 AU
490
ap_caller->accessUnitProcess ++;
491
lv_sampleDuration = gf_isom_get_sample_duration(ap_mp4, ap_caller->global->sop_trackNbTable[lv_idSession-1], ap_caller->accessUnitProcess + 1);
493
lv_ts = (u64) ((1000 * (s64) (ap_caller->accessUnit->DTS + ap_caller->accessUnit->CTS_Offset)) / lv_timescale);
494
ap_caller->packetizer->sl_header.compositionTimeStamp = lv_ts;
496
lv_ts = (u64) ((1000 * ap_caller->accessUnit->DTS) / lv_timescale);
497
ap_caller->packetizer->sl_header.decodingTimeStamp = lv_ts;
499
ap_caller->packetizer->sl_header.randomAccessPointFlag = ap_caller->accessUnit->IsRAP;
501
gf_rtp_builder_process(ap_caller->packetizer, ap_caller->accessUnit->data, ap_caller->accessUnit->dataLength, 1,
502
ap_caller->accessUnit->dataLength, lv_sampleDuration, lv_sampleDescIndex);
503
gf_isom_sample_del(&ap_caller->accessUnit);
507
lv_totalLengthFilled += ap_caller->maxSizeBurst; // to quit the loop
509
} // end if exist sample
512
lv_totalLengthFilled += ap_caller->maxSizeBurst;
516
//fprintf(stdout, "*********************************END PAQUETISATION Session %u* accesunit process %u********************************\n", lv_idSession, ap_caller->accessUnitProcess );
518
} /* paquetisation */
520
// ---------------------------------------------------------------------------------------------------
524
* retrieves the parameters in the configuration file
528
int configuration(Simulator *av_simulator, char *av_argv1)
530
char lv_config[1024]; /* cfg file name */
531
GF_Config *lp_configFile; /* Configuration file struct */
534
sprintf(lv_config,"%s",av_argv1); // copy the path
535
fprintf(stdout, "[configuration]---------------read the param---------------\n");
536
fprintf(stdout, "[configuration] file name: %s \n", lv_config);
538
lp_configFile = gf_cfg_new(PATHFILE,lv_config);
541
fprintf(stderr, "mp4 streamer ERROR: could not open the file\n");
545
av_simulator->sov_nbSessions = gf_cfg_get_section_count(lp_configFile) -1;
546
fprintf(stdout, "[configuration] nbSessions du fichier de config = %u \n", av_simulator->sov_nbSessions);
548
av_simulator->sop_ip = gf_cfg_get_key(lp_configFile, "GLOBAL", "IP_dest");
549
fprintf(stdout, "[configuration] IP destinataire= %s \n", av_simulator->sop_ip);
551
av_simulator->sov_delay_offtime = atoi(gf_cfg_get_key(lp_configFile, "GLOBAL", "delay_offtime"));
552
fprintf(stdout, "[configuration] delay offtime = %u ms \n", av_simulator->sov_delay_offtime);
554
av_simulator->sov_burstDuration = atoi(gf_cfg_get_key(lp_configFile, "GLOBAL", "burst_duration"));
555
fprintf(stdout, "[configuration] burst duration= %u ms \n", av_simulator->sov_burstDuration);
557
av_simulator->sov_peakBitRate = atoi(gf_cfg_get_key(lp_configFile, "GLOBAL", "peak_bit_rate"));
558
fprintf(stdout, "[configuration] peak bit rate= %u kbps \n", av_simulator->sov_peakBitRate);
560
// for each session: cfg file
561
av_simulator->sop_portTable = (u32 *)malloc(av_simulator->sov_nbSessions * sizeof(u32));
562
av_simulator->sop_trackNbTable = (u32 *)malloc(av_simulator->sov_nbSessions * sizeof(u32));
563
av_simulator->sop_fileTable = (char **)malloc(av_simulator->sov_nbSessions * sizeof(char *));
564
av_simulator->sop_looping = (u32 *)malloc(av_simulator->sov_nbSessions * sizeof(u32));
566
for(i=0; i<= av_simulator->sov_nbSessions - 1; i++)
568
char lv_sessionName[1024];
570
sprintf(lv_sessionName, "SESSION%d",i+1);
571
av_simulator->sop_fileTable[i] = (char *) malloc(512);
573
// retrieve parameters in cfg file
574
av_simulator->sop_fileTable[i] = gf_cfg_get_key(lp_configFile, lv_sessionName, "file");
575
av_simulator->sop_portTable[i] = atoi(gf_cfg_get_key(lp_configFile, lv_sessionName, "port"));
576
av_simulator->sop_trackNbTable[i] = atoi(gf_cfg_get_key(lp_configFile, lv_sessionName, "track_nb"));
577
av_simulator->sop_looping[i] = atoi(gf_cfg_get_key(lp_configFile, lv_sessionName, "looping"));
578
fprintf(stdout, "[configuration] _id %u _port %u _file %s _track %u \n",
579
i+1, av_simulator->sop_portTable[i], av_simulator->sop_fileTable[i], av_simulator->sop_trackNbTable[i]);
582
av_simulator->sov_numberPacketSent = 0;
583
av_simulator->sov_burstSize = av_simulator->sov_burstDuration * av_simulator->sov_peakBitRate; // size in bit
585
} /* configuration */
587
// ---------------------------------------------------------------------------------------------------
591
* called by a thread or in the main() for the 1st session
592
* 1 thread <=> 1 session
596
void timelineManagement(void *ap_caller)
598
u32 lv_sleepDuration; /* in ms */
599
int lv_sleepDurationInt; /* in ms */
600
u32 lv_currentTime; /* in ms */
601
u64 lv_totalLengthSent = 0; /* in bits */
602
u64 lv_mediaSize = 0; /* in bits */
605
RTP_Caller *lp_rtp = ap_caller;
607
// gets the size of the media
608
lv_idSession = lp_rtp->id;
609
lv_mediaSize = gf_isom_get_media_data_size(lp_rtp->mp4File, lp_rtp->global->sop_trackNbTable[lv_idSession-1]) *8 ; // size in bytes *8 = in bits
610
//fprintf(stdout, "mp4 streamer: id %u, length of the media: "LLD" bits trackBb %u\n", lv_idSession, lv_mediaSize,lp_rtp->global->sop_trackNbTable[lv_idSession-1] );
618
if(lp_rtp->looping != 1) // no looping
620
while((int)(lp_rtp->accessUnitProcess) <= (int)(lp_rtp->nbAccesUnit))
621
//while(lv_totalLengthSent <= lv_mediaSize) // --> does not work... stops the sending without any reasons
623
fprintf(stdout, "[MANAGEMENT TIMELINE]__________________________________\n");
624
fprintf(stdout, "[timeMgt] _id %u _AU %u \n", lp_rtp->id, lp_rtp->accessUnitProcess);
626
lv_currentTime = gf_sys_clock();
627
lv_sleepDuration = lp_rtp->nextBurstTime - 1000 - lv_currentTime; // (can be negative)
628
lv_sleepDurationInt = (int) lv_sleepDuration;
630
if(lv_sleepDurationInt <= 0) // begin the process now because sleepDuration is negative
632
//fprintf(stdout, "mp4 streamer: [timeMgt] pkt _id %u _nextBT %u _currentTime %u \n",lp_rtp->id, lp_rtp->nextBurstTime, lv_currentTime);
633
paquetisation(lp_rtp, lp_rtp->mp4File);
637
lv_sleepDuration = (u32) lv_sleepDurationInt;
638
//fprintf(stdout,"mp4 streamer: [timeMgt] sleep _id %u _dur %u _nextBT %u _currentTime %u\n",lp_rtp->id, lv_sleepDuration, lp_rtp->nextBurstTime, lv_currentTime);
639
gf_sleep(lv_sleepDuration);
640
paquetisation(lp_rtp, lp_rtp->mp4File);
642
lv_totalLengthSent += lp_rtp->totalLengthSent;
643
fprintf(stdout, "[timeMgt] _id %u _totalLengthSent "LLD"\n",lp_rtp->id,lv_totalLengthSent );
645
} // end if no looping
649
* Infinite loop ==> to send the media "en boucle"
655
while((int)(lp_rtp->accessUnitProcess) <= (int)(lp_rtp->nbAccesUnit))
657
//fprintf(stdout, "[MANAGEMENT TIMELINE]__________________________________\n");
658
//fprintf(stdout, "[timeMgt] _id %u _AU %u \n", lp_rtp->id, lp_rtp->accessUnitProcess);
660
lv_currentTime = gf_sys_clock();
661
lv_sleepDuration = lp_rtp->nextBurstTime - 1000 - lv_currentTime; // (can be negative)
662
lv_sleepDurationInt = (int) lv_sleepDuration;
664
if(lv_sleepDurationInt <= 0) // begin the process now because sleepDuration is negative
666
//fprintf(stdout, "mp4 streamer: [timeMgt] pkt _id %u _nextBT %u _currentTime %u \n",lp_rtp->id, lp_rtp->nextBurstTime, lv_currentTime);
667
paquetisation(lp_rtp, lp_rtp->mp4File);
671
lv_sleepDuration = (u32) lv_sleepDurationInt;
672
//fprintf(stdout,"mp4 streamer: [timeMgt] sleep _id %u _dur %u _nextBT %u _currentTime %u\n",lp_rtp->id, lv_sleepDuration, lp_rtp->nextBurstTime, lv_currentTime);
673
gf_sleep(lv_sleepDuration);
674
paquetisation(lp_rtp, lp_rtp->mp4File);
676
lv_totalLengthSent += lp_rtp->totalLengthSent;
677
if(lp_rtp->accessUnitProcess == lp_rtp->nbAccesUnit)
679
lp_rtp->accessUnitProcess += lp_rtp->nbAccesUnit;
682
//fprintf(stdout, "[timeMgt] _id %u _totalLengthSent "LLD"\n",lp_rtp->id,lv_totalLengthSent );
685
lp_rtp->accessUnitProcess = 0; // number of the AU to process. set to 0 at the beginnning
686
lp_rtp->nextBurstTime = gf_sys_clock() + lp_rtp->global->sov_burstDuration + lp_rtp->global->sov_delay_offtime;
687
lp_rtp->dataLengthInBurst = 0; // total length filled in current burst
688
lp_rtp->totalLengthSent = 0; // total length sent to channel
689
lp_rtp->nbAccesUnit = gf_isom_get_sample_count(lp_rtp->mp4File, lp_rtp->global->sop_trackNbTable[lp_rtp->id -1]);
691
} // end else looping
693
} /* timelineManagement */
695
// ---------------------------------------------------------------------------------------------------
699
* checks if the parameters the user has choosen
700
* matches with the play of the media
703
int checkConfig(RTP_Caller *ap_caller)
705
u32 lv_burstDuration; /* ms */
706
u32 lv_delay_offtime; /* ms */
707
u32 lv_peakRate; /* in kbps */
708
u32 lv_physicalBitRate; /* in kbps */
709
u64 lv_mediaDuration; /* in ms */
710
u64 lv_mediasize; /* in octet (bytes) --> to convert in bits*/
713
RTP_Caller *lp_caller= ap_caller;
715
lv_burstDuration = lp_caller->global->sov_burstDuration; // ms
716
lv_delay_offtime = lp_caller->global->sov_delay_offtime; // ms
717
lv_peakRate = lp_caller->global->sov_peakBitRate; // kbps
718
lv_physicalBitRate = (lv_burstDuration * lv_peakRate)/(lv_delay_offtime + lv_burstDuration); // kbps
720
lv_trackNumber = lp_caller->global->sop_trackNbTable[lp_caller->id -1];
721
lv_mediaDuration = gf_isom_get_track_duration(lp_caller->mp4File, lv_trackNumber); //
722
lv_mediasize = gf_isom_get_media_data_size(lp_caller->mp4File, lv_trackNumber) * 8; // (gf_isom_get_media_data_size en octets)
724
lp_caller->mediaSize = (u32)lv_mediasize; // in bits
725
lp_caller->mediaDuration = (u32)lv_mediaDuration; // in ms
726
lp_caller->bitRate = (u32)lv_mediasize / (u32)lv_mediaDuration ; // in bps
727
lp_caller->maxSizeBurst = lp_caller->bitRate * ((u32)lv_burstDuration + (u32)lv_delay_offtime ); // bps * ms ==> bits
728
//lp_caller->maxSizeBurst = lp_caller->bitRate * ((u32)lv_burstDuration); // bps * ms ==> bits
729
lp_caller->physicalBitRate = lv_physicalBitRate;
730
lp_caller->looping = lp_caller->global->sop_looping[lp_caller->id -1];
732
fprintf(stdout, "[INFO MEDIA] id number %u \n", lp_caller->id);
733
//fprintf(stdout, "[INFO MEDIA: burst duration %u (ms) offtime %u (ms) peak rate %u (kbps)\n", lv_burstDuration, lv_delay_offtime, lv_peakRate);
734
fprintf(stdout, "[INFO MEDIA] media duration "LLD" (ms) media size "LLD" (bits) max burst size %u (bits) \n",lv_mediaDuration, lv_mediasize, lp_caller->maxSizeBurst);
735
fprintf(stdout, "[INFO MEDIA] compute: mediaBitRate %u (kbps) physical max bitrate %u (kbps) \n", lp_caller->bitRate, lv_physicalBitRate );
737
// condition: media bit rate <= max physical bit rate
738
if(lv_physicalBitRate <= lp_caller->bitRate ) // comparison in kbps
740
fprintf(stderr, "mp4 streamer: CFG WARNING: The media %u you will receive may not be play continuously\n", lp_caller->id);
741
fprintf(stderr, " since you do not send enough data in a burst. Increase the peak bit rate\n");
742
fprintf(stderr, " Please reconfigure your cfg file\n");
750
// ---------------------------------------------------------------------------------------------------
753
* usage prints the usage of this module when it is not well-used
757
void usage(char *argv0)
759
fprintf(stderr, "usage: %s configurationFile \n", argv0);
762
// --------------------------------------------------------------------------------------------------------------------
763
// --------------------------------------------------------------------------------------------------------------------
765
// --------------------------------------------------------------------------------------------------------------------
766
// --------------------------------------------------------------------------------------------------------------------
770
* The argument passed are:
771
* 1- the configuration file
775
int main(int argc, char **argv)
778
* Declarations of local variables
781
Simulator lv_global; /* Simulator metadata (from cfg file) */
782
RTP_Caller *lp_caller; /* RTP Caller struct for each session */
783
GF_Err e = GF_OK; /* Error Message */
784
u32 i; /* incrementation */
785
u32 lv_run = 1; /* 1 process running, 0 stopping process*/
787
// process of cts parameters
788
u32 *lp_sessionNumberToProcess; // table of the session to process: 0 de not process, 1 process the AU
789
u64 *lp_sessionNumberCTS;
790
u64 lv_ctsMin = (u64)-1;
791
u32 lv_countCTS = 0; // count the number of session which have the same cts
800
fprintf(stdout, "/****************************************************** \n");
801
fprintf(stdout, " * \n");
802
fprintf(stdout, " * MP 4 streamer Programm\n");
803
fprintf(stdout, " * Project: MIX 2006\n");
804
fprintf(stdout, " * Students: Anh-Vu BUI and Xiangfeng LIU\n");
805
fprintf(stdout, " * \n");
806
fprintf(stdout, " *****************************************************/ \n");
811
gf_sys_init(); /* Init */
812
memset(&lv_global, 0, sizeof(Simulator));
813
lv_global.ov_timeOrigin = gf_sys_clock();
819
configuration(&lv_global, argv[1]);
825
lp_caller = (RTP_Caller *)malloc(lv_global.sov_nbSessions * sizeof(RTP_Caller));
826
lp_sessionNumberToProcess = (u32 *)malloc(lv_global.sov_nbSessions * sizeof(u32));
827
lp_sessionNumberCTS = (u64 *)malloc(lv_global.sov_nbSessions * sizeof(u64));
829
for(i=0; i<= lv_global.sov_nbSessions - 1; i++)
831
lp_sessionNumberToProcess[i] = 0;
832
lp_sessionNumberCTS[i] = 100000;
834
memset(&lp_caller[i], 0, sizeof(RTP_Caller)); /* Allocation */
835
lp_caller[i].id = i+1;
836
lp_caller[i].accessUnitProcess = 0;
837
lp_caller[i].nextBurstTime = 0;
838
lp_caller[i].dataLengthInBurst = 0;
839
lp_caller[i].totalLengthSent = 0;
840
e = rtp_init_channel(&lp_caller[i].channel, lv_global.sop_ip, lv_global.sop_portTable[i]);
843
fprintf(stderr, "Could not initialize RTP Channel\n");
845
e = rtp_init_packetizer(&lp_caller[i]);
848
fprintf(stderr, "Could not initialize Packetizer \n");
850
lp_caller[i].packets_to_send = gf_list_new();
851
// lp_caller[i].accessUnit don't need to initialize
852
// lp_caller[i].header
853
// lp_caller[i].payload
854
// lp_caller[i].payload_len
855
// lp_caller[i].payload_valid_len
856
lp_caller[i].global = &lv_global;
857
lp_caller[i].thread = gf_th_new();
863
fprintf(stdout, "mp4 streamer: _____________________read mp 4 files_______________________ \n");
864
for(i=0; i<= lv_global.sov_nbSessions -1; i++)
866
lp_caller[i].mp4File = gf_isom_open(lv_global.sop_fileTable[i], GF_ISOM_OPEN_READ, NULL);
867
//fprintf(stdout, "mp4 streamer: file of session %u opened successfully\n", i);
868
if (!lp_caller[i].mp4File)
870
fprintf(stderr, "mp4 streamer ERROR: Could not open input MP4 file of session %u\n", i);
876
* Check the configuration of the network
879
fprintf(stdout, "mp4 streamer: _______________________check config________________________ \n");
880
// nb_service * burst duration <= off time
881
if(lv_global.sov_nbSessions * lv_global.sov_burstDuration > lv_global.sov_delay_offtime )
883
fprintf(stderr, "mp4 streamer CFG ERROR: nb service * burst duration > off time\n");
884
fprintf(stderr, "mp4 streamer CFG ERROR: please reconfigure your cfg file\n");
888
for(i=0; i<= lv_global.sov_nbSessions -1; i++)
890
checkConfig(&lp_caller[i]);
893
for(i=0; i<= lv_global.sov_nbSessions -1; i++)
895
if (lv_global.sop_trackNbTable[i] > gf_isom_get_track_count(lp_caller[i].mp4File))
897
fprintf(stderr, "mp4 streamer ERROR: session %u: Track > track count \n", i);
900
lp_caller[i].nbAccesUnit = gf_isom_get_sample_count(lp_caller[i].mp4File, lp_caller[i].global->sop_trackNbTable[i]);
903
fprintf(stdout, "[MANAGEMENT TIMELINE]_FIRST_SESSION_________________________\n");
904
fprintf(stdout, "[timeMgt] _id %u _AU %u \n", lp_caller[0].id, lp_caller[0].accessUnitProcess);
905
paquetisation(&lp_caller[0], lp_caller[0].mp4File);// 0 =>first session
907
//fprintf(stdout, "[MANAGEMENT TIMELINE]_NEXT_SESSION_________________________\n");
908
for(i=1; i<= lv_global.sov_nbSessions -1; i++) // except session 1
910
initTimeManagement(&lp_caller[i]);
911
gf_th_run(lp_caller[i].thread, timelineManagement, &lp_caller[i] );
913
initTimeManagement(&lp_caller[0]);
914
timelineManagement(&lp_caller[0]);
916
fprintf(stdout, "___________END THREAD MAIN__________wait 30 sec before closing_____\n");
917
gf_sleep(30000); // pour �viter que les autres threads ne soient d�truits.
924
fprintf(stdout, "mp4 streamer: ________________________desallocation_________________________\n");
925
for(i=0; i<= lv_global.sov_nbSessions -1; i++)
927
//fprintf(stdout, "mp4 streamer: desallocation 1\n");
928
free(lp_caller[i].payload);
930
//fprintf(stdout, "mp4 streamer: desallocation 2\n");
931
gf_list_del(lp_caller[i].payload);
933
//fprintf(stdout, "mp4 streamer: desallocation 3\n");
934
gf_rtp_del(lp_caller[i].channel);
936
//fprintf(stdout, "mp4 streamer: desallocation 4\n");
937
gf_rtp_builder_del(lp_caller[i].packetizer);
939
//fprintf(stdout, "mp4 streamer: desallocation 5\n");
940
if (lp_caller[i].mp4File) gf_isom_close(lp_caller[i].mp4File);
945
fprintf(stdout, "mp4 streamer: _________________________the end____________________________\n");