Statistics
| Branch: | Revision:

chunker-player / chunker_streamer.c @ 648357d7

History | View | Annotate | Download (23.1 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 <libavcodec/avcodec.h>
12
#include <libavformat/avformat.h>
13

    
14
#include <stdio.h>
15

    
16
#include "chunker_streamer.h"
17
#include "codec_definitions.h"
18

    
19
//#define DEBUG_AUDIO_FRAMES
20
//#define DEBUG_VIDEO_FRAMES
21
//#define DEBUG_CHUNKER
22
//#define DEBUG_TIME
23

    
24
ChunkerMetadata *cmeta = NULL;
25

    
26

    
27
int chunkFilled(ExternalChunk *echunk, ChunkerMetadata *cmeta) {
28
        // different strategies to implement
29
        if(cmeta->strategy == 0) // number of frames per chunk constant
30
                if(echunk->frames_num == cmeta->val_strategy)
31
                        return 1;
32
        
33
        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
34
                if(echunk->payload_len >= cmeta->val_strategy)
35
                        return 1;
36
        
37
        return 0;
38
}
39

    
40
/*
41
void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
42
        FILE *pFile;
43
        char szFilename[32];
44
        int  y;
45
  
46
  // Open file
47
        sprintf(szFilename, "frame%d.ppm", iFrame);
48

49
          pFile=fopen(szFilename, "wb");
50
          if(pFile==NULL)
51
                    return;
52
  
53
  // Write header
54
        fprintf(pFile, "P5\n%d %d\n255\n", width, height);
55
  
56
  // Write pixel data
57
          for(y=0; y<height; y++)
58
                    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile);
59
  
60
  // Close file
61
          fclose(pFile);
62
}
63
*/
64

    
65
/*
66
void saveChunkOnFile(ExternalChunk *chunk) {
67
        char buf[1024], outfile[1024];
68
        FILE *fp;
69
        
70
        strcpy(buf,"chunks//CHUNK");
71
        strcat(buf,"\0");
72
        sprintf(outfile,"%s%d",buf,chunk->seq);
73
        fp = fopen(outfile,"wb");
74
        fwrite(&(chunk->seq),sizeof(int),1,fp);
75
        fwrite(&(chunk->frames_num),sizeof(int),1,fp);
76
        fwrite(&(chunk->start_time),sizeof(struct timeval),1,fp);
77
        fwrite(&(chunk->end_time),sizeof(struct timeval),1,fp);
78
        fwrite(&(chunk->payload_len),sizeof(int),1,fp);
79
        fwrite(&(chunk->len),sizeof(int),1,fp);
80
        fwrite(&(chunk->category),sizeof(int),1,fp);
81
        fwrite(&(chunk->priority),sizeof(double),1,fp);
82
        fwrite(&(chunk->_refcnt),sizeof(int),1,fp);
83
        fwrite(chunk->data,sizeof(uint8_t),sizeof(uint8_t)*chunk->payload_len,fp);
84
        fclose(fp);
85
}
86
*/
87

    
88
void initChunk(ExternalChunk *chunk, int *seq_num) {
89
        chunk->seq = (*seq_num)++;
90
        chunk->frames_num = 0;
91
        chunk->payload_len = 0;
92
        chunk->len=0;
93
  if(chunk->data != NULL)
94
    free(chunk->data);
95
        chunk->data = NULL;
96
        chunk->start_time.tv_sec = -1;
97
        chunk->start_time.tv_usec = -1;
98
        chunk->end_time.tv_sec = -1;
99
        chunk->end_time.tv_usec = -1;
100
        chunk->priority = 0;
101
        chunk->category = 0;
102
        chunk->_refcnt = 0;
103
}
104

    
105
int main(int argc, char *argv[]) {
106
        int i=0;
107

    
108
        //output variables
109
        int seq_current_chunk = 1; //chunk numbering starts from 1; HINT do i need more bytes?
110
        uint8_t *video_outbuf = NULL;
111
        int video_outbuf_size, video_frame_size;
112
        uint8_t *audio_outbuf = NULL;
113
        int audio_outbuf_size, audio_frame_size;
114
        int audio_data_size;
115

    
116
        //numeric identifiers of input streams
117
        int videoStream = -1;
118
        int audioStream = -1;
119

    
120
        int len1;
121
        int frameFinished;
122
        //frame sequential counters
123
        int contFrameAudio=0, contFrameVideo=0;
124
        int numBytes;
125

    
126
        //command line parameters
127
        int audio_bitrate;
128
        int video_bitrate;
129
        int live_source = 0;
130
        
131
        //a raw buffer for decoded uncompressed audio samples
132
        int16_t *samples = NULL;
133
        //a raw uncompressed video picture
134
        AVFrame *pFrame = NULL;
135

    
136
        AVFormatContext *pFormatCtx;
137
        AVCodecContext  *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx;
138
        AVCodec         *pCodec,*pCodecEnc,*aCodec,*aCodecEnc;
139
        AVPacket         packet;
140

    
141
        //Napa-Wine specific Frame and Chunk structures for transport
142
        Frame *frame = NULL;
143
        ExternalChunk *chunk = NULL;
144
        ExternalChunk *chunkaudio = NULL;
145
        
146
        //char buf[1024], outfile[1024];
147

    
148
        //stuff needed to compute the right timestamps
149
        short int FirstTimeAudio=1, FirstTimeVideo=1;
150
        long long newTime;
151
        double ptsvideo1=0.0;
152
        double ptsaudio1=0.0;
153
        int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0;
154

    
155

    
156
        //scan the command line
157
        if(argc < 4) {
158
                fprintf(stderr, "execute ./chunker_streamer moviefile audiobitrate videobitrate <live source flag (0 or 1)>\n");
159
                return -1;
160
        }
161
        sscanf(argv[2],"%d", &audio_bitrate);
162
        sscanf(argv[3],"%d", &video_bitrate);
163
        if(argc==5) sscanf(argv[4],"%d", &live_source);
164

    
165
        // read the configuration file
166
        cmeta = chunkerInit();
167
        if(live_source)
168
                fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n");
169

    
170
        // Register all formats and codecs
171
        av_register_all();
172

    
173
        // Open input file
174
        if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) != 0) {
175
                fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n");
176
                exit(-1);
177
        }
