Statistics
| Branch: | Revision:

chunker-player / chunker_player / player_stats.c @ e11386c0

History | View | Annotate | Download (15.9 KB)

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

    
8
void ChunkerPlayerStats_Init()
9
{
10
        LastIFrameNumber = -1;
11
        LastQualityEstimation = 0.5f;
12
        qoe_adjust_factor = sqrt(VideoCallbackThreadParams.height*VideoCallbackThreadParams.width);
13
        
14
        if(LogTraces)
15
        {
16
                // rename all log files as well as the yuv file (new experiment)
17
                char tmp[255];
18
                LastLoggedVFrameNumber = 0;
19
                FirstLoggedVFrameNumber = -1;
20
                sprintf(tmp, "traces/%d_%s", ++ExperimentsCount, Channels[SelectedChannel].Title);
21
                CREATE_DIR(tmp);
22
                sprintf(VideoTraceFilename, "traces/%d_%s/videotrace.log", ExperimentsCount, Channels[SelectedChannel].Title);
23
                sprintf(AudioTraceFilename, "traces/%d_%s/audiotrace.log", ExperimentsCount, Channels[SelectedChannel].Title);
24
                sprintf(QoETraceFileName, "traces/%d_%s/qoe.log", ExperimentsCount, Channels[SelectedChannel].Title);
25
                
26
                // copy the loss pattern file
27
                FILE* fsrc = fopen("_chunklossrate.conf", "rb");
28
                if(fsrc)
29
                {
30
                        sprintf(tmp, "traces/%d_%s/_chunklossrate.conf", ExperimentsCount, Channels[SelectedChannel].Title);
31
                        FILE* fdst = fopen(tmp, "wb");
32
                        if(fdst)
33
                        {
34
                                fseek(fsrc, 0, SEEK_END);
35
                                int dst_size = ftell(fsrc);
36
                                fseek(fsrc, 0, SEEK_SET);
37

    
38
                                char* fbuffer = (char*) malloc(dst_size);
39
                                fread((void*)fbuffer, dst_size, 1, fsrc);
40
                                fwrite((void*) fbuffer, dst_size, 1, fdst);
41
                                fclose(fdst);
42
                                free(fbuffer);
43
                        }
44
                        fclose(fsrc);
45
                }
46
        }
47
        
48
#ifdef SAVE_YUV
49
        sprintf(YUVFileName, "traces/%d_%s/out_orig.yuv", ExperimentsCount, Channels[SelectedChannel].Title);
50
#endif
51
}
52

    
53
void ChunkerPlayerStats_UpdateAudioLossHistory(SHistory* history, long int frame_id, long int last_frame_extracted)
54
{
55
        // update packet history
56
        struct timeval now_tv;
57
        gettimeofday(&now_tv, NULL);
58
        if(last_frame_extracted > 0 && frame_id > last_frame_extracted)
59
        {
60
                int j, lost_frames = frame_id - last_frame_extracted - 1;
61
        
62
                SDL_LockMutex(history->Mutex);
63
                for(j=1; j<=lost_frames; j++)
64
                {
65
                        history->History[history->Index].ID = last_frame_extracted+j;
66
                        history->History[history->Index].Status = LOST_FRAME;
67
                        history->History[history->Index].Time = now_tv;
68
                        history->History[history->Index].Type = 5; // AUDIO
69
                        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
70
#ifdef DEBUG_STATS
71
                        if(LogTraces)
72
                                assert(history->Index != history->LogIndex);
73
#else
74
                if(history->Index == history->LogIndex)
75
                {
76
                        // unexpected full loss history buffer, must refresh trace files before continue...
77
                        ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
78
                }
79
#endif
80
                        history->LostCount++;
81
                }
82
                SDL_UnlockMutex(history->Mutex);
83
        }
84
}
85

    
86
void ChunkerPlayerStats_UpdateVideoLossHistory(SHistory* history, long int frame_id, long int last_frame_extracted)
87
{
88
        // update packet history
89
        struct timeval now_tv;
90
        gettimeofday(&now_tv, NULL);
91
        if(last_frame_extracted > 0 && frame_id > last_frame_extracted)
92
        {
93
                int j, lost_frames = frame_id - last_frame_extracted - 1;
94
        
95
                SDL_LockMutex(history->Mutex);
96
                for(j=1; j<=lost_frames; j++)
97
                {
98
                        history->History[history->Index].ID = last_frame_extracted+j;
99
                        history->History[history->Index].Status = LOST_FRAME;
100
                        history->History[history->Index].Time = now_tv;
101
                        history->History[history->Index].Type = 0; // UNKNOWN VIDEO FRAME
102
                        history->History[history->Index].Statistics.LastIFrameDistance = -1; // UNKNOWN
103
                        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
104
#ifdef DEBUG_STATS
105
                        if(LogTraces)
106
                                assert(history->Index != history->LogIndex);
107
#else
108
                        if(history->Index == history->LogIndex)
109
                        {
110
                                // unexpected full packet history buffer, must refresh trace files before continue...
111
                                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
112
                        }
113
#endif
114
                        history->LostCount++;
115
                }
116
                SDL_UnlockMutex(history->Mutex);
117
        }
118
}
119

    
120
void ChunkerPlayerStats_UpdateAudioSkipHistory(SHistory* history, long int frame_id, int size)
121
{
122
        // update packet history
123
        struct timeval now_tv;
124
        gettimeofday(&now_tv, NULL);
125
        
126
        SDL_LockMutex(history->Mutex);
127
        history->History[history->Index].ID = frame_id;
128
        history->History[history->Index].Status = SKIPPED_FRAME;
129
        history->History[history->Index].Time = now_tv;
130
        history->History[history->Index].Size = size;
131
        history->History[history->Index].Type = 5; // AUDIO
132
        
133
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
134
        
135
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
136

    
137
#ifdef DEBUG_STATS
138
        if(LogTraces)
139
                assert(history->Index != history->LogIndex);
140
#else
141
        if(history->Index == history->LogIndex)
142
        {
143
                // unexpected full loss history buffer, must refresh trace files before continue...
144
                ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
145
        }
146
#endif
147
        history->SkipCount++;
148
        SDL_UnlockMutex(history->Mutex);
149
}
150

    
151
void ChunkerPlayerStats_UpdateVideoSkipHistory(SHistory* history, long int frame_id, short int Type, int Size, AVFrame* pFrame)
152
{
153
        // update packet history
154
        struct timeval now_tv;
155
        gettimeofday(&now_tv, NULL);
156
        
157
        SDL_LockMutex(history->Mutex);
158
        history->History[history->Index].ID = frame_id;
159
        history->History[history->Index].Status = SKIPPED_FRAME;
160
        history->History[history->Index].Time = now_tv;
161
        history->History[history->Index].Size = Size;
162
        history->History[history->Index].Type = Type;
163
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
164
        
165
        if(history->History[history->Index].Type == 1)
166
        {
167
                history->History[history->Index].Statistics.LastIFrameDistance = 0;
168
                LastIFrameNumber = frame_id;
169
        }
170
        else if(LastIFrameNumber > 0)
171
                history->History[history->Index].Statistics.LastIFrameDistance = frame_id-LastIFrameNumber;
172

    
173
        if(history->History[history->Index].Statistics.LastIFrameDistance >= 0 && (history->History[history->Index].Statistics.LastIFrameDistance < LastSourceIFrameDistance))
174
                LastSourceIFrameDistance = (unsigned char)history->History[history->Index].Statistics.LastIFrameDistance;
175
        
176
        history->Index = (history->Index+1)%QUEUE_HISTORY_SIZE;
177

    
178
#ifdef DEBUG_STATS
179
        if(LogTraces)
180
                assert(history->Index != history->LogIndex);
181
#else
182
        if(history->Index == history->LogIndex)
183
        {
184
                // unexpected full loss history buffer, must refresh trace files before continue...
185
                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
186
        }
187
#endif
188
        history->SkipCount++;
189
        SDL_UnlockMutex(history->Mutex);
190
}
191

    
192
void ChunkerPlayerStats_UpdateAudioPlayedHistory(SHistory* history, long int frame_id, int size)
193
{
194
        // update packet history
195
        struct timeval now_tv;
196
        gettimeofday(&now_tv, NULL);
197
        
198
        SDL_LockMutex(history->Mutex);
199
        history->History[history->Index].ID = frame_id;
200
        history->History[history->Index].Status = PLAYED_FRAME;
201
        history->History[history->Index].Time = now_tv;
202
        history->History[history->Index].Size = size;
203
        history->History[history->Index].Type = 5;
204
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
205
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
206

    
207
#ifdef DEBUG_STATS
208
        if(LogTraces)
209
                assert(history->Index != history->LogIndex);
210
#else
211
        if(history->Index == history->LogIndex)
212
        {
213
                // unexpected full loss history buffer, must refresh trace files before continue...
214
                ChunkerPlayerStats_PrintHistoryTrace(history, AudioTraceFilename);
215
        }
216
#endif
217

    
218
        history->PlayedCount++;
219
        SDL_UnlockMutex(history->Mutex);
220
}
221

    
222
void ChunkerPlayerStats_UpdateVideoPlayedHistory(SHistory* history, long int frame_id, short int Type, int Size, AVFrame* pFrame)
223
{
224
        // update packet history
225
        struct timeval now_tv;
226
        gettimeofday(&now_tv, NULL);
227
        
228
        SDL_LockMutex(history->Mutex);
229
        history->History[history->Index].ID = frame_id;
230
        history->History[history->Index].Status = PLAYED_FRAME;
231
        history->History[history->Index].Time = now_tv;
232
        history->History[history->Index].Size = Size;
233
        history->History[history->Index].Type = Type;
234
        ChunkerPlayerStats_GetStats(history, &(history->History[history->Index].Statistics));
235
        if(history->History[history->Index].Type == 1)
236
        {
237
                history->History[history->Index].Statistics.LastIFrameDistance = 0;
238
                LastIFrameNumber = frame_id;
239
        }
240
        else if(LastIFrameNumber > 0)
241
                history->History[history->Index].Statistics.LastIFrameDistance = frame_id-LastIFrameNumber;
242
        
243
        if(history->History[history->Index].Statistics.LastIFrameDistance >= 0 && (history->History[history->Index].Statistics.LastIFrameDistance < LastSourceIFrameDistance))
244
                LastSourceIFrameDistance = (unsigned char)history->History[history->Index].Statistics.LastIFrameDistance;
245

    
246
        history->Index=(history->Index+1)%QUEUE_HISTORY_SIZE;
247
#ifdef DEBUG_STATS
248
        if(LogTraces)
249
                assert(history->Index != history->LogIndex);
250
#else
251
        if(history->Index == history->LogIndex)
252
        {
253
                // unexpected full packet history buffer, must refresh trace files before continue...
254
                ChunkerPlayerStats_PrintHistoryTrace(history, VideoTraceFilename);
255
        }
256
#endif
257
        history->PlayedCount++;
258
        SDL_UnlockMutex(history->Mutex);
259
}
260

    
261
int ChunkerPlayerStats_GetMeanVideoQuality(SHistory* history, double* quality)
262
{
263
        static double qoe_reference_coeff = sqrt(QOE_REFERENCE_FRAME_WIDTH*QOE_REFERENCE_FRAME_HEIGHT);
264
        
265
        int counter = 0;
266
        SDL_LockMutex(history->Mutex);
267
                
268
        if(history->QoEIndex != history->Index)
269
        {
270
                int index;
271
                int end_index;
272
                int start_index;
273
                int tmp_index;
274
                double NN_inputs[7];
275
                int losses = 0;
276

    
277
                start_index = history->QoEIndex;
278
                end_index = history->Index-1;
279
                if(end_index < 0)
280
                        end_index = QUEUE_HISTORY_SIZE-1;
281
                else if(history->Index < start_index)
282
                        end_index += QUEUE_HISTORY_SIZE;
283
                        
284
#ifdef DEBUG_STATS
285
                printf("DEBUG_STATS: start_index=%d, end_index=%d\n", start_index, end_index);
286
#endif
287
                
288
                int inside_burst = 0;
289
                int burst_size = 0;
290
                int burst_count = 0;
291
                double mean_burstiness = 0;
292
                for(index=start_index; (index<=end_index); index++)
293
                {
294
                        tmp_index = index%QUEUE_HISTORY_SIZE;
295
#ifdef DEBUG_STATS
296
                        if(LogTraces)
297
                                assert(history->History[tmp_index].Type != 5);
298
#endif
299

    
300
                        if((FirstLoggedVFrameNumber < 0))
301
                                FirstLoggedVFrameNumber = history->History[tmp_index].ID;
302
                        LastLoggedVFrameNumber = history->History[tmp_index].ID;
303
                        VideoFramesLogged[history->History[tmp_index].Status]++;
304

    
305
                        if(history->History[tmp_index].Status == LOST_FRAME)
306
                        {
307
                                losses++;
308
                                inside_burst = 1;
309
                                burst_size++;
310
                        }
311
                        else
312
                        {
313
                                if(inside_burst)
314
                                {
315
                                        inside_burst = 0;
316
                                        mean_burstiness += burst_size;
317
                                        burst_size = 0;
318
                                        burst_count++;
319
                                }
320
                        }
321
                        
322
                        counter++;
323
                }
324
                if(inside_burst)
325
                {
326
                        inside_burst = 0;
327
                        mean_burstiness += burst_size;
328
                        burst_size = 0;
329
                        burst_count++;
330
                }
331
                
332
                if(burst_count > 0)
333
                        mean_burstiness /= ((double)burst_count);
334

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

    
376
        index = history->Index-1;
377
        for(i=1; i<QUEUE_HISTORY_SIZE; i++)
378
        {
379
                if(index<0)
380
                        index = QUEUE_HISTORY_SIZE-1;
381

    
382
                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)))
