Prioritize object-based audio in DefaultTrackSelector

Object-based audio is more efficient and flexible than channel-based audio, supporting a broader range of devices. This update makes `DefaultTrackSelector` prefer object-based audio when other factors are equal, ensuring its use whenever possible.

#cherrypick

PiperOrigin-RevId: 683990051
This commit is contained in:
rohks 2024-10-09 04:52:55 -07:00 committed by Copybara-Service
parent 5e5d486ef1
commit 4df7216bc0
3 changed files with 61 additions and 9 deletions

View File

@ -53,6 +53,8 @@
`MediaItem.Builder.setImageDurationMs` mandatory for image export.
* Add export support for gaps in sequences of audio EditedMediaItems.
* Track Selection:
* `DefaultTrackSelector`: Prefer object-based audio over channel-based
audio when other factors are equal.
* Extractors:
* Fix preroll sample handling for non-keyframe media start positions when
processing edit lists in MP4 files

View File

@ -3406,6 +3406,20 @@ public class DefaultTrackSelector extends MappingTrackSelector
}
}
private static boolean isObjectBasedAudio(Format format) {
if (format.sampleMimeType == null) {
return false;
}
switch (format.sampleMimeType) {
case MimeTypes.AUDIO_E_AC3_JOC:
case MimeTypes.AUDIO_AC4:
case MimeTypes.AUDIO_IAMF:
return true;
default:
return false;
}
}
private static boolean isDolbyAudio(Format format) {
if (format.sampleMimeType == null) {
return false;
@ -3726,6 +3740,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
private final int preferredMimeTypeMatchIndex;
private final boolean usesPrimaryDecoder;
private final boolean usesHardwareAcceleration;
private final boolean isObjectBasedAudio;
public AudioTrackInfo(
int rendererIndex,
@ -3770,6 +3785,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
getRoleFlagMatchScore(format.roleFlags, parameters.preferredAudioRoleFlags);
hasMainOrNoRoleFlag = format.roleFlags == 0 || (format.roleFlags & C.ROLE_FLAG_MAIN) != 0;
isDefaultSelectionFlag = (format.selectionFlags & C.SELECTION_FLAG_DEFAULT) != 0;
isObjectBasedAudio = isObjectBasedAudio(format);
channelCount = format.channelCount;
sampleRate = format.sampleRate;
bitrate = format.bitrate;
@ -3877,6 +3893,7 @@ public class DefaultTrackSelector extends MappingTrackSelector
.compareFalseFirst(this.usesPrimaryDecoder, other.usesPrimaryDecoder)
.compareFalseFirst(this.usesHardwareAcceleration, other.usesHardwareAcceleration)
// 5. Compare technical quality.
.compareFalseFirst(this.isObjectBasedAudio, other.isObjectBasedAudio)
.compare(this.channelCount, other.channelCount, qualityOrdering)
.compare(this.sampleRate, other.sampleRate, qualityOrdering);
if (Util.areEqual(this.language, other.language)) {

View File

@ -988,6 +988,39 @@ public final class DefaultTrackSelectorTest {
assertFixedSelection(result.selections[0], trackGroups, firstLanguageFormat);
}
/**
* Tests that track selector will prefer audio tracks with object based audio over tracks with
* higher channel count when other factors are the same, and tracks are within renderer's
* capabilities.
*/
@Test
public void
selectTracks_audioChannelCountConstraintsDisabled_preferObjectBasedAudioBeforeChannelCount()
throws Exception {
Format channelBasedAudioWithHigherChannelCountFormat =
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC3).setChannelCount(6).build();
Format objectBasedAudioWithLowerChannelCountFormat =
new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC4).setChannelCount(2).build();
TrackGroupArray trackGroups =
wrapFormats(
channelBasedAudioWithHigherChannelCountFormat,
objectBasedAudioWithLowerChannelCountFormat);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setConstrainAudioChannelCountToDeviceCapabilities(false)
.build());
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES},
trackGroups,
periodId,
TIMELINE);
assertFixedSelection(
result.selections[0], trackGroups, objectBasedAudioWithLowerChannelCountFormat);
}
/**
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
* higher sample rate when audio channel count constraints are disabled, other factors are the
@ -2779,37 +2812,37 @@ public final class DefaultTrackSelectorTest {
public void selectTracks_withPreferredAudioMimeTypes_selectsTrackWithPreferredMimeType()
throws Exception {
Format formatAac = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build();
Format formatAc4 = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AC4).build();
Format formatEAc3 = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_E_AC3).build();
TrackGroupArray trackGroups = wrapFormats(formatAac, formatAc4, formatEAc3);
Format formatOpus = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_OPUS).build();
Format formatFlac = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_FLAC).build();
TrackGroupArray trackGroups = wrapFormats(formatAac, formatOpus, formatFlac);
trackSelector.setParameters(
trackSelector.buildUponParameters().setPreferredAudioMimeType(MimeTypes.AUDIO_AC4));
trackSelector.buildUponParameters().setPreferredAudioMimeType(MimeTypes.AUDIO_OPUS));
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections[0], trackGroups, formatAc4);
assertFixedSelection(result.selections[0], trackGroups, formatOpus);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AC4, MimeTypes.AUDIO_AAC));
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_OPUS, MimeTypes.AUDIO_AAC));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections[0], trackGroups, formatAc4);
assertFixedSelection(result.selections[0], trackGroups, formatOpus);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AMR, MimeTypes.AUDIO_E_AC3));
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AMR, MimeTypes.AUDIO_FLAC));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
assertFixedSelection(result.selections[0], trackGroups, formatEAc3);
assertFixedSelection(result.selections[0], trackGroups, formatFlac);
// Select first in the list if no preference is specified.
trackSelector.setParameters(