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:
parent
5e5d486ef1
commit
4df7216bc0
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user