Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_core.c @ 47943338

History | View | Annotate | Download (45.6 KB)

1 01f952d0 GiuseppeTropea
/*
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 10c75ef7 GiuseppeTropea
#include "player_defines.h"
9
#include "chunker_player.h"
10 31e4e8ba GiuseppeTropea
#include "player_gui.h"
11 10c75ef7 GiuseppeTropea
#include "player_core.h"
12 e11386c0 CsabaKiraly
#include "player_stats.h"
13 10c75ef7 GiuseppeTropea
#include <assert.h>
14 e11386c0 CsabaKiraly
#include <time.h>
15 10c75ef7 GiuseppeTropea
16 2f5ae7bb Csaba Kiraly
static char *video_codec;
17
18 31e4e8ba GiuseppeTropea
void SaveFrame(AVFrame *pFrame, int width, int height);
19
int VideoCallback(void *valthread);
20 e11386c0 CsabaKiraly
int CollectStatisticsThread(void *params);
21 31e4e8ba GiuseppeTropea
void AudioCallback(void *userdata, Uint8 *stream, int len);
22 e11386c0 CsabaKiraly
void PacketQueueClearStats(PacketQueue *q);
23
void ChunkerPlayerCore_Pause();
24
25
//int lastCheckedVideoFrame = -1;
26
long int last_video_frame_extracted = -1;
27 31e4e8ba GiuseppeTropea
28 0cd6b05d CarmeloDaniele
int timeval_subtract(struct timeval* x, struct timeval* y, struct timeval* result)
29
{
30
  // Perform the carry for the later subtraction by updating y.
31
  if (x->tv_usec < y->tv_usec)
32
  {
33
    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
34
    y->tv_usec -= 1000000 * nsec;
35
    y->tv_sec += nsec;
36
  }
37
  if (x->tv_usec - y->tv_usec > 1000000)
38
  {
39
    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
40
    y->tv_usec += 1000000 * nsec;
41
    y->tv_sec -= nsec;
42
  }
43
44
  // Compute the time remaining to wait. tv_usec is certainly positive.
45
  result->tv_sec = x->tv_sec - y->tv_sec;
46
  result->tv_usec = x->tv_usec - y->tv_usec;
47
48
  // Return 1 if result is negative.
49
  return x->tv_sec < y->tv_sec;
50
}
51
52
53 10c75ef7 GiuseppeTropea
void PacketQueueInit(PacketQueue *q, short int Type)
54
{
55
#ifdef DEBUG_QUEUE
56 730c29f4 GiuseppeTropea
        printf("QUEUE: INIT BEGIN: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
57 10c75ef7 GiuseppeTropea
#endif
58
        memset(q,0,sizeof(PacketQueue));
59
        q->mutex = SDL_CreateMutex();
60
        QueueFillingMode=1;
61
        q->queueType=Type;
62
        q->last_frame_extracted = -1;
63
        q->first_pkt= NULL;
64 802f63d4 Csaba Kiraly
        q->minpts_pkt= NULL;
65 10c75ef7 GiuseppeTropea
        //q->last_pkt = NULL;
66
        q->nb_packets = 0;
67
        q->size = 0;
68
        q->density= 0.0;
69
        FirstTime = 1;
70
        FirstTimeAudio = 1;
71 e11386c0 CsabaKiraly
        //init up statistics
72
        
73
        q->PacketHistory.Mutex = SDL_CreateMutex();
74
        PacketQueueClearStats(q);
75
        
76 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
77 730c29f4 GiuseppeTropea
        printf("QUEUE: INIT END: NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
78 10c75ef7 GiuseppeTropea
#endif
79
}
80
81 333348bb GiuseppeTropea
void PacketQueueReset(PacketQueue *q)
82 10c75ef7 GiuseppeTropea
{
83
        AVPacketList *tmp,*tmp1;
84
#ifdef DEBUG_QUEUE
85 730c29f4 GiuseppeTropea
        printf("QUEUE: RESET BEGIN: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
86 10c75ef7 GiuseppeTropea
#endif
87
        SDL_LockMutex(q->mutex);
88
89
        tmp = q->first_pkt;
90
        while(tmp) {
91
                tmp1 = tmp;
92
                tmp = tmp->next;
93
                av_free_packet(&(tmp1->pkt));
94
                av_free(tmp1);
95
#ifdef DEBUG_QUEUE
96
                printf("F ");
97
#endif
98 e11386c0 CsabaKiraly
                q->PacketHistory.LostCount++;
99 10c75ef7 GiuseppeTropea
        }
100
#ifdef DEBUG_QUEUE
101
        printf("\n");
102
#endif
103
104
        QueueFillingMode=1;
105
        q->last_frame_extracted = -1;
106 e11386c0 CsabaKiraly
        
107 31e4e8ba GiuseppeTropea
        // on queue reset do not reset loss count
108
        // (loss count reset is done on queue init, ie channel switch)
109
        q->density=0.0;
110 10c75ef7 GiuseppeTropea
        q->first_pkt= NULL;
111 802f63d4 Csaba Kiraly
        q->minpts_pkt= NULL;
112 10c75ef7 GiuseppeTropea
        //q->last_pkt = NULL;
113
        q->nb_packets = 0;
114
        q->size = 0;
115
        FirstTime = 1;
116
        FirstTimeAudio = 1;
117 e11386c0 CsabaKiraly
        //clean up statistics
118
        PacketQueueClearStats(q);
119 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
120 730c29f4 GiuseppeTropea
        printf("QUEUE: RESET END: NPackets=%d Type=%s LastExtr=%d\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
121 10c75ef7 GiuseppeTropea
#endif
122
        SDL_UnlockMutex(q->mutex);
123
}
124
125 e11386c0 CsabaKiraly
void PacketQueueClearStats(PacketQueue *q)
126
{
127 aa041505 GiuseppeTropea
        sprintf(q->stats_message, "%s", "\n");
128 e11386c0 CsabaKiraly
        int i;
129
        memset((void*)q->PacketHistory.History, 0, sizeof(SHistoryElement)*QUEUE_HISTORY_SIZE);
130
        for(i=0; i<QUEUE_HISTORY_SIZE; i++)
131
        {
132
                q->PacketHistory.History[i].Statistics.LastIFrameDistance = -1;
133
                q->PacketHistory.History[i].Status = -1;
134
        }
135
        q->PacketHistory.Index = q->PacketHistory.LogIndex = 0;
136
        q->PacketHistory.Index = q->PacketHistory.QoEIndex = 0;
137
        q->PacketHistory.LostCount = q->PacketHistory.PlayedCount = q->PacketHistory.SkipCount = 0;
138 dae4a53f GiuseppeTropea
}
139
140 10c75ef7 GiuseppeTropea
int ChunkerPlayerCore_PacketQueuePut(PacketQueue *q, AVPacket *pkt)
141
{
142 e11386c0 CsabaKiraly
        //~ printf("\tSTREAM_INDEX=%d\n", pkt->stream_index);
143 10c75ef7 GiuseppeTropea
        short int skip = 0;
144
        AVPacketList *pkt1, *tmp, *prevtmp;
145 e11386c0 CsabaKiraly
        int res = 0;
146 333348bb GiuseppeTropea
147
        if(q->nb_packets > queue_filling_threshold*QUEUE_MAX_GROW_FACTOR) {
148 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
149 730c29f4 GiuseppeTropea
                printf("QUEUE: PUT i have TOO MANY packets %d Type=%s, RESETTING\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
150 333348bb GiuseppeTropea
#endif
151
                PacketQueueReset(q);
152 e11386c0 CsabaKiraly
        }
153 333348bb GiuseppeTropea
154 10c75ef7 GiuseppeTropea
        //make a copy of the incoming packet
155
        if(av_dup_packet(pkt) < 0) {
156
#ifdef DEBUG_QUEUE
157 730c29f4 GiuseppeTropea
                printf("QUEUE: PUT in Queue cannot duplicate in packet        : NPackets=%d Type=%s\n",q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
158 10c75ef7 GiuseppeTropea
#endif
159
                return -1;
160
        }
161
        pkt1 = av_malloc(sizeof(AVPacketList));
162
163
        if(!pkt1) {
164
                av_free_packet(pkt);
165
                return -1;
166
        }
167
        pkt1->pkt = *pkt;
168
        pkt1->next = NULL;
169 e11386c0 CsabaKiraly
        
170
        static time_t last_auto_switch = 0;
171
172
        if(
173
                (pkt->stream_index < last_video_frame_extracted)
174
                && (pkt->stream_index <= RESTART_FRAME_NUMBER_THRESHOLD)
175
                && ((time(NULL) - last_auto_switch) > 10)
176
        )
177
        {
178 d0daa06f Csaba Kiraly
                printf("file streaming loop detected => re-tune channel and start grabbing statistics\n");
179 e11386c0 CsabaKiraly
                last_auto_switch = time(NULL);
180
                SDL_LockMutex(q->mutex);
181
                ReTune(&(Channels[SelectedChannel]));
182
                SDL_UnlockMutex(q->mutex);
183
        }
184 10c75ef7 GiuseppeTropea
185 e11386c0 CsabaKiraly
        else
186
        {
187
                SDL_LockMutex(q->mutex);
188 10c75ef7 GiuseppeTropea
189 e11386c0 CsabaKiraly
                // INSERTION SORT ALGORITHM
190
                // before inserting pkt, check if pkt.stream_index is <= current_extracted_frame.
191
                if(pkt->stream_index > q->last_frame_extracted)
192
                {
193
                        // either checking starting from the first_pkt or needed other struct like AVPacketList with next and prev....
194
                        //if (!q->last_pkt)
195
                        if(!q->first_pkt) {
196
                                q->first_pkt = pkt1;
197
                                q->last_pkt = pkt1;
198
                        }
199
                        else if(pkt->stream_index < q->first_pkt->pkt.stream_index) {
200
                                //the packet that has arrived is earlier than the first we got some time ago!
201
                                //we need to put it at the head of the queue
202
                                pkt1->next = q->first_pkt;
203
                                q->first_pkt = pkt1;
204
                        }
205
                        else {
206
                                tmp = q->first_pkt;
207
                                while(tmp->pkt.stream_index < pkt->stream_index) {
208
                                        prevtmp = tmp;
209
                                        tmp = tmp->next;
210 10c75ef7 GiuseppeTropea
211 e11386c0 CsabaKiraly
                                        if(!tmp) {
212
                                                break;
213
                                        }
214 10c75ef7 GiuseppeTropea
                                }
215 e11386c0 CsabaKiraly
                                if(tmp && tmp->pkt.stream_index == pkt->stream_index) {
216
                                        //we already have a frame with that index
217
                                        skip = 1;
218 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
219 e11386c0 CsabaKiraly
                                        printf("%s QUEUE: PUT: we already have frame with index %d, skipping\n", ((q->queueType == AUDIO) ? "AUDIO" : "VIDEO"), pkt->stream_index);
220 10c75ef7 GiuseppeTropea
#endif
221 e11386c0 CsabaKiraly
                                }
222
                                else {
223
                                        prevtmp->next = pkt1;
224
                                        pkt1->next = tmp;
225
                                        if(pkt1->next == NULL)
226
                                                q->last_pkt = pkt1;
227
                                }
228
                                //q->last_pkt->next = pkt1; // It was uncommented when not insertion sort
229 10c75ef7 GiuseppeTropea
                        }
230 e11386c0 CsabaKiraly
                        if(skip == 0) {
231
                                //q->last_pkt = pkt1;
232
                                q->nb_packets++;
233
                                q->size += pkt1->pkt.size;
234
                                if(q->nb_packets>=queue_filling_threshold && QueueFillingMode) // && q->queueType==AUDIO)
235
                                {
236
                                        QueueFillingMode=0;
237 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
238 e11386c0 CsabaKiraly
                                        printf("QUEUE: PUT: FillingMode set to zero\n");
239 10c75ef7 GiuseppeTropea
#endif
240 e11386c0 CsabaKiraly
                                }
241 802f63d4 Csaba Kiraly
                                //set min
242
                                if (!q->minpts_pkt || (pkt1->pkt.pts < q->minpts_pkt->pts)) {
243
                                        q->minpts_pkt = &(pkt1->pkt);
244
                                }
245 10c75ef7 GiuseppeTropea
                        }
246
                }
247 e11386c0 CsabaKiraly
                else {
248
                        av_free_packet(&pkt1->pkt);
249
                        av_free(pkt1);
250 10c75ef7 GiuseppeTropea
#ifdef DEBUG_QUEUE
251 e11386c0 CsabaKiraly
                        printf("QUEUE: PUT: NOT inserting because index %d <= last extracted %d\n", pkt->stream_index, q->last_frame_extracted);
252 10c75ef7 GiuseppeTropea
#endif
253 e11386c0 CsabaKiraly
                        res = 1;
254
                }
255
                SDL_UnlockMutex(q->mutex);
256 10c75ef7 GiuseppeTropea
        }
257 1a9b74ea GiuseppeTropea
258 e11386c0 CsabaKiraly
        return res;
259 10c75ef7 GiuseppeTropea
}
260
261 2f5ae7bb Csaba Kiraly
int ChunkerPlayerCore_InitCodecs(char *v_codec, int width, int height, char *audio_codec, int sample_rate, short int audio_channels)
262 10c75ef7 GiuseppeTropea
{
263 2f5ae7bb Csaba Kiraly
        video_codec = v_codec;
264
265 10c75ef7 GiuseppeTropea
        // some initializations
266
        QueueStopped = 0;
267
        AudioQueueOffset=0;
268
        AVPlaying = 0;
269
        GotSigInt = 0;
270
        FirstTimeAudio=1;
271
        FirstTime = 1;
272
        deltaAudioQError=0;
273
        InitRect = NULL;
274
        img_convert_ctx = NULL;
275
        
276 bfc47ca9 Csaba Kiraly
        SDL_AudioSpec *wanted_spec;
277 10c75ef7 GiuseppeTropea
        AVCodec         *aCodec;
278
        
279
        memset(&VideoCallbackThreadParams, 0, sizeof(ThreadVal));
280
        
281
        VideoCallbackThreadParams.width = width;
282
        VideoCallbackThreadParams.height = height;
283
284
        // Register all formats and codecs
285 01f952d0 GiuseppeTropea
        avcodec_init();
286 10c75ef7 GiuseppeTropea
        av_register_all();
287
288
        aCodecCtx = avcodec_alloc_context();
289
        //aCodecCtx->bit_rate = 64000;
290
        aCodecCtx->sample_rate = sample_rate;
291
        aCodecCtx->channels = audio_channels;
292 2f5ae7bb Csaba Kiraly
        aCodec = avcodec_find_decoder_by_name(audio_codec);
293 10c75ef7 GiuseppeTropea
        if(!aCodec) {
294
                printf("Codec not found!\n");
295
                return -1;
296
        }
297
        if(avcodec_open(aCodecCtx, aCodec)<0) {
298
                fprintf(stderr, "could not open codec\n");
299
                return -1; // Could not open codec
300
        }
301
        printf("using audio Codecid: %d ",aCodecCtx->codec_id);
302
        printf("samplerate: %d ",aCodecCtx->sample_rate);
303
        printf("channels: %d\n",aCodecCtx->channels);
304 bfc47ca9 Csaba Kiraly
305
        if (! (wanted_spec = malloc(sizeof(*wanted_spec)))) {
306
                perror("error initializing audio");
307
                return -1;
308
        }
309
        wanted_spec->freq = aCodecCtx->sample_rate;
310
        wanted_spec->format = AUDIO_S16SYS;
311
        wanted_spec->channels = aCodecCtx->channels;
312
        wanted_spec->silence = 0;
313
        wanted_spec->samples = SDL_AUDIO_BUFFER_SIZE;
314
        wanted_spec->callback = AudioCallback;
315
        wanted_spec->userdata = aCodecCtx;
316
317
#ifdef DEBUG_AUDIO
318
        printf("wanted freq:%d\n",wanted_spec->freq);
319
        printf("wanted format:%d\n",wanted_spec->format);
320
        printf("wanted channels:%d\n",wanted_spec->channels);
321
        printf("wanted silence:%d\n",wanted_spec->silence);
322
        printf("wanted samples:%d\n",wanted_spec->samples);
323
#endif
324
325
        if(SDL_OpenAudio(wanted_spec,AudioSpecification)<0)
326 5ca3d85e GiuseppeTropea
        {
327 e11386c0 CsabaKiraly
                fprintf(stderr,"SDL_OpenAudio: %s\n", SDL_GetError());
328 5ca3d85e GiuseppeTropea
                return -1;
329
        }
330 bfc47ca9 Csaba Kiraly
        if (!AudioSpecification) {
331
                AudioSpecification = wanted_spec;
332
        } else {
333
                free(wanted_spec);
334
        }
335
336
        CurrentAudioFreq = AudioSpecification->freq;
337
        CurrentAudioSamples = AudioSpecification->samples;
338
        dimAudioQ = AudioSpecification->size;
339
        deltaAudioQ = (float)((float)AudioSpecification->samples)*1000/AudioSpecification->freq;        //in ms
340 6ca535a1 Csaba Kiraly
        CurrentAudioSilence = AudioSpecification->silence;
341 10c75ef7 GiuseppeTropea
342
#ifdef DEBUG_AUDIO
343 bfc47ca9 Csaba Kiraly
        printf("freq:%d\n",AudioSpecification->freq);
344
        printf("format:%d\n",AudioSpecification->format);
345
        printf("channels:%d\n",AudioSpecification->channels);
346
        printf("silence:%d\n",AudioSpecification->silence);
347
        printf("samples:%d\n",AudioSpecification->samples);
348
        printf("size:%d\n",AudioSpecification->size);
349 10c75ef7 GiuseppeTropea
        printf("deltaAudioQ: %f\n",deltaAudioQ);
350
#endif
351
352
        outbuf_audio = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
353
354
        //initialize the audio and the video queues
355
        PacketQueueInit(&audioq, AUDIO);
356
        PacketQueueInit(&videoq, VIDEO);
357
        
358
        // Init audio and video buffers
359
        av_init_packet(&AudioPkt);
360
        av_init_packet(&VideoPkt);
361 b4dc1ea0 GiuseppeTropea
        //printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d\n", AVCODEC_MAX_AUDIO_FRAME_SIZE);
362 10c75ef7 GiuseppeTropea
        AudioPkt.data=(uint8_t *)malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
363
        if(!AudioPkt.data) return 1;
364
        VideoPkt.data=(uint8_t *)malloc(width*height*3/2);
365
        if(!VideoPkt.data) return 1;
366
        
367
        InitRect = (SDL_Rect*) malloc(sizeof(SDL_Rect));
368
        if(!InitRect)
369
        {
370
                printf("Memory error!!!\n");
371
                return -1;
372
        }
373
        InitRect->x = OverlayRect.x;
374
        InitRect->y = OverlayRect.y;
375
        InitRect->w = OverlayRect.w;
376
        InitRect->h = OverlayRect.h;
377
        
378 31e4e8ba GiuseppeTropea
        char audio_stats[255], video_stats[255];
379
        sprintf(audio_stats, "waiting for incoming audio packets...");
380
        sprintf(video_stats, "waiting for incoming video packets...");
381 6f1fe643 CarmeloDaniele
        ChunkerPlayerGUI_SetStatsText(audio_stats, video_stats,LED_GREEN);
382 31e4e8ba GiuseppeTropea
        
383 10c75ef7 GiuseppeTropea
        return 0;
384
}
385
386 e11386c0 CsabaKiraly
int DecodeEnqueuedAudio(AVPacket *pkt, PacketQueue *q, int* size)
387 10c75ef7 GiuseppeTropea
{
388
        uint16_t *audio_bufQ = NULL;
389
        int16_t *dataQ = NULL;
390
        int data_sizeQ = AVCODEC_MAX_AUDIO_FRAME_SIZE;
391
        int lenQ;
392
        int ret = 0;
393
394
        //set the flag to decoded anyway        
395
        pkt->convergence_duration = -1;
396
397
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
398
        if(audio_bufQ) {
399
#ifdef DEBUG_AUDIO_BUFFER
400
                printf("AUDIO_BUFFER: about to decode packet %d, size %d, data %d\n", pkt->stream_index, pkt->size, pkt->data);
401
#endif
402
                //decode the packet data
403
                lenQ = avcodec_decode_audio3(aCodecCtx, (int16_t *)audio_bufQ, &data_sizeQ, pkt);
404
                if(lenQ > 0) {
405
                        dataQ = (int16_t *)av_malloc(data_sizeQ); //this will be free later at the time of playback
406
                        if(dataQ) {
407
                                memcpy(dataQ, audio_bufQ, data_sizeQ);
408 a22455b3 GiuseppeTropea
                                if(pkt->data != NULL)
409
                                {
410
                                        //discard the old encoded bytes
411
                                        av_free(pkt->data);
412
                                }
413 10c75ef7 GiuseppeTropea
                                //subtract them from queue size
414
                                q->size -= pkt->size;
415 e11386c0 CsabaKiraly
                                *size = pkt->size;
416 10c75ef7 GiuseppeTropea
                                pkt->data = (int8_t *)dataQ;
417
                                pkt->size = data_sizeQ;
418
                                //add new size to queue size
419
                                q->size += pkt->size;
420
                                ret = 1;
421
                        }
422
                        else {
423
#ifdef DEBUG_AUDIO_BUFFER
424
                                printf("AUDIO_BUFFER: cannot alloc space for decoded packet %d\n", pkt->stream_index);
425
#endif
426
                        }
427
                }
428
                else {
429
#ifdef DEBUG_AUDIO_BUFFER
430
                        printf("AUDIO_BUFFER: cannot decode packet %d\n", pkt->stream_index);
431
#endif
432
                }
433
                av_free(audio_bufQ);
434
        }
435
        else {
436
#ifdef DEBUG_AUDIO_BUFFER
437
                printf("AUDIO_BUFFER: cannot alloc decode buffer for packet %d\n", pkt->stream_index);
438
#endif
439
        }
440
        return ret; //problems occurred
441
}
442
443
/**
444
 * removes a packet from the list and returns the next
445
 * */
