Statistics
| Branch: | Revision:

chunker-player / chunker_streamer / chunker_streamer.c @ df2ad829

History | View | Annotate | Download (27.3 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=10;
187
        pCodecCtxEnc->qmax=51;
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 = 10; // 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;
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
        pCodecCtxEnc->width = pCodecCtx->width;
214
        pCodecCtxEnc->height = pCodecCtx->height;
215
        // frames per second 
216
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
217
        pCodecCtxEnc->gop_size = 10; // emit one intra frame every ten frames 
218
        //pCodecCtxEnc->max_b_frames=1;
219
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
220
#endif
221
        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);
222

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

    
248

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

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

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

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

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

    
341
        /* initialize the HTTP chunk pusher */
342
        initChunkPusher(); //TRIPLO
343

    
344
        long sleep=0;
345
        struct timeval now_tv;
346
        struct timeval tmp_tv;
347
        long long lateTime = 0;
348
        long long maxAudioInterval = 0;
349
        long long maxVDecodeTime = 0;
350

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

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

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

    
440
                                        //use pts if dts is invalid
441
                                        if(packet.dts!=AV_NOPTS_VALUE)
442
                                                target_pts = packet.dts;
443
                                        else if(packet.pts!=AV_NOPTS_VALUE)
444
                                                target_pts = packet.pts;
445
                                        else
446
                                                continue;
447

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

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

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

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

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

    
628
                                frame->timestamp.tv_sec = (unsigned int)newTime/1000;
629
                                frame->timestamp.tv_usec = newTime%1000;
630
                                frame->size = audio_frame_size;
631
                                frame->type = 5; // 5 is audio type
632
#ifdef DEBUG_AUDIO_FRAMES
633
                                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);
634
                                fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
635
                                fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio);        
636
#endif
637
                                contFrameAudio++;
638

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

    
646
                                if(chunkFilled(chunkaudio, cmeta))
647
                                {
648
                                        if(!live_source)
649
                                        {
650
                                                if(newTime_prev != 0)
651
                                                {
652
                                                        long long maxDelay = newTime_audio - newTime_prev;
653

    
654
                                                        gettimeofday(&now_tv, NULL);
655
                                                        long long usec = (now_tv.tv_sec-lastAudioSent.tv_sec)*1000000;
656
                                                        usec+=(now_tv.tv_usec-lastAudioSent.tv_usec);
657

    
658
                                                        if(usec > maxAudioInterval)
659
                                                                maxAudioInterval = usec;
660

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

    
667
                                                        if((lateTime+maxAudioInterval) < 0)
668
                                                                sleep = (lateTime+maxAudioInterval)*-1;
669
                                                        else
670
                                                                sleep = 0;
671
                                                }
672
                                                else
673
                                                        sleep = 0;
674

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

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

    
722
        /* finalize the HTTP chunk pusher */
723
        finalizeChunkPusher();
724

    
725
        free(chunk);
726
        free(chunkaudio);
727
        free(frame);
728
        av_free(video_outbuf);
729
        av_free(audio_outbuf);
730
        free(cmeta);
731

    
732
        // Free the YUV frame
733
        av_free(pFrame);
734
        av_free(samples);
735
  
736
        // Close the codec
737
        avcodec_close(pCodecCtx);
738
        avcodec_close(pCodecCtxEnc);
739

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

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

    
775
        return 0;
776
}
777

    
778

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

    
783
        //moving temp pointer to encode Frame on the wire
784
        uint8_t *tempdata = NULL;
785

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

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

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

    
824
        //update timestamps
825
        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) {
826
                                                chunk->start_time.tv_sec = frame->timestamp.tv_sec;
827
                                                chunk->start_time.tv_usec = frame->timestamp.tv_usec;
828
        }
829
        
830
        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) {
831
                                                chunk->end_time.tv_sec = frame->timestamp.tv_sec;
832
                                                chunk->end_time.tv_usec = frame->timestamp.tv_usec;
833
        }
834
        return 0;
835
}
836