Statistics
| Branch: | Revision:

chunker-player / chunker_streamer / chunker_streamer.c @ 9996b19f

History | View | Annotate | Download (27.4 KB)

1
// chunker_streamer.c
2
// Author 
3
// Diego Reforgiato
4
// Giuseppe Tropea
5
// Dario Marchese
6
// Carmelo Daniele
7
//
8
// Use the file compile.localffmpeg.static to build the program
9

    
10

    
11
#include "chunker_streamer.h"
12

    
13

    
14
//#define DEBUG_AUDIO_FRAMES
15
//#define DEBUG_VIDEO_FRAMES
16
//#define DEBUG_CHUNKER
17
#define DEBUG_ANOMALIES
18
//#define DEBUG_TIMESTAMPING
19

    
20
#define MAX(a,b) ((a>b)?(a):(b))
21

    
22
ChunkerMetadata *cmeta = NULL;
23
int seq_current_chunk = 1; //chunk numbering starts from 1; HINT do i need more bytes?
24

    
25

    
26
int chunkFilled(ExternalChunk *echunk, ChunkerMetadata *cmeta) {
27
        // different strategies to implement
28
        if(cmeta->strategy == 0) { // number of frames per chunk constant
29
#ifdef DEBUG_CHUNKER
30
                fprintf(stderr, "CHUNKER: check if frames num %d == %d in chunk %d\n", echunk->frames_num, cmeta->val_strategy, echunk->seq);
31
#endif
32
                if(echunk->frames_num == cmeta->val_strategy)
33
                        return 1;
34
  }
35
        
36
        if(cmeta->strategy == 1) // constant size. Note that for now each chunk will have a size just greater or equal than the required value - It can be considered as constant size. If that is not good we need to change the code. Also, to prevent too low values of strategy_val. This choice is more robust
37
                if(echunk->payload_len >= cmeta->val_strategy)
38
                        return 1;
39
        
40
        return 0;
41
}
42

    
43

    
44
void initChunk(ExternalChunk *chunk, int *seq_num) {
45
        chunk->seq = (*seq_num)++;
46
        chunk->frames_num = 0;
47
        chunk->payload_len = 0;
48
        chunk->len=0;
49
  if(chunk->data != NULL)
50
    free(chunk->data);
51
        chunk->data = NULL;
52
        chunk->start_time.tv_sec = -1;
53
        chunk->start_time.tv_usec = -1;
54
        chunk->end_time.tv_sec = -1;
55
        chunk->end_time.tv_usec = -1;
56
        chunk->priority = 0;
57
        chunk->category = 0;
58
        chunk->_refcnt = 0;
59
}
60

    
61

    
62
int main(int argc, char *argv[]) {
63
        int i=0;
64

    
65
        //output variables
66
        uint8_t *video_outbuf = NULL;
67
        int video_outbuf_size, video_frame_size;
68
        uint8_t *audio_outbuf = NULL;
69
        int audio_outbuf_size, audio_frame_size;
70
        int audio_data_size;
71

    
72
        //numeric identifiers of input streams
73
        int videoStream = -1;
74
        int audioStream = -1;
75

    
76
        int len1;
77
        int frameFinished;
78
        //frame sequential counters
79
        int contFrameAudio=1, contFrameVideo=1;
80
        int numBytes;
81

    
82
        //command line parameters
83
        int audio_bitrate;
84
        int video_bitrate;
85
        int live_source = 0; //tells to sleep before reading next frame in not live (i.e. file)
86
        int offset_av = 0; //tells to compensate for offset between audio and video in the file
87
        
88
        //a raw buffer for decoded uncompressed audio samples
89
        int16_t *samples = NULL;
90
        //a raw uncompressed video picture
91
        AVFrame *pFrame = NULL;
92

    
93
        AVFormatContext *pFormatCtx;
94
        AVCodecContext  *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx;
95
        AVCodec         *pCodec,*pCodecEnc,*aCodec,*aCodecEnc;
96
        AVPacket         packet;
97

    
98
        //stuff needed to compute the right timestamps
99
        short int FirstTimeAudio=1, FirstTimeVideo=1;
100
        short int pts_anomalies_counter=0;
101
        short int newtime_anomalies_counter=0;
102
        long long newTime=0, newTime_audio=0, newTime_prev=0;
103
        struct timeval lastAudioSent = {0, 0};
104
        double ptsvideo1=0.0;
105
        double ptsaudio1=0.0;
106
        int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0;
107

    
108
        //Napa-Wine specific Frame and Chunk structures for transport
109
        Frame *frame = NULL;
110
        ExternalChunk *chunk = NULL;
111
        ExternalChunk *chunkaudio = NULL;
112

    
113

    
114
        //scan the command line
115
        if(argc < 4) {
116
                fprintf(stderr, "execute ./chunker_streamer moviefile audiobitrate videobitrate <live source flag (0 or 1)> <offset av flag (0 or 1)>\n");
117
                return -1;
118
        }
119
        sscanf(argv[2],"%d", &audio_bitrate);
120
        sscanf(argv[3],"%d", &video_bitrate);
121
        if(argc>=5) sscanf(argv[4],"%d", &live_source);
122
        if(argc==6) sscanf(argv[5],"%d", &offset_av);
123

    
124
restart:
125
        // read the configuration file
126
        cmeta = chunkerInit();
127
        if(live_source)
128
                fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n");
129
        if(offset_av)
130
                fprintf(stderr, "INIT: Compensating AV OFFSET in file\n");
131

    
132
        // Register all formats and codecs
133
        av_register_all();
134

    
135
        // Open input file
136
        if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) != 0) {
137
                fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n");
138
                exit(-1);
139
        }