446
AVPacketList *RemoveFromQueue(PacketQueue *q, AVPacketList *p)
447
{
448 72d1fe4f Csaba Kiraly
        AVPacketList *p1;
449
450
        if (q->first_pkt == p) {
451
                q->first_pkt = p->next;
452
        }
453 802f63d4 Csaba Kiraly
        if (&(p->pkt) == q->minpts_pkt) {
454
                q->minpts_pkt = NULL;
455
        }
456 72d1fe4f Csaba Kiraly
457 10c75ef7 GiuseppeTropea
        AVPacketList *retpk = p->next;
458
        q->nb_packets--;
459
        //adjust size here and not in the various cases of the dequeue
460
        q->size -= p->pkt.size;
461
        if(&p->pkt)
462 e11386c0 CsabaKiraly
        {
463 10c75ef7 GiuseppeTropea
                av_free_packet(&p->pkt);
464 e11386c0 CsabaKiraly
        }
465 5204d5b1 Csaba Kiraly
        if(p) {
466 10c75ef7 GiuseppeTropea
                av_free(p);
467 5204d5b1 Csaba Kiraly
        }
468
469 802f63d4 Csaba Kiraly
        //updating min info
470
        for (p1 = q->first_pkt; p1; p1 = p1->next) {
471
                if (!q->minpts_pkt || p1->pkt.pts < q->minpts_pkt->pts) {
472
                        q->minpts_pkt = &(p1->pkt);
473
                }
474
        }
475
476 10c75ef7 GiuseppeTropea
        return retpk;
477
}
478
479 e11386c0 CsabaKiraly
AVPacketList *SeekAndDecodePacketStartingFrom(AVPacketList *p, PacketQueue *q, int* size)
480 10c75ef7 GiuseppeTropea
{
481
        while(p) {
482
                        //check if audio packet has been already decoded
483
                        if(p->pkt.convergence_duration == 0) {
484
                                //not decoded yet, try to decode it
485 e11386c0 CsabaKiraly
                                if( !DecodeEnqueuedAudio(&(p->pkt), q, size) ) {
486 10c75ef7 GiuseppeTropea
                                        //it was not possible to decode this packet, return next one
487
                                        p = RemoveFromQueue(q, p);
488
                                }
489
                                else
490
                                        return p;
491
                        }
492
                        else
493
                                return p;
494
        }
495
        return NULL;
496
}
497
498 e11386c0 CsabaKiraly
int PacketQueueGet(PacketQueue *q, AVPacket *pkt, short int av, int* size)
499 31e4e8ba GiuseppeTropea
{
500 10c75ef7 GiuseppeTropea
        //AVPacket tmp;
501
        AVPacketList *pkt1 = NULL;
502
        int ret=-1;
503
        int SizeToCopy=0;
504 e11386c0 CsabaKiraly
        struct timeval now_tv;
505 bdd9a5f5 Csaba Kiraly
        int reqsize;
506 10c75ef7 GiuseppeTropea
507
        SDL_LockMutex(q->mutex);
508
509
#ifdef DEBUG_QUEUE
510 730c29f4 GiuseppeTropea
        printf("QUEUE: Get NPackets=%d Type=%s\n", q->nb_packets, (q->queueType==AUDIO) ? "AUDIO" : "VIDEO");
511 10c75ef7 GiuseppeTropea
#endif
512
513
        if((q->queueType==AUDIO && QueueFillingMode) || QueueStopped)
514
        {
515
                SDL_UnlockMutex(q->mutex);
516
                return -1;
517
        }
518
519
        if(av==1) { //somebody requested an audio packet, q is the audio queue
520 bdd9a5f5 Csaba Kiraly
                reqsize = dimAudioQ; //TODO pass this as parameter, not garanteed by SDL to be exactly dimAudioQ
521
                pkt->size = 0;
522
                pkt->dts = 0;
523
                pkt->pts = 0;
524 10c75ef7 GiuseppeTropea
                //try to dequeue the first packet of the audio queue
525 bdd9a5f5 Csaba Kiraly
                pkt1 = q->first_pkt;
526
                while (pkt->size < reqsize && pkt1 && SeekAndDecodePacketStartingFrom(pkt1, q, size)) {
527 55ebaadf Csaba Kiraly
                        AVPacketList *next = pkt1->next;        //save it here since we could delete pkt1 later
528 bdd9a5f5 Csaba Kiraly
                        if (!pkt->dts) pkt->dts = pkt1->pkt.dts;
529
                        if (!pkt->pts) pkt->pts = pkt1->pkt.pts;
530
                        pkt->stream_index = pkt1->pkt.stream_index;
531
                        pkt->flags = 1;
532
                        pkt->pos = -1;
533
                        pkt->convergence_duration = -1;
534
                        if (pkt1->pkt.size - AudioQueueOffset <= reqsize - pkt->size) { //we need the whole packet
535
                                SizeToCopy = pkt1->pkt.size - AudioQueueOffset;        //packet might be partial
536
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
537
                                pkt->size += SizeToCopy;
538
                                AudioQueueOffset = 0;
539
                                RemoveFromQueue(q, pkt1);
540
                        } else {
541
                                SizeToCopy = reqsize - pkt->size;        //partial packet remains
542
                                memcpy(pkt->data + pkt->size, pkt1->pkt.data + AudioQueueOffset, SizeToCopy);
543
                                pkt->size += SizeToCopy;
544
                                AudioQueueOffset += SizeToCopy;
545 26b12580 Csaba Kiraly
                                pkt1->pkt.dts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
546
                                pkt1->pkt.pts += SizeToCopy/(dimAudioQ/CurrentAudioSamples)/(CurrentAudioFreq/1000);
547 10c75ef7 GiuseppeTropea
                        }
548 bdd9a5f5 Csaba Kiraly
549 10c75ef7 GiuseppeTropea
#ifdef DEBUG_AUDIO_BUFFER
550 bdd9a5f5 Csaba Kiraly
                        printf("2: idx %d    \taqo %d    \tstc %d    \taqe %f    \tpsz %d\n", pkt1->pkt.stream_index, AudioQueueOffset, SizeToCopy, deltaAudioQError, pkt1->pkt.size);
551 10c75ef7 GiuseppeTropea
#endif
552
553 bdd9a5f5 Csaba Kiraly
                        //update index of last frame extracted
554 8b3daf42 Csaba Kiraly
                        //ChunkerPlayerStats_UpdateAudioLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
555 bdd9a5f5 Csaba Kiraly
                        q->last_frame_extracted = pkt->stream_index;
556
557 55ebaadf Csaba Kiraly
                        pkt1 = next;
558 10c75ef7 GiuseppeTropea
                }
559 bdd9a5f5 Csaba Kiraly
                ret = 1; //TODO: check some conditions
560
        } else { //somebody requested a video packet, q is the video queue
561 10c75ef7 GiuseppeTropea
                pkt1 = q->first_pkt;
562
                if(pkt1) {
563 730c29f4 GiuseppeTropea
#ifdef DEBUG_QUEUE_DEEP
564 10c75ef7 GiuseppeTropea
                        printf("  AV not 1\n");
565
#endif
566
                        pkt->size = pkt1->pkt.size;
567
                        pkt->dts = pkt1->pkt.dts;
568
                        pkt->pts = pkt1->pkt.pts;
569
                        pkt->stream_index = pkt1->pkt.stream_index;
570
                        pkt->flags = pkt1->pkt.flags;
571
                        pkt->pos = pkt1->pkt.pos;
572
                        pkt->convergence_duration = pkt1->pkt.convergence_duration;
573
                        //*pkt = pkt1->pkt;
574 69fd123e GiuseppeTropea
                        
575
                        if((pkt->data != NULL) && (pkt1->pkt.data != NULL))
576
                                memcpy(pkt->data, pkt1->pkt.data, pkt1->pkt.size);
577 e11386c0 CsabaKiraly
                                
578 10c75ef7 GiuseppeTropea
                        //HINT SEE BEFORE q->size -= pkt1->pkt.size;
579 72d1fe4f Csaba Kiraly
                        RemoveFromQueue(q, pkt1);
580 10c75ef7 GiuseppeTropea
581
                        ret = 1;
582 e11386c0 CsabaKiraly
                        
583
                        ChunkerPlayerStats_UpdateVideoLossHistory(&(q->PacketHistory), pkt->stream_index, q->last_frame_extracted);
584
                        
585 10c75ef7 GiuseppeTropea
                        //update index of last frame extracted
586
                        q->last_frame_extracted = pkt->stream_index;
587 e11386c0 CsabaKiraly
                        last_video_frame_extracted = q->last_frame_extracted;
588 10c75ef7 GiuseppeTropea
                }
589
#ifdef DEBUG_QUEUE
590
                else {
591
                        printf("  VIDEO pk1 NULL!!!!\n");
592
                }
593
#endif
594
        }
595
596
        if(q->nb_packets==0 && q->queueType==AUDIO) {
597
                QueueFillingMode=1;
598
#ifdef DEBUG_QUEUE
599
                printf("QUEUE: Get FillingMode ON\n");
600
#endif
601
        }
602
#ifdef DEBUG_QUEUE
603 730c29f4 GiuseppeTropea
        printf("QUEUE: Get Last %s Frame Extracted = %d\n", (q->queueType==AUDIO) ? "AUDIO" : "VIDEO", q->last_frame_extracted);
604 10c75ef7 GiuseppeTropea
#endif
605
606
        SDL_UnlockMutex(q->mutex);
607
        return ret;
608
}
609
610
int AudioDecodeFrame(uint8_t *audio_buf, int buf_size) {
611
        //struct timeval now;
612
        int audio_pkt_size = 0;
613 e11386c0 CsabaKiraly
        int compressed_size = 0;
614 10c75ef7 GiuseppeTropea
        long long Now;
615
        short int DecodeAudio=0, SkipAudio=0;
616
        //int len1, data_size;
617
618
        //gettimeofday(&now,NULL);
619
        //Now = (now.tv_sec)*1000+now.tv_usec/1000;
620
        Now=(long long)SDL_GetTicks();
621 e11386c0 CsabaKiraly
        struct timeval now_tv;
622 10c75ef7 GiuseppeTropea
623
        if(QueueFillingMode || QueueStopped)
624
        {
625
                //SDL_LockMutex(timing_mutex);
626
                FirstTimeAudio=1;
627
                FirstTime = 1;
628
                //SDL_UnlockMutex(timing_mutex);
629
                return -1;
630
        }
631
632
        if((FirstTime==1 || FirstTimeAudio==1) && audioq.size>0) {
633
                if(audioq.first_pkt->pkt.pts>0)
634
                {
635
                        //SDL_LockMutex(timing_mutex);
636
                        DeltaTime=Now-(long long)(audioq.first_pkt->pkt.pts);
637
                        FirstTimeAudio = 0;
638
                        FirstTime = 0;
639
                        //SDL_UnlockMutex(timing_mutex);
640
#ifdef DEBUG_AUDIO 
641
                         printf("AUDIO: audio_decode_frame - DeltaTimeAudio=%lld\n",DeltaTime);
642
#endif
643
                }
644
        }
645
646
#ifdef DEBUG_AUDIO 
647
        if(audioq.first_pkt)
648
        {
649
                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);
650
                printf("AUDIO: QueueLen=%d ",(int)audioq.nb_packets);
651
                printf("AUDIO: QueueSize=%d\n",(int)audioq.size);
652
        }
653
        else
654
                printf("AUDIO: audio_decode_frame - Empty queue\n");
655
#endif
656
657 e11386c0 CsabaKiraly
        gettimeofday(&now_tv, NULL);
658
        if(audioq.nb_packets>0)
659
        {
660 797f31cb Csaba Kiraly
                if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //too late ... TODO: figure out the right number
661 e11386c0 CsabaKiraly
                {
662 10c75ef7 GiuseppeTropea
                        SkipAudio = 1;
663
                        DecodeAudio = 0;
664
                }
665 797f31cb Csaba Kiraly
                else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
666
                        (double)audioq.first_pkt->pkt.pts+DeltaTime<=Now+deltaAudioQ+3*deltaAudioQ) {        //TODO: how much in future? On some systems, SDL asks for more buffers in a raw
667 10c75ef7 GiuseppeTropea
                                SkipAudio = 0;
668
                                DecodeAudio = 1;
669
                }
670
        }
671 e11386c0 CsabaKiraly
        
672
        while(SkipAudio==1 && audioq.size>0)
673
        {
674 10c75ef7 GiuseppeTropea
                SkipAudio = 0;
675
#ifdef DEBUG_AUDIO
676
                 printf("AUDIO: skipaudio: queue size=%d\n",audioq.size);
677
#endif
678 e11386c0 CsabaKiraly
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
679 10c75ef7 GiuseppeTropea
                        return -1;
680
                }
681
                if(audioq.first_pkt)
682
                {
683 e11386c0 CsabaKiraly
                        ChunkerPlayerStats_UpdateAudioSkipHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
684
                        
685 797f31cb Csaba Kiraly
                        if((double)audioq.first_pkt->pkt.pts+DeltaTime<Now+deltaAudioQ)        //TODO: figure out the right number
686 e11386c0 CsabaKiraly
                        {
687 10c75ef7 GiuseppeTropea
                                SkipAudio = 1;
688
                                DecodeAudio = 0;
689
                        }
690 797f31cb Csaba Kiraly
                        else if((double)audioq.first_pkt->pkt.pts+DeltaTime>=Now+deltaAudioQ &&        //TODO: figure out the right number
691
                                (double)audioq.first_pkt->pkt.pts+DeltaTime<=Now+deltaAudioQ+3*deltaAudioQ) {        //TODO: how much in future?
692 10c75ef7 GiuseppeTropea
                                        SkipAudio = 0;
693
                                        DecodeAudio = 1;
694
                        }
695
                }
696
        }
697
        if(DecodeAudio==1) {
698 e11386c0 CsabaKiraly
                if(PacketQueueGet(&audioq,&AudioPkt,1, &compressed_size) < 0) {
699 10c75ef7 GiuseppeTropea
                        return -1;
700
                }
701
                memcpy(audio_buf,AudioPkt.data,AudioPkt.size);
702
                audio_pkt_size = AudioPkt.size;
703
#ifdef DEBUG_AUDIO
704
                 printf("AUDIO: Decode audio\n");
705
#endif
706 e11386c0 CsabaKiraly
707
                ChunkerPlayerStats_UpdateAudioPlayedHistory(&(audioq.PacketHistory), AudioPkt.stream_index, compressed_size);
708 10c75ef7 GiuseppeTropea
        }
709
710
        return audio_pkt_size;
711
}
712
713
int VideoCallback(void *valthread)
714
{
715
        //AVPacket pktvideo;
716
        AVCodecContext  *pCodecCtx;
717
        AVCodec         *pCodec;
718
        AVFrame         *pFrame;
719
        int frameFinished;
720
        AVPicture pict;
721
        long long Now;
722
        short int SkipVideo, DecodeVideo;
723 f2376895 Csaba Kiraly
        uint64_t last_pts = 0;
724 e11386c0 CsabaKiraly
        
725
#ifdef SAVE_YUV
726
        static AVFrame* lastSavedFrameBuffer = NULL;
727
        
728
        if(!lastSavedFrameBuffer)
729
                lastSavedFrameBuffer = (AVFrame*) malloc(sizeof(AVFrame));
730
#endif
731 10c75ef7 GiuseppeTropea
732
        //double frame_rate = 0.0,time_between_frames=0.0;
733
        //struct timeval now;
734
735
        //int wait_for_sync = 1;
736
        ThreadVal *tval;
737
        tval = (ThreadVal *)valthread;
738
739
        //frame_rate = tval->framerate;
740
        //time_between_frames = 1.e6 / frame_rate;
741
        //gettimeofday(&time_now,0);
742
743
        //frecon = fopen("recondechunk.mpg","wb");
744
745 2f5ae7bb Csaba Kiraly
        //setup video decoder
746
        pCodec = avcodec_find_decoder_by_name(video_codec);
747
        if (pCodec) {
748
                fprintf(stderr, "INIT: Setting VIDEO codecID to: %d\n",pCodec->id);
749
        } else {
750
                fprintf(stderr, "INIT: Unknown VIDEO codec: %s!\n", video_codec);
751
                return -1; // Codec not found
752
        }
753
754 10c75ef7 GiuseppeTropea
        pCodecCtx=avcodec_alloc_context();
755
        pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
756 e11386c0 CsabaKiraly
        //pCodecCtx->debug = FF_DEBUG_DCT_COEFF;
757 2f5ae7bb Csaba Kiraly
        pCodecCtx->codec_id = pCodec->id;
758
759 10c75ef7 GiuseppeTropea
        //pCodecCtx->bit_rate = 400000;
760
        // resolution must be a multiple of two
761
        pCodecCtx->width = tval->width;//176;//352;
762
        pCodecCtx->height = tval->height;//144;//288;
763 e11386c0 CsabaKiraly
764 10c75ef7 GiuseppeTropea
        // frames per second
765
        //pCodecCtx->time_base = (AVRational){1,25};
766
        //pCodecCtx->gop_size = 10; // emit one intra frame every ten frames
767
        //pCodecCtx->max_b_frames=1;
768
        pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
769
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
770
771
        if(pCodec==NULL) {
772
                fprintf(stderr, "Unsupported codec!\n");
773
                return -1; // Codec not found
774
        }
775
        if(avcodec_open(pCodecCtx, pCodec) < 0) {
776
                fprintf(stderr, "could not open codec\n");
777
                return -1; // Could not open codec
778
        }
779
        pFrame=avcodec_alloc_frame();
780
        if(pFrame==NULL) {
781
                printf("Memory error!!!\n");
782
                return -1;
783
        }
784
        
785
#ifdef DEBUG_VIDEO
786
         printf("VIDEO: video_callback entering main cycle\n");
787
#endif
788 e11386c0 CsabaKiraly
789
        struct timeval now_tv;
790 10c75ef7 GiuseppeTropea
        while(AVPlaying && !quit) {
791
                if(QueueFillingMode || QueueStopped)
792
                {
793
                        //SDL_LockMutex(timing_mutex);
794
                        FirstTime = 1;
795
                        //SDL_UnlockMutex(timing_mutex);
796
                        usleep(5000);
797
                        continue;
798
                }
799
800
                DecodeVideo = 0;
801
                SkipVideo = 0;
802
                Now=(long long)SDL_GetTicks();
803
                if(FirstTime==1 && videoq.size>0) {
804
                        if(videoq.first_pkt->pkt.pts>0)
805
                        {
806
                                //SDL_LockMutex(timing_mutex);
807
                                DeltaTime=Now-(long long)videoq.first_pkt->pkt.pts;
808
                                FirstTime = 0;
809
                                //SDL_UnlockMutex(timing_mutex);
810
                        }
811
#ifdef DEBUG_VIDEO 
812
                         printf("VIDEO: VideoCallback - DeltaTimeAudio=%lld\n",DeltaTime);
813
#endif
814
                }
815
816
#ifdef DEBUG_VIDEO 
817
                if(videoq.first_pkt)
818
                {
819
                        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);
820
                        printf("VIDEO: Index=%d ", (int)videoq.first_pkt->pkt.stream_index);
821
                        printf("VIDEO: QueueLen=%d ", (int)videoq.nb_packets);
822
                        printf("VIDEO: QueueSize=%d\n", (int)videoq.size);
823
                }
824
                else
825
                        printf("VIDEO: VideoCallback - Empty queue\n");
826
#endif
827
828
                if(videoq.nb_packets>0) {
829 3f0d2b09 Csaba Kiraly
                        long long target_ts = videoq.minpts_pkt->pts + DeltaTime;
830 eddda230 Csaba Kiraly
                        long long frame_timespan = MAX_TOLLERANCE;        //TODO: calculate real value
831 3f0d2b09 Csaba Kiraly
                        if(target_ts<Now-(long long)MAX_TOLLERANCE) {
832 10c75ef7 GiuseppeTropea
                                SkipVideo = 1;
833
                                DecodeVideo = 0;
834 3f0d2b09 Csaba Kiraly
                        } else if(target_ts>=Now-(long long)MAX_TOLLERANCE && target_ts<=Now) {
835
                                SkipVideo = 0;
836
                                DecodeVideo = 1;
837
                        } else if (last_pts+frame_timespan+DeltaTime<=Now) {
838
                                SkipVideo = 0;
839
                                DecodeVideo = 1;
840 10c75ef7 GiuseppeTropea
                        }
841
                }
842 3f0d2b09 Csaba Kiraly
                // else (i.e. videoq.minpts_pkt->pts+DeltaTime>Now+MAX_TOLLERANCE)
843
                // do nothing and continue
844 10c75ef7 GiuseppeTropea
#ifdef DEBUG_VIDEO
845
                printf("VIDEO: skipvideo:%d decodevideo:%d\n",SkipVideo,DecodeVideo);
846
#endif
847 e11386c0 CsabaKiraly
                gettimeofday(&now_tv, NULL);
848
                
849 3f0d2b09 Csaba Kiraly
                if(SkipVideo==1 && videoq.size>0)
850 e11386c0 CsabaKiraly
                {
851 10c75ef7 GiuseppeTropea
                        SkipVideo = 0;
852
#ifdef DEBUG_VIDEO 
853
                         printf("VIDEO: Skip Video\n");
854
#endif
855 e11386c0 CsabaKiraly
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) < 0) {
856 10c75ef7 GiuseppeTropea
                                break;
857
                        }
858 e11386c0 CsabaKiraly
859 10c75ef7 GiuseppeTropea
                        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
860 e11386c0 CsabaKiraly
                        
861
                        // sometimes assertion fails, maybe the decoder change the frame type
862
                        //~ if(LastSourceIFrameDistance == 0)
863
                                //~ assert(pFrame->pict_type == 1);
864
865
                        
866
                        ChunkerPlayerStats_UpdateVideoSkipHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
867
                        
868
                        /*if(pFrame->pict_type == 1)
869
                        {
870
                                int i1;
871
                                // every 23 items (23 is the qstride field in the AVFrame struct) there is 1 zero.
872
                                // 396/23 = 17 => 396 macroblocks + 17 zeros = 413 items
873
                                for(i1=0; i1< 413; i1++)
874
                                        fprintf(qscaletable_file, "%d\t", (int)pFrame->qscale_table[i1]);
875
                                fprintf(qscaletable_file, "\n");
876
                        }*/
877
                        
878
                        //ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size);
879 3f0d2b09 Csaba Kiraly
                        continue;
880 10c75ef7 GiuseppeTropea
                }
881
882 b2538639 Csaba Kiraly
                if (DecodeVideo==1) {
883 e11386c0 CsabaKiraly
                        if(PacketQueueGet(&videoq,&VideoPkt,0, NULL) > 0) {
884 10c75ef7 GiuseppeTropea
                                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &VideoPkt);
885 f2376895 Csaba Kiraly
                                last_pts = pFrame->pkt_pts;
886
                                if (!videoq.minpts_pkt || videoq.minpts_pkt->pts > Now - DeltaTime) {
887 451f397a Csaba Kiraly
                                        DecodeVideo = 0;
888
                                }
889 10c75ef7 GiuseppeTropea
890 e11386c0 CsabaKiraly
                                if(frameFinished)
891
                                { // it must be true all the time else error
892 10c75ef7 GiuseppeTropea
#ifdef DEBUG_VIDEO
893
                                        printf("VIDEO: FrameFinished\n");
894
#endif
895 e11386c0 CsabaKiraly
                                        decoded_vframes++;
896
                                        
897
                                        // sometimes assertion fails, maybe the decoder change the frame type
898
                                        //~ if(LastSourceIFrameDistance == 0)
899
                                                //~ assert(pFrame->pict_type == 1);
900
#ifdef SAVE_YUV
901
                                        if(LastSavedVFrame == -1)
902
                                        {
903
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
904 10c75ef7 GiuseppeTropea
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
905 e11386c0 CsabaKiraly
                                                LastSavedVFrame = VideoPkt.stream_index;
906
                                        }
907
                                        else if(LastSavedVFrame == (VideoPkt.stream_index-1))
908
                                        {
909
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
910
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
911
                                                LastSavedVFrame = VideoPkt.stream_index;
912
                                        }
913
                                        else if(LastSavedVFrame >= 0)
914
                                        {
915
                                                while(LastSavedVFrame < (VideoPkt.stream_index-1))
916
                                                {
917
                                                        SaveFrame(lastSavedFrameBuffer, pCodecCtx->width, pCodecCtx->height);
918
                                                }
919
920
                                                memcpy(lastSavedFrameBuffer, pFrame, sizeof(AVFrame));
921
                                                SaveFrame(pFrame, pCodecCtx->width, pCodecCtx->height);
922
                                                LastSavedVFrame = VideoPkt.stream_index;
923
                                        }
924
#endif
925
                                        ChunkerPlayerStats_UpdateVideoPlayedHistory(&(videoq.PacketHistory), VideoPkt.stream_index, pFrame->pict_type, VideoPkt.size, pFrame);
926 10c75ef7 GiuseppeTropea
927
                                        if(SilentMode)
928
                                                continue;
929
930
                                        // Lock SDL_yuv_overlay
931
                                        if(SDL_MUSTLOCK(MainScreen)) {
932
                                                if(SDL_LockSurface(MainScreen) < 0) {
933
                                                        continue;
934
                                                }
935
                                        }
936
937
                                        if(SDL_LockYUVOverlay(YUVOverlay) < 0) {
938
                                                if(SDL_MUSTLOCK(MainScreen)) {
939
                                                        SDL_UnlockSurface(MainScreen);
940
                                                }
941
                                                continue;
942
                                        }
943
                                        
944
                                        pict.data[0] = YUVOverlay->pixels[0];
945
                                        pict.data[1] = YUVOverlay->pixels[2];
946
                                        pict.data[2] = YUVOverlay->pixels[1];
947
948
                                        pict.linesize[0] = YUVOverlay->pitches[0];
949
                                        pict.linesize[1] = YUVOverlay->pitches[2];
950
                                        pict.linesize[2] = YUVOverlay->pitches[1];
951
952
                                        if(img_convert_ctx == NULL) {
953
                                                img_convert_ctx = sws_getContext(tval->width, tval->height, PIX_FMT_YUV420P, InitRect->w, InitRect->h, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
954
                                                if(img_convert_ctx == NULL) {
955
                                                        fprintf(stderr, "Cannot initialize the conversion context!\n");
956
                                                        exit(1);
957
                                                }
958
                                        }
959 e11386c0 CsabaKiraly
                                        
960
#ifdef VIDEO_DEINTERLACE
961
                                        avpicture_deinterlace(
962
                                                (AVPicture*) pFrame,
963
                                                (const AVPicture*) pFrame,
964
                                                pCodecCtx->pix_fmt,
965
                                                tval->width, tval->height);
966
#endif
967
                                        
968 10c75ef7 GiuseppeTropea
                                        // let's draw the data (*yuv[3]) on a SDL screen (*screen)
969
                                        sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, tval->height, pict.data, pict.linesize);
970
                                        SDL_UnlockYUVOverlay(YUVOverlay);
971
                                        // Show, baby, show!
972
                                        SDL_LockMutex(OverlayMutex);
973
                                        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
974
                                        SDL_UnlockMutex(OverlayMutex);
975
976
                                        //redisplay logo
977
                                        /**SDL_BlitSurface(image, NULL, MainScreen, &dest);*/
978
                                        /* Update the screen area just changed */
979
                                        /**SDL_UpdateRects(MainScreen, 1, &dest);*/
980
981
                                        if(SDL_MUSTLOCK(MainScreen)) {
982
                                                SDL_UnlockSurface(MainScreen);
983
                                        }
984
                                } //if FrameFinished
985 e11386c0 CsabaKiraly
                                else
986
                                {
987
                                        ChunkerPlayerStats_UpdateVideoLossHistory(&(videoq.PacketHistory), VideoPkt.stream_index+1, videoq.last_frame_extracted-1);
988
                                }
989 451f397a Csaba Kiraly
                        } else { // if packet_queue_get
990
                                DecodeVideo = 0;
991
                        }
