Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_stats.c @ 47943338

History | View | Annotate | Download (16.4 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 e11386c0 CsabaKiraly
#include "player_defines.h"
9
#include "player_stats.h"
10
#include "player_core.h"
11
#include "chunker_player.h"
12
#include <time.h>
13
#include <assert.h>
14
15
void ChunkerPlayerStats_Init()
16
{
17
        LastIFrameNumber = -1;
18
        LastQualityEstimation = 0.5f;
19
        qoe_adjust_factor = sqrt(VideoCallbackThreadParams.height*VideoCallbackThreadParams.width);
20
        
21
        if(LogTraces)
22
        {
23
                // rename all log files as well as the yuv file (new experiment)
24
                char tmp[255];
25
                LastLoggedVFrameNumber = 0;
26
                FirstLoggedVFrameNumber = -1;
27
                sprintf(tmp, "traces/%d_%s", ++ExperimentsCount, Channels[SelectedChannel].Title);
28
                CREATE_DIR(tmp);
29
                sprintf(VideoTraceFilename, "traces/%d_%s/videotrace.log", ExperimentsCount, Channels[SelectedChannel].Title);
30
                sprintf(AudioTraceFilename, "traces/%d_%s/audiotrace.log", ExperimentsCount, Channels[SelectedChannel].Title);
31
                sprintf(QoETraceFileName, "traces/%d_%s/qoe.log", ExperimentsCount, Channels[SelectedChannel].Title);
32
                
33
                // copy the loss pattern file
34
                FILE* fsrc = fopen("_chunklossrate.conf", "rb");
35
                if(fsrc)
36
                {
37
                        sprintf(tmp, "traces/%d_%s/_chunklossrate.conf", ExperimentsCount, Channels[SelectedChannel].Title);
38
                        FILE* fdst = fopen(tmp, "wb");
39
                        if(fdst)
40
                        {
41
                                fseek(fsrc, 0, SEEK_END);
42
                                int dst_size = ftell(fsrc);
43
                                fseek(fsrc, 0, SEEK_SET);
44
45
                                char* fbuffer = (char*) malloc(dst_size);
46
                                fread((void*)fbuffer, dst_size, 1, fsrc);
47
                                fwrite((void*) fbuffer, dst_size, 1, fdst);
48
                                fclose(fdst);
49
                                free(fbuffer);
50
                        }
51
                        fclose(fsrc);
52
                }
53
        }
54
        
55
#ifdef SAVE_YUV
56
        sprintf(YUVFileName, "traces/%d_%s/out_orig.yuv", ExperimentsCount, Channels[SelectedChannel].Title);
57
#endif
58
}
59
60
void ChunkerPlayerStats_UpdateAudioLossHistory(SHistory* history, long int frame_id, long int last_frame_extracted)
61
{
62
        // update packet history
63
        struct timeval now_tv;
64
        gettimeofday(&now_tv, NULL);
65
        if(last_frame_extracted > 0 && frame_id > last_frame_extracted)
66
        {
67
                int j, lost_frames = frame_id - last_frame_extracted - 1;
68
        
69
                SDL_LockMutex(history->Mutex);
70
                for(j=1; j<=lost_frames; j++)
71
                {
72
                        history->History[history->Index].ID = last_frame_extracted+j;
73
                        history->History[history->Index].Status = LOST_FRAME;
74
                        history->History[history->Index].Time = now_tv;
75
                        history->History[history->Index].Type = 5; // AUDIO
76
                        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
77
#ifdef DEBUG_STATS
78
                        if(LogTraces)
79
                                assert(history->Index != history->LogIndex);
80
#else
81
                if(history->Index == history->LogIndex)
82
                {
83
                        // unexpected full loss history buffer, must refresh trace files before continue...
84
                        ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
85
                }
86
#endif
87
                        history->LostCount++;
88
                }
89
                SDL_UnlockMutex(history->Mutex);
90
        }
91
}
92
93
void ChunkerPlayerStats_UpdateVideoLossHistory(SHistory* history, long int frame_id, long int last_frame_extracted)
94
{
95
        // update packet history
96
        struct timeval now_tv;
97
        gettimeofday(&now_tv, NULL);
98
        if(last_frame_extracted > 0 && frame_id > last_frame_extracted)
99
        {
100
                int j, lost_frames = frame_id - last_frame_extracted - 1;
101
        
102
                SDL_LockMutex(history->Mutex);
103
                for(j=1; j<=lost_frames; j++)
104
                {
105
                        history->History[history->Index].ID = last_frame_extracted+j;
106
                        history->History[history->Index].Status = LOST_FRAME;
107
                        history->History[history->Index].Time = now_tv;
108
                        history->History[history->Index].Type = 0; // UNKNOWN VIDEO FRAME
109
                        history->History[history->Index].Statistics.LastIFrameDistance = -1; // UNKNOWN
110
                        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
111
#ifdef DEBUG_STATS
112
                        if(LogTraces)
113
                                assert(history->Index != history->LogIndex);
114
#else
115
                        if(history->Index == history->LogIndex)
116
                        {
117
                                // unexpected full packet history buffer, must refresh trace files before continue...
118
                                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
119
                        }
120
#endif
121
                        history->LostCount++;
122
                }
123
                SDL_UnlockMutex(history->Mutex);
124
        }
125
}
126
127
void ChunkerPlayerStats_UpdateAudioSkipHistory(SHistory* history, long int frame_id, int size)
128
{
129
        // update packet history
130
        struct timeval now_tv;
131
        gettimeofday(&now_tv, NULL);
132
        
133
        SDL_LockMutex(history->Mutex);
134
        history->History[history->Index].ID = frame_id;
135
        history->History[history->Index].Status = SKIPPED_FRAME;
136
        history->History[history->Index].Time = now_tv;
137
        history->History[history->Index].Size = size;
138
        history->History[history->Index].Type = 5; // AUDIO
139
        
140
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
141
        
142
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
143
144
#ifdef DEBUG_STATS
145
        if(LogTraces)
146
                assert(history->Index != history->LogIndex);
147
#else
148
        if(history->Index == history->LogIndex)
149
        {
150
                // unexpected full loss history buffer, must refresh trace files before continue...
151
                ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
152
        }
153
#endif
154
        history->SkipCount++;
155
        SDL_UnlockMutex(history->Mutex);
156
}
157
158
void ChunkerPlayerStats_UpdateVideoSkipHistory(SHistory* history, long int frame_id, short int Type, int Size, AVFrame* pFrame)
159
{
160
        // update packet history
161
        struct timeval now_tv;
162
        gettimeofday(&now_tv, NULL);
163
        
164
        SDL_LockMutex(history->Mutex);
165
        history->History[history->Index].ID = frame_id;
166
        history->History[history->Index].Status = SKIPPED_FRAME;
167
        history->History[history->Index].Time = now_tv;
168
        history->History[history->Index].Size = Size;
169
        history->History[history->Index].Type = Type;
170
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
171
        
172
        if(history->History[history->Index].Type == 1)
173
        {
174
                history->History[history->Index].Statistics.LastIFrameDistance = 0;
175
                LastIFrameNumber = frame_id;
176
        }
177
        else if(LastIFrameNumber > 0)
178
                history->History[history->Index].Statistics.LastIFrameDistance = frame_id-LastIFrameNumber;
179
180
        if(history->History[history->Index].Statistics.LastIFrameDistance >= 0 && (history->History[history->Index].Statistics.LastIFrameDistance < LastSourceIFrameDistance))
181
                LastSourceIFrameDistance = (unsigned char)history->History[history->Index].Statistics.LastIFrameDistance;
182
        
183
        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
184
185
#ifdef DEBUG_STATS
186
        if(LogTraces)
187
                assert(history->Index != history->LogIndex);
188
#else
189
        if(history->Index == history->LogIndex)
190
        {
191
                // unexpected full loss history buffer, must refresh trace files before continue...
192
                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
193
        }
194
#endif
195
        history->SkipCount++;
196
        SDL_UnlockMutex(history->Mutex);
197
}
198
199
void ChunkerPlayerStats_UpdateAudioPlayedHistory(SHistory* history, long int frame_id, int size)
200
{
201
        // update packet history
202
        struct timeval now_tv;
203
        gettimeofday(&now_tv, NULL);
204
        
205
        SDL_LockMutex(history->Mutex);
206
        history->History[history->Index].ID = frame_id;
207
        history->History[history->Index].Status = PLAYED_FRAME;
208
        history->History[history->Index].Time = now_tv;
209
        history->History[history->Index].Size = size;
210
        history->History[history->Index].Type = 5;
211
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
212
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
213
214
#ifdef DEBUG_STATS
215
        if(LogTraces)
216
                assert(history->Index != history->LogIndex);
217
#else
218
        if(history->Index == history->LogIndex)
219
        {
220
                // unexpected full loss history buffer, must refresh trace files before continue...
221
                ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
222
        }
223
#endif
224
225
        history->PlayedCount++;
226
        SDL_UnlockMutex(history->Mutex);
227
}
228
229
void ChunkerPlayerStats_UpdateVideoPlayedHistory(SHistory* history, long int frame_id, short int Type, int Size, AVFrame* pFrame)
230
{
231
        // update packet history
232
        struct timeval now_tv;
233
        gettimeofday(&now_tv, NULL);
234
        
235
        SDL_LockMutex(history->Mutex);
236
        history->History[history->Index].ID = frame_id;
237
        history->History[history->Index].Status = PLAYED_FRAME;
238
        history->History[history->Index].Time = now_tv;
239
        history->History[history->Index].Size = Size;
240
        history->History[history->Index].Type = Type;
241
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
242
        if(history->History[history->Index].Type == 1)
243
        {
244
                history->History[history->Index].Statistics.LastIFrameDistance = 0;
245
                LastIFrameNumber = frame_id;
246
        }
247
        else if(LastIFrameNumber > 0)
248
                history->History[history->Index].Statistics.LastIFrameDistance = frame_id-LastIFrameNumber;
249
        
250
        if(history->History[history->Index].Statistics.LastIFrameDistance >= 0 && (history->History[history->Index].Statistics.LastIFrameDistance < LastSourceIFrameDistance))
251
                LastSourceIFrameDistance = (unsigned char)history->History[history->Index].Statistics.LastIFrameDistance;
252
253
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
254
#ifdef DEBUG_STATS
255
        if(LogTraces)
256
                assert(history->Index != history->LogIndex);
257
#else
258
        if(history->Index == history->LogIndex)
259
        {
260
                // unexpected full packet history buffer, must refresh trace files before continue...
261
                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
262
        }
263
#endif
264
        history->PlayedCount++;
265
        SDL_UnlockMutex(history->Mutex);
266
}
267
268 54217c91 GiuseppeTropea
int ChunkerPlayerStats_GetMeanVideoQuality(SHistory* history, int real_bitrate, double* quality)
269 e11386c0 CsabaKiraly
{
270
        static double qoe_reference_coeff = sqrt(QOE_REFERENCE_FRAME_WIDTH*QOE_REFERENCE_FRAME_HEIGHT);
271
        
272
        int counter = 0;
273
        SDL_LockMutex(history->Mutex);
274
                
275
        if(history->QoEIndex != history->Index)
276
        {
277
                int index;
278
                int end_index;
279
                int start_index;
280
                int tmp_index;
281
                double NN_inputs[7];
282
                int losses = 0;
283
284
                start_index = history->QoEIndex;
285
                end_index = history->Index-1;
286
                if(end_index < 0)
287
                        end_index = QUEUE_HISTORY_SIZE-1;
288
                else if(history->Index < start_index)
289
                        end_index += QUEUE_HISTORY_SIZE;
290
                        
291
#ifdef DEBUG_STATS
292
                printf("DEBUG_STATS: start_index=%d, end_index=%d\n", start_index, end_index);
293
#endif
294
                
295
                int inside_burst = 0;
296
                int burst_size = 0;
297
                int burst_count = 0;
298
                double mean_burstiness = 0;
299
                for(index=start_index; (index<=end_index); index++)
300
                {
301
                        tmp_index = index%QUEUE_HISTORY_SIZE;
302
#ifdef DEBUG_STATS
303
                        if(LogTraces)
304
                                assert(history->History[tmp_index].Type != 5);
305
#endif
306
307
                        if((FirstLoggedVFrameNumber < 0))
308
                                FirstLoggedVFrameNumber = history->History[tmp_index].ID;
309
                        LastLoggedVFrameNumber = history->History[tmp_index].ID;
310
                        VideoFramesLogged[history->History[tmp_index].Status]++;
311
312
                        if(history->History[tmp_index].Status == LOST_FRAME)
313
                        {
314
                                losses++;
315
                                inside_burst = 1;
316
                                burst_size++;
317
                        }
318
                        else
319
                        {
320
                                if(inside_burst)
321
                                {
322
                                        inside_burst = 0;
323
                                        mean_burstiness += burst_size;
324
                                        burst_size = 0;
325
                                        burst_count++;
326
                                }
327
                        }
328
                        
329
                        counter++;
330
                }
331
                if(inside_burst)
332
                {
333
                        inside_burst = 0;
334
                        mean_burstiness += burst_size;
335
                        burst_size = 0;
336
                        burst_count++;
337
                }
338
                
339
                if(burst_count > 0)
340
                        mean_burstiness /= ((double)burst_count);
341
342 54217c91 GiuseppeTropea
                double input_bitrate = (double)real_bitrate;
343
//                double input_bitrate = ((double)Channels[SelectedChannel].Bitrate) / 1000;
344 e11386c0 CsabaKiraly
                // adjust bitrate with respect to the qoe reference resolution/bitrate ratio
345 54217c91 GiuseppeTropea
                input_bitrate *= (qoe_reference_coeff/qoe_adjust_factor);
346
                //feed the NN
347
                NN_inputs[0] = input_bitrate;
348 e11386c0 CsabaKiraly
                NN_inputs[1] = ((double)losses)/((double)counter) * 100;
349
                NN_inputs[2] = mean_burstiness;
350
                
351
#ifdef DEBUG_STATS
352
                printf("NN_inputs[0] = %.3f, NN_inputs[1] = %.3f, NN_inputs[2] = %.3f\n", NN_inputs[0], NN_inputs[1], NN_inputs[2]);
353
#endif
354
                QoE_Estimator(NN_inputs, quality);
355
                
356
                if(LogTraces)
357
                {
358
                        FILE* tracefile = NULL;
359
                        tracefile = fopen(QoETraceFileName, "a");
360
                        if(tracefile)
361
                        {
362
                                // bitrate (Kbits/sec) loss_percentage loss_burstiness est_mean_psnr
363 54217c91 GiuseppeTropea
                                fprintf(tracefile, "%d %.3f %.3f %.3f\n", (int)(input_bitrate), (float)(((double)losses)/((double)counter) * 100), (float)mean_burstiness, (float)(*quality));
364 f1024bf4 CarmeloDaniele
                                fclose(tracefile);
365 e11386c0 CsabaKiraly
                        }
366
                }
367
                
368
                history->QoEIndex = (end_index+1)%QUEUE_HISTORY_SIZE;
369
        }
370
        SDL_UnlockMutex(history->Mutex);
371
        
372
        return counter;
373
}
374
/**
375
 * returns 1 if statistics data changed
376
 */
377
int ChunkerPlayerStats_GetStats(SHistory* history, SStats* statistics)
378
{
379
        struct timeval now;
380
        int lost=0, played=0, skipped=0, index, i;
381
        int bytes = 0;
382
        
383
        gettimeofday(&now, NULL);
384
        
385
        SDL_LockMutex(history->Mutex);
386
387
        index = history->Index-1;
388
        for(i=1; i<QUEUE_HISTORY_SIZE; i++)
389
        {
390
                if(index<0)
391
                        index = QUEUE_HISTORY_SIZE-1;
392
393
                if((((history->History[index].Time.tv_sec*1000)+(history->History[index].Time.tv_usec/1000)) > ((now.tv_sec*1000)+(now.tv_usec/1000) - MAIN_STATS_WINDOW)))
394
                {
395
                        switch(history->History[index].Status)
396
                        {
397
                                case LOST_FRAME:
398
                                        lost++;
399
                                        break;
400
                                case PLAYED_FRAME:
401
                                        played++;
402
                                        bytes+=history->History[index].Size;
403
                                        break;
404
                                case SKIPPED_FRAME:
405
                                        skipped++;
406
                                        bytes+=history->History[index].Size;
407
                                        break;
408
                        }
409
                        index--;
410
                        continue;
411
                }
412
                break;
413
        }
414
415
        statistics->Lossrate = (int)(((double)lost)/((double)(MAIN_STATS_WINDOW/1000)));
416
        statistics->Skiprate = (int)(((double)skipped)/((double)(MAIN_STATS_WINDOW/1000)));
417
        statistics->Bitrate = (int)((((double)bytes)/1000*8)/((double)(MAIN_STATS_WINDOW/1000)));
418
        
419
        double tot = (double)(skipped+played+lost);
420
        if(tot > 0)
421
        {
422
                statistics->PercLossrate = (int)(((double)lost)/tot* 100);
423
                statistics->PercSkiprate = (int)(((double)skipped)/tot* 100);
424
        }
425
        else
426
                statistics->PercLossrate = statistics->PercSkiprate = 0;
427
        
428
        SDL_UnlockMutex(history->Mutex);
429
        
430
        return (lost || played || skipped || bytes);
431
}
432
433
void ChunkerPlayerStats_PrintContextFile()
434
{
435
        // edit yuv log file
436
        char tmp[255];
437
        sprintf(tmp, "traces/%d_%s/player_context.txt", ExperimentsCount, Channels[SelectedChannel].Title);
438
        FILE* tmp_file = fopen(tmp, "w");
439
        if(tmp_file)
440
        {
441
                fprintf(tmp_file, "width = %d\n", VideoCallbackThreadParams.width);
442
                fprintf(tmp_file, "height = %d\n", VideoCallbackThreadParams.height);
443
                fprintf(tmp_file, "total_video_frames_logged = %ld\n", VideoFramesLogged[0]+VideoFramesLogged[1]+VideoFramesLogged[2]);
444
                fprintf(tmp_file, "first_video_frame_number = %ld\n", FirstLoggedVFrameNumber);
445
                fprintf(tmp_file, "last_video_frame_number = %ld\n", LastLoggedVFrameNumber);
446
                fprintf(tmp_file, "total_video_frames_decoded = %ld\n", VideoFramesLogged[PLAYED_FRAME]);
447
                fprintf(tmp_file, "skipped_video_frames = %ld\n", VideoFramesLogged[SKIPPED_FRAME]);
448
                fprintf(tmp_file, "lost_video_frames = %ld\n", VideoFramesLogged[LOST_FRAME]);
449
                fclose(tmp_file);
450
        }
451
}
452
453
int ChunkerPlayerStats_PrintHistoryTrace(SHistory* history, char* tracefilename)
454
{
455
        int counter = 0;
456
        SDL_LockMutex(history->Mutex);
457
458
#ifdef DEBUG_STATS        
459
        if(LogTraces)
460
                assert(tracefilename != NULL);
461
#endif
462
        FILE* tracefile = NULL;
463
        tracefile = fopen(tracefilename, "a");
464 f1024bf4 CarmeloDaniele
        if(tracefile)
465 e11386c0 CsabaKiraly
        {
466 f1024bf4 CarmeloDaniele
            if(history->LogIndex != history->Index)
467
            {
468
                    int index;
469
                    int end_index;
470
                    int start_index;
471 e11386c0 CsabaKiraly
472 f1024bf4 CarmeloDaniele
                    start_index = history->LogIndex;
473
                    end_index = history->Index-1;
474
                    if(end_index < 0)
475
                            end_index = QUEUE_HISTORY_SIZE-1;
476
                    else if(history->Index < start_index)
477
                            end_index += QUEUE_HISTORY_SIZE;
478 e11386c0 CsabaKiraly
                
479 f1024bf4 CarmeloDaniele
                    for(index=start_index; (index<=end_index); index++)
480
                    {
481
                            int id = history->History[index%QUEUE_HISTORY_SIZE].ID;
482
                            int status = history->History[index%QUEUE_HISTORY_SIZE].Status;
483
                            int lossrate = -1, skiprate = -1, perc_lossrate = -1, perc_skiprate = -1, lastiframe_dist = -1;
484
                            int bitrate = -1;
485
                            char type = '?';
486
                            switch(history->History[index%QUEUE_HISTORY_SIZE].Type)
487
                            {
488
                                    case 1:
489
                                            type = 'I';
490
                                            break;
491
                                    case 2:
492
                                            type = 'P';
493
                                            break;
494
                                    case 3:
495
                                            type = 'B';
496
                                            break;
497
                                    case 5:
498
                                            type = 'A';
499
                                            break;
500
                            }
501
                            if(history->History[index%QUEUE_HISTORY_SIZE].Type != 5)
502
                            {
503
                                    if((FirstLoggedVFrameNumber < 0))
504
                                            FirstLoggedVFrameNumber = id;
505
                                    LastLoggedVFrameNumber = id;
506
                                    VideoFramesLogged[status]++;
507
                            }
508
                            if(status != LOST_FRAME)
509
                            {
510
                                    lossrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Lossrate;
511
                                    skiprate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Skiprate;
512
                                    perc_lossrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.PercLossrate;
513
                                    perc_skiprate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.PercSkiprate;
514
                                    if(type != 'A')
515
                                    {
516
                                            lastiframe_dist = history->History[index%QUEUE_HISTORY_SIZE].Statistics.LastIFrameDistance;
517
                                    }
518
                                    bitrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Bitrate;
519
                            }
520
                            fprintf(tracefile, "%d %d %c %d %d %d %d %d %d\n",
521
                                    id, status, type, lossrate, skiprate, perc_lossrate, perc_skiprate, lastiframe_dist, bitrate);
522
                            counter++;
523
                    }
524
                    history->LogIndex = (end_index+1)%QUEUE_HISTORY_SIZE;
525
            }
526
            fclose(tracefile);
527 e11386c0 CsabaKiraly
        }
528
                
529
        SDL_UnlockMutex(history->Mutex);
530
        return counter;
531
}