140

    
141
        // Retrieve stream information
142
        if(av_find_stream_info(pFormatCtx) < 0) {
143
                fprintf(stdout, "INIT: Couldn't find stream information. Exiting.\n");
144
                exit(-1);
145
        }
146

    
147
        // Dump information about file onto standard error
148
        dump_format(pFormatCtx, 0, argv[1], 0);
149

    
150
        // Find the video and audio stream numbers
151
        for(i=0; i<pFormatCtx->nb_streams; i++) {
152
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && videoStream<0) {
153
                        videoStream=i;
154
                }
155
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audioStream<0) {
156
                        audioStream=i;
157
                }
158
        }
159
        fprintf(stderr, "INIT: Num streams : %d TBR: %d %d RFRAMERATE:%d %d Duration:%d\n", pFormatCtx->nb_streams, pFormatCtx->streams[videoStream]->time_base.num, pFormatCtx->streams[videoStream]->time_base.den, pFormatCtx->streams[videoStream]->r_frame_rate.num, pFormatCtx->streams[videoStream]->r_frame_rate.den, pFormatCtx->streams[videoStream]->duration);
160

    
161
        fprintf(stderr, "INIT: Video stream has id : %d\n",videoStream);
162
        fprintf(stderr, "INIT: Audio stream has id : %d\n",audioStream);
163

    
164
        if(videoStream==-1 && audioStream==-1) {
165
                fprintf(stdout, "INIT: Didn't find audio and video streams. Exiting.\n");
166
                exit(-1);
167
        }
168

    
169
        // Get a pointer to the codec context for the input video stream
170
        pCodecCtx=pFormatCtx->streams[videoStream]->codec;
171
        pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
172
        //extract W and H
173
        fprintf(stderr, "INIT: Width:%d Height:%d\n", pCodecCtx->width, pCodecCtx->height);
174

    
175
        // Get a pointer to the codec context for the input audio stream
176
        if(audioStream != -1) {
177
                aCodecCtx=pFormatCtx->streams[audioStream]->codec;
178
                fprintf(stderr, "INIT: AUDIO Codecid: %d channels %d samplerate %d\n", aCodecCtx->codec_id, aCodecCtx->channels, aCodecCtx->sample_rate);
179
        }
180

    
181
        //setup video output encoder
182
        pCodecCtxEnc=avcodec_alloc_context();
183
#ifdef H264_VIDEO_ENCODER
184
        pCodecCtxEnc->me_range=16;
185
        pCodecCtxEnc->max_qdiff=4;
186
        pCodecCtxEnc->qmin=1;
187
        pCodecCtxEnc->qmax=30;
188
        pCodecCtxEnc->qcompress=0.6;
189
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
190
        pCodecCtxEnc->codec_id   = CODEC_ID_H264;//13;//pCodecCtx->codec_id;
191
        pCodecCtxEnc->bit_rate = video_bitrate;///400000;
192
        // resolution must be a multiple of two 
193
        pCodecCtxEnc->width = pCodecCtx->width;
194
        pCodecCtxEnc->height = pCodecCtx->height;
195
        // frames per second 
196
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
197
        pCodecCtxEnc->gop_size = 100; // emit one intra frame every ten frames 
198
        //pCodecCtxEnc->max_b_frames=1;
199
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
200

    
201
        pCodecCtxEnc->bit_rate_tolerance = video_bitrate*50;
202
//        pCodecCtxEnc->rc_min_rate = 0;
203
//        pCodecCtxEnc->rc_max_rate = 0;
204
//        pCodecCtxEnc->rc_buffer_size = 0;
205
//        pCodecCtxEnc->flags |= CODEC_FLAG_PSNR;
206
//        pCodecCtxEnc->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8;
207
//        pCodecCtxEnc->crf = 0.0f;
208

    
209
#else
210
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
211
        pCodecCtxEnc->codec_id   = CODEC_ID_MPEG4;
212
        pCodecCtxEnc->bit_rate = video_bitrate;
