Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HLS (fMP4) Exoplayer v2.17.1 DTS Digital Surround Passthrough Issue #10204

Closed
1 task
cedricxperi opened this issue Apr 20, 2022 · 6 comments
Closed
1 task
Assignees
Labels

Comments

@cedricxperi
Copy link
Contributor

cedricxperi commented Apr 20, 2022

ExoPlayer Version

2.17.1

Devices that reproduce the issue

Nvidia Shield TV Pro

Devices that do not reproduce the issue

None

Reproducible in the demo app?

Yes

Reproduction steps

Playback a HLS (fMP4) DTS Digital Surround audio stream on Nvidia Shield TV Pro (connected to an AVR via HDMI) running v2.17.1 Exoplayer demo app.
The DTS bitstream should be passthrough to the AVR for decoding. This works in earlier versions of Exoplayer, E.g. v2.14.1. In v2.17.1 the playback fails.

Expected result

The DTS bitstream should be passthrough to the AVR for decoding.

Actual result

Playback Fails.

Diagnosis

In Exoplayer, there is a variable  allowChunklessPreparation in HLSMediaPeriod.java which determines whether chunkless preparation (for HLS-fMp4 streams) is allowed. If chunkless preparation is allowed, the attributes of the Codec (such as channelCount) will not be determined by downloading a segment and parsing the Moov box (AtomParsers.parseAudioSampleEntry()). Instead, it will be trying to read these attributes from the Multivariant HLS playlist. Details on Multivariant playlist is here: https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/creating_a_multivariant_playlist

When Exoplayer is deciding whether to passthrough the bitstream, it calls DefaultAudioSink().isPassthroughPlaybackSupported(), which will return false when channelCount of the stream is unknown.

When allowChunklessPreparation is set to true, it depends on the HLS manifests (See HlsPlaylistParser::parseMultivariantPlaylist(), HLSMediaPeriod::deriveAudioFormat()) to provide information on the CODECS.  However, in the test streams used, "channelCount" is not part of the information provide by the HLS Multivariant playlist. This resulted in the channelCount not being defined and DefaultAudioSink().isPassthroughPlaybackSupported() will return false causing the Digital Surround bitstream passthrough to fail.

When allowChunklessPreparation is set to false, channelCount will be read by parsing the Moov box (AtomParsers.parseAudioSampleEntry()) during the setup stage. A subsequent call to DefaultAudioSink().isPassthroughPlaybackSupported() will then return true and passthrough is possible.

In Exoplayer v2.14.1, allowChunklessPreparation in HLSMediaPeriod.java was not set explicitly and it defaults to false. Therefore passthrough works.

In Exoplayer v2.17.1, allowChunklessPreparation in HLSMediaPeriod.java was initialised to true. This caused passthrough to fail for the reasons mentioned earlier (channelCount undefined).

Solution

In order to overcome this issue, It is recommended in Exoplayer v2.17.X to initialise allowChunklessPreparation to false in the constructor of HLSMediaSource.Factory. This will allow HLS-fMP4 with DTS Digital Surround to passthrough successfully.

Media

Test media will be emailed to dev.exoplayer@gmail.com

Bug Report

@christosts
Copy link
Contributor

christosts commented Apr 20, 2022

@andrewlewis do you now if we can make a safe guess on the number of channels if the information is missing from Format for those audio formats for which the player does audio passthrough? In this issue it's DTS, but I think the same problem may apply for the other audio encodings too. With HLS chunkless preparation, we cannot know the channel count from the playlist., hence Format.channelCount is not set.

For example, could DefaultAudioSink do something similar as in the ENCODING_E_AC3_JOC case (link)?

@andrewlewis
Copy link
Collaborator

If this is for plain DTS it looks like it only goes up to 5.1 so we could conservatively check for 6 channel output capability. That should be safe in the sense that there can't be more channels in the stream when it loads. For HDMI audio capabilities we get a max channel count so that probably means that fewer channels than the max are always supported.

@cedricxperi
Copy link
Contributor Author

cedricxperi commented Apr 27, 2022

Hi @andrewlewis @christosts ,

Picking up on your suggestions, how about something like below in DefaultAudioSink.getEncodingAndChannelConfigForPassthrough(). I have tested that the below works for passing through DTS Digital surround on Nvidia Shield TV Pro. Thanks.

if (encoding == C.ENCODING_E_AC3_JOC) {
// E-AC3 JOC is object based so the format channel count is arbitrary. From API 29 we can get
// the channel count for this encoding, but before then there is no way to query it so we
// assume 6 channel audio is supported.
if (Util.SDK_INT >= 29) {
// Default to 48 kHz if the format doesn't have a sample rate (for example, for chunkless
// HLS preparation). See [Internal: b/222127949].
int sampleRate = format.sampleRate != NO_VALUE ? format.sampleRate : 48000;
channelCount =
getMaxSupportedChannelCountForPassthroughV29(C.ENCODING_E_AC3_JOC, sampleRate);
if (channelCount == 0) {
Log.w(TAG, "E-AC3 JOC encoding supported but no channel count supported");
return null;
}
} else {
channelCount = 6;
}
} else if (encoding == C.ENCODING_DTS) {
channelCount = format.channelCount;
if (channelCount == NO_VALUE){
channelCount = 6;
}
} else {

channelCount = format.channelCount;
if (channelCount > audioCapabilities.getMaxChannelCount()) {
return null;
}
}

@christosts
Copy link
Contributor

Yes, we will add a fix along those lines - we are planning to have the fix included in the release.

@cedricxperi
Copy link
Contributor Author

@christosts That's great. Thanks a lot.

@christosts
Copy link
Contributor

christosts commented Jun 8, 2022

The upcoming 2.18 release will have a fix for this. The issue will be updated with a link to the commit once the dev branch is updated. The submitted fix covers not only DTS but other surround formats for which the player does audio passthrough playback and were affected by HLS chunkless preparation.

Thank you for bringing this issue to our attention and sharing test content. I will close this issue for now, feel free to re-open is the fix did not resolve your problem.

marcbaechinger pushed a commit that referenced this issue Jun 9, 2022
With HLS chunkless preparation, audio formats may have no value
for channel count. In this case, the DefaultAudioSink will either query
the platform for a supported channel count (API 29+) or assume a max
channel count based on the encoding spec in order to decide whether the
audio format can be played with audio passthrough.

Issue: #10204

#minor-release

PiperOrigin-RevId: 453644548
marcbaechinger pushed a commit to androidx/media that referenced this issue Jun 9, 2022
With HLS chunkless preparation, audio formats may have no value
for channel count. In this case, the DefaultAudioSink will either query
the platform for a supported channel count (API 29+) or assume a max
channel count based on the encoding spec in order to decide whether the
audio format can be played with audio passthrough.

Issue: google/ExoPlayer#10204

#minor-release

PiperOrigin-RevId: 453644548
marcbaechinger pushed a commit that referenced this issue Jun 15, 2022
With HLS chunkless preparation, audio formats may have no value
for channel count. In this case, the DefaultAudioSink will either query
the platform for a supported channel count (API 29+) or assume a max
channel count based on the encoding spec in order to decide whether the
audio format can be played with audio passthrough.

Issue: #10204

#minor-release

PiperOrigin-RevId: 453644548
(cherry picked from commit b3b57bc)
marcbaechinger pushed a commit to androidx/media that referenced this issue Jun 15, 2022
With HLS chunkless preparation, audio formats may have no value
for channel count. In this case, the DefaultAudioSink will either query
the platform for a supported channel count (API 29+) or assume a max
channel count based on the encoding spec in order to decide whether the
audio format can be played with audio passthrough.

Issue: google/ExoPlayer#10204

#minor-release

PiperOrigin-RevId: 453644548
(cherry picked from commit 8697338)
@google google locked and limited conversation to collaborators Aug 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants