Statistics
| Branch: | Revision:

chunker-player / chunker_streamer / chunker_streamer.c @ 3bcbf04c

History | View | Annotate | Download (39.9 KB)

1
/*
2
 *  Copyright (c) 2009-2011 Carmelo Daniele, Dario Marchese, Diego Reforgiato, Giuseppe Tropea
3
 *  developed for the Napa-Wine EU project. See www.napa-wine.eu
4
 *
5
 *  This is free software; see lgpl-2.1.txt
6
 */
7

    
8
#include "chunker_streamer.h"
9
#include <signal.h>
10
#include <math.h>
11
#include <getopt.h>
12
#include <libswscale/swscale.h>
13

    
14
#define STREAMER_MAX(a,b) ((a>b)?(a):(b))
15
#define STREAMER_MIN(a,b) ((a<b)?(a):(b))
16

    
17
//#define DEBUG_AUDIO_FRAMES
18
//#define DEBUG_VIDEO_FRAMES
19
//#define DEBUG_CHUNKER
20
#define DEBUG_ANOMALIES
21
//~ #define DEBUG_TIMESTAMPING
22
#define GET_PSNR(x) ((x==0) ? 0 : (-10.0*log(x)/log(10)))
23

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

    
27
#define AUDIO_CHUNK 0
28
#define VIDEO_CHUNK 1
29

    
30
void SaveFrame(AVFrame *pFrame, int width, int height);
31
void SaveEncodedFrame(Frame* frame, uint8_t *video_outbuf);
32
int video_record_count = 0;
33
int savedVideoFrames = 0;
34
long int firstSavedVideoFrame = 0;
35
ChunkerStreamerTestMode = 0;
36

    
37
// Constant number of frames per chunk
38
int chunkFilledFramesStrategy(ExternalChunk *echunk, int chunkType)
39
{
40
#ifdef DEBUG_CHUNKER
41
        fprintf(stderr, "CHUNKER: check if frames num %d == %d in chunk %d\n", echunk->frames_num, cmeta->framesPerChunk[chunkType], echunk->seq);
42
#endif
43
        if(echunk->frames_num == cmeta->framesPerChunk[chunkType])
44
                return 1;
45

    
46
        return 0;
47
}
48

    
49
// Constant size. Note that for now each chunk will have a size just greater or equal than the required value
50
// It can be considered as constant size.
51
int chunkFilledSizeStrategy(ExternalChunk *echunk, int chunkType)
52
{
53
#ifdef DEBUG_CHUNKER
54
        fprintf(stderr, "CHUNKER: check if chunk size %d >= %d in chunk %d\n", echunk->payload_len, cmeta->targetChunkSize, echunk->seq);
55
#endif
56
        if(echunk->payload_len >= cmeta->targetChunkSize)
57
                return 1;
58
        
59
        return 0;
60
}
61

    
62
// Performace optimization.
63
// The chunkFilled function has been splitted into two functions (one for each strategy).
64
// Instead of continuously check the strategy flag (which is constant),
65
// we change the callback just once according to the current strategy (look at the switch statement in the main in which this function pointer is set)
66
int (*chunkFilled)(ExternalChunk *echunk, int chunkType);
67

    
68
void initChunk(ExternalChunk *chunk, int *seq_num) {
69
        chunk->seq = (*seq_num)++;
70
        chunk->frames_num = 0;
71
        chunk->payload_len = 0;
72
        chunk->len=0;
73
  if(chunk->data != NULL)
74
    free(chunk->data);
75
        chunk->data = NULL;
76
        chunk->start_time.tv_sec = -1;
77
        chunk->start_time.tv_usec = -1;
78
        chunk->end_time.tv_sec = -1;
79
        chunk->end_time.tv_usec = -1;
80
        chunk->priority = 0;
81
        chunk->category = 0;
82
        chunk->_refcnt = 0;
83
}
84

    
85
int quit = 0;
86

    
87
void sigproc()
88
{
89
        printf("you have pressed ctrl-c, terminating...\n");
90
        quit = 1;
91
}
92

    
93
static void print_usage(int argc, char *argv[])
94
{
95
  fprintf (stderr,
96
    "\nUsage:%s [options]\n"
97
    "\n"
98
    "Mandatory options:\n"
99
    "\t[-i input file]\n"
100
    "\t[-a audio bitrate]\n"
101
    "\t[-v video bitrate]\n\n"
102
    "Other options:\n"
103
    "\t[-s WxH]: force video size.\n"
104
    "\t[-l]: this is a live stream.\n"
105
    "\t[-o]: adjust av frames timestamps.\n"
106
    "\t[-t]: QoE test mode\n\n"
107
    "=======================================================\n", argv[0]
108
    );
109
  }
