Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_core.c @ e11386c0

History | View | Annotate | Download (42 KB)

1
#include "player_defines.h"
2
#include "chunker_player.h"
3
#include "player_gui.h"
4
#include "player_core.h"
5
#include "player_stats.h"
6
#include <assert.h>
7
#include <time.h>
8

    
9
void SaveFrame(AVFrame *pFrame, int width, int height);
10
int VideoCallback(void *valthread);
11
int CollectStatisticsThread(void *params);
12
void AudioCallback(void *userdata, Uint8 *stream, int len);
13
void PacketQueueClearStats(PacketQueue *q);
14
void ChunkerPlayerCore_Pause();
15

    
16
//int lastCheckedVideoFrame = -1;
17
long int last_video_frame_extracted = -1;
18

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

    
46
void PacketQueueReset(PacketQueue *q)
47
{
48
        AVPacketList *tmp,*tmp1;
49
#ifdef DEBUG_QUEUE
50
        printf("QUEUE: RESET BEGIN: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
51
#endif
52
        SDL_LockMutex(q->mutex);
53

    
54
        tmp = q->first_pkt;
55
        while(tmp) {
56
                tmp1 = tmp;
57
                tmp = tmp->next;
58
                av_free_packet(&(tmp1->pkt));
59
                av_free(tmp1);
60
#ifdef DEBUG_QUEUE
61
                printf("F ");
62
#endif
63
                q->PacketHistory.LostCount++;
64
        }
65
#ifdef DEBUG_QUEUE
66
        printf("\n");
67
#endif
68

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

    
89
void PacketQueueClearStats(PacketQueue *q)
90
{
91
        sprintf(q->stats_message, "%s", "\n");
92
        int i;
93
        memset((void*)q->PacketHistory.History, 0, sizeof(SHistoryElement)*QUEUE_HISTORY_SIZE);
94
        for(i=0; i<QUEUE_HISTORY_SIZE; i++)
95
        {
96
                q->PacketHistory.History[i].Statistics.LastIFrameDistance = -1;
97
                q->PacketHistory.History[i].Status = -1;
98
        }
99
        q->PacketHistory.Index = q->PacketHistory.LogIndex = 0;
100
        q->PacketHistory.Index = q->PacketHistory.QoEIndex = 0;
101
        q->PacketHistory.LostCount = q->PacketHistory.PlayedCount = q->PacketHistory.SkipCount = 0;
102
}
103

    
104
int ChunkerPlayerCore_PacketQueuePut(PacketQueue *q, AVPacket *pkt)
105
{
106
        //~ printf("\tSTREAM_INDEX=%d\n", pkt->stream_index);
107
        short int skip = 0;
108
        AVPacketList *pkt1, *tmp, *prevtmp;
109
        int res = 0;
110

    
111
        if(q->nb_packets > queue_filling_threshold*QUEUE_MAX_GROW_FACTOR) {
112
#ifdef DEBUG_QUEUE
113
                printf("QUEUE: PUT i have TOO MANY packets %d Type=%s, RESETTING\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
114
#endif
115
                PacketQueueReset(q);
116
        }
117

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

    
127
        if(!pkt1) {
128
                av_free_packet(pkt);
129
                return -1;
130
        }
131
        pkt1->pkt = *pkt;
132
        pkt1->next = NULL;
133
        
134
        static time_t last_auto_switch = 0;
135

    
136
        // file streaming loop detected => re-tune channel and start grabbing statistics
137
        if(
138
                (pkt->stream_index < last_video_frame_extracted)
139
                && (pkt->stream_index <= RESTART_FRAME_NUMBER_THRESHOLD)
140
                && ((time(NULL) - last_auto_switch) > 10)
141
        )
142
        {
143
                last_auto_switch = time(NULL);
144
                SDL_LockMutex(q->mutex);
145
                ReTune(&(Channels[SelectedChannel]));
146
                SDL_UnlockMutex(q->mutex);
147
        }
148

    
149
        else
150
        {
151
                SDL_LockMutex(q->mutex);
152

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

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

    
218
        return res;
219
}
220

    
221
int ChunkerPlayerCore_InitCodecs(int width, int height, int sample_rate, short int audio_channels)
222
{
223
        // some initializations
224
        QueueStopped = 0;
225
        AudioQueueOffset=0;
226
        AVPlaying = 0;
227
        GotSigInt = 0;
228
        FirstTimeAudio=1;
229
        FirstTime = 1;
230
        deltaAudioQError=0;
231
        InitRect = NULL;
232
        img_convert_ctx = NULL;
233
        
234
        SDL_AudioSpec wanted_spec;
235
        AVCodec         *aCodec;
236
        
237
        memset(&VideoCallbackThreadParams, 0, sizeof(ThreadVal));
238
        
239
        VideoCallbackThreadParams.width = width;
240
        VideoCallbackThreadParams.height = height;
241

    
242
        // Register all formats and codecs
243
        av_register_all();
244

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

    
281
#ifdef DEBUG_AUDIO
282
        printf("freq:%d\n",AudioSpecification.freq);
283
        printf("format:%d\n",AudioSpecification.format);
284
        printf("channels:%d\n",AudioSpecification.channels);
285
        printf("silence:%d\n",AudioSpecification.silence);
286
        printf("samples:%d\n",AudioSpecification.samples);
287
        printf("size:%d\n",AudioSpecification.size);
288
        printf("deltaAudioQ: %f\n",deltaAudioQ);
289
#endif
290

    
291
        outbuf_audio = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
292

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

    
325
int DecodeEnqueuedAudio(AVPacket *pkt, PacketQueue *q, int* size)
326
{
327
        uint16_t *audio_bufQ = NULL;
328
        int16_t *dataQ = NULL;
329
        int data_sizeQ = AVCODEC_MAX_AUDIO_FRAME_SIZE;
330
        int lenQ;
331
        int ret = 0;
332

    
333
        //set the flag to decoded anyway        
334
        pkt->convergence_duration = -1;
335

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

    
382
/**
383
 * removes a packet from the list and returns the next
384
 * */
385
AVPacketList *RemoveFromQueue(PacketQueue *q, AVPacketList *p)
386
{
387
        AVPacketList *retpk = p->next;
388
        q->nb_packets--;
389
        //adjust size here and not in the various cases of the dequeue
390
        q->size -= p->pkt.size;
391
        if(&p->pkt)
392
        {
393
                av_free_packet(&p->pkt);
394
        }
395
        if(p)
396
                av_free(p);
397
        return retpk;
398
}
399

    
400
AVPacketList *SeekAndDecodePacketStartingFrom(AVPacketList *p, PacketQueue *q, int* size)
401
{
402
        while(p) {
403
                        //check if audio packet has been already decoded
404
                        if(p->pkt.convergence_duration == 0) {
405
                                //not decoded yet, try to decode it
406
                                if( !DecodeEnqueuedAudio(&(p->pkt), q, size) ) {
407
                                        //it was not possible to decode this packet, return next one
408
                                        p = RemoveFromQueue(q, p);
409
                                }
410
                                else
411
                                        return p;
412
                        }
413
                        else
414
                                return p;
415
        }
416
        return NULL;
417
}
418

    
419
int PacketQueueGet(PacketQueue *q, AVPacket *pkt, short int av, int* size)
420
{
421
        //AVPacket tmp;
422
        AVPacketList *pkt1 = NULL;
423
        int ret=-1;
424
        int SizeToCopy=0;
425
        struct timeval now_tv;
426

    
427
        SDL_LockMutex(q->mutex);
428

    
429
#ifdef DEBUG_QUEUE
430
        printf("QUEUE: Get NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
431
#endif
432

    
433
        if((q->queueType==AUDIO && QueueFillingMode) || QueueStopped)
434
        {
435
                SDL_UnlockMutex(q->mutex);
436
                return -1;
437
        }
438

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

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

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

    
565
                        ret = 1;
566
                        
567
                        ChunkerPlayerStats_UpdateVideoLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
568
                        
569
                        //update index of last frame extracted
570
                        q->last_frame_extracted = pkt->stream_index;
571
                        last_video_frame_extracted = q->last_frame_extracted;
572
                }
573
#ifdef DEBUG_QUEUE
574
                else {
575
                        printf("  VIDEO pk1 NULL!!!!\n");
576
                }
577
#endif
578
        }
579

    
580
        if(q->nb_packets==0 && q->queueType==AUDIO) {
581
                QueueFillingMode=1;
582
#ifdef DEBUG_QUEUE
583
                printf("QUEUE: Get FillingMode ON\n");
584
#endif
585
        }
586
#ifdef DEBUG_QUEUE
587
        printf("QUEUE: Get Last %s Frame Extracted = %d\n", (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
588
#endif
589

    
590
        SDL_UnlockMutex(q->mutex);
591
        return ret;
592
}
593

    
594
int AudioDecodeFrame(uint8_t *audio_buf, int buf_size) {
595
        //struct timeval now;
596
        int audio_pkt_size = 0;
597
        int compressed_size = 0;
598
        long long Now;
599
        short int DecodeAudio=0, SkipAudio=0;
600
        //int len1, data_size;
601

    
602
        //gettimeofday(&now,NULL);
603
        //Now = (now.tv_sec)*1000+now.tv_usec/1000;
604
        Now=(long long)SDL_GetTicks();
605
        struct timeval now_tv;
606

    
607
        if(QueueFillingMode || QueueStopped)
608
        {
609
                //SDL_LockMutex(timing_mutex);
610
                FirstTimeAudio=1;
611
                FirstTime = 1;
612
                //SDL_UnlockMutex(timing_mutex);
613
                return -1;
614
        }
615

    
616
        if((FirstTime==1 || FirstTimeAudio==1) && audioq.size>0) {
617
                if(audioq.first_pkt->pkt.pts>0)
618
                {
619
                        //SDL_LockMutex(timing_mutex);
620
                        DeltaTime=Now-(long long)(audioq.first_pkt->pkt.pts);
621
                        FirstTimeAudio = 0;
622
                        FirstTime = 0;
623
                        //SDL_UnlockMutex(timing_mutex);
624
#ifdef DEBUG_AUDIO 
625
                         printf("AUDIO: audio_decode_frame - DeltaTimeAudio=%lld\n",DeltaTime);
626
#endif
627
                }
628
        }
629

    
630
#ifdef DEBUG_AUDIO 
631
        if(audioq.first_pkt)
632
        {
633
                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);
634
                printf("AUDIO: QueueLen=%d ",(int)audioq.nb_packets);
635
                printf("AUDIO: QueueSize=%d\n",(int)audioq.size);
636
        }
637
        else
638
                printf("AUDIO: audio_decode_frame - Empty queue\n");
639
#endif
640

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

    
691
                ChunkerPlayerStats_UpdateAudioPlayedHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
692
        }
693

    
694
        return audio_pkt_size;
695
}
696

    
697
int VideoCallback(void *valthread)
698
{
699
        //AVPacket pktvideo;
700
        AVCodecContext  *pCodecCtx;
701
        AVCodec         *pCodec;
702
        AVFrame         *pFrame;
703
        int frameFinished;
704
        AVPicture pict;
705
        long long Now;
706
        short int SkipVideo, DecodeVideo;
707
        
708
#ifdef SAVE_YUV
709
        static AVFrame* lastSavedFrameBuffer = NULL;
710
        
711
        if(!lastSavedFrameBuffer)
712
                lastSavedFrameBuffer = (AVFrame*) malloc(sizeof(AVFrame));
713
#endif
714

    
715
        //double frame_rate = 0.0,time_between_frames=0.0;
716
        //struct timeval now;
717

    
718
        //int wait_for_sync = 1;
719
        ThreadVal *tval;
720
        tval = (ThreadVal *)valthread;
721

    
722
        //frame_rate = tval->framerate;
723
        //time_between_frames = 1.e6 / frame_rate;
724
        //gettimeofday(&time_now,0);
725

    
726
        //frecon = fopen("recondechunk.mpg","wb");
727

    
728
        pCodecCtx=avcodec_alloc_context();
729
        pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
730
        //pCodecCtx->debug = FF_DEBUG_DCT_COEFF;
731
#ifdef H264_VIDEO_ENCODER
732
        pCodecCtx->codec_id  = CODEC_ID_H264;
733
        pCodecCtx->me_range = 16;
734
        pCodecCtx->max_qdiff = 4;
735
        pCodecCtx->qmin = 1;
736
        pCodecCtx->qmax = 30;
737
        pCodecCtx->qcompress = 0.6;
738
#else
739
        pCodecCtx->codec_id  = CODEC_ID_MPEG4;
740
#endif
741
        //pCodecCtx->bit_rate = 400000;
742
        // resolution must be a multiple of two
743
        pCodecCtx->width = tval->width;//176;//352;
744
        pCodecCtx->height = tval->height;//144;//288;
745

    
746
        // frames per second
747
        //pCodecCtx->time_base = (AVRational){1,25};
748
        //pCodecCtx->gop_size = 10; // emit one intra frame every ten frames
749
        //pCodecCtx->max_b_frames=1;
750
        pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
751
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
752

    
753
        if(pCodec==NULL) {
754
                fprintf(stderr, "Unsupported codec!\n");
755
                return -1; // Codec not found
756
        }
757
        if(avcodec_open(pCodecCtx, pCodec) < 0) {
758
                fprintf(stderr, "could not open codec\n");
759
                return -1; // Could not open codec
760
        }
761
        pFrame=avcodec_alloc_frame();
762
        if(pFrame==NULL) {
763
                printf("Memory error!!!\n");
764
                return -1;
765
        }
766
        
767
#ifdef DEBUG_VIDEO
768
         printf("VIDEO: video_callback entering main cycle\n");
769
#endif
770

    
771
        struct timeval now_tv;
772
        while(AVPlaying && !quit) {
773
                if(QueueFillingMode || QueueStopped)
774
                {
775
                        //SDL_LockMutex(timing_mutex);
776
                        FirstTime = 1;
777
                        //SDL_UnlockMutex(timing_mutex);
778
                        usleep(5000);
779
                        continue;
780
                }
781

    
782
                DecodeVideo = 0;
783
                SkipVideo = 0;
784
                Now=(long long)SDL_GetTicks();
785
                if(FirstTime==1 && videoq.size>0) {
786
                        if(videoq.first_pkt->pkt.pts>0)
787
                        {
788
                                //SDL_LockMutex(timing_mutex);
789
                                DeltaTime=Now-(long long)videoq.first_pkt->pkt.pts;
790
                                FirstTime = 0;
791
                                //SDL_UnlockMutex(timing_mutex);
792
                        }
793
#ifdef DEBUG_VIDEO 
794
                         printf("VIDEO: VideoCallback - DeltaTimeAudio=%lld\n",DeltaTime);
795
#endif
796
                }
797

    
798
#ifdef DEBUG_VIDEO 
799
                if(videoq.first_pkt)
800
                {
801
                        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);
802
                        printf("VIDEO: Index=%d ", (int)videoq.first_pkt->pkt.stream_index);
803
                        printf("VIDEO: QueueLen=%d ", (int)videoq.nb_packets);
804
                        printf("VIDEO: QueueSize=%d\n", (int)videoq.size);
805
                }
806
                else
807
                        printf("VIDEO: VideoCallback - Empty queue\n");
808
#endif
809

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

    
841
                        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
842
                        
843
                        // sometimes assertion fails, maybe the decoder change the frame type
844
                        //~ if(LastSourceIFrameDistance == 0)
845
                                //~ assert(pFrame->pict_type == 1);
846

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

    
876
                if(DecodeVideo==1) {
877
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) > 0) {
878
                                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
879

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

    
910
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
911
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
912
                                                LastSavedVFrame = VideoPkt.stream_index;
913
                                        }
914
#endif
915
                                        ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
916

    
917
                                        if(SilentMode)
918
                                                continue;
919

    
920
                                        // Lock SDL_yuv_overlay
921
                                        if(SDL_MUSTLOCK(MainScreen)) {
922
                                                if(SDL_LockSurface(MainScreen) < 0) {
923
                                                        continue;
924
                                                }
925
                                        }
926

    
927
                                        if(SDL_LockYUVOverlay(YUVOverlay) < 0) {
928
                                                if(SDL_MUSTLOCK(MainScreen)) {
929
                                                        SDL_UnlockSurface(MainScreen);
930
                                                }
931
                                                continue;
932
                                        }
933
                                        
934
                                        pict.data[0] = YUVOverlay->pixels[0];
935
                                        pict.data[1] = YUVOverlay->pixels[2];
936
                                        pict.data[2] = YUVOverlay->pixels[1];
937

    
938
                                        pict.linesize[0] = YUVOverlay->pitches[0];
939
                                        pict.linesize[1] = YUVOverlay->pitches[2];
940
                                        pict.linesize[2] = YUVOverlay->pitches[1];
941

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

    
966
                                        //redisplay logo
967
                                        /**SDL_BlitSurface(image, NULL, MainScreen, &dest);*/
968
                                        /* Update the screen area just changed */
969
                                        /**SDL_UpdateRects(MainScreen, 1, &dest);*/
970

    
971
                                        if(SDL_MUSTLOCK(MainScreen)) {
972
                                                SDL_UnlockSurface(MainScreen);
973
                                        }
974
                                } //if FrameFinished
975
                                else
976
                                {
977
                                        ChunkerPlayerStats_UpdateVideoLossHistory(&(videoq.PacketHistory), VideoPkt.stream_index+1, videoq.last_frame_extracted-1);
978
                                }
979
                        } // if packet_queue_get
980
                } //if DecodeVideo=1
981

    
982
                usleep(5000);
983
        }
984
        avcodec_close(pCodecCtx);
985
        av_free(pCodecCtx);
986
        av_free(pFrame);
987
        //fclose(frecon);
988
#ifdef DEBUG_VIDEO
989
         printf("VIDEO: video callback end\n");
990
#endif
991

    
992
#ifdef SAVE_YUV
993
        if(!lastSavedFrameBuffer)
994
                free(lastSavedFrameBuffer);
995
        
996
        lastSavedFrameBuffer = NULL;
997
#endif
998

    
999
        return 0;
1000
}
1001

    
1002
void AudioCallback(void *userdata, Uint8 *stream, int len)
1003
{
1004
        //AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
1005
        int audio_size;
1006

    
1007
        static uint8_t audio_buf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
1008

    
1009
        audio_size = AudioDecodeFrame(audio_buf, sizeof(audio_buf));
1010
        
1011
        if(SilentMode != 1)
1012
                if(audio_size != len) {
1013
                        memset(stream, 0, len);
1014
                } else {
1015
                        memcpy(stream, (uint8_t *)audio_buf, len);
1016
                }
1017
}
1018

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

    
1046
int ChunkerPlayerCore_IsRunning()
1047
{
1048
        return AVPlaying;
1049
}
1050

    
1051
void ChunkerPlayerCore_Play()
1052
{
1053
        if(AVPlaying) return;
1054
        AVPlaying = 1;
1055
        
1056
        SDL_PauseAudio(0);
1057
        video_thread = SDL_CreateThread(VideoCallback, &VideoCallbackThreadParams);
1058
        ChunkerPlayerStats_Init();
1059
        stats_thread = SDL_CreateThread(CollectStatisticsThread, NULL);
1060
        
1061
        decoded_vframes = 0;
1062
        LastSavedVFrame = -1;
1063
}
1064

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

    
1103
void ChunkerPlayerCore_Pause()
1104
{
1105
        if(!AVPlaying) return;
1106
        
1107
        AVPlaying = 0;
1108
        
1109
        // Stop audio&video playback
1110
        SDL_WaitThread(video_thread, NULL);
1111
        SDL_PauseAudio(1);
1112
        
1113
        PacketQueueReset(&audioq);
1114
        PacketQueueReset(&videoq);
1115
}
1116

    
1117
int ChunkerPlayerCore_AudioEnded()
1118
{
1119
        return (audioq.nb_packets==0 && audioq.last_frame_extracted>0);
1120
}
1121

    
1122
void ChunkerPlayerCore_ResetAVQueues()
1123
{
1124
#ifdef DEBUG_QUEUE
1125
        printf("QUEUE: MAIN SHOULD RESET\n");
1126
#endif
1127
        PacketQueueReset(&audioq);
1128
        PacketQueueReset(&videoq);
1129
}
1130

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

    
1177
        Chunk *gchunk = NULL;
1178
        int decoded_size = -1;
1179
        uint8_t *tempdata, *buffer;
1180
        int j;
1181
        Frame *frame = NULL;
1182
        AVPacket packet, packetaudio;
1183

    
1184
        uint16_t *audio_bufQ = NULL;
1185

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

    
1190
        static int chunks_out_of_order = 0;
1191
        static int last_chunk_id = -1;
1192

    
1193
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
1194
        if(!audio_bufQ) {
1195
                printf("Memory error in audio_bufQ!\n");
1196
                return PLAYER_FAIL_RETURN;
1197
        }
1198

    
1199
        gchunk = (Chunk *)malloc(sizeof(Chunk));
1200
        if(!gchunk) {
1201
                printf("Memory error in gchunk!\n");
1202
                av_free(audio_bufQ);
1203
                return PLAYER_FAIL_RETURN;
1204
        }
1205

    
1206
        decoded_size = decodeChunk(gchunk, block, block_size);
1207

    
1208
        if(last_chunk_id == -1)
1209
                last_chunk_id = gchunk->id;
1210

    
1211
        if(gchunk->id > (last_chunk_id+1)) {
1212
                chunks_out_of_order += gchunk->id - last_chunk_id - 1;
1213
        }
1214
        last_chunk_id = gchunk->id;
1215

    
1216
#ifdef DEBUG_CHUNKER
1217
        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);
1218
#endif
1219
  if(decoded_size < 0) {
1220
                //HINT here i should differentiate between various return values of the decode
1221
                //in order to free what has been allocated there
1222
                printf("chunk probably corrupted!\n");
1223
                av_free(audio_bufQ);
1224
                free(gchunk);
1225
                return PLAYER_FAIL_RETURN;
1226
        }
1227

    
1228
        frame = (Frame *)malloc(sizeof(Frame));
1229
        if(!frame) {
1230
                printf("Memory error in Frame!\n");
1231
                if(gchunk) {
1232
                        if(gchunk->attributes) {
1233
                                free(gchunk->attributes);
1234
                        }
1235
                        free(gchunk);
1236
                }
1237
                av_free(audio_bufQ);
1238
                return PLAYER_FAIL_RETURN;
1239
        }
1240

    
1241
        tempdata = gchunk->data; //let it point to first frame of payload
1242
        j=gchunk->size;
1243
        while(j>0 && !quit) {
1244
                frame->number = bit32_encoded_pull(tempdata);
1245
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1246
                frame->timestamp.tv_sec = bit32_encoded_pull(tempdata);
1247
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1248
                frame->timestamp.tv_usec = bit32_encoded_pull(tempdata);
1249
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1250
                frame->size = bit32_encoded_pull(tempdata);
1251
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1252
                frame->type = bit32_encoded_pull(tempdata);
1253
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1254

    
1255
                buffer = tempdata; // here coded frame information
1256
                tempdata += frame->size; //let it point to the next frame
1257

    
1258
                if(frame->type < 5) { // video frame
1259
                        av_init_packet(&packet);
1260
                        packet.data = buffer;//video_bufQ;
1261
                        packet.size = frame->size;
1262
                        packet.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1263
                        packet.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1264
                        packet.stream_index = frame->number; // use of stream_index for number frame
1265
                        //packet.duration = frame->timestamp.tv_sec;
1266
                        if(packet.size > 0)
1267
                                ChunkerPlayerCore_PacketQueuePut(&videoq, &packet); //the _put makes a copy of the packet
1268

    
1269
#ifdef DEBUG_SOURCE
1270
                        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);
1271
#endif
1272
                }
