Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_core.c @ 6f1fe643

History | View | Annotate | Download (42.4 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 "player_defines.h"
9
#include "chunker_player.h"
10
#include "player_gui.h"
11
#include "player_core.h"
12
#include "player_stats.h"
13
#include <assert.h>
14
#include <time.h>
15

    
16
void SaveFrame(AVFrame *pFrame, int width, int height);
17
int VideoCallback(void *valthread);
18
int CollectStatisticsThread(void *params);
19
void AudioCallback(void *userdata, Uint8 *stream, int len);
20
void PacketQueueClearStats(PacketQueue *q);
21
void ChunkerPlayerCore_Pause();
22

    
23
//int lastCheckedVideoFrame = -1;
24
long int last_video_frame_extracted = -1;
25

    
26
void PacketQueueInit(PacketQueue *q, short int Type)
27
{
28
#ifdef DEBUG_QUEUE
29
        printf("QUEUE: INIT BEGIN: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
30
#endif
31
        memset(q,0,sizeof(PacketQueue));
32
        q->mutex = SDL_CreateMutex();
33
        QueueFillingMode=1;
34
        q->queueType=Type;
35
        q->last_frame_extracted = -1;
36
        q->first_pkt= NULL;
37
        //q->last_pkt = NULL;
38
        q->nb_packets = 0;
39
        q->size = 0;
40
        q->density= 0.0;
41
        FirstTime = 1;
42
        FirstTimeAudio = 1;
43
        //init up statistics
44
        
45
        q->PacketHistory.Mutex = SDL_CreateMutex();
46
        PacketQueueClearStats(q);
47
        
48
#ifdef DEBUG_QUEUE
49
        printf("QUEUE: INIT END: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
50
#endif
51
}
52

    
53
void PacketQueueReset(PacketQueue *q)
54
{
55
        AVPacketList *tmp,*tmp1;
56
#ifdef DEBUG_QUEUE
57
        printf("QUEUE: RESET BEGIN: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
58
#endif
59
        SDL_LockMutex(q->mutex);
60

    
61
        tmp = q->first_pkt;
62
        while(tmp) {
63
                tmp1 = tmp;
64
                tmp = tmp->next;
65
                av_free_packet(&(tmp1->pkt));
66
                av_free(tmp1);
67
#ifdef DEBUG_QUEUE
68
                printf("F ");
69
#endif
70
                q->PacketHistory.LostCount++;
71
        }
72
#ifdef DEBUG_QUEUE
73
        printf("\n");
74
#endif
75

    
76
        QueueFillingMode=1;
77
        q->last_frame_extracted = -1;
78
        
79
        // on queue reset do not reset loss count
80
        // (loss count reset is done on queue init, ie channel switch)
81
        q->density=0.0;
82
        q->first_pkt= NULL;
83
        //q->last_pkt = NULL;
84
        q->nb_packets = 0;
85
        q->size = 0;
86
        FirstTime = 1;
87
        FirstTimeAudio = 1;
88
        //clean up statistics
89
        PacketQueueClearStats(q);
90
#ifdef DEBUG_QUEUE
91
        printf("QUEUE: RESET END: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
92
#endif
93
        SDL_UnlockMutex(q->mutex);
94
}
95

    
96
void PacketQueueClearStats(PacketQueue *q)
97
{
98
        sprintf(q->stats_message, "%s", "\n");
99
        int i;
100
        memset((void*)q->PacketHistory.History, 0, sizeof(SHistoryElement)*QUEUE_HISTORY_SIZE);
101
        for(i=0; i<QUEUE_HISTORY_SIZE; i++)
102
        {
103
                q->PacketHistory.History[i].Statistics.LastIFrameDistance = -1;
104
                q->PacketHistory.History[i].Status = -1;
105
        }
106
        q->PacketHistory.Index = q->PacketHistory.LogIndex = 0;
107
        q->PacketHistory.Index = q->PacketHistory.QoEIndex = 0;
108
        q->PacketHistory.LostCount = q->PacketHistory.PlayedCount = q->PacketHistory.SkipCount = 0;
109
}
110

    
111
int ChunkerPlayerCore_PacketQueuePut(PacketQueue *q, AVPacket *pkt)
112
{
113
        //~ printf("\tSTREAM_INDEX=%d\n", pkt->stream_index);
114
        short int skip = 0;
115
        AVPacketList *pkt1, *tmp, *prevtmp;
116
        int res = 0;
117

    
118
        if(q->nb_packets > queue_filling_threshold*QUEUE_MAX_GROW_FACTOR) {
119
#ifdef DEBUG_QUEUE
120
                printf("QUEUE: PUT i have TOO MANY packets %d Type=%s, RESETTING\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
121
#endif
122
                PacketQueueReset(q);
123
        }
124

    
125
        //make a copy of the incoming packet
126
        if(av_dup_packet(pkt) < 0) {
127
#ifdef DEBUG_QUEUE
128
                printf("QUEUE: PUT in Queue cannot duplicate in packet        : NPackets=%d Type=%s\n",q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
129
#endif
130
                return -1;
131
        }
132
        pkt1 = av_malloc(sizeof(AVPacketList));
133

    
134
        if(!pkt1) {
135
                av_free_packet(pkt);
136
                return -1;
137
        }
138
        pkt1->pkt = *pkt;
139
        pkt1->next = NULL;
140
        
141
        static time_t last_auto_switch = 0;
142

    
143
        // file streaming loop detected => re-tune channel and start grabbing statistics
144
        if(
145
                (pkt->stream_index < last_video_frame_extracted)
146
                && (pkt->stream_index <= RESTART_FRAME_NUMBER_THRESHOLD)
147
                && ((time(NULL) - last_auto_switch) > 10)
148
        )
149
        {
150
                last_auto_switch = time(NULL);
151
                SDL_LockMutex(q->mutex);
152
                ReTune(&(Channels[SelectedChannel]));
153
                SDL_UnlockMutex(q->mutex);
154
        }
155

    
156
        else
157
        {
158
                SDL_LockMutex(q->mutex);
159

    
160
                // INSERTION SORT ALGORITHM
161
                // before inserting pkt, check if pkt.stream_index is <= current_extracted_frame.
162
                if(pkt->stream_index > q->last_frame_extracted)
163
                {
164
                        // either checking starting from the first_pkt or needed other struct like AVPacketList with next and prev....
165
                        //if (!q->last_pkt)
166
                        if(!q->first_pkt) {
167
                                q->first_pkt = pkt1;
168
                                q->last_pkt = pkt1;
169
                        }
170
                        else if(pkt->stream_index < q->first_pkt->pkt.stream_index) {
171
                                //the packet that has arrived is earlier than the first we got some time ago!
172
                                //we need to put it at the head of the queue
173
                                pkt1->next = q->first_pkt;
174
                                q->first_pkt = pkt1;
175
                        }
176
                        else {
177
                                tmp = q->first_pkt;
178
                                while(tmp->pkt.stream_index < pkt->stream_index) {
179
                                        prevtmp = tmp;
180
                                        tmp = tmp->next;
181

    
182
                                        if(!tmp) {
183
                                                break;
184
                                        }
185
                                }
186
                                if(tmp && tmp->pkt.stream_index == pkt->stream_index) {
187
                                        //we already have a frame with that index
188
                                        skip = 1;
189
#ifdef DEBUG_QUEUE
190
                                        printf("%s QUEUE: PUT: we already have frame with index %d, skipping\n", ((q->queueType == AUDIO) ? "AUDIO" : "VIDEO"), pkt->stream_index);
191
#endif
192
                                }
193
                                else {
194
                                        prevtmp->next = pkt1;
195
                                        pkt1->next = tmp;
196
                                        if(pkt1->next == NULL)
197
                                                q->last_pkt = pkt1;
198
                                }
199
                                //q->last_pkt->next = pkt1; // It was uncommented when not insertion sort
200
                        }
201
                        if(skip == 0) {
202
                                //q->last_pkt = pkt1;
203
                                q->nb_packets++;
204
                                q->size += pkt1->pkt.size;
205
                                if(q->nb_packets>=queue_filling_threshold && QueueFillingMode) // && q->queueType==AUDIO)
206
                                {
207
                                        QueueFillingMode=0;
208
#ifdef DEBUG_QUEUE
209
                                        printf("QUEUE: PUT: FillingMode set to zero\n");
210
#endif
211
                                }
212
                        }
213
                }
214
                else {
215
                        av_free_packet(&pkt1->pkt);
216
                        av_free(pkt1);
217
#ifdef DEBUG_QUEUE
218
                        printf("QUEUE: PUT: NOT inserting because index %d <= last extracted %d\n", pkt->stream_index, q->last_frame_extracted);
219
#endif
220
                        res = 1;
221
                }
222
                SDL_UnlockMutex(q->mutex);
223
        }
224

    
225
        return res;
226
}
227

    
228
int ChunkerPlayerCore_InitCodecs(int width, int height, int sample_rate, short int audio_channels)
229
{
230
        // some initializations
231
        QueueStopped = 0;
232
        AudioQueueOffset=0;
233
        AVPlaying = 0;
234
        GotSigInt = 0;
235
        FirstTimeAudio=1;
236
        FirstTime = 1;
237
        deltaAudioQError=0;
238
        InitRect = NULL;
239
        img_convert_ctx = NULL;
240
        
241
        SDL_AudioSpec wanted_spec;
242
        AVCodec         *aCodec;
243
        
244
        memset(&VideoCallbackThreadParams, 0, sizeof(ThreadVal));
245
        
246
        VideoCallbackThreadParams.width = width;
247
        VideoCallbackThreadParams.height = height;
248

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

    
253
        aCodecCtx = avcodec_alloc_context();
254
        //aCodecCtx->bit_rate = 64000;
255
        aCodecCtx->sample_rate = sample_rate;
256
        aCodecCtx->channels = audio_channels;
257
#ifdef MP3_AUDIO_ENCODER
258
        aCodec = avcodec_find_decoder(CODEC_ID_MP3); // codec audio
259
#else
260
        aCodec = avcodec_find_decoder(CODEC_ID_MP2);
261
#endif
262
        printf("MP2 codec id %d MP3 codec id %d\n",CODEC_ID_MP2,CODEC_ID_MP3);
263
        if(!aCodec) {
264
                printf("Codec not found!\n");
265
                return -1;
266
        }
267
        if(avcodec_open(aCodecCtx, aCodec)<0) {
268
                fprintf(stderr, "could not open codec\n");
269
                return -1; // Could not open codec
270
        }
271
        printf("using audio Codecid: %d ",aCodecCtx->codec_id);
272
        printf("samplerate: %d ",aCodecCtx->sample_rate);
273
        printf("channels: %d\n",aCodecCtx->channels);
274
        CurrentAudioFreq = wanted_spec.freq = aCodecCtx->sample_rate;
275
        wanted_spec.format = AUDIO_S16SYS;
276
        wanted_spec.channels = aCodecCtx->channels;
277
        wanted_spec.silence = 0;
278
        CurrentAudioSamples = wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
279
        wanted_spec.callback = AudioCallback;
280
        wanted_spec.userdata = aCodecCtx;
281
        if(SDL_OpenAudio(&wanted_spec,&AudioSpecification)<0)
282
        {
283
                fprintf(stderr,"SDL_OpenAudio: %s\n", SDL_GetError());
284
                return -1;
285
        }
286
        dimAudioQ = AudioSpecification.size;
287
        deltaAudioQ = (float)((float)AudioSpecification.samples)*1000/AudioSpecification.freq;
288

    
289
#ifdef DEBUG_AUDIO
290
        printf("freq:%d\n",AudioSpecification.freq);
291
        printf("format:%d\n",AudioSpecification.format);
292
        printf("channels:%d\n",AudioSpecification.channels);
293
        printf("silence:%d\n",AudioSpecification.silence);
294
        printf("samples:%d\n",AudioSpecification.samples);
295
        printf("size:%d\n",AudioSpecification.size);
296
        printf("deltaAudioQ: %f\n",deltaAudioQ);
297
#endif
298

    
299
        outbuf_audio = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
300

    
301
        //initialize the audio and the video queues
302
        PacketQueueInit(&audioq, AUDIO);
303
        PacketQueueInit(&videoq, VIDEO);
304
        
305
        // Init audio and video buffers
306
        av_init_packet(&AudioPkt);
307
        av_init_packet(&VideoPkt);
308
        //printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d\n", AVCODEC_MAX_AUDIO_FRAME_SIZE);
309
        AudioPkt.data=(uint8_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
310
        if(!AudioPkt.data) return 1;
311
        VideoPkt.data=(uint8_t *)malloc(width*height*3/2);
312
        if(!VideoPkt.data) return 1;
313
        
314
        InitRect = (SDL_Rect*) malloc(sizeof(SDL_Rect));
315
        if(!InitRect)
316
        {
317
                printf("Memory error!!!\n");
318
                return -1;
319
        }
320
        InitRect->x = OverlayRect.x;
321
        InitRect->y = OverlayRect.y;
322
        InitRect->w = OverlayRect.w;
323
        InitRect->h = OverlayRect.h;
324
        
325
        char audio_stats[255], video_stats[255];
326
        sprintf(audio_stats, "waiting for incoming audio packets...");
327
        sprintf(video_stats, "waiting for incoming video packets...");
328
        ChunkerPlayerGUI_SetStatsText(audio_stats, video_stats,LED_GREEN);
329
        
330
        return 0;
331
}
332

    
333
int DecodeEnqueuedAudio(AVPacket *pkt, PacketQueue *q, int* size)
334
{
335
        uint16_t *audio_bufQ = NULL;
336
        int16_t *dataQ = NULL;
337
        int data_sizeQ = AVCODEC_MAX_AUDIO_FRAME_SIZE;
338
        int lenQ;
339
        int ret = 0;
340

    
341
        //set the flag to decoded anyway        
342
        pkt->convergence_duration = -1;
343

    
344
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
345
        if(audio_bufQ) {
346
#ifdef DEBUG_AUDIO_BUFFER
347
                printf("AUDIO_BUFFER: about to decode packet %d, size %d, data %d\n", pkt->stream_index, pkt->size, pkt->data);
348
#endif
349
                //decode the packet data
350
                lenQ = avcodec_decode_audio3(aCodecCtx, (int16_t *)audio_bufQ, &data_sizeQ, pkt);
351
                if(lenQ > 0) {
352
                        dataQ = (int16_t *)av_malloc(data_sizeQ); //this will be free later at the time of playback
353
                        if(dataQ) {
354
                                memcpy(dataQ, audio_bufQ, data_sizeQ);
355
                                if(pkt->data != NULL)
356
                                {
357
                                        //discard the old encoded bytes
358
                                        av_free(pkt->data);
359
                                }
360
                                //subtract them from queue size
361
                                q->size -= pkt->size;
362
                                *size = pkt->size;
363
                                pkt->data = (int8_t *)dataQ;
364
                                pkt->size = data_sizeQ;
365
                                //add new size to queue size
366
                                q->size += pkt->size;
367
                                ret = 1;
368
                        }
369
                        else {
370
#ifdef DEBUG_AUDIO_BUFFER
371
                                printf("AUDIO_BUFFER: cannot alloc space for decoded packet %d\n", pkt->stream_index);
372
#endif
373
                        }
374
                }
375
                else {
376
#ifdef DEBUG_AUDIO_BUFFER
377
                        printf("AUDIO_BUFFER: cannot decode packet %d\n", pkt->stream_index);
378
#endif
379
                }
380
                av_free(audio_bufQ);
381
        }
382
        else {
383
#ifdef DEBUG_AUDIO_BUFFER
384
                printf("AUDIO_BUFFER: cannot alloc decode buffer for packet %d\n", pkt->stream_index);
385
#endif
386
        }
387
        return ret; //problems occurred
388
}
389

    
390
/**
391
 * removes a packet from the list and returns the next
392
 * */
393
AVPacketList *RemoveFromQueue(PacketQueue *q, AVPacketList *p)
394
{
395
        AVPacketList *retpk = p->next;
396
        q->nb_packets--;
397
        //adjust size here and not in the various cases of the dequeue
398
        q->size -= p->pkt.size;
399
        if(&p->pkt)
400
        {
401
                av_free_packet(&p->pkt);
402
        }
403
        if(p)
404
                av_free(p);
405
        return retpk;
406
}
407

    
408
AVPacketList *SeekAndDecodePacketStartingFrom(AVPacketList *p, PacketQueue *q, int* size)
409
{
410
        while(p) {
411
                        //check if audio packet has been already decoded
412
                        if(p->pkt.convergence_duration == 0) {
413
                                //not decoded yet, try to decode it
414
                                if( !DecodeEnqueuedAudio(&(p->pkt), q, size) ) {
415
                                        //it was not possible to decode this packet, return next one
416
                                        p = RemoveFromQueue(q, p);
417
                                }
418
                                else
419
                                        return p;
420
                        }
421
                        else
422
                                return p;
423
        }
424
        return NULL;
425
}
426

    
427
int PacketQueueGet(PacketQueue *q, AVPacket *pkt, short int av, int* size)
428
{
429
        //AVPacket tmp;
430
        AVPacketList *pkt1 = NULL;
431
        int ret=-1;
432
        int SizeToCopy=0;
433
        struct timeval now_tv;
434

    
435
        SDL_LockMutex(q->mutex);
436

    
437
#ifdef DEBUG_QUEUE
438
        printf("QUEUE: Get NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
439
#endif
440

    
441
        if((q->queueType==AUDIO && QueueFillingMode) || QueueStopped)
442
        {
443
                SDL_UnlockMutex(q->mutex);
444
                return -1;
445
        }
446

    
447
        if(av==1) { //somebody requested an audio packet, q is the audio queue
448
                //try to dequeue the first packet of the audio queue
449
                pkt1 = SeekAndDecodePacketStartingFrom(q->first_pkt, q, size);
450
                if(pkt1) { //yes we have them!
451
                        if(pkt1->pkt.size-AudioQueueOffset > dimAudioQ) {
452
                                //one packet is enough to give us the requested number of bytes by the audio_callback
453
#ifdef DEBUG_QUEUE_DEEP
454
                                printf("  AV=1 and Extract from the same packet\n");
455
#endif
456
                                pkt->size = dimAudioQ;
457
                                memcpy(pkt->data,pkt1->pkt.data+AudioQueueOffset,dimAudioQ);
458
                                pkt->dts = pkt1->pkt.dts;
459
                                pkt->pts = pkt1->pkt.pts;
460
                                pkt->stream_index = pkt1->pkt.stream_index;//1;
461
                                pkt->flags = 1;
462
                                pkt->pos = -1;
463
                                pkt->convergence_duration = -1;
464
#ifdef DEBUG_QUEUE_DEEP
465
                                printf("   Adjust timestamps Old = %lld New = %lld\n", pkt1->pkt.dts, (int64_t)(pkt1->pkt.dts + deltaAudioQ + deltaAudioQError));
466
#endif
467
                                int64_t Olddts=pkt1->pkt.dts;
468
                                pkt1->pkt.dts += deltaAudioQ + deltaAudioQError;
469
                                pkt1->pkt.pts += deltaAudioQ + deltaAudioQError;
470
                                deltaAudioQError=(float)Olddts + deltaAudioQ + deltaAudioQError - (float)pkt1->pkt.dts;
471
                                AudioQueueOffset += dimAudioQ;
472
#ifdef DEBUG_QUEUE_DEEP
473
                                printf("   deltaAudioQError = %f\n",deltaAudioQError);
474
#endif
475

    
476
                                ChunkerPlayerStats_UpdateAudioLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
477
                                
478
                                //update index of last frame extracted
479
                                q->last_frame_extracted = pkt->stream_index;
480
#ifdef DEBUG_AUDIO_BUFFER
481
                                printf("1: idx %d    \taqo %d    \tstc %d    \taqe %f    \tpsz %d\n", pkt1->pkt.stream_index, AudioQueueOffset, SizeToCopy, deltaAudioQError, pkt1->pkt.size);
482
#endif
483
                                ret = 1; //OK
484
                        }
485
                        else {
486
                                //we need bytes from two consecutive packets to satisfy the audio_callback
487
#ifdef DEBUG_QUEUE_DEEP
488
                                printf("  AV = 1 and Extract from 2 packets\n");
489
#endif
490
                                //check for a valid next packet since we will finish the current packet
491
                                //and also take some bytes from the next one
492
                                pkt1->next = SeekAndDecodePacketStartingFrom(pkt1->next, q, size);
493
                                if(pkt1->next) {
494
#ifdef DEBUG_QUEUE_DEEP
495
                                        printf("   we have a next...\n");
496
#endif
497
                                        pkt->size = dimAudioQ;
498
                                        pkt->dts = pkt1->pkt.dts;
499
                                        pkt->pts = pkt1->pkt.pts;
500
                                        pkt->stream_index = pkt1->pkt.stream_index;//1;
501
                                        pkt->flags = 1;
502
                                        pkt->pos = -1;
503
                                        pkt->convergence_duration = -1;
504
                                        {
505
                                                SizeToCopy=pkt1->pkt.size-AudioQueueOffset;
506
#ifdef DEBUG_QUEUE_DEEP
507
                                                printf("      SizeToCopy=%d\n",SizeToCopy);
508
#endif
509
                                                memcpy(pkt->data, pkt1->pkt.data+AudioQueueOffset, SizeToCopy);
510
                                                memcpy(pkt->data+SizeToCopy, pkt1->next->pkt.data, (dimAudioQ-SizeToCopy)*sizeof(uint8_t));
511
                                        }
512
#ifdef DEBUG_AUDIO_BUFFER
513
                                        printf("2: idx %d    \taqo %d    \tstc %d    \taqe %f    \tpsz %d\n", pkt1->pkt.stream_index, AudioQueueOffset, SizeToCopy, deltaAudioQError, pkt1->pkt.size);
514
#endif
515
                                }
516
#ifdef DEBUG_AUDIO_BUFFER
517
                                else {
518
                                        printf("2: NONEXT\n");
519
                                }
520
#endif
521
                                //HINT SEE before q->size -= SizeToCopy;
522
                                q->first_pkt = RemoveFromQueue(q, pkt1);
523

    
524
                                // Adjust timestamps
525
                                pkt1 = q->first_pkt;
526
                                if(pkt1) {
527
                                        int Offset=(dimAudioQ-SizeToCopy)*1000/(AudioSpecification.freq*2*AudioSpecification.channels);
528
                                        int64_t LastDts=pkt1->pkt.dts;
529
                                        pkt1->pkt.dts += Offset + deltaAudioQError;
530
                                        pkt1->pkt.pts += Offset + deltaAudioQError;
531
                                        deltaAudioQError = (float)LastDts + (float)Offset + deltaAudioQError - (float)pkt1->pkt.dts;
532
#ifdef DEBUG_QUEUE_DEEP
533
                                        printf("   Adjust timestamps Old = %lld New = %lld\n", LastDts, pkt1->pkt.dts);
534
#endif
535
                                        AudioQueueOffset = dimAudioQ - SizeToCopy;
536
                                        //SEE BEFORE HINT q->size -= AudioQueueOffset;
537
                                        ret = 1;
538
                                        
539
                                        ChunkerPlayerStats_UpdateAudioLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
540
                                }
541
                                else {
542
                                        AudioQueueOffset=0;
543
                                }
544
#ifdef DEBUG_QUEUE_DEEP
545
                                printf("   deltaAudioQError = %f\n",deltaAudioQError);
546
#endif
547
                                //update index of last frame extracted
548
                                q->last_frame_extracted = pkt->stream_index;
549
                        }
550
                }
551
        }
552
        else { //somebody requested a video packet, q is the video queue
553
                pkt1 = q->first_pkt;
554
                if(pkt1) {
555
#ifdef DEBUG_QUEUE_DEEP
556
                        printf("  AV not 1\n");
557
#endif
558
                        pkt->size = pkt1->pkt.size;
559
                        pkt->dts = pkt1->pkt.dts;
560
                        pkt->pts = pkt1->pkt.pts;
561
                        pkt->stream_index = pkt1->pkt.stream_index;
562
                        pkt->flags = pkt1->pkt.flags;
563
                        pkt->pos = pkt1->pkt.pos;
564
                        pkt->convergence_duration = pkt1->pkt.convergence_duration;
565
                        //*pkt = pkt1->pkt;
566
                        
567
                        if((pkt->data != NULL) && (pkt1->pkt.data != NULL))
568
                                memcpy(pkt->data, pkt1->pkt.data, pkt1->pkt.size);
569
                                
570
                        //HINT SEE BEFORE q->size -= pkt1->pkt.size;
571
                        q->first_pkt = RemoveFromQueue(q, pkt1);
572

    
573
                        ret = 1;
574
                        
575
                        ChunkerPlayerStats_UpdateVideoLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
576
                        
577
                        //update index of last frame extracted
578
                        q->last_frame_extracted = pkt->stream_index;
579
                        last_video_frame_extracted = q->last_frame_extracted;
580
                }
581
#ifdef DEBUG_QUEUE
582
                else {
583
                        printf("  VIDEO pk1 NULL!!!!\n");
584
                }
585
#endif
586
        }
587

    
588
        if(q->nb_packets==0 && q->queueType==AUDIO) {
589
                QueueFillingMode=1;
590
#ifdef DEBUG_QUEUE
591
                printf("QUEUE: Get FillingMode ON\n");
592
#endif
593
        }
594
#ifdef DEBUG_QUEUE
595
        printf("QUEUE: Get Last %s Frame Extracted = %d\n", (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
596
#endif
597

    
598
        SDL_UnlockMutex(q->mutex);
599
        return ret;
600
}
601

    
602
int AudioDecodeFrame(uint8_t *audio_buf, int buf_size) {
603
        //struct timeval now;
604
        int audio_pkt_size = 0;
605
        int compressed_size = 0;
606
        long long Now;
607
        short int DecodeAudio=0, SkipAudio=0;
608
        //int len1, data_size;
609

    
610
        //gettimeofday(&now,NULL);
611
        //Now = (now.tv_sec)*1000+now.tv_usec/1000;
612
        Now=(long long)SDL_GetTicks();
613
        struct timeval now_tv;
614

    
615
        if(QueueFillingMode || QueueStopped)
616
        {
617
                //SDL_LockMutex(timing_mutex);
618
                FirstTimeAudio=1;
619
                FirstTime = 1;
620
                //SDL_UnlockMutex(timing_mutex);
621
                return -1;
622
        }
623

    
624
        if((FirstTime==1 || FirstTimeAudio==1) && audioq.size>0) {
625
                if(audioq.first_pkt->pkt.pts>0)
626
                {
627
                        //SDL_LockMutex(timing_mutex);
628
                        DeltaTime=Now-(long long)(audioq.first_pkt->pkt.pts);
629
                        FirstTimeAudio = 0;
630
                        FirstTime = 0;
631
                        //SDL_UnlockMutex(timing_mutex);
632
#ifdef DEBUG_AUDIO 
633
                         printf("AUDIO: audio_decode_frame - DeltaTimeAudio=%lld\n",DeltaTime);
634
#endif
635
                }
636
        }
637

    
638
#ifdef DEBUG_AUDIO 
639
        if(audioq.first_pkt)
640
        {
641
                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);
642
                printf("AUDIO: QueueLen=%d ",(int)audioq.nb_packets);
643
                printf("AUDIO: QueueSize=%d\n",(int)audioq.size);
644
        }
645
        else
646
                printf("AUDIO: audio_decode_frame - Empty queue\n");
647
#endif
648

    
649
        gettimeofday(&now_tv, NULL);
650
        if(audioq.nb_packets>0)
651
        {
652
                if((long long)audioq.first_pkt->pkt.pts+DeltaTime<Now-(long long)MAX_TOLLERANCE)
653
                {
654
                        SkipAudio = 1;
655
                        DecodeAudio = 0;
656
                }
657
                else if((long long)audioq.first_pkt->pkt.pts+DeltaTime>=Now-(long long)MAX_TOLLERANCE &&
658
                        (long long)audioq.first_pkt->pkt.pts+DeltaTime<=Now+(long long)MAX_TOLLERANCE) {
659
                                SkipAudio = 0;
660
                                DecodeAudio = 1;
661
                }
662
        }
663
        
664
        while(SkipAudio==1 && audioq.size>0)
665
        {
666
                SkipAudio = 0;
667
#ifdef DEBUG_AUDIO
668
                 printf("AUDIO: skipaudio: queue size=%d\n",audioq.size);
669
#endif
670
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
671
                        return -1;
672
                }
673
                if(audioq.first_pkt)
674
                {
675
                        ChunkerPlayerStats_UpdateAudioSkipHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
676
                        
677
                        if((long long)audioq.first_pkt->pkt.pts+DeltaTime<Now-(long long)MAX_TOLLERANCE)
678
                        {
679
                                SkipAudio = 1;
680
                                DecodeAudio = 0;
681
                        }
682
                        else if((long long)audioq.first_pkt->pkt.pts+DeltaTime>=Now-(long long)MAX_TOLLERANCE &&
683
                                (long long)audioq.first_pkt->pkt.pts+DeltaTime<=Now+(long long)MAX_TOLLERANCE) {
684
                                        SkipAudio = 0;
685
                                        DecodeAudio = 1;
686
                        }
687
                }
688
        }
689
        if(DecodeAudio==1) {
690
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
691
                        return -1;
692
                }
693
                memcpy(audio_buf,AudioPkt.data,AudioPkt.size);
694
                audio_pkt_size = AudioPkt.size;
695
#ifdef DEBUG_AUDIO
696
                 printf("AUDIO: Decode audio\n");
697
#endif
698

    
699
                ChunkerPlayerStats_UpdateAudioPlayedHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
700
        }
701

    
702
        return audio_pkt_size;
703
}
704

    
705
int VideoCallback(void *valthread)
706
{
707
        //AVPacket pktvideo;
708
        AVCodecContext  *pCodecCtx;
709
        AVCodec         *pCodec;
710
        AVFrame         *pFrame;
711
        int frameFinished;
712
        AVPicture pict;
713
        long long Now;
714
        short int SkipVideo, DecodeVideo;
715
        
716
#ifdef SAVE_YUV
717
        static AVFrame* lastSavedFrameBuffer = NULL;
718
        
719
        if(!lastSavedFrameBuffer)
720
                lastSavedFrameBuffer = (AVFrame*) malloc(sizeof(AVFrame));
721
#endif
722

    
723
        //double frame_rate = 0.0,time_between_frames=0.0;
724
        //struct timeval now;
725

    
726
        //int wait_for_sync = 1;
727
        ThreadVal *tval;
728
        tval = (ThreadVal *)valthread;
729

    
730
        //frame_rate = tval->framerate;
731
        //time_between_frames = 1.e6 / frame_rate;
732
        //gettimeofday(&time_now,0);
733

    
734
        //frecon = fopen("recondechunk.mpg","wb");
735

    
736
        pCodecCtx=avcodec_alloc_context();
737
        pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
738
        //pCodecCtx->debug = FF_DEBUG_DCT_COEFF;
739
#ifdef H264_VIDEO_ENCODER
740
        pCodecCtx->codec_id  = CODEC_ID_H264;
741
        pCodecCtx->me_range = 16;
742
        pCodecCtx->max_qdiff = 4;
743
        pCodecCtx->qmin = 1;
744
        pCodecCtx->qmax = 30;
745
        pCodecCtx->qcompress = 0.6;
746
#else
747
        pCodecCtx->codec_id  = CODEC_ID_MPEG4;
748
#endif
749
        //pCodecCtx->bit_rate = 400000;
750
        // resolution must be a multiple of two
751
        pCodecCtx->width = tval->width;//176;//352;
752
        pCodecCtx->height = tval->height;//144;//288;
753

    
754
        // frames per second
755
        //pCodecCtx->time_base = (AVRational){1,25};
756
        //pCodecCtx->gop_size = 10; // emit one intra frame every ten frames
757
        //pCodecCtx->max_b_frames=1;
758
        pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
759
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
760

    
761
        if(pCodec==NULL) {
762
                fprintf(stderr, "Unsupported codec!\n");
763
                return -1; // Codec not found
764
        }
765
        if(avcodec_open(pCodecCtx, pCodec) < 0) {
766
                fprintf(stderr, "could not open codec\n");
767
                return -1; // Could not open codec
768
        }
769
        pFrame=avcodec_alloc_frame();
770
        if(pFrame==NULL) {
771
                printf("Memory error!!!\n");
772
                return -1;
773
        }
774
        
775
#ifdef DEBUG_VIDEO
776
         printf("VIDEO: video_callback entering main cycle\n");
777
#endif
778

    
779
        struct timeval now_tv;
780
        while(AVPlaying && !quit) {
781
                if(QueueFillingMode || QueueStopped)
782
                {
783
                        //SDL_LockMutex(timing_mutex);
784
                        FirstTime = 1;
785
                        //SDL_UnlockMutex(timing_mutex);
786
                        usleep(5000);
787
                        continue;
788
                }
789

    
790
                DecodeVideo = 0;
791
                SkipVideo = 0;
792
                Now=(long long)SDL_GetTicks();
793
                if(FirstTime==1 && videoq.size>0) {
794
                        if(videoq.first_pkt->pkt.pts>0)
795
                        {
796
                                //SDL_LockMutex(timing_mutex);
797
                                DeltaTime=Now-(long long)videoq.first_pkt->pkt.pts;
798
                                FirstTime = 0;
799
                                //SDL_UnlockMutex(timing_mutex);
800
                        }
801
#ifdef DEBUG_VIDEO 
802
                         printf("VIDEO: VideoCallback - DeltaTimeAudio=%lld\n",DeltaTime);
803
#endif
804
                }
805

    
806
#ifdef DEBUG_VIDEO 
807
                if(videoq.first_pkt)
808
                {
809
                        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);
810
                        printf("VIDEO: Index=%d ", (int)videoq.first_pkt->pkt.stream_index);
811
                        printf("VIDEO: QueueLen=%d ", (int)videoq.nb_packets);
812
                        printf("VIDEO: QueueSize=%d\n", (int)videoq.size);
813
                }
814
                else
815
                        printf("VIDEO: VideoCallback - Empty queue\n");
816
#endif
817

    
818
                if(videoq.nb_packets>0) {
819
                        if(((long long)videoq.first_pkt->pkt.pts+DeltaTime)<Now-(long long)MAX_TOLLERANCE)
820
                        {
821
                                SkipVideo = 1;
822
                                DecodeVideo = 0;
823
                        }
824
                        else 
825
                                if(((long long)videoq.first_pkt->pkt.pts+DeltaTime)>=Now-(long long)MAX_TOLLERANCE &&
826
                                   ((long long)videoq.first_pkt->pkt.pts+DeltaTime)<=Now+(long long)MAX_TOLLERANCE) {
827
                                        SkipVideo = 0;
828
                                        DecodeVideo = 1;
829
                                }
830
                                
831
                                // else (i.e. videoq.first_pkt->pkt.pts+DeltaTime>Now+MAX_TOLLERANCE)
832
                                // do nothing and continue
833
                }
834
#ifdef DEBUG_VIDEO
835
                printf("VIDEO: skipvideo:%d decodevideo:%d\n",SkipVideo,DecodeVideo);
836
#endif
837
                gettimeofday(&now_tv, NULL);
838
                
839
                while(SkipVideo==1 && videoq.size>0)
840
                {
841
                        SkipVideo = 0;
842
#ifdef DEBUG_VIDEO 
843
                         printf("VIDEO: Skip Video\n");
844
#endif
845
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) < 0) {
846
                                break;
847
                        }
848

    
849
                        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
850
                        
851
                        // sometimes assertion fails, maybe the decoder change the frame type
852
                        //~ if(LastSourceIFrameDistance == 0)
853
                                //~ assert(pFrame->pict_type == 1);
854

    
855
                        if(videoq.first_pkt)
856
                        {
857
                                if((long long)videoq.first_pkt->pkt.pts+DeltaTime<Now-(long long)MAX_TOLLERANCE)
858
                                {
859
                                        SkipVideo = 1;
860
                                        DecodeVideo = 0;
861
                                }
862
                                else if((long long)videoq.first_pkt->pkt.pts+DeltaTime>=Now-(long long)MAX_TOLLERANCE &&
863
                                                                (long long)videoq.first_pkt->pkt.pts+DeltaTime<=Now+(long long)MAX_TOLLERANCE) {
864
                                        SkipVideo = 0;
865
                                        DecodeVideo = 1;
866
                                }
867
                        }
868
                        
869
                        ChunkerPlayerStats_UpdateVideoSkipHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
870
                        
871
                        /*if(pFrame->pict_type == 1)
872
                        {
873
                                int i1;
874
                                // every 23 items (23 is the qstride field in the AVFrame struct) there is 1 zero.
875
                                // 396/23 = 17 => 396 macroblocks + 17 zeros = 413 items
876
                                for(i1=0; i1< 413; i1++)
877
                                        fprintf(qscaletable_file, "%d\t", (int)pFrame->qscale_table[i1]);
878
                                fprintf(qscaletable_file, "\n");
879
                        }*/
880
                        
881
                        //ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size);
882
                }
883

    
884
                if(DecodeVideo==1) {
885
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) > 0) {
886
                                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
887

    
888
                                if(frameFinished)
889
                                { // it must be true all the time else error
890
#ifdef DEBUG_VIDEO
891
                                        printf("VIDEO: FrameFinished\n");
892
#endif
893
                                        decoded_vframes++;
894
                                        
895
                                        // sometimes assertion fails, maybe the decoder change the frame type
896
                                        //~ if(LastSourceIFrameDistance == 0)
897
                                                //~ assert(pFrame->pict_type == 1);
898
#ifdef SAVE_YUV
899
                                        if(LastSavedVFrame == -1)
900
                                        {
901
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
902
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
903
                                                LastSavedVFrame = VideoPkt.stream_index;
904
                                        }
905
                                        else if(LastSavedVFrame == (VideoPkt.stream_index-1))
906
                                        {
907
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
908
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
909
                                                LastSavedVFrame = VideoPkt.stream_index;
910
                                        }
911
                                        else if(LastSavedVFrame >= 0)
912
                                        {
913
                                                while(LastSavedVFrame < (VideoPkt.stream_index-1))
914
                                                {
915
                                                        SaveFrame(lastSavedFrameBuffer, pCodecCtx->width, pCodecCtx->height);
916
                                                }
917

    
918
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
919
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
920
                                                LastSavedVFrame = VideoPkt.stream_index;
921
                                        }
922
#endif
923
                                        ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
924

    
925
                                        if(SilentMode)
926
                                                continue;
927

    
928
                                        // Lock SDL_yuv_overlay
929
                                        if(SDL_MUSTLOCK(MainScreen)) {
930
                                                if(SDL_LockSurface(MainScreen) < 0) {
931
                                                        continue;
932
                                                }
933
                                        }
934

    
935
                                        if(SDL_LockYUVOverlay(YUVOverlay) < 0) {
936
                                                if(SDL_MUSTLOCK(MainScreen)) {
937
                                                        SDL_UnlockSurface(MainScreen);
938
                                                }
939
                                                continue;
940
                                        }
941
                                        
942
                                        pict.data[0] = YUVOverlay->pixels[0];
943
                                        pict.data[1] = YUVOverlay->pixels[2];
944
                                        pict.data[2] = YUVOverlay->pixels[1];
945

    
946
                                        pict.linesize[0] = YUVOverlay->pitches[0];
947
                                        pict.linesize[1] = YUVOverlay->pitches[2];
948
                                        pict.linesize[2] = YUVOverlay->pitches[1];
949

    
950
                                        if(img_convert_ctx == NULL) {
951
                                                img_convert_ctx = sws_getContext(tval->width, tval->height, PIX_FMT_YUV420P, InitRect->w, InitRect->h, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
952
                                                if(img_convert_ctx == NULL) {
953
                                                        fprintf(stderr, "Cannot initialize the conversion context!\n");
954
                                                        exit(1);
955
                                                }
956
                                        }
957
                                        
958
#ifdef VIDEO_DEINTERLACE
959
                                        avpicture_deinterlace(
960
                                                (AVPicture*) pFrame,
961
                                                (const AVPicture*) pFrame,
962
                                                pCodecCtx->pix_fmt,
963
                                                tval->width, tval->height);
964
#endif
965
                                        
966
                                        // let's draw the data (*yuv[3]) on a SDL screen (*screen)
967
                                        sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, tval->height, pict.data, pict.linesize);
968
                                        SDL_UnlockYUVOverlay(YUVOverlay);
969
                                        // Show, baby, show!
970
                                        SDL_LockMutex(OverlayMutex);
971
                                        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
972
                                        SDL_UnlockMutex(OverlayMutex);
973

    
974
                                        //redisplay logo
975
                                        /**SDL_BlitSurface(image, NULL, MainScreen, &dest);*/
976
                                        /* Update the screen area just changed */
977
                                        /**SDL_UpdateRects(MainScreen, 1, &dest);*/
978

    
979
                                        if(SDL_MUSTLOCK(MainScreen)) {
980
                                                SDL_UnlockSurface(MainScreen);
981
                                        }
982
                                } //if FrameFinished
983
                                else
984
                                {
985
                                        ChunkerPlayerStats_UpdateVideoLossHistory(&(videoq.PacketHistory), VideoPkt.stream_index+1, videoq.last_frame_extracted-1);
986
                                }
987
                        } // if packet_queue_get
988
                } //if DecodeVideo=1
989

    
990
                usleep(5000);
991
        }
992
        avcodec_close(pCodecCtx);
993
        av_free(pCodecCtx);
994
        av_free(pFrame);
995
        //fclose(frecon);
996
#ifdef DEBUG_VIDEO
997
         printf("VIDEO: video callback end\n");
998
#endif
999

    
1000
#ifdef SAVE_YUV
1001
        if(!lastSavedFrameBuffer)
1002
                free(lastSavedFrameBuffer);
1003
        
1004
        lastSavedFrameBuffer = NULL;
1005
#endif
1006

    
1007
        return 0;
1008
}
1009

    
1010
void AudioCallback(void *userdata, Uint8 *stream, int len)
1011
{
1012
        //AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
1013
        int audio_size;
1014

    
1015
        static uint8_t audio_buf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
1016

    
1017
        audio_size = AudioDecodeFrame(audio_buf, sizeof(audio_buf));
1018
        
1019
        if(SilentMode != 1)
1020
                if(audio_size != len) {
1021
                        memset(stream, 0, len);
1022
                } else {
1023
                        memcpy(stream, (uint8_t *)audio_buf, len);
1024
                }
1025
}
1026

    
1027
void SaveFrame(AVFrame *pFrame, int width, int height)
1028
{
1029
        FILE *pFile;
1030
        int  y;
1031
  
1032
         // Open file
1033
        pFile=fopen(YUVFileName, "ab");
1034
        if(pFile==NULL)
1035
                return;
1036
  
1037
        // Write header
1038
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1039
  
1040
        // Write Y data
1041
        for(y=0; y<height; y++)
1042
                  fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile);
1043
        // Write U data
1044
        for(y=0; y<height/2; y++)
1045
                  fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile);
1046
        // Write V data
1047
        for(y=0; y<height/2; y++)
1048
                  fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile);
1049
  
1050
        // Close file
1051
        fclose(pFile);
1052
}
1053

    
1054
int ChunkerPlayerCore_IsRunning()
1055
{
1056
        return AVPlaying;
1057
}
1058

    
1059
void ChunkerPlayerCore_Play()
1060
{
1061
        if(AVPlaying) return;
1062
        AVPlaying = 1;
1063
        
1064
        SDL_PauseAudio(0);
1065
        video_thread = SDL_CreateThread(VideoCallback, &VideoCallbackThreadParams);
1066
        ChunkerPlayerStats_Init();
1067
        stats_thread = SDL_CreateThread(CollectStatisticsThread, NULL);
1068
        
1069
        decoded_vframes = 0;
1070
        LastSavedVFrame = -1;
1071
}
1072

    
1073
void ChunkerPlayerCore_Stop()
1074
{
1075
        if(!AVPlaying) return;
1076
        
1077
        AVPlaying = 0;
1078
        
1079
        // Stop audio&video playback
1080
        SDL_WaitThread(video_thread, NULL);
1081
        SDL_WaitThread(stats_thread, NULL);
1082
        SDL_PauseAudio(1);        
1083
        SDL_CloseAudio();
1084
        
1085
        if(YUVOverlay != NULL)
1086
        {
1087
                SDL_FreeYUVOverlay(YUVOverlay);
1088
                YUVOverlay = NULL;
1089
        }
1090
        
1091
        PacketQueueReset(&audioq);
1092
        PacketQueueReset(&videoq);
1093
        
1094
        avcodec_close(aCodecCtx);
1095
        av_free(aCodecCtx);
1096
        free(AudioPkt.data);
1097
        free(VideoPkt.data);
1098
        free(outbuf_audio);
1099
        free(InitRect);
1100
        
1101
        /*
1102
        * Sleep two buffers' worth of audio before closing, in order
1103
        *  to allow the playback to finish. This isn't always enough;
1104
        *   perhaps SDL needs a way to explicitly wait for device drain?
1105
        */
1106
        int delay = 2 * 1000 * CurrentAudioSamples / CurrentAudioFreq;
1107
        // printf("SDL_Delay(%d)\n", delay*10);
1108
        SDL_Delay(delay*10);
1109
}
1110

    
1111
void ChunkerPlayerCore_Pause()
1112
{
1113
        if(!AVPlaying) return;
1114
        
1115
        AVPlaying = 0;
1116
        
1117
        // Stop audio&video playback
1118
        SDL_WaitThread(video_thread, NULL);
1119
        SDL_PauseAudio(1);
1120
        
1121
        PacketQueueReset(&audioq);
1122
        PacketQueueReset(&videoq);
1123
}
1124

    
1125
int ChunkerPlayerCore_AudioEnded()
1126
{
1127
        return (audioq.nb_packets==0 && audioq.last_frame_extracted>0);
1128
}
1129

    
1130
void ChunkerPlayerCore_ResetAVQueues()
1131
{
1132
#ifdef DEBUG_QUEUE
1133
        printf("QUEUE: MAIN SHOULD RESET\n");
1134
#endif
1135
        PacketQueueReset(&audioq);
1136
        PacketQueueReset(&videoq);
1137
}
1138

    
1139
int ChunkerPlayerCore_EnqueueBlocks(const uint8_t *block, const int block_size)
1140
{
1141
#ifdef EMULATE_CHUNK_LOSS
1142
        static time_t loss_cycle_start_time = 0, now = 0;
1143
        static int early_losses = 0;
1144
        static int clp_frames = 0;
1145
        
1146
        if(ScheduledChunkLosses)
1147
        {
1148
                static unsigned int random_threshold;
1149
                now=time(NULL);
1150
                if(!loss_cycle_start_time)
1151
                        loss_cycle_start_time = now;
1152
                        
1153
                if(((now-loss_cycle_start_time) >= ScheduledChunkLosses[((CurrChunkLossIndex+1)%NScheduledChunkLosses)].Time) && (NScheduledChunkLosses>1 || CurrChunkLossIndex==-1))
1154
                {
1155
                        CurrChunkLossIndex = ((CurrChunkLossIndex+1)%NScheduledChunkLosses);
1156
                        if(CurrChunkLossIndex == (NScheduledChunkLosses-1))
1157
                                loss_cycle_start_time = now;
1158
                        
1159
                        if(ScheduledChunkLosses[CurrChunkLossIndex].Value == -1)
1160
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].MinValue + (rand() % (ScheduledChunkLosses[CurrChunkLossIndex].MaxValue-ScheduledChunkLosses[CurrChunkLossIndex].MinValue));
1161
                        else
1162
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].Value;
1163
                        
1164
                        printf("new ScheduledChunkLoss, time: %d, value: %d\n", (int)ScheduledChunkLosses[CurrChunkLossIndex].Time, random_threshold);
1165
                }