110

    
111
sendChunk(ExternalChunk *chunk) {
112
#ifdef HTTPIO
113
                                                pushChunkHttp(chunk, cmeta->outside_world_url);
114
#endif
115
#ifdef TCPIO
116
                                                pushChunkTcp(chunk);
117
#endif
118
#ifdef UDPIO
119
                                                pushChunkUDP(chunk);
120
#endif
121
}
122

    
123
int main(int argc, char *argv[]) {
124
        signal(SIGINT, sigproc);
125
        
126
        int i=0;
127

    
128
        //output variables
129
        uint8_t *video_outbuf = NULL;
130
        int video_outbuf_size, video_frame_size;
131
        uint8_t *audio_outbuf = NULL;
132
        int audio_outbuf_size, audio_frame_size;
133
        int audio_data_size;
134

    
135
        //numeric identifiers of input streams
136
        int videoStream = -1;
137
        int audioStream = -1;
138

    
139
        int len1;
140
        int frameFinished;
141
        //frame sequential counters
142
        int contFrameAudio=1, contFrameVideo=0;
143
        int numBytes;
144

    
145
        //command line parameters
146
        int audio_bitrate = -1;
147
        int video_bitrate = -1;
148
        int live_source = 0; //tells to sleep before reading next frame in not live (i.e. file)
149
        int offset_av = 0; //tells to compensate for offset between audio and video in the file
150
        
151
        //a raw buffer for decoded uncompressed audio samples
152
        int16_t *samples = NULL;
153
        //a raw uncompressed video picture
154
        AVFrame *pFrame = NULL;
155
        AVFrame *scaledFrame = NULL;
156

    
157
        AVFormatContext *pFormatCtx;
158
        AVCodecContext  *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx;
159
        AVCodec         *pCodec,*pCodecEnc,*aCodec,*aCodecEnc;
160
        AVPacket         packet;
161

    
162
        //stuff needed to compute the right timestamps
163
        short int FirstTimeAudio=1, FirstTimeVideo=1;
164
        short int pts_anomalies_counter=0;
165
        short int newtime_anomalies_counter=0;
166
        long long newTime=0, newTime_audio=0, newTime_video=0, newTime_prev=0;
167
        struct timeval lastAudioSent = {0, 0};
168
        double ptsvideo1=0.0;
169
        double ptsaudio1=0.0;
170
        int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0;
171

    
172
        //Napa-Wine specific Frame and Chunk structures for transport
173
        Frame *frame = NULL;
174
        ExternalChunk *chunk = NULL;
175
        ExternalChunk *chunkaudio = NULL;
176
        
177
        char av_input[1024];
178
        int dest_width = -1;
179
        int dest_height = -1;
180
        
181
        static struct option long_options[] =
182
        {
183
                /* These options set a flag. */
184
                {"long_option", required_argument, 0, 0},
185
                {0, 0, 0, 0}
186
        };
187
        /* `getopt_long' stores the option index here. */
188
        int option_index = 0, c;
189
        int mandatories = 0;
190
        while ((c = getopt_long (argc, argv, "i:a:v:s:lot", long_options, &option_index)) != -1)
191
        {
192
                switch (c) {
193
                        case 0: //for long options
194
                                break;
195
                        case 'i':
196
                                sprintf(av_input, "%s", optarg);
197
                                mandatories++;
198
                                break;
199
                        case 'a':
200
                                sscanf(optarg, "%d", &audio_bitrate);
201
                                mandatories++;
202
                                break;
203
                        case 'v':
204
                                sscanf(optarg, "%d", &video_bitrate);
205
                                mandatories++;
206
                                break;
207
                        case 's':
208
                                sscanf(optarg, "%dx%d", &dest_width, &dest_height);
209
                                break;
210
                        case 'l':
211
                                live_source = 1;
212
                                break;
213
                        case 'o':
214
                                offset_av = 1;
215
                                break;
216
                        case 't':
217
                                ChunkerStreamerTestMode = 1;
218
                                break;
219
                        default:
220
                                print_usage(argc, argv);
221
                                return -1;
222
                }
223
        }
224
        
225
        if(mandatories < 3) 
226
        {
227
                print_usage(argc, argv);
228
                return -1;
229
        }
230

    
231
#ifdef YUV_RECORD_ENABLED
232
        if(ChunkerStreamerTestMode)
233
        {
234
                DELETE_DIR("yuv_data");
235
                CREATE_DIR("yuv_data");
236
                //FILE* pFile=fopen("yuv_data/streamer_out.yuv", "w");
237
                //fclose(pFile);
238
        }
239
#endif
240

    
241
restart:
242
        // read the configuration file
243
        cmeta = chunkerInit();
244
        switch(cmeta->strategy)
245
        {
246
                case 1:
247
                        chunkFilled = chunkFilledSizeStrategy;
248
                        break;
249
                default:
250
                        chunkFilled = chunkFilledFramesStrategy;
251
        }
252
                
253
        if(live_source)
254
                fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n");
255
        if(offset_av)
256
                fprintf(stderr, "INIT: Compensating AV OFFSET in file\n");
257

    
258
        // Register all formats and codecs
259
        av_register_all();
260

    
261
        // Open input file
262
        if(av_open_input_file(&pFormatCtx, av_input, NULL, 0, NULL) != 0) {
263
                fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n");
264
                exit(-1);
265
        }
266

    
267
        // Retrieve stream information
268
        if(av_find_stream_info(pFormatCtx) < 0) {
269
                fprintf(stdout, "INIT: Couldn't find stream information. Exiting.\n");
270
                exit(-1);
271
        }
272

    
273
        // Dump information about file onto standard error
274
        dump_format(pFormatCtx, 0, av_input, 0);
275

    
276
        // Find the video and audio stream numbers
277
        for(i=0; i<pFormatCtx->nb_streams; i++) {
278
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && videoStream<0) {
279
                        videoStream=i;
280
                }
281
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audioStream<0) {
282
                        audioStream=i;
283
                }
284
        }
285
        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);
286

    
287
        fprintf(stderr, "INIT: Video stream has id : %d\n",videoStream);
288
        fprintf(stderr, "INIT: Audio stream has id : %d\n",audioStream);
289

    
290
        if(videoStream==-1 && audioStream==-1) {
291
                fprintf(stdout, "INIT: Didn't find audio and video streams. Exiting.\n");
292
                exit(-1);
293
        }
294

    
295
        // Get a pointer to the codec context for the input video stream
296
        pCodecCtx=pFormatCtx->streams[videoStream]->codec;
297
        pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
298
        //extract W and H
299
        fprintf(stderr, "INIT: Width:%d Height:%d\n", pCodecCtx->width, pCodecCtx->height);
300

    
301
        // Get a pointer to the codec context for the input audio stream
302
        if(audioStream != -1) {
303
                aCodecCtx=pFormatCtx->streams[audioStream]->codec;
304
                fprintf(stderr, "INIT: AUDIO Codecid: %d channels %d samplerate %d\n", aCodecCtx->codec_id, aCodecCtx->channels, aCodecCtx->sample_rate);
305
        }
306

    
307
        //setup video output encoder
308
        pCodecCtxEnc=avcodec_alloc_context();
309
#ifdef H264_VIDEO_ENCODER
310
        pCodecCtxEnc->me_range=16;
311
        pCodecCtxEnc->max_qdiff=4;
312
        pCodecCtxEnc->qmin=1;
313
        pCodecCtxEnc->qmax=30;
314
        pCodecCtxEnc->qcompress=0.6;
315
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
316
        pCodecCtxEnc->codec_id   = CODEC_ID_H264;//13;//pCodecCtx->codec_id;
317
        pCodecCtxEnc->bit_rate = video_bitrate;///400000;
318
        // resolution must be a multiple of two 
319
        pCodecCtxEnc->width = (dest_width > 0) ? dest_width : pCodecCtx->width;
320
        pCodecCtxEnc->height = (dest_height > 0) ? dest_height : pCodecCtx->height;
321
        // frames per second 
322
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
323
        pCodecCtxEnc->gop_size = 12; // emit one intra frame every ten frames 
324
        pCodecCtxEnc->max_b_frames=1;
325
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
326

    
327
        pCodecCtxEnc->bit_rate_tolerance = video_bitrate*50;
328
//        pCodecCtxEnc->rc_min_rate = 0;
329
//        pCodecCtxEnc->rc_max_rate = 0;
330
//        pCodecCtxEnc->rc_buffer_size = 0;
331
        pCodecCtxEnc->flags |= CODEC_FLAG_PSNR;
332
//        pCodecCtxEnc->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8;
333
//        pCodecCtxEnc->crf = 0.0f;
334
        
335
#ifdef STREAMER_X264_USE_SSIM
336
        pCodecCtxEnc->flags2 |= CODEC_FLAG2_SSIM;
337
#endif
338

    
339
        pCodecCtxEnc->weighted_p_pred=2; //maps wpredp=2; weighted prediction analysis method
340
        // pCodecCtxEnc->rc_min_rate = 0;
