~ubuntu-branches/ubuntu/intrepid/gpac/intrepid-proposed

« back to all changes in this revision

Viewing changes to applications/testapps/mp4_streamer/main.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2007-01-24 23:34:57 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070124233457-zzlls8afkt0nyakj
Tags: 0.4.2~rc2-0ubuntu1
* New upstream release
  * Most notably MP4 tagging support via MP4Box -itags
* debian/patches/01_64bits.dpatch: dropped; included upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *                      GPAC - Multimedia Framework C SDK
 
3
 *
 
4
 *                      Copyright (c) Cyril Concolato / Jean Le Feuvre 2000-2005
 
5
 *                                      All rights reserved
 
6
 *
 
7
 *  This file is part of GPAC / mp4 simple streamer application
 
8
 *
 
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)
 
12
 *  any later version.
 
13
 *   
 
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.
 
18
 *   
 
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. 
 
22
 *
 
23
 */
 
24
 
 
25
//------------------------------------------------------------
 
26
// Includes
 
27
//------------------------------------------------------------
 
28
        // Third
 
29
 
 
30
        // Project
 
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>
 
37
 
 
38
 
 
39
//------------------------------------------------------------
 
40
// Define
 
41
//------------------------------------------------------------
 
42
#define PATHFILE "."
 
43
#define RTP_HEADER_SIZE 12 // in bytes (octets)
 
44
 
 
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)
 
50
 
 
51
//------------------------------------------------------------
 
52
// Typedef
 
53
//------------------------------------------------------------
 
54
 
 
55
typedef struct {        
 
56
        // config
 
57
        u32 sov_burstDuration;
 
58
        u32 sov_peakBitRate;
 
59
        u32 sov_delay_offtime;
 
60
        u32 sov_nbSessions;
 
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
 
66
 
 
67
        // time
 
68
        u32 ov_currentTime;     
 
69
        u32 ov_timeOrigin;                      // origin of main.c ( = 0)
 
70
 
 
71
        // other param
 
72
        u32 sov_numberPacketSent;
 
73
        u32 sov_burstSize;
 
74
} Simulator;
 
75
 
 
76
typedef struct {
 
77
        GF_RTPHeader header;
 
78
        char *payload;
 
79
        u32 payload_len;
 
80
} RTP_Packet;
 
81
 
 
82
typedef struct {
 
83
        /* id */
 
84
        int id;
 
85
        u32 bitRate; // of the media
 
86
        u32 mediaSize;
 
87
        u32 mediaDuration;
 
88
        u32 nbAccesUnit;
 
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
 
92
 
 
93
        /* access unit*/
 
94
        u32 accessUnitProcess; // number of the AU to process. set to 0 at the beginnning
 
95
        u32 nextBurstTime;
 
96
        u32 dataLengthInBurst; // total length filled in current burst
 
97
        u64 totalLengthSent;   // total length sent to channel
 
98
 
 
99
        /* Type */
 
100
        GF_RTPChannel *channel; 
 
101
        GP_RTPPacketizer *packetizer;
 
102
        GF_List *packets_to_send;       
 
103
        GF_ISOSample  *accessUnit; // the AU
 
104
        GF_ISOFile *mp4File;
 
105
 
 
106
        /* The current packet being formed */
 
107
        GF_RTPHeader header;
 
108
        char *payload;
 
109
        u32 payload_len;
 
110
        u32 payload_valid_len;
 
111
 
 
112
        /* Management */
 
113
        Simulator *global;
 
114
        GF_Thread *thread; // thread of session 1 is not used
 
115
} RTP_Caller;
 
116
 
 
117
 
 
118
//------------------------------------------------------------
 
119
//
 
120
// Functions
 
121
//
 
122
//------------------------------------------------------------
 
123
 
 
124
/*
 
125
 * setOffsetTime
 
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
 
128
 */
 
129
 
 
130
void setOffsetTime(u32 av_offsetTime)
 
131
{
 
132
        sov_timeOffset = av_offsetTime;
 
133
}
 
134
 
 
135
/*
 
136
 * initTimeManagement
 
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
 
141
 */
 
142
 
 
143
void initTimeManagement(RTP_Caller *ap_caller)
 
144
{       // set the time when CTS = 0
 
145
        if(ap_caller->id == 1)
 
146
        {
 
147
                ap_caller->nextBurstTime = sov_timeOffset +ap_caller->global->sov_burstDuration + ap_caller->global->sov_delay_offtime;         
 
148
        }
 
149
        else
 
150
        {
 
151
                ap_caller->nextBurstTime = sov_timeOffset + (ap_caller->id - 1)* ap_caller->global->sov_burstDuration;
 
152
        }
 
153
        //fprintf(stdout,"mp4 streamer: [initMgtTime] _id %u _currentTime %u _nextBurstTime %u\n",ap_caller->id, gf_sys_clock(),ap_caller->nextBurstTime);
 
154
 
 
155
}
 
156
 
 
157
/*
 
158
 * setNextBurstTime
 
159
 *      is called in OnPacketDone just before the burst is sent
 
160
 *      sets the nextBurstTime of the given session
 
161
 */
 
162
 
 
163
void setNextBurstTime(RTP_Caller *ap_caller)
 
164
{
 
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);
 
167
}
 
168
 
 
169
 
 
170
/*
 
171
 * callback functions
 
172
 *
 
173
 *
 
174
 */
 
175
 
 
176
static void OnNewPacket(void *cbk, GF_RTPHeader *header)
 
177
{
 
178
        RTP_Caller *caller = cbk;
 
179
        if (!header) return;
 
180
        memcpy(&caller->header, header, sizeof(GF_RTPHeader));
 
181
        //fprintf(stdout, "mp4 streamer: [ONP] _session %u\n", caller->id);
 
182
} /* OnNewPacket */
 
183
 
 
184
static void OnPacketDone(void *cbk, GF_RTPHeader *header) 
 
185
{
 
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)
 
189
        
 
190
        lv_sizeSent = 0;        
 
191
        lv_nextBurstTime = caller->nextBurstTime; // time of next burst to play 
 
192
        caller->global->ov_currentTime = gf_sys_clock();// gets system clock (current time)     
 
193
                
 
194
        //fprintf(stdout,"[OPD] _id %u _AU %u _currentTime %u _nextBursTime %u\n",caller->id, caller->accessUnitProcess, caller->global->ov_currentTime, lv_nextBurstTime);
 
195
 
 
196
        /*
 
197
         * Check for the first burst sending
 
198
         * ==> allows to set the time of the first sending and start threads
 
199
         *
 
200
         */
 
201
 
 
202
        if(sov_numberBurstSent == 0 && (caller->id == 1))
 
203
        {               
 
204
                u32 lv_totalLengthFilled =0; // in bits
 
205
                u32 i;
 
206
                u32 lv_packetCount=0;
 
207
                u32 lv_currentPacketSize; // in bits
 
208
                
 
209
                RTP_Packet *tmp;
 
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;          
 
217
                
 
218
                lv_packetCount = gf_list_count(caller->packets_to_send);        
 
219
                lv_currentPacketSize = (tmp->payload_len + RTP_HEADER_SIZE) * 8; // in bits
 
220
 
 
221
                if(lv_packetCount == 0)
 
222
                {
 
223
                        lv_totalLengthFilled += lv_currentPacketSize;
 
224
                }
 
225
                else
 
226
                {
 
227
                        for (i=0;i< lv_packetCount;i++)                 
 
228
                        {
 
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;
 
232
                        } 
 
233
                        lv_totalLengthFilled += lv_currentPacketSize;
 
234
                }
 
235
                
 
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...
 
240
                        {
 
241
                                caller->totalLengthSent += (tmp->payload_len * 8); 
 
242
                                gf_rtp_send_packet(caller->channel, &tmp->header, 0, 0, tmp->payload, tmp->payload_len);
 
243
                                free(tmp->payload);                             
 
244
                        }
 
245
                        else
 
246
                        {
 
247
                                for (i=0;i<= lv_packetCount -1 ;i++) 
 
248
                                {
 
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);                                
 
252
                                        free(rtp->payload);
 
253
                                }                       
 
254
                                gf_list_reset(caller->packets_to_send);
 
255
                        }
 
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() );
 
258
                
 
259
                } // end if               
 
260
                else // store
 
261
                {
 
262
                        //fprintf(stdout, "[OPD STO] 1st rtp store _pktSize %u _totSize %u\n", lv_currentPacketSize, lv_totalLengthFilled);
 
263
                }
 
