Statistics
| Branch: | Revision:

chunker-player / chunker_streamer / chunker_streamer.c @ e11386c0

History | View | Annotate | Download (39.2 KB)

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

    
10

    
11
#include "chunker_streamer.h"
12
#include <signal.h>
13
#include <math.h>
14
#include <getopt.h>
15
#include <libswscale/swscale.h>
16

    
17
#define STREAMER_MAX(a,b) ((a>b)?(a):(b))
18
#define STREAMER_MIN(a,b) ((a<b)?(a):(b))
19

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

    
27
ChunkerMetadata *cmeta = NULL;
28
int seq_current_chunk = 1; //chunk numbering starts from 1; HINT do i need more bytes?
29

    
30
#define AUDIO_CHUNK 0
31
#define VIDEO_CHUNK 1
32

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

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

    
49
        return 0;
50
}
51

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

    
65
// Performace optimization.
66
// The chunkFilled function has been splitted into two functions (one for each strategy).
67
// Instead of continuously check the strategy flag (which is constant),
68
// 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)
69
int (*chunkFilled)(ExternalChunk *echunk, int chunkType);
70

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

    
88
int quit = 0;
89

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

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

    
114
int main(int argc, char *argv[]) {
115
        signal(SIGINT, sigproc);
116
        
117
        int i=0;
118

    
119
        //output variables
120
        uint8_t *video_outbuf = NULL;
121
        int video_outbuf_size, video_frame_size;
122
        uint8_t *audio_outbuf = NULL;
123
        int audio_outbuf_size, audio_frame_size;
124
        int audio_data_size;
125

    
126
        //numeric identifiers of input streams
127
        int videoStream = -1;
128
        int audioStream = -1;
129

    
130
        int len1;
131
        int frameFinished;
132
        //frame sequential counters
133
        int contFrameAudio=1, contFrameVideo=0;
134
        int numBytes;
135

    
136
        //command line parameters
137
        int audio_bitrate = -1;
138
        int video_bitrate = -1;
139
        int live_source = 0; //tells to sleep before reading next frame in not live (i.e. file)
140
        int offset_av = 0; //tells to compensate for offset between audio and video in the file
141
        
142
        //a raw buffer for decoded uncompressed audio samples
143
        int16_t *samples = NULL;
144
        //a raw uncompressed video picture
145
        AVFrame *pFrame = NULL;
146
        AVFrame *scaledFrame = NULL;
147

    
148
        AVFormatContext *pFormatCtx;
149
        AVCodecContext  *pCodecCtx,*pCodecCtxEnc,*aCodecCtxEnc,*aCodecCtx;
150
        AVCodec         *pCodec,*pCodecEnc,*aCodec,*aCodecEnc;
151
        AVPacket         packet;
152

    
153
        //stuff needed to compute the right timestamps
154
        short int FirstTimeAudio=1, FirstTimeVideo=1;
155
        short int pts_anomalies_counter=0;
156
        short int newtime_anomalies_counter=0;
157
        long long newTime=0, newTime_audio=0, newTime_video=0, newTime_prev=0;
158
        struct timeval lastAudioSent = {0, 0};
159
        double ptsvideo1=0.0;
160
        double ptsaudio1=0.0;
161
        int64_t last_pkt_dts=0, delta_video=0, delta_audio=0, last_pkt_dts_audio=0, target_pts=0;
162

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

    
222
#ifdef YUV_RECORD_ENABLED
223
        if(ChunkerStreamerTestMode)
224
        {
225
                DELETE_DIR("yuv_data");
226
                CREATE_DIR("yuv_data");
227
                //FILE* pFile=fopen("yuv_data/streamer_out.yuv", "w");
228
                //fclose(pFile);
229
        }
230
#endif
231

    
232
restart:
233
        // read the configuration file
234
        cmeta = chunkerInit();
235
        switch(cmeta->strategy)
236
        {
237
                case 1:
238
                        chunkFilled = chunkFilledSizeStrategy;
239
                        break;
240
                default:
241
                        chunkFilled = chunkFilledFramesStrategy;
242
        }
243
                
244
        if(live_source)
245
                fprintf(stderr, "INIT: Using LIVE SOURCE TimeStamps\n");
246
        if(offset_av)
247
                fprintf(stderr, "INIT: Compensating AV OFFSET in file\n");
248

    
249
        // Register all formats and codecs
250
        av_register_all();
251

    
252
        // Open input file
253
        if(av_open_input_file(&pFormatCtx, av_input, NULL, 0, NULL) != 0) {
254
                fprintf(stdout, "INIT: Couldn't open video file. Exiting.\n");
255
                exit(-1);
256
        }
257

    
258
        // Retrieve stream information
259
        if(av_find_stream_info(pFormatCtx) < 0) {
260
                fprintf(stdout, "INIT: Couldn't find stream information. Exiting.\n");
261
                exit(-1);
262
        }
263

    
264
        // Dump information about file onto standard error
265
        dump_format(pFormatCtx, 0, av_input, 0);
266

    
267
        // Find the video and audio stream numbers
268
        for(i=0; i<pFormatCtx->nb_streams; i++) {
269
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && videoStream<0) {
270
                        videoStream=i;
271
                }
272
                if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audioStream<0) {
273
                        audioStream=i;
274
                }
275
        }
276
        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);
277

    
278
        fprintf(stderr, "INIT: Video stream has id : %d\n",videoStream);
279
        fprintf(stderr, "INIT: Audio stream has id : %d\n",audioStream);
280

    
281
        if(videoStream==-1 && audioStream==-1) {
282
                fprintf(stdout, "INIT: Didn't find audio and video streams. Exiting.\n");
283
                exit(-1);
284
        }
285

    
286
        // Get a pointer to the codec context for the input video stream
287
        pCodecCtx=pFormatCtx->streams[videoStream]->codec;
288
        pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
289
        //extract W and H
290
        fprintf(stderr, "INIT: Width:%d Height:%d\n", pCodecCtx->width, pCodecCtx->height);
291

    
292
        // Get a pointer to the codec context for the input audio stream
293
        if(audioStream != -1) {
294
                aCodecCtx=pFormatCtx->streams[audioStream]->codec;
295
                fprintf(stderr, "INIT: AUDIO Codecid: %d channels %d samplerate %d\n", aCodecCtx->codec_id, aCodecCtx->channels, aCodecCtx->sample_rate);
296
        }
297

    
298
        //setup video output encoder
299
        pCodecCtxEnc=avcodec_alloc_context();
300
#ifdef H264_VIDEO_ENCODER
301
        pCodecCtxEnc->me_range=16;
302
        pCodecCtxEnc->max_qdiff=4;
303
        pCodecCtxEnc->qmin=1;
304
        pCodecCtxEnc->qmax=30;
305
        pCodecCtxEnc->qcompress=0.6;
306
        pCodecCtxEnc->codec_type = CODEC_TYPE_VIDEO;
307
        pCodecCtxEnc->codec_id   = CODEC_ID_H264;//13;//pCodecCtx->codec_id;
308
        pCodecCtxEnc->bit_rate = video_bitrate;///400000;
309
        // resolution must be a multiple of two 
310
        pCodecCtxEnc->width = (dest_width > 0) ? dest_width : pCodecCtx->width;
311
        pCodecCtxEnc->height = (dest_height > 0) ? dest_height : pCodecCtx->height;
312
        // frames per second 
313
        pCodecCtxEnc->time_base= pCodecCtx->time_base;//(AVRational){1,25};
314
        pCodecCtxEnc->gop_size = 100; // emit one intra frame every ten frames 
315
        //pCodecCtxEnc->max_b_frames=1;
316
        pCodecCtxEnc->pix_fmt = PIX_FMT_YUV420P;
317

    
318
        pCodecCtxEnc->bit_rate_tolerance = video_bitrate*50;
319
//        pCodecCtxEnc->rc_min_rate = 0;
320
//        pCodecCtxEnc->rc_max_rate = 0;
321
//        pCodecCtxEnc->rc_buffer_size = 0;
322
        pCodecCtxEnc->flags |= CODEC_FLAG_PSNR;
323
//        pCodecCtxEnc->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8;
324
//        pCodecCtxEnc->crf = 0.0f;
325
        
326
#ifdef STREAMER_X264_USE_SSIM
327
        pCodecCtxEnc->flags2 |= CODEC_FLAG2_SSIM;
328
#endif
329

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

    
356
        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);
357

    
358
        // Find the decoder for the video stream
359
#ifdef H264_VIDEO_ENCODER
360
        fprintf(stderr, "INIT: Setting VIDEO codecID to H264: %d %d\n",pCodecCtx->codec_id, CODEC_ID_H264);
361
        pCodecEnc = avcodec_find_encoder(CODEC_ID_H264);//pCodecCtx->codec_id);
362
#else
363
        fprintf(stderr, "INIT: Setting VIDEO codecID to mpeg4: %d %d\n",pCodecCtx->codec_id, CODEC_ID_MPEG4);
364
        pCodecEnc = avcodec_find_encoder(CODEC_ID_MPEG4);
365
#endif
366

    
367
        if(pCodec==NULL) {
368
                fprintf(stderr, "INIT: Unsupported IN VIDEO pcodec!\n");
369
                return -1; // Codec not found
370
        }
371
        if(pCodecEnc==NULL) {
372
                fprintf(stderr, "INIT: Unsupported OUT VIDEO pcodecenc!\n");
373
                return -1; // Codec not found
374
        }
375
        if(avcodec_open(pCodecCtx, pCodec)<0) {
376
                fprintf(stderr, "INIT: could not open IN VIDEO codec\n");
377
                return -1; // Could not open codec
378
        }
379
        if(avcodec_open(pCodecCtxEnc, pCodecEnc)<0) {
380
                fprintf(stderr, "INIT: could not open OUT VIDEO codecEnc\n");
381
                return -1; // Could not open codec
382
        }
