Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions are |
| 6 | * met: |
| 7 | * * Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * * Redistributions in binary form must reproduce the above |
| 10 | * copyright notice, this list of conditions and the following |
| 11 | * disclaimer in the documentation and/or other materials provided |
| 12 | * with the distribution. |
| 13 | * * Neither the name of The Linux Foundation nor the names of its |
| 14 | * contributors may be used to endorse or promote products derived |
| 15 | * from this software without specific prior written permission. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| 27 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | */ |
| 29 | |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 30 | #include <utils/Log.h> |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 31 | #include "DashPlayerStats.h" |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 32 | |
| 33 | #define NO_MIMETYPE_AVAILABLE "N/A" |
| 34 | |
| 35 | namespace android { |
| 36 | |
| 37 | DashPlayerStats::DashPlayerStats() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 38 | Mutex::Autolock autoLock(mStatsLock); |
| 39 | mMIME = new char[strlen(NO_MIMETYPE_AVAILABLE)+1]; |
| 40 | strcpy(mMIME,NO_MIMETYPE_AVAILABLE); |
| 41 | mNumVideoFramesDecoded = 0; |
| 42 | mNumVideoFramesDropped = 0; |
| 43 | mConsecutiveFramesDropped = 0; |
| 44 | mCatchupTimeStart = 0; |
| 45 | mNumTimesSyncLoss = 0; |
| 46 | mMaxEarlyDelta = 0; |
| 47 | mMaxLateDelta = 0; |
| 48 | mMaxTimeSyncLoss = 0; |
| 49 | mTotalFrames = 0; |
| 50 | mFirstFrameLatencyStartUs = getTimeOfDayUs(); |
| 51 | mLastFrame = 0; |
| 52 | mLastFrameUs = 0; |
| 53 | mStatisticsFrames = 0; |
| 54 | mFPSSumUs = 0; |
| 55 | mVeryFirstFrame = true; |
| 56 | mSeekPerformed = false; |
| 57 | mTotalTime = 0; |
| 58 | mFirstFrameTime = 0; |
| 59 | mTotalRenderingFrames = 0; |
| 60 | mBufferingEvent = false; |
| 61 | mFd = -1; |
| 62 | mFileOut = NULL; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | DashPlayerStats::~DashPlayerStats() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 66 | Mutex::Autolock autoLock(mStatsLock); |
| 67 | if(mFileOut){ |
| 68 | fclose(mFileOut); |
| 69 | mFileOut = NULL; |
| 70 | } |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 71 | if(mMIME) { |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 72 | delete[] mMIME; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 73 | } |
| 74 | } |
| 75 | |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 76 | void DashPlayerStats::setFileDescAndOutputStream(int fd) { |
| 77 | Mutex::Autolock autoLock(mStatsLock); |
| 78 | mFd = fd; |
| 79 | if(mFileOut){ |
| 80 | fclose(mFileOut); |
| 81 | mFileOut = NULL; |
| 82 | } |
| 83 | mFileOut = fdopen(dup(fd), "w"); |
| 84 | } |
| 85 | |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 86 | void DashPlayerStats::setMime(const char* mime) { |
| 87 | Mutex::Autolock autoLock(mStatsLock); |
| 88 | if(mime != NULL) { |
| 89 | int mimeLen = strlen(mime); |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 90 | if(mMIME) { |
| 91 | delete[] mMIME; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | mMIME = new char[mimeLen+1]; |
| 95 | strcpy(mMIME,mime); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | void DashPlayerStats::setVeryFirstFrame(bool vff) { |
| 100 | Mutex::Autolock autoLock(mStatsLock); |
| 101 | mVeryFirstFrame = true; |
| 102 | } |
| 103 | |
| 104 | void DashPlayerStats::notifySeek() { |
| 105 | Mutex::Autolock autoLock(mStatsLock); |
| 106 | mFirstFrameLatencyStartUs = getTimeOfDayUs(); |
| 107 | mSeekPerformed = true; |
| 108 | } |
| 109 | |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 110 | void DashPlayerStats::notifyBufferingEvent() { |
| 111 | Mutex::Autolock autoLock(mStatsLock); |
| 112 | mBufferingEvent = true; |
| 113 | } |
| 114 | |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 115 | void DashPlayerStats::incrementTotalFrames() { |
| 116 | Mutex::Autolock autoLock(mStatsLock); |
| 117 | mTotalFrames++; |
| 118 | } |
| 119 | |
| 120 | void DashPlayerStats::incrementTotalRenderingFrames() { |
| 121 | Mutex::Autolock autoLock(mStatsLock); |
| 122 | mTotalRenderingFrames++; |
| 123 | } |
| 124 | |
| 125 | void DashPlayerStats::incrementDroppedFrames() { |
| 126 | Mutex::Autolock autoLock(mStatsLock); |
| 127 | mNumVideoFramesDropped++; |
| 128 | } |
| 129 | |
| 130 | void DashPlayerStats::logStatistics() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 131 | if(mFileOut) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 132 | Mutex::Autolock autoLock(mStatsLock); |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 133 | fprintf(mFileOut, "=====================================================\n"); |
| 134 | fprintf(mFileOut, "Mime Type: %s\n",mMIME); |
| 135 | fprintf(mFileOut, "Number of total frames: %llu\n",mTotalFrames); |
| 136 | fprintf(mFileOut, "Number of frames dropped: %lld\n",mNumVideoFramesDropped); |
| 137 | fprintf(mFileOut, "Number of frames rendered: %llu\n",mTotalRenderingFrames); |
| 138 | fprintf(mFileOut, "Percentage dropped: %.2f\n", |
| 139 | mTotalFrames == 0 ? 0.0 : (double)mNumVideoFramesDropped / mTotalFrames); |
| 140 | fprintf(mFileOut, "=====================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 141 | } |
| 142 | } |
| 143 | |
| 144 | void DashPlayerStats::logPause(int64_t positionUs) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 145 | if(mFileOut) { |
| 146 | fprintf(mFileOut, "=====================================================\n"); |
| 147 | fprintf(mFileOut, "Pause position: %lld ms\n",positionUs/1000); |
| 148 | fprintf(mFileOut, "=====================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 149 | } |
| 150 | } |
| 151 | |
| 152 | void DashPlayerStats::logSeek(int64_t seekTimeUs) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 153 | if(mFileOut) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 154 | Mutex::Autolock autoLock(mStatsLock); |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 155 | fprintf(mFileOut, "=====================================================\n"); |
| 156 | fprintf(mFileOut, "Seek position: %lld ms\n",seekTimeUs/1000); |
| 157 | fprintf(mFileOut, "Seek latency: %lld ms\n",(getTimeOfDayUs() - mFirstFrameLatencyStartUs)/1000); |
| 158 | fprintf(mFileOut, "=====================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 159 | } |
| 160 | } |
| 161 | |
| 162 | void DashPlayerStats::recordLate(int64_t ts, int64_t clock, int64_t delta, int64_t anchorTime) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 163 | Mutex::Autolock autoLock(mStatsLock); |
| 164 | mNumVideoFramesDropped++; |
| 165 | mConsecutiveFramesDropped++; |
| 166 | if (mConsecutiveFramesDropped == 1){ |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 167 | mCatchupTimeStart = anchorTime; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 168 | } |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 169 | |
| 170 | logLate(ts,clock,delta); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 171 | } |
| 172 | |
| 173 | void DashPlayerStats::recordOnTime(int64_t ts, int64_t clock, int64_t delta) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 174 | Mutex::Autolock autoLock(mStatsLock); |
| 175 | mNumVideoFramesDecoded++; |
| 176 | mConsecutiveFramesDropped = 0; |
| 177 | logOnTime(ts,clock,delta); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | void DashPlayerStats::logSyncLoss() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 181 | if(mFileOut) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 182 | Mutex::Autolock autoLock(mStatsLock); |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 183 | fprintf(mFileOut, "=====================================================\n"); |
| 184 | fprintf(mFileOut, "Number of times AV Sync Losses = %u\n", mNumTimesSyncLoss); |
| 185 | fprintf(mFileOut, "Max Video Ahead time delta = %u\n", -mMaxEarlyDelta/1000); |
| 186 | fprintf(mFileOut, "Max Video Behind time delta = %u\n", mMaxLateDelta/1000); |
| 187 | fprintf(mFileOut, "Max Time sync loss = %u\n",mMaxTimeSyncLoss/1000); |
| 188 | fprintf(mFileOut, "=====================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 189 | } |
| 190 | } |
| 191 | |
| 192 | void DashPlayerStats::logFps() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 193 | if (mFileOut) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 194 | Mutex::Autolock autoLock(mStatsLock); |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 195 | int64_t now = getTimeOfDayUs(); |
| 196 | |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 197 | if(mTotalRenderingFrames < 2){ |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 198 | mLastFrameUs = now; |
| 199 | mFirstFrameTime = now; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 200 | } |
| 201 | |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 202 | mTotalTime = now - mFirstFrameTime; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 203 | int64_t diff = now - mLastFrameUs; |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 204 | if (diff > 250000 && !mVeryFirstFrame && !mBufferingEvent) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 205 | double fps =((mTotalRenderingFrames - mLastFrame) * 1E6)/diff; |
| 206 | if (mStatisticsFrames == 0) { |
| 207 | fps =((mTotalRenderingFrames - mLastFrame - 1) * 1E6)/diff; |
| 208 | } |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 209 | fprintf(mFileOut, "Frames per second: %.4f, Duration of measurement: %lld\n", fps,diff); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 210 | mFPSSumUs += fps; |
| 211 | ++mStatisticsFrames; |
| 212 | mLastFrameUs = now; |
| 213 | mLastFrame = mTotalRenderingFrames; |
| 214 | } |
| 215 | |
| 216 | if(mSeekPerformed) { |
| 217 | mVeryFirstFrame = false; |
| 218 | mSeekPerformed = false; |
| 219 | } else if(mVeryFirstFrame) { |
| 220 | logFirstFrame(); |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 221 | fprintf(mFileOut, "setting first frame time\n"); |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 222 | mLastFrameUs = now; |
| 223 | } else if(mBufferingEvent) { |
| 224 | mLastFrameUs = now; |
| 225 | mLastFrame = mTotalRenderingFrames; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 226 | } |
Naupada Dharmendra Patnaik | 84a8aa1 | 2013-02-01 14:34:07 +0530 | [diff] [blame] | 227 | mBufferingEvent = false; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | |
| 231 | void DashPlayerStats::logFpsSummary() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 232 | if (mFileOut) { |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 233 | logStatistics(); |
| 234 | logSyncLoss(); |
| 235 | { |
| 236 | Mutex::Autolock autoLock(mStatsLock); |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 237 | fprintf(mFileOut, "=========================================================\n"); |
| 238 | fprintf(mFileOut, "Average Frames Per Second: %.4f\n", mFPSSumUs/((double)mStatisticsFrames)); |
| 239 | fprintf(mFileOut, "Total Frames (rendered) / Total Time: %.4f\n", ((double)(mTotalRenderingFrames-1)*1E6)/((double)mTotalTime)); |
| 240 | fprintf(mFileOut, "========================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 241 | } |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | int64_t DashPlayerStats::getTimeOfDayUs() { |
| 246 | struct timeval tv; |
| 247 | gettimeofday(&tv, NULL); |
| 248 | return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; |
| 249 | } |
| 250 | |
| 251 | // WARNING: Most private functions are only thread-safe within mStatsLock |
| 252 | inline void DashPlayerStats::logFirstFrame() { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 253 | fprintf(mFileOut, "=====================================================\n"); |
| 254 | fprintf(mFileOut, "First frame latency: %lld ms\n",(getTimeOfDayUs()-mFirstFrameLatencyStartUs)/1000); |
| 255 | fprintf(mFileOut, "=====================================================\n"); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 256 | mVeryFirstFrame = false; |
| 257 | } |
| 258 | |
| 259 | inline void DashPlayerStats::logCatchUp(int64_t ts, int64_t clock, int64_t delta) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 260 | if (mConsecutiveFramesDropped > 0) { |
| 261 | mNumTimesSyncLoss++; |
| 262 | if (mMaxTimeSyncLoss < (clock - mCatchupTimeStart) && clock > 0 && ts > 0) { |
| 263 | mMaxTimeSyncLoss = clock - mCatchupTimeStart; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 264 | } |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | inline void DashPlayerStats::logLate(int64_t ts, int64_t clock, int64_t delta) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 269 | if (mMaxLateDelta < delta && clock > 0 && ts > 0) { |
| 270 | mMaxLateDelta = delta; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 271 | } |
| 272 | } |
| 273 | |
| 274 | inline void DashPlayerStats::logOnTime(int64_t ts, int64_t clock, int64_t delta) { |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 275 | bool needLogLate = false; |
| 276 | logCatchUp(ts, clock, delta); |
| 277 | if (delta <= 0) { |
| 278 | if ((-delta) > (-mMaxEarlyDelta) && clock > 0 && ts > 0) { |
| 279 | mMaxEarlyDelta = delta; |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 280 | } |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 281 | } |
Surajit Podder | 852ebd5 | 2013-02-21 15:05:18 +0530 | [diff] [blame] | 282 | else { |
| 283 | needLogLate = true; |
| 284 | } |
| 285 | |
| 286 | if(needLogLate) logLate(ts, clock, delta); |
Ajit Khare | 73cfaf4 | 2013-01-07 23:28:47 -0800 | [diff] [blame] | 287 | } |
| 288 | |
| 289 | } // namespace android |