213
        //times 20 follows the defaults, was not needed in previous versions of libavcodec
214
        pCodecCtxEnc->bit_rate_tolerance = video_bitrate*20;
215
//        pCodecCtxEnc->crf = 20.0f;
216
        pCodecCtxEnc->width = pCodecCtx->width;
217
        pCodecCtxEnc->height = pCodecCtx->height;
218
        // frames per second 
219
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
220
        pCodecCtxEnc->gop_size = 100; // emit one intra frame every ten frames 
221
        //pCodecCtxEnc->max_b_frames=1;
222
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
223
#endif
224
        fprintf(stderr, "INIT: VIDEO timebase OUT:%d %d IN: %d %d\n", pCodecCtxEnc->time_base.num, pCodecCtxEnc->time_base.den, pCodecCtx->time_base.num, pCodecCtx->time_base.den);
225

    
226
        // Find the decoder for the video stream
227
#ifdef H264_VIDEO_ENCODER
228
        fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264);
229
        pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id);
230
#else
231
        fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4);
232
        pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4);
233
#endif
234
        if(pCodec==NULL) {
235
                fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n");
236
                return -1; // Codec not found
237
        }
238
        if(pCodecEnc==NULL) {
239
                fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n");
240
                return -1; // Codec not found
241
        }
242
        if(avcodec_open(pCodecCtx, pCodec)<0) {
243
                fprintf(stderr, "INIT: could not open IN VIDEO codec\n");
244
                return -1; // Could not open codec
245
        }
246
        if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) {
247
                fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n");
248
                return -1; // Could not open codec
249
        }
250

    
251

    
252
        //setup audio output encoder
253
        aCodecCtxEnc = avcodec_alloc_context();
254
        aCodecCtxEnc->bit_rate = audio_bitrate; //256000
255
        aCodecCtxEnc->sample_fmt = SAMPLE_FMT_S16;
256
        aCodecCtxEnc->sample_rate = aCodecCtx->sample_rate;
257
        aCodecCtxEnc->channels = aCodecCtx->channels;
258
        fprintf(stderr, "INIT: AUDIO bitrate OUT:%d sample_rate:%d channels:%d\n", aCodecCtxEnc->bit_rate, aCodecCtxEnc->sample_rate, aCodecCtxEnc->channels);
259

    
260
        // Find the decoder for the audio stream
261
        if(audioStream!=-1) {
262
                aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
263
#ifdef MP3_AUDIO_ENCODER
264
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP3);
265
#else
266
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP2);
267
#endif
268
                if(aCodec==NULL) {
269
                        fprintf(stderr,"INIT: Unsupported acodec!\n");
270
                        return -1;
271
                }
272
                if(aCodecEnc==NULL) {
273
                        fprintf(stderr,"INIT: Unsupported acodecEnc!\n");
274
                        return -1;
275
                }
276
        
277
                if(avcodec_open(aCodecCtx, aCodec)<0) {
278
                        fprintf(stderr, "INIT: could not open IN AUDIO codec\n");
279
                        return -1; // Could not open codec
280
                }
281
                if(avcodec_open(aCodecCtxEnc, aCodecEnc)<0) {
282
                        fprintf(stderr, "INIT: could not open OUT AUDIO codec\n");
283
                        return -1; // Could not open codec
284
                }
285
        }
286

    
287
        // Allocate audio in and out buffers
