Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_core.c @ e5557dc3

History | View | Annotate | Download (47.2 KB)

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

    
8
#include <libavcodec/avcodec.h>
9
#include <libavformat/avformat.h>
10
#include <libswscale/swscale.h>
11

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

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

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

    
47
        SHistory PacketHistory;
48
        
49
        double density;
50
        char stats_message[255];
51
} PacketQueue;
52

    
53
AVCodecContext  *aCodecCtx;
54
SDL_Thread *video_thread;
55
SDL_Thread *stats_thread;
56
uint8_t *outbuf_audio;
57
// short int QueueFillingMode=1;
58
short int QueueStopped;
59
ThreadVal VideoCallbackThreadParams;
60

    
61
int AudioQueueOffset;
62
PacketQueue audioq;
63
PacketQueue videoq;
64
AVPacket AudioPkt, VideoPkt;
65
int AVPlaying;
66
int CurrentAudioFreq;
67
int CurrentAudioSamples;
68
uint8_t CurrentAudioSilence;
69

    
70
SDL_Rect *InitRect;
71
SDL_AudioSpec *AudioSpecification;
72

    
73
struct SwsContext *img_convert_ctx;
74
int GotSigInt;
75

    
76
long long DeltaTime;
77
short int FirstTimeAudio, FirstTime;
78

    
79
int dimAudioQ;
80
float deltaAudioQ;
81
float deltaAudioQError;
82

    
83
int SaveYUV;
84
char YUVFileName[256];
85
int SaveLoss;
86

    
87
char VideoFrameLossRateLogFilename[256];
88
char VideoFrameSkipRateLogFilename[256];
89

    
90
long int decoded_vframes;
91
long int LastSavedVFrame;
92

    
93
void SaveFrame(AVFrame *pFrame, int width, int height);
94
int VideoCallback(void *valthread);
95
int CollectStatisticsThread(void *params);
96
void AudioCallback(void *userdata, Uint8 *stream, int len);
97
void PacketQueueClearStats(PacketQueue *q);
98

    
99
//int lastCheckedVideoFrame = -1;
100
long int last_video_frame_extracted = -1;
101

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

    
118
  // Compute the time remaining to wait. tv_usec is certainly positive.
119
  result->tv_sec = x->tv_sec - y->tv_sec;
120
  result->tv_usec = x->tv_usec - y->tv_usec;
121

    
122
  // Return 1 if result is negative.
123
  return x->tv_sec < y->tv_sec;
124
}
125

    
126

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

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

    
163
        tmp = q->first_pkt;
164
        while(tmp) {
165
                tmp1 = tmp;
166
                tmp = tmp->next;
167
                av_free_packet(&(tmp1->pkt));
168
                av_free(tmp1);
169
#ifdef DEBUG_QUEUE
170
                printf("F ");
171
#endif
172
                q->PacketHistory.LostCount++;
173
        }
174
#ifdef DEBUG_QUEUE
175
        printf("\n");
