Add a basic stats overlay

This commit is contained in:
Cameron Gutman
2020-11-01 13:27:10 -06:00
parent 2114e39237
commit 44f713f5c9
5 changed files with 125 additions and 1 deletions
+10
View File
@@ -11,6 +11,14 @@
#define CONN_TEST_SERVER "ios.conntest.moonlight-stream.org"
typedef struct {
CFTimeInterval startTime;
CFTimeInterval endTime;
int totalFrames;
int receivedFrames;
int networkDroppedFrames;
} video_stats_t;
@protocol ConnectionCallbacks <NSObject>
- (void) connectionStarted;
@@ -29,5 +37,7 @@
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks;
-(void) terminate;
-(void) main;
-(BOOL) getVideoStats:(video_stats_t*)stats;
-(NSString*) getActiveCodecName;
@end
+59
View File
@@ -30,6 +30,10 @@
static NSLock* initLock;
static OpusMSDecoder* opusDecoder;
static id<ConnectionCallbacks> _callbacks;
static int lastFrameNumber;
static int activeVideoFormat;
static video_stats_t currentVideoStats;
static video_stats_t lastVideoStats;
#define OUTPUT_BUS 0
@@ -54,6 +58,10 @@ static VideoDecoderRenderer* renderer;
int DrDecoderSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags)
{
[renderer setupWithVideoFormat:videoFormat refreshRate:redrawRate];
lastFrameNumber = 0;
activeVideoFormat = videoFormat;
memset(&currentVideoStats, 0, sizeof(currentVideoStats));
memset(&lastVideoStats, 0, sizeof(lastVideoStats));
return 0;
}
@@ -62,6 +70,33 @@ void DrCleanup(void)
[renderer cleanup];
}
-(BOOL) getVideoStats:(video_stats_t*)stats
{
// We return lastVideoStats because it is a complete 1 second window
if (lastVideoStats.endTime != 0) {
memcpy(stats, &lastVideoStats, sizeof(*stats));
return YES;
}
// No stats yet
return NO;
}
-(NSString*) getActiveCodecName
{
switch (activeVideoFormat)
{
case VIDEO_FORMAT_H264:
return @"H.264";
case VIDEO_FORMAT_H265:
return @"HEVC";
case VIDEO_FORMAT_H265_MAIN10:
return @"HEVC Main 10";
default:
return @"UNKNOWN";
}
}
int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
{
int offset = 0;
@@ -71,6 +106,30 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
// A frame was lost due to OOM condition
return DR_NEED_IDR;
}
CFTimeInterval now = CACurrentMediaTime();
if (!lastFrameNumber) {
currentVideoStats.startTime = now;
lastFrameNumber = decodeUnit->frameNumber;
}
else {
// Flip stats roughly every second
if (now - currentVideoStats.startTime > 1.0f) {
lastVideoStats = currentVideoStats;
memset(&currentVideoStats, 0, sizeof(currentVideoStats));
currentVideoStats.startTime = now;
}
// Any frame number greater than m_LastFrameNumber + 1 represents a dropped frame
currentVideoStats.networkDroppedFrames += decodeUnit->frameNumber - (lastFrameNumber + 1);
currentVideoStats.totalFrames += decodeUnit->frameNumber - (lastFrameNumber + 1);
lastFrameNumber = decodeUnit->frameNumber;
}
currentVideoStats.receivedFrames++;
currentVideoStats.totalFrames++;
currentVideoStats.endTime = now;
PLENTRY entry = decodeUnit->bufferList;
while (entry != NULL) {
+2
View File
@@ -15,4 +15,6 @@
- (void) stopStream;
- (NSString*) getStatsOverlayText;
@end
+21
View File
@@ -130,4 +130,25 @@
return TRUE;
}
- (NSString*) getStatsOverlayText {
video_stats_t stats;
if (!_connection) {
return nil;
}
if (![_connection getVideoStats:&stats]) {
return nil;
}
float interval = stats.endTime - stats.startTime;
return [NSString stringWithFormat:@"Video stream: %dx%d %.2f FPS (Codec: %@)\nIncoming frame rate from network: %.2f FPS\nFrames dropped by your network connection: %.2f%%\n",
_config.width,
_config.height,
stats.totalFrames / interval,
[_connection getActiveCodecName],
stats.receivedFrames / interval,
stats.networkDroppedFrames / interval];
}
@end