264
                gf_list_add(caller->packets_to_send, tmp); // store the last packet not sent
 
265
                                                
 
266
        } // end if first packet of session n�1
 
267
        else
 
268
        {
 
269
                u32 lv_totalLengthFilled =0; // in bits
 
270
                u32 i;
 
271
                u32 lv_packetCount=0;
 
272
                u32 lv_currentPacketSize; // in bits
 
273
                
 
274
                RTP_Packet *tmp;
 
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;          
 
282
                
 
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)
 
286
                {
 
287
                        lv_totalLengthFilled += lv_currentPacketSize;
 
288
                }
 
289
                else
 
290
                {
 
291
                        for (i=0;i< lv_packetCount;i++)                 
 
292
                        {
 
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 ;
 
296
                        } 
 
297
                        lv_totalLengthFilled += lv_currentPacketSize;
 
298
                }               
 
299
                                
 
300
                if( lv_totalLengthFilled >= caller->maxSizeBurst ) 
 
301
                { // send the RTP packets in gf_list
 
302
                        u32 lv_sleep;
 
303
                        
 
304
                        lv_sleep = caller->nextBurstTime - caller->global->ov_currentTime;
 
305
                        if ((int)lv_sleep <0)
 
306
                        {
 
307
                                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  );
 
309
                        }
 
310
                        
 
311
                        gf_sleep(lv_sleep); // sleep and send the burst
 
312
                        
 
313
                        setNextBurstTime(caller); // time management
 
314
                        
 
315
                        if(lv_packetCount == 0)
 
316
                        {
 
317
                                caller->totalLengthSent += (tmp->payload_len)*8; 
 
318
                                gf_rtp_send_packet(caller->channel, &tmp->header, 0, 0, tmp->payload, tmp->payload_len);
 
319
                                free(tmp->payload);                             
 
320
                        }
 
321
                        else
 
322
                        {
 
323
                                for (i=0;i<= lv_packetCount -1 ;i++) 
 
324
                                {                       
 
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);
 
328
                                        free(rtp->payload);     
 
329
                                }                       
 
330
                                gf_list_reset(caller->packets_to_send);
 
331
                        }
 
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);
 
334
        
 
335
                } // end if               
 
336
                else // store
 
337
                {
 
338
                        //fprintf(stdout, "[OPD STO] _id %u _pktSize %u _totSize %u _nbPkt in Burst %u \n", caller->id, lv_currentPacketSize, lv_totalLengthFilled, lv_packetCount);
 
339
                }
 
340
                gf_list_add(caller->packets_to_send, tmp); // store the last packet not sent
 
341
        }
 
342
 
 
343
} /* OnPacketdone */
 
344
 
 
345
static void OnData(void *cbk, char *data, u32 data_size, Bool is_head) 
 
346
{
 
347
        RTP_Caller *caller = cbk;
 
348
        if (!data ||!data_size) return;
 
349
 
 
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;
 
354
        } else {
 
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;
 
358
                } 
 
359
                if (!is_head) {
 
360
                        memcpy(caller->payload+caller->payload_valid_len, data, data_size);
 
361
                } else {
 
362
                        memmove(caller->payload+data_size, caller->payload, caller->payload_valid_len);
 
363
                        memcpy(caller->payload, data, data_size);
 
364
                }
 
365
                caller->payload_valid_len += data_size;
 
366
        }       
 
367
 
 
368
} /* OnData */
 
369
 
 
370
static u32 payload_type = 96;
 
371
 
 
372
GF_Err rtp_init_packetizer(RTP_Caller *caller)
 
373
{       
 
374
        char sdp_fmt[5000];
 
375
 
 
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); 
 
380
        payload_type++;
 
381
 
 
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);
 
385
 
 
386
        caller->packetizer->rtp_header.Version = 2;
 
387
        caller->packetizer->rtp_header.SSRC = rand();//RandomNumber identifiant la source
 
388
 
 
389
        return GF_OK;
 
390
} /* rtp_init_packetizer */
 
391
 
 
392
GF_Err rtp_init_channel(GF_RTPChannel **chan, char * dest, int port)
 