176
#endif
177

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

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

    
214
int ChunkerPlayerCore_PacketQueuePut(PacketQueue *q, AVPacket *pkt)
215
{
216
        //~ printf("\tSTREAM_INDEX=%d\n", pkt->stream_index);
217
        short int skip = 0;
218
        AVPacketList *pkt1, *tmp, *prevtmp;
219
        int res = 0;
220

    
221
        if(q->nb_packets > queue_filling_threshold*QUEUE_MAX_GROW_FACTOR) {
222
#ifdef DEBUG_QUEUE
223
                printf("QUEUE: PUT i have TOO MANY packets %d Type=%s, RESETTING\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
224
#endif
225
                PacketQueueReset(q);
226
        }
227

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

    
237
        if(!pkt1) {
238
                av_free_packet(pkt);
239
                return -1;
240
        }
241
        pkt1->pkt = *pkt;
242
        pkt1->next = NULL;
243
        
244
        static time_t last_auto_switch = 0;
245

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

    
259
        else
260
        {
261
                SDL_LockMutex(q->mutex);
262

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

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

    
332
        return res;
333
}
334

    
335
int ChunkerPlayerCore_InitCodecs(char *v_codec, int width, int height, char *audio_codec, int sample_rate, short int audio_channels)
336
{
337
        // some initializations
338
        QueueStopped = 0;
339
        AudioQueueOffset=0;
340
        AVPlaying = 0;
341
        GotSigInt = 0;
342
        FirstTimeAudio=1;
343
        FirstTime = 1;
344
        deltaAudioQError=0;
345
        InitRect = NULL;
346
        img_convert_ctx = NULL;
347
        
348
        SDL_AudioSpec *wanted_spec;
349
        AVCodec         *aCodec;
350
        
351
        memset(&VideoCallbackThreadParams, 0, sizeof(ThreadVal));
352
        
353
        VideoCallbackThreadParams.width = width;
354
        VideoCallbackThreadParams.height = height;
355
        VideoCallbackThreadParams.video_codec = strdup(v_codec);
356

    
357
        // Register all formats and codecs
358
        avcodec_init();
359
        av_register_all();
360

    
361
        aCodecCtx = avcodec_alloc_context();
362
        //aCodecCtx->bit_rate = 64000;
363
        aCodecCtx->sample_rate = sample_rate;
364
        aCodecCtx->channels = audio_channels;
365
        aCodec = avcodec_find_decoder_by_name(audio_codec);
366
        if(!aCodec) {
367
                printf("Codec not found!\n");
368
                return -1;
369
        }
370
        if(avcodec_open(aCodecCtx, aCodec)<0) {
371
                fprintf(stderr, "could not open codec\n");
372
                return -1; // Could not open codec
373
        }
374
        printf("using audio Codecid: %d ",aCodecCtx->codec_id);
375
        printf("samplerate: %d ",aCodecCtx->sample_rate);
376
        printf("channels: %d\n",aCodecCtx->channels);
377

    
378
        if (! (wanted_spec = malloc(sizeof(*wanted_spec)))) {
379
                perror("error initializing audio");
380
                return -1;
381
        }
382
        wanted_spec->freq = aCodecCtx->sample_rate;
383
        wanted_spec->format = AUDIO_S16SYS;
384
        wanted_spec->channels = aCodecCtx->channels;
385
        wanted_spec->silence = 0;
386
        wanted_spec->samples = SDL_AUDIO_BUFFER_SIZE;
387
        wanted_spec->callback = AudioCallback;
388
        wanted_spec->userdata = aCodecCtx;
389

    
390
#ifdef DEBUG_AUDIO
391
        printf("wanted freq:%d\n",wanted_spec->freq);
392
        printf("wanted format:%d\n",wanted_spec->format);
393
        printf("wanted channels:%d\n",wanted_spec->channels);
394
        printf("wanted silence:%d\n",wanted_spec->silence);
395
        printf("wanted samples:%d\n",wanted_spec->samples);
396
#endif
397

    
398
        if(SDL_OpenAudio(wanted_spec,AudioSpecification)<0)
399
        {
400
                fprintf(stderr,"SDL_OpenAudio: %s\n", SDL_GetError());
401
                return -1;
402
        }
403
        if (!AudioSpecification) {
404
                AudioSpecification = wanted_spec;
405
        } else {
406
                free(wanted_spec);
407
        }
408

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

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

    
425
        outbuf_audio = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
426

    
427
        //initialize the audio and the video queues
428
        PacketQueueInit(&audioq, AUDIO);
429
        PacketQueueInit(&videoq, VIDEO);
430
        
431
        // Init audio and video buffers
432
        av_init_packet(&AudioPkt);
433
        av_init_packet(&VideoPkt);
434
        //printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d\n", AVCODEC_MAX_AUDIO_FRAME_SIZE);
435
        AudioPkt.data=(uint8_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
436
        if(!AudioPkt.data) return 1;
437
        VideoPkt.data=(uint8_t *)malloc(width*height*3/2);
438
        if(!VideoPkt.data) return 1;
439
        
440
        InitRect = (SDL_Rect*) malloc(sizeof(SDL_Rect));
441
        if(!InitRect)
442
        {
443
                printf("Memory error!!!\n");
444
                return -1;
445
        }
446
        InitRect->x = OverlayRect.x;
447
        InitRect->y = OverlayRect.y;
448
        InitRect->w = OverlayRect.w;
449
        InitRect->h = OverlayRect.h;
450
        
451
        char audio_stats[255], video_stats[255];
452
        sprintf(audio_stats, "waiting for incoming audio packets...");
453
        sprintf(video_stats, "waiting for incoming video packets...");
454
        ChunkerPlayerGUI_SetStatsText(audio_stats, video_stats,LED_GREEN);
455
        
456
        return 0;
457
}
458

    
459
int DecodeEnqueuedAudio(AVPacket *pkt, PacketQueue *q, int* size)
460
{
461
        uint16_t *audio_bufQ = NULL;
462
        int16_t *dataQ = NULL;
463
        int data_sizeQ = AVCODEC_MAX_AUDIO_FRAME_SIZE;
464
        int lenQ;
465
        int ret = 0;
466

    
467
        //set the flag to decoded anyway        
468
        pkt->convergence_duration = -1;
469

    
470
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
471
        if(audio_bufQ) {
472
#ifdef DEBUG_AUDIO_BUFFER
473
                printf("AUDIO_BUFFER: about to decode packet %d, size %d, data %d\n", pkt->stream_index, pkt->size, pkt->data);
474
#endif
475
                //decode the packet data
476
                lenQ = avcodec_decode_audio3(aCodecCtx, (int16_t *)audio_bufQ, &data_sizeQ, pkt);
477
                if(lenQ > 0) {
478
                        dataQ = (int16_t *)av_malloc(data_sizeQ); //this will be free later at the time of playback
479
                        if(dataQ) {
480
                                memcpy(dataQ, audio_bufQ, data_sizeQ);
481
                                if(pkt->data != NULL)
482
                                {
483
                                        //discard the old encoded bytes
484
                                        av_free(pkt->data);
485
                                }
486
                                //subtract them from queue size
487
                                q->size -= pkt->size;
488
                                *size = pkt->size;
489
                                pkt->data = (uint8_t *)dataQ;
490
                                pkt->size = data_sizeQ;
491
                                //add new size to queue size
492
                                q->size += pkt->size;
493
                                ret = 1;
494
                        }
495
                        else {
496
#ifdef DEBUG_AUDIO_BUFFER
497
                                printf("AUDIO_BUFFER: cannot alloc space for decoded packet %d\n", pkt->stream_index);
498
#endif
499
                        }
500
                }
501
                else {
502
#ifdef DEBUG_AUDIO_BUFFER
503
                        printf("AUDIO_BUFFER: cannot decode packet %d\n", pkt->stream_index);
504
#endif
505
                }
506
                av_free(audio_bufQ);
507
        }
508
        else {
509
#ifdef DEBUG_AUDIO_BUFFER
510
                printf("AUDIO_BUFFER: cannot alloc decode buffer for packet %d\n", pkt->stream_index);
511
#endif
512
        }
513
        return ret; //problems occurred
514
}
515

    
516
/**
517
 * removes a packet from the list and returns the next
518
 * */
519
AVPacketList *RemoveFromQueue(PacketQueue *q, AVPacketList *p)
520
{
521
        AVPacketList *p1;
522

    
523
        if (q->first_pkt == p) {
524
                q->first_pkt = p->next;
525
        }
526
        if (&(p->pkt) == q->minpts_pkt) {
527
                q->minpts_pkt = NULL;
528
        }
529

    
530
        AVPacketList *retpk = p->next;
531
        q->nb_packets--;
532
        //adjust size here and not in the various cases of the dequeue
533
        q->size -= p->pkt.size;
534
        if(&p->pkt)
535
        {
536
                av_free_packet(&p->pkt);
537
        }
538
        if(p) {
539
                av_free(p);
540
        }
541

    
542
        //updating min info
543
        for (p1 = q->first_pkt; p1; p1 = p1->next) {
544
                if (!q->minpts_pkt || p1->pkt.pts < q->minpts_pkt->pts) {
545
                        q->minpts_pkt = &(p1->pkt);
546
                }
547
        }
548

    
549
        return retpk;
550
}
551

    
552
AVPacketList *SeekAndDecodePacketStartingFrom(AVPacketList *p, PacketQueue *q, int* size)
553
{
554
        while(p) {
555
                        //check if audio packet has been already decoded
556
                        if(p->pkt.convergence_duration == 0) {
557
                                //not decoded yet, try to decode it
558
                                if( !DecodeEnqueuedAudio(&(p->pkt), q, size) ) {
559
                                        //it was not possible to decode this packet, return next one
560
                                        p = RemoveFromQueue(q, p);
561
                                }
562
                                else
563
                                        return p;
564
                        }
565
                        else
566
                                return p;
567
        }
568
        return NULL;
569
}
570

    
571
int PacketQueueGet(PacketQueue *q, AVPacket *pkt, short int av, int* size)
572
{
573
        //AVPacket tmp;
574
        AVPacketList *pkt1 = NULL;
575
        int ret=-1;
576
        int SizeToCopy=0;
577
        int reqsize;
578

    
579
        SDL_LockMutex(q->mutex);
580

    
581
#ifdef DEBUG_QUEUE
582
        printf("QUEUE: Get NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
583
#endif
584

    
585
        if((q->queueType==AUDIO && QueueFillingMode) || QueueStopped)
586
        {
587
                SDL_UnlockMutex(q->mutex);
588
                return -1;
589
        }
590

    
591
        if(av==1) { //somebody requested an audio packet, q is the audio queue
592
                reqsize = dimAudioQ; //TODO pass this as parameter, not garanteed by SDL to be exactly dimAudioQ
593
                pkt->size = 0;
594
                pkt->dts = 0;
595
                pkt->pts = 0;
596
                //try to dequeue the first packet of the audio queue
597
                pkt1 = q->first_pkt;
598
                while (pkt->size < reqsize && pkt1 && SeekAndDecodePacketStartingFrom(pkt1, q, size)) {
599
                        AVPacketList *next = pkt1->next;        //save it here since we could delete pkt1 later
600
                        if (!pkt->dts) pkt->dts = pkt1->pkt.dts;
601
                        if (!pkt->pts) pkt->pts = pkt1->pkt.pts;
602
                        pkt->stream_index = pkt1->pkt.stream_index;
603
                        pkt->flags = 1;
604
                        pkt->pos = -1;
605
                        pkt->convergence_duration = -1;
606
                        if (pkt1->pkt.size - AudioQueueOffset <= reqsize - pkt->size) { //we need the whole packet
607
                                SizeToCopy = pkt1->pkt.size - AudioQueueOffset;        //packet might be partial
608
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
609
                                pkt->size += SizeToCopy;
610
                                AudioQueueOffset = 0;
611
                                RemoveFromQueue(q, pkt1);
612
                        } else {
613
                                SizeToCopy = reqsize - pkt->size;        //partial packet remains
614
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
615
                                pkt->size += SizeToCopy;
616
                                AudioQueueOffset += SizeToCopy;
617
                                pkt1->pkt.dts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
618
                                pkt1->pkt.pts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
619
                        }
620

    
621
#ifdef DEBUG_AUDIO_BUFFER
622
                        printf("2: idx %d    \taqo %d    \tstc %d    \taqe %f    \tpsz %d\n", pkt1->pkt.stream_index, AudioQueueOffset, SizeToCopy, deltaAudioQError, pkt1->pkt.size);
623
#endif
624

    
625
                        //update index of last frame extracted
626
                        //ChunkerPlayerStats_UpdateAudioLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
627
                        q->last_frame_extracted = pkt->stream_index;
628

    
629
                        pkt1 = next;
630
                }
631
                ret = 1; //TODO: check some conditions
632
        } else { //somebody requested a video packet, q is the video queue
633
                pkt1 = q->first_pkt;
634
                if(pkt1) {
635
#ifdef DEBUG_QUEUE_DEEP
636
                        printf("  AV not 1\n");
637
#endif
638
                        pkt->size = pkt1->pkt.size;
639
                        pkt->dts = pkt1->pkt.dts;
640
                        pkt->pts = pkt1->pkt.pts;
641
                        pkt->stream_index = pkt1->pkt.stream_index;
642
                        pkt->flags = pkt1->pkt.flags;
643
                        pkt->pos = pkt1->pkt.pos;
644
                        pkt->convergence_duration = pkt1->pkt.convergence_duration;
645
                        //*pkt = pkt1->pkt;
646
                        
647
                        if((pkt->data != NULL) && (pkt1->pkt.data != NULL))
648
                                memcpy(pkt->data, pkt1->pkt.data, pkt1->pkt.size);
649
                                
650
                        //HINT SEE BEFORE q->size -= pkt1->pkt.size;
651
                        RemoveFromQueue(q, pkt1);
652

    
653
                        ret = 1;
654
                        
655
                        ChunkerPlayerStats_UpdateVideoLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
656
                        
657
                        //update index of last frame extracted
658
                        q->last_frame_extracted = pkt->stream_index;
659
                        last_video_frame_extracted = q->last_frame_extracted;
660
                }
661
#ifdef DEBUG_QUEUE
662
                else {
663
                        printf("  VIDEO pk1 NULL!!!!\n");
664
                }
665
#endif
666
        }
667

    
668
        if(q->nb_packets==0 && q->queueType==AUDIO) {
669
                QueueFillingMode=1;
670
#ifdef DEBUG_QUEUE
671
                printf("QUEUE: Get FillingMode ON\n");
672
#endif
673
        }
674
#ifdef DEBUG_QUEUE
675
        printf("QUEUE: Get Last %s Frame Extracted = %d\n", (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
676
#endif
677

    
678
        SDL_UnlockMutex(q->mutex);
679
        return ret;
680
}
681

    
682
int AudioDecodeFrame(uint8_t *audio_buf, int buf_size) {
683
        //struct timeval now;
684
        int audio_pkt_size = 0;
685
        int compressed_size = 0;
686
        long long Now;
687
        short int DecodeAudio=0, SkipAudio=0;
688
        //int len1, data_size;
689

    
690
        //gettimeofday(&now,NULL);
691
        //Now = (now.tv_sec)*1000+now.tv_usec/1000;
692
        Now=(long long)SDL_GetTicks();
693
        struct timeval now_tv;
694

    
695
        if(QueueFillingMode || QueueStopped)
696
        {
697
                //SDL_LockMutex(timing_mutex);
698
                FirstTimeAudio=1;
699
                FirstTime = 1;
700
                //SDL_UnlockMutex(timing_mutex);
701
                return -1;
702
        }
703

    
704
        if((FirstTime==1 || FirstTimeAudio==1) && audioq.size>0) {
705
                if(audioq.first_pkt->pkt.pts>0)
706
                {
707
                        //SDL_LockMutex(timing_mutex);
708
                        DeltaTime=Now-(long long)(audioq.first_pkt->pkt.pts);
709
                        FirstTimeAudio = 0;
710
                        FirstTime = 0;
711
                        //SDL_UnlockMutex(timing_mutex);
712
#ifdef DEBUG_AUDIO 
713
                         printf("AUDIO: audio_decode_frame - DeltaTimeAudio=%lld\n",DeltaTime);
714
#endif
715
                }
716
        }
717

    
718
#ifdef DEBUG_AUDIO 
719
        if(audioq.first_pkt)
720
        {
721
                printf("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);
722
                printf("AUDIO: QueueLen=%d ",(int)audioq.nb_packets);
723
                printf("AUDIO: QueueSize=%d\n",(int)audioq.size);
724
        }
725
        else
726
                printf("AUDIO: audio_decode_frame - Empty queue\n");
727
#endif
728

    
729
        gettimeofday(&now_tv, NULL);
730
        if(audioq.nb_packets>0)
731
        {
732
                if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //too late ... TODO: figure out the right number
733
                {
734
                        SkipAudio = 1;
735
                        DecodeAudio = 0;
736
                }
737
                else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
738
                        (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
739
                                SkipAudio = 0;
740
                                DecodeAudio = 1;
741
                }
742
        }
743
        
744
        while(SkipAudio==1 && audioq.size>0)
745
        {
746
                SkipAudio = 0;
747
#ifdef DEBUG_AUDIO
748
                 printf("AUDIO: skipaudio: queue size=%d\n",audioq.size);
749
#endif
750
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
751
                        return -1;
752
                }
753
                if(audioq.first_pkt)
754
                {
755
                        ChunkerPlayerStats_UpdateAudioSkipHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
756
                        
757
                        if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //TODO: figure out the right number
758
                        {
759
                                SkipAudio = 1;
760
                                DecodeAudio = 0;
761
                        }
762
                        else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
763
                                (double)audioq.first_pkt->pkt.pts+DeltaTime<=Now+deltaAudioQ+3*deltaAudioQ) {        //TODO: how much in future?
764
                                        SkipAudio = 0;
765
                                        DecodeAudio = 1;
766
                        }
767
                }
768
        }
769
        if(DecodeAudio==1) {
770
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
771
                        return -1;
772
                }
773
                memcpy(audio_buf,AudioPkt.data,AudioPkt.size);
774
                audio_pkt_size = AudioPkt.size;
775
#ifdef DEBUG_AUDIO
776
                 printf("AUDIO: Decode audio\n");
777
#endif
778

    
779
                ChunkerPlayerStats_UpdateAudioPlayedHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
780
        }
781

    
782
        return audio_pkt_size;
783
}
784

    
785
int VideoCallback(void *valthread)
786
{
787
        //AVPacket pktvideo;
788
        AVCodecContext  *pCodecCtx;
789
        AVCodec         *pCodec;
790
        AVFrame         *pFrame;
791
        int frameFinished;
792
        AVPicture pict;
793
        long long Now;
794
        short int SkipVideo, DecodeVideo;
795
        uint64_t last_pts = 0;
796
        
797
#ifdef SAVE_YUV
798
        static AVFrame* lastSavedFrameBuffer = NULL;
799
        
800
        if(!lastSavedFrameBuffer)
801
                lastSavedFrameBuffer = (AVFrame*) malloc(sizeof(AVFrame));
802
#endif
803

    
804
        //double frame_rate = 0.0,time_between_frames=0.0;
805
        //struct timeval now;
806

    
807
        //int wait_for_sync = 1;
808
        ThreadVal *tval;
809
        tval = (ThreadVal *)valthread;
810

    
811
        //frame_rate = tval->framerate;
812
        //time_between_frames = 1.e6 / frame_rate;
813
        //gettimeofday(&time_now,0);
814

    
815
        //frecon = fopen("recondechunk.mpg","wb");
816

    
817
        //setup video decoder
818
        pCodec = avcodec_find_decoder_by_name(tval->video_codec);
819
        if (pCodec) {
820
                fprintf(stderr, "INIT: Setting VIDEO codecID to: %d\n",pCodec->id);
821
        } else {
822
                fprintf(stderr, "INIT: Unknown VIDEO codec: %s!\n", tval->video_codec);
823
                return -1; // Codec not found
824
        }
825

    
826
        pCodecCtx=avcodec_alloc_context();
827
        pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
828
        //pCodecCtx->debug = FF_DEBUG_DCT_COEFF;
829
        pCodecCtx->codec_id = pCodec->id;
830

    
831
        //pCodecCtx->bit_rate = 400000;
832
        // resolution must be a multiple of two
833
        pCodecCtx->width = tval->width;//176;//352;
834
        pCodecCtx->height = tval->height;//144;//288;
835

    
836
        // frames per second
837
        //pCodecCtx->time_base = (AVRational){1,25};
838
        //pCodecCtx->gop_size = 10; // emit one intra frame every ten frames
839
        //pCodecCtx->max_b_frames=1;
840
        pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
841
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
842

    
843
        if(pCodec==NULL) {
844
                fprintf(stderr, "Unsupported codec!\n");
845
                return -1; // Codec not found
846
        }
847
        if(avcodec_open(pCodecCtx, pCodec) < 0) {
848
                fprintf(stderr, "could not open codec\n");
849
                return -1; // Could not open codec
850
        }
851
        pFrame=avcodec_alloc_frame();
852
        if(pFrame==NULL) {
853
                printf("Memory error!!!\n");
854
                return -1;
855
        }
856
        
857
#ifdef DEBUG_VIDEO
858
         printf("VIDEO: video_callback entering main cycle\n");
859
#endif
860

    
861
        struct timeval now_tv;
862
        while(AVPlaying && !quit) {
863
                if(QueueFillingMode || QueueStopped)
864
                {
865
                        //SDL_LockMutex(timing_mutex);
866
                        FirstTime = 1;
867
                        //SDL_UnlockMutex(timing_mutex);
868
                        usleep(5000);
869
                        continue;
870
                }
871

    
872
                DecodeVideo = 0;
873
                SkipVideo = 0;
874
                Now=(long long)SDL_GetTicks();
875
                if(FirstTime==1 && videoq.size>0) {
876
                        if(videoq.first_pkt->pkt.pts>0)
877
                        {
878
                                //SDL_LockMutex(timing_mutex);
879
                                DeltaTime=Now-(long long)videoq.first_pkt->pkt.pts;
880
                                FirstTime = 0;
881
                                //SDL_UnlockMutex(timing_mutex);
882
                        }
883
#ifdef DEBUG_VIDEO 
884
                         printf("VIDEO: VideoCallback - DeltaTimeAudio=%lld\n",DeltaTime);
885
#endif
886
                }
887

    
888
#ifdef DEBUG_VIDEO 
889
                if(videoq.first_pkt)
890
                {
891
                        printf("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);
892
                        printf("VIDEO: Index=%d ", (int)videoq.first_pkt->pkt.stream_index);
893
                        printf("VIDEO: QueueLen=%d ", (int)videoq.nb_packets);
894
                        printf("VIDEO: QueueSize=%d\n", (int)videoq.size);
895
                }
896
                else
897
                        printf("VIDEO: VideoCallback - Empty queue\n");
898
#endif
899

    
900
                if(videoq.nb_packets>0) {
901
                        long long target_ts = videoq.minpts_pkt->pts + DeltaTime;
902
                        long long frame_timespan = MAX_TOLLERANCE;        //TODO: calculate real value
903
                        if(target_ts<Now-(long long)MAX_TOLLERANCE) {
904
                                SkipVideo = 1;
905
                                DecodeVideo = 0;
906
                        } else if(target_ts>=Now-(long long)MAX_TOLLERANCE && target_ts<=Now) {
907
                                SkipVideo = 0;
908
                                DecodeVideo = 1;
909
                        } else if (last_pts+frame_timespan+DeltaTime<=Now) {
910
                                SkipVideo = 0;
911
                                DecodeVideo = 1;
912
                        }
913
                }
914
                // else (i.e. videoq.minpts_pkt->pts+DeltaTime>Now+MAX_TOLLERANCE)
915
                // do nothing and continue
916
#ifdef DEBUG_VIDEO
917
                printf("VIDEO: skipvideo:%d decodevideo:%d\n",SkipVideo,DecodeVideo);
918
#endif
919
                gettimeofday(&now_tv, NULL);
920
                
921
                if(SkipVideo==1 && videoq.size>0)
922
                {
923
                        SkipVideo = 0;
924
#ifdef DEBUG_VIDEO 
925
                         printf("VIDEO: Skip Video\n");
926
#endif
927
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) < 0) {
928
                                break;
929
                        }
930

    
931
                        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
932
                        
933
                        // sometimes assertion fails, maybe the decoder change the frame type
934
                        //~ if(LastSourceIFrameDistance == 0)
935
                                //~ assert(pFrame->pict_type == 1);
936

    
937
                        
938
                        ChunkerPlayerStats_UpdateVideoSkipHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
939
                        
940
                        /*if(pFrame->pict_type == 1)
941
                        {
942
                                int i1;
943
                                // every 23 items (23 is the qstride field in the AVFrame struct) there is 1 zero.
944
                                // 396/23 = 17 => 396 macroblocks + 17 zeros = 413 items
945
                                for(i1=0; i1< 413; i1++)
946
                                        fprintf(qscaletable_file, "%d\t", (int)pFrame->qscale_table[i1]);
947
                                fprintf(qscaletable_file, "\n");
948
                        }*/
949
                        
950
                        //ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size);
951
                        continue;
952
                }
953

    
954
                if (DecodeVideo==1) {
955
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) > 0) {
956
                                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
957
                                last_pts = pFrame->pkt_pts;
958
                                if (!videoq.minpts_pkt || videoq.minpts_pkt->pts > Now - DeltaTime) {
959
                                        DecodeVideo = 0;
960
                                }
961

    
962
                                if(frameFinished)
963
                                { // it must be true all the time else error
964
#ifdef DEBUG_VIDEO
965
                                        printf("VIDEO: FrameFinished\n");
966
#endif
967
                                        decoded_vframes++;
968
                                        
969
                                        // sometimes assertion fails, maybe the decoder change the frame type
970
                                        //~ if(LastSourceIFrameDistance == 0)
971
                                                //~ assert(pFrame->pict_type == 1);
972
#ifdef SAVE_YUV
973
                                        if(LastSavedVFrame == -1)
974
                                        {
975
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
976
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
977
                                                LastSavedVFrame = VideoPkt.stream_index;
978
                                        }
979
                                        else if(LastSavedVFrame == (VideoPkt.stream_index-1))
980
                                        {
981
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
982
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
983
                                                LastSavedVFrame = VideoPkt.stream_index;
984
                                        }
985
                                        else if(LastSavedVFrame >= 0)
986
                                        {
987
                                                while(LastSavedVFrame < (VideoPkt.stream_index-1))
988
                                                {
989
                                                        SaveFrame(lastSavedFrameBuffer, pCodecCtx->width, pCodecCtx->height);
990
                                                }
991

    
992
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
993
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
994
                                                LastSavedVFrame = VideoPkt.stream_index;
995
                                        }
996
#endif
997
                                        ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
998

    
999
                                        if(SilentMode)
1000
                                                continue;
1001

    
1002
                                        // Lock SDL_yuv_overlay
1003
                                        if(SDL_MUSTLOCK(MainScreen)) {
1004
                                                if(SDL_LockSurface(MainScreen) < 0) {
1005
                                                        continue;
1006
                                                }
1007
                                        }
1008

    
1009
                                        if(SDL_LockYUVOverlay(YUVOverlay) < 0) {
1010
                                                if(SDL_MUSTLOCK(MainScreen)) {
1011
                                                        SDL_UnlockSurface(MainScreen);
1012
                                                }
1013
                                                continue;
1014
                                        }
1015
                                        
1016
                                        pict.data[0] = YUVOverlay->pixels[0];
1017
                                        pict.data[1] = YUVOverlay->pixels[2];
1018
                                        pict.data[2] = YUVOverlay->pixels[1];
1019

    
1020
                                        pict.linesize[0] = YUVOverlay->pitches[0];
1021
                                        pict.linesize[1] = YUVOverlay->pitches[2];
1022
                                        pict.linesize[2] = YUVOverlay->pitches[1];
1023

    
1024
                                        if(img_convert_ctx == NULL) {
1025
                                                img_convert_ctx = sws_getContext(tval->width, tval->height, PIX_FMT_YUV420P, InitRect->w, InitRect->h, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
1026
                                                if(img_convert_ctx == NULL) {
1027
                                                        fprintf(stderr, "Cannot initialize the conversion context!\n");
1028
                                                        exit(1);
1029
                                                }
1030
                                        }
1031
                                        
1032
#ifdef VIDEO_DEINTERLACE
1033
                                        avpicture_deinterlace(
1034
                                                (AVPicture*) pFrame,
1035
                                                (const AVPicture*) pFrame,
1036
                                                pCodecCtx->pix_fmt,
1037
                                                tval->width, tval->height);
1038
#endif
1039
                                        
1040
                                        // let's draw the data (*yuv[3]) on a SDL screen (*screen)
1041
                                        sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, tval->height, pict.data, pict.linesize);
1042
                                        SDL_UnlockYUVOverlay(YUVOverlay);
1043
                                        // Show, baby, show!
1044
                                        SDL_LockMutex(OverlayMutex);
1045
                                        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
1046
                                        SDL_UnlockMutex(OverlayMutex);
1047

    
1048
                                        //redisplay logo
1049
                                        /**SDL_BlitSurface(image, NULL, MainScreen, &dest);*/
1050
                                        /* Update the screen area just changed */
1051
                                        /**SDL_UpdateRects(MainScreen, 1, &dest);*/
1052

    
1053
                                        if(SDL_MUSTLOCK(MainScreen)) {
1054
                                                SDL_UnlockSurface(MainScreen);
1055
                                        }
1056
                                } //if FrameFinished
1057
                                else
1058
                                {
1059
                                        ChunkerPlayerStats_UpdateVideoLossHistory(&(videoq.PacketHistory), VideoPkt.stream_index+1, videoq.last_frame_extracted-1);
1060
                                }
1061
                        } else { // if packet_queue_get
1062
                                DecodeVideo = 0;
1063
                        }
1064
                } //if DecodeVideo=1
1065

    
1066
                usleep(5000);
1067
        }
1068
        avcodec_close(pCodecCtx);
1069
        av_free(pCodecCtx);
1070
        av_free(pFrame);
1071
        //fclose(frecon);
1072
#ifdef DEBUG_VIDEO
1073
         printf("VIDEO: video callback end\n");
1074
#endif
1075

    
1076
#ifdef SAVE_YUV
1077
        if(!lastSavedFrameBuffer)
1078
                free(lastSavedFrameBuffer);
1079
        
1080
        lastSavedFrameBuffer = NULL;
1081
#endif
1082

    
1083
        return 0;
1084
}
1085

    
1086
void AudioCallback(void *userdata, Uint8 *stream, int len)
1087
{
1088
        //AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
1089
        int audio_size;
1090

    
1091
        static uint8_t audio_buf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
1092

    
1093
        memset(audio_buf, CurrentAudioSilence, sizeof(audio_buf));
1094
        audio_size = AudioDecodeFrame(audio_buf, sizeof(audio_buf));
1095
        
1096
        if(SilentMode < 2) {
1097
                if(audio_size != len) {
1098
                        memset(stream, CurrentAudioSilence, len);
1099
                } else {
1100
                        memcpy(stream, (uint8_t *)audio_buf, len);
1101
                }
1102
        }
1103
}
1104

    
1105
void SaveFrame(AVFrame *pFrame, int width, int height)
1106
{
1107
        FILE *pFile;
1108
        int  y;
1109
  
1110
         // Open file
1111
        pFile=fopen(YUVFileName, "ab");
1112
        if(pFile==NULL)
1113
                return;
1114
  
1115
        // Write header
1116
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1117
  
1118
        // Write Y data
1119
        for(y=0; y<height; y++)
1120
                  fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile);
1121
        // Write U data
1122
        for(y=0; y<height/2; y++)
1123
                  fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile);
1124
        // Write V data
1125
        for(y=0; y<height/2; y++)
1126
                  fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile);
1127
  
1128
        // Close file
1129
        fclose(pFile);
1130
}
1131

    
1132
int ChunkerPlayerCore_IsRunning()
1133
{
1134
        return AVPlaying;
1135
}
1136

    
1137
void ChunkerPlayerCore_Play()
1138
{
1139
        if(AVPlaying) return;
1140
        AVPlaying = 1;
1141
        
1142
        SDL_PauseAudio(0);
1143
        video_thread = SDL_CreateThread(VideoCallback, &VideoCallbackThreadParams);
1144
        ChunkerPlayerStats_Init(&VideoCallbackThreadParams);
1145
        stats_thread = SDL_CreateThread(CollectStatisticsThread, NULL);
1146
        
1147
        decoded_vframes = 0;
1148
        LastSavedVFrame = -1;
1149
}
1150

    
1151
void ChunkerPlayerCore_Stop()
1152
{
1153
        if(!AVPlaying) return;
1154
        
1155
        AVPlaying = 0;
1156
        
1157
        // Stop audio&video playback
1158
        SDL_WaitThread(video_thread, NULL);
1159
        SDL_WaitThread(stats_thread, NULL);
1160
        SDL_PauseAudio(1);        
1161
        SDL_CloseAudio();
1162
        
1163
        if(YUVOverlay != NULL)
1164
        {
1165
                SDL_FreeYUVOverlay(YUVOverlay);
1166
                YUVOverlay = NULL;
1167
        }
1168
        
1169
        PacketQueueReset(&audioq);
1170
        PacketQueueReset(&videoq);
1171
        
1172
        avcodec_close(aCodecCtx);
1173
        av_free(aCodecCtx);
1174
        free(AudioPkt.data);
1175
        free(VideoPkt.data);
1176
        free(outbuf_audio);
1177
        free(InitRect);
1178
        
1179
        /*
1180
        * Sleep two buffers' worth of audio before closing, in order
1181
        *  to allow the playback to finish. This isn't always enough;
1182
        *   perhaps SDL needs a way to explicitly wait for device drain?
1183
        */
1184
        int delay = 2 * 1000 * CurrentAudioSamples / CurrentAudioFreq;
1185
        // printf("SDL_Delay(%d)\n", delay*10);
1186
        SDL_Delay(delay*10);
1187
}
1188

    
1189
void ChunkerPlayerCore_Pause()
1190
{
1191
        if(!AVPlaying) return;
1192
        
1193
        AVPlaying = 0;
1194
        
1195
        // Stop audio&video playback
1196
        SDL_WaitThread(video_thread, NULL);
1197
        SDL_PauseAudio(1);
1198
        
1199
        PacketQueueReset(&audioq);
1200
        PacketQueueReset(&videoq);
1201
}
1202

    
1203
int ChunkerPlayerCore_AudioEnded()
1204
{
1205
        return (audioq.nb_packets==0 && audioq.last_frame_extracted>0);
1206
}
1207

    
1208
void ChunkerPlayerCore_ResetAVQueues()
1209
{
1210
#ifdef DEBUG_QUEUE
1211
        printf("QUEUE: MAIN SHOULD RESET\n");
1212
#endif
1213
        PacketQueueReset(&audioq);
1214
        PacketQueueReset(&videoq);
1215
}
1216

    
1217
int ChunkerPlayerCore_EnqueueBlocks(const uint8_t *block, const int block_size)
1218
{
1219
#ifdef EMULATE_CHUNK_LOSS
1220
        static time_t loss_cycle_start_time = 0, now = 0;
1221
        static int early_losses = 0;
1222
        static int clp_frames = 0;
1223
        
1224
        if(ScheduledChunkLosses)
1225
        {
1226
                static unsigned int random_threshold;
1227
                now=time(NULL);
1228
                if(!loss_cycle_start_time)
1229
                        loss_cycle_start_time = now;
1230
                        
1231
                if(((now-loss_cycle_start_time) >= ScheduledChunkLosses[((CurrChunkLossIndex+1)%NScheduledChunkLosses)].Time) && (NScheduledChunkLosses>1 || CurrChunkLossIndex==-1))
1232
                {
1233
                        CurrChunkLossIndex = ((CurrChunkLossIndex+1)%NScheduledChunkLosses);
1234
                        if(CurrChunkLossIndex == (NScheduledChunkLosses-1))
1235
                                loss_cycle_start_time = now;
1236
                        
1237
                        if(ScheduledChunkLosses[CurrChunkLossIndex].Value == -1)
1238
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].MinValue + (rand() % (ScheduledChunkLosses[CurrChunkLossIndex].MaxValue-ScheduledChunkLosses[CurrChunkLossIndex].MinValue));
1239
                        else
1240
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].Value;
1241
                        
1242
                        printf("new ScheduledChunkLoss, time: %d, value: %d\n", (int)ScheduledChunkLosses[CurrChunkLossIndex].Time, random_threshold);
1243
                }