341
        // pCodecCtxEnc->rc_max_rate = video_bitrate*2;
342
        // pCodecCtxEnc->rc_buffer_size = 0;
343
#else
344
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
345
        pCodecCtxEnc->codec_id   = CODEC_ID_MPEG4;
346
        pCodecCtxEnc->bit_rate = video_bitrate;
347
        //~ pCodecCtxEnc->qmin = 30;
348
        //~ pCodecCtxEnc->qmax = 30;
349
        //times 20 follows the defaults, was not needed in previous versions of libavcodec
350
        pCodecCtxEnc->bit_rate_tolerance = video_bitrate*20;
351
//        pCodecCtxEnc->crf = 20.0f;
352
        pCodecCtxEnc->width = (dest_width > 0) ? dest_width : pCodecCtx->width;
353
        pCodecCtxEnc->height = (dest_height > 0) ? dest_height : pCodecCtx->height;
354
        // frames per second 
355
        //~ pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
356
        //printf("pCodecCtx->time_base=%d/%d\n", pCodecCtx->time_base.num, pCodecCtx->time_base.den);
357
        pCodecCtxEnc->time_base= (AVRational){1,25};
358
        pCodecCtxEnc->gop_size = 12; // emit one intra frame every twelve frames 
359
        pCodecCtxEnc->max_b_frames=1;
360
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
361
        pCodecCtxEnc->flags = CODEC_FLAG_PSNR;
362
        //~ pCodecCtxEnc->flags |= CODEC_FLAG_QSCALE;
363
#endif
364

    
365
        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);
366

    
367
        // Find the decoder for the video stream
368
#ifdef H264_VIDEO_ENCODER
369
        fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264);
370
        pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id);
371
#else
372
        fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4);
373
        pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4);
374
#endif
375

    
376
        if(pCodec==NULL) {
377
                fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n");
378
                return -1; // Codec not found
379
        }
380
        if(pCodecEnc==NULL) {
381
                fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n");
382
                return -1; // Codec not found
383
        }
384
        if(avcodec_open(pCodecCtx, pCodec)<0) {
385
                fprintf(stderr, "INIT: could not open IN VIDEO codec\n");
386
                return -1; // Could not open codec
387
        }
388
        if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) {
389
                fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n");
390
                return -1; // Could not open codec
391
        }
392

    
393
        if(audioStream!=-1) {
394
                //setup audio output encoder
395
                aCodecCtxEnc = avcodec_alloc_context();
396
                aCodecCtxEnc->bit_rate = audio_bitrate; //256000
397
                aCodecCtxEnc->sample_fmt = SAMPLE_FMT_S16;
398
                aCodecCtxEnc->sample_rate = aCodecCtx->sample_rate;
399
                aCodecCtxEnc->channels = aCodecCtx->channels;
400
                fprintf(stderr, "INIT: AUDIO bitrate OUT:%d sample_rate:%d channels:%d\n", aCodecCtxEnc->bit_rate, aCodecCtxEnc->sample_rate, aCodecCtxEnc->channels);
401

    
402
                // Find the decoder for the audio stream
403
                aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
404
#ifdef MP3_AUDIO_ENCODER
405
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP3);
406
#else
407
                aCodecEnc = avcodec_find_encoder(CODEC_ID_MP2);
408
#endif
409
                if(aCodec==NULL) {
410
                        fprintf(stderr,"INIT: Unsupported acodec!\n");
411
                        return -1;
412
                }
413
                if(aCodecEnc==NULL) {
414
                        fprintf(stderr,"INIT: Unsupported acodecEnc!\n");
415
                        return -1;
416
                }
417
        
418
                if(avcodec_open(aCodecCtx, aCodec)<0) {
419
                        fprintf(stderr, "INIT: could not open IN AUDIO codec\n");
420
                        return -1; // Could not open codec
421
                }
422
                if(avcodec_open(aCodecCtxEnc, aCodecEnc)<0) {
423
                        fprintf(stderr, "INIT: could not open OUT AUDIO codec\n");
424
                        return -1; // Could not open codec
425
                }
426
        }
427
        else {
428
                fprintf(stderr,"INIT: NO AUDIO TRACK IN INPUT FILE\n");
429
        }
430

    
431
        // Allocate audio in and out buffers