393
{
 
394
 
 
395
        GF_RTSPTransport tr;
 
396
        GF_Err res;
 
397
 
 
398
        *chan = gf_rtp_new();
 
399
        gf_rtp_set_ports(*chan);
 
400
 
 
401
        tr.IsUnicast=1;
 
402
        tr.Profile="RTP/AVP";//RTSP_PROFILE_RTP_AVP;
 
403
        tr.destination = dest;
 
404
        tr.source = "0.0.0.0";
 
405
        tr.IsRecord = 0;
 
406
        tr.Append = 0;
 
407
        tr.SSRC = rand();
 
408
        
 
409
        tr.client_port_first = port; //RTP
 
410
        tr.client_port_last  = port+1; //RTCP (not used a priori)
 
411
 
 
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)
 
414
 
 
415
        res = gf_rtp_setup_transport(*chan, &tr, dest);
 
416
        if (res !=0) return res;
 
417
 
 
418
        gf_rtp_initialize(*chan, 0, 1, 1500, 0, 0, NULL);
 
419
        if (res !=0) return res;
 
420
 
 
421
        
 
422
 
 
423
        return GF_OK;
 
424
} /* rtp_init_channel */
 
425
 
 
426
// ---------------------------------------------------------------------------------------------------
 
427
 
 
428
/* 
 
429
 * paquetization of a burst
 
430
 *      process the AUs till the burst size is reached.
 
431
 *
 
432
 */
 
433
 
 
434
void paquetisation(RTP_Caller *ap_caller, GF_ISOFile *ap_mp4)
 
435
{
 
436
        int lv_idSession;       
 
437
        u32 lv_accesUnitLength; // in bits
 
438
        u32 lv_totalLengthFilled; // in bits
 
439
        u32 lv_timescale;
 
440
        u32 lv_sampleDuration;
 
441
        u8 lv_sampleDescIndex;
 
442
        u64 lv_ts;
 
443
        u32 lv_auCount;
 
444
                
 
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]);
 
450
                
 
451
        while (lv_totalLengthFilled <= ap_caller->maxSizeBurst)
 
452
        {                       
 
453
                if(ap_caller->accessUnitProcess + 1 <= lv_auCount) // attention overflow acceUnit number <= get_sample_count
 
454
                {
 
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;
 
457
                        
 
458
                        /*
 
459
                        // solution 1
 
460
                        if( (lv_totalLengthFilled + lv_accesUnitLength) <= ap_caller->maxSizeBurst ) // OK
 
461
                        {
 
462
                                lv_totalLengthFilled += lv_accesUnitLength;                                                                     
 
463
                        }
 
464
                        else // forget
 
465
                        {
 
466
                                lv_totalLengthFilled += ap_caller->maxSizeBurst; // to quit the loop
 
467
                        }
 
468
 
 
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);
 
472
                                
 
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;
 
475
                                                        
 
476
                        lv_ts = (u64) ((90000 * ap_caller->accessUnit->DTS) / lv_timescale);
 
477
                        ap_caller->packetizer->sl_header.decodingTimeStamp = lv_ts;
 
478
                                                                
 
479
                        ap_caller->packetizer->sl_header.randomAccessPointFlag = ap_caller->accessUnit->IsRAP;
 
480
                                                                                        
 
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);
 
484
                        */
 
485
                        if( (lv_totalLengthFilled + lv_accesUnitLength) <= ap_caller->maxSizeBurst ) // OK
 
486
                        {
 
487
                                lv_totalLengthFilled += lv_accesUnitLength;     
 
488
 
 
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);
 
492
                                        
 
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;
 
495
                                                                
 
496
                                lv_ts = (u64) ((1000 * ap_caller->accessUnit->DTS) / lv_timescale);
 
497
                                ap_caller->packetizer->sl_header.decodingTimeStamp = lv_ts;
 
498
                                                                        
 
499
                                ap_caller->packetizer->sl_header.randomAccessPointFlag = ap_caller->accessUnit->IsRAP;
 
500
                                                                                                
 
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);
 
504
                        }
 
505
                        else // forget
 
506
                        {
 
507
                                lv_totalLengthFilled += ap_caller->maxSizeBurst; // to quit the loop
 
508
                        }
 
509
                } // end if exist sample
 
510
                else
 
511
                {
 
512
                        lv_totalLengthFilled += ap_caller->maxSizeBurst;
 
513
                }
 
514
        } // end while
 