288
        samples = (int16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
289
        if(samples == NULL) {
290
                fprintf(stderr, "INIT: Memory error alloc audio samples!!!\n");
291
                return -1;
292
        }
293
        audio_outbuf_size = STREAMER_MAX_AUDIO_BUFFER_SIZE;
294
        audio_outbuf = av_malloc(audio_outbuf_size);
295
        if(audio_outbuf == NULL) {
296
                fprintf(stderr, "INIT: Memory error alloc audio_outbuf!!!\n");
297
                return -1;
298
        }
299

    
300
        // Allocate video in frame and out buffer
301
        pFrame=avcodec_alloc_frame();
302
        if(pFrame==NULL) {
303
                fprintf(stderr, "INIT: Memory error alloc video frame!!!\n");
304
                return -1;
305
        }
306
        video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE;
307
        video_outbuf = av_malloc(video_outbuf_size);
308
        if(!video_outbuf) {
309
                fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n");
310
                return -1;
311
        }
312

    
313
        //allocate Napa-Wine transport
314
        frame = (Frame *)malloc(sizeof(Frame));
315
        if(!frame) {
316
                fprintf(stderr, "INIT: Memory error alloc Frame!!!\n");
317
                return -1;
318
        }
319
        //create an empty first video chunk
320
        chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
321
        if(!chunk) {
322
                fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
323
                return -1;
324
        }
325
        chunk->data = NULL;
326
        chunk->seq = 0;
327
        //initChunk(chunk, &seq_current_chunk); if i init them now i get out of sequence
328
#ifdef DEBUG_CHUNKER
329
        fprintf(stderr, "INIT: chunk video %d\n", chunk->seq);
330
#endif
331
        //create empty first audio chunk
332
        chunkaudio = (ExternalChunk *)malloc(sizeof(ExternalChunk));
333
        if(!chunkaudio) {
334
                fprintf(stderr, "INIT: Memory error alloc chunkaudio!!!\n");
335
                return -1;
336
        }
337
  chunkaudio->data=NULL;
338
        chunkaudio->seq = 0;
339
        //initChunk(chunkaudio, &seq_current_chunk);
340
#ifdef DEBUG_CHUNKER
341
        fprintf(stderr, "INIT: chunk audio %d\n", chunkaudio->seq);
342
#endif
343

    
344
        /* initialize the HTTP chunk pusher */
345
        initChunkPusher(); //TRIPLO
346

    
347
        long sleep=0;
348
        struct timeval now_tv;
349
        struct timeval tmp_tv;
350
        long long lateTime = 0;
351
        long long maxAudioInterval = 0;
352
        long long maxVDecodeTime = 0;
353

    
354
        //main loop to read from the input file
355
        while(av_read_frame(pFormatCtx, &packet)>=0)
356
        {
357
                //detect if a strange number of anomalies is occurring
358
                if(ptsvideo1 < 0 || ptsvideo1 > packet.dts || ptsaudio1 < 0 || ptsaudio1 > packet.dts) {
359
                        pts_anomalies_counter++;
360
#ifdef DEBUG_ANOMALIES
361
                        fprintf(stderr, "READLOOP: pts BASE anomaly detected number %d\n", pts_anomalies_counter);
362
#endif
363
                        if(live_source) { //reset just in case of live source
364
                                if(pts_anomalies_counter > 25) { //just a random threshold
365
                                        pts_anomalies_counter = 0;
366
                                        FirstTimeVideo = 1;
367
                                        FirstTimeAudio = 1;
368
#ifdef DEBUG_ANOMALIES
369
                                        fprintf(stderr, "READLOOP: too many pts BASE anomalies. resetting pts base\n");
370
#endif
371
                                }
372
                        }
373
                }
374

    
375
                if(newtime_anomalies_counter > 50) { //just a random threshold
376
                        if(live_source) { //restart just in case of live source
377
#ifdef DEBUG_ANOMALIES
378
                                fprintf(stderr, "READLOOP: too many NEGATIVE TIMESTAMPS anomalies. Restarting.\n");
379
#endif
380
                                goto close;
381
                        }
382
                }
383

    
384
                // Is this a packet from the video stream?
385
                if(packet.stream_index==videoStream)
386
                {
387
                        if(!live_source)
388
                        {
389
                                // lateTime < 0 means a positive time account that can be used to decode video frames
390
                                // if (lateTime + maxVDecodeTime) >= 0 then we may have a negative time account after video transcoding
391
                                // therefore, it's better to skip the frame
392
                                if((lateTime+maxVDecodeTime) >= 0)
393
                                {
394
#ifdef DEBUG_ANOMALIES
395
                                        fprintf(stderr, "\n\n\t\t************************* SKIPPING VIDEO FRAME ***********************************\n\n", sleep);
396
#endif
397
                                        continue;
398
                                }
399
                        }
400
                        
401
                        gettimeofday(&tmp_tv, NULL);
402
                        
403
                        //decode the video packet into a raw pFrame
404
                        if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet)>0)
405
                        {
406
                                // usleep(5000);
407
#ifdef DEBUG_VIDEO_FRAMES
408
                                fprintf(stderr, "\n-------VIDEO FRAME type %d\n", pFrame->pict_type);
409
                                fprintf(stderr, "VIDEO: dts %lld pts %lld\n", packet.dts, packet.pts);
410
#endif
411
                                if(frameFinished) { // it must be true all the time else error
412
                                        frame->number = contFrameVideo;
413
#ifdef DEBUG_VIDEO_FRAMES
414
                                        fprintf(stderr, "VIDEO: finished frame %d dts %lld pts %lld\n", frame->number, packet.dts, packet.pts);
415
#endif
416
                                        if(frame->number==0) {
417
                                                if(packet.dts==AV_NOPTS_VALUE)
418
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
419
                                                        continue;
420
                                                last_pkt_dts = packet.dts;
421
                                                newTime = 0;
422
                                        }
423
                                        else {
424
                                                if(packet.dts!=AV_NOPTS_VALUE) {
425
                                                        delta_video = packet.dts-last_pkt_dts;
426
                                                        last_pkt_dts = packet.dts;
427
                                                }
428
                                                else if(delta_video==0)
429
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
430
                                                        continue;
431
                                        }
432
#ifdef DEBUG_VIDEO_FRAMES
433
                                        fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video);
434
#endif
435
                                        video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
436
                                        if(video_frame_size <= 0)
437
                                                continue;
438
#ifdef DEBUG_VIDEO_FRAMES
439
                                        fprintf(stderr, "VIDEO: original codec frame number %d vs. encoded %d vs. packed %d\n", pCodecCtx->frame_number, pCodecCtxEnc->frame_number, frame->number);
440
                                        fprintf(stderr, "VIDEO: duration %d timebase %d %d container timebase %d\n", (int)packet.duration, pCodecCtxEnc->time_base.den, pCodecCtxEnc->time_base.num, pCodecCtx->time_base.den);
441
#endif
442

    
443
                                        //use pts if dts is invalid
444
                                        if(packet.dts!=AV_NOPTS_VALUE)
445
                                                target_pts = packet.dts;
446
                                        else if(packet.pts!=AV_NOPTS_VALUE)
447
                                                target_pts = packet.pts;
448
                                        else
449
                                                continue;
450

    
451
                                        if(!offset_av)
452
                                        {
453
                                                if(FirstTimeVideo && packet.dts>0) {
454
                                                        ptsvideo1 = (double)packet.dts;
455
                                                        FirstTimeVideo = 0;
456
#ifdef DEBUG_VIDEO_FRAMES
457
                                                        fprintf(stderr, "VIDEO: SET PTS BASE OFFSET %f\n", ptsvideo1);
458
#endif
459
                                                }
460
                                        }
461
                                        else //we want to compensate audio and video offset for this source
462
                                        {
463
                                                if(FirstTimeVideo && packet.dts>0) {
464
                                                        //maintain the offset between audio pts and video pts
465
                                                        //because in case of live source they have the same numbering
466
                                                        if(ptsaudio1 > 0) //if we have already seen some audio frames...
467
                                                                ptsvideo1 = ptsaudio1;
468
                                                        else
469
                                                                ptsvideo1 = (double)packet.dts;
470
                                                        FirstTimeVideo = 0;
471
#ifdef DEBUG_VIDEO_FRAMES
472
                                                        fprintf(stderr, "VIDEO LIVE: SET PTS BASE OFFSET %f\n", ptsvideo1);
473
#endif
474
                                                }
475
                                        }
476
                                        //compute the new video timestamp in milliseconds
477
                                        if(frame->number>0) {
478
                                                newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
479
                                        }
480
#ifdef DEBUG_TIMESTAMPING
481
                                        fprintf(stderr, "VIDEO: NEWTIMESTAMP %ld\n", newTime);
482
#endif
483
                                        if(newTime<0) {
484
#ifdef DEBUG_VIDEO_FRAMES
485
                                                fprintf(stderr, "VIDEO: SKIPPING FRAME\n");
486
#endif
487
                                                newtime_anomalies_counter++;
488
                                                continue; //SKIP THIS FRAME, bad timestamp
489
                                        }
490
        
491
                                        frame->timestamp.tv_sec = (long long)newTime/1000;
492
                                        frame->timestamp.tv_usec = newTime%1000;
493
                                        frame->size = video_frame_size;
494
                                        frame->type = pFrame->pict_type;
495
#ifdef DEBUG_VIDEO_FRAMES
496
                                        fprintf(stderr, "VIDEO: encapsulated frame size:%d type:%d\n", frame->size, frame->type);
497
                                        fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
498
#endif
499
                                        contFrameVideo++; //lets increase the numbering of the frames
500

    
501
                                        if(update_chunk(chunk, frame, video_outbuf) == -1) {
502
                                                fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq);
503
                                                exit(-1);
504
                                        }
505

    
506
                                        if(chunkFilled(chunk, cmeta)) { // is chunk filled using current strategy?
507
                                                //SAVE ON FILE
508
                                                //saveChunkOnFile(chunk);
509
                                                //Send the chunk via http to an external transport/player
510
                                                pushChunkHttp(chunk, cmeta->outside_world_url);
511
#ifdef DEBUG_CHUNKER
512
                                                fprintf(stderr, "VIDEO: sent chunk video %d\n", chunk->seq);
513
#endif
514
                                                chunk->seq = 0; //signal that we need an increase
515
                                                //initChunk(chunk, &seq_current_chunk);
516
                                                
517
                                                gettimeofday(&now_tv, NULL);
518
                                                long long usec = (now_tv.tv_sec-tmp_tv.tv_sec)*1000000;
519
                                                usec+=(now_tv.tv_usec-tmp_tv.tv_usec);
520
                                                
521
                                                if(usec > maxVDecodeTime)
522
                                                        maxVDecodeTime = usec;
523
                                        }
524
                                        /* pict_type maybe 1 (I), 2 (P), 3 (B), 5 (AUDIO)*/
525
                                }
