fix(player): update MPVKit and stream buffering
This commit is contained in:
@@ -789,7 +789,7 @@
|
||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
||||
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/edde746/MPVKit",
|
||||
"state" : {
|
||||
"revision" : "1fe345d46bac91f4e85239ad268430e037040b2b"
|
||||
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/edde746/MPVKit",
|
||||
"state" : {
|
||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
||||
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -763,7 +763,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
||||
_audioFocusFuture = currentPlayer.requestAudioFocus();
|
||||
_audioFocusFuture!.ignore();
|
||||
}
|
||||
await currentPlayer.setProperty('msg-level', debugLoggingEnabled ? 'all=debug' : 'all=error');
|
||||
await currentPlayer.setProperty('msg-level', debugLoggingEnabled ? 'all=debug,ffmpeg/video=warn' : 'all=error');
|
||||
await currentPlayer.setLogLevel(debugLoggingEnabled ? 'v' : 'warn');
|
||||
await currentPlayer.setProperty('hwdec', _getHwdecValue(enableHardwareDecoding));
|
||||
|
||||
|
||||
@@ -10,9 +10,15 @@ const mpvDefaultStreamBufferBytes = 128 * 1024;
|
||||
/// in bytes, seconds × video byterate — which makes ffmpeg's DTS-ordered
|
||||
/// reads ping-pong across the file. Over HTTP every ping-pong that escapes
|
||||
/// mpv's stream ring buffer is a byte seek, and ffmpeg's http layer drops and
|
||||
/// redials the connection on every seek, collapsing throughput. MKV is
|
||||
/// interleaved by spec and excluded.
|
||||
const poorlyInterleavedContainers = {'mp4', 'mov', 'm4v', '3gp', '3g2'};
|
||||
/// redials the connection on every seek, collapsing throughput.
|
||||
const quickTimeFamilyContainers = {'mp4', 'mov', 'm4v', '3gp', '3g2'};
|
||||
|
||||
/// Matroska/WebM is normally well-interleaved, but UHD direct-play remuxes can
|
||||
/// still overrun mpv's tiny 128 KiB default stream ring during normal demuxer
|
||||
/// read bursts. Only opt in when the server reports a high bitrate so common
|
||||
/// MKV playback keeps the default memory profile.
|
||||
const matroskaFamilyContainers = {'mkv', 'matroska', 'webm'};
|
||||
const _highBitrateMatroskaThresholdKbps = 40 * 1000;
|
||||
|
||||
const minStreamRingBytes = 16 * 1024 * 1024;
|
||||
const maxStreamRingBytes = 128 * 1024 * 1024;
|
||||
@@ -60,10 +66,15 @@ int? networkStreamRingBytes({
|
||||
if (container == null) return null;
|
||||
// Jellyfin may report ffmpeg demuxer alias lists ('mov,mp4,m4a,3gp,3g2,mj2').
|
||||
final tokens = container.toLowerCase().split(',').map((token) => token.trim());
|
||||
if (!tokens.any(poorlyInterleavedContainers.contains)) return null;
|
||||
final isQuickTimeFamily = tokens.any(quickTimeFamilyContainers.contains);
|
||||
final isMatroskaFamily = tokens.any(matroskaFamilyContainers.contains);
|
||||
if (!isQuickTimeFamily && !isMatroskaFamily) return null;
|
||||
|
||||
final cap = max(minStreamRingBytes, min(maxBytes, maxStreamRingBytes));
|
||||
if (bitrateKbps == null || bitrateKbps <= 0) return min(unknownBitrateStreamRingBytes, cap);
|
||||
if (bitrateKbps == null || bitrateKbps <= 0) {
|
||||
return isQuickTimeFamily ? min(unknownBitrateStreamRingBytes, cap) : null;
|
||||
}
|
||||
if (!isQuickTimeFamily && bitrateKbps < _highBitrateMatroskaThresholdKbps) return null;
|
||||
|
||||
final bytesPerSecond = bitrateKbps * 1000 ~/ 8;
|
||||
final ring = nextPowerOfTwo(bytesPerSecond * _streamRingContentSeconds);
|
||||
|
||||
@@ -883,7 +883,7 @@
|
||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
||||
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/edde746/MPVKit",
|
||||
"state" : {
|
||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
||||
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/edde746/MPVKit",
|
||||
"state" : {
|
||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
||||
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -21,12 +21,22 @@ void main() {
|
||||
});
|
||||
|
||||
test('returns null for well-interleaved or unknown containers', () {
|
||||
expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 69140), isNull);
|
||||
expect(networkStreamRingBytes(container: 'avi', bitrateKbps: 69140), isNull);
|
||||
expect(networkStreamRingBytes(container: null, bitrateKbps: 69140), isNull);
|
||||
expect(networkStreamRingBytes(container: '', bitrateKbps: 69140), isNull);
|
||||
});
|
||||
|
||||
test('sizes high-bitrate Matroska direct play to 64MiB', () {
|
||||
expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
expect(networkStreamRingBytes(container: 'matroska', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
});
|
||||
|
||||
test('keeps ordinary Matroska direct play on the default stream ring', () {
|
||||
expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 39000), isNull);
|
||||
expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: null), isNull);
|
||||
expect(networkStreamRingBytes(container: 'mkv', bitrateKbps: 0), isNull);
|
||||
});
|
||||
|
||||
test('matches QuickTime-family containers case-insensitively', () {
|
||||
expect(networkStreamRingBytes(container: 'MOV', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
expect(networkStreamRingBytes(container: 'mp4', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
@@ -34,7 +44,7 @@ void main() {
|
||||
|
||||
test('matches ffmpeg demuxer alias lists from Jellyfin', () {
|
||||
expect(networkStreamRingBytes(container: 'mov,mp4,m4a,3gp,3g2,mj2', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
expect(networkStreamRingBytes(container: 'matroska,webm', bitrateKbps: 69140), isNull);
|
||||
expect(networkStreamRingBytes(container: 'matroska,webm', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||
});
|
||||
|
||||
test('falls back to 64MiB when bitrate is unknown', () {
|
||||
|
||||
@@ -933,7 +933,7 @@
|
||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||
requirement = {
|
||||
kind = revision;
|
||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
||||
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/edde746/MPVKit",
|
||||
"state" : {
|
||||
"revision" : "1fe345d46bac91f4e85239ad268430e037040b2b"
|
||||
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user