1166
        
1167
                if(clp_frames > 0)
1168
                {
1169
                        clp_frames--;
1170
                        return PLAYER_FAIL_RETURN;
1171
                }
1172
                if((rand() % 100) < random_threshold)
1173
                {
1174
                        if(early_losses > 0)
1175
                early_losses--;
1176
            else
1177
            {
1178
                clp_frames=early_losses=(ScheduledChunkLosses[CurrChunkLossIndex].Burstiness-1);
1179
                return PLAYER_FAIL_RETURN;
1180
            }
1181
                }
1182
        }
1183
#endif
1184

    
1185
        Chunk *gchunk = NULL;
1186
        int decoded_size = -1;
1187
        uint8_t *tempdata, *buffer;
1188
        int j;
1189
        Frame *frame = NULL;
1190
        AVPacket packet, packetaudio;
1191

    
1192
        uint16_t *audio_bufQ = NULL;
1193

    
1194
        //the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
1195
        static int sizeFrameHeader = 5*sizeof(int32_t);
1196
        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;
1197

    
1198
        static int chunks_out_of_order = 0;
1199
        static int last_chunk_id = -1;
1200

    
1201
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
1202
        if(!audio_bufQ) {
1203
                printf("Memory error in audio_bufQ!\n");
1204
                return PLAYER_FAIL_RETURN;
1205
        }