383

    
384
        if(audioStream!=-1) {
385
                //setup audio output encoder
386
                aCodecCtxEnc = avcodec_alloc_context();
387
                aCodecCtxEnc->bit_rate = audio_bitrate; //256000
388
                aCodecCtxEnc->sample_fmt = SAMPLE_FMT_S16;
389
                aCodecCtxEnc->sample_rate = aCodecCtx->sample_rate;
390
                aCodecCtxEnc->channels = aCodecCtx->channels;
391
                fprintf(stderr, "INIT: AUDIO bitrate OUT:%d sample_rate:%d channels:%d\n", aCodecCtxEnc->bit_rate, aCodecCtxEnc->sample_rate, aCodecCtxEnc->channels);
392

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

    
422
        // Allocate audio in and out buffers
423
        samples = (int16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
424
        if(samples == NULL) {
425
                fprintf(stderr, "INIT: Memory error alloc audio samples!!!\n");
426
                return -1;
427
        }
428
        audio_outbuf_size = STREAMER_MAX_AUDIO_BUFFER_SIZE;
429
        audio_outbuf = av_malloc(audio_outbuf_size);
430
        if(audio_outbuf == NULL) {
431
                fprintf(stderr, "INIT: Memory error alloc audio_outbuf!!!\n");
432
                return -1;
433
        }
434

    
435
        // Allocate video in frame and out buffer
436
        pFrame=avcodec_alloc_frame();
437
        scaledFrame=avcodec_alloc_frame();
438
        if(pFrame==NULL || scaledFrame == NULL) {
439
                fprintf(stderr, "INIT: Memory error alloc video frame!!!\n");
440
                return -1;
441
        }
442
        video_outbuf_size = STREAMER_MAX_VIDEO_BUFFER_SIZE;
443
        video_outbuf = av_malloc(video_outbuf_size);
444
        int scaledFrame_buf_size = avpicture_get_size( PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
445
        uint8_t* scaledFrame_buffer = (uint8_t *) av_malloc( scaledFrame_buf_size * sizeof( uint8_t ) );
446
        avpicture_fill( (AVPicture*) scaledFrame, scaledFrame_buffer, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height);
447
        if(!video_outbuf || !scaledFrame_buffer) {
448
                fprintf(stderr, "INIT: Memory error alloc video_outbuf!!!\n");
449
                return -1;
450
        }
451

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

    
483
        /* initialize the HTTP chunk pusher */
484
        initChunkPusher(); //TRIPLO
485

    
486
        long sleep=0;
487
        struct timeval now_tv;
488
        struct timeval tmp_tv;
489
        long long lateTime = 0;
490
        long long maxAudioInterval = 0;
491
        long long maxVDecodeTime = 0;
492
        unsigned char lastIFrameDistance = 0;
493

    
494
#ifdef TCPIO
495
        static char peer_ip[16];
496
        static int peer_port;
497
        int res = sscanf(cmeta->outside_world_url, "tcp://%15[0-9.]:%d", peer_ip, &peer_port);
498
        if (res < 2) {
499
                fprintf(stderr,"error parsing output url: %s\n", cmeta->outside_world_url);
500
                return -2;
501
        }
502
        
503
        initTCPPush(peer_ip, peer_port);
504
#endif
505
        
506
        char videotrace_filename[255];
507
        char psnr_filename[255];
508
        sprintf(videotrace_filename, "yuv_data/videotrace.log");
509
        sprintf(psnr_filename, "yuv_data/psnrtrace.log");
510
        FILE* videotrace = fopen(videotrace_filename, "w");
511
        FILE* psnrtrace = fopen(psnr_filename, "w");
512

    
513
        //main loop to read from the input file
514
        while((av_read_frame(pFormatCtx, &packet)>=0) && !quit)
515
        {
516
                //detect if a strange number of anomalies is occurring
517
                if(ptsvideo1 < 0 || ptsvideo1 > packet.dts || ptsaudio1 < 0 || ptsaudio1 > packet.dts) {
518
                        pts_anomalies_counter++;
519
#ifdef DEBUG_ANOMALIES
520
                        fprintf(stderr, "READLOOP: pts BASE anomaly detected number %d\n", pts_anomalies_counter);
521
#endif
522
                        if(live_source) { //reset just in case of live source
523
                                if(pts_anomalies_counter > 25) { //just a random threshold
524
                                        pts_anomalies_counter = 0;
525
                                        FirstTimeVideo = 1;
526
                                        FirstTimeAudio = 1;
527
#ifdef DEBUG_ANOMALIES
528
                                        fprintf(stderr, "READLOOP: too many pts BASE anomalies. resetting pts base\n");
529
#endif
530
                                }
531
                        }
532
                }
533

    
534
                //newTime_video and _audio are in usec
535
                //if video and audio stamps differ more than 5sec
536
                if( newTime_video - newTime_audio > 5000000 || newTime_video - newTime_audio < -5000000 ) {
537
                        newtime_anomalies_counter++;
538
#ifdef DEBUG_ANOMALIES
539
                        fprintf(stderr, "READLOOP: NEWTIME audio video differ anomaly detected number %d\n", newtime_anomalies_counter);
540
#endif
541
                }
542

    
543
                if(newtime_anomalies_counter > 50) { //just a random threshold
544
                        if(live_source) { //restart just in case of live source
545
#ifdef DEBUG_ANOMALIES
546
                                fprintf(stderr, "READLOOP: too many NEGATIVE TIMESTAMPS anomalies. Restarting.\n");
547
#endif
548
                                goto close;
549
                        }
550
                }
551

    
552
                // Is this a packet from the video stream?
553
                if(packet.stream_index==videoStream)
554
                {
555
                        if(!live_source)
556
                        {
557
                                if(audioStream != -1) { //take this "time bank" method into account only if we have audio track
558
                                        // lateTime < 0 means a positive time account that can be used to decode video frames
559
                                        // if (lateTime + maxVDecodeTime) >= 0 then we may have a negative time account after video transcoding
560
                                        // therefore, it's better to skip the frame
561
                                        if((lateTime+maxVDecodeTime) >= 0)
562
                                        {
563
#ifdef DEBUG_ANOMALIES
564
                                                fprintf(stderr, "\n\n\t\t************************* SKIPPING VIDEO FRAME ***********************************\n\n", sleep);
565
#endif
566
                                                continue;
567
                                        }
568
                                }
569
                        }
570
                        
571
                        gettimeofday(&tmp_tv, NULL);
572
                        
573
                        //decode the video packet into a raw pFrame
574
                        if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet)>0)
575
                        {
576
                                // usleep(5000);
577
#ifdef DEBUG_VIDEO_FRAMES
578
                                fprintf(stderr, "\n-------VIDEO FRAME type %d\n", pFrame->pict_type);
579
                                fprintf(stderr, "VIDEO: dts %lld pts %lld\n", packet.dts, packet.pts);
580
#endif
581
                                if(frameFinished)
582
                                { // it must be true all the time else error
583
                                
584
                                        frame->number = ++contFrameVideo;
585

    
586
#ifdef VIDEO_DEINTERLACE
587
                                        avpicture_deinterlace(
588
                                                (AVPicture*) pFrame,
589
                                                (const AVPicture*) pFrame,
590
                                                pCodecCtxEnc->pix_fmt,
591
                                                pCodecCtxEnc->width,
592
                                                pCodecCtxEnc->height);
593
#endif
594

    
595
#ifdef DEBUG_VIDEO_FRAMES
596
                                        fprintf(stderr, "VIDEO: finished frame %d dts %lld pts %lld\n", frame->number, packet.dts, packet.pts);
597
#endif
598
                                        if(frame->number==0) {
599
                                                if(packet.dts==AV_NOPTS_VALUE)
600
                                                {
601
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
602
                                                        contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
603
                                                        continue;
604
                                                }
605
                                                last_pkt_dts = packet.dts;
606
                                                newTime = 0;
607
                                        }
608
                                        else {
609
                                                if(packet.dts!=AV_NOPTS_VALUE) {
610
                                                        delta_video = packet.dts-last_pkt_dts;
611
                                                        last_pkt_dts = packet.dts;
612
                                                }
613
                                                else if(delta_video==0)
614
                                                {
615
                                                        //a Dts with a noPts value is troublesome case for delta calculation based on Dts
616
                                                        contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
617
                                                        continue;
618
                                                }
619
                                        }
620
#ifdef DEBUG_VIDEO_FRAMES
621
                                        fprintf(stderr, "VIDEO: deltavideo : %d\n", (int)delta_video);
622
#endif
623

    
624
                                        if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
625
                                        {
626
                                                static AVPicture pict;
627
                                                static struct SwsContext *img_convert_ctx = NULL;
628
                                                
629
                                                if(img_convert_ctx == NULL)
630
                                                {
631
                                                        img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, pCodecCtxEnc->width, pCodecCtxEnc->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
632
                                                        if(img_convert_ctx == NULL) {
633
                                                                fprintf(stderr, "Cannot initialize the conversion context!\n");
634
                                                                exit(1);
635
                                                        }
636
                                                }
637
                                                sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, scaledFrame->data, scaledFrame->linesize);
638
                                                video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, scaledFrame);
639
                                        }
640
                                        else
641
                                                video_frame_size = avcodec_encode_video(pCodecCtxEnc, video_outbuf, video_outbuf_size, pFrame);
642
                                        
643
                                        if(video_frame_size <= 0)
644
                                        {
645
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
646
                                                continue;
647
                                        }
648

    
649
                                        //use pts if dts is invalid
650
                                        if(packet.dts!=AV_NOPTS_VALUE)
651
                                                target_pts = packet.dts;
652
                                        else if(packet.pts!=AV_NOPTS_VALUE)
653
                                                target_pts = packet.pts;
654
                                        else
655
                                        {
656
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
657
                                                continue;
658
                                        }
659

    
660
                                        if(!offset_av)
661
                                        {
662
                                                if(FirstTimeVideo && packet.dts>0) {
663
                                                        ptsvideo1 = (double)packet.dts;
664
                                                        FirstTimeVideo = 0;
665
#ifdef DEBUG_VIDEO_FRAMES
666
                                                        fprintf(stderr, "VIDEO: SET PTS BASE OFFSET %f\n", ptsvideo1);
667
#endif
668
                                                }
669
                                        }
670
                                        else //we want to compensate audio and video offset for this source
671
                                        {
672
                                                if(FirstTimeVideo && packet.dts>0) {
673
                                                        //maintain the offset between audio pts and video pts
674
                                                        //because in case of live source they have the same numbering
675
                                                        if(ptsaudio1 > 0) //if we have already seen some audio frames...
676
                                                                ptsvideo1 = ptsaudio1;
677
                                                        else
678
                                                                ptsvideo1 = (double)packet.dts;
679
                                                        FirstTimeVideo = 0;
680
#ifdef DEBUG_VIDEO_FRAMES
681
                                                        fprintf(stderr, "VIDEO LIVE: SET PTS BASE OFFSET %f\n", ptsvideo1);
682
#endif
683
                                                }
684
                                        }
685
                                        //compute the new video timestamp in milliseconds
686
                                        if(frame->number>0) {
687
                                                newTime = ((double)target_pts-ptsvideo1)*1000.0/((double)delta_video*(double)av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate));
688
                                                // store timestamp in useconds for next frame sleep
689
                                                newTime_video = newTime*1000;
690
                                        }
691
#ifdef DEBUG_TIMESTAMPING
692
                                        fprintf(stderr, "VIDEO: NEWTIMESTAMP %ld\n", newTime);
693
#endif
694
                                        if(newTime<0) {
695
#ifdef DEBUG_VIDEO_FRAMES
696
                                                fprintf(stderr, "VIDEO: SKIPPING FRAME\n");
697
#endif
698
                                                newtime_anomalies_counter++;
699
#ifdef DEBUG_ANOMALIES
700
                                                fprintf(stderr, "READLOOP: NEWTIME negative video timestamp anomaly detected number %d\n", newtime_anomalies_counter);
701
#endif
702
                                                contFrameVideo = STREAMER_MAX(contFrameVideo-1, 0);
703
                                                continue; //SKIP THIS FRAME, bad timestamp
704
                                        }
705
                                        
706
                                        //~ printf("pCodecCtxEnc->error[0]=%lld\n", pFrame->error[0]);
707
        
708
                                        frame->timestamp.tv_sec = (long long)newTime/1000;
709
                                        frame->timestamp.tv_usec = newTime%1000;
710
                                        frame->size = video_frame_size;
711
                                        /* pict_type maybe 1 (I), 2 (P), 3 (B), 5 (AUDIO)*/
712
                                        frame->type = (unsigned char)pFrame->pict_type;
713

    
714
#ifdef H264_VIDEO_ENCODER
715

    
716
#ifdef STREAMER_X264_USE_SSIM
717
                                        /*double ssim_y = x264_context->enc->stat.frame.f_ssim
718
                      / (((x264_context->enc->param.i_width-6)>>2) * ((x264_context->enc->param.i_height-6)>>2));*/
719
#else
720
                                        //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 ));
721
                                        //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);
722
#endif
723

    
724
#else
725
                                        //psnr = (uint16_t) ((float)(STREAMER_MIN(GET_PSNR(pCodecCtxEnc->error[0]/(pCodecCtxEnc->width*pCodecCtxEnc->height*255.0*255.0)),MAX_PSNR))*65536/MAX_PSNR);
726
                                        //pCodecCtxEnc->error[0] = 0;
727
#endif
728

    
729
#ifdef DEBUG_VIDEO_FRAMES
730
                                        fprintf(stderr, "VIDEO: original codec frame number %d vs. encoded %d vs. packed %d\n", pCodecCtx->frame_number, pCodecCtxEnc->frame_number, frame->number);
731
                                        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);
732
#endif
733

    
734
#ifdef YUV_RECORD_ENABLED
735
                                        if(ChunkerStreamerTestMode)
736
                                        {
737
                                                if(videotrace)
738
                                                        fprintf(videotrace, "%d %d %d\n", frame->number, pFrame->pict_type, frame->size);
739

    
740
                                                if(pCodecCtx->height != pCodecCtxEnc->height || pCodecCtx->width != pCodecCtxEnc->width)
741
                                                        SaveFrame(scaledFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
742
                                                else
743
                                                        SaveFrame(pFrame, pCodecCtxEnc->width, pCodecCtxEnc->height);
744

    
745
                                                ++savedVideoFrames;
746
                                                SaveEncodedFrame(frame, video_outbuf);
747

    
748
                                                if(!firstSavedVideoFrame)
749
                                                        firstSavedVideoFrame = frame->number;
750
                                                
751
                                                char tmp_filename[255];
752
                                                sprintf(tmp_filename, "yuv_data/streamer_out_context.txt");
753
                                                FILE* tmp = fopen(tmp_filename, "w");
754
                                                if(tmp)
755
                                                {
756
                                                        fprintf(tmp, "width = %d\nheight = %d\ntotal_frames_saved = %d\ntotal_frames_decoded = %d\nfirst_frame_number = %d\nlast_frame_number = %d\n"
757
                                                                ,pCodecCtxEnc->width, pCodecCtxEnc->height
758
                                                                ,savedVideoFrames, savedVideoFrames, firstSavedVideoFrame, frame->number);
759
                                                        fclose(tmp);
760
                                                }
761
                                        }
762
#endif
763

    
764
#ifdef DEBUG_VIDEO_FRAMES
765
                                        fprintf(stderr, "VIDEO: encapsulated frame size:%d type:%d\n", frame->size, frame->type);
766
                                        fprintf(stderr, "VIDEO: timestamped sec %d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
767
#endif
768
                                        //contFrameVideo++; //lets increase the numbering of the frames
769

    
770
                                        if(update_chunk(chunk, frame, video_outbuf) == -1) {
771
                                                fprintf(stderr, "VIDEO: unable to update chunk %d. Exiting.\n", chunk->seq);
772
                                                exit(-1);
773
                                        }
774

    
775
                                        if(chunkFilled(chunk, VIDEO_CHUNK)) { // is chunk filled using current strategy?
776
                                                //SAVE ON FILE
777
                                                //saveChunkOnFile(chunk);
778
                                                //Send the chunk via http to an external transport/player
779
#ifdef HTTPIO
780
                                                pushChunkHttp(chunk, cmeta->outside_world_url);
781
#endif
782
#ifdef TCPIO
783
                                                pushChunkTcp(chunk);
784
#endif
785
#ifdef DEBUG_CHUNKER
786
                                                fprintf(stderr, "VIDEO: sent chunk video %d\n", chunk->seq);
787
#endif
788
                                                chunk->seq = 0; //signal that we need an increase
789
                                                //initChunk(chunk, &seq_current_chunk);
790
                                        }
791

    
792
                                        //compute how long it took to encode video frame
793
                                        gettimeofday(&now_tv, NULL);
794
                                        long long usec = (now_tv.tv_sec-tmp_tv.tv_sec)*1000000;
795
                                        usec+=(now_tv.tv_usec-tmp_tv.tv_usec);
796
                                        if(usec > maxVDecodeTime)
797
                                                maxVDecodeTime = usec;
798

    
799
                                        //we DONT have an audio track, so we compute timings and determine
800
                                        //how much time we have to sleep at next VIDEO frame taking
801
                                        //also into account how much time was needed to encode the current
802
                                        //video frame
803
                                        //all this in case the video source is not live, i.e. not self-timing
804
                                        //and only in case there is no audio track
805
                                        if(audioStream == -1) {
806
                                                if(!live_source) {
807
                                                        if(newTime_prev != 0) {
808
                                                                //how much delay between video frames ideally
809
                                                                long long maxDelay = newTime_video - newTime_prev;
810
                                                                sleep = (maxDelay - usec);
811
#ifdef DEBUG_ANOMALIES
812
                                                                printf("\tmaxDelay=%ld\n", ((long)maxDelay));
813
                                                                printf("\tlast video frame interval=%ld; sleep time=%ld\n", ((long)usec), ((long)sleep));
814
#endif
815
                                                        }
816
                                                        else
817
                                                                sleep = 0;
818

    
819
                                                        //update and store counters
820
                                                        newTime_prev = newTime_video;
821

    
822
                                                        //i can also sleep now instead of at the beginning of
823
                                                        //the next frame because in this case we only have video
824
                                                        //frames, hence it would immediately be the next thing to do
825
                                                        if(sleep > 0) {
826
#ifdef DEBUG_ANOMALIES
827
                                                                fprintf(stderr, "\n\tREADLOOP: going to sleep for %ld microseconds\n", sleep);
828
#endif
829
                                                                usleep(sleep);
830
                                                        }
831

    
832
                                                }
833
                                        }
834

    
835
                                }
836
                        }
837
                }
