Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_core.c @ 25d95dfe

History | View | Annotate | Download (50.4 KB)

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

    
9
#include <libavcodec/avcodec.h>
10
#include <libavformat/avformat.h>
11
#include <libswscale/swscale.h>
12
#include "libav-compat.h"
13

    
14
#include <stdio.h>
15
#include <unistd.h>
16
#include "external_chunk_transcoding.h"
17
#include "frame.h"
18
#include <SDL.h>
19
#include <SDL_thread.h>
20
#include <SDL_mutex.h>
21
// #include <SDL_ttf.h>
22
// #include <SDL_image.h>
23
#include <SDL_video.h>
24
#include <assert.h>
25
#include <time.h>
26

    
27
#include "player_stats.h"
28
#include "player_defines.h"
29
#include "chunker_player.h"
30
#include "player_gui.h"
31
#include "player_core.h"
32
#include "player_stats.h"
33

    
34
#define MAX(A,B)    ((A)>(B) ? (A) : (B))
35
#define MIN(A,B)    ((A)<(B) ? (A) : (B))
36

    
37
SDL_Overlay *YUVOverlay;
38

    
39
typedef struct PacketQueue {
40
        AVPacketList *first_pkt;
41
        AVPacket *minpts_pkt;
42
        AVPacketList *last_pkt;
43
        int nb_packets;
44
        int size;
45
        SDL_mutex *mutex;
46
        short int queueType;
47
        int last_frame_extracted; //HINT THIS SHOULD BE MORE THAN 4 BYTES
48
        //total frames lost, as seen from the queue, since last queue init
49
        int total_lost_frames;
50
        long cumulative_bitrate;
51
        long cumulative_samples;
52

    
53
        SHistory PacketHistory;
54
        
55
        double density;
56
        char stats_message[255];
57
} PacketQueue;
58

    
59
AVCodecContext  *aCodecCtx;
60
SDL_Thread *video_thread;
61
SDL_Thread *stats_thread;
62
uint8_t *outbuf_audio;
63
// short int QueueFillingMode=1;
64
short int QueueStopped;
65
ThreadVal VideoCallbackThreadParams;
66

    
67
int AudioQueueOffset;
68
PacketQueue audioq;
69
PacketQueue videoq;
70
AVPacket AudioPkt, VideoPkt;
71
int AVPlaying;
72
int CurrentAudioFreq;
73
int CurrentAudioSamples;
74
uint8_t CurrentAudioSilence;
75

    
76
int GotSigInt;
77

    
78
long long DeltaTime;
79
short int FirstTimeAudio, FirstTime;
80

    
81
int dimAudioQ;
82
float deltaAudioQ;
83
float deltaAudioQError;
84

    
85
int SaveYUV;
86
char YUVFileName[256];
87
int SaveLoss;
88

    
89
char VideoFrameLossRateLogFilename[256];
90
char VideoFrameSkipRateLogFilename[256];
91

    
92
long int decoded_vframes;
93
long int LastSavedVFrame;
94

    
95
float ycrop = 0;
96

    
97
void SaveFrame(AVFrame *pFrame, int width, int height);
98
int VideoCallback(void *valthread);
99
int CollectStatisticsThread(void *params);
100
void AudioCallback(void *userdata, Uint8 *stream, int len);
101
void PacketQueueClearStats(PacketQueue *q);
102

    
103
//int lastCheckedVideoFrame = -1;
104
long int last_video_frame_extracted = -1;
105

    
106
int timeval_subtract(struct timeval* x, struct timeval* y, struct timeval* result)
107
{
108
  // Perform the carry for the later subtraction by updating y.
109
  if (x->tv_usec < y->tv_usec)
110
  {
111
    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
112
    y->tv_usec -= 1000000 * nsec;
113
    y->tv_sec += nsec;
114
  }
115
  if (x->tv_usec - y->tv_usec > 1000000)
116
  {
117
    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
118
    y->tv_usec += 1000000 * nsec;
119
    y->tv_sec -= nsec;
120
  }
121

    
122
  // Compute the time remaining to wait. tv_usec is certainly positive.
123
  result->tv_sec = x->tv_sec - y->tv_sec;
124
  result->tv_usec = x->tv_usec - y->tv_usec;
125

    
126
  // Return 1 if result is negative.
127
  return x->tv_sec < y->tv_sec;
128
}
129

    
130

    
131
void PacketQueueInit(PacketQueue *q, short int Type)
132
{
133
#ifdef DEBUG_QUEUE
134
        fprintf(stderr,"QUEUE: INIT BEGIN: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
135
#endif
136
        memset(q,0,sizeof(PacketQueue));
137
        q->mutex = SDL_CreateMutex();
138
        QueueFillingMode=1;
139
        q->queueType=Type;
140
        q->last_frame_extracted = -1;
141
        q->first_pkt= NULL;
142
        q->minpts_pkt= NULL;
143
        //q->last_pkt = NULL;
144
        q->nb_packets = 0;
145
        q->size = 0;
146
        q->density= 0.0;
147
        FirstTime = 1;
148
        FirstTimeAudio = 1;
149
        //init up statistics
150
        
151
        q->PacketHistory.Mutex = SDL_CreateMutex();
152
        PacketQueueClearStats(q);
153
        
154
#ifdef DEBUG_QUEUE
155
        fprintf(stderr,"QUEUE: INIT END: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
156
#endif
157
}
158

    
159
void PacketQueueReset(PacketQueue *q)
160
{
161
        AVPacketList *tmp,*tmp1;
162
#ifdef DEBUG_QUEUE
163
        fprintf(stderr,"QUEUE: RESET BEGIN: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
164
#endif
165
        SDL_LockMutex(q->mutex);
166

    
167
        tmp = q->first_pkt;
168
        while(tmp) {
169
                tmp1 = tmp;
170
                tmp = tmp->next;
171
                av_free_packet(&(tmp1->pkt));
172
                av_free(tmp1);
173
#ifdef DEBUG_QUEUE
174
                fprintf(stderr,"F ");
175
#endif
176
                q->PacketHistory.LostCount++;
177
        }
178
#ifdef DEBUG_QUEUE
179
        fprintf(stderr,"\n");
180
#endif
181

    
182
        QueueFillingMode=1;
183
        q->last_frame_extracted = -1;
184
        
185
        // on queue reset do not reset loss count
186
        // (loss count reset is done on queue init, ie channel switch)
187
        q->density=0.0;
188
        q->first_pkt= NULL;
189
        q->minpts_pkt= NULL;
190
        //q->last_pkt = NULL;
191
        q->nb_packets = 0;
192
        q->size = 0;
193
        FirstTime = 1;
194
        FirstTimeAudio = 1;
195
        //clean up statistics
196
        PacketQueueClearStats(q);
197
#ifdef DEBUG_QUEUE
198
        fprintf(stderr,"QUEUE: RESET END: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
199
#endif
200
        SDL_UnlockMutex(q->mutex);
201
}
202

    
203
void PacketQueueClearStats(PacketQueue *q)
204
{
205
        sprintf(q->stats_message, "%s", "\n");
206
        int i;
207
        memset((void*)q->PacketHistory.History, 0, sizeof(SHistoryElement)*QUEUE_HISTORY_SIZE);
208
        for(i=0; i<QUEUE_HISTORY_SIZE; i++)
209
        {
210
                q->PacketHistory.History[i].Statistics.LastIFrameDistance = -1;
211
                q->PacketHistory.History[i].Status = -1;
212
        }
213
        q->PacketHistory.Index = q->PacketHistory.LogIndex = 0;
214
        q->PacketHistory.Index = q->PacketHistory.QoEIndex = 0;
215
        q->PacketHistory.LostCount = q->PacketHistory.PlayedCount = q->PacketHistory.SkipCount = 0;
216
}
217

    
218
int ChunkerPlayerCore_PacketQueuePut(PacketQueue *q, AVPacket *pkt)
219
{
220
        //~ fprintf(stderr,"\tSTREAM_INDEX=%d\n", pkt->stream_index);
221
        short int skip = 0;
222
        AVPacketList *pkt1, *tmp, *prevtmp;
223
        int res = 0;
224

    
225
        if(q->nb_packets > queue_filling_threshold*QUEUE_MAX_GROW_FACTOR) {
226
#ifdef DEBUG_QUEUE
227
                fprintf(stderr,"QUEUE: PUT i have TOO MANY packets %d Type=%s, RESETTING\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
228
#endif
229
                PacketQueueReset(q);
230
        }
231

    
232
        //make a copy of the incoming packet
233
        if(av_dup_packet(pkt) < 0) {
234
#ifdef DEBUG_QUEUE
235
                fprintf(stderr,"QUEUE: PUT in Queue cannot duplicate in packet        : NPackets=%d Type=%s\n",q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
236
#endif
237
                return -1;
238
        }
239
        pkt1 = av_malloc(sizeof(AVPacketList));
240

    
241
        if(!pkt1) {
242
                av_free_packet(pkt);
243
                return -1;
244
        }
245
        pkt1->pkt = *pkt;
246
        pkt1->next = NULL;
247
        
248
        static time_t last_auto_switch = 0;
249

    
250
        if(
251
                (pkt->stream_index < last_video_frame_extracted)
252
                && (pkt->stream_index <= RESTART_FRAME_NUMBER_THRESHOLD)
253
                && ((time(NULL) - last_auto_switch) > 10)
254
        )
255
        {
256
                fprintf(stderr,"file streaming loop detected => re-tune channel and start grabbing statistics\n");
257
                last_auto_switch = time(NULL);
258
                SDL_LockMutex(q->mutex);
259
                ReTune(&(Channels[SelectedChannel]));
260
                SDL_UnlockMutex(q->mutex);
261
        }
262

    
263
        else
264
        {
265
                SDL_LockMutex(q->mutex);
266

    
267
                // INSERTION SORT ALGORITHM
268
                // before inserting pkt, check if pkt.stream_index is <= current_extracted_frame.
269
                if(pkt->stream_index > q->last_frame_extracted)
270
                {
271
                        // either checking starting from the first_pkt or needed other struct like AVPacketList with next and prev....
272
                        //if (!q->last_pkt)
273
                        if(!q->first_pkt) {
274
                                q->first_pkt = pkt1;
275
                                q->last_pkt = pkt1;
276
                        }
277
                        else if(pkt->stream_index < q->first_pkt->pkt.stream_index) {
278
                                //the packet that has arrived is earlier than the first we got some time ago!
279
                                //we need to put it at the head of the queue
280
                                pkt1->next = q->first_pkt;
281
                                q->first_pkt = pkt1;
282
                        }
283
                        else {
284
                                tmp = q->first_pkt;
285
                                while(tmp->pkt.stream_index < pkt->stream_index) {
286
                                        prevtmp = tmp;
287
                                        tmp = tmp->next;
288

    
289
                                        if(!tmp) {
290
                                                break;
291
                                        }
292
                                }
293
                                if(tmp && tmp->pkt.stream_index == pkt->stream_index) {
294
                                        //we already have a frame with that index
295
                                        skip = 1;
296
#ifdef DEBUG_QUEUE
297
                                        fprintf(stderr,"%s QUEUE: PUT: we already have frame with index %d, skipping\n", ((q->queueType == AUDIO) ? "AUDIO" : "VIDEO"), pkt->stream_index);
298
#endif
299
                                }
300
                                else {
301
                                        prevtmp->next = pkt1;
302
                                        pkt1->next = tmp;
303
                                        if(pkt1->next == NULL)
304
                                                q->last_pkt = pkt1;
305
                                }
306
                                //q->last_pkt->next = pkt1; // It was uncommented when not insertion sort
307
                        }
308
                        if(skip == 0) {
309
                                //q->last_pkt = pkt1;
310
                                q->nb_packets++;
311
                                q->size += pkt1->pkt.size;
312
                                if(q->nb_packets>=queue_filling_threshold && QueueFillingMode) // && q->queueType==AUDIO)
313
                                {
314
                                        QueueFillingMode=0;
315
#ifdef DEBUG_QUEUE
316
                                        fprintf(stderr,"QUEUE: PUT: FillingMode set to zero\n");
317
#endif
318
                                }
319
                                //set min
320
                                if (!q->minpts_pkt || (pkt1->pkt.pts < q->minpts_pkt->pts)) {
321
                                        q->minpts_pkt = &(pkt1->pkt);
322
                                }
323
                        }
324
                }
325
                else {
326
                        av_free_packet(&pkt1->pkt);
327
                        av_free(pkt1);
328
#ifdef DEBUG_QUEUE
329
                        fprintf(stderr,"QUEUE: PUT: NOT inserting because index %d <= last extracted %d\n", pkt->stream_index, q->last_frame_extracted);
330
#endif
331
                        res = 1;
332
                }
333
                SDL_UnlockMutex(q->mutex);
334
        }
335

    
336
        return res;
337
}
338

    
339
int OpenACodec (char *audio_codec, int sample_rate, short int audio_channels)
340
{
341
        AVCodec *aCodec;
342

    
343
        aCodecCtx = avcodec_alloc_context();
344
        //aCodecCtx->bit_rate = 64000;
345
        aCodecCtx->sample_rate = sample_rate;
346
        aCodecCtx->channels = audio_channels;
347
        aCodec = avcodec_find_decoder_by_name(audio_codec);
348
        if(!aCodec) {
349
                fprintf(stderr,"Codec not found!\n");
350
                return -1;
351
        }
352
        if(avcodec_open(aCodecCtx, aCodec)<0) {
353
                fprintf(stderr, "could not open codec\n");
354
                return -1; // Could not open codec
355
        }
356
        fprintf(stderr,"using audio Codecid: %d ",aCodecCtx->codec_id);
357
        fprintf(stderr,"samplerate: %d ",aCodecCtx->sample_rate);
358
        fprintf(stderr,"channels: %d\n",aCodecCtx->channels);
359

    
360
        return 1;
361
}
362

    
363
int OpenAudio(AVCodecContext  *aCodecCtx)
364
{
365
        SDL_AudioSpec *wanted_spec;
366
        static SDL_AudioSpec *wanted_spec_old = NULL;
367

    
368
        if (! (wanted_spec = malloc(sizeof(*wanted_spec)))) {
369
                perror("error initializing audio");
370
                return -1;
371
        }
372
        wanted_spec->freq = aCodecCtx->sample_rate;
373
        wanted_spec->format = AUDIO_S16SYS;
374
        wanted_spec->channels = aCodecCtx->channels;
375
        wanted_spec->silence = 0;
376
        wanted_spec->samples = SDL_AUDIO_BUFFER_SIZE;
377
        wanted_spec->callback = AudioCallback;
378
        wanted_spec->userdata = aCodecCtx;
379

    
380
#ifdef DEBUG_AUDIO
381
        fprintf(stderr,"wanted freq:%d\n",wanted_spec->freq);
382
        fprintf(stderr,"wanted format:%d\n",wanted_spec->format);
383
        fprintf(stderr,"wanted channels:%d\n",wanted_spec->channels);
384
        fprintf(stderr,"wanted silence:%d\n",wanted_spec->silence);
385
        fprintf(stderr,"wanted samples:%d\n",wanted_spec->samples);
386
#endif
387

    
388
        if (wanted_spec_old && 
389
           (wanted_spec->freq == wanted_spec_old->freq) &&
390
           (wanted_spec->channels == wanted_spec_old->channels)) {        //do not reinit audio if the wanted specification is the same as before
391
                return 1;
392
        }
393

    
394
        if(wanted_spec_old) {
395
                SDL_CloseAudio();
396
        }
397

    
398
        if (! (wanted_spec_old = malloc(sizeof(*wanted_spec_old)))) {
399
                perror("error initializing audio");
400
                return -1;
401
        }
402
        memcpy(wanted_spec_old, wanted_spec, sizeof(*wanted_spec));
403

    
404
        if (SDL_OpenAudio(wanted_spec,NULL)<0) {
405
                fprintf(stderr,"SDL_OpenAudio: %s\n", SDL_GetError());
406
                return -1;
407
        }
408

    
409
        CurrentAudioFreq = wanted_spec->freq;
410
        CurrentAudioSamples = wanted_spec->samples;
411
        dimAudioQ = wanted_spec->size;
412
        deltaAudioQ = (float)((float)wanted_spec->samples)*1000/wanted_spec->freq;        //in ms
413
        CurrentAudioSilence = wanted_spec->silence;
414

    
415
#ifdef DEBUG_AUDIO
416
        fprintf(stderr,"freq:%d\n",wanted_spec->freq);
417
        fprintf(stderr,"format:%d\n",wanted_spec->format);
418
        fprintf(stderr,"channels:%d\n",wanted_spec->channels);
419
        fprintf(stderr,"silence:%d\n",wanted_spec->silence);
420
        fprintf(stderr,"samples:%d\n",wanted_spec->samples);
421
        fprintf(stderr,"size:%d\n",wanted_spec->size);
422
        fprintf(stderr,"deltaAudioQ: %f\n",deltaAudioQ);
423
#endif
424

    
425
        return 1;
426
}
427

    
428
int ChunkerPlayerCore_InitAudioCodecs(char *audio_codec, int sample_rate, short int audio_channels)
429
{
430
        // some initializations
431
        QueueStopped = 0;
432
        AudioQueueOffset=0;
433
        AVPlaying = 0;
434
        GotSigInt = 0;
435
        FirstTimeAudio=1;
436
        FirstTime = 1;
437
        deltaAudioQError=0;
438

    
439

    
440
        if (OpenACodec(audio_codec, sample_rate, audio_channels) < 0) {
441
                return -1;
442
        }
443

    
444
        if (OpenAudio(aCodecCtx) < 1) {
445
                return -1;
446
        }
447

    
448
        outbuf_audio = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
449

    
450
        //initialize the audio queue
451
        PacketQueueInit(&audioq, AUDIO);
452
        
453
        // Init audio buffers
454
        av_init_packet(&AudioPkt);
455
        //fprintf(stderr,"AVCODEC_MAX_AUDIO_FRAME_SIZE=%d\n", AVCODEC_MAX_AUDIO_FRAME_SIZE);
456
        AudioPkt.data=(uint8_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
457
        if(!AudioPkt.data) return -1;
458

    
459
        return 0;
460
}
461

    
462
int ChunkerPlayerCore_InitVideoCodecs(char *v_codec, int width, int height)
463
{
464

    
465
        memset(&VideoCallbackThreadParams, 0, sizeof(ThreadVal));
466
        
467
        VideoCallbackThreadParams.width = width;
468
        VideoCallbackThreadParams.height = height;
469
        VideoCallbackThreadParams.video_codec = strdup(v_codec);
470

    
471
        //initialize the video queue
472
        PacketQueueInit(&videoq, VIDEO);
473

    
474
        // Init video buffers
475
        av_init_packet(&VideoPkt);
476

    
477
        VideoPkt.data=(uint8_t *)malloc(width*height*3/2);
478
        if(!VideoPkt.data) return -1;
479

    
480
        return 0;
481
}
482

    
483
int ChunkerPlayerCore_InitCodecs(char *v_codec, int width, int height, char *audio_codec, int sample_rate, short int audio_channels)
484
{
485
        char audio_stats[255], video_stats[255];
486

    
487
        // Register all formats and codecs
488
        av_log_set_level(AV_LOG_WARNING);
489
        avcodec_init();
490
        av_register_all();
491

    
492
        if (ChunkerPlayerCore_InitAudioCodecs(audio_codec, sample_rate, audio_channels) < 0) {
493
                printf("[ERROR] Could not initilize audio codecs");
494
                //return -1;
495
        }
496

    
497
        if (ChunkerPlayerCore_InitVideoCodecs(v_codec, width, height) < 0) {
498
                printf("[ERROR] Could not initilize video codecs");
499
                //return -1;
500
        }
501

    
502
        av_log_set_level(AV_LOG_ERROR);
503

    
504
        sprintf(audio_stats, "waiting for incoming audio packets...");
505
        sprintf(video_stats, "waiting for incoming video packets...");
506
        ChunkerPlayerGUI_SetStatsText(audio_stats, video_stats,qoe_led ? LED_GREEN : LED_NONE);
507
}
508

    
509
int DecodeEnqueuedAudio(AVPacket *pkt, PacketQueue *q, int* size)
510
{
511
        uint16_t *audio_bufQ = NULL;
512
        int16_t *dataQ = NULL;
513
        int data_sizeQ = AVCODEC_MAX_AUDIO_FRAME_SIZE;
514
        int lenQ;
515
        int ret = 0;
516

    
517
        //set the flag to decoded anyway        
518
        pkt->convergence_duration = -1;
519

    
520
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
521
        if(audio_bufQ) {
522
#ifdef DEBUG_AUDIO_BUFFER
523
                fprintf(stderr,"AUDIO_BUFFER: about to decode packet %d, size %d, data %d\n", pkt->stream_index, pkt->size, pkt->data);
524
#endif
525
                //decode the packet data
526
                lenQ = avcodec_decode_audio3(aCodecCtx, (int16_t *)audio_bufQ, &data_sizeQ, pkt);
527
                if(lenQ > 0) {
528
                        dataQ = (int16_t *)av_malloc(data_sizeQ); //this will be free later at the time of playback
529
                        if(dataQ) {
530
                                memcpy(dataQ, audio_bufQ, data_sizeQ);
531
                                if(pkt->data != NULL)
532
                                {
533
                                        //discard the old encoded bytes
534
                                        av_free(pkt->data);
535
                                }
536
                                //subtract them from queue size
537
                                q->size -= pkt->size;
538
                                *size = pkt->size;
539
                                pkt->data = (uint8_t *)dataQ;
540
                                pkt->size = data_sizeQ;
541
                                //add new size to queue size
542
                                q->size += pkt->size;
543
                                ret = 1;
544
                        }
545
                        else {
546
#ifdef DEBUG_AUDIO_BUFFER
547
                                fprintf(stderr,"AUDIO_BUFFER: cannot alloc space for decoded packet %d\n", pkt->stream_index);
548
#endif
549
                        }
550
                }
551
                else {
552
#ifdef DEBUG_AUDIO_BUFFER
553
                        fprintf(stderr,"AUDIO_BUFFER: cannot decode packet %d\n", pkt->stream_index);
554
#endif
555
                }
556
                av_free(audio_bufQ);
557
        }
558
        else {
559
#ifdef DEBUG_AUDIO_BUFFER
560
                fprintf(stderr,"AUDIO_BUFFER: cannot alloc decode buffer for packet %d\n", pkt->stream_index);
561
#endif
562
        }
563
        return ret; //problems occurred
564
}
565

    
566
/**
567
 * removes a packet from the list and returns the next
568
 * */
569
AVPacketList *RemoveFromQueue(PacketQueue *q, AVPacketList *p)
570
{
571
        AVPacketList *p1;
572

    
573
        if (q->first_pkt == p) {
574
                q->first_pkt = p->next;
575
        }
576
        if (&(p->pkt) == q->minpts_pkt) {
577
                q->minpts_pkt = NULL;
578
        }
579

    
580
        AVPacketList *retpk = p->next;
581
        q->nb_packets--;
582
        //adjust size here and not in the various cases of the dequeue
583
        q->size -= p->pkt.size;
584
        if(&p->pkt)
585
        {
586
                av_free_packet(&p->pkt);
587
        }
588
        if(p) {
589
                av_free(p);
590
        }
591

    
592
        //updating min info
593
        for (p1 = q->first_pkt; p1; p1 = p1->next) {
594
                if (!q->minpts_pkt || p1->pkt.pts < q->minpts_pkt->pts) {
595
                        q->minpts_pkt = &(p1->pkt);
596
                }
597
        }
598

    
599
        return retpk;
600
}
601

    
602
AVPacketList *SeekAndDecodePacketStartingFrom(AVPacketList *p, PacketQueue *q, int* size)
603
{
604
        while(p) {
605
                        //check if audio packet has been already decoded
606
                        if(p->pkt.convergence_duration == 0) {
607
                                //not decoded yet, try to decode it
608
                                if( !DecodeEnqueuedAudio(&(p->pkt), q, size) ) {
609
                                        //it was not possible to decode this packet, return next one
610
                                        p = RemoveFromQueue(q, p);
611
                                }
612
                                else
613
                                        return p;
614
                        }
615
                        else
616
                                return p;
617
        }
618
        return NULL;
619
}
620

    
621
int PacketQueueGet(PacketQueue *q, AVPacket *pkt, short int av, int* size)
622
{
623
        //AVPacket tmp;
624
        AVPacketList *pkt1 = NULL;
625
        int ret=-1;
626
        int SizeToCopy=0;
627
        int reqsize;
628

    
629
        SDL_LockMutex(q->mutex);
630

    
631
#ifdef DEBUG_QUEUE
632
        fprintf(stderr,"QUEUE: Get NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
633
#endif
634

    
635
        if((q->queueType==AUDIO && QueueFillingMode) || QueueStopped)
636
        {
637
                SDL_UnlockMutex(q->mutex);
638
                return -1;
639
        }
640

    
641
        if(av==1) { //somebody requested an audio packet, q is the audio queue
642
                reqsize = dimAudioQ; //TODO pass this as parameter, not garanteed by SDL to be exactly dimAudioQ
643
                pkt->size = 0;
644
                pkt->dts = 0;
645
                pkt->pts = 0;
646
                //try to dequeue the first packet of the audio queue
647
                pkt1 = q->first_pkt;
648
                while (pkt->size < reqsize && pkt1 && SeekAndDecodePacketStartingFrom(pkt1, q, size)) {
649
                        AVPacketList *next = pkt1->next;        //save it here since we could delete pkt1 later
650
                        if (!pkt->dts) pkt->dts = pkt1->pkt.dts;
651
                        if (!pkt->pts) pkt->pts = pkt1->pkt.pts;
652
                        pkt->stream_index = pkt1->pkt.stream_index;
653
                        pkt->flags = 1;
654
                        pkt->pos = -1;
655
                        pkt->convergence_duration = -1;
656
                        if (pkt1->pkt.size - AudioQueueOffset <= reqsize - pkt->size) { //we need the whole packet
657
                                SizeToCopy = pkt1->pkt.size - AudioQueueOffset;        //packet might be partial
658
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
659
                                pkt->size += SizeToCopy;
660
                                AudioQueueOffset = 0;
661
                                RemoveFromQueue(q, pkt1);
662
                        } else {
663
                                SizeToCopy = reqsize - pkt->size;        //partial packet remains
664
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
665
                                pkt->size += SizeToCopy;
666
                                AudioQueueOffset += SizeToCopy;
667
                                pkt1->pkt.dts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
668
                                pkt1->pkt.pts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
669
                        }
670

    
671
#ifdef DEBUG_AUDIO_BUFFER
672
                        fprintf(stderr,"2: idx %d    \taqo %d    \tstc %d    \taqe %f    \tpsz %d\n", pkt1->pkt.stream_index, AudioQueueOffset, SizeToCopy, deltaAudioQError, pkt1->pkt.size);
673
#endif
674

    
675
                        //update index of last frame extracted
676
                        //ChunkerPlayerStats_UpdateAudioLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
677
                        q->last_frame_extracted = pkt->stream_index;
678

    
679
                        pkt1 = next;
680
                }
681
                ret = 1; //TODO: check some conditions
682
        } else { //somebody requested a video packet, q is the video queue
683
                pkt1 = q->first_pkt;
684
                if(pkt1) {
685
#ifdef DEBUG_QUEUE_DEEP
686
                        fprintf(stderr,"  AV not 1\n");
687
#endif
688
                        pkt->size = pkt1->pkt.size;
689
                        pkt->dts = pkt1->pkt.dts;
690
                        pkt->pts = pkt1->pkt.pts;
691
                        pkt->stream_index = pkt1->pkt.stream_index;
692
                        pkt->flags = pkt1->pkt.flags;
693
                        pkt->pos = pkt1->pkt.pos;
694
                        pkt->convergence_duration = pkt1->pkt.convergence_duration;
695
                        //*pkt = pkt1->pkt;
696
                        
697
                        if((pkt->data != NULL) && (pkt1->pkt.data != NULL))
698
                                memcpy(pkt->data, pkt1->pkt.data, pkt1->pkt.size);
699
                                
700
                        //HINT SEE BEFORE q->size -= pkt1->pkt.size;
701
                        RemoveFromQueue(q, pkt1);
702

    
703
                        ret = 1;
704
                        
705
                        ChunkerPlayerStats_UpdateVideoLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
706
                        
707
                        //update index of last frame extracted
708
                        q->last_frame_extracted = pkt->stream_index;
709
                        last_video_frame_extracted = q->last_frame_extracted;
710
                }
711
#ifdef DEBUG_QUEUE
712
                else {
713
                        fprintf(stderr,"  VIDEO pk1 NULL!!!!\n");
714
                }
715
#endif
716
        }
717

    
718
        if(q->nb_packets==0 && q->queueType==AUDIO) {
719
                QueueFillingMode=1;
720
#ifdef DEBUG_QUEUE
721
                fprintf(stderr,"QUEUE: Get FillingMode ON\n");
722
#endif
723
        }
724
#ifdef DEBUG_QUEUE
725
        fprintf(stderr,"QUEUE: Get Last %s Frame Extracted = %d\n", (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
726
#endif
727

    
728
        SDL_UnlockMutex(q->mutex);
729
        return ret;
730
}
731

    
732
int AudioDecodeFrame(uint8_t *audio_buf, int buf_size) {
733
        //struct timeval now;
734
        int audio_pkt_size = 0;
735
        int compressed_size = 0;
736
        long long Now;
737
        short int DecodeAudio=0, SkipAudio=0;
738
        //int len1, data_size;
739

    
740
        //gettimeofday(&now,NULL);
741
        //Now = (now.tv_sec)*1000+now.tv_usec/1000;
742
        Now=(long long)SDL_GetTicks();
743

    
744
        if(QueueFillingMode || QueueStopped)
745
        {
746
                //SDL_LockMutex(timing_mutex);
747
                FirstTimeAudio=1;
748
                FirstTime = 1;
749
                //SDL_UnlockMutex(timing_mutex);
750
                return -1;
751
        }
752

    
753
        if((FirstTime==1 || FirstTimeAudio==1) && audioq.size>0) {
754
                if(audioq.first_pkt->pkt.pts>0)
755
                {
756
                        //SDL_LockMutex(timing_mutex);
757
                        DeltaTime=Now-(long long)(audioq.first_pkt->pkt.pts);
758
                        FirstTimeAudio = 0;
759
                        FirstTime = 0;
760
                        //SDL_UnlockMutex(timing_mutex);
761
#ifdef DEBUG_AUDIO 
762
                         fprintf(stderr,"AUDIO: audio_decode_frame - DeltaTimeAudio=%lld\n",DeltaTime);
763
#endif
764
                }
765
        }
766

    
767
#ifdef DEBUG_AUDIO 
768
        if(audioq.first_pkt)
769
        {
770
                fprintf(stderr,"AUDIO: audio_decode_frame - Syncro params: Delta:%lld Now:%lld pts=%lld pts+Delta=%lld ",(long long)DeltaTime,Now,(long long)audioq.first_pkt->pkt.pts,(long long)audioq.first_pkt->pkt.pts+DeltaTime);
771
                fprintf(stderr,"AUDIO: QueueLen=%d ",(int)audioq.nb_packets);
772
                fprintf(stderr,"AUDIO: QueueSize=%d\n",(int)audioq.size);
773
        }
774
        else
775
                fprintf(stderr,"AUDIO: audio_decode_frame - Empty queue\n");
776
#endif
777

    
778
        if(audioq.nb_packets>0)
779
        {
780
                if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //too late ... TODO: figure out the right number
781
                {
782
                        SkipAudio = 1;
783
                        DecodeAudio = 0;
784
                }
785
                else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
786
                        (double)audioq.first_pkt->pkt.pts+DeltaTime<=Now+deltaAudioQ+3*deltaAudioQ) {        //TODO: how much in future? On some systems, SDL asks for more buffers in a raw
787
                                SkipAudio = 0;
788
                                DecodeAudio = 1;
789
                }
790
        }
791
        
792
        while(SkipAudio==1 && audioq.size>0)
793
        {
794
                SkipAudio = 0;
795
#ifdef DEBUG_AUDIO
796
                 fprintf(stderr,"AUDIO: skipaudio: queue size=%d\n",audioq.size);
797
#endif
798
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
799
                        return -1;
800
                }
801
                if(audioq.first_pkt)
802
                {
803
                        ChunkerPlayerStats_UpdateAudioSkipHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
804
                        
805
                        if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //TODO: figure out the right number
806
                        {
807
                                SkipAudio = 1;
808
                                DecodeAudio = 0;
809
                        }
810
                        else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
811
                                (double)audioq.first_pkt->pkt.pts+DeltaTime<=Now+deltaAudioQ+3*deltaAudioQ) {        //TODO: how much in future?
812
                                        SkipAudio = 0;
813
                                        DecodeAudio = 1;
814
                        }
815
                }
816
        }
817
        if(DecodeAudio==1) {
818
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
819
                        return -1;
820
                }
821
#ifdef DEBUG_SYNC
822
                fprintf(stderr, "AUDIO delay =%lld ms\n",(long long)AudioPkt.pts+DeltaTime-Now);
823
#endif
824
                memcpy(audio_buf,AudioPkt.data,AudioPkt.size);
825
                audio_pkt_size = AudioPkt.size;
826
#ifdef DEBUG_AUDIO
827
                 fprintf(stderr,"AUDIO: Decode audio\n");
828
#endif
829

    
830
                ChunkerPlayerStats_UpdateAudioPlayedHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
831
        }
832

    
833
        return audio_pkt_size;
834
}
835

    
836

    
837
void ChunkerPlayerCore_SetYCrop(float yc){
838
        ycrop = yc;
839
}
840

    
841
// Render a Frame to a YUV Overlay. Note that the Overlay is already bound to an SDL Surface
842
// Note that width, height would not be needed in new ffmpeg versions where this info is contained in AVFrame
843
// see: [FFmpeg-devel] [PATCH] lavc: add width and height fields to AVFrame
844
int RenderFrame2Overlay(AVFrame *pFrame, int frame_width, int frame_height, int tcrop, int bcrop,  SDL_Overlay *YUVOverlay)
845
{
846
        AVPicture pict;
847
        static struct SwsContext *img_convert_ctx = NULL;        //if the function is used for more streams, this could be made part of some context passed as a parameter (to optimize performance)
848

    
849
                                        if(SDL_LockYUVOverlay(YUVOverlay) < 0) {
850
                                                return -1;
851
                                        }
852

    
853
                                        pict.data[0] = YUVOverlay->pixels[0];
854
                                        pict.data[1] = YUVOverlay->pixels[2];
855
                                        pict.data[2] = YUVOverlay->pixels[1];
856

    
857
                                        pict.linesize[0] = YUVOverlay->pitches[0];
858
                                        pict.linesize[1] = YUVOverlay->pitches[2];
859
                                        pict.linesize[2] = YUVOverlay->pitches[1];
860

    
861
                                        img_convert_ctx = sws_getCachedContext(img_convert_ctx, frame_width, frame_height - tcrop - bcrop, PIX_FMT_YUV420P, YUVOverlay->w, YUVOverlay->h, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
862
                                        if(img_convert_ctx == NULL) {
863
                                                fprintf(stderr, "Cannot initialize the conversion context!\n");
864
                                                exit(1);
865
                                        }
866

    
867
                                        // let's draw the data (*yuv[3]) on a SDL screen (*screen)
868
                                        sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, -tcrop, frame_height - bcrop, pict.data, pict.linesize);
869
                                        SDL_UnlockYUVOverlay(YUVOverlay);
870

    
871
        return 0;
872
}
873

    
874
// Render a YUV Overlay to the specified Rect of the Surface. Note that the Overlay is already bound to an SDL Surface.
875
int RenderOverlay2Rect(SDL_Overlay *YUVOverlay, SDL_Rect *Rect)
876
{
877

    
878
                                        // Lock SDL_yuv_overlay
879
                                        if(SDL_MUSTLOCK(MainScreen)) {
880
                                                if(SDL_LockSurface(MainScreen) < 0) {
881
                                                        return -1;
882
                                                }
883
                                        }
884

    
885
                                        // Show, baby, show!
886
                                        SDL_LockMutex(OverlayMutex);
887
                                        SDL_DisplayYUVOverlay(YUVOverlay, Rect);
888
                                        SDL_UnlockMutex(OverlayMutex);
889

    
890
                                        if(SDL_MUSTLOCK(MainScreen)) {
891
                                                SDL_UnlockSurface(MainScreen);
892
                                        }
893

    
894
        return 0;
895

    
896
}
897

    
898

    
899
int VideoCallback(void *valthread)
900
{
901
        //AVPacket pktvideo;
902
        AVCodecContext  *pCodecCtx;
903
        AVCodec         *pCodec;
904
        AVFrame         *pFrame;
905
        int frameFinished;
906
        long long Now;
907
        long long Last = 0;
908
        short int SkipVideo, DecodeVideo;
909
        uint64_t last_pts = 0;
910
        long long decode_delay = 0;
911
        int queue_size_checked = 0;
912
        
913
#ifdef SAVE_YUV
914
        static AVFrame* lastSavedFrameBuffer = NULL;
915
        
916
        if(!lastSavedFrameBuffer)
917
                lastSavedFrameBuffer = (AVFrame*) malloc(sizeof(AVFrame));
918
#endif
919

    
920
        //double frame_rate = 0.0,time_between_frames=0.0;
921
        //struct timeval now;
922

    
923
        //int wait_for_sync = 1;
924
        ThreadVal *tval;
925
        tval = (ThreadVal *)valthread;
926

    
927
        //frame_rate = tval->framerate;
928
        //time_between_frames = 1.e6 / frame_rate;
929
        //gettimeofday(&time_now,0);
930

    
931
        //frecon = fopen("recondechunk.mpg","wb");
932

    
933
        //setup video decoder
934
        pCodec = avcodec_find_decoder_by_name(tval->video_codec);
935
        if (pCodec) {
936
                fprintf(stderr, "INIT: Setting VIDEO codecID to: %d\n",pCodec->id);
937
        } else {
938
                fprintf(stderr, "INIT: Unknown VIDEO codec: %s!\n", tval->video_codec);
939
                return -1; // Codec not found
940
        }
941

    
942
        pCodecCtx=avcodec_alloc_context();
943
        pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
944
        //pCodecCtx->debug = FF_DEBUG_DCT_COEFF;
945
        pCodecCtx->codec_id = pCodec->id;
946

    
947
        //pCodecCtx->bit_rate = 400000;
948
        // resolution must be a multiple of two
949
        pCodecCtx->width = tval->width;//176;//352;
950
        pCodecCtx->height = tval->height;//144;//288;
951

    
952
        // frames per second
953
        //pCodecCtx->time_base = (AVRational){1,25};
954
        //pCodecCtx->gop_size = 10; // emit one intra frame every ten frames
955
        //pCodecCtx->max_b_frames=1;
956
        pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
957
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
958

    
959
        if(pCodec==NULL) {
960
                fprintf(stderr, "Unsupported codec!\n");
961
                return -1; // Codec not found
962
        }
963
        if(avcodec_open(pCodecCtx, pCodec) < 0) {
964
                fprintf(stderr, "could not open codec\n");
965
                return -1; // Could not open codec
966
        }
967
        pFrame=avcodec_alloc_frame();
968
        if(pFrame==NULL) {
969
                fprintf(stderr,"Memory error!!!\n");
970
                return -1;
971
        }
972
        
973
#ifdef DEBUG_VIDEO
974
         fprintf(stderr,"VIDEO: video_callback entering main cycle\n");
975
#endif
976

    
977
        while(AVPlaying && !quit) {
978

    
979
                if(QueueFillingMode || QueueStopped)
980
                {
981
                        //SDL_LockMutex(timing_mutex);
982
                        FirstTime = 1;
983
                        //SDL_UnlockMutex(timing_mutex);
984
                        usleep(5000);
985
                        continue;
986
                }
987

    
988
                DecodeVideo = 0;
989
                SkipVideo = 0;
990
                Now=(long long)SDL_GetTicks();
991
                if(FirstTime==1 && videoq.size>0) {
992
                        if(videoq.first_pkt->pkt.pts>0)
993
                        {
994
                                //SDL_LockMutex(timing_mutex);
995
                                DeltaTime=Now-(long long)videoq.first_pkt->pkt.pts;
996
                                FirstTime = 0;
997
                                FirstTimeAudio = 0;
998
                                //SDL_UnlockMutex(timing_mutex);
999
                        }
1000
#ifdef DEBUG_VIDEO 
1001
                         fprintf(stderr,"VIDEO: VideoCallback - DeltaTimeAudio=%lld\n",DeltaTime);
1002
#endif
1003
                }
1004

    
1005
#ifdef DEBUG_VIDEO 
1006
                if(videoq.first_pkt)
1007
                {
1008
                        fprintf(stderr,"VIDEO: VideoCallback - Syncro params: Delta:%lld Now:%lld pts=%lld pts+Delta=%lld ",(long long)DeltaTime,Now,(long long)videoq.first_pkt->pkt.pts,(long long)videoq.first_pkt->pkt.pts+DeltaTime);
1009
                        fprintf(stderr,"VIDEO: Index=%d ", (int)videoq.first_pkt->pkt.stream_index);
1010
                        fprintf(stderr,"VIDEO: QueueLen=%d ", (int)videoq.nb_packets);
1011
                        fprintf(stderr,"VIDEO: QueueSize=%d\n", (int)videoq.size);
1012
                }
1013
                else
1014
                        fprintf(stderr,"VIDEO: VideoCallback - Empty queue\n");
1015
#endif
1016

    
1017
#ifdef DEBUG_VIDEO
1018
                fprintf(stderr,"VIDEO: skipvideo:%d decodevideo:%d\n",SkipVideo,DecodeVideo);
1019
#endif
1020
//                        ChunkerPlayerStats_UpdateVideoSkipHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
1021

    
1022
                if(videoq.nb_packets>0) {
1023
                        if (!queue_size_checked && videoq.last_pkt->pkt.pts - videoq.first_pkt->pkt.pts < decode_delay) {        //queue too short
1024
#ifdef DEBUG_SYNC
1025
                                fprintf(stderr, "VIDEO queue too short,diff(%lld) < decode_delay(%lld), increasing delta from \n",videoq.last_pkt->pkt.pts - videoq.first_pkt->pkt.pts, decode_delay, DeltaTime);
1026
#endif
1027
                                DeltaTime += decode_delay - (videoq.last_pkt->pkt.pts - videoq.first_pkt->pkt.pts);
1028
                                queue_size_checked = 1;        //make sure we do not increase the delay several times bacause of the same frame
1029
                        }
1030
                        if (videoq.first_pkt->pkt.pts + DeltaTime - Now < decode_delay) {        //time to decode, should be based on DTS
1031
                            if (PacketQueueGet(&videoq,&VideoPkt,0, NULL) > 0) {
1032
                                queue_size_checked = 0;
1033
                                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
1034
#ifdef DEBUG_SYNC
1035
                                fprintf(stderr, "VIDEO delta =%lld ms; dt=%lld \n",(long long) pFrame->pkt_pts - last_pts, Now - Last);
1036
#endif
1037
                                last_pts = pFrame->pkt_pts;
1038
                                if (pFrame->pkt_pts) decode_delay = MAX(decode_delay, VideoPkt.pts - pFrame->pkt_pts);        //TODO: base this on dts
1039
                                decode_delay = MIN(decode_delay, 40 * 5);        //TODO, this workaround would not be needed if decode_delay would be based on DTS
1040
#ifdef DEBUG_SYNC
1041
                                fprintf(stderr, "VIDEO t=%lld ms ptsin=%lld ptsout=%lld \n",Now, (long long)VideoPkt.pts+DeltaTime, pFrame->pkt_pts+DeltaTime);
1042
                                fprintf(stderr, "VIDEO delay =%lld ms ; %lld ms \n",(long long)VideoPkt.pts+DeltaTime-Now, pFrame->pkt_pts+DeltaTime-Now);
1043
#endif
1044

    
1045
                                if(frameFinished)
1046
                                { // it must be true all the time else error
1047

    
1048
                                        long long target_pts = pFrame->pkt_pts + DeltaTime;
1049
                                        long long earlier = target_pts - Now;
1050
                                        int halfcrop;
1051

    
1052
#ifdef DEBUG_VIDEO
1053
                                        fprintf(stderr,"VIDEO: FrameFinished\n");
1054
#endif
1055
                                        decoded_vframes++;
1056
                                        
1057

    
1058
#ifdef VIDEO_DEINTERLACE
1059
                                        avpicture_deinterlace(
1060
                                                (AVPicture*) pFrame,
1061
                                                (const AVPicture*) pFrame,
1062
                                                pCodecCtx->pix_fmt,
1063
                                                tval->width, tval->height);
1064
#endif
1065

    
1066
#ifdef SAVE_YUV
1067
                                        if(LastSavedVFrame == -1)
1068
                                        {
1069
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
1070
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
1071
                                                LastSavedVFrame = VideoPkt.stream_index;
1072
                                        }
1073
                                        else if(LastSavedVFrame == (VideoPkt.stream_index-1))
1074
                                        {
1075
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
1076
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
1077
                                                LastSavedVFrame = VideoPkt.stream_index;
1078
                                        }
1079
                                        else if(LastSavedVFrame >= 0)
1080
                                        {
1081
                                                while(LastSavedVFrame < (VideoPkt.stream_index-1))
1082
                                                {
1083
                                                        SaveFrame(lastSavedFrameBuffer, pCodecCtx->width, pCodecCtx->height);
1084
                                                }
1085

    
1086
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
1087
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
1088
                                                LastSavedVFrame = VideoPkt.stream_index;
1089
                                        }
1090
#endif
1091
                                        ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
1092

    
1093
                                        if(SilentMode)
1094
                                                continue;
1095

    
1096
                                        SDL_LockMutex(OverlayMutex);
1097
                                        halfcrop = ycrop * pCodecCtx->height /2;
1098
                                        if (RenderFrame2Overlay(pFrame, pCodecCtx->width, pCodecCtx->height, halfcrop, halfcrop, YUVOverlay) < 0){
1099
                                                SDL_UnlockMutex(OverlayMutex);
1100
                                                continue;
1101
                                        }
1102

    
1103
                                        //wait for the playback time
1104
#ifdef DEBUG_SYNC
1105
                                        fprintf(stderr, "VIDEO earlier =%lld ms\n",earlier);
1106
#endif
1107
                                        if (earlier > 0) {
1108
                                                usleep(MIN(earlier,1000) * 1000);
1109
//                                        } else if (earlier < 0) {
1110
//                                                fprintf(stderr, "should increase delay2 : pFrame->pkt_pts=%lld, DeltaTime=%lld, Now=%lld, earlier=%lld\n", pFrame->pkt_pts, DeltaTime, Now, earlier);
1111
//                                                DeltaTime -= earlier;
1112
                                        }
1113

    
1114
                                        Last = Now;
1115

    
1116
                                        if (RenderOverlay2Rect(YUVOverlay, ChunkerPlayerGUI_GetMainOverlayRect()) < 0) {
1117
                                                SDL_UnlockMutex(OverlayMutex);
1118
                                                continue;
1119
                                        }
1120
                                        SDL_UnlockMutex(OverlayMutex);
1121

    
1122
                                        //redisplay logo
1123
                                        /**SDL_BlitSurface(image, NULL, MainScreen, &dest);*/
1124
                                        /* Update the screen area just changed */
1125
                                        /**SDL_UpdateRects(MainScreen, 1, &dest);*/
1126
                                } //if FrameFinished
1127
                                else
1128
                                {
1129
                                        ChunkerPlayerStats_UpdateVideoLossHistory(&(videoq.PacketHistory), VideoPkt.stream_index+1, videoq.last_frame_extracted-1);
1130
                                }
1131
                            }
1132
                        }
1133
                        usleep(5000);
1134
                }
1135
                usleep(5000);
1136
        }
1137
        avcodec_close(pCodecCtx);
1138
        av_free(pCodecCtx);
1139
        av_free(pFrame);
1140
        //fclose(frecon);
1141
#ifdef DEBUG_VIDEO
1142
         fprintf(stderr,"VIDEO: video callback end\n");
1143
#endif
1144

    
1145
#ifdef SAVE_YUV
1146
        if(!lastSavedFrameBuffer)
1147
                free(lastSavedFrameBuffer);
1148
        
1149
        lastSavedFrameBuffer = NULL;
1150
#endif
1151

    
1152
        return 0;
1153
}
1154

    
1155
void AudioCallback(void *userdata, Uint8 *stream, int len)
1156
{
1157
        //AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
1158
        int audio_size;
1159

    
1160
        static uint8_t audio_buf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
1161

    
1162
        memset(audio_buf, CurrentAudioSilence, sizeof(audio_buf));
1163
        audio_size = AudioDecodeFrame(audio_buf, sizeof(audio_buf));
1164
        
1165
        if(SilentMode < 2) {
1166
                if(audio_size != len) {
1167
                        memset(stream, CurrentAudioSilence, len);
1168
                } else {
1169
                        memcpy(stream, (uint8_t *)audio_buf, len);
1170
                }
1171
        }
1172
}
1173

    
1174
void SaveFrame(AVFrame *pFrame, int width, int height)
1175
{
1176
        FILE *pFile;
1177
        int  y;
1178
  
1179
         // Open file
1180
        pFile=fopen(YUVFileName, "ab");
1181
        if(pFile==NULL)
1182
                return;
1183
  
1184
        // Write header
1185
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1186
  
1187
        // Write Y data
1188
        for(y=0; y<height; y++)
1189
                  fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile);
1190
        // Write U data
1191
        for(y=0; y<height/2; y++)
1192
                  fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile);
1193
        // Write V data
1194
        for(y=0; y<height/2; y++)
1195
                  fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile);
1196
  
1197
        // Close file
1198
        fclose(pFile);
1199
}
1200

    
1201
int ChunkerPlayerCore_IsRunning()
1202
{
1203
        return AVPlaying;
1204
}
1205

    
1206
void ChunkerPlayerCore_Play()
1207
{
1208
        if(AVPlaying) return;
1209
        AVPlaying = 1;
1210
        
1211
        SDL_PauseAudio(0);
1212
        video_thread = SDL_CreateThread(VideoCallback, &VideoCallbackThreadParams);
1213
        ChunkerPlayerStats_Init(&VideoCallbackThreadParams);
1214
        stats_thread = SDL_CreateThread(CollectStatisticsThread, NULL);
1215
        
1216
        decoded_vframes = 0;
1217
        LastSavedVFrame = -1;
1218
}
1219

    
1220
void ChunkerPlayerCore_Stop()
1221
{
1222
        if(!AVPlaying) return;
1223
        
1224
        AVPlaying = 0;
1225
        
1226
        // Stop audio&video playback
1227
        SDL_WaitThread(video_thread, NULL);
1228
        SDL_WaitThread(stats_thread, NULL);
1229
        SDL_PauseAudio(1);        
1230
        
1231
        if(YUVOverlay != NULL)
1232
        {
1233
                SDL_FreeYUVOverlay(YUVOverlay);
1234
                YUVOverlay = NULL;
1235
        }
1236
        
1237
        PacketQueueReset(&audioq);
1238
        PacketQueueReset(&videoq);
1239
        
1240
        avcodec_close(aCodecCtx);
1241
        av_free(aCodecCtx);
1242
        free(AudioPkt.data);
1243
        free(VideoPkt.data);
1244
        free(outbuf_audio);
1245
        
1246
        /*
1247
        * Sleep two buffers' worth of audio before closing, in order
1248
        *  to allow the playback to finish. This isn't always enough;
1249
        *   perhaps SDL needs a way to explicitly wait for device drain?
1250
        * Doesn't seem to be necessary -> disabled
1251
        */
1252
        //int delay = 2 * 1000 * CurrentAudioSamples / CurrentAudioFreq;
1253
        // fprintf(stderr,"SDL_Delay(%d)\n", delay*10);
1254
        //SDL_Delay(delay*10);
1255
}
1256

    
1257
void ChunkerPlayerCore_Finalize()
1258
{
1259
        if(YUVOverlay != NULL)
1260
        {
1261
                SDL_FreeYUVOverlay(YUVOverlay);
1262
                YUVOverlay = NULL;
1263
        }
1264

    
1265
        SDL_CloseAudio();
1266
}
1267

    
1268
void ChunkerPlayerCore_Pause()
1269
{
1270
        if(!AVPlaying) return;
1271
        
1272
        AVPlaying = 0;
1273
        
1274
        // Stop audio&video playback
1275
        SDL_WaitThread(video_thread, NULL);
1276
        SDL_PauseAudio(1);
1277
        
1278
        PacketQueueReset(&audioq);
1279
        PacketQueueReset(&videoq);
1280
}
1281

    
1282
int ChunkerPlayerCore_AudioEnded()
1283
{
1284
        return (audioq.nb_packets==0 && audioq.last_frame_extracted>0);
1285
}
1286

    
1287
void ChunkerPlayerCore_ResetAVQueues()
1288
{
1289
#ifdef DEBUG_QUEUE
1290
        fprintf(stderr,"QUEUE: MAIN SHOULD RESET\n");
1291
#endif
1292
        PacketQueueReset(&audioq);
1293
        PacketQueueReset(&videoq);
1294
}
1295

    
1296
int ChunkerPlayerCore_EnqueueBlocks(const uint8_t *block, const int block_size)
1297
{
1298
#ifdef EMULATE_CHUNK_LOSS
1299
        static time_t loss_cycle_start_time = 0, now = 0;
1300
        static int early_losses = 0;
1301
        static int clp_frames = 0;
1302
        
1303
        if(ScheduledChunkLosses)
1304
        {
1305
                static unsigned int random_threshold;
1306
                now=time(NULL);
1307
                if(!loss_cycle_start_time)
1308
                        loss_cycle_start_time = now;
1309
                        
1310
                if(((now-loss_cycle_start_time) >= ScheduledChunkLosses[((CurrChunkLossIndex+1)%NScheduledChunkLosses)].Time) && (NScheduledChunkLosses>1 || CurrChunkLossIndex==-1))
1311
                {
1312
                        CurrChunkLossIndex = ((CurrChunkLossIndex+1)%NScheduledChunkLosses);
1313
                        if(CurrChunkLossIndex == (NScheduledChunkLosses-1))
1314
                                loss_cycle_start_time = now;
1315
                        
1316
                        if(ScheduledChunkLosses[CurrChunkLossIndex].Value == -1)
1317
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].MinValue + (rand() % (ScheduledChunkLosses[CurrChunkLossIndex].MaxValue-ScheduledChunkLosses[CurrChunkLossIndex].MinValue));
1318
                        else
1319
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].Value;
1320
                        
1321
                        fprintf(stderr,"new ScheduledChunkLoss, time: %d, value: %d\n", (int)ScheduledChunkLosses[CurrChunkLossIndex].Time, random_threshold);
1322
                }
1323
        
1324
                if(clp_frames > 0)
1325
                {
1326
                        clp_frames--;
1327
                        return PLAYER_FAIL_RETURN;
1328
                }
1329
                if((rand() % 100) < random_threshold)
1330
                {
1331
                        if(early_losses > 0)
1332
                early_losses--;
1333
            else
1334
            {
1335
                clp_frames=early_losses=(ScheduledChunkLosses[CurrChunkLossIndex].Burstiness-1);
1336
                return PLAYER_FAIL_RETURN;
1337
            }
1338
                }
1339
        }
1340
#endif
1341

    
1342
        Chunk *gchunk = NULL;
1343
        int decoded_size = -1;
1344
        uint8_t *tempdata, *buffer;
1345
        int j;
1346
        Frame *frame = NULL;
1347
        AVPacket packet, packetaudio;
1348

    
1349
        uint16_t *audio_bufQ = NULL;
1350

    
1351
        //the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
1352
        static int sizeFrameHeader = 5*sizeof(int32_t);
1353
        //the following we dont need anymore
1354
        //static int ExternalChunk_header_size = 5*CHUNK_TRANSCODING_INT_SIZE + 2*CHUNK_TRANSCODING_INT_SIZE + 2*CHUNK_TRANSCODING_INT_SIZE + 1*CHUNK_TRANSCODING_INT_SIZE*2;
1355

    
1356
        static int chunks_out_of_order = 0;
1357
        static int last_chunk_id = -1;
1358

    
1359
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
1360
        if(!audio_bufQ) {
1361
                fprintf(stderr,"Memory error in audio_bufQ!\n");
1362
                return PLAYER_FAIL_RETURN;
1363
        }
1364

    
1365
        gchunk = (Chunk *)malloc(sizeof(Chunk));
1366
        if(!gchunk) {
1367
                fprintf(stderr,"Memory error in gchunk!\n");
1368
                av_free(audio_bufQ);
1369
                return PLAYER_FAIL_RETURN;
1370
        }
1371

    
1372
        decoded_size = decodeChunk(gchunk, block, block_size);
1373

    
1374
        if(last_chunk_id == -1)
1375
                last_chunk_id = gchunk->id;
1376

    
1377
        if(gchunk->id > (last_chunk_id+1)) {
1378
                chunks_out_of_order += gchunk->id - last_chunk_id - 1;
1379
        }
1380
        last_chunk_id = gchunk->id;
1381

    
1382
#ifdef DEBUG_CHUNKER
1383
        fprintf(stderr,"CHUNKER: enqueueBlock: id %d decoded_size %d target size %d - out_of_order %d\n", gchunk->id, decoded_size, GRAPES_ENCODED_CHUNK_HEADER_SIZE + gchunk->size, chunks_out_of_order);
1384
#endif
1385
  if(decoded_size < 0) {
1386
                //HINT here i should differentiate between various return values of the decode
1387
                //in order to free what has been allocated there
1388
                fprintf(stderr,"chunk probably corrupted!\n");
1389
                av_free(audio_bufQ);
1390
                free(gchunk);
1391
                return PLAYER_FAIL_RETURN;
1392
        }
1393

    
1394
        frame = (Frame *)malloc(sizeof(Frame));
1395
        if(!frame) {
1396
                fprintf(stderr,"Memory error in Frame!\n");
1397
                if(gchunk) {
1398
                        if(gchunk->attributes) {
1399
                                free(gchunk->attributes);
1400
                        }
1401
                        free(gchunk);
1402
                }
1403
                av_free(audio_bufQ);
1404
                return PLAYER_FAIL_RETURN;
1405
        }
1406

    
1407
        tempdata = gchunk->data; //let it point to first frame of payload
1408
        j=gchunk->size;
1409
        while(j>0 && !quit) {
1410
                frame->number = bit32_encoded_pull(tempdata);
1411
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1412
                frame->timestamp.tv_sec = bit32_encoded_pull(tempdata);
1413
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1414
                frame->timestamp.tv_usec = bit32_encoded_pull(tempdata);
1415
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1416
                frame->size = bit32_encoded_pull(tempdata);
1417
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1418
                frame->type = bit32_encoded_pull(tempdata);
1419
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1420

    
1421
                buffer = tempdata; // here coded frame information
1422
                tempdata += frame->size; //let it point to the next frame
1423

    
1424
                if(frame->type < 5) { // video frame
1425
                        av_init_packet(&packet);
1426
                        packet.data = buffer;//video_bufQ;
1427
                        packet.size = frame->size;
1428
                        packet.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1429
                        packet.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1430
                        packet.stream_index = frame->number; // use of stream_index for number frame
1431
                        //packet.duration = frame->timestamp.tv_sec;
1432
                        if(packet.size > 0) {
1433
                                int ret = ChunkerPlayerCore_PacketQueuePut(&videoq, &packet); //the _put makes a copy of the packet
1434
                                if (ret == 1) {        //TODO: check and correct return values
1435
                                        fprintf(stderr, "late chunk received, increasing delay to %lld\n", DeltaTime);
1436
                                        DeltaTime += 5;        //TODO: handle audio skip; verify this value
1437
                                }
1438
                        }
1439

    
1440
#ifdef DEBUG_SOURCE
1441
                        fprintf(stderr,"SOURCE: Insert video in queue pts=%lld %d %d sindex:%d\n",packet.pts,(int)frame->timestamp.tv_sec,(int)frame->timestamp.tv_usec,packet.stream_index);
1442
#endif
1443
                }
1444
                else if(frame->type == 5) { // audio frame
1445
                        av_init_packet(&packetaudio);
1446
                        packetaudio.data = buffer;
1447
                        packetaudio.size = frame->size;
1448
                        packetaudio.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1449
                        packetaudio.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1450
                        //packetaudio.duration = frame->timestamp.tv_sec;
1451
                        packetaudio.stream_index = frame->number; // use of stream_index for number frame
1452
                        packetaudio.flags = 1;
1453
                        packetaudio.pos = -1;
1454

    
1455
                        //instead of -1, in order to signal it is not decoded yet
1456
                        packetaudio.convergence_duration = 0;
1457

    
1458
                        // insert the audio frame into the queue
1459
                        if(packetaudio.size > 0) {
1460
                                int ret = ChunkerPlayerCore_PacketQueuePut(&audioq, &packetaudio);//makes a copy of the packet so i can free here
1461
                                if (ret == 1) {        //TODO: check and correct return values
1462
                                        fprintf(stderr, "late chunk received, increasing delay to %lld\n", DeltaTime);
1463
                                        DeltaTime += 5;        //TODO: handle audio skip; verify this value
1464
                                }
1465
                        }
1466

    
1467
#ifdef DEBUG_SOURCE
1468
                        fprintf(stderr,"SOURCE: Insert audio in queue pts=%lld sindex:%d\n", packetaudio.pts, packetaudio.stream_index);
1469
#endif
1470
                }
1471
                else {
1472
                        fprintf(stderr,"SOURCE: Unknown frame type %d. Size %d\n", frame->type, frame->size);
1473
                }
1474
                if(frame->size > 0)
1475
                        j = j - sizeFrameHeader - frame->size;
1476
                else {
1477
                        fprintf(stderr,"SOURCE: Corrupt frames (size %d) in chunk. Skipping it...\n", frame->size);
1478
                        j = -1;
1479
                }
1480
        }
1481
        //chunk ingestion terminated!
1482
        if(gchunk) {
1483
                if(gchunk->attributes) {
1484
                        free(gchunk->attributes);
1485
                }
1486
                if(gchunk->data)
1487
                        free(gchunk->data);
1488
                free(gchunk);
1489
        }
1490
        if(frame)
1491
                free(frame);
1492
        if(audio_bufQ)
1493
                av_free(audio_bufQ);
1494
                
1495
        return PLAYER_OK_RETURN;
1496
}
1497

    
1498
void ChunkerPlayerCore_SetupOverlay(int width, int height)
1499
{
1500
        // if(!MainScreen && !SilentMode)
1501
        // {
1502
                // fprintf(stderr,"Cannot find main screen, exiting...\n");
1503
                // exit(1);
1504
        // }
1505
        
1506
        if(SilentMode)
1507
                return;
1508

    
1509
        //TODO: return with error if size is too small
1510
        width = MAX(width, 8);
1511
        height = MAX(height, 8);
1512

    
1513
        SDL_LockMutex(OverlayMutex);
1514
        if(YUVOverlay != NULL)
1515
        {
1516
                SDL_FreeYUVOverlay(YUVOverlay);
1517
                YUVOverlay = NULL;
1518
        }
1519
        
1520
        // create video overlay for display of video frames
1521
        // fprintf(stderr,"SDL_CreateYUVOverlay(%d, %d, SDL_YV12_OVERLAY, MainScreen)\n", width, height);
1522
        YUVOverlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, MainScreen);
1523
        if ( YUVOverlay == NULL )
1524
        {
1525
                fprintf(stderr,"SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError());
1526
                exit(1);
1527
        }
1528

    
1529
        if ( YUVOverlay->hw_overlay )
1530
                fprintf(stderr,"SDL: Using hardware overlay.\n");
1531
        
1532
        SDL_DisplayYUVOverlay(YUVOverlay, ChunkerPlayerGUI_GetMainOverlayRect());
1533
        
1534
        SDL_UnlockMutex(OverlayMutex);
1535
}
1536

    
1537
int CollectStatisticsThread(void *params)
1538
{
1539
        struct timeval last_stats_evaluation, now, last_trace, last_qoe_evaluation;
1540
        gettimeofday(&last_stats_evaluation, NULL);
1541
        last_trace = last_stats_evaluation;
1542
        last_qoe_evaluation = last_stats_evaluation;
1543
        
1544
        double video_qdensity;
1545
        double audio_qdensity;
1546
        char audio_stats_text[255];
1547
        char video_stats_text[255];
1548
        SStats audio_statistics, video_statistics;
1549
        double qoe = 0;
1550
        int sleep_time = STATS_THREAD_GRANULARITY*1000;
1551
        int audio_avg_bitrate = 0;
1552
        int video_avg_bitrate = 0;
1553
        
1554
        while(AVPlaying && !quit)
1555
        {
1556
                usleep(sleep_time);
1557
                
1558
                gettimeofday(&now, NULL);
1559
                
1560
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_stats_evaluation.tv_sec*1000)+(last_stats_evaluation.tv_usec/1000))) > GUI_PRINTSTATS_INTERVAL)
1561
                {
1562
                        // estimate audio queue stats
1563
                        int audio_stats_changed = ChunkerPlayerStats_GetStats(&(audioq.PacketHistory), &audio_statistics);
1564
                        
1565
                        // estimate video queue stats
1566
                        int video_stats_changed = ChunkerPlayerStats_GetStats(&(videoq.PacketHistory), &video_statistics);
1567

    
1568
                        // compute avg bitrate up to now
1569
                        audioq.cumulative_bitrate += audio_statistics.Bitrate;
1570
                        audioq.cumulative_samples++;
1571
                        audio_avg_bitrate = (int)( ((double)audioq.cumulative_bitrate) / ((double)audioq.cumulative_samples) );
1572
                        videoq.cumulative_bitrate += video_statistics.Bitrate;
1573
                        videoq.cumulative_samples++;
1574
                        video_avg_bitrate = (int)( ((double)videoq.cumulative_bitrate) / ((double)videoq.cumulative_samples) );
1575

    
1576
#ifdef DEBUG_STATS
1577
                        fprintf(stderr,"VIDEO: %d Kbit/sec; ", video_statistics.Bitrate);
1578
                        fprintf(stderr,"AUDIO: %d Kbit/sec\n", audio_statistics.Bitrate);
1579
#endif
1580

    
1581
                        // QUEUE DENSITY EVALUATION
1582
                        if((audioq.last_pkt != NULL) && (audioq.first_pkt != NULL))
1583
                                if(audioq.last_pkt->pkt.stream_index >= audioq.first_pkt->pkt.stream_index)
1584
                                {
1585
                                        //plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1586
                                        audio_qdensity = (double)audioq.nb_packets / (double)(audioq.last_pkt->pkt.stream_index - audioq.first_pkt->pkt.stream_index + 1) * 100.0;
1587
                                }
1588
                        
1589
                        if((videoq.last_pkt != NULL) && (videoq.first_pkt != NULL))
1590
                                if(videoq.last_pkt->pkt.stream_index >= videoq.first_pkt->pkt.stream_index)
1591
                                {
1592
                                        // plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1593
                                        video_qdensity = (double)videoq.nb_packets / (double)(videoq.last_pkt->pkt.stream_index - videoq.first_pkt->pkt.stream_index + 1) * 100.0;
1594
                                }
1595
                        
1596
                        if(LogTraces)
1597
                        {
1598
                                ChunkerPlayerStats_PrintHistoryTrace(&(audioq.PacketHistory), AudioTraceFilename);
1599
                                ChunkerPlayerStats_PrintHistoryTrace(&(videoq.PacketHistory), VideoTraceFilename);
1600
                                
1601
                                //if(SilentMode != 1 && SilentMode != 2)
1602
                                        ChunkerPlayerStats_PrintContextFile();
1603
                        }
1604

    
1605
                        // PRINT STATISTICS ON GUI
1606
                        if(!Audio_ON)
1607
                                sprintf(audio_stats_text, "AUDIO MUTED");
1608
                        else if(audio_stats_changed)
1609
//                                sprintf(audio_stats_text, "[AUDIO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)", (int)audioq.nb_packets, (int)audio_qdensity, (int)audio_statistics.Lossrate, audioq.PacketHistory.LostCount, audio_statistics.Skiprate, audioq.PacketHistory.SkipCount);
1610
                                sprintf(audio_stats_text, "[AUDIO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - rate: %d kbits/sec (avg: %d)", (int)audioq.nb_packets, (int)audio_qdensity, (int)audio_statistics.Lossrate, audioq.PacketHistory.LostCount, audio_statistics.Bitrate, audio_avg_bitrate);
1611
                        else
1612
                                sprintf(audio_stats_text, "waiting for incoming audio packets...");
1613

    
1614
                        if(video_stats_changed)
1615
                        {
1616
                                char est_psnr_string[255];
1617
                                sprintf(est_psnr_string, ".");
1618
                                if(qoe)
1619
                                {
1620
                                        sprintf(est_psnr_string, " - Est. Mean PSNR: %.1f db", (float)qoe);
1621
#ifdef PSNR_PUBLICATION
1622
                                        // Publish measure into repository
1623
                                        if(RepoAddress[0]!='\0')
1624
                                        {
1625
                                            MeasurementRecord r;
1626
                            r.originator = NetworkID;
1627
                            r.targetA = NetworkID;
1628
                            r.targetB = NULL;
1629
                            r.published_name = "PSNR_MEAN";
1630
                            r.value = qoe;
1631
                            r.string_value = NULL;
1632
                            r.channel = Channels[SelectedChannel].Title;
1633
                            gettimeofday(&(r.timestamp), NULL);
1634
                            // One update every REPO_UPDATE_INTERVALL seconds
1635
                            struct timeval ElapsedTime;
1636
                            timeval_subtract(&(r.timestamp),&LastTimeRepoPublish,&ElapsedTime);
1637
                        if(ElapsedTime.tv_sec>=PSNR_REPO_UPDATE_INTERVALL)
1638
                        {
1639
                            LastTimeRepoPublish=r.timestamp;
1640
                            if(repPublish(repoclient,NULL,NULL,&r)!=NULL) {
1641
#ifdef DEBUG_PSNR
1642
                               fprintf(stderr,"PSNR publish: %s  %e  %s\n",r.originator,qoe,r.channel);
1643
#endif
1644
                                                                                                                }
1645
                        }
1646
                   }
1647
#endif
1648
                                }
1649

    
1650
//                                sprintf(video_stats_text, "[VIDEO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)%s", (int)videoq.nb_packets, (int)video_qdensity, video_statistics.Lossrate, videoq.PacketHistory.LostCount, video_statistics.Skiprate, videoq.PacketHistory.SkipCount, est_psnr_string);
1651
                                sprintf(video_stats_text, "[VIDEO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - rate: %d kbits/sec (avg: %d) %s", (int)videoq.nb_packets, (int)video_qdensity, video_statistics.Lossrate, videoq.PacketHistory.LostCount, video_statistics.Bitrate, video_avg_bitrate, est_psnr_string);
1652
                        }
1653
                        else
1654
                                sprintf(video_stats_text, "waiting for incoming video packets...");
1655
                        
1656
                        if(qoe && qoe_led) {
1657
                            ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text,(qoe>LED_THRS_YELLOW?LED_GREEN:((qoe<=LED_THRS_YELLOW && qoe>LED_THRS_RED)?LED_YELLOW:LED_RED)));
1658
                        } else {
1659
                            ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text,LED_NONE);
1660
                        }
1661

    
1662
                        last_stats_evaluation = now;
1663
                }
1664
                
1665
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_qoe_evaluation.tv_sec*1000)+(last_qoe_evaluation.tv_usec/1000))) > EVAL_QOE_INTERVAL)
1666
                {
1667
                        // ESTIMATE QoE
1668
                        //ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), &qoe);
1669
                        // ESTIMATE QoE using real-time computed cumulative average bitrate
1670
                        // (plus a diminshing contribution of the instantaneous bitrate, until the cumulative avg stabilizes)
1671
                        int input_bitrate = 0;
1672
                        // stabilize after circa 30 seconds
1673
                        if(videoq.cumulative_samples < 30*(1000/GUI_PRINTSTATS_INTERVAL))
1674
                                input_bitrate = video_statistics.Bitrate;
1675
                        else
1676
                                input_bitrate = video_avg_bitrate;
1677
                        //double a = 1 / ((double)videoq.cumulative_samples);
1678
                        //double b = 1-a;
1679
                        //double input_bitrate = a*((double)video_statistics.Bitrate) + b*((double)video_avg_bitrate);
1680
                        ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), input_bitrate, &qoe);
1681
#ifdef DEBUG_STATS
1682
                        fprintf(stderr,"rate %d avg %d wghtd %d cum_samp %d PSNR %f\n", video_statistics.Bitrate, video_avg_bitrate, (int)input_bitrate, videoq.cumulative_samples, (float)qoe);
1683
#endif
1684
                        last_qoe_evaluation = now;
1685
                }
1686
        }
1687
        return 0;
1688
}
1689

    
1690
void ChunkerPlayerCore_ChangeDelay(int ms)
1691
{
1692
        DeltaTime += ms;
1693
}