1206

    
1207
        gchunk = (Chunk *)malloc(sizeof(Chunk));
1208
        if(!gchunk) {
1209
                printf("Memory error in gchunk!\n");
1210
                av_free(audio_bufQ);
1211
                return PLAYER_FAIL_RETURN;
1212
        }
1213

    
1214
        decoded_size = decodeChunk(gchunk, block, block_size);
1215

    
1216
        if(last_chunk_id == -1)
1217
                last_chunk_id = gchunk->id;
1218

    
1219
        if(gchunk->id > (last_chunk_id+1)) {
1220
                chunks_out_of_order += gchunk->id - last_chunk_id - 1;
1221
        }
1222
        last_chunk_id = gchunk->id;
1223

    
1224
#ifdef DEBUG_CHUNKER
1225
        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);
1226
#endif
1227
  if(decoded_size < 0) {
1228
                //HINT here i should differentiate between various return values of the decode
1229
                //in order to free what has been allocated there
1230
                printf("chunk probably corrupted!\n");
1231
                av_free(audio_bufQ);
1232
                free(gchunk);
1233
                return PLAYER_FAIL_RETURN;
1234
        }
1235

    
1236
        frame = (Frame *)malloc(sizeof(Frame));
1237
        if(!frame) {
1238
                printf("Memory error in Frame!\n");
1239
                if(gchunk) {
1240
                        if(gchunk->attributes) {
1241
                                free(gchunk->attributes);
1242
                        }
1243
                        free(gchunk);
1244
                }
1245
                av_free(audio_bufQ);
1246
                return PLAYER_FAIL_RETURN;
1247
        }
1248

    
1249
        tempdata = gchunk->data; //let it point to first frame of payload
1250
        j=gchunk->size;
1251
        while(j>0 && !quit) {
1252
                frame->number = bit32_encoded_pull(tempdata);
1253
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1254
                frame->timestamp.tv_sec = bit32_encoded_pull(tempdata);
1255
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1256
                frame->timestamp.tv_usec = bit32_encoded_pull(tempdata);
1257
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1258
                frame->size = bit32_encoded_pull(tempdata);
1259
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1260
                frame->type = bit32_encoded_pull(tempdata);
1261
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1262

    
1263
                buffer = tempdata; // here coded frame information
1264
                tempdata += frame->size; //let it point to the next frame
1265

    
1266
                if(frame->type < 5) { // video frame
1267
                        av_init_packet(&packet);
1268
                        packet.data = buffer;//video_bufQ;
1269
                        packet.size = frame->size;
1270
                        packet.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1271
                        packet.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1272
                        packet.stream_index = frame->number; // use of stream_index for number frame
1273
                        //packet.duration = frame->timestamp.tv_sec;
1274
                        if(packet.size > 0)
1275
                                ChunkerPlayerCore_PacketQueuePut(&videoq, &packet); //the _put makes a copy of the packet
1276

    
1277
#ifdef DEBUG_SOURCE
1278
                        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);
1279
#endif
1280
                }