432
        samples = (int16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
433
        if(samples == NULL) {
434
                fprintf(stderr, "INIT: Memory error alloc audio samples!!!\n");
435
                return -1;
436
        }
437
        audio_outbuf_size = STREAMER_MAX_AUDIO_BUFFER_SIZE;
438
        audio_outbuf = av_malloc(audio_outbuf_size);
439
        if(audio_outbuf == NULL) {
440
                fprintf(stderr, "INIT: Memory error alloc audio_outbuf!!!\n");
441
                return -1;
442
        }
443

    
444
        // Allocate video in frame and out buffer
445
        pFrame=avcodec_alloc_frame();
446
        scaledFrame=avcodec_alloc_frame();
447
        if(pFrame==NULL || scaledFrame == NULL) {
448
                fprintf(stderr, "INIT: Memory error alloc video frame!!!\n");
449
                return -1;
450
        }
451
        video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE;
452
        video_outbuf = av_malloc(video_outbuf_size);
453
        int scaledFrame_buf_size = avpicture_get_size( PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
454
        uint8_t* scaledFrame_buffer = (uint8_t *) av_malloc( scaledFrame_buf_size * sizeof( uint8_t ) );
455
        avpicture_fill( (AVPicture*) scaledFrame, scaledFrame_buffer, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
456
        if(!video_outbuf || !scaledFrame_buffer) {
457
                fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n");
458
                return -1;
459
        }
460

    
461
        //allocate Napa-Wine transport
462
        frame = (Frame *)malloc(sizeof(Frame));
463
        if(!frame) {
464
                fprintf(stderr, "INIT: Memory error alloc Frame!!!\n");
465
                return -1;
466
        }
467
        //create an empty first video chunk
468
        chunk = (ExternalChunk *)malloc(sizeof(ExternalChunk));
469
        if(!chunk) {
470
                fprintf(stderr, "INIT: Memory error alloc chunk!!!\n");
471
                return -1;
472
        }
473
        chunk->data = NULL;
474
        chunk->seq = 0;
475
        //initChunk(chunk, &seq_current_chunk); if i init them now i get out of sequence
476
#ifdef DEBUG_CHUNKER
477
        fprintf(stderr, "INIT: chunk video %d\n", chunk->seq);
478
#endif
479
        //create empty first audio chunk
480
        chunkaudio = (ExternalChunk *)malloc(sizeof(ExternalChunk));
481
        if(!chunkaudio) {
482
                fprintf(stderr, "INIT: Memory error alloc chunkaudio!!!\n");
483
                return -1;
484
        }
485
  chunkaudio->data=NULL;
486
        chunkaudio->seq = 0;
487
        //initChunk(chunkaudio, &seq_current_chunk);
488
#ifdef DEBUG_CHUNKER
489
        fprintf(stderr, "INIT: chunk audio %d\n", chunkaudio->seq);
490
#endif
491

    
492
#ifdef HTTPIO
493
        /* initialize the HTTP chunk pusher */
494
        initChunkPusher(); //TRIPLO
495
#endif
496

    
497
        long sleep=0;
498
        struct timeval now_tv;
499
        struct timeval tmp_tv;
500
        long long lateTime = 0;
501
        long long maxAudioInterval = 0;
502
        long long maxVDecodeTime = 0;
503
        unsigned char lastIFrameDistance = 0;
504

    
505
#ifdef TCPIO
506
        static char peer_ip[16];
507
        static int peer_port;
508
        int res = sscanf(cmeta->outside_world_url, "tcp://%15[0-9.]:%d", peer_ip, &peer_port);
509
        if (res < 2) {
510
                fprintf(stderr,"error parsing output url: %s\n", cmeta->outside_world_url);
511
                return -2;
512
        }
513
        
514
        initTCPPush(peer_ip, peer_port);
515
#endif
516
#ifdef UDPIO
517
        static char peer_ip[16];
518
        static int peer_port;
519
        int res = sscanf(cmeta->outside_world_url, "udp://%15[0-9.]:%d", peer_ip, &peer_port);
520
        if (res < 2) {
521
                fprintf(stderr,"error parsing output url: %s\n", cmeta->outside_world_url);
522
                return -2;
523
        }
524
        
525
        initUDPPush(peer_ip, peer_port);
526
#endif
527
        
528
        char videotrace_filename[255];
529
        char psnr_filename[255];
530
        sprintf(videotrace_filename, "yuv_data/videotrace.log");
531
        sprintf(psnr_filename, "yuv_data/psnrtrace.log");
532
        FILE* videotrace = fopen(videotrace_filename, "w");
533
        FILE* psnrtrace = fopen(psnr_filename, "w");
534

    
535
        //main loop to read from the input file
536
        while((av_read_frame(pFormatCtx, &packet)>=0) && !quit)
537
        {
538
                //detect if a strange number of anomalies is occurring
539
                if(ptsvideo1 < 0 || ptsvideo1 > packet.dts || ptsaudio1 < 0 || ptsaudio1 > packet.dts) {
540
                        pts_anomalies_counter++;
541
#ifdef DEBUG_ANOMALIES
542
                        fprintf(stderr, "READLOOP: pts BASE anomaly detected number %d\n", pts_anomalies_counter);
543
#endif
544
                        if(live_source) { //reset just in case of live source
545
                                if(pts_anomalies_counter > 25) { //just a random threshold
546
                                        pts_anomalies_counter = 0;
547
                                        FirstTimeVideo = 1;
548
                                        FirstTimeAudio = 1;
549
#ifdef DEBUG_ANOMALIES
550
                                        fprintf(stderr, "READLOOP: too many pts BASE anomalies. resetting pts base\n");
551
#endif
552
                                }
553
                        }
554
                }
555

    
556
                //newTime_video and _audio are in usec
557
                //if video and audio stamps differ more than 5sec
558
                if( newTime_video - newTime_audio > 5000000 || newTime_video - newTime_audio < -5000000 ) {
559
                        newtime_anomalies_counter++;
560
#ifdef DEBUG_ANOMALIES
561
                        fprintf(stderr, "READLOOP: NEWTIME audio video differ anomaly detected number %d\n", newtime_anomalies_counter);
562
#endif
563
                }
564

    
565
                if(newtime_anomalies_counter > 50) { //just a random threshold
566
                        if(live_source) { //restart just in case of live source
567
#ifdef DEBUG_ANOMALIES
568
                                fprintf(stderr, "READLOOP: too many NEGATIVE TIMESTAMPS anomalies. Restarting.\n");
569
#endif
570
                                goto close;
571
                        }
572
                }
573

    
574
                // Is this a packet from the video stream?
575
                if(packet.stream_index==videoStream)
576
                {
577
                        if(!live_source)
578
                        {
579
                                if(audioStream != -1) { //take this "time bank" method into account only if we have audio track
580
                                        // lateTime < 0 means a positive time account that can be used to decode video frames
581
                                        // if (lateTime + maxVDecodeTime) >= 0 then we may have a negative time account after video transcoding
582
                                        // therefore, it's better to skip the frame
583
                                        if((lateTime+maxVDecodeTime) >= 0)
584
                                        {
585
#ifdef DEBUG_ANOMALIES
586
                                                fprintf(stderr, "\n\n\t\t************************* SKIPPING VIDEO FRAME ***********************************\n\n", sleep);
587
#endif
588
                                                continue;
589
                                        }
590
                                }
591
                        }
592
                        
593
                        gettimeofday(&tmp_tv, NULL);
594
                        
595
                        //decode the video packet into a raw pFrame
596
                        if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet)>0)
597
                        {
598
                                // usleep(5000);
599
#ifdef DEBUG_VIDEO_FRAMES
600
                                fprintf(stderr, "\n-------VIDEO FRAME type %d\n", pFrame->pict_type);
601
                                fprintf(stderr, "VIDEO: dts %lld pts %lld\n", packet.dts, packet.pts);
602
#endif
603
                                if(frameFinished)
604
                                { // it must be true all the time else error
605
                                
606
                                        frame->number = ++contFrameVideo;
607

    
608
#ifdef VIDEO_DEINTERLACE
609
                                        avpicture_deinterlace(
610
                                                (AVPicture*) pFrame,
611
                                                (const AVPicture*) pFrame,
612
                                                pCodecCtxEnc->pix_fmt,
613
                                                pCodecCtxEnc->width,
614
                                                pCodecCtxEnc->height);
615
#endif
616

    
617
#ifdef DEBUG_VIDEO_FRAMES
618
                                        fprintf(stderr, "VIDEO: finished frame %d dts %lld pts %lld\n", frame->number, packet.dts, packet.pts);
619
#endif
620
                                        if(frame->number==0) {
621
                                                if(packet.dts==AV_NOPTS_VALUE)
622
                                                {
623
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
624
                                                        contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
625
                                                        continue;
626
                                                }
627
                                                last_pkt_dts = packet.dts;
628
                                                newTime = 0;
629
                                        }
630
                                        else {
631
                                                if(packet.dts!=AV_NOPTS_VALUE) {
632
                                                        delta_video = packet.dts-last_pkt_dts;
633
                                                        last_pkt_dts = packet.dts;
634
                                                }
635
                                                else if(delta_video==0)
636
                                                {
637
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
638
                                                        contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
639
                                                        continue;
640
                                                }
641
                                        }
642
#ifdef DEBUG_VIDEO_FRAMES
643
                                        fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video);
644
#endif
645

    
646
                                        if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
647
                                        {
648
                                                static AVPicture pict;
649
                                                static struct SwsContext *img_convert_ctx = NULL;
650
                                                
651
                                                if(img_convert_ctx == NULL)
652
                                                {
653
                                                        img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
654
                                                        if(img_convert_ctx == NULL) {
655
                                                                fprintf(stderr, "Cannot initialize the conversion context!\n");
656
                                                                exit(1);
657
                                                        }
658
                                                }
659
                                                sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, scaledFrame->data, scaledFrame->linesize);
660
                                                video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, scaledFrame);
661
                                        }
662
                                        else
663
                                                video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
664
                                        
665
                                        if(video_frame_size <= 0)
666
                                        {
667
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
668
                                                continue;
669
                                        }
670

    
671
#ifdef DEBUG_VIDEO_FRAMES
672
                                        if(pCodecCtxEnc->coded_frame) {
673
                                                fprintf(stderr, "\n-------VIDEO FRAME intype %d%s -> outtype: %d%s\n",
674
                                                        pFrame->pict_type, pFrame->key_frame ? " (key)" : "",
675
                                                        pCodecCtxEnc->coded_frame->pict_type, pCodecCtxEnc->coded_frame->key_frame ? " (key)" : "");
676
                                        }
677
#endif
678

    
679
                                        //use pts if dts is invalid
680
                                        if(packet.dts!=AV_NOPTS_VALUE)
681
                                                target_pts = packet.dts;
682
                                        else if(packet.pts!=AV_NOPTS_VALUE)
683
                                                target_pts = packet.pts;
684
                                        else
685
                                        {
686
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
687
                                                continue;
688
                                        }
689

    
690
                                        if(!offset_av)
691
                                        {
692
                                                if(FirstTimeVideo && packet.dts>0) {
693
                                                        ptsvideo1 = (double)packet.dts;
694
                                                        FirstTimeVideo = 0;
695
#ifdef DEBUG_VIDEO_FRAMES
696
                                                        fprintf(stderr, "VIDEO: SET PTS BASE OFFSET %f\n", ptsvideo1);
697
#endif
698
                                                }
699
                                        }
700
                                        else //we want to compensate audio and video offset for this source
701
                                        {
702
                                                if(FirstTimeVideo && packet.dts>0) {
703
                                                        //maintain the offset between audio pts and video pts
704
                                                        //because in case of live source they have the same numbering
705
                                                        if(ptsaudio1 > 0) //if we have already seen some audio frames...
706
                                                                ptsvideo1 = ptsaudio1;
707
                                                        else
708
                                                                ptsvideo1 = (double)packet.dts;
709
                                                        FirstTimeVideo = 0;
710
#ifdef DEBUG_VIDEO_FRAMES
711
                                                        fprintf(stderr, "VIDEO LIVE: SET PTS BASE OFFSET %f\n", ptsvideo1);
712
#endif
713
                                                }
714
                                        }
715
                                        //compute the new video timestamp in milliseconds
716
                                        if(frame->number>0) {
717
                                                newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
718
                                                // store timestamp in useconds for next frame sleep
719
                                                newTime_video = newTime*1000;
720
                                        }
721
#ifdef DEBUG_TIMESTAMPING
722
                                        fprintf(stderr, "VIDEO: NEWTIMESTAMP %ld\n", newTime);
723
#endif
724
                                        if(newTime<0) {
725
#ifdef DEBUG_VIDEO_FRAMES
726
                                                fprintf(stderr, "VIDEO: SKIPPING FRAME\n");
727
#endif
728
                                                newtime_anomalies_counter++;
729
#ifdef DEBUG_ANOMALIES
730
                                                fprintf(stderr, "READLOOP: NEWTIME negative video timestamp anomaly detected number %d\n", newtime_anomalies_counter);
731
#endif
732
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
733
                                                continue; //SKIP THIS FRAME, bad timestamp
734
                                        }
735
                                        
736
                                        //~ printf("pCodecCtxEnc->error[0]=%lld\n", pFrame->error[0]);
737
        
738
                                        frame->timestamp.tv_sec = (long long)newTime/1000;
739
                                        frame->timestamp.tv_usec = newTime%1000;
740
                                        frame->size = video_frame_size;
741
                                        /* pict_type maybe 1 (I), 2 (P), 3 (B), 5 (AUDIO)*/
742
                                        frame->type = (unsigned char)pCodecCtxEnc->coded_frame->pict_type;
743

    
744
#ifdef H264_VIDEO_ENCODER
745

    
746
#ifdef STREAMER_X264_USE_SSIM
747
                                        /*double ssim_y = x264_context->enc->stat.frame.f_ssim
748
                      / (((x264_context->enc->param.i_width-6)>>2) * ((x264_context->enc->param.i_height-6)>>2));*/
749
#else
750
                                        //fprintf(psnrtrace, "%f\n", (float)x264_psnr( x264_context->enc->stat.frame.i_ssd[0], x264_context->enc->param.i_width * x264_context->enc->param.i_height ));
751
                                        //frame->psnr = (uint16_t) ((float)(STREAMER_MIN(x264_psnr( x264_context->enc->stat.frame.i_ssd[0], x264_context->enc->param.i_width * x264_context->enc->param.i_height ),MAX_PSNR))*65536/MAX_PSNR);
752
#endif
753

    
754
#else
755
                                        //psnr = (uint16_t) ((float)(STREAMER_MIN(GET_PSNR(pCodecCtxEnc->error[0]/(pCodecCtxEnc->width*pCodecCtxEnc->height*255.0*255.0)),MAX_PSNR))*65536/MAX_PSNR);
756
                                        //pCodecCtxEnc->error[0] = 0;
757
#endif
758

    
759
#ifdef DEBUG_VIDEO_FRAMES
760
                                        fprintf(stderr, "VIDEO: original codec frame number %d vs. encoded %d vs. packed %d\n", pCodecCtx->frame_number, pCodecCtxEnc->frame_number, frame->number);
761
                                        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);
762
#endif
763

    
764
#ifdef YUV_RECORD_ENABLED
765
                                        if(ChunkerStreamerTestMode)
766
                                        {
767
                                                if(videotrace)
768
                                                        fprintf(videotrace, "%d %d %d\n", frame->number, pFrame->pict_type, frame->size);
769

    
770
                                                if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
771
                                                        SaveFrame(scaledFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
772
                                                else
773
                                                        SaveFrame(pFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
774

    
775
                                                ++savedVideoFrames;
776
                                                SaveEncodedFrame(frame, video_outbuf);
777

    
778
                                                if(!firstSavedVideoFrame)
779
                                                        firstSavedVideoFrame = frame->number;
780
                                                
781
                                                char tmp_filename[255];
782
                                                sprintf(tmp_filename, "yuv_data/streamer_out_context.txt");
783
                                                FILE* tmp = fopen(tmp_filename, "w");
784
                                                if(tmp)
785
                                                {
786
                                                        fprintf(tmp, "width = %d\nheight = %d\ntotal_frames_saved = %d\ntotal_frames_decoded = %d\nfirst_frame_number = %d\nlast_frame_number = %d\n"
787
                                                                ,pCodecCtxEnc->width, pCodecCtxEnc->height
788
                                                                ,savedVideoFrames, savedVideoFrames, firstSavedVideoFrame, frame->number);
789
                                                        fclose(tmp);
790
                                                }
791
                                        }
792
#endif
793

    
794
#ifdef DEBUG_VIDEO_FRAMES
795
                                        fprintf(stderr, "VIDEO: encapsulated frame size:%d type:%d\n", frame->size, frame->type);
796
                                        fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
797
#endif
798
                                        //contFrameVideo++; //lets increase the numbering of the frames
799

    
800
                                        if(update_chunk(chunk, frame, video_outbuf) == -1) {
801
                                                fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq);
802
                                                exit(-1);
803
                                        }
804

    
805
                                        if(chunkFilled(chunk, VIDEO_CHUNK)) { // is chunk filled using current strategy?
806
                                                //SAVE ON FILE
807
                                                //saveChunkOnFile(chunk);
808
                                                //Send the chunk to an external transport/player
809
                                                sendChunk(chunk);
810
#ifdef DEBUG_CHUNKER
811
                                                fprintf(stderr, "VIDEO: sent chunk video %d\n", chunk->seq);
812
#endif
813
                                                chunk->seq = 0; //signal that we need an increase
814
                                                //initChunk(chunk, &seq_current_chunk);
815
                                        }
816

    
817
                                        //compute how long it took to encode video frame
818
                                        gettimeofday(&now_tv, NULL);
819
                                        long long usec = (now_tv.tv_sec-tmp_tv.tv_sec)*1000000;
820
                                        usec+=(now_tv.tv_usec-tmp_tv.tv_usec);
821
                                        if(usec > maxVDecodeTime)
822
                                                maxVDecodeTime = usec;
823

    
824
                                        //we DONT have an audio track, so we compute timings and determine
825
                                        //how much time we have to sleep at next VIDEO frame taking
826
                                        //also into account how much time was needed to encode the current
827
                                        //video frame
828
                                        //all this in case the video source is not live, i.e. not self-timing
829
                                        //and only in case there is no audio track
830
                                        if(audioStream == -1) {
831
                                                if(!live_source) {
832
                                                        if(newTime_prev != 0) {
833
                                                                //how much delay between video frames ideally
834
                                                                long long maxDelay = newTime_video - newTime_prev;
835
                                                                sleep = (maxDelay - usec);
836
#ifdef DEBUG_ANOMALIES
837
                                                                printf("\tmaxDelay=%ld\n", ((long)maxDelay));
838
                                                                printf("\tlast video frame interval=%ld; sleep time=%ld\n", ((long)usec), ((long)sleep));
839
#endif
840
                                                        }
841
                                                        else
842
                                                                sleep = 0;
843

    
844
                                                        //update and store counters
845
                                                        newTime_prev = newTime_video;
846

    
847
                                                        //i can also sleep now instead of at the beginning of
848
                                                        //the next frame because in this case we only have video
849
                                                        //frames, hence it would immediately be the next thing to do
850
                                                        if(sleep > 0) {
851
#ifdef DEBUG_ANOMALIES
852
                                                                fprintf(stderr, "\n\tREADLOOP: going to sleep for %ld microseconds\n", sleep);
853
#endif
854
                                                                usleep(sleep);
855
                                                        }
856

    
857
                                                }
858
                                        }
859

    
860
                                }
861
                        }
