feat: add back lowest latency mode for AVSampleBuffer

This commit is contained in:
Acaki committed 2025-08-27 15:53:00 +08:00
1 parent eb3501e090
commit 39d7d9e213
9 files changed
+107 -36

No files matched your search

+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"> <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>
+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"> <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>
+1
View File
@@ -43,6 +43,7 @@ typedef NS_ENUM(NSInteger, GyroMode) {
}; };
typedef NS_ENUM(NSInteger, FramePacingMode) { typedef NS_ENUM(NSInteger, FramePacingMode) {
FramePacingModeOff,
FramePacingModeLegacy, FramePacingModeLegacy,
FramePacingModeQueue FramePacingModeQueue
}; };
+3 -2
View File
@@ -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;
+10 -6
View File
@@ -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"
+20 -19
View File
@@ -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];
/* /*
+33 -3
View File
@@ -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" : {
+34 -3
View File
@@ -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" : {