515
 
 
516
        //fprintf(stdout, "*********************************END PAQUETISATION Session %u* accesunit process %u********************************\n", lv_idSession, ap_caller->accessUnitProcess );
 
517
        
 
518
} /* paquetisation */
 
519
 
 
520
// ---------------------------------------------------------------------------------------------------
 
521
 
 
522
/*
 
523
 * configuration:
 
524
 *      retrieves the parameters in the configuration file
 
525
 *
 
526
 */
 
527
 
 
528
int configuration(Simulator *av_simulator, char *av_argv1)
 
529
{
 
530
        char lv_config[1024];           /* cfg file name */
 
531
        GF_Config *lp_configFile;       /* Configuration file struct */
 
532
        u32 i;                                          /* counter */
 
533
 
 
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);
 
537
 
 
538
        lp_configFile = gf_cfg_new(PATHFILE,lv_config); 
 
539
        if(!lp_configFile)
 
540
        {
 
541
                fprintf(stderr, "mp4 streamer ERROR: could not open the file\n");
 
542
                return GF_IO_ERR;
 
543
        }
 
544
 
 
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);
 
547
 
 
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);        
 
550
        
 
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);
 
553
 
 
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);
 
556
 
 
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);
 
559
 
 
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));
 
565
 
 
566
        for(i=0; i<= av_simulator->sov_nbSessions - 1; i++)
 
567
        {
 
568
                char lv_sessionName[1024];
 
569
 
 
570
                sprintf(lv_sessionName, "SESSION%d",i+1);               
 
571
                av_simulator->sop_fileTable[i] = (char *) malloc(512);
 
572
                                
 
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]);
 
580
        }
 
581
 
 
582
        av_simulator->sov_numberPacketSent = 0;
 
583
        av_simulator->sov_burstSize = av_simulator->sov_burstDuration * av_simulator->sov_peakBitRate; // size in bit
 
584
        return 1;
 
585
} /* configuration */
 
586
 
 
587
// ---------------------------------------------------------------------------------------------------
 
588
 
 
589
/*
 
590
 * timelineManagement
 
591
 *      called by a thread or in the main() for the 1st session
 
592
 *      1 thread <=> 1 session
 
593
 *
 
594
 */
 
595
 
 
596
void timelineManagement(void *ap_caller)
 
597
{
 
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 */
 
603
        u32 lv_idSession;       
 
604
 
 
605
        RTP_Caller *lp_rtp = ap_caller;
 
606
        
 
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] );
 
611
 
 
612
 
 
613
        /*
 
614
         * Normal use
 
615
         *
 
616
         */
 
617
 
 
618
        if(lp_rtp->looping != 1) // no looping
 
619
        {
 
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
 
622
                {
 
623
                        fprintf(stdout, "[MANAGEMENT TIMELINE]__________________________________\n");
 
624
                        fprintf(stdout, "[timeMgt] _id %u _AU %u \n", lp_rtp->id, lp_rtp->accessUnitProcess);
 
625
 
 
626
                        lv_currentTime = gf_sys_clock();
 
627
                        lv_sleepDuration = lp_rtp->nextBurstTime - 1000 - lv_currentTime; // (can be negative)
 
628
                        lv_sleepDurationInt = (int) lv_sleepDuration;
 
629
 
 
630
                        if(lv_sleepDurationInt <= 0) // begin the process now because sleepDuration is negative
 
631
                        {
 
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);
 
634
                        }
 
635
                        else // positive
 
636
                        {               
 
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);
 
641
                        }
 
642
                        lv_totalLengthSent += lp_rtp->totalLengthSent;          
 
643
                        fprintf(stdout, "[timeMgt] _id %u _totalLengthSent "LLD"\n",lp_rtp->id,lv_totalLengthSent );            
 
644
                }
 
645
        } // end if no looping
 
646
        else
 