526
                        }
527
                }
528
                else if(packet.stream_index==audioStream)
529
                {
530
                        if(sleep > 0)
531
                        {
532
#ifdef DEBUG_ANOMALIES
533
                                fprintf(stderr, "\n\tREADLOOP: going to sleep for %ld microseconds\n", sleep);
534
#endif
535
                                usleep(sleep);
536
                        }
537
                        
538
                        audio_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
539
                        //decode the audio packet into a raw audio source buffer
540
                        if(avcodec_decode_audio3(aCodecCtx, samples, &audio_data_size, &packet)>0)
541
                        {
542
#ifdef DEBUG_AUDIO_FRAMES
543
                                fprintf(stderr, "\n-------AUDIO FRAME\n");
544
                                fprintf(stderr, "AUDIO: newTimeaudioSTART : %lf\n", (double)(packet.pts)*av_q2d(pFormatCtx->streams[audioStream]->time_base));
545
#endif
546
                                if(audio_data_size>0) {
547
#ifdef DEBUG_AUDIO_FRAMES
548
                                        fprintf(stderr, "AUDIO: datasizeaudio:%d\n", audio_data_size);
549
#endif
550
                                        /* if a frame has been decoded, output it */
551
                                        //fwrite(samples, 1, audio_data_size, outfileaudio);
552
                                }
553
                                else
554
                                        continue;
555
        
556
                                audio_frame_size = avcodec_encode_audio(aCodecCtxEnc, audio_outbuf, audio_data_size, samples);
557
                                if(audio_frame_size <= 0)
558
                                        continue;
559
                                
560
                                frame->number = contFrameAudio;
561

    
562
                                if(frame->number==0) {
563
                                        if(packet.dts==AV_NOPTS_VALUE)
564
                                                continue;
565
                                        last_pkt_dts_audio = packet.dts;
566
                                        newTime = 0;
567
                                }
568
                                else {
569
                                        if(packet.dts!=AV_NOPTS_VALUE) {
570
                                                delta_audio = packet.dts-last_pkt_dts_audio;
571
                                                last_pkt_dts_audio = packet.dts;
572
                                        }
573
                                        else if(delta_audio==0)
574
                                                continue;
575
                                }
576
#ifdef DEBUG_AUDIO_FRAMES
577
                                fprintf(stderr, "AUDIO: original codec frame number %d vs. encoded %d vs. packed %d\n", aCodecCtx->frame_number, aCodecCtxEnc->frame_number, frame->number);
578
#endif
579
                                //use pts if dts is invalid
580
                                if(packet.dts!=AV_NOPTS_VALUE)
581
                                        target_pts = packet.dts;
582
                                else if(packet.pts!=AV_NOPTS_VALUE)
583
                                        target_pts = packet.pts;
584
                                else
585
                                        continue;
586

    
587
                                if(!offset_av)
588
                                {
589
                                        if(FirstTimeAudio && packet.dts>0) {
590
                                                ptsaudio1 = (double)packet.dts;
591
                                                FirstTimeAudio = 0;
592
#ifdef DEBUG_AUDIO_FRAMES
593
                                                fprintf(stderr, "AUDIO: SET PTS BASE OFFSET %f\n", ptsaudio1);
594
#endif
595
                                        }
596
                                }
597
                                else //we want to compensate audio and video offset for this source
598
                                {
599
                                        if(FirstTimeAudio && packet.dts>0) {
600
                                                //maintain the offset between audio pts and video pts
601
                                                //because in case of live source they have the same numbering
602
                                                if(ptsvideo1 > 0) //if we have already seen some video frames...
603
                                                        ptsaudio1 = ptsvideo1;
604
                                                else
605
                                                        ptsaudio1 = (double)packet.dts;
606
                                                FirstTimeAudio = 0;
607
#ifdef DEBUG_AUDIO_FRAMES
608
                                                fprintf(stderr, "AUDIO LIVE: SET PTS BASE OFFSET %f\n", ptsaudio1);
609
#endif
610
                                        }
611
                                }
612
                                //compute the new audio timestamps in milliseconds
613
                                if(frame->number>0) {
614
                                        newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio;
615
                                        
616
                                        // store timestamp in useconds for next frame sleep
617
                                        newTime_audio = newTime*1000;
618
                                        
619
                                }
620
#ifdef DEBUG_TIMESTAMPING
621
                                fprintf(stderr, "AUDIO: NEWTIMESTAMP %d\n", newTime);
622
#endif
623
                                if(newTime<0) {
624
#ifdef DEBUG_AUDIO_FRAMES
625
                                        fprintf(stderr, "AUDIO: SKIPPING FRAME\n");
626
#endif
627
                                        newtime_anomalies_counter++;
628
                                        continue; //SKIP THIS FRAME, bad timestamp
629
                                }
630

    
631
                                frame->timestamp.tv_sec = (unsigned int)newTime/1000;
632
                                frame->timestamp.tv_usec = newTime%1000;
633
                                frame->size = audio_frame_size;
634
                                frame->type = 5; // 5 is audio type
635
#ifdef DEBUG_AUDIO_FRAMES
636
                                fprintf(stderr, "AUDIO: pts %d duration %d timebase %d %d dts %d\n", (int)packet.pts, (int)packet.duration, pFormatCtx->streams[audioStream]->time_base.num, pFormatCtx->streams[audioStream]->time_base.den, (int)packet.dts);
637
                                fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
638
                                fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio);        
639
#endif
640
                                contFrameAudio++;
641

    
642
                                if(update_chunk(chunkaudio, frame, audio_outbuf) == -1) {
643
                                        fprintf(stderr, "AUDIO: unable to update chunk %d. Exiting.\n", chunkaudio->seq);
644
                                        exit(-1);
645
                                }
646
                                //set priority
647
                                chunkaudio->priority = 1;
648

    
649
                                if(chunkFilled(chunkaudio, cmeta))
650
                                {
651
                                        if(!live_source)
652
                                        {
653
                                                if(newTime_prev != 0)
654
                                                {
655
                                                        long long maxDelay = newTime_audio - newTime_prev;
656

    
657
                                                        gettimeofday(&now_tv, NULL);
658
                                                        long long usec = (now_tv.tv_sec-lastAudioSent.tv_sec)*1000000;
659
                                                        usec+=(now_tv.tv_usec-lastAudioSent.tv_usec);
660

    
661
                                                        if(usec > maxAudioInterval)
662
                                                                maxAudioInterval = usec;
663

    
664
                                                        lateTime -= (maxDelay - usec);
665
#ifdef DEBUG_ANOMALIES
666
                                                        printf("\tmaxDelay=%ld, maxAudioInterval=%ld\n", ((long)maxDelay), ((long) maxAudioInterval));
667
                                                        printf("\tlast audio frame interval=%ld; lateTime=%ld\n", ((long)usec), ((long)lateTime));
668
#endif
669

    
670
                                                        if((lateTime+maxAudioInterval) < 0)
671
                                                                sleep = (lateTime+maxAudioInterval)*-1;
672
                                                        else
673
                                                                sleep = 0;
674
                                                }
675
                                                else
676
                                                        sleep = 0;
677

    
678
                                                newTime_prev = newTime_audio;
679
                                                gettimeofday(&lastAudioSent, NULL);
680
                                        }
681
                                        
682
                                        // is chunk filled using current strategy?
683
                                        //SAVE ON FILE
684
                                        //saveChunkOnFile(chunkaudio);
685
                                        //Send the chunk via http to an external transport/player
686
                                        pushChunkHttp(chunkaudio, cmeta->outside_world_url);
687
#ifdef DEBUG_CHUNKER
688
                                        fprintf(stderr, "AUDIO: just sent chunk audio %d\n", chunkaudio->seq);
689
#endif
690
                                        chunkaudio->seq = 0; //signal that we need an increase
691
                                        //initChunk(chunkaudio, &seq_current_chunk);
692
                                }
693
                        }
694
                }
695
                else {
696
#ifdef DEBUG_CHUNKER
697
                        fprintf(stderr,"Free the packet that was allocated by av_read_frame\n");
698
#endif
699
                        av_free_packet(&packet);
700
                }
701
        }
702

    
703
close:
704
        if(chunk->seq != 0 && chunk->frames_num>0) {
705
                //SAVE ON FILE
706
                //saveChunkOnFile(chunk);
707
                //Send the chunk via http to an external transport/player
708
                pushChunkHttp(chunk, cmeta->outside_world_url);
709
#ifdef DEBUG_CHUNKER
710
                fprintf(stderr, "CHUNKER: SENDING LAST VIDEO CHUNK\n");
711
#endif
712
                chunk->seq = 0; //signal that we need an increase just in case we will restart
713
        }
714
        if(chunkaudio->seq != 0 && chunkaudio->frames_num>0) {
715
                //SAVE ON FILE     
716
                //saveChunkOnFile(chunkaudio);
717
                //Send the chunk via http to an external transport/player
718
                pushChunkHttp(chunkaudio, cmeta->outside_world_url);
719
#ifdef DEBUG_CHUNKER
720
                fprintf(stderr, "CHUNKER: SENDING LAST AUDIO CHUNK\n");
721
#endif
722
                chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
723
        }