838
                else if(packet.stream_index==audioStream)
839
                {
840
                        if(sleep > 0)
841
                        {
842
#ifdef DEBUG_ANOMALIES
843
                                fprintf(stderr, "\n\tREADLOOP: going to sleep for %ld microseconds\n", sleep);
844
#endif
845
                                usleep(sleep);
846
                        }
847
                        
848
                        audio_data_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
849
                        //decode the audio packet into a raw audio source buffer
850
                        if(avcodec_decode_audio3(aCodecCtx, samples, &audio_data_size, &packet)>0)
851
                        {
852
#ifdef DEBUG_AUDIO_FRAMES
853
                                fprintf(stderr, "\n-------AUDIO FRAME\n");
854
                                fprintf(stderr, "AUDIO: newTimeaudioSTART : %lf\n", (double)(packet.pts)*av_q2d(pFormatCtx->streams[audioStream]->time_base));
855
#endif
856
                                if(audio_data_size>0) {
857
#ifdef DEBUG_AUDIO_FRAMES
858
                                        fprintf(stderr, "AUDIO: datasizeaudio:%d\n", audio_data_size);
859
#endif
860
                                        /* if a frame has been decoded, output it */
861
                                        //fwrite(samples, 1, audio_data_size, outfileaudio);
862
                                }
863
                                else
864
                                        continue;
865
        
866
                                audio_frame_size = avcodec_encode_audio(aCodecCtxEnc, audio_outbuf, audio_data_size, samples);
867
                                if(audio_frame_size <= 0)
868
                                        continue;
869
                                
870
                                frame->number = contFrameAudio;
871

    
872
                                if(frame->number==0) {
873
                                        if(packet.dts==AV_NOPTS_VALUE)
874
                                                continue;
875
                                        last_pkt_dts_audio = packet.dts;
876
                                        newTime = 0;
877
                                }
878
                                else {
879
                                        if(packet.dts!=AV_NOPTS_VALUE) {
880
                                                delta_audio = packet.dts-last_pkt_dts_audio;
881
                                                last_pkt_dts_audio = packet.dts;
882
                                        }
883
                                        else if(delta_audio==0)
884
                                                continue;
885
                                }
886
#ifdef DEBUG_AUDIO_FRAMES
887
                                fprintf(stderr, "AUDIO: original codec frame number %d vs. encoded %d vs. packed %d\n", aCodecCtx->frame_number, aCodecCtxEnc->frame_number, frame->number);
888
#endif
889
                                //use pts if dts is invalid
890
                                if(packet.dts!=AV_NOPTS_VALUE)
891
                                        target_pts = packet.dts;
892
                                else if(packet.pts!=AV_NOPTS_VALUE)
893
                                        target_pts = packet.pts;
894
                                else
895
                                        continue;
896

    
897
                                if(!offset_av)
898
                                {
899
                                        if(FirstTimeAudio && packet.dts>0) {
900
                                                ptsaudio1 = (double)packet.dts;
901
                                                FirstTimeAudio = 0;
902
#ifdef DEBUG_AUDIO_FRAMES
903
                                                fprintf(stderr, "AUDIO: SET PTS BASE OFFSET %f\n", ptsaudio1);
904
#endif
905
                                        }
906
                                }
907
                                else //we want to compensate audio and video offset for this source
908
                                {
909
                                        if(FirstTimeAudio && packet.dts>0) {
910
                                                //maintain the offset between audio pts and video pts
911
                                                //because in case of live source they have the same numbering
912
                                                if(ptsvideo1 > 0) //if we have already seen some video frames...
913
                                                        ptsaudio1 = ptsvideo1;
914
                                                else
915
                                                        ptsaudio1 = (double)packet.dts;
916
                                                FirstTimeAudio = 0;
917
#ifdef DEBUG_AUDIO_FRAMES
918
                                                fprintf(stderr, "AUDIO LIVE: SET PTS BASE OFFSET %f\n", ptsaudio1);
919
#endif
920
                                        }
921
                                }
922
                                //compute the new audio timestamps in milliseconds
923
                                if(frame->number>0) {
924
                                        newTime = (((double)target_pts-ptsaudio1)*1000.0*((double)av_q2d(pFormatCtx->streams[audioStream]->time_base)));//*(double)delta_audio;
925
                                        // store timestamp in useconds for next frame sleep
926
                                        newTime_audio = newTime*1000;
927
                                }
928
#ifdef DEBUG_TIMESTAMPING
929
                                fprintf(stderr, "AUDIO: NEWTIMESTAMP %d\n", newTime);
930
#endif
931
                                if(newTime<0) {
932
#ifdef DEBUG_AUDIO_FRAMES
933
                                        fprintf(stderr, "AUDIO: SKIPPING FRAME\n");
934
#endif
935
                                        newtime_anomalies_counter++;
936
#ifdef DEBUG_ANOMALIES
937
                                        fprintf(stderr, "READLOOP: NEWTIME negative audio timestamp anomaly detected number %d\n", newtime_anomalies_counter);
938
#endif
939
                                        continue; //SKIP THIS FRAME, bad timestamp
940
                                }
941

    
942
                                frame->timestamp.tv_sec = (unsigned int)newTime/1000;
943
                                frame->timestamp.tv_usec = newTime%1000;
944
                                frame->size = audio_frame_size;
945
                                frame->type = 5; // 5 is audio type
946
#ifdef DEBUG_AUDIO_FRAMES
947
                                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);
948
                                fprintf(stderr, "AUDIO: timestamp sec:%d usec:%d\n", frame->timestamp.tv_sec, frame->timestamp.tv_usec);
949
                                fprintf(stderr, "AUDIO: deltaaudio %lld\n", delta_audio);        
950
#endif
951
                                contFrameAudio++;
952

    
953
                                if(update_chunk(chunkaudio, frame, audio_outbuf) == -1) {
954
                                        fprintf(stderr, "AUDIO: unable to update chunk %d. Exiting.\n", chunkaudio->seq);
955
                                        exit(-1);
956
                                }
957
                                //set priority
958
                                chunkaudio->priority = 1;
959

    
960
                                if(chunkFilled(chunkaudio, AUDIO_CHUNK)) {
961
                                        // is chunk filled using current strategy?
962
                                        //SAVE ON FILE
963
                                        //saveChunkOnFile(chunkaudio);
964
                                        //Send the chunk via http to an external transport/player
965
                                        pushChunkHttp(chunkaudio, cmeta->outside_world_url);
966
#ifdef DEBUG_CHUNKER
967
                                        fprintf(stderr, "AUDIO: just sent chunk audio %d\n", chunkaudio->seq);
968
#endif
969
                                        chunkaudio->seq = 0; //signal that we need an increase
970
                                        //initChunk(chunkaudio, &seq_current_chunk);
971
                                }
972

    
973
                                //we have an audio track, so we compute timings and determine
974
                                //how much time we have to sleep at next audio frame taking
975
                                //also into account how much time was needed to encode the
976
                                //video frames
977
                                //all this in case the video source is not live, i.e. not self-timing
978
                                if(!live_source)
979
                                {
980
                                        if(newTime_prev != 0)
981
                                        {
982
                                                long long maxDelay = newTime_audio - newTime_prev;
983

    
984
                                                gettimeofday(&now_tv, NULL);
985
                                                long long usec = (now_tv.tv_sec-lastAudioSent.tv_sec)*1000000;
986
                                                usec+=(now_tv.tv_usec-lastAudioSent.tv_usec);
987

    
988
                                                if(usec > maxAudioInterval)
989
                                                        maxAudioInterval = usec;
990

    
991
                                                lateTime -= (maxDelay - usec);
992
#ifdef DEBUG_ANOMALIES
993
                                                printf("\tmaxDelay=%ld, maxAudioInterval=%ld\n", ((long)maxDelay), ((long) maxAudioInterval));
994
                                                printf("\tlast audio frame interval=%ld; lateTime=%ld\n", ((long)usec), ((long)lateTime));
995
#endif
996

    
997
                                                if((lateTime+maxAudioInterval) < 0)
998
                                                        sleep = (lateTime+maxAudioInterval)*-1;
999
                                                else
1000
                                                        sleep = 0;
1001
                                        }
1002
                                        else
1003
                                                sleep = 0;
1004

    
1005
                                        newTime_prev = newTime_audio;
1006
                                        gettimeofday(&lastAudioSent, NULL);
1007
                                }
1008
                        }