992 10c75ef7 GiuseppeTropea
                } //if DecodeVideo=1
993
994
                usleep(5000);
995
        }
996 e11386c0 CsabaKiraly
        avcodec_close(pCodecCtx);
997 10c75ef7 GiuseppeTropea
        av_free(pCodecCtx);
998
        av_free(pFrame);
999
        //fclose(frecon);
1000
#ifdef DEBUG_VIDEO
1001
         printf("VIDEO: video callback end\n");
1002
#endif
1003 e11386c0 CsabaKiraly
1004
#ifdef SAVE_YUV
1005
        if(!lastSavedFrameBuffer)
1006
                free(lastSavedFrameBuffer);
1007
        
1008
        lastSavedFrameBuffer = NULL;
1009
#endif
1010
1011 10c75ef7 GiuseppeTropea
        return 0;
1012
}
1013
1014
void AudioCallback(void *userdata, Uint8 *stream, int len)
1015
{
1016
        //AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
1017
        int audio_size;
1018
1019
        static uint8_t audio_buf[AVCODEC_MAX_AUDIO_FRAME_SIZE];
1020
1021 6ca535a1 Csaba Kiraly
        memset(audio_buf, CurrentAudioSilence, sizeof(audio_buf));
1022 10c75ef7 GiuseppeTropea
        audio_size = AudioDecodeFrame(audio_buf, sizeof(audio_buf));
1023 5ca3d85e GiuseppeTropea
        
1024 ccf75e3a GiuseppeTropea
        if(SilentMode < 2)
1025 5ca3d85e GiuseppeTropea
                if(audio_size != len) {
1026 6ca535a1 Csaba Kiraly
                        memset(stream, CurrentAudioSilence, len);
1027 5ca3d85e GiuseppeTropea
                } else {
1028
                        memcpy(stream, (uint8_t *)audio_buf, len);
1029
                }
1030 10c75ef7 GiuseppeTropea
}
1031
1032
void SaveFrame(AVFrame *pFrame, int width, int height)
1033
{
1034
        FILE *pFile;
1035
        int  y;
1036
  
1037
         // Open file
1038
        pFile=fopen(YUVFileName, "ab");
1039
        if(pFile==NULL)
1040
                return;
1041
  
1042
        // Write header
1043
        //fprintf(pFile, "P5\n%d %d\n255\n", width, height);
1044
  
1045
        // Write Y data
1046
        for(y=0; y<height; y++)
1047
                  fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width, pFile);
1048
        // Write U data
1049
        for(y=0; y<height/2; y++)
1050
                  fwrite(pFrame->data[1]+y*pFrame->linesize[1], 1, width/2, pFile);
1051
        // Write V data
1052
        for(y=0; y<height/2; y++)
1053
                  fwrite(pFrame->data[2]+y*pFrame->linesize[2], 1, width/2, pFile);
1054
  
1055
        // Close file
1056
        fclose(pFile);
1057
}
1058
1059
int ChunkerPlayerCore_IsRunning()
1060
{
1061
        return AVPlaying;
1062
}
1063
1064
void ChunkerPlayerCore_Play()
1065
{
1066
        if(AVPlaying) return;
1067
        AVPlaying = 1;
1068 e11386c0 CsabaKiraly
        
1069 10c75ef7 GiuseppeTropea
        SDL_PauseAudio(0);
1070
        video_thread = SDL_CreateThread(VideoCallback, &VideoCallbackThreadParams);
1071 e11386c0 CsabaKiraly
        ChunkerPlayerStats_Init();
1072
        stats_thread = SDL_CreateThread(CollectStatisticsThread, NULL);
1073
        
1074
        decoded_vframes = 0;
1075
        LastSavedVFrame = -1;
1076 10c75ef7 GiuseppeTropea
}
1077
1078
void ChunkerPlayerCore_Stop()
1079
{
1080
        if(!AVPlaying) return;
1081
        
1082
        AVPlaying = 0;
1083
        
1084
        // Stop audio&video playback
1085
        SDL_WaitThread(video_thread, NULL);
1086 e11386c0 CsabaKiraly
        SDL_WaitThread(stats_thread, NULL);
1087
        SDL_PauseAudio(1);        
1088 10c75ef7 GiuseppeTropea
        SDL_CloseAudio();
1089
        
1090
        if(YUVOverlay != NULL)
1091
        {
1092
                SDL_FreeYUVOverlay(YUVOverlay);
1093
                YUVOverlay = NULL;
1094
        }
1095
        
1096 333348bb GiuseppeTropea
        PacketQueueReset(&audioq);
1097
        PacketQueueReset(&videoq);
1098 10c75ef7 GiuseppeTropea
        
1099 e11386c0 CsabaKiraly
        avcodec_close(aCodecCtx);
1100 10c75ef7 GiuseppeTropea
        av_free(aCodecCtx);
1101
        free(AudioPkt.data);
1102
        free(VideoPkt.data);
1103
        free(outbuf_audio);
1104
        free(InitRect);
1105 e11386c0 CsabaKiraly
        
1106
        /*
1107
        * Sleep two buffers' worth of audio before closing, in order
1108
        *  to allow the playback to finish. This isn't always enough;
1109
        *   perhaps SDL needs a way to explicitly wait for device drain?
1110
        */
1111
        int delay = 2 * 1000 * CurrentAudioSamples / CurrentAudioFreq;
1112
        // printf("SDL_Delay(%d)\n", delay*10);
1113
        SDL_Delay(delay*10);
1114
}
1115
1116
void ChunkerPlayerCore_Pause()
1117
{
1118
        if(!AVPlaying) return;
1119
        
1120
        AVPlaying = 0;
1121
        
1122
        // Stop audio&video playback
1123
        SDL_WaitThread(video_thread, NULL);
1124
        SDL_PauseAudio(1);
1125
        
1126
        PacketQueueReset(&audioq);
1127
        PacketQueueReset(&videoq);
1128 10c75ef7 GiuseppeTropea
}
1129
1130 31e4e8ba GiuseppeTropea
int ChunkerPlayerCore_AudioEnded()
1131 10c75ef7 GiuseppeTropea
{
1132
        return (audioq.nb_packets==0 && audioq.last_frame_extracted>0);
1133
}
1134
1135
void ChunkerPlayerCore_ResetAVQueues()
1136
{
1137
#ifdef DEBUG_QUEUE
1138
        printf("QUEUE: MAIN SHOULD RESET\n");
1139
#endif
1140 333348bb GiuseppeTropea
        PacketQueueReset(&audioq);
1141
        PacketQueueReset(&videoq);
1142 10c75ef7 GiuseppeTropea
}
1143
1144
int ChunkerPlayerCore_EnqueueBlocks(const uint8_t *block, const int block_size)
1145
{
1146 e11386c0 CsabaKiraly
#ifdef EMULATE_CHUNK_LOSS
1147
        static time_t loss_cycle_start_time = 0, now = 0;
1148
        static int early_losses = 0;
1149
        static int clp_frames = 0;
1150
        
1151
        if(ScheduledChunkLosses)
1152
        {
1153
                static unsigned int random_threshold;
1154
                now=time(NULL);
1155
                if(!loss_cycle_start_time)
1156
                        loss_cycle_start_time = now;
1157
                        
1158
                if(((now-loss_cycle_start_time) >= ScheduledChunkLosses[((CurrChunkLossIndex+1)%NScheduledChunkLosses)].Time) && (NScheduledChunkLosses>1 || CurrChunkLossIndex==-1))
1159
                {
1160
                        CurrChunkLossIndex = ((CurrChunkLossIndex+1)%NScheduledChunkLosses);
1161
                        if(CurrChunkLossIndex == (NScheduledChunkLosses-1))
1162
                                loss_cycle_start_time = now;
1163
                        
1164
                        if(ScheduledChunkLosses[CurrChunkLossIndex].Value == -1)
1165
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].MinValue + (rand() % (ScheduledChunkLosses[CurrChunkLossIndex].MaxValue-ScheduledChunkLosses[CurrChunkLossIndex].MinValue));
1166
                        else
1167
                                random_threshold = ScheduledChunkLosses[CurrChunkLossIndex].Value;
1168
                        
1169
                        printf("new ScheduledChunkLoss, time: %d, value: %d\n", (int)ScheduledChunkLosses[CurrChunkLossIndex].Time, random_threshold);
1170
                }
1171
        
1172
                if(clp_frames > 0)
1173
                {
1174
                        clp_frames--;
1175
                        return PLAYER_FAIL_RETURN;
1176
                }
1177
                if((rand() % 100) < random_threshold)
1178
                {
1179
                        if(early_losses > 0)
1180
                early_losses--;
1181
            else
1182
            {
1183
                clp_frames=early_losses=(ScheduledChunkLosses[CurrChunkLossIndex].Burstiness-1);
1184
                return PLAYER_FAIL_RETURN;
1185
            }
1186
                }
1187
        }