1244
        
1245
                if(clp_frames > 0)
1246
                {
1247
                        clp_frames--;
1248
                        return PLAYER_FAIL_RETURN;
1249
                }
1250
                if((rand() % 100) < random_threshold)
1251
                {
1252
                        if(early_losses > 0)
1253
                early_losses--;
1254
            else
1255
            {
1256
                clp_frames=early_losses=(ScheduledChunkLosses[CurrChunkLossIndex].Burstiness-1);
1257
                return PLAYER_FAIL_RETURN;
1258
            }
1259
                }
1260
        }
1261
#endif
1262

    
1263
        Chunk *gchunk = NULL;
1264
        int decoded_size = -1;
1265
        uint8_t *tempdata, *buffer;
1266
        int j;
1267
        Frame *frame = NULL;
1268
        AVPacket packet, packetaudio;
1269

    
1270
        uint16_t *audio_bufQ = NULL;
1271

    
1272
        //the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
1273
        static int sizeFrameHeader = 5*sizeof(int32_t);
1274
        //the following we dont need anymore
1275
        //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;
1276

    
1277
        static int chunks_out_of_order = 0;
1278
        static int last_chunk_id = -1;
1279

    
1280
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
1281
        if(!audio_bufQ) {
1282
                printf("Memory error in audio_bufQ!\n");
1283
                return PLAYER_FAIL_RETURN;
1284
        }