1009
                }
1010
                else {
1011
#ifdef DEBUG_CHUNKER
1012
                        fprintf(stderr,"Free the packet that was allocated by av_read_frame\n");
1013
#endif
1014
                        av_free_packet(&packet);
1015
                }
1016
        }
1017
        
1018
        if(videotrace)
1019
                fclose(videotrace);
1020
        if(psnrtrace)
1021
                fclose(psnrtrace);
1022

    
1023
close:
1024
        if(chunk->seq != 0 && chunk->frames_num>0) {
1025
                //SAVE ON FILE
1026
                //saveChunkOnFile(chunk);
1027
                //Send the chunk via http to an external transport/player
1028
                pushChunkHttp(chunk, cmeta->outside_world_url);
1029
#ifdef DEBUG_CHUNKER
1030
                fprintf(stderr, "CHUNKER: SENDING LAST VIDEO CHUNK\n");
1031
#endif
1032
                chunk->seq = 0; //signal that we need an increase just in case we will restart
1033
        }
1034
        if(chunkaudio->seq != 0 && chunkaudio->frames_num>0) {
1035
                //SAVE ON FILE     
1036
                //saveChunkOnFile(chunkaudio);
1037
                //Send the chunk via http to an external transport/player
1038
                pushChunkHttp(chunkaudio, cmeta->outside_world_url);
1039
#ifdef DEBUG_CHUNKER
1040
                fprintf(stderr, "CHUNKER: SENDING LAST AUDIO CHUNK\n");
1041
#endif
1042
                chunkaudio->seq = 0; //signal that we need an increase just in case we will restart
1043
        }