1281
                else if(frame->type == 5) { // audio frame
1282
                        av_init_packet(&packetaudio);
1283
                        packetaudio.data = buffer;
1284
                        packetaudio.size = frame->size;
1285
                        packetaudio.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1286
                        packetaudio.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1287
                        //packetaudio.duration = frame->timestamp.tv_sec;
1288
                        packetaudio.stream_index = frame->number; // use of stream_index for number frame
1289
                        packetaudio.flags = 1;
1290
                        packetaudio.pos = -1;
1291

    
1292
                        //instead of -1, in order to signal it is not decoded yet
1293
                        packetaudio.convergence_duration = 0;
1294

    
1295
                        // insert the audio frame into the queue
1296
                        if(packetaudio.size > 0)
1297
                                ChunkerPlayerCore_PacketQueuePut(&audioq, &packetaudio);//makes a copy of the packet so i can free here
1298

    
1299
#ifdef DEBUG_SOURCE
1300
                        printf("SOURCE: Insert audio in queue pts=%lld sindex:%d\n", packetaudio.pts, packetaudio.stream_index);
1301
#endif
1302
                }
1303
                else {
1304
                        printf("SOURCE: Unknown frame type %d. Size %d\n", frame->type, frame->size);
1305
                }
1306
                if(frame->size > 0)
