feat: add back lowest latency mode for AVSampleBuffer

This commit is contained in:
Acaki
2025-08-27 15:53:00 +08:00
parent eb3501e090
commit 39d7d9e213
9 changed files with 107 additions and 36 deletions
+1
View File
@@ -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">
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
<segments>
<segment title="Off"/>
<segment title="Legacy"/>
<segment title="Queue Buffering"/>
</segments>
+1
View File
@@ -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">
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
<segments>
<segment title="Off"/>
<segment title="Legacy"/>
<segment title="Queue Buffering"/>
</segments>
+1
View File
@@ -43,6 +43,7 @@ typedef NS_ENUM(NSInteger, GyroMode) {
};
typedef NS_ENUM(NSInteger, FramePacingMode) {
FramePacingModeOff,
FramePacingModeLegacy,
FramePacingModeQueue
};
+3 -2
View File
@@ -493,9 +493,10 @@ void ClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t
LiInitializeVideoCallbacks(&_drCallbacks);
_drCallbacks.setup = DrDecoderSetup;
_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];
if ([[dataMan getSettings].framePacingMode integerValue] == FramePacingModeLegacy) {
FramePacingMode framePacingMode = [[dataMan getSettings].framePacingMode integerValue];
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
_drCallbacks.capabilities = CAPABILITY_PULL_RENDERER |
CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC |
CAPABILITY_REFERENCE_FRAME_INVALIDATION_AV1;
+10 -6
View File
@@ -189,13 +189,13 @@
float interval = stats.endTime - stats.startTime;
// Check if we're using legacy pacing mode
// Get frame pacing mode
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
float fps;
if (isLegacyPacing) {
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
fps = stats.totalFrames / interval;
} else {
float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f;
@@ -210,10 +210,14 @@
stats.networkDroppedFrames / interval,
latencyString];
else {
if (isLegacyPacing) {
if (framePacingMode == FramePacingModeLegacy || framePacingMode == FramePacingModeOff) {
NSString* rendererWithPacing = stats.renderingBackendString;
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"
+20 -19
View File
@@ -55,7 +55,7 @@ extern int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
NSInteger _maxRefreshRate;
RenderingBackend _renderingBackend;
BOOL _useLegacyPacing;
FramePacingMode _framePacingMode;
}
- (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];
_useLegacyPacing = [[dataMan getSettings].framePacingMode integerValue] == FramePacingModeLegacy;
_framePacingMode = [[dataMan getSettings].framePacingMode integerValue];
_frameQueue = [FrameQueue sharedInstance];
[_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
SEL displayLinkSelector;
if (_useLegacyPacing) {
// Legacy frame pacing: use simple displayLinkCallback
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
// Legacy frame pacing or Off mode: use simple displayLinkCallback
displayLinkSelector = @selector(displayLinkCallback:);
} else {
// PACING_MODE_VSYNC:
@@ -332,21 +332,22 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
while (LiPollNextVideoFrame(&handle, &du)) {
LiCompleteVideoFrame(handle, DrSubmitDecodeUnit(du));
/*
// 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
// refresh rate of the display to drop below the physical maximum.
if (displayRefreshRate >= _frameRate * 0.9f) {
// Keep one pending frame to smooth out gaps due to
// network jitter at the cost of 1 frame of latency
if (LiGetPendingVideoFrames() == 1) {
break;
// Skip frame pacing logic if frame pacing is off
if (_framePacingMode != FramePacingModeOff) {
// 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
// refresh rate of the display to drop below the physical maximum.
if (displayRefreshRate >= _frameRate * 0.9f) {
// Keep one pending frame to smooth out gaps due to
// network jitter at the cost of 1 frame of latency
if (LiGetPendingVideoFrames() == 1) {
break;
}
}
}
*/
}
}
@@ -858,7 +859,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
CMSampleBufferRef sampleBuffer;
CMTime presentationTimeStamp;
if (_useLegacyPacing) {
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
presentationTimeStamp = CMTimeMake(du->presentationTimeUs / 1000, 1000);
} else {
presentationTimeStamp = CMTimeMake((int64_t)du->rtpTimestamp, 90000);
@@ -883,7 +884,7 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
return DR_NEED_IDR;
}
if (_useLegacyPacing) {
if (_framePacingMode == FramePacingModeLegacy || _framePacingMode == FramePacingModeOff) {
// Enqueue the next frame
[self->_displayLayer enqueueSampleBuffer:sampleBuffer];
@@ -1745,16 +1745,17 @@ BOOL isCustomResolution(int resolutionSelected) {
}
- (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];
if(sender.selectedSegmentIndex == FramePacingModeLegacy){
if(sender.selectedSegmentIndex == FramePacingModeOff || sender.selectedSegmentIndex == FramePacingModeLegacy){
[self.enableGraphsSwitch setOn:NO];
[self findDynamicLabelFromStack:_graphOpacityStack].hidden = YES;
}
[self.enableGraphsSwitch setEnabled:sender.selectedSegmentIndex == FramePacingModeQueue];
[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];
/*
+33 -3
View File
@@ -32,7 +32,37 @@
}
},
"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",
"localizations" : {
"en" : {
@@ -61,8 +91,8 @@
}
}
},
"2Dp-Qg-chi.segmentTitles[1]" : {
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[1] = \"Queue Buffering\"; ObjectID = \"2Dp-Qg-chi\";",
"2Dp-Qg-chi.segmentTitles[2]" : {
"comment" : "Class = \"UISegmentedControl\"; 2Dp-Qg-chi.segmentTitles[2] = \"Queue Buffering\"; ObjectID = \"2Dp-Qg-chi\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
+34 -3
View File
@@ -1058,7 +1058,38 @@
}
},
"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",
"localizations" : {
"en" : {
@@ -1087,8 +1118,8 @@
}
}
},
"CC6-pu-Uoh.segmentTitles[1]" : {
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[1] = \"Queue Buffering\"; ObjectID = \"CC6-pu-Uoh\";",
"CC6-pu-Uoh.segmentTitles[2]" : {
"comment" : "Class = \"UISegmentedControl\"; CC6-pu-Uoh.segmentTitles[2] = \"Queue Buffering\"; ObjectID = \"CC6-pu-Uoh\";",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {