Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_stats.c @ f1024bf4

History | View | Annotate | Download (16.3 KB)

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

    
8
#include "player_defines.h"
9
#include "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
int ChunkerPlayerStats_GetMeanVideoQuality(SHistory* history, double* quality)
269
{
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
                // adjust bitrate with respect to the qoe reference resolution/bitrate ratio
343
                NN_inputs[0] = ((double)Channels[SelectedChannel].Bitrate) * (qoe_reference_coeff/qoe_adjust_factor) / 1000;
344
                NN_inputs[1] = ((double)losses)/((double)counter) * 100;
345
                NN_inputs[2] = mean_burstiness;
346
                
347
#ifdef DEBUG_STATS
348
                printf("NN_inputs[0] = %.3f, NN_inputs[1] = %.3f, NN_inputs[2] = %.3f\n", NN_inputs[0], NN_inputs[1], NN_inputs[2]);
349
#endif
350
                QoE_Estimator(NN_inputs, quality);
351
                
352
                if(LogTraces)
353
                {
354
                        FILE* tracefile = NULL;
355
                        tracefile = fopen(QoETraceFileName, "a");
356
                        if(tracefile)
357
                        {
358
                                // bitrate (Kbits/sec) loss_percentage loss_burstiness est_mean_psnr
359
                                fprintf(tracefile, "%d %.3f %.3f %.3f\n", (int)((Channels[SelectedChannel].Bitrate) * (qoe_reference_coeff/qoe_adjust_factor) / 1000), (float)(((double)losses)/((double)counter) * 100), (float)mean_burstiness, (float)(*quality));
360
                                fclose(tracefile);
361
                        }
362
                }
363
                
364
                history->QoEIndex = (end_index+1)%QUEUE_HISTORY_SIZE;
365
        }
366
        SDL_UnlockMutex(history->Mutex);
367
        
368
        return counter;
369
}
370
/**
371
 * returns 1 if statistics data changed
372
 */
373
int ChunkerPlayerStats_GetStats(SHistory* history, SStats* statistics)
374
{
375
        struct timeval now;
376
        int lost=0, played=0, skipped=0, index, i;
377
        int bytes = 0;
378
        
379
        gettimeofday(&now, NULL);
380
        
381
        SDL_LockMutex(history->Mutex);
382

    
383
        index = history->Index-1;
384
        for(i=1; i<QUEUE_HISTORY_SIZE; i++)
385
        {
386
                if(index<0)
387
                        index = QUEUE_HISTORY_SIZE-1;
388

    
389
                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)))
390
                {
391
                        switch(history->History[index].Status)
392
                        {
393
                                case LOST_FRAME:
394
                                        lost++;
395
                                        break;
396
                                case PLAYED_FRAME:
397
                                        played++;
398
                                        bytes+=history->History[index].Size;
399
                                        break;
400
                                case SKIPPED_FRAME:
401
                                        skipped++;
402
                                        bytes+=history->History[index].Size;
403
                                        break;
404
                        }
405
                        index--;
406
                        continue;
407
                }
408
                break;
409
        }
410

    
411
        statistics->Lossrate = (int)(((double)lost)/((double)(MAIN_STATS_WINDOW/1000)));
412
        statistics->Skiprate = (int)(((double)skipped)/((double)(MAIN_STATS_WINDOW/1000)));
413
        statistics->Bitrate = (int)((((double)bytes)/1000*8)/((double)(MAIN_STATS_WINDOW/1000)));
414
        
415
        double tot = (double)(skipped+played+lost);
416
        if(tot > 0)
417
        {
418
                statistics->PercLossrate = (int)(((double)lost)/tot* 100);
419
                statistics->PercSkiprate = (int)(((double)skipped)/tot* 100);
420
        }
421
        else
422
                statistics->PercLossrate = statistics->PercSkiprate = 0;
423
        
424
        SDL_UnlockMutex(history->Mutex);
425
        
426
        return (lost || played || skipped || bytes);
