fix(player): show audio codec and bitrate in the performance overlay on ExoPlayer
The Android performance overlay showed only sample rate and channels for EAC3, FLAC, DTS, TrueHD, and Opus tracks. The overlay reads the codec from media3's Format.codecs, an RFC 6381 string only MP4/HLS provide (hence AAC working), and the bitrate from Format.bitrate, which Matroska carries only when the muxer wrote BPS statistics tags. Fall back to the already-transmitted sample MIME type for the codec name (audio and video), and measure the audio bitrate in the FFmpeg demuxer from packet sizes over their pts span — the same source mpv uses for its audio-bitrate property — when the container declares none. close #2063
This commit is contained in:
@@ -200,6 +200,25 @@ void main() {
|
||||
expect(CodecUtils.formatAudioCodec('alac'), 'ALAC');
|
||||
expect(CodecUtils.formatAudioCodec('weird'), 'WEIRD');
|
||||
});
|
||||
|
||||
test('audio MIME types from ExoPlayer Format.sampleMimeType map to friendly names (#2063)', () {
|
||||
expect(CodecUtils.formatAudioCodec('audio/mp4a-latm'), 'AAC');
|
||||
expect(CodecUtils.formatAudioCodec('audio/mpeg'), 'MP3');
|
||||
expect(CodecUtils.formatAudioCodec('audio/ac3'), 'AC3');
|
||||
expect(CodecUtils.formatAudioCodec('audio/eac3'), 'E-AC3');
|
||||
expect(CodecUtils.formatAudioCodec('audio/eac3-joc'), 'E-AC3');
|
||||
expect(CodecUtils.formatAudioCodec('audio/true-hd'), 'TrueHD');
|
||||
expect(CodecUtils.formatAudioCodec('audio/vnd.dts'), 'DTS');
|
||||
expect(CodecUtils.formatAudioCodec('audio/vnd.dts.hd'), 'DTS-HD');
|
||||
expect(CodecUtils.formatAudioCodec('audio/vnd.dts.hd;profile=lbr'), 'DTS-HD');
|
||||
expect(CodecUtils.formatAudioCodec('audio/vnd.dts.uhd;audio=p2'), 'DTS:X');
|
||||
expect(CodecUtils.formatAudioCodec('audio/flac'), 'FLAC');
|
||||
expect(CodecUtils.formatAudioCodec('audio/opus'), 'Opus');
|
||||
expect(CodecUtils.formatAudioCodec('audio/vorbis'), 'Vorbis');
|
||||
expect(CodecUtils.formatAudioCodec('audio/ac4'), 'AC4');
|
||||
expect(CodecUtils.formatAudioCodec('audio/raw'), 'PCM');
|
||||
expect(CodecUtils.formatAudioCodec('audio/alac'), 'ALAC');
|
||||
});
|
||||
});
|
||||
|
||||
group('CodecUtils.formatAudioChannels', () {
|
||||
|
||||
@@ -50,6 +50,22 @@ class _PropertyPlayer implements Player {
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
/// Player fake that reports native (Android ExoPlayer) stats.
|
||||
class _NativeStatsPlayer extends _PropertyPlayer {
|
||||
_NativeStatsPlayer(this.stats) : super(const {});
|
||||
|
||||
final Map<String, dynamic> stats;
|
||||
|
||||
@override
|
||||
bool get providesNativeStats => true;
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> getStats() async => stats;
|
||||
|
||||
@override
|
||||
Future<String> runtimePlayerType() async => 'exoplayer';
|
||||
}
|
||||
|
||||
Future<PerformanceStats> _firstStats(_PropertyPlayer player) async {
|
||||
final service = PerformanceStatsService(player);
|
||||
try {
|
||||
@@ -117,4 +133,51 @@ void main() {
|
||||
expect(stats.audioPassthroughFormatted, 'DTS-HD');
|
||||
});
|
||||
});
|
||||
|
||||
group('PerformanceStatsService ExoPlayer codec display (#2063)', () {
|
||||
test('falls back to the sample MIME type when the container has no codecs string', () async {
|
||||
// Matroska via the FFmpeg demuxer: Format.codecs is null; only the
|
||||
// MIME types identify the streams.
|
||||
final stats = await _firstStats(
|
||||
_NativeStatsPlayer({
|
||||
'playerType': 'exoplayer',
|
||||
'videoCodec': null,
|
||||
'videoMimeType': 'video/hevc',
|
||||
'audioCodec': null,
|
||||
'audioMimeType': 'audio/eac3',
|
||||
'audioSampleRate': 48000,
|
||||
'audioChannels': 6,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(stats.videoCodec, 'HEVC');
|
||||
expect(stats.audioCodec, 'E-AC3');
|
||||
expect(stats.audioChannels, '5.1');
|
||||
});
|
||||
|
||||
test('an explicit codecs string wins over the MIME type', () async {
|
||||
final stats = await _firstStats(
|
||||
_NativeStatsPlayer({
|
||||
'playerType': 'exoplayer',
|
||||
'videoCodec': 'hvc1.2.4.L153.B0',
|
||||
'videoMimeType': 'video/hevc',
|
||||
'audioCodec': 'mp4a.40.2',
|
||||
'audioMimeType': 'audio/mp4a-latm',
|
||||
}),
|
||||
);
|
||||
|
||||
expect(stats.videoCodec, 'HEVC');
|
||||
expect(stats.audioCodec, 'AAC');
|
||||
});
|
||||
|
||||
test('measured audio bitrate from the native side is surfaced', () async {
|
||||
final stats = await _firstStats(
|
||||
_NativeStatsPlayer({'playerType': 'exoplayer', 'audioMimeType': 'audio/vnd.dts', 'audioBitrate': 1509000}),
|
||||
);
|
||||
|
||||
expect(stats.audioCodec, 'DTS');
|
||||
expect(stats.hasValidAudioBitrate, isTrue);
|
||||
expect(stats.audioBitrateFormatted, '1509 kbps');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user