1273
                else if(frame->type == 5) { // audio frame
1274
                        av_init_packet(&packetaudio);
1275
                        packetaudio.data = buffer;
1276
                        packetaudio.size = frame->size;
1277
                        packetaudio.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1278
                        packetaudio.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1279
                        //packetaudio.duration = frame->timestamp.tv_sec;
1280
                        packetaudio.stream_index = frame->number; // use of stream_index for number frame
1281
                        packetaudio.flags = 1;
1282
                        packetaudio.pos = -1;
1283

    
1284
                        //instead of -1, in order to signal it is not decoded yet
1285
                        packetaudio.convergence_duration = 0;
1286

    
1287
                        // insert the audio frame into the queue
1288
                        if(packetaudio.size > 0)
1289
                                ChunkerPlayerCore_PacketQueuePut(&audioq, &packetaudio);//makes a copy of the packet so i can free here
1290

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

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

    
1350
        if ( YUVOverlay->hw_overlay )
1351
                fprintf(stderr,"SDL: Using hardware overlay.\n");
1352
        // OverlayRect.x = (screen_w - width) / 2;
1353
        
1354
        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
1355
        
1356
        SDL_UnlockMutex(OverlayMutex);
1357
}
1358

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

    
1390
#ifdef DEBUG_STATS
1391
                        printf("VIDEO: %d Kbit/sec; ", video_statistics.Bitrate);
1392
                        printf("AUDIO: %d Kbit/sec\n", audio_statistics.Bitrate);
1393
#endif
1394

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

    
1419
                        // PRINT STATISTICS ON GUI
1420
                        if(!Audio_ON)
1421
                                sprintf(audio_stats_text, "AUDIO MUTED");
1422
                        else if(audio_stats_changed)
1423
                                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);
1424
                        else
1425
                                sprintf(audio_stats_text, "waiting for incoming audio packets...");
1426

    
1427
                        if(video_stats_changed)
1428
                        {
1429
                                char est_psnr_string[255];
1430
                                sprintf(est_psnr_string, "");
1431
                                if(qoe)
1432
                                        sprintf(est_psnr_string, " - Est. Mean PSNR: %.1f db", (float)qoe);
1433

    
1434
                                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);
1435
                        }
1436
                        else
1437
                                sprintf(video_stats_text, "waiting for incoming video packets...");
1438

    
1439
                        ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text);
1440
                        last_stats_evaluation = now;
1441
                }
1442
                
1443
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_qoe_evaluation.tv_sec*1000)+(last_qoe_evaluation.tv_usec/1000))) > EVAL_QOE_INTERVAL)
1444
                {
1445
                        // ESTIMATE QoE
1446
                        ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), &qoe);
1447
                        
1448
#ifdef DEBUG_STATS
1449
                        printf("QoE index: %f\n", (float) qoe);
1450
#endif
1451
                        last_qoe_evaluation = now;
1452
                }
1453
        }
1454
}