862
                }
863
                else if(packet.stream_index==audioStream)
864
                {
865
                        if(sleep > 0)
866
                        {
867
#ifdef DEBUG_ANOMALIES
868
                                fprintf(stderr, "\n\tREADLOOP: going to sleep for %ld microseconds\n", sleep);
869
#endif
870
                                usleep(sleep);
871
                        }
872
                        
873
                        audio_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
874
                        //decode the audio packet into a raw audio source buffer
875
                        if(avcodec_decode_audio3(aCodecCtx, samples, &audio_data_size, &packet)>0)
876
                        {
877
#ifdef DEBUG_AUDIO_FRAMES
878
                                fprintf(stderr, "\n-------AUDIO FRAME\n");
879
                                fprintf(stderr, "AUDIO: newTimeaudioSTART : %lf\n", (double)(packet.pts)*av_q2d(pFormatCtx->streams[audioStream]->time_base));
880
#endif
881
                                if(audio_data_size>0) {
882
#ifdef DEBUG_AUDIO_FRAMES
883
                                        fprintf(stderr, "AUDIO: datasizeaudio:%d\n", audio_data_size);
884
#endif
885
                                        /* if a frame has been decoded, output it */
886
                                        //fwrite(samples, 1, audio_data_size, outfileaudio);
887
                                }
888
                                else
889
                                        continue;
890
        
891
                                audio_frame_size = avcodec_encode_audio(aCodecCtxEnc, audio_outbuf, audio_data_size, samples);
892
                                if(audio_frame_size <= 0)
893
                                        continue;
894
                                
895
                                frame->number = contFrameAudio;
896

    
897
                                if(frame->number==0) {
898
                                        if(packet.dts==AV_NOPTS_VALUE)
899
                                                continue;
900
                                        last_pkt_dts_audio = packet.dts;
901
                                        newTime = 0;
902
                                }
903
                                else {
904
                                        if(packet.dts!=AV_NOPTS_VALUE) {
905
                                                delta_audio = packet.dts-last_pkt_dts_audio;
906
                                                last_pkt_dts_audio = packet.dts;
907
                                        }
908
                                        else if(delta_audio==0)
909
                                                continue;
910
                                }
911
#ifdef DEBUG_AUDIO_FRAMES
912
                                fprintf(stderr, "AUDIO: original codec frame number %d vs. encoded %d vs. packed %d\n", aCodecCtx->frame_number, aCodecCtxEnc->frame_number, frame->number);
913
#endif
914
                                //use pts if dts is invalid
915
                                if(packet.dts!=AV_NOPTS_VALUE)
916
                                        target_pts = packet.dts;
917
                                else if(packet.pts!=AV_NOPTS_VALUE)
918
                                        target_pts = packet.pts;
919
                                else
920
                                        continue;
921

    
922
                                if(!offset_av)
923
                                {
924
                                        if(FirstTimeAudio && packet.dts>0) {
925
                                                ptsaudio1 = (double)packet.dts;
926
                                                FirstTimeAudio = 0;
927
#ifdef DEBUG_AUDIO_FRAMES
928
                                                fprintf(stderr, "AUDIO: SET PTS BASE OFFSET %f\n", ptsaudio1);
929
#endif
930
                                        }
931
                                }
932
                                else //we want to compensate audio and video offset for this source
933
                                {
934
                                        if(FirstTimeAudio && packet.dts>0) {
935
                                                //maintain the offset between audio pts and video pts
936
                                                //because in case of live source they have the same numbering
937
                                                if(ptsvideo1 > 0) //if we have already seen some video frames...
938
                                                        ptsaudio1 = ptsvideo1;
939
                                                else
940
                                                        ptsaudio1 = (double)packet.dts;
941
                                                FirstTimeAudio = 0;
942
#ifdef DEBUG_AUDIO_FRAMES
943
                                                fprintf(stderr, "AUDIO LIVE: SET PTS BASE OFFSET %f\n", ptsaudio1);
944
#endif
945
                                        }
946
                                }
947
                                //compute the new audio timestamps in milliseconds
948
                                if(frame->number>0) {
949
                                        newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio;
950
                                        // store timestamp in useconds for next frame sleep
951
                                        newTime_audio = newTime*1000;
952
                                }
953
#ifdef DEBUG_TIMESTAMPING
954
                                fprintf(stderr, "AUDIO: NEWTIMESTAMP %d\n", newTime);
955
#endif
956
                                if(newTime<0) {
957
#ifdef DEBUG_AUDIO_FRAMES
958
                                        fprintf(stderr, "AUDIO: SKIPPING FRAME\n");
959
#endif
960
                                        newtime_anomalies_counter++;
961
#ifdef DEBUG_ANOMALIES
962
                                        fprintf(stderr, "READLOOP: NEWTIME negative audio timestamp anomaly detected number %d\n", newtime_anomalies_counter);
963
#endif
964
                                        continue; //SKIP THIS FRAME, bad timestamp
965
                                }
966

    
967
                                frame->timestamp.tv_sec = (unsigned int)newTime/1000;
968
                                frame->timestamp.tv_usec = newTime%1000;
969
                                frame->size = audio_frame_size;
970
                                frame->type = 5; // 5 is audio type
971
#ifdef DEBUG_AUDIO_FRAMES
972
                                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);
973
                                fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
974
                                fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio);        