1188
#endif
1189
1190 10c75ef7 GiuseppeTropea
        Chunk *gchunk = NULL;
1191
        int decoded_size = -1;
1192
        uint8_t *tempdata, *buffer;
1193 31e4e8ba GiuseppeTropea
        int j;
1194 10c75ef7 GiuseppeTropea
        Frame *frame = NULL;
1195
        AVPacket packet, packetaudio;
1196
1197
        uint16_t *audio_bufQ = NULL;
1198
1199
        //the frame.h gets encoded into 5 slots of 32bits (3 ints plus 2 more for the timeval struct
1200
        static int sizeFrameHeader = 5*sizeof(int32_t);
1201
        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;
1202
1203 dae4a53f GiuseppeTropea
        static int chunks_out_of_order = 0;
1204
        static int last_chunk_id = -1;
1205
1206 10c75ef7 GiuseppeTropea
        audio_bufQ = (uint16_t *)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
1207
        if(!audio_bufQ) {
1208
                printf("Memory error in audio_bufQ!\n");
1209
                return PLAYER_FAIL_RETURN;
1210
        }
1211
1212
        gchunk = (Chunk *)malloc(sizeof(Chunk));
1213
        if(!gchunk) {
1214
                printf("Memory error in gchunk!\n");
1215
                av_free(audio_bufQ);
1216
                return PLAYER_FAIL_RETURN;
1217
        }
1218
1219
        decoded_size = decodeChunk(gchunk, block, block_size);
1220 dae4a53f GiuseppeTropea
1221
        if(last_chunk_id == -1)
1222
                last_chunk_id = gchunk->id;
1223
1224
        if(gchunk->id > (last_chunk_id+1)) {
1225
                chunks_out_of_order += gchunk->id - last_chunk_id - 1;
1226
        }
1227
        last_chunk_id = gchunk->id;
1228
1229 10c75ef7 GiuseppeTropea
#ifdef DEBUG_CHUNKER
1230 aa041505 GiuseppeTropea
        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);
1231 10c75ef7 GiuseppeTropea
#endif
1232 aa8b089c CsabaKiraly
  if(decoded_size < 0) {
1233 10c75ef7 GiuseppeTropea
                //HINT here i should differentiate between various return values of the decode
1234
                //in order to free what has been allocated there
1235
                printf("chunk probably corrupted!\n");
1236
                av_free(audio_bufQ);
1237
                free(gchunk);
1238
                return PLAYER_FAIL_RETURN;
1239
        }
1240
1241
        frame = (Frame *)malloc(sizeof(Frame));
1242
        if(!frame) {
1243
                printf("Memory error in Frame!\n");
1244 5ba8c167 CsabaKiraly
                if(gchunk) {
1245
                        if(gchunk->attributes) {
1246
                                free(gchunk->attributes);
1247
                        }
1248
                        free(gchunk);
1249
                }
1250 10c75ef7 GiuseppeTropea
                av_free(audio_bufQ);
1251
                return PLAYER_FAIL_RETURN;
1252
        }
1253
1254 5ba8c167 CsabaKiraly
        tempdata = gchunk->data; //let it point to first frame of payload
1255
        j=gchunk->size;
1256 10c75ef7 GiuseppeTropea
        while(j>0 && !quit) {
1257
                frame->number = bit32_encoded_pull(tempdata);
1258
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1259
                frame->timestamp.tv_sec = bit32_encoded_pull(tempdata);
1260
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1261
                frame->timestamp.tv_usec = bit32_encoded_pull(tempdata);
1262
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1263
                frame->size = bit32_encoded_pull(tempdata);
1264
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1265
                frame->type = bit32_encoded_pull(tempdata);
1266
                tempdata += CHUNK_TRANSCODING_INT_SIZE;
1267
1268
                buffer = tempdata; // here coded frame information
1269
                tempdata += frame->size; //let it point to the next frame
1270
1271
                if(frame->type < 5) { // video frame
1272
                        av_init_packet(&packet);
1273
                        packet.data = buffer;//video_bufQ;
1274
                        packet.size = frame->size;
1275
                        packet.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1276
                        packet.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1277
                        packet.stream_index = frame->number; // use of stream_index for number frame
1278
                        //packet.duration = frame->timestamp.tv_sec;
1279 7c0033b3 Csaba Kiraly
                        if(packet.size > 0) {
1280
                                int ret = ChunkerPlayerCore_PacketQueuePut(&videoq, &packet); //the _put makes a copy of the packet
1281
                                if (ret == 1) {        //TODO: check and correct return values
1282
                                        fprintf(stderr, "late chunk received, increasing delay\n");
1283
                                        DeltaTime += 40;        //TODO: handle audio skip; verify this value
1284
                                }
1285
                        }
1286 10c75ef7 GiuseppeTropea
1287
#ifdef DEBUG_SOURCE
1288
                        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);
1289
#endif
1290
                }
1291
                else if(frame->type == 5) { // audio frame
1292
                        av_init_packet(&packetaudio);
1293
                        packetaudio.data = buffer;
1294
                        packetaudio.size = frame->size;
1295
                        packetaudio.pts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1296
                        packetaudio.dts = frame->timestamp.tv_sec*(unsigned long long)1000+frame->timestamp.tv_usec;
1297
                        //packetaudio.duration = frame->timestamp.tv_sec;
1298
                        packetaudio.stream_index = frame->number; // use of stream_index for number frame
1299
                        packetaudio.flags = 1;
1300
                        packetaudio.pos = -1;
1301
1302
                        //instead of -1, in order to signal it is not decoded yet
1303
                        packetaudio.convergence_duration = 0;
1304
1305
                        // insert the audio frame into the queue
1306 7c0033b3 Csaba Kiraly
                        if(packetaudio.size > 0) {
1307
                                int ret = ChunkerPlayerCore_PacketQueuePut(&audioq, &packetaudio);//makes a copy of the packet so i can free here
1308
                                if (ret == 1) {        //TODO: check and correct return values
1309
                                        fprintf(stderr, "late chunk received, increasing delay\n");
1310
                                        DeltaTime += 40;        //TODO: handle audio skip; verify this value
1311
                                }
1312
                        }
1313 10c75ef7 GiuseppeTropea
1314
#ifdef DEBUG_SOURCE
1315
                        printf("SOURCE: Insert audio in queue pts=%lld sindex:%d\n", packetaudio.pts, packetaudio.stream_index);
1316
#endif
1317
                }
1318
                else {
1319
                        printf("SOURCE: Unknown frame type %d. Size %d\n", frame->type, frame->size);
1320
                }
1321
                if(frame->size > 0)
1322
                        j = j - sizeFrameHeader - frame->size;
1323
                else {
1324
                        printf("SOURCE: Corrupt frames (size %d) in chunk. Skipping it...\n", frame->size);
1325
                        j = -1;
1326
                }
1327
        }
1328
        //chunk ingestion terminated!
1329 5ba8c167 CsabaKiraly
        if(gchunk) {
1330
                if(gchunk->attributes) {
1331
                        free(gchunk->attributes);
1332
                }
1333 eac72849 GiuseppeTropea
                if(gchunk->data)
1334
                        free(gchunk->data);
1335 5ba8c167 CsabaKiraly
                free(gchunk);
1336
        }
1337 10c75ef7 GiuseppeTropea
        if(frame)
1338
                free(frame);
1339
        if(audio_bufQ)
1340
                av_free(audio_bufQ);
1341 31e4e8ba GiuseppeTropea
                
1342
        return PLAYER_OK_RETURN;
1343 10c75ef7 GiuseppeTropea
}
1344
1345
void ChunkerPlayerCore_SetupOverlay(int width, int height)
1346
{
1347 31e4e8ba GiuseppeTropea
        // if(!MainScreen && !SilentMode)
1348
        // {
1349
                // printf("Cannot find main screen, exiting...\n");
1350
                // exit(1);
1351
        // }
1352
        
1353
        if(SilentMode)
1354
                return;
1355
                
1356 10c75ef7 GiuseppeTropea
        SDL_LockMutex(OverlayMutex);
1357
        if(YUVOverlay != NULL)
1358
        {
1359
                SDL_FreeYUVOverlay(YUVOverlay);
1360
                YUVOverlay = NULL;
1361
        }
1362
        
1363
        // create video overlay for display of video frames
1364
        // printf("SDL_CreateYUVOverlay(%d, %d, SDL_YV12_OVERLAY, MainScreen)\n", width, height);
1365
        YUVOverlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, MainScreen);
1366
        // YUVOverlay = SDL_CreateYUVOverlay(OverlayRect.w, OverlayRect.h, SDL_YV12_OVERLAY, MainScreen);
1367
        if ( YUVOverlay == NULL )
1368
        {
1369
                fprintf(stderr,"SDL: Couldn't create SDL_yuv_overlay: %s", SDL_GetError());
1370
                exit(1);
1371
        }
1372
1373
        if ( YUVOverlay->hw_overlay )
1374
                fprintf(stderr,"SDL: Using hardware overlay.\n");
1375
        // OverlayRect.x = (screen_w - width) / 2;
1376
        
1377
        SDL_DisplayYUVOverlay(YUVOverlay, &OverlayRect);
1378
        
1379
        SDL_UnlockMutex(OverlayMutex);
1380
}
1381 e11386c0 CsabaKiraly
1382
int CollectStatisticsThread(void *params)
1383
{
1384
        struct timeval last_stats_evaluation, now, last_trace, last_qoe_evaluation;
1385
        gettimeofday(&last_stats_evaluation, NULL);
1386
        last_trace = last_stats_evaluation;
1387
        last_qoe_evaluation = last_stats_evaluation;
1388
        
1389
        double video_qdensity;
1390
        double audio_qdensity;
1391
        char audio_stats_text[255];
1392
        char video_stats_text[255];
1393
        int loss_changed = 0;
1394
        int density_changed = 0;
1395
        SStats audio_statistics, video_statistics;
1396
        double qoe = 0;
1397
        int sleep_time = STATS_THREAD_GRANULARITY*1000;
1398 54217c91 GiuseppeTropea
        int audio_avg_bitrate = 0;
1399
        int video_avg_bitrate = 0;
1400 e11386c0 CsabaKiraly
        
1401
        while(AVPlaying && !quit)
1402
        {
1403
                usleep(sleep_time);
1404
                
1405
                gettimeofday(&now, NULL);
1406
                
1407
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_stats_evaluation.tv_sec*1000)+(last_stats_evaluation.tv_usec/1000))) > GUI_PRINTSTATS_INTERVAL)
1408
                {
1409
                        // estimate audio queue stats
1410
                        int audio_stats_changed = ChunkerPlayerStats_GetStats(&(audioq.PacketHistory), &audio_statistics);
1411
                        
1412
                        // estimate video queue stats
1413
                        int video_stats_changed = ChunkerPlayerStats_GetStats(&(videoq.PacketHistory), &video_statistics);
1414
1415 54217c91 GiuseppeTropea
                        // compute avg bitrate up to now
1416
                        audioq.cumulative_bitrate += audio_statistics.Bitrate;
1417
                        audioq.cumulative_samples++;
1418
                        audio_avg_bitrate = (int)( ((double)audioq.cumulative_bitrate) / ((double)audioq.cumulative_samples) );
1419
                        videoq.cumulative_bitrate += video_statistics.Bitrate;
1420
                        videoq.cumulative_samples++;
1421
                        video_avg_bitrate = (int)( ((double)videoq.cumulative_bitrate) / ((double)videoq.cumulative_samples) );
1422
1423 e11386c0 CsabaKiraly
#ifdef DEBUG_STATS
1424
                        printf("VIDEO: %d Kbit/sec; ", video_statistics.Bitrate);
1425
                        printf("AUDIO: %d Kbit/sec\n", audio_statistics.Bitrate);
1426
#endif
1427
1428
                        // QUEUE DENSITY EVALUATION
1429
                        if((audioq.last_pkt != NULL) && (audioq.first_pkt != NULL))
1430
                                if(audioq.last_pkt->pkt.stream_index >= audioq.first_pkt->pkt.stream_index)
1431
                                {
1432
                                        //plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1433
                                        audio_qdensity = (double)audioq.nb_packets / (double)(audioq.last_pkt->pkt.stream_index - audioq.first_pkt->pkt.stream_index + 1) * 100.0;
1434
                                }
1435
                        
1436
                        if((videoq.last_pkt != NULL) && (videoq.first_pkt != NULL))
1437
                                if(videoq.last_pkt->pkt.stream_index >= videoq.first_pkt->pkt.stream_index)
1438
                                {
1439
                                        // plus 1 because if they are adjacent (difference 1) there really should be 2 packets in the queue
1440
                                        video_qdensity = (double)videoq.nb_packets / (double)(videoq.last_pkt->pkt.stream_index - videoq.first_pkt->pkt.stream_index + 1) * 100.0;
1441
                                }
1442
                        
1443
                        if(LogTraces)
1444
                        {
1445
                                ChunkerPlayerStats_PrintHistoryTrace(&(audioq.PacketHistory), AudioTraceFilename);
1446
                                ChunkerPlayerStats_PrintHistoryTrace(&(videoq.PacketHistory), VideoTraceFilename);
1447
                                
1448 0cd6b05d CarmeloDaniele
                                //if(SilentMode != 1 && SilentMode != 2)
1449 e11386c0 CsabaKiraly
                                        ChunkerPlayerStats_PrintContextFile();
1450
                        }
1451
1452
                        // PRINT STATISTICS ON GUI
1453
                        if(!Audio_ON)
1454
                                sprintf(audio_stats_text, "AUDIO MUTED");
1455
                        else if(audio_stats_changed)
1456 54217c91 GiuseppeTropea
//                                sprintf(audio_stats_text, "[AUDIO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)", (int)audioq.nb_packets, (int)audio_qdensity, (int)audio_statistics.Lossrate, audioq.PacketHistory.LostCount, audio_statistics.Skiprate, audioq.PacketHistory.SkipCount);
1457
                                sprintf(audio_stats_text, "[AUDIO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - rate: %d kbits/sec (avg: %d)", (int)audioq.nb_packets, (int)audio_qdensity, (int)audio_statistics.Lossrate, audioq.PacketHistory.LostCount, audio_statistics.Bitrate, audio_avg_bitrate);
1458 e11386c0 CsabaKiraly
                        else
1459
                                sprintf(audio_stats_text, "waiting for incoming audio packets...");
1460
1461
                        if(video_stats_changed)
1462
                        {
1463
                                char est_psnr_string[255];
1464
                                sprintf(est_psnr_string, "");
1465
                                if(qoe)
1466 0cd6b05d CarmeloDaniele
                                {
1467 e11386c0 CsabaKiraly
                                        sprintf(est_psnr_string, " - Est. Mean PSNR: %.1f db", (float)qoe);
1468 b0e46569 GiuseppeTropea
#ifdef PSNR_PUBLICATION
1469 0cd6b05d CarmeloDaniele
                                        // Publish measure into repository
1470 af11718f CarmeloDaniele
                                        if(RepoAddress[0]!='\0')
1471
                                        {
1472
                                            MeasurementRecord r;
1473
                            r.originator = NetworkID;
1474
                            r.targetA = NetworkID;
1475 0b2dc7c4 GiuseppeTropea
                            r.targetB = NULL;
1476 af11718f CarmeloDaniele
                            r.published_name = "PSNR_MEAN";
1477
                            r.value = qoe;
1478
                            r.string_value = NULL;
1479
                            r.channel = Channels[SelectedChannel].Title;
1480
                            gettimeofday(&(r.timestamp), NULL);
1481
                            // One update every REPO_UPDATE_INTERVALL seconds
1482
                            struct timeval ElapsedTime;
1483
                            timeval_subtract(&(r.timestamp),&LastTimeRepoPublish,&ElapsedTime);
1484
                        if(ElapsedTime.tv_sec>=PSNR_REPO_UPDATE_INTERVALL)
1485
                        {
1486
                            LastTimeRepoPublish=r.timestamp;
1487 055f853d GiuseppeTropea
                            if(repPublish(repoclient,NULL,NULL,&r)!=NULL) {
1488 59e008ed GiuseppeTropea
#ifdef DEBUG_PSNR
1489 af11718f CarmeloDaniele
                               printf("PSNR publish: %s  %e  %s\n",r.originator,qoe,r.channel);
1490 59e008ed GiuseppeTropea
#endif
1491 055f853d GiuseppeTropea
                                                                                                                }
1492 af11718f CarmeloDaniele
                        }
1493
                   }
1494 b0e46569 GiuseppeTropea
#endif
1495 0cd6b05d CarmeloDaniele
                                }
1496 e11386c0 CsabaKiraly
1497 54217c91 GiuseppeTropea
//                                sprintf(video_stats_text, "[VIDEO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - skips: %d/sec (%ld tot)%s", (int)videoq.nb_packets, (int)video_qdensity, video_statistics.Lossrate, videoq.PacketHistory.LostCount, video_statistics.Skiprate, videoq.PacketHistory.SkipCount, est_psnr_string);
1498
                                sprintf(video_stats_text, "[VIDEO] qsize: %d qdensity: %d\%% - losses: %d/sec (%ld tot) - rate: %d kbits/sec (avg: %d) %s", (int)videoq.nb_packets, (int)video_qdensity, video_statistics.Lossrate, videoq.PacketHistory.LostCount, video_statistics.Bitrate, video_avg_bitrate, est_psnr_string);
1499 e11386c0 CsabaKiraly
                        }
1500
                        else
1501
                                sprintf(video_stats_text, "waiting for incoming video packets...");
1502 6f1fe643 CarmeloDaniele
                        
1503
                        if(qoe)
1504
                            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)));
1505
                        else
1506
                            ChunkerPlayerGUI_SetStatsText(audio_stats_text, video_stats_text,LED_GREEN);
1507
                        
1508 e11386c0 CsabaKiraly
1509
                        last_stats_evaluation = now;
1510
                }
1511
                
1512
                if((((now.tv_sec*1000)+(now.tv_usec/1000)) - ((last_qoe_evaluation.tv_sec*1000)+(last_qoe_evaluation.tv_usec/1000))) > EVAL_QOE_INTERVAL)
1513
                {
1514
                        // ESTIMATE QoE
1515 54217c91 GiuseppeTropea
                        //ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), &qoe);
1516
                        // ESTIMATE QoE using real-time computed cumulative average bitrate
1517
                        // (plus a diminshing contribution of the instantaneous bitrate, until the cumulative avg stabilizes)
1518
                        int input_bitrate = 0;
1519
                        // stabilize after circa 30 seconds
1520
                        if(videoq.cumulative_samples < 30*(1000/GUI_PRINTSTATS_INTERVAL))
1521
                                input_bitrate = video_statistics.Bitrate;
1522
                        else
1523
                                input_bitrate = video_avg_bitrate;
1524
                        //double a = 1 / ((double)videoq.cumulative_samples);
1525
                        //double b = 1-a;
1526
                        //double input_bitrate = a*((double)video_statistics.Bitrate) + b*((double)video_avg_bitrate);
1527
                        ChunkerPlayerStats_GetMeanVideoQuality(&(videoq.PacketHistory), input_bitrate, &qoe);
1528 e11386c0 CsabaKiraly
#ifdef DEBUG_STATS
1529 54217c91 GiuseppeTropea
                        printf("rate %d avg %d wghtd %d cum_samp %d PSNR %f\n", video_statistics.Bitrate, video_avg_bitrate, (int)input_bitrate, videoq.cumulative_samples, (float)qoe);
1530 e11386c0 CsabaKiraly
#endif
1531
                        last_qoe_evaluation = now;
1532
                }
1533
        }
1534
}