1285

    
1286
        gchunk = (Chunk *)malloc(sizeof(Chunk));
1287
        if(!gchunk) {
1288
                printf("Memory error in gchunk!\n");
1289
                av_free(audio_bufQ);
1290
                return PLAYER_FAIL_RETURN;
1291
        }
1292

    
1293
        decoded_size = decodeChunk(gchunk, block, block_size);
1294

    
1295
        if(last_chunk_id == -1)
1296
                last_chunk_id = gchunk->id;
1297

    
1298
        if(gchunk->id > (last_chunk_id+1)) {
1299
                chunks_out_of_order += gchunk->id - last_chunk_id - 1;
1300
        }
1301
        last_chunk_id = gchunk->id;
1302

    
1303
#ifdef DEBUG_CHUNKER
1304
        printf("CHUNKER: enqueueBlock: id %d decoded_size %d target size %d - out_of_order %d\n", gchunk->id, decoded_size, GRAPES_ENCODED_CHUNK_HEADER_SIZE + ExternalChunk_header_size + gchunk->size, chunks_out_of_order);
1305
#endif
1306
  if(decoded_size < 0) {
1307
                //HINT here i should differentiate between various return values of the decode
1308
                //in order to free what has been allocated there
1309
                printf("chunk probably corrupted!\n");
1310
                av_free(audio_bufQ);
1311
                free(gchunk);
1312
                return PLAYER_FAIL_RETURN;
1313
        }