975
#endif
976
                                contFrameAudio++;
977

    
978
                                if(update_chunk(chunkaudio, frame, audio_outbuf) == -1) {
979
                                        fprintf(stderr, "AUDIO: unable to update chunk %d. Exiting.\n", chunkaudio->seq);
980
                                        exit(-1);
981
                                }
982
                                //set priority
983
                                chunkaudio->priority = 1;
984

    
985
                                if(chunkFilled(chunkaudio, AUDIO_CHUNK)) {
986
                                        // is chunk filled using current strategy?
987
                                        //SAVE ON FILE
988
                                        //saveChunkOnFile(chunkaudio);
989
                                        //Send the chunk to an external transport/player
990
                                        sendChunk(chunkaudio);
991
#ifdef DEBUG_CHUNKER
992
                                        fprintf(stderr, "AUDIO: just sent chunk audio %d\n", chunkaudio->seq);
993
#endif
994
                                        chunkaudio->seq = 0; //signal that we need an increase
995
                                        //initChunk(chunkaudio, &seq_current_chunk);
996
                                }
997

    
998
                                //we have an audio track, so we compute timings and determine
999
                                //how much time we have to sleep at next audio frame taking
1000
                                //also into account how much time was needed to encode the
1001
                                //video frames
1002
                                //all this in case the video source is not live, i.e. not self-timing
1003
                                if(!live_source)
1004
                                {
1005
                                        if(newTime_prev != 0)
1006
                                        {
1007
                                                long long maxDelay = newTime_audio - newTime_prev;
1008

    
1009
                                                gettimeofday(&now_tv, NULL);
1010
                                                long long usec = (now_tv.tv_sec-lastAudioSent.tv_sec)*1000000;
1011
                                                usec+=(now_tv.tv_usec-lastAudioSent.tv_usec);
1012

    
1013
                                                if(usec > maxAudioInterval)
1014
                                                        maxAudioInterval = usec;
1015

    
1016
                                                lateTime -= (maxDelay - usec);
1017
#ifdef DEBUG_ANOMALIES
1018
                                                printf("\tmaxDelay=%ld, maxAudioInterval=%ld\n", ((long)maxDelay), ((long) maxAudioInterval));
1019
                                                printf("\tlast audio frame interval=%ld; lateTime=%ld\n", ((long)usec), ((long)lateTime));
1020
#endif
1021

    
1022
                                                if((lateTime+maxAudioInterval) < 0)
1023
                                                        sleep = (lateTime+maxAudioInterval)*-1;
1024
                                                else
1025
                                                        sleep = 0;
1026
                                        }
1027
                                        else
1028
                                                sleep = 0;
1029

    
1030
                                        newTime_prev = newTime_audio;
1031
                                        gettimeofday(&lastAudioSent, NULL);
1032
                                }
1033
                        }
1034
                }
1035
                else {
1036
#ifdef DEBUG_CHUNKER
1037
                        fprintf(stderr,"Free the packet that was allocated by av_read_frame\n");
1038
#endif
1039
                        av_free_packet(&packet);
1040
                }
1041
        }
1042
        
1043
        if(videotrace)
1044
                fclose(videotrace);
1045
        if(psnrtrace)
1046
                fclose(psnrtrace);
1047

    
1048
close:
1049
        if(chunk->seq != 0 && chunk->frames_num>0) {
1050
                //SAVE ON FILE
1051
                //saveChunkOnFile(chunk);
1052
                //Send the chunk to an external transport/player
1053
                sendChunk(chunk);
1054
#ifdef DEBUG_CHUNKER
1055
                fprintf(stderr, "CHUNKER: SENDING LAST VIDEO CHUNK\n");
1056
#endif
1057
                chunk->seq = 0; //signal that we need an increase just in case we will restart
1058
        }
1059
        if(chunkaudio->seq != 0 && chunkaudio->frames_num>0) {
1060
                //SAVE ON FILE     
1061
                //saveChunkOnFile(chunkaudio);
1062
                //Send the chunk via http to an external transport/player
1063
                sendChunk(chunkaudio);
1064
#ifdef DEBUG_CHUNKER
1065
                fprintf(stderr, "CHUNKER: SENDING LAST AUDIO CHUNK\n");
1066
#endif
1067
                chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
1068
        }
1069

    
1070
#ifdef HTTPIO
1071
        /* finalize the HTTP chunk pusher */
1072
        finalizeChunkPusher();
1073
#elif TCPIO
1074
        finalizeTCPChunkPusher();
1075
#endif
1076

    
1077
        free(chunk);
1078
        free(chunkaudio);
1079
        free(frame);
1080
        av_free(video_outbuf);
1081
        av_free(scaledFrame_buffer);
1082
        av_free(audio_outbuf);
1083
        free(cmeta);
1084

    
1085
        // Free the YUV frame