178

    
179
        // Retrieve stream information
180
        if(av_find_stream_info(pFormatCtx) < 0) {
181
                fprintf(stdout, "INIT: Couldn't find stream information. Exiting.\n");
182
                exit(-1);
183
        }
184

    
185
        // Dump information about file onto standard error
186
        dump_format(pFormatCtx, 0, argv[1], 0);
187

    
188
        // Find the video and audio stream numbers
189
        for(i=0; i<pFormatCtx->nb_streams; i++) {
190
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && videoStream<0) {
191
                        videoStream=i;
192
                }
193
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audioStream<0) {
194
                        audioStream=i;
195
                }
196
        }
197
        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);
198

    
199
        fprintf(stderr, "INIT: Video stream has id : %d\n",videoStream);
200
        fprintf(stderr, "INIT: Audio stream has id : %d\n",audioStream);
201

    
202
        if(videoStream==-1 && audioStream==-1) {
203
                fprintf(stdout, "INIT: Didn't find audio and video streams. Exiting.\n");
204
                exit(-1);
205
        }
206

    
207
        // Get a pointer to the codec context for the input video stream
208
        pCodecCtx=pFormatCtx->streams[videoStream]->codec;
209
        pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
210
        //extract W and H
211
        fprintf(stderr, "INIT: Width:%d Height:%d\n", pCodecCtx->width, pCodecCtx->height);
212

    
213
        // Get a pointer to the codec context for the input audio stream
214
        if(audioStream != -1) {
215
                aCodecCtx=pFormatCtx->streams[audioStream]->codec;
216
                fprintf(stderr, "INIT: AUDIO Codecid: %d channels %d samplerate %d\n", aCodecCtx->codec_id, aCodecCtx->channels, aCodecCtx->sample_rate);
217
        }
218

    
219
        //setup video output encoder
220
        pCodecCtxEnc=avcodec_alloc_context();
221
#ifdef H264_VIDEO_ENCODER
222
        pCodecCtxEnc->me_range=16;
223
        pCodecCtxEnc->max_qdiff=4;
224
        pCodecCtxEnc->qmin=10;