647
        {
 
648
                /*
 
649
                 * Infinite loop ==> to send the media "en boucle"
 
650
                 *
 
651
                 */
 
652
 
 
653
                while(1)
 
654
                {
 
655
                        while((int)(lp_rtp->accessUnitProcess) <= (int)(lp_rtp->nbAccesUnit))           
 
656
                        {
 
657
                                //fprintf(stdout, "[MANAGEMENT TIMELINE]__________________________________\n");
 
658
                                //fprintf(stdout, "[timeMgt] _id %u _AU %u \n", lp_rtp->id, lp_rtp->accessUnitProcess);
 
659
 
 
660
                                lv_currentTime = gf_sys_clock();
 
661
                                lv_sleepDuration = lp_rtp->nextBurstTime - 1000 - lv_currentTime; // (can be negative)
 
662
                                lv_sleepDurationInt = (int) lv_sleepDuration;
 
663
 
 
664
                                if(lv_sleepDurationInt <= 0) // begin the process now because sleepDuration is negative
 
665
                                {
 
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);
 
668
                                }
 
669
                                else // positive
 
670
                                {               
 
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);
 
675
                                }
 
676
                                lv_totalLengthSent += lp_rtp->totalLengthSent;          
 
677
                                if(lp_rtp->accessUnitProcess == lp_rtp->nbAccesUnit)
 
678
                                {
 
679
                                        lp_rtp->accessUnitProcess += lp_rtp->nbAccesUnit;
 
680
                                }
 
681
                                
 
682
                                //fprintf(stdout, "[timeMgt] _id %u _totalLengthSent "LLD"\n",lp_rtp->id,lv_totalLengthSent );          
 
683
                        }
 
684
                        //reset parameters                                      
 
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]);
 
690
                } // end while 1
 
691
        } // end else looping
 
692
 
 
693
} /* timelineManagement */
 
694
 
 
695
// ---------------------------------------------------------------------------------------------------
 
696
 
 
697
/*
 
698
 * checkConfig
 
699
 *      checks if the parameters the user has choosen
 
700
 *      matches with the play of the media
 
701
 */
 
702
 
 
703
int checkConfig(RTP_Caller *ap_caller)
 
704
{       
 
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*/
 
711
        u32 lv_calcul =0;
 
712
        u32 lv_trackNumber;             
 
713
        RTP_Caller *lp_caller= ap_caller;
 
714
 
 
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
 
719
 
 
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)
 
723
        
 
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];
 
731
        
 
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 );
 
736
                
 
737
        // condition: media bit rate <= max physical bit rate   
 
738
        if(lv_physicalBitRate <= lp_caller->bitRate ) // comparison in kbps     
 
739
        {
 
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");
 
743
                return GF_IO_ERR;
 
744
        }
 
745
        
 
746
        return 1;
 
747
 
 
748
} /* checkConfig */
 
749
 
 
750
// ---------------------------------------------------------------------------------------------------
 
751
 
 
752
/*
 
753
 * usage prints the usage of this module when it is not well-used
 
754
 *
 
755
 */
 
756
 
 
757
void usage(char *argv0) 
 
758
{
 
759
        fprintf(stderr, "usage: %s configurationFile \n", argv0);
 
760
} /* usage */
 
761
 
 
762
// --------------------------------------------------------------------------------------------------------------------
 
763
// --------------------------------------------------------------------------------------------------------------------
 
764
// MAIN
 
765
// --------------------------------------------------------------------------------------------------------------------
 
766
// --------------------------------------------------------------------------------------------------------------------
 
767
 
 
768
/*
 
769
 *  Main 
 
770
 *  The argument passed are:
 
771
 *              1- the configuration file
 
772
 *
 
773
 */
 
774
 
 
775
int main(int argc, char **argv)
 
776
{
 
777
        /*
 
778
         * Declarations of local variables
 
779
         *
 
780
         */
 
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*/
 
786
 
 
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
 
792
 
 
793
        // test 
 
794
        if (argc < 2) 
 
795
        {
 
796
                usage(argv[0]);
 
797
                return GF_IO_ERR;
 
798
        }
 
799
 
 
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");
 
807
        /*
 
808
         * Initialization
 
809
         *
 
810
         */
 
811
        gf_sys_init();                          /* Init */
 
812
        memset(&lv_global, 0, sizeof(Simulator));
 
813
        lv_global.ov_timeOrigin = gf_sys_clock();
 
814
                                
 
815
        /*
 
816
         * Configuration File
 
817
         *
 
818
         */             
 
819
        configuration(&lv_global, argv[1]);
 
820
 
 
821
        /*
 
822
         *      Allocation
 
823
         *
 
824
         */     
 
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));
 