1314

    
1315
        frame = (Frame *)malloc(sizeof(Frame));
1316
        if(!frame) {
1317
                printf("Memory error in Frame!\n");
1318
                if(gchunk) {
1319
                        if(gchunk->attributes) {
1320
                                free(gchunk->attributes);
1321
                        }
1322
                        free(gchunk);
1323
                }
1324
                av_free(audio_bufQ);
1325
                return PLAYER_FAIL_RETURN;
1326
        }
1327

    
1328
        tempdata = gchunk->data; //let it point to first frame of payload
1329
        j=gchunk->size;
1330
        while(j>0 && !quit) {
1331
                frame->number = bit32_encoded_pull(tempdata);
1332
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1333
                frame->timestamp.tv_sec = bit32_encoded_pull(tempdata);
1334
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1335
                frame->timestamp.tv_usec = bit32_encoded_pull(tempdata);
1336
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1337
                frame->size = bit32_encoded_pull(tempdata);
1338
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1339
                frame->type = bit32_encoded_pull(tempdata);
1340
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1341

    
1342
                buffer = tempdata; // here coded frame information
1343
                tempdata += frame->size; //let it point to the next frame
1344

    
1345
                if(frame->type < 5) { // video frame
1346
                        av_init_packet(&packet);
1347
                        packet.data = buffer;//video_bufQ;
1348
                        packet.size = frame->size;
1349
                        packet.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1350
                        packet.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1351
                        packet.stream_index = frame->number; // use of stream_index for number frame
1352
                        //packet.duration = frame->timestamp.tv_sec;
1353
                        if(packet.size > 0) {
1354
                                int ret = ChunkerPlayerCore_PacketQueuePut(&videoq, &packet); //the _put makes a copy of the packet
1355
                                if (ret == 1) {        //TODO: check and correct return values
1356
                                        fprintf(stderr, "late chunk received, increasing delay\n");
1357
                                        DeltaTime += 40;        //TODO: handle audio skip; verify this value
1358
                                }
1359
                        }
1360

    
1361
#ifdef DEBUG_SOURCE
1362
                        printf("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);
1363
#endif
1364
                }
1365
                else if(frame->type == 5) { // audio frame
1366
                        av_init_packet(&packetaudio);
1367
                        packetaudio.data = buffer;
1368
                        packetaudio.size = frame->size;
1369
                        packetaudio.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1370
                        packetaudio.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1371
                        //packetaudio.duration = frame->timestamp.tv_sec;
1372
                        packetaudio.stream_index = frame->number; // use of stream_index for number frame
1373
                        packetaudio.flags = 1;
1374
                        packetaudio.pos = -1;
1375

    
1376
                        //instead of -1, in order to signal it is not decoded yet
1377
                        packetaudio.convergence_duration = 0;
1378

    
1379
                        // insert the audio frame into the queue
1380
                        if(packetaudio.size > 0) {
1381
                                int ret = ChunkerPlayerCore_PacketQueuePut(&audioq, &packetaudio);//makes a copy of the packet so i can free here
1382
                                if (ret == 1) {        //TODO: check and correct return values
1383
                                        fprintf(stderr, "late chunk received, increasing delay\n");
1384
                                        DeltaTime += 40;        //TODO: handle audio skip; verify this value
1385
                                }
1386
                        }
1387

    
1388
#ifdef DEBUG_SOURCE
1389
                        printf("SOURCE: Insert audio in queue pts=%lld sindex:%d\n", packetaudio.pts, packetaudio.stream_index);
1390
#endif
1391
                }
1392
                else {
1393
                        printf("SOURCE: Unknown frame type %d. Size %d\n", frame->type, frame->size);
1394
                }
1395
                if(frame->size > 0)
1396
                        j = j - sizeFrameHeader - frame->size;
1397
                else {
1398
                        printf("SOURCE: Corrupt frames (size %d) in chunk. Skipping it...\n", frame->size);
1399
                        j = -1;
1400
                }
1401
        }
1402
        //chunk ingestion terminated!
1403
        if(gchunk) {
1404
                if(gchunk->attributes) {
1405
                        free(gchunk->attributes);
1406
                }
1407
                if(gchunk->data)
1408
                        free(gchunk->data);
1409
                free(gchunk);
1410
        }
1411
        if(frame)
1412
                free(frame);
1413
        if(audio_bufQ)
1414
                av_free(audio_bufQ);
1415
                
1416
        return PLAYER_OK_RETURN;
1417
}
1418

    
1419
void ChunkerPlayerCore_SetupOverlay(int width, int height)
1420
{
1421
        // if(!MainScreen && !SilentMode)
1422
        // {
1423
                // printf("Cannot find main screen, exiting...\n");
1424
                // exit(1);
1425
        // }
1426
        
1427
        if(SilentMode)
1428
                return;
1429
                
1430
        SDL_LockMutex(OverlayMutex);
1431
        if(YUVOverlay != NULL)
1432
        {
1433
                SDL_FreeYUVOverlay(YUVOverlay);
1434
                YUVOverlay = NULL;
1435
        }
1436
        
1437
        // create video overlay for display of video frames
1438
        // printf("SDL_CreateYUVOverlay(%d, %d, SDL_YV12_OVERLAY, MainScreen)\n", width, height);
1439
        YUVOverlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, MainScreen);
