feat: add back lowest latency mode for AVSampleBuffer
This commit is contained in:
1 parent
eb3501e090
commit
39d7d9e213
9 files changed
+107
-36
No files matched your search
@@ -1000,6 +1000,7 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="2Dp-Qg-chi" userLabel="Frame Pacing Mode Selector">
|
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="2Dp-Qg-chi" userLabel="Frame Pacing Mode Selector">
|
||||||
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
|
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
|
||||||
<segments>
|
<segments>
|
||||||
|
<segment title="Off"/>
|
||||||
<segment title="Legacy"/>
|
<segment title="Legacy"/>
|
||||||
<segment title="Queue Buffering"/>
|
<segment title="Queue Buffering"/>
|
||||||
</segments>
|
</segments>
|
||||||
|
|||||||
@@ -1695,6 +1695,7 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="CC6-pu-Uoh" userLabel="Frame Pacing Mode Selector">
|
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" translatesAutoresizingMaskIntoConstraints="NO" id="CC6-pu-Uoh" userLabel="Frame Pacing Mode Selector">
|
||||||
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
|
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
|
||||||
<segments>
|
<segments>
|
||||||
|
<segment title="Off"/>
|
||||||
<segment title="Legacy"/>
|
<segment title="Legacy"/>
|
||||||
<segment title="Queue Buffering"/>
|
<segment title="Queue Buffering"/>
|
||||||
</segments>
|
</segments>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ typedef NS_ENUM(NSInteger, GyroMode) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FramePacingMode) {
|
typedef NS_ENUM(NSInteger, FramePacingMode) {
|
||||||
|
FramePacingModeOff,
|
||||||
FramePacingModeLegacy,
|
FramePacingModeLegacy,
|
||||||
FramePacingModeQueue
|
FramePacingModeQueue
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -493,9 +493,10 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t
|
|||||||
LiInitializeVideoCallbacks(&_drCallbacks);
|
LiInitializeVideoCallbacks(&_drCallbacks);
|
||||||
_drCallbacks.setup = DrDecoderSetup;
|
_drCallbacks.setup = DrDecoderSetup;
|
||||||
_drCallbacks.cleanup = DrCleanup;
|
_drCallbacks.cleanup = DrCleanup;
|
||||||
// Use pull renderer for legacy frame pacing, direct submit for modern frame pacing
|
// Use pull renderer for legacy and off frame pacing, direct submit for queue-based frame pacing
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
if ([[dataMan getSettings].framePacingMode integerValue] == FramePacingModeLegacy) {
|
FramePacingMode framePacingMode = [[dataMan getSettings].framePacingMode integerValue];
|
||||||
|
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
|
||||||
_drCallbacks.capabilities = CAPABILITY_PULL_RENDERER |
|
_drCallbacks.capabilities = CAPABILITY_PULL_RENDERER |
|
||||||
CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC |
|
CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC |
|
||||||
CAPABILITY_REFERENCE_FRAME_INVALIDATION_AV1;
|
CAPABILITY_REFERENCE_FRAME_INVALIDATION_AV1;
|
||||||
|
|||||||
@@ -189,13 +189,13 @@
|
|||||||
|
|
||||||
float interval = stats.endTime - stats.startTime;
|
float interval = stats.endTime - stats.startTime;
|
||||||
|
|
||||||
// Check if we're using legacy pacing mode
|
// Get frame pacing mode
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
BOOL isLegacyPacing = [[dataMan getSettings].framePacingMode integerValue] == FramePacingModeLegacy;
|
FramePacingMode framePacingMode = [[dataMan getSettings].framePacingMode integerValue];
|
||||||
|
|
||||||
// Calculate FPS differently based on pacing mode
|
// Calculate FPS differently based on pacing mode
|
||||||
float fps;
|
float fps;
|
||||||
if (isLegacyPacing) {
|
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
|
||||||
fps = stats.totalFrames / interval;
|
fps = stats.totalFrames / interval;
|
||||||
} else {
|
} else {
|
||||||
float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f;
|
float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f;
|
||||||
@@ -210,10 +210,14 @@
|
|||||||
stats.networkDroppedFrames / interval,
|
stats.networkDroppedFrames / interval,
|
||||||
latencyString];
|
latencyString];
|
||||||
else {
|
else {
|
||||||
if (isLegacyPacing) {
|
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
|
||||||
NSString* rendererWithPacing = stats.renderingBackendString;
|
NSString* rendererWithPacing = stats.renderingBackendString;
|
||||||
if ([stats.renderingBackendString isEqualToString:@"AVSampleBuffer"]) {
|
if ([stats.renderingBackendString isEqualToString:@"AVSampleBuffer"]) {
|
||||||
rendererWithPacing = @"AVSampleBuffer (Legacy Pacing)";
|
if (framePacingMode == FramePacingModeOff) {
|
||||||
|
rendererWithPacing = @"AVSampleBuffer (No Pacing)";
|
||||||
|
} else {
|
||||||
|
rendererWithPacing = @"AVSampleBuffer (Legacy Pacing)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\n"
|
return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\n"
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
|||||||
NSInteger _maxRefreshRate;
|
NSInteger _maxRefreshRate;
|
||||||
RenderingBackend _renderingBackend;
|
RenderingBackend _renderingBackend;
|
||||||
|
|
||||||
BOOL _useLegacyPacing;
|
FramePacingMode _framePacingMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reinitializeDisplayLayer
|
- (void)reinitializeDisplayLayer
|
||||||
@@ -130,7 +130,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
|||||||
|
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
|
|
||||||
_useLegacyPacing = [[dataMan getSettings].framePacingMode integerValue] == FramePacingModeLegacy;
|
_framePacingMode = [[dataMan getSettings].framePacingMode integerValue];
|
||||||
|
|
||||||
_frameQueue = [FrameQueue sharedInstance];
|
_frameQueue = [FrameQueue sharedInstance];
|
||||||
[_frameQueue start];
|
[_frameQueue start];
|
||||||
@@ -162,8 +162,8 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
|
|||||||
|
|
||||||
// Choose the appropriate selector based on frame pacing mode
|
// Choose the appropriate selector based on frame pacing mode
|
||||||
SEL displayLinkSelector;
|
SEL displayLinkSelector;
|
||||||
if (_useLegacyPacing) {
|
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
|
||||||
// Legacy frame pacing: use simple displayLinkCallback
|
// Legacy frame pacing or Off mode: use simple displayLinkCallback
|
||||||
displayLinkSelector = @selector(displayLinkCallback:);
|
displayLinkSelector = @selector(displayLinkCallback:);
|
||||||
} else {
|
} else {
|
||||||
// PACING_MODE_VSYNC:
|
// PACING_MODE_VSYNC:
|
||||||
@@ -332,21 +332,22 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
|||||||
while (LiPollNextVideoFrame(&handle, &du)) {
|
while (LiPollNextVideoFrame(&handle, &du)) {
|
||||||
LiCompleteVideoFrame(handle, DrSubmitDecodeUnit(du));
|
LiCompleteVideoFrame(handle, DrSubmitDecodeUnit(du));
|
||||||
|
|
||||||
/*
|
// Skip frame pacing logic if frame pacing is off
|
||||||
// Calculate the actual display refresh rate
|
if (_framePacingMode != FramePacingModeOff) {
|
||||||
double displayRefreshRate = 1 / (_displayLink.targetTimestamp - _displayLink.timestamp);
|
// Calculate the actual display refresh rate
|
||||||
|
double displayRefreshRate = 1 / (_displayLink.targetTimestamp - _displayLink.timestamp);
|
||||||
// Only pace frames if the display refresh rate is >= 90% of our stream frame rate.
|
|
||||||
// Battery saver, accessibility settings, or device thermals can cause the actual
|
// Only pace frames if the display refresh rate is >= 90% of our stream frame rate.
|
||||||
// refresh rate of the display to drop below the physical maximum.
|
// Battery saver, accessibility settings, or device thermals can cause the actual
|
||||||
if (displayRefreshRate >= _frameRate * 0.9f) {
|
// refresh rate of the display to drop below the physical maximum.
|
||||||
// Keep one pending frame to smooth out gaps due to
|
if (displayRefreshRate >= _frameRate * 0.9f) {
|
||||||
// network jitter at the cost of 1 frame of latency
|
// Keep one pending frame to smooth out gaps due to
|
||||||
if (LiGetPendingVideoFrames() == 1) {
|
// network jitter at the cost of 1 frame of latency
|
||||||
break;
|
if (LiGetPendingVideoFrames() == 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,7 +859,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
|||||||
|
|
||||||
CMSampleBufferRef sampleBuffer;
|
CMSampleBufferRef sampleBuffer;
|
||||||
CMTime presentationTimeStamp;
|
CMTime presentationTimeStamp;
|
||||||
if (_useLegacyPacing) {
|
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
|
||||||
presentationTimeStamp = CMTimeMake(du->presentationTimeUs / 1000, 1000);
|
presentationTimeStamp = CMTimeMake(du->presentationTimeUs / 1000, 1000);
|
||||||
} else {
|
} else {
|
||||||
presentationTimeStamp = CMTimeMake((int64_t)du->rtpTimestamp, 90000);
|
presentationTimeStamp = CMTimeMake((int64_t)du->rtpTimestamp, 90000);
|
||||||
@@ -883,7 +884,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
|||||||
return DR_NEED_IDR;
|
return DR_NEED_IDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_useLegacyPacing) {
|
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
|
||||||
// Enqueue the next frame
|
// Enqueue the next frame
|
||||||
[self->_displayLayer enqueueSampleBuffer:sampleBuffer];
|
[self->_displayLayer enqueueSampleBuffer:sampleBuffer];
|
||||||
|
|
||||||
|
|||||||
@@ -1745,16 +1745,17 @@ BOOL isCustomResolution(int resolutionSelected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)framePacingModeChanged:(UISegmentedControl *)sender {
|
- (void)framePacingModeChanged:(UISegmentedControl *)sender {
|
||||||
[self setHidden:sender.selectedSegmentIndex == FramePacingModeLegacy forStack:self.frameQueueSizeStack];
|
// Hide frame queue size for Off and Legacy modes
|
||||||
|
[self setHidden:(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy) forStack:self.frameQueueSizeStack];
|
||||||
[videoSection updateViewForFoldState];
|
[videoSection updateViewForFoldState];
|
||||||
|
|
||||||
if(sender.selectedSegmentIndex == FramePacingModeLegacy){
|
if(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy){
|
||||||
[self.enableGraphsSwitch setOn:NO];
|
[self.enableGraphsSwitch setOn:NO];
|
||||||
[self findDynamicLabelFromStack:_graphOpacityStack].hidden = YES;
|
[self findDynamicLabelFromStack:_graphOpacityStack].hidden = YES;
|
||||||
}
|
}
|
||||||
[self.enableGraphsSwitch setEnabled:sender.selectedSegmentIndex == FramePacingModeQueue];
|
[self.enableGraphsSwitch setEnabled:sender.selectedSegmentIndex == FramePacingModeQueue];
|
||||||
[self.graphOpacityStepper setEnabled:self.enableGraphsSwitch.isOn];
|
[self.graphOpacityStepper setEnabled:self.enableGraphsSwitch.isOn];
|
||||||
[self setHidden:sender.selectedSegmentIndex == FramePacingModeLegacy forStack:self.performanceGraphStack];
|
[self setHidden:(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy) forStack:self.performanceGraphStack];
|
||||||
[otherSection updateViewForFoldState];
|
[otherSection updateViewForFoldState];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -32,7 +32,37 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"2Dp-Qg-chi.segmentTitles[0]" : {
|
"2Dp-Qg-chi.segmentTitles[0]" : {
|
||||||
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[0] = \"Legacy\"; ObjectID = \"2Dp-Qg-chi\";",
|
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[0] = \"Off\"; ObjectID = \"2Dp-Qg-chi\";",
|
||||||
|
"extractionState" : "extracted_with_value",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "new",
|
||||||
|
"value" : "Off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "关闭"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "關閉"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "關閉"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2Dp-Qg-chi.segmentTitles[1]" : {
|
||||||
|
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[1] = \"Legacy\"; ObjectID = \"2Dp-Qg-chi\";",
|
||||||
"extractionState" : "extracted_with_value",
|
"extractionState" : "extracted_with_value",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -61,8 +91,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"2Dp-Qg-chi.segmentTitles[1]" : {
|
"2Dp-Qg-chi.segmentTitles[2]" : {
|
||||||
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[1] = \"Queue Buffering\"; ObjectID = \"2Dp-Qg-chi\";",
|
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[2] = \"Queue Buffering\"; ObjectID = \"2Dp-Qg-chi\";",
|
||||||
"extractionState" : "extracted_with_value",
|
"extractionState" : "extracted_with_value",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
|
|||||||
@@ -1058,7 +1058,38 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CC6-pu-Uoh.segmentTitles[0]" : {
|
"CC6-pu-Uoh.segmentTitles[0]" : {
|
||||||
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[0] = \"Legacy\"; ObjectID = \"CC6-pu-Uoh\";",
|
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[0] = \"Off\"; ObjectID = \"CC6-pu-Uoh\";",
|
||||||
|
"extractionState" : "extracted_with_value",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "new",
|
||||||
|
"value" : "Off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "关闭"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "關閉"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-HK" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "關閉"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CC6-pu-Uoh.segmentTitles[1]" : {
|
||||||
|
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[1] = \"Legacy\"; ObjectID = \"CC6-pu-Uoh\";",
|
||||||
"extractionState" : "extracted_with_value",
|
"extractionState" : "extracted_with_value",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -1087,8 +1118,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CC6-pu-Uoh.segmentTitles[1]" : {
|
"CC6-pu-Uoh.segmentTitles[2]" : {
|
||||||
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[1] = \"Queue Buffering\"; ObjectID = \"CC6-pu-Uoh\";",
|
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[2] = \"Queue Buffering\"; ObjectID = \"CC6-pu-Uoh\";",
|
||||||
"extractionState" : "extracted_with_value",
|
"extractionState" : "extracted_with_value",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
|
|||||||
Reference in new issue
Block a user