1044

    
1045
#ifdef HTTPIO
1046
        /* finalize the HTTP chunk pusher */
1047
        finalizeChunkPusher();
1048
#elif TCPIO
1049
        finalizeTCPChunkPusher();
1050
#endif
1051

    
1052
        free(chunk);
1053
        free(chunkaudio);
1054
        free(frame);
1055
        av_free(video_outbuf);
1056
        av_free(scaledFrame_buffer);
1057
        av_free(audio_outbuf);
1058
        free(cmeta);
1059

    
1060
        // Free the YUV frame
1061
        av_free(pFrame);
1062
        av_free(scaledFrame);
1063
        av_free(samples);
1064
  
1065
        // Close the codec
1066
        avcodec_close(pCodecCtx);
1067
        avcodec_close(pCodecCtxEnc);
1068

    
1069
        if(audioStream!=-1) {
1070
                avcodec_close(aCodecCtx);
1071
                avcodec_close(aCodecCtxEnc);
1072
        }
1073
  
1074
        // Close the video file
1075
        av_close_input_file(pFormatCtx);
1076

    
1077
        if(LOOP_MODE) {
1078
                //we want video to continue, but the av_read_frame stopped
1079
                //lets wait a 5 secs, and cycle in again
1080
                usleep(5000000);
1081
#ifdef DEBUG_CHUNKER
1082
                fprintf(stderr, "CHUNKER: WAITING 5 secs FOR LIVE SOURCE TO SKIP ERRORS AND RESTARTING\n");
1083
#endif
1084
                videoStream = -1;
1085
                audioStream = -1;
1086
                FirstTimeAudio=1;
1087
                FirstTimeVideo=1;
1088
                pts_anomalies_counter=0;
1089
                newtime_anomalies_counter=0;
1090
                newTime=0;
1091
                newTime_audio=0;
1092
                newTime_prev=0;
1093
                ptsvideo1=0.0;
1094
                ptsaudio1=0.0;
1095
                last_pkt_dts=0;
1096
                delta_video=0;
1097
                delta_audio=0;
1098
                last_pkt_dts_audio=0;
1099
                target_pts=0;
1100
                i=0;
1101
                //~ contFrameVideo = 0;
1102
                //~ contFrameAudio = 1;
1103
                
1104
#ifdef YUV_RECORD_ENABLED
1105
                if(ChunkerStreamerTestMode)
1106
                {
1107
                        video_record_count++;
1108
                        //~ savedVideoFrames = 0;
1109
                        
1110
                        //~ char tmp_filename[255];
1111
                        //~ sprintf(tmp_filename, "yuv_data/out_%d.yuv", video_record_count);
1112
                        //~ FILE *pFile=fopen(tmp_filename, "w");
1113
                        //~ if(pFile!=NULL)
1114
                                //~ fclose(pFile);
1115
                }
1116
#endif
1117

    
1118
                goto restart;
1119
        }
