fix(player): update MPVKit and stream buffering
This commit is contained in:
@@ -789,7 +789,7 @@
|
|||||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = revision;
|
kind = revision;
|
||||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/edde746/MPVKit",
|
"location" : "https://github.com/edde746/MPVKit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "1fe345d46bac91f4e85239ad268430e037040b2b"
|
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/edde746/MPVKit",
|
"location" : "https://github.com/edde746/MPVKit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -763,7 +763,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
|
|||||||
_audioFocusFuture = currentPlayer.requestAudioFocus();
|
_audioFocusFuture = currentPlayer.requestAudioFocus();
|
||||||
_audioFocusFuture!.ignore();
|
_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.setLogLevel(debugLoggingEnabled ? 'v' : 'warn');
|
||||||
await currentPlayer.setProperty('hwdec', _getHwdecValue(enableHardwareDecoding));
|
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
|
/// in bytes, seconds × video byterate — which makes ffmpeg's DTS-ordered
|
||||||
/// reads ping-pong across the file. Over HTTP every ping-pong that escapes
|
/// 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
|
/// 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
|
/// redials the connection on every seek, collapsing throughput.
|
||||||
/// interleaved by spec and excluded.
|
const quickTimeFamilyContainers = {'mp4', 'mov', 'm4v', '3gp', '3g2'};
|
||||||
const poorlyInterleavedContainers = {'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 minStreamRingBytes = 16 * 1024 * 1024;
|
||||||
const maxStreamRingBytes = 128 * 1024 * 1024;
|
const maxStreamRingBytes = 128 * 1024 * 1024;
|
||||||
@@ -60,10 +66,15 @@ int? networkStreamRingBytes({
|
|||||||
if (container == null) return null;
|
if (container == null) return null;
|
||||||
// Jellyfin may report ffmpeg demuxer alias lists ('mov,mp4,m4a,3gp,3g2,mj2').
|
// Jellyfin may report ffmpeg demuxer alias lists ('mov,mp4,m4a,3gp,3g2,mj2').
|
||||||
final tokens = container.toLowerCase().split(',').map((token) => token.trim());
|
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));
|
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 bytesPerSecond = bitrateKbps * 1000 ~/ 8;
|
||||||
final ring = nextPowerOfTwo(bytesPerSecond * _streamRingContentSeconds);
|
final ring = nextPowerOfTwo(bytesPerSecond * _streamRingContentSeconds);
|
||||||
|
|||||||
@@ -883,7 +883,7 @@
|
|||||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = revision;
|
kind = revision;
|
||||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/edde746/MPVKit",
|
"location" : "https://github.com/edde746/MPVKit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/edde746/MPVKit",
|
"location" : "https://github.com/edde746/MPVKit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "1fc33029bc0317583866c62811dc0ab2aa2415b6"
|
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,12 +21,22 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('returns null for well-interleaved or unknown containers', () {
|
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: 'avi', bitrateKbps: 69140), isNull);
|
||||||
expect(networkStreamRingBytes(container: null, bitrateKbps: 69140), isNull);
|
expect(networkStreamRingBytes(container: null, bitrateKbps: 69140), isNull);
|
||||||
expect(networkStreamRingBytes(container: '', 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', () {
|
test('matches QuickTime-family containers case-insensitively', () {
|
||||||
expect(networkStreamRingBytes(container: 'MOV', bitrateKbps: 69140), 64 * 1024 * 1024);
|
expect(networkStreamRingBytes(container: 'MOV', bitrateKbps: 69140), 64 * 1024 * 1024);
|
||||||
expect(networkStreamRingBytes(container: 'mp4', 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', () {
|
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: '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', () {
|
test('falls back to 64MiB when bitrate is unknown', () {
|
||||||
|
|||||||
@@ -933,7 +933,7 @@
|
|||||||
repositoryURL = "https://github.com/edde746/MPVKit";
|
repositoryURL = "https://github.com/edde746/MPVKit";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = revision;
|
kind = revision;
|
||||||
revision = 1fe345d46bac91f4e85239ad268430e037040b2b;
|
revision = 245b69dce22156e81b79c84cfcb748358b674e47;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/edde746/MPVKit",
|
"location" : "https://github.com/edde746/MPVKit",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "1fe345d46bac91f4e85239ad268430e037040b2b"
|
"revision" : "245b69dce22156e81b79c84cfcb748358b674e47"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user