1440
        // YUVOverlay = SDL_CreateYUVOverlay(OverlayRect.w, OverlayRect.h, SDL_YV12_OVERLAY, MainScreen);
1441
        if ( YUVOverlay == NULL )
1442
        {
1443
                fprintf(stderr,"SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError());
1444
                exit(1);
1445
        }
1446

    
1447
        if ( YUVOverlay->hw_overlay )
1448
                fprintf(stderr,"SDL: Using hardware overlay.\n");
1449
        // OverlayRect.x = (screen_w - width) / 2;
1450
        
1451
        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
1452
        
1453
        SDL_UnlockMutex(OverlayMutex);
1454
}
1455

    
1456
int CollectStatisticsThread(void *params)
1457
{
1458
        struct timeval last_stats_evaluation, now, last_trace, last_qoe_evaluation;
1459
        gettimeofday(&last_stats_evaluation, NULL);
1460
        last_trace = last_stats_evaluation;
1461
        last_qoe_evaluation = last_stats_evaluation;
1462
        
1463
        double video_qdensity;
1464
        double audio_qdensity;
1465
        char audio_stats_text[255];
1466
        char video_stats_text[255];
1467
        SStats audio_statistics, video_statistics;
1468
        double qoe = 0;
1469
        int sleep_time = STATS_THREAD_GRANULARITY*1000;
1470
        int audio_avg_bitrate = 0;
1471
        int video_avg_bitrate = 0;
1472
        
1473
        while(AVPlaying && !quit)
1474
        {
1475
                usleep(sleep_time);
1476
                
1477
                gettimeofday(&now, NULL);
1478
                
1479
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_stats_evaluation.tv_sec*1000)+(last_stats_evaluation.tv_usec/1000))) > GUI_PRINTSTATS_INTERVAL)
1480
                {
1481
                        // estimate audio queue stats
1482
                        int audio_stats_changed = ChunkerPlayerStats_GetStats(&(audioq.PacketHistory), &audio_statistics);
1483
                        
1484
                        // estimate video queue stats
1485
                        int video_stats_changed = ChunkerPlayerStats_GetStats(&(videoq.PacketHistory), &video_statistics);
1486

    
1487
                        // compute avg bitrate up to now
1488
                        audioq.cumulative_bitrate += audio_statistics.Bitrate;
1489
                        audioq.cumulative_samples++;
1490
                        audio_avg_bitrate = (int)( ((double)audioq.cumulative_bitrate) / ((double)audioq.cumulative_samples) );
1491
                        videoq.cumulative_bitrate += video_statistics.Bitrate;
1492
                        videoq.cumulative_samples++;
1493
                        video_avg_bitrate = (int)( ((double)videoq.cumulative_bitrate) / ((double)videoq.cumulative_samples) );
1494

    
1495
#ifdef DEBUG_STATS
1496
                        printf("VIDEO: %d Kbit/sec; ", video_statistics.Bitrate);
1497
                        printf("AUDIO: %d Kbit/sec\n", audio_statistics.Bitrate);
1498
#endif
1499

    
1500
                        // QUEUE DENSITY EVALUATION
1501
                        if((audioq.last_pkt != NULL) && (audioq.first_pkt != NULL))
1502
                                if(audioq.last_pkt->pkt.stream_index >= audioq.first_pkt->pkt.stream_index)
1503
                                {
1504
                                        //plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1505
                                        audio_qdensity = (double)audioq.nb_packets / (double)(audioq.last_pkt->pkt.stream_index - audioq.first_pkt->pkt.stream_index + 1) * 100.0;
1506
                                }
1507
                        
1508
                        if((videoq.last_pkt != NULL) && (videoq.first_pkt != NULL))
1509
                                if(videoq.last_pkt->pkt.stream_index >= videoq.first_pkt->pkt.stream_index)
1510
                                {
1511
                                        // plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1512
                                        video_qdensity = (double)videoq.nb_packets / (double)(videoq.last_pkt->pkt.stream_index - videoq.first_pkt->pkt.stream_index + 1) * 100.0;
1513
                                }
1514
                        
1515
                        if(LogTraces)
1516
                        {
1517
                                ChunkerPlayerStats_PrintHistoryTrace(&(audioq.PacketHistory), AudioTraceFilename);
1518
                                ChunkerPlayerStats_PrintHistoryTrace(&(videoq.PacketHistory), VideoTraceFilename);
1519
                                
1520
                                //if(SilentMode != 1 && SilentMode != 2)
1521
                                        ChunkerPlayerStats_PrintContextFile();
1522
                        }
1523

    
1524
                        // PRINT STATISTICS ON GUI
1525
                        if(!Audio_ON)
1526
                                sprintf(audio_stats_text, "AUDIO MUTED");
1527
                        else if(audio_stats_changed)
1528
//                                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);
1529
                                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);