828
 
 
829
        for(i=0; i<= lv_global.sov_nbSessions - 1; i++)
 
830
        {       
 
831
                lp_sessionNumberToProcess[i] = 0;
 
832
                lp_sessionNumberCTS[i] = 100000;
 
833
                
 
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]);
 
841
                if (e) 
 
842
                {
 
843
                        fprintf(stderr, "Could not initialize RTP Channel\n");
 
844
                }                       
 
845
                e = rtp_init_packetizer(&lp_caller[i]);
 
846
                if (e) 
 
847
                {
 
848
                        fprintf(stderr, "Could not initialize Packetizer \n");
 
849
                }
 
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();      
 
858
        }
 
859
 
 
860
        /*
 
861
         * read the mp4 files
 
862
         */
 
863
        fprintf(stdout, "mp4 streamer: _____________________read mp 4 files_______________________ \n");
 
864
        for(i=0; i<= lv_global.sov_nbSessions -1; i++)
 
865
        {               
 
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)
 
869
                {
 
870
                        fprintf(stderr, "mp4 streamer ERROR: Could not open input MP4 file of session %u\n", i);
 
871
                        return GF_IO_ERR;
 
872
                } 
 
873
        } /* end read file*/
 
874
 
 
875
        /*
 
876
         * Check the configuration of the network
 
877
         */
 
878
 
 
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 )
 
882
        {
 
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");
 
885
                return GF_IO_ERR;
 
886
        }
 
887
        // burst 
 
888
        for(i=0; i<= lv_global.sov_nbSessions -1; i++)
 
889
        {
 
890
                checkConfig(&lp_caller[i]);
 
891
        }
 
892
        
 
893
        for(i=0; i<= lv_global.sov_nbSessions -1; i++)
 
894
        {
 
895
                if (lv_global.sop_trackNbTable[i] > gf_isom_get_track_count(lp_caller[i].mp4File)) 
 
896
                {
 
897
                                fprintf(stderr, "mp4 streamer ERROR: session %u: Track > track count \n", i);
 
898
                                return GF_IO_ERR;                       
 
899
                }                               
 
900
                lp_caller[i].nbAccesUnit = gf_isom_get_sample_count(lp_caller[i].mp4File, lp_caller[i].global->sop_trackNbTable[i]);
 
901
        } /* end init */
 
902
                
 
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         
 
906
 
 
907
        //fprintf(stdout, "[MANAGEMENT TIMELINE]_NEXT_SESSION_________________________\n");
 
908
        for(i=1; i<= lv_global.sov_nbSessions -1; i++) // except session 1
 
909
        {
 
910
                initTimeManagement(&lp_caller[i]);
 
911
                gf_th_run(lp_caller[i].thread, timelineManagement, &lp_caller[i] );
 
912
        }               
 
913
        initTimeManagement(&lp_caller[0]);
 
914
        timelineManagement(&lp_caller[0]);
 
915
 
 
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.
 
918
 
 
919
        /*
 
920
         * Desallocation 
 
921
         *
 
922
         */
 
923
        
 
924
        fprintf(stdout, "mp4 streamer: ________________________desallocation_________________________\n");
 
925
        for(i=0; i<= lv_global.sov_nbSessions -1; i++)
 
926
        {
 
927
                //fprintf(stdout, "mp4 streamer: desallocation 1\n");
 
928
                free(lp_caller[i].payload);     
 
929
                
 
930
                //fprintf(stdout, "mp4 streamer: desallocation 2\n");
 
931
                gf_list_del(lp_caller[i].payload);
 
932
 
 
933
                //fprintf(stdout, "mp4 streamer: desallocation 3\n");
 
934
                gf_rtp_del(lp_caller[i].channel);
 
935
 
 
936
                //fprintf(stdout, "mp4 streamer: desallocation 4\n");
 
937
                gf_rtp_builder_del(lp_caller[i].packetizer);
 
938
 
 
939
                //fprintf(stdout, "mp4 streamer: desallocation 5\n");
 
940
                if (lp_caller[i].mp4File) gf_isom_close(lp_caller[i].mp4File);
 
941
        }       
 
942
        
 
943
        gf_sys_close();
 
944
 
 
945
        fprintf(stdout, "mp4 streamer: _________________________the end____________________________\n");
 
946
        return e;
 
947
 
 
948
} /* end main */