225
        pCodecCtxEnc->qmax=51;
226
        pCodecCtxEnc->qcompress=0.6;
227
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
228
        pCodecCtxEnc->codec_id   = CODEC_ID_H264;//13;//pCodecCtx->codec_id;
229
        pCodecCtxEnc->bit_rate = video_bitrate;///400000;
230
        // resolution must be a multiple of two 
231
        pCodecCtxEnc->width = pCodecCtx->width;
232
        pCodecCtxEnc->height = pCodecCtx->height;
233
        // frames per second 
234
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
235
        pCodecCtxEnc->gop_size = 10; // emit one intra frame every ten frames 
236
        //pCodecCtxEnc->max_b_frames=1;
237
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
238
#else
239
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
240
        pCodecCtxEnc->codec_id   = CODEC_ID_MPEG4;
241
        pCodecCtxEnc->bit_rate = video_bitrate;
242
        pCodecCtxEnc->width = pCodecCtx->width;
243
        pCodecCtxEnc->height = pCodecCtx->height;
244
        // frames per second 
245
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
246
        pCodecCtxEnc->gop_size = 10; // emit one intra frame every ten frames 
247
        //pCodecCtxEnc->max_b_frames=1;
248
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
249
#endif
250
        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);
251

    
252
        // Find the decoder for the video stream
253
#ifdef H264_VIDEO_ENCODER
254
        fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264);
255
        pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id);
256
#else
257
        fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4);
258
        pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4);
259
#endif
260
        if(pCodec==NULL) {
261
                fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n");
262
                return -1; // Codec not found
263
        }
264
        if(pCodecEnc==NULL) {
265
                fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n");
266
                return -1; // Codec not found
267
        }
268
        if(avcodec_open(pCodecCtx, pCodec)<0) {
269
                fprintf(stderr, "INIT: could not open IN VIDEO codec\n");
270
                return -1; // Could not open codec
271
        }
272
        if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) {
273
                fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n");
274
                return -1; // Could not open codec
275
        }
276

    
277

    
278
        //setup audio output encoder
279
        aCodecCtxEnc = avcodec_alloc_context();
280
        aCodecCtxEnc->bit_rate = audio_bitrate; //256000
281
        aCodecCtxEnc->sample_fmt = SAMPLE_FMT_S16;
282
        aCodecCtxEnc->sample_rate = aCodecCtx->sample_rate;
283
        aCodecCtxEnc->channels = aCodecCtx->channels;
284
        fprintf(stderr, "INIT: AUDIO bitrate OUT:%d sample_rate:%d channels:%d\n", aCodecCtxEnc->bit_rate, aCodecCtxEnc->sample_rate, aCodecCtxEnc->channels);
285

    
286
        // Find the decoder for the audio stream
287
        if(audioStream!=-1) {
288
                aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
289
#ifdef MP3_AUDIO_ENCODER
290
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP3);
291
#else
292
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP2);
293
#endif
294
                if(aCodec==NULL) {
295
                        fprintf(stderr,"INIT: Unsupported acodec!\n");
296
                        return -1;
297
                }
298
                if(aCodecEnc==NULL) {
299
                        fprintf(stderr,"INIT: Unsupported acodecEnc!\n");
300
                        return -1;
301
                }
302
        
303
                if(avcodec_open(aCodecCtx, aCodec)<0) {
304
                        fprintf(stderr, "INIT: could not open IN AUDIO codec\n");
305
                        return -1; // Could not open codec
306
                }
307
                if(avcodec_open(aCodecCtxEnc, aCodecEnc)<0) {
308
                        fprintf(stderr, "INIT: could not open OUT AUDIO codec\n");
309
                        return -1; // Could not open codec
310
                }
311
        }
312

    
313
        // Allocate audio in and out buffers