1086
        av_free(pFrame);
1087
        av_free(scaledFrame);
1088
        av_free(samples);
1089
  
1090
        // Close the codec
1091
        avcodec_close(pCodecCtx);
1092
        avcodec_close(pCodecCtxEnc);
1093

    
1094
        if(audioStream!=-1) {
1095
                avcodec_close(aCodecCtx);
1096
                avcodec_close(aCodecCtxEnc);
1097
        }
1098
  
1099
        // Close the video file
1100
        av_close_input_file(pFormatCtx);
1101

    
1102
        if(LOOP_MODE) {
1103
                //we want video to continue, but the av_read_frame stopped
1104
                //lets wait a 5 secs, and cycle in again
1105
                usleep(5000000);
1106
#ifdef DEBUG_CHUNKER
1107
                fprintf(stderr, "CHUNKER: WAITING 5 secs FOR LIVE SOURCE TO SKIP ERRORS AND RESTARTING\n");
1108
#endif
1109
                videoStream = -1;
1110
                audioStream = -1;
1111
                FirstTimeAudio=1;
1112
                FirstTimeVideo=1;
1113
                pts_anomalies_counter=0;
1114
                newtime_anomalies_counter=0;
1115
                newTime=0;
1116
                newTime_audio=0;
1117
                newTime_prev=0;
1118
                ptsvideo1=0.0;
1119
                ptsaudio1=0.0;
1120
                last_pkt_dts=0;
1121
                delta_video=0;
1122
                delta_audio=0;
1123
                last_pkt_dts_audio=0;
1124
                target_pts=0;
1125
                i=0;
1126
                //~ contFrameVideo = 0;
1127
                //~ contFrameAudio = 1;
1128
                
1129
#ifdef YUV_RECORD_ENABLED
1130
                if(ChunkerStreamerTestMode)
1131
                {
1132
                        video_record_count++;
1133
                        //~ savedVideoFrames = 0;
1134
                        
1135
                        //~ char tmp_filename[255];
1136
                        //~ sprintf(tmp_filename, "yuv_data/out_%d.yuv", video_record_count);
1137
                        //~ FILE *pFile=fopen(tmp_filename, "w");
1138
                        //~ if(pFile!=NULL)
1139
                                //~ fclose(pFile);
1140
                }
1141
#endif
1142

    
1143
                goto restart;
1144
        }
1145

    
1146
        return 0;
1147
}
1148

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

    
1153
        //moving temp pointer to encode Frame on the wire
1154
        uint8_t *tempdata = NULL;
1155

    
1156
        if(chunk->seq == 0) {
1157
                initChunk(chunk, &seq_current_chunk);
1158
        }
1159
        //HINT on malloc
1160
        chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len + frame->size + sizeFrameHeader));
1161
        if(!chunk->data)  {
1162
                fprintf(stderr, "Memory error in chunk!!!\n");
1163
                return -1;
1164
        }
1165
        chunk->frames_num++; // number of frames in the current chunk
1166

    
1167
/*
1168
        //package the Frame header
1169
        tempdata = chunk->data+chunk->payload_len;
1170
        *((int32_t *)tempdata) = frame->number;
1171
        tempdata+=sizeof(int32_t);
1172
        *((struct timeval *)tempdata) = frame->timestamp;
1173
        tempdata+=sizeof(struct timeval);
1174
        *((int32_t *)tempdata) = frame->size;
1175
        tempdata+=sizeof(int32_t);
1176
        *((int32_t *)tempdata) = frame->type;
1177
        tempdata+=sizeof(int32_t);
1178
*/
1179
        //package the Frame header: network order and platform independent
1180
        tempdata = chunk->data+chunk->payload_len;
1181
        bit32_encoded_push(frame->number, tempdata);
1182
        bit32_encoded_push(frame->timestamp.tv_sec, tempdata + CHUNK_TRANSCODING_INT_SIZE);
1183
        bit32_encoded_push(frame->timestamp.tv_usec, tempdata + CHUNK_TRANSCODING_INT_SIZE*2);
1184
        bit32_encoded_push(frame->size, tempdata + CHUNK_TRANSCODING_INT_SIZE*3);
1185
        bit32_encoded_push(frame->type, tempdata + CHUNK_TRANSCODING_INT_SIZE*4);
1186

    
1187
         //insert the new frame data
1188
        memcpy(chunk->data + chunk->payload_len + sizeFrameHeader, outbuf, frame->size);
1189
        chunk->payload_len += frame->size + sizeFrameHeader; // update payload length
1190
        //chunk lenght is updated just prior to pushing it out because
1191
        //the chunk header len is better calculated there
1192
        //chunk->len = sizeChunkHeader + chunk->payload_len; // update overall length
1193

    
1194
        //update timestamps
1195
        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) {
1196
                                                chunk->start_time.tv_sec = frame->timestamp.tv_sec;
1197
                                                chunk->start_time.tv_usec = frame->timestamp.tv_usec;
1198
        }
1199
        
1200
        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) {
1201
                                                chunk->end_time.tv_sec = frame->timestamp.tv_sec;
1202
                                                chunk->end_time.tv_usec = frame->timestamp.tv_usec;
1203
        }
1204
        return 0;
1205
}
1206

    
1207
void SaveFrame(AVFrame *pFrame, int width, int height)
1208
{
1209
        FILE *pFile;
1210
        int  y;
1211

    
1212
         // Open file
1213
        char tmp_filename[255];
1214
        sprintf(tmp_filename, "yuv_data/streamer_out.yuv");
1215
        pFile=fopen(tmp_filename, "ab");
1216
        if(pFile==NULL)
1217
                return;
1218

    
1219
        // Write header
1220
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1221
  
1222
        // Write Y data
1223
        for(y=0; y<height; y++)
1224
                  if(fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile) != width)
1225
                {
1226
                        printf("errno = %d\n", errno);
1227
                        exit(1);
1228
                }
1229
        // Write U data
1230
        for(y=0; y<height/2; y++)
1231
                  if(fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile) != width/2)
1232
                  {
1233
                        printf("errno = %d\n", errno);
1234
                        exit(1);
1235
                }
1236
        // Write V data
1237
        for(y=0; y<height/2; y++)
1238
                  if(fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile) != width/2)
1239
                  {
1240
                        printf("errno = %d\n", errno);
1241
                        exit(1);
1242
                }
1243
  
1244
        // Close file
1245
        fclose(pFile);
1246
}
1247

    
1248
void SaveEncodedFrame(Frame* frame, uint8_t *video_outbuf)
1249
{
1250
        static FILE* pFile = NULL;
1251
        
1252
        pFile=fopen("yuv_data/streamer_out.mpeg4", "ab");
1253
        fwrite(frame, sizeof(Frame), 1, pFile);
1254
        fwrite(video_outbuf, frame->size, 1, pFile);
1255
        fclose(pFile);
1256
}