427
}
428

    
429
void ChunkerPlayerStats_PrintContextFile()
430
{
431
        // edit yuv log file
432
        char tmp[255];
433
        sprintf(tmp, "traces/%d_%s/player_context.txt", ExperimentsCount, Channels[SelectedChannel].Title);
434
        FILE* tmp_file = fopen(tmp, "w");
435
        if(tmp_file)
436
        {
437
                fprintf(tmp_file, "width = %d\n", VideoCallbackThreadParams.width);
438
                fprintf(tmp_file, "height = %d\n", VideoCallbackThreadParams.height);
439
                fprintf(tmp_file, "total_video_frames_logged = %ld\n", VideoFramesLogged[0]+VideoFramesLogged[1]+VideoFramesLogged[2]);
440
                fprintf(tmp_file, "first_video_frame_number = %ld\n", FirstLoggedVFrameNumber);
441
                fprintf(tmp_file, "last_video_frame_number = %ld\n", LastLoggedVFrameNumber);
442
                fprintf(tmp_file, "total_video_frames_decoded = %ld\n", VideoFramesLogged[PLAYED_FRAME]);
443
                fprintf(tmp_file, "skipped_video_frames = %ld\n", VideoFramesLogged[SKIPPED_FRAME]);
444
                fprintf(tmp_file, "lost_video_frames = %ld\n", VideoFramesLogged[LOST_FRAME]);
445
                fclose(tmp_file);
446
        }
447
}
448

    
449
int ChunkerPlayerStats_PrintHistoryTrace(SHistory* history, char* tracefilename)
450
{
451
        int counter = 0;
452
        SDL_LockMutex(history->Mutex);
453

    
454
#ifdef DEBUG_STATS        
455
        if(LogTraces)
456
                assert(tracefilename != NULL);
457
#endif
458
        FILE* tracefile = NULL;
459
        tracefile = fopen(tracefilename, "a");
460
        if(tracefile)
461
        {
462
            if(history->LogIndex != history->Index)
463
            {
464
                    int index;
465
                    int end_index;
466
                    int start_index;
467

    
468
                    start_index = history->LogIndex;
469
                    end_index = history->Index-1;
470
                    if(end_index < 0)
471
                            end_index = QUEUE_HISTORY_SIZE-1;
472
                    else if(history->Index < start_index)
473
                            end_index += QUEUE_HISTORY_SIZE;
474
                
475
                    for(index=start_index; (index<=end_index); index++)
476
                    {
477
                            int id = history->History[index%QUEUE_HISTORY_SIZE].ID;
478
                            int status = history->History[index%QUEUE_HISTORY_SIZE].Status;
479
                            int lossrate = -1, skiprate = -1, perc_lossrate = -1, perc_skiprate = -1, lastiframe_dist = -1;
480
                            int bitrate = -1;
481
                            char type = '?';
482
                            switch(history->History[index%QUEUE_HISTORY_SIZE].Type)
483
                            {
484
                                    case 1:
485
                                            type = 'I';
486
                                            break;
487
                                    case 2:
488
                                            type = 'P';
489
                                            break;
490
                                    case 3:
491
                                            type = 'B';
492
                                            break;
493
                                    case 5:
494
                                            type = 'A';
495
                                            break;
496
                            }
497
                            if(history->History[index%QUEUE_HISTORY_SIZE].Type != 5)
498
                            {
499
                                    if((FirstLoggedVFrameNumber < 0))
500
                                            FirstLoggedVFrameNumber = id;
501
                                    LastLoggedVFrameNumber = id;
502
                                    VideoFramesLogged[status]++;
503
                            }
504
                            if(status != LOST_FRAME)
505
                            {
506
                                    lossrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Lossrate;
507
                                    skiprate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Skiprate;
508
                                    perc_lossrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.PercLossrate;
509
                                    perc_skiprate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.PercSkiprate;
510
                                    if(type != 'A')
511
                                    {
512
                                            lastiframe_dist = history->History[index%QUEUE_HISTORY_SIZE].Statistics.LastIFrameDistance;
513
                                    }
514
                                    bitrate = history->History[index%QUEUE_HISTORY_SIZE].Statistics.Bitrate;
515
                            }
516
                            fprintf(tracefile, "%d %d %c %d %d %d %d %d %d\n",
517
                                    id, status, type, lossrate, skiprate, perc_lossrate, perc_skiprate, lastiframe_dist, bitrate);
518
                            counter++;
519
                    }
520
                    history->LogIndex = (end_index+1)%QUEUE_HISTORY_SIZE;
521
            }
522
            fclose(tracefile);
523
        }
524
                
525
        SDL_UnlockMutex(history->Mutex);
526
        return counter;
527
}