383
                {
384
                        switch(history->History[index].Status)
385
                        {
386
                                case LOST_FRAME:
387
                                        lost++;
388
                                        break;
389
                                case PLAYED_FRAME:
390
                                        played++;
391
                                        bytes+=history->History[index].Size;
392
                                        break;
393
                                case SKIPPED_FRAME:
394
                                        skipped++;
395
                                        bytes+=history->History[index].Size;
396
                                        break;
397
                        }
398
                        index--;
399
                        continue;
400
                }
401
                break;
402
        }
403

    
404
        statistics->Lossrate = (int)(((double)lost)/((double)(MAIN_STATS_WINDOW/1000)));
405
        statistics->Skiprate = (int)(((double)skipped)/((double)(MAIN_STATS_WINDOW/1000)));
406
        statistics->Bitrate = (int)((((double)bytes)/1000*8)/((double)(MAIN_STATS_WINDOW/1000)));
407
        
408
        double tot = (double)(skipped+played+lost);
409
        if(tot > 0)
410
        {
411
                statistics->PercLossrate = (int)(((double)lost)/tot* 100);
412
                statistics->PercSkiprate = (int)(((double)skipped)/tot* 100);
413
        }
414
        else
415
                statistics->PercLossrate = statistics->PercSkiprate = 0;
416
        
417
        SDL_UnlockMutex(history->Mutex);
418
        
419
        return (lost || played || skipped || bytes);
420
}
421

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

    
442
int ChunkerPlayerStats_PrintHistoryTrace(SHistory* history, char* tracefilename)
443
{
444
        int counter = 0;
445
        SDL_LockMutex(history->Mutex);
446

    
447
#ifdef DEBUG_STATS        
448
        if(LogTraces)
449
                assert(tracefilename != NULL);
450
#endif
451
        FILE* tracefile = NULL;
452
        tracefile = fopen(tracefilename, "a");
453
                
454
        if(history->LogIndex != history->Index)
455
        {
456
                int index;
457
                int end_index;
458
                int start_index;
459

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