1120

    
1121
        return 0;
1122
}
1123

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

    
1128
        //moving temp pointer to encode Frame on the wire
1129
        uint8_t *tempdata = NULL;
1130

    
1131
        if(chunk->seq == 0) {
1132
                initChunk(chunk, &seq_current_chunk);
1133
        }
1134
        //HINT on malloc
1135
        chunk->data = (uint8_t *)realloc(chunk->data, sizeof(uint8_t)*(chunk->payload_len + frame->size + sizeFrameHeader));
1136
        if(!chunk->data)  {
1137
                fprintf(stderr, "Memory error in chunk!!!\n");
1138
                return -1;
1139
        }
1140
        chunk->frames_num++; // number of frames in the current chunk
1141

    
1142
/*
1143
        //package the Frame header
1144
        tempdata = chunk->data+chunk->payload_len;
1145
        *((int32_t *)tempdata) = frame->number;
1146
        tempdata+=sizeof(int32_t);
1147
        *((struct timeval *)tempdata) = frame->timestamp;
1148
        tempdata+=sizeof(struct timeval);
1149
        *((int32_t *)tempdata) = frame->size;
1150
        tempdata+=sizeof(int32_t);
1151
        *((int32_t *)tempdata) = frame->type;
1152
        tempdata+=sizeof(int32_t);
1153
*/
1154
        //package the Frame header: network order and platform independent
1155
        tempdata = chunk->data+chunk->payload_len;
1156
        bit32_encoded_push(frame->number, tempdata);
1157
        bit32_encoded_push(frame->timestamp.tv_sec, tempdata + CHUNK_TRANSCODING_INT_SIZE);
1158
        bit32_encoded_push(frame->timestamp.tv_usec, tempdata + CHUNK_TRANSCODING_INT_SIZE*2);
1159
        bit32_encoded_push(frame->size, tempdata + CHUNK_TRANSCODING_INT_SIZE*3);
1160
        bit32_encoded_push(frame->type, tempdata + CHUNK_TRANSCODING_INT_SIZE*4);
1161

    
1162
         //insert the new frame data
1163
        memcpy(chunk->data + chunk->payload_len + sizeFrameHeader, outbuf, frame->size);
1164
        chunk->payload_len += frame->size + sizeFrameHeader; // update payload length
1165
        //chunk lenght is updated just prior to pushing it out because
1166
        //the chunk header len is better calculated there
1167
        //chunk->len = sizeChunkHeader + chunk->payload_len; // update overall length
1168

    
1169
        //update timestamps
1170
        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) {
1171
                                                chunk->start_time.tv_sec = frame->timestamp.tv_sec;
1172
                                                chunk->start_time.tv_usec = frame->timestamp.tv_usec;
1173
        }
1174
        
1175
        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) {
1176
                                                chunk->end_time.tv_sec = frame->timestamp.tv_sec;
1177
                                                chunk->end_time.tv_usec = frame->timestamp.tv_usec;
1178
        }
1179
        return 0;
1180
}
1181

    
1182
void SaveFrame(AVFrame *pFrame, int width, int height)
1183
{
1184
        FILE *pFile;
1185
        int  y;
1186

    
1187
         // Open file
1188
        char tmp_filename[255];
1189
        sprintf(tmp_filename, "yuv_data/streamer_out.yuv");
1190
        pFile=fopen(tmp_filename, "ab");
1191
        if(pFile==NULL)
1192
                return;
1193

    
1194
        // Write header
1195
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1196
  
1197
        // Write Y data
1198
        for(y=0; y<height; y++)
1199
                  if(fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile) != width)
1200
                {
1201
                        printf("errno = %d\n", errno);
1202
                        exit(1);
1203
                }
1204
        // Write U data
1205
        for(y=0; y<height/2; y++)
1206
                  if(fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile) != width/2)
1207
                  {
1208
                        printf("errno = %d\n", errno);
1209
                        exit(1);
1210
                }
1211
        // Write V data
1212
        for(y=0; y<height/2; y++)
1213
                  if(fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile) != width/2)
1214
                  {
1215
                        printf("errno = %d\n", errno);
1216
                        exit(1);
1217
                }
1218
  
1219
        // Close file
1220
        fclose(pFile);
1221
}
1222

    
1223
void SaveEncodedFrame(Frame* frame, uint8_t *video_outbuf)
1224
{
1225
        static FILE* pFile = NULL;
1226
        
1227
        pFile=fopen("yuv_data/streamer_out.mpeg4", "ab");
1228
        fwrite(frame, sizeof(Frame), 1, pFile);
1229
        fwrite(video_outbuf, frame->size, 1, pFile);
1230
        fclose(pFile);
1231
}