314
        samples = (int16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
315
        if(samples == NULL) {
316
                fprintf(stderr, "INIT: Memory error alloc audio samples!!!\n");
317
                return -1;
318
        }
319
        audio_outbuf_size = STREAMER_MAX_AUDIO_BUFFER_SIZE;
320
        audio_outbuf = av_malloc(audio_outbuf_size);
321
        if(audio_outbuf == NULL) {
322
                fprintf(stderr, "INIT: Memory error alloc audio_outbuf!!!\n");
323
                return -1;
324
        }
325

    
326
        // Allocate video in frame and out buffer
327
        pFrame=avcodec_alloc_frame();
328
        if(pFrame==NULL) {
329
                fprintf(stderr, "INIT: Memory error alloc video frame!!!\n");
330
                return -1;
331
        }
332
        video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE;
333
        video_outbuf = av_malloc(video_outbuf_size);
334
        if(!video_outbuf) {
335
                fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n");
336
                return -1;
337
        }
338

    
339
        //allocate Napa-Wine transport
340
        frame = (Frame *)malloc(sizeof(Frame));
341
        if(!frame) {
342
                fprintf(stderr, "INIT: Memory error alloc Frame!!!\n");
343
                return -1;
344
        }
345
        chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
346
        if(!chunk) {
347
                fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
348
                return -1;
349
        }
350

    
351
        //init an empty first video chunk
352
        chunk->data=NULL;
353
        initChunk(chunk, &seq_current_chunk);
354
#ifdef DEBUG_CHUNKER
355
        fprintf(stderr, "INIT: chunk video %d\n", chunk->seq);
356
#endif
357
        //init empty first audio chunk
358
        chunkaudio = (ExternalChunk *)malloc(sizeof(ExternalChunk));
359
        if(!chunkaudio) {
360
                fprintf(stderr, "INIT: Memory error alloc chunkaudio!!!\n");
361
                return -1;
362
        }
363
  chunkaudio->data=NULL;
364
        initChunk(chunkaudio, &seq_current_chunk);
365
#ifdef DEBUG_CHUNKER
366
        fprintf(stderr, "INIT: chunk audio %d\n", chunkaudio->seq);
367
#endif
368

    
369
        /* initialize the HTTP chunk pusher */
370
        initChunkPusher(); //TRIPLO
371

    
372
//        i=0;
373

    
374
        //main loop to read from the input file
375
        while(av_read_frame(pFormatCtx, &packet)>=0) {
376
                // Is this a packet from the video stream?
377
                if(packet.stream_index==videoStream) {
378
                        //decode the video packet into a raw pFrame
379
                        if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet)>0) {
380
#ifdef DEBUG_VIDEO_FRAMES
381
                                fprintf(stderr, "-------VIDEO FRAME type %d\n", pFrame->pict_type);
382
                                fprintf(stderr, "VIDEO: dts %lld pts %lld\n", packet.dts, packet.pts);
383
#endif
384
                                if(frameFinished) { // it must be true all the time else error
385
                                        frame->number = contFrameVideo;
386
#ifdef DEBUG_VIDEO_FRAMES
387
                                        fprintf(stderr, "VIDEO: finished frame %d dts %lld pts %lld\n", frame->number, packet.dts, packet.pts);
388
#endif
389
                                        if(frame->number==0) {
390
                                                if(packet.dts==AV_NOPTS_VALUE)
391
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
392
                                                        continue;
393
                                                last_pkt_dts = packet.dts;
394
                                                newTime = 0;
395
                                        }
396
                                        else {
397
                                                if(packet.dts!=AV_NOPTS_VALUE) {
398
                                                        delta_video = packet.dts-last_pkt_dts;
399
                                                        last_pkt_dts = packet.dts;
400
                                                }
401
                                                else if(delta_video==0)
402
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
403
                                                        continue;
404
                                        }
405
#ifdef DEBUG_VIDEO_FRAMES
406
                                        fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video);
407
#endif
408
                                        video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
409
#ifdef DEBUG_VIDEO_FRAMES
410
                                        fprintf(stderr, "VIDEO: original codec frame number %d\n", pCodecCtx->frame_number);
411
                                        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);
412
#endif
413

    
414
                                        //use pts if dts is invalid
415
                                        if(packet.dts!=AV_NOPTS_VALUE)
416
                                                target_pts = packet.dts;
417
                                        else if(packet.pts!=AV_NOPTS_VALUE)
418
                                                target_pts = packet.pts;
419
                                        else
420
                                                continue;
421

    
422
                                        if(!live_source)
423
                                        {
424
                                                if(FirstTimeVideo && packet.pts>0) {
425
                                                        ptsvideo1 = (double)packet.dts;
426
                                                        FirstTimeVideo = 0;
427
#ifdef DEBUG_VIDEO_FRAMES
428
                                                        fprintf(stderr, "VIDEO: SET PTS BASE OFFSET %f\n", ptsvideo1);
429
#endif
430
                                                }
431
                                                if(frame->number>0) {
432
                                                        newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
433
                                                }
434
                                        }
435
                                        else //live source
436
                                        {
437
                                                if(FirstTimeVideo && packet.dts>0) {
438
                                                        //maintain the offset between audio pts and video pts
439
                                                        //because in case of live source they have the same numbering
440
                                                        if(ptsaudio1 > 0) //if we have already seen some audio frames...
441
                                                                ptsvideo1 = ptsaudio1;
442
                                                        else
443
                                                                ptsvideo1 = (double)packet.dts;
444
                                                        FirstTimeVideo = 0;
445
#ifdef DEBUG_VIDEO_FRAMES
446
                                                        fprintf(stderr, "VIDEO LIVE: SET PTS BASE OFFSET %f\n", ptsvideo1);
447
#endif
448
                                                }
449
                                                if(frame->number>0) {
450
                                                        newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
451
                                                }
452
                                        }
453
#ifdef DEBUG_VIDEO_FRAMES
454
                                        fprintf(stderr, "VIDEO: NEWTIMESTAMP %ld\n", newTime);
455
#endif
456
                                        if(newTime<0) {
457
#ifdef DEBUG_VIDEO_FRAMES
458
                                                fprintf(stderr, "VIDEO: SKIPPING FRAME\n");
459
#endif
460
                                                continue; //SKIP THIS FRAME, bad timestamp
461
                                        }
462
        
463
                                        frame->timestamp.tv_sec = (long long)newTime/1000;
464
                                        frame->timestamp.tv_usec = newTime%1000;
465
                                        frame->size = video_frame_size;
466
                                        frame->type = pFrame->pict_type;
467
#ifdef DEBUG_VIDEO_FRAMES
468
                                        fprintf(stderr, "VIDEO: encapsulated frame num:%d size:%d type:%d\n", frame->number, frame->size, frame->type);
469
                                        fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
470
#endif
471
                                        contFrameVideo++; //lets increase the numbering of the frames
472

    
473
                                        if(update_chunk(chunk, frame, video_outbuf) == -1) {
474
                                                fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq);
475
                                                exit(-1);
476
                                        }