1307
                        j = j - sizeFrameHeader - frame->size;
1308
                else {
1309
                        printf("SOURCE: Corrupt frames (size %d) in chunk. Skipping it...\n", frame->size);
1310
                        j = -1;
1311
                }
1312
        }
1313
        //chunk ingestion terminated!
1314
        if(gchunk) {
1315
                if(gchunk->attributes) {
1316
                        free(gchunk->attributes);
1317
                }
1318
                if(gchunk->data)
1319
                        free(gchunk->data);
1320
                free(gchunk);
1321
        }
1322
        if(frame)
1323
                free(frame);
1324
        if(audio_bufQ)
1325
                av_free(audio_bufQ);
1326
                
1327
        return PLAYER_OK_RETURN;
1328
}
1329

    
1330
void ChunkerPlayerCore_SetupOverlay(int width, int height)
1331
{
1332
        // if(!MainScreen && !SilentMode)
1333
        // {
1334
                // printf("Cannot find main screen, exiting...\n");
1335
                // exit(1);
1336
        // }
1337
        
1338
        if(SilentMode)
1339
                return;
1340
                
1341
        SDL_LockMutex(OverlayMutex);
1342
        if(YUVOverlay != NULL)
1343
        {
1344
                SDL_FreeYUVOverlay(YUVOverlay);
1345
                YUVOverlay = NULL;
1346
        }
1347
        
1348
        // create video overlay for display of video frames
1349
        // printf("SDL_CreateYUVOverlay(%d, %d, SDL_YV12_OVERLAY, MainScreen)\n", width, height);
1350
        YUVOverlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, MainScreen);