1530
                        else
1531
                                sprintf(audio_stats_text, "waiting for incoming audio packets...");
1532

    
1533
                        if(video_stats_changed)
1534
                        {
1535
                                char est_psnr_string[255];
1536
                                sprintf(est_psnr_string, ".");
1537
                                if(qoe)
1538
                                {
1539
                                        sprintf(est_psnr_string, " - Est. Mean PSNR: %.1f db", (float)qoe);
1540
#ifdef PSNR_PUBLICATION
1541
                                        // Publish measure into repository
1542
                                        if(RepoAddress[0]!='\0')
1543
                                        {
1544
                                            MeasurementRecord r;
1545
                            r.originator = NetworkID;
1546
                            r.targetA = NetworkID;
1547
                            r.targetB = NULL;
1548
                            r.published_name = "PSNR_MEAN";
1549
                            r.value = qoe;
1550
                            r.string_value = NULL;
1551
                            r.channel = Channels[SelectedChannel].Title;
1552
                            gettimeofday(&(r.timestamp), NULL);
1553
                            // One update every REPO_UPDATE_INTERVALL seconds
1554
                            struct timeval ElapsedTime;
1555
                            timeval_subtract(&(r.timestamp),&LastTimeRepoPublish,&ElapsedTime);
1556
                        if(ElapsedTime.tv_sec>=PSNR_REPO_UPDATE_INTERVALL)
1557
                        {
1558
                            LastTimeRepoPublish=r.timestamp;
1559
                            if(repPublish(repoclient,NULL,NULL,&r)!=NULL) {
1560
#ifdef DEBUG_PSNR
1561
                               printf("PSNR publish: %s  %e  %s\n",r.originator,qoe,r.channel);
1562
#endif
1563
                                                                                                                }
1564
                        }
1565
                   }
1566
#endif
1567
                                }
1568

    
1569
//                                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);
1570
                                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);
1571
                        }
1572
                        else
1573
                                sprintf(video_stats_text, "waiting for incoming video packets...");
1574
                        
1575
                        if(qoe)
1576
                            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)));
1577
                        else
1578
                            ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text,LED_GREEN);
1579
                        
1580

    
1581
                        last_stats_evaluation = now;
1582
                }
1583
                
1584
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_qoe_evaluation.tv_sec*1000)+(last_qoe_evaluation.tv_usec/1000))) > EVAL_QOE_INTERVAL)
1585
                {
1586
                        // ESTIMATE QoE
1587
                        //ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), &qoe);
1588
                        // ESTIMATE QoE using real-time computed cumulative average bitrate
1589
                        // (plus a diminshing contribution of the instantaneous bitrate, until the cumulative avg stabilizes)
1590
                        int input_bitrate = 0;
1591
                        // stabilize after circa 30 seconds
1592
                        if(videoq.cumulative_samples < 30*(1000/GUI_PRINTSTATS_INTERVAL))
1593
                                input_bitrate = video_statistics.Bitrate;
1594
                        else
1595
                                input_bitrate = video_avg_bitrate;
1596
                        //double a = 1 / ((double)videoq.cumulative_samples);
1597
                        //double b = 1-a;
1598
                        //double input_bitrate = a*((double)video_statistics.Bitrate) + b*((double)video_avg_bitrate);
1599
                        ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), input_bitrate, &qoe);
1600
#ifdef DEBUG_STATS
1601
                        printf("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);
1602
#endif
1603
                        last_qoe_evaluation = now;
1604
                }
1605
        }
1606
        return 0;
1607
}