477

    
478
                                        if(chunkFilled(chunk, cmeta)) { // is chunk filled using current strategy?
479
                                                //SAVE ON FILE
480
                                                //saveChunkOnFile(chunk);
481
                                                //Send the chunk via http to an external transport/player
482
                                                pushChunkHttp(chunk, cmeta->outside_world_url);
483
                                                initChunk(chunk, &seq_current_chunk);
484
#ifdef DEBUG_CHUNKER
485
                                                fprintf(stderr, "VIDEO: chunk video %d\n", chunk->seq);
486
#endif
487
                                        }
488
                                        /* pict_type maybe 1 (I), 2 (P), 3 (B), 5 (AUDIO)*/
489
                                }
490
                        }
491
                }
492
                else if(packet.stream_index==audioStream) {
493
                        audio_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
494
                        //decode the audio packet into a raw audio source buffer
495
                        if(avcodec_decode_audio3(aCodecCtx, samples, &audio_data_size, &packet)>0) {
496
#ifdef DEBUG_AUDIO_FRAMES
497
                                fprintf(stderr, "\n-------AUDIO FRAME\n");
498
                                fprintf(stderr, "AUDIO: newTimeaudioSTART : %lf\n", (double)(packet.pts)*av_q2d(pFormatCtx->streams[audioStream]->time_base));
499
#endif
500
                                if(audio_data_size>0) {
501
#ifdef DEBUG_AUDIO_FRAMES
502
                                        fprintf(stderr, "AUDIO: datasizeaudio:%d\n", audio_data_size);
503
#endif
504
                                        /* if a frame has been decoded, output it */
505
                                        //fwrite(samples, 1, audio_data_size, outfileaudio);
506
                                }
507
                                else
508
                                        continue;
509
        
510
                                audio_frame_size = avcodec_encode_audio(aCodecCtxEnc, audio_outbuf, audio_data_size, samples);
511
                                frame->number = contFrameAudio;
512

    
513
                                if(frame->number==0) {
514
                                        if(packet.dts==AV_NOPTS_VALUE)
515
                                                continue;
516
                                        last_pkt_dts_audio = packet.dts;
517
                                        newTime = 0;
518
                                }
519
                                else {
520
                                        if(packet.dts!=AV_NOPTS_VALUE) {
521
                                                delta_audio = packet.dts-last_pkt_dts_audio;
522
                                                last_pkt_dts_audio = packet.dts;
523
                                        }
524
                                        else if(delta_audio==0)
525
                                                continue;
526
                                }
527

    
528
                                //use pts if dts is invalid
529
                                if(packet.dts!=AV_NOPTS_VALUE)
530
                                        target_pts = packet.dts;
531
                                else if(packet.pts!=AV_NOPTS_VALUE)
532
                                        target_pts = packet.pts;
533
                                else
534
                                        continue;
535

    
536
                                if(!live_source)
537
                                {
538
                                        if(FirstTimeAudio && packet.pts>0) {
539
                                                //maintain the offset between audio pts and video pts
540
                                                //because in case of live source they have the same numbering
541
                                                if(ptsvideo1 > 0) //if we have already seen some video frames...
542
                                                        ptsaudio1 = ptsvideo1;
543
                                                else
544
                                                        ptsaudio1 = (double)packet.dts;
545
                                                FirstTimeAudio = 0;
546
#ifdef DEBUG_AUDIO_FRAMES
547
                                                fprintf(stderr, "AUDIO: SET PTS BASE OFFSET %f\n", ptsaudio1);
548
#endif
549
                                        }
550
                                        if(frame->number>0) {
551
                                                        if(ptsaudio1>0)
552
                                                                //use audio-based timestamps when available (both for video and audio frames)
553
                                                                newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio;
554
                                                        else
555
                                                                newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
556
                                        }
557
                                }
558
                                else //live source
559
                                {
560
                                        if(FirstTimeAudio && packet.pts>0) {
561
                                                //maintain the offset between audio pts and video pts
562
                                                //because in case of live source they have the same numbering
563
                                                if(ptsvideo1 > 0) //if we have already seen some video frames...
564
                                                        ptsaudio1 = ptsvideo1;
565
                                                else
566
                                                        ptsaudio1 = (double)packet.dts;
567
                                                FirstTimeAudio = 0;
568
#ifdef DEBUG_AUDIO_FRAMES
569
                                                fprintf(stderr, "AUDIO LIVE: SET PTS BASE OFFSET %f\n", ptsaudio1);
570
#endif
571
                                        }
572

    
573
                                        if(frame->number>0) {
574
                                                                newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio;
575
                                        }
576
                                }
577
#ifdef DEBUG_AUDIO_FRAMES
578
                                fprintf(stderr, "AUDIO: NEWTIMESTAMP %d\n", newTime);
579
#endif
580
                                if(newTime<0) {
581
#ifdef DEBUG_AUDIO_FRAMES
582
                                        fprintf(stderr, "AUDIO: SKIPPING FRAME\n");
583
#endif
584
                                        continue; //SKIP THIS FRAME, bad timestamp
585
                                }
586

    
587
                                frame->timestamp.tv_sec = (unsigned int)newTime/1000;
588
                                frame->timestamp.tv_usec = newTime%1000;
589
                                frame->size = audio_frame_size;
590
                                frame->type = 5; // 5 is audio type
591
#ifdef DEBUG_AUDIO_FRAMES
592
                                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);
593
                                fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
594
                                fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio);        