724

    
725
        /* finalize the HTTP chunk pusher */
726
        finalizeChunkPusher();
727

    
728
        free(chunk);
729
        free(chunkaudio);
730
        free(frame);
731
        av_free(video_outbuf);
732
        av_free(audio_outbuf);
733
        free(cmeta);
734

    
735
        // Free the YUV frame
736
        av_free(pFrame);
737
        av_free(samples);
738
  
739
        // Close the codec
740
        avcodec_close(pCodecCtx);
741
        avcodec_close(pCodecCtxEnc);
742

    
743
        if(audioStream!=-1) {
744
                avcodec_close(aCodecCtx);
745
                avcodec_close(aCodecCtxEnc);
746
        }
747
  
748
        // Close the video file
749
        av_close_input_file(pFormatCtx);
750

    
751
        if(LOOP_MODE) {
752
                //we want video to continue, but the av_read_frame stopped
753
                //lets wait a 5 secs, and cycle in again
754
                usleep(5000000);
755
#ifdef DEBUG_CHUNKER
756
                fprintf(stderr, "CHUNKER: WAITING 5 secs FOR LIVE SOURCE TO SKIP ERRORS AND RESTARTING\n");
757
#endif
758
                videoStream = -1;
759
                audioStream = -1;
760
                FirstTimeAudio=1;
761
                FirstTimeVideo=1;
762
                pts_anomalies_counter=0;
763
                newtime_anomalies_counter=0;
764
                newTime=0;
765
                newTime_audio=0;
766
                newTime_prev=0;
767
                ptsvideo1=0.0;
768
                ptsaudio1=0.0;
769
                last_pkt_dts=0;
770
                delta_video=0;
771
                delta_audio=0;
772
                last_pkt_dts_audio=0;
773
                target_pts=0;
774
                i=0;
775
                goto restart;
776
        }
777

    
778
        return 0;
779
}
780

    
781

    
782
int update_chunk(ExternalChunk *chunk, Frame *frame, uint8_t *outbuf) {
783
        //the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
784
        static int sizeFrameHeader = 5*sizeof(int32_t);
785

    
786
        //moving temp pointer to encode Frame on the wire
787
        uint8_t *tempdata = NULL;
788

    
789
        if(chunk->seq == 0) {
790
                initChunk(chunk, &seq_current_chunk);
791
        }
792
        //HINT on malloc
793
        chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len + frame->size + sizeFrameHeader));
794
        if(!chunk->data)  {
795
                fprintf(stderr, "Memory error in chunk!!!\n");
796
                return -1;
797
        }
798
        chunk->frames_num++; // number of frames in the current chunk
799

    
800
/*
801
        //package the Frame header
802
        tempdata = chunk->data+chunk->payload_len;
803
        *((int32_t *)tempdata) = frame->number;
804
        tempdata+=sizeof(int32_t);
805
        *((struct timeval *)tempdata) = frame->timestamp;
806
        tempdata+=sizeof(struct timeval);
807
        *((int32_t *)tempdata) = frame->size;
808
        tempdata+=sizeof(int32_t);
809
        *((int32_t *)tempdata) = frame->type;
810
        tempdata+=sizeof(int32_t);
811
*/
812
        //package the Frame header: network order and platform independent
813
        tempdata = chunk->data+chunk->payload_len;
814
        bit32_encoded_push(frame->number, tempdata);
815
        bit32_encoded_push(frame->timestamp.tv_sec, tempdata + CHUNK_TRANSCODING_INT_SIZE);
816
        bit32_encoded_push(frame->timestamp.tv_usec, tempdata + CHUNK_TRANSCODING_INT_SIZE*2);
817
        bit32_encoded_push(frame->size, tempdata + CHUNK_TRANSCODING_INT_SIZE*3);
818
        bit32_encoded_push(frame->type, tempdata + CHUNK_TRANSCODING_INT_SIZE*4);
819

    
820
         //insert the new frame data
821
        memcpy(chunk->data + chunk->payload_len + sizeFrameHeader, outbuf, frame->size);
822
        chunk->payload_len += frame->size + sizeFrameHeader; // update payload length
823
        //chunk lenght is updated just prior to pushing it out because
824
        //the chunk header len is better calculated there
825
        //chunk->len = sizeChunkHeader + chunk->payload_len; // update overall length
826

    
827
        //update timestamps
828
        if(((int)frame->timestamp.tv_sec < (int)chunk->start_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->start_time.tv_sec && (int)frame->timestamp.tv_usec < (int)chunk->start_time.tv_usec) || (int)chunk->start_time.tv_sec==-1) {
829
                                                chunk->start_time.tv_sec = frame->timestamp.tv_sec;
830
                                                chunk->start_time.tv_usec = frame->timestamp.tv_usec;
831
        }
832
        
833
        if(((int)frame->timestamp.tv_sec > (int)chunk->end_time.tv_sec) || ((int)frame->timestamp.tv_sec==(int)chunk->end_time.tv_sec && (int)frame->timestamp.tv_usec > (int)chunk->end_time.tv_usec) || (int)chunk->end_time.tv_sec==-1) {
834
                                                chunk->end_time.tv_sec = frame->timestamp.tv_sec;
835
                                                chunk->end_time.tv_usec = frame->timestamp.tv_usec;
836
        }
837
        return 0;
838
}
839