1351
        // YUVOverlay = SDL_CreateYUVOverlay(OverlayRect.w, OverlayRect.h, SDL_YV12_OVERLAY, MainScreen);
1352
        if ( YUVOverlay == NULL )
1353
        {
1354
                fprintf(stderr,"SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError());
1355
                exit(1);
1356
        }
1357

    
1358
        if ( YUVOverlay->hw_overlay )
1359
                fprintf(stderr,"SDL: Using hardware overlay.\n");
1360
        // OverlayRect.x = (screen_w - width) / 2;
1361
        
1362
        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
1363
        
1364
        SDL_UnlockMutex(OverlayMutex);
1365
}
1366

    
1367
int CollectStatisticsThread(void *params)
1368
{
1369
        struct timeval last_stats_evaluation, now, last_trace, last_qoe_evaluation;
1370
        gettimeofday(&last_stats_evaluation, NULL);
1371
        last_trace = last_stats_evaluation;
1372
        last_qoe_evaluation = last_stats_evaluation;
1373
        
1374
        double video_qdensity;
1375
        double audio_qdensity;
1376
        char audio_stats_text[255];
1377
        char video_stats_text[255];
1378
        int loss_changed = 0;
1379
        int density_changed = 0;
1380
        SStats audio_statistics, video_statistics;
1381
        double qoe = 0;
1382
        int sleep_time = STATS_THREAD_GRANULARITY*1000;
1383
        
1384
        while(AVPlaying && !quit)
1385
        {
1386
                usleep(sleep_time);
1387
                
1388
                gettimeofday(&now, NULL);
1389
                
1390
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_stats_evaluation.tv_sec*1000)+(last_stats_evaluation.tv_usec/1000))) > GUI_PRINTSTATS_INTERVAL)
1391
                {
1392
                        // estimate audio queue stats
1393
                        int audio_stats_changed = ChunkerPlayerStats_GetStats(&(audioq.PacketHistory), &audio_statistics);
1394
                        
1395
                        // estimate video queue stats
1396
                        int video_stats_changed = ChunkerPlayerStats_GetStats(&(videoq.PacketHistory), &video_statistics);
1397

    
1398
#ifdef DEBUG_STATS
1399
                        printf("VIDEO: %d Kbit/sec; ", video_statistics.Bitrate);
1400
                        printf("AUDIO: %d Kbit/sec\n", audio_statistics.Bitrate);
1401
#endif
1402

    
1403
                        // QUEUE DENSITY EVALUATION
1404
                        if((audioq.last_pkt != NULL) && (audioq.first_pkt != NULL))
1405
                                if(audioq.last_pkt->pkt.stream_index >= audioq.first_pkt->pkt.stream_index)
1406
                                {
1407
                                        //plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1408
                                        audio_qdensity = (double)audioq.nb_packets / (double)(audioq.last_pkt->pkt.stream_index - audioq.first_pkt->pkt.stream_index + 1) * 100.0;
1409
                                }
1410
                        
1411
                        if((videoq.last_pkt != NULL) && (videoq.first_pkt != NULL))
1412
                                if(videoq.last_pkt->pkt.stream_index >= videoq.first_pkt->pkt.stream_index)
1413
                                {
1414
                                        // plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1415
                                        video_qdensity = (double)videoq.nb_packets / (double)(videoq.last_pkt->pkt.stream_index - videoq.first_pkt->pkt.stream_index + 1) * 100.0;
1416
                                }
1417
                        
1418
                        if(LogTraces)
1419
                        {
1420
                                ChunkerPlayerStats_PrintHistoryTrace(&(audioq.PacketHistory), AudioTraceFilename);
1421
                                ChunkerPlayerStats_PrintHistoryTrace(&(videoq.PacketHistory), VideoTraceFilename);
1422
                                
1423
                                if(SilentMode != 1 && SilentMode != 2)
1424
                                        ChunkerPlayerStats_PrintContextFile();
1425
                        }
1426

    
1427
                        // PRINT STATISTICS ON GUI
1428
                        if(!Audio_ON)
1429
                                sprintf(audio_stats_text, "AUDIO MUTED");
1430
                        else if(audio_stats_changed)
1431
                                sprintf(audio_stats_text, "[AUDIO] qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)", (int)audio_qdensity, (int)audio_statistics.Lossrate, audioq.PacketHistory.LostCount, audio_statistics.Skiprate, audioq.PacketHistory.SkipCount);
1432
                        else
1433
                                sprintf(audio_stats_text, "waiting for incoming audio packets...");
1434

    
1435
                        if(video_stats_changed)
1436
                        {
1437
                                char est_psnr_string[255];
1438
                                sprintf(est_psnr_string, "");
1439
                                if(qoe)
1440
                                        sprintf(est_psnr_string, " - Est. Mean PSNR: %.1f db", (float)qoe);
1441

    
1442
                                sprintf(video_stats_text, "[VIDEO] qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)%s", (int)video_qdensity, video_statistics.Lossrate, videoq.PacketHistory.LostCount, video_statistics.Skiprate, videoq.PacketHistory.SkipCount, est_psnr_string);
1443
                        }
1444
                        else
1445
                                sprintf(video_stats_text, "waiting for incoming video packets...");
1446
                        
1447
                        if(qoe)
1448
                            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)));
1449
                        else
1450
                            ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text,LED_GREEN);
1451
                        
1452

    
1453
                        last_stats_evaluation = now;
1454
                }
1455
                
1456
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_qoe_evaluation.tv_sec*1000)+(last_qoe_evaluation.tv_usec/1000))) > EVAL_QOE_INTERVAL)
1457
                {
1458
                        // ESTIMATE QoE
1459
                        ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), &qoe);
1460
                        
1461
#ifdef DEBUG_STATS
1462
                        printf("QoE index: %f\n", (float) qoe);
1463
#endif
1464
                        last_qoe_evaluation = now;
1465
                }
1466
        }
1467
}