595
#endif
596
                                contFrameAudio++;
597

    
598
                                if(update_chunk(chunkaudio, frame, audio_outbuf) == -1) {
599
                                        fprintf(stderr, "AUDIO: unable to update chunk %d. Exiting.\n", chunkaudio->seq);
600
                                        exit(-1);
601
                                }
602
                                //set priority
603
                                chunkaudio->priority = 1;
604

    
605
                                if(chunkFilled(chunkaudio, cmeta)) { // is chunk filled using current strategy?
606
                                        //SAVE ON FILE
607
                                        //saveChunkOnFile(chunkaudio);
608
                                        //Send the chunk via http to an external transport/player
609
                                        pushChunkHttp(chunkaudio, cmeta->outside_world_url);
610
                                        initChunk(chunkaudio, &seq_current_chunk);
611
#ifdef DEBUG_CHUNKER
612
                                        fprintf(stderr, "AUDIO: chunk audio %d\n", chunkaudio->seq);
613
#endif
614
                                }
615
                        }
616
                }
617
                else {
618
#ifdef DEBUG_AUDIO_FRAMES
619
                        fprintf(stderr,"Free the packet that was allocated by av_read_frame\n");
620
#endif
621
                        av_free_packet(&packet);
622
                }
623
        }
624

    
625
        if(chunk->frames_num>0) {
626
                //SAVE ON FILE
627
                //saveChunkOnFile(chunk);
628
                //Send the chunk via http to an external transport/player
629
                pushChunkHttp(chunk, cmeta->outside_world_url);
630
        }
631
        if(chunkaudio->frames_num>0) {
632
                //SAVE ON FILE
633
                //saveChunkOnFile(chunkaudio);
634
                //Send the chunk via http to an external transport/player
635
                pushChunkHttp(chunkaudio, cmeta->outside_world_url);
636
        }
637

    
638
        /* finalize the HTTP chunk pusher */
639
        finalizeChunkPusher();
640

    
641
        free(chunk);
642
        free(chunkaudio);
643
        free(frame);
644
        av_free(video_outbuf);
645
        av_free(audio_outbuf);
646
        free(cmeta);
647

    
648
        // Free the YUV frame
649
        av_free(pFrame);
650
        av_free(samples);
651
  
652
        // Close the codec
653
        avcodec_close(pCodecCtx);
654
        avcodec_close(pCodecCtxEnc);
655

    
656
        if(audioStream!=-1) {
657
                avcodec_close(aCodecCtx);
658
                avcodec_close(aCodecCtxEnc);
659
        }
660
  
661
        // Close the video file
662
        av_close_input_file(pFormatCtx);
663
        return 0;
664
}
665

    
666

    
667
int update_chunk(ExternalChunk *chunk, Frame *frame, uint8_t *outbuf) {
668
        static int sizeFrameHeader = 3*sizeof(int32_t)+sizeof(struct timeval);
669
        static int sizeChunkHeader = 6*sizeof(int32_t)+2*sizeof(struct timeval)+sizeof(double);
670

    
671
        //moving temp pointer to encode Frame on the wire
672
        uint8_t *tempdata = NULL;
673

    
674
        //HINT on malloc
675
        chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len + frame->size + sizeFrameHeader));
676
        if(!chunk->data)  {
677
                fprintf(stderr, "Memory error in chunk!!!\n");
678
                return -1;
679
        }
680
        chunk->frames_num++; // number of frames in the current chunk
681

    
682
        //package the Frame header
683
        tempdata = chunk->data+chunk->payload_len;
684
        *((int32_t *)tempdata) = frame->number;
685
        tempdata+=sizeof(int32_t);
686
        *((struct timeval *)tempdata) = frame->timestamp;
687
        tempdata+=sizeof(struct timeval);
688
        *((int32_t *)tempdata) = frame->size;
689
        tempdata+=sizeof(int32_t);
690
        *((int32_t *)tempdata) = frame->type;
691
        tempdata+=sizeof(int32_t);
692

    
693
         //insert the new frame data
694
        memcpy(chunk->data + chunk->payload_len + sizeFrameHeader, outbuf, frame->size);
695
        chunk->payload_len += frame->size + sizeFrameHeader; // update payload length
696
        chunk->len = sizeChunkHeader + chunk->payload_len; // update overall length
697

    
698
        //update timestamps
699
        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) {
700
                                                chunk->start_time.tv_sec = frame->timestamp.tv_sec;
701
                                                chunk->start_time.tv_usec = frame->timestamp.tv_usec;
702
        }
703
        
704
        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) {
705
                                                chunk->end_time.tv_sec = frame->timestamp.tv_sec;
706
                                                chunk->end_time.tv_usec = frame->timestamp.tv_usec;